Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compilation error when using generic inheritance, class variable and union #15120

Open
wolfgang371 opened this issue Oct 23, 2024 · 5 comments
Open
Labels
kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:compiler:semantic topic:lang:type-system

Comments

@wolfgang371
Copy link

This is the stripped-down example:

class X(T) # need to be generic
    @@x = 0 # need to be class variable
    def initialize(@x : T|X(T)) # need to be union type
    end
    def m
        if @@x > 0 # triggers: Error: can't infer the type of class variable '@@x' of X(Int32)
            x = @x
            if x.is_a?(X(T))
                x.m # need to call method
            end
        end
    end
end

class Y(T) < X(T) # needed (but unused...)
end

x = X(Int32).new(42).m # triggers error in line 6 (see above)

I don't have a workaround for this... 😦

I'm running

Crystal 1.14.0 [dacd97bcc] (2024-10-09)
LLVM: 18.1.6
Default target: x86_64-unknown-linux-gnu
@wolfgang371 wolfgang371 added the kind:bug A bug in the code. Does not apply to documentation, specs, etc. label Oct 23, 2024
@HertzDevil
Copy link
Contributor

HertzDevil commented Oct 24, 2024

You could replace @@x with a class_property and always access it as X.x.

@wolfgang371
Copy link
Author

wolfgang371 commented Oct 24, 2024

Thanks @HertzDevil, this workaround (variant 3 below) does help me!

The variant 2 below, however, also triggers the error.

class X(T) # need to be generic
    class_property x = 0 # need to be class variable
    def initialize(@x : T|X(T)) # need to be union type
    end
    def m
        # @@x           # variant #1: triggers: Error: can't infer the type of class variable '@@x' of X(Int32)
        # self.class.x  # variant #2: triggers: Error: can't infer the type of class variable '@@x' of X(Int32).class
        X(T).x        # variant #3: works
        x = @x
        if x.is_a?(X(T))
            x.m # need to call method
        end
    end
end

class Y(T) < X(T) # needed (but unused...)
end

x = X(Int32).new(42).m # triggers error in line 6 (see above)

@Sija
Copy link
Contributor

Sija commented Oct 24, 2024

@wolfgang371 Avoid using #number when the number is not a GitHub issue or PR, since it creates unintended reference(s).

@wolfgang371
Copy link
Author

When including this fix in my original program I run in the next problem (dunno if I should file an extra issue since they're just piling up anyhow) - stripped down version here:

class Grid(T)
    @input : Array(T|self)
    def initialize(input = Array(T|self).new)
        @input = input.map(&.as(T|self)) # cast to uniform type
    end
    def enumerate_grids : Array(Tuple(Int32, self))
        grids = [{0, self}]
        @input.each do |cell|
            if cell.is_a?(self)
                grids += cell.enumerate_grids.map do |level, grid|
                    {level+1, grid}
                end
            end
        end
        grids
    end
end

class GridX(T) < Grid(T) # no error if commented out...
end

Grid(Int32).new([10,20]).enumerate_grids

# triggers (newlines inserted manually):
# Error: method Grid(Int32)#enumerate_grids must return
#
# Array(Tuple(Int32, Grid(Int32)))
#
# but it is returning (
#
# Array(Tuple(Int32, Grid(Int32))) |
# Array(Tuple(Int32, Grid(Int32)))
#
# )

@wolfgang371
Copy link
Author

wolfgang371 commented Oct 25, 2024

Funny enough, the latter bug already seems to be rather resistant. With the usual antidote the compile time error mutates to a runtime error:

        # ...
        grids.as(Array(Tuple(Int32, Grid(Int32)))) # instead of just returning plain `grids`
        # ...

yields (whitespace added manually)

Unhandled exception: Cast from
        Array(Tuple(Int32, Grid(Int32)))
to
        Array(Tuple(Int32, Grid(Int32)))
failed, at /tmp/inheritance-bug.cr:15:9:15 (TypeCastError)

😉

Seems like I need to copy and paste instead of inheriting here... 😕

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:compiler:semantic topic:lang:type-system
Projects
None yet
Development

No branches or pull requests

5 participants