crystal-lang / crystal

The Crystal Programming Language
https://crystal-lang.org
Apache License 2.0
19.21k stars 1.61k forks source link

False positive for "Recursive struct detected" #14644

Open jgaskins opened 1 month ago

jgaskins commented 1 month ago

The compiler thinks it detects a recursive struct with this code:

abstract struct Content
end

record Text < Content
record Image < Content
record Result < Content, content : Text | Image

The Result type can't hold an instance of itself, though, even via cyclical recursion. It is intended to be able to hold an instance of one of the other types, but since they can't hold a Result (and nothing else in this code can, for that matter), there's no way for this to actually be a recursive struct.

The recursive struct detection appears to be over-extrapolating from the Text | Image union type to all Content subtypes.

straight-shoota commented 1 month ago

Yeah, this is essentially #2661.

As a workaround you can introduce a named type for Text | Image, i.e. without Content. In contrast to an unnamed union this won't be unified then.

abstract struct Content
end

abstract struct TextOrImageContent < Content
end

record Text < TextOrImageContent
record Image < TextOrImageContent
record Result < Content, content : Text | Image

As you can see, the union Text | Image even works when there's a closer type that it can unify as.

ysbaddaden commented 1 month ago

Well, it's still unified, but we introduced an intermediary type to unify to (TextOrImageContent+), instead of the top one (Content+) :)