crystal icon indicating copy to clipboard operation
crystal copied to clipboard

Better handle free vars and unknown types in abstract defs

Open Blacksmoke16 opened this issue 3 months ago • 4 comments

Fixes #10699

I broke out the rescue blocks into one for each side, removing the logic that always just defaulted to true if there was a type lookup error. It'll now properly throw an error if one side has a type that doesn't resolve. E.g. example one in the originally issue. This PR does NOT handle the case where both side are invalid types, but could change this as a follow up if we wanted too.

A type is assumed to be resolvable if it is a free var, global, is a generic type var, or is not a Path. This handles the second example in the original issue. It's still not super strict, as as it stands, the logic allows using a diff free var name, or really even just def foo(x) to satisfy abstract def foo(x : U) : U forall U. This satisfies my use case at least by ensuring at least one T.class overload exists.

EDIT: ~Moving this to a draft, abstract def get_env(type : Int32) shouldn't be valid given abstract def get_env(type : T.class) : T forall T.~

Blacksmoke16 avatar Nov 23 '25 22:11 Blacksmoke16

just def foo(x) to satisfy abstract def foo(x : U) : U forall U

IMO this should be legal with or without a return type in the abstract def, same goes for more specific pairs like def foo(x : Indexable) versus abstract def foo(x : Array(T)) forall T. As it stands right now, this PR now forbids those.

HertzDevil avatar Nov 24 '25 14:11 HertzDevil

I reverted 9e97b5b854577f703d7fcbbfa253cce38f374d37, but kept the specs/added a few more. This bring it back with behavior that exists on master. Ultimately I think we'd want to prevent def transform(x : Int32) : Int32 from being considered valid for abstract def transform(x : Array(T)) forall T. But that can be a follow up at some point as it was already considered valid even before this PR.

Blacksmoke16 avatar Nov 24 '25 15:11 Blacksmoke16

This implementation seems way too complicated to be good 😢

Technically, formatting a list of generic arguments doesn't seem much different from formatting other lists of elements. Maybe we could reuse the existing format_literal_elements helper?

That should also fix some edge cases. For example, the rule to add a trailing comma when the type vars span multiple lines does not match with the rule for array literals. There, we don't add a trailing comma if the end delimiter is on the same line.

straight-shoota avatar Dec 03 '25 11:12 straight-shoota

Is this comment meant for #16430 instead...?

HertzDevil avatar Dec 03 '25 11:12 HertzDevil