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

Error when nested array/hash is used on inheritance #10133

Open
SlayerShadow opened this issue Dec 22, 2020 · 9 comments
Open

Error when nested array/hash is used on inheritance #10133

SlayerShadow opened this issue Dec 22, 2020 · 9 comments
Labels
kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:compiler:generics

Comments

@SlayerShadow
Copy link

SlayerShadow commented Dec 22, 2020

class Some < Array( Array( UInt32 ) )
end
 
Some.new

(carc)

This produces an error:

Error: instance variable '@buffer' of Array(Array(UInt32)) must be Pointer(Array(UInt32)), not Pointer(Array(UInt32))

With 1-dimensional array it works:

class Some < Array( UInt32 )
end

Some.new

(carc)


Same for Hash (reduced as much as possible):

class Some < Hash( UInt32, Hash( UInt32, UInt32 ) )
end

Some.new

(carc)

Error: instance variable '@entries' of Hash(UInt32, Hash(UInt32, UInt32)) must be Pointer(Hash::Entry(UInt32, Hash(UInt32, UInt32))), not Pointer(Hash::Entry(UInt32, Hash(UInt32, UInt32)))

Tested against master too at: Crystal 1.0.0-dev [935476e] (2020-12-18).

@SlayerShadow
Copy link
Author

Combinations

  • Some < Hash( UInt32, Array( UInt32 ) )
  • Some < Array( Hash( UInt32, UInt32 ) )
  • Some < Array( Hash( UInt32, Array( UInt32 ) ) )

work well. It seems that only fails when array of array and hash of hash is used.

@straight-shoota
Copy link
Member

This is very well a bug, but inheriting from Array or Hash is really not advisable. Please use composition instead.

@SlayerShadow
Copy link
Author

Yeah I just use an uninherited class with 2D @buffer instead.

@HertzDevil
Copy link
Contributor

This happens to any nested generic, not just Array:

class Foo(T)
end

class Bar(T)
  def initialize
    @buffer = Foo(T).new
  end
end

class Baz < Bar(Bar(Int32))
end

Baz.new
# Error: instance variable '@buffer' of Bar(Bar(Int32)) must be Foo(Bar(Int32)), not Foo(Bar(Int32))

@straight-shoota straight-shoota added kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:compiler:generics labels Apr 25, 2021
@straight-shoota
Copy link
Member

Closing as duplicate of #2665

@HertzDevil
Copy link
Contributor

HertzDevil commented Jun 21, 2021

The above Array case appears to be fixed on master, but the Hash case is still failing. Reduced:

class A(T1)
end

class B(T2)
end

class C(T3)
  @entries = A(B(T3)).new
end

class D < C(C(Int32))
end

D.new # Error: instance variable '@entries' of C(C(Int32)) must be A(B(C(Int32))), not A(B(C(Int32)))

@HertzDevil
Copy link
Contributor

The array example is not really fixed:

class Foo(T)
end

class Bar(T)
  def initialize
    @buffer = Foo(T).new
  end
end

class Baz < Bar(Bar(Int32))
end

typeof(Baz.new.@buffer) # => (Foo(Bar(Int32)) | Foo(Bar(Int32)))

This seemingly reducible union is actually Foo(Bar(Int32)) | Foo(Bar(Int32)+); one of them's generic type argument is a virtual type, the other's isn't. Likewise, the hash example fails due to a mismatch between A(B(C(Int32))) and A(B(C(Int32)+)).

So this is related to #10302 (comment). Regardless of whether virtual types will stay, there should never be a need for generic type arguments to be virtual.

@HertzDevil
Copy link
Contributor

Another snippet taken from the forum:

class Item(V)
end

class Foo(T)
end

class Bar(V) < Foo(Item(V))
  @foo = uninitialized Item(V)

  def foo(value : V, name = nil)
    @foo = Item(V).new # Error: instance variable '@foo' of Bar(Tuple(Foo(String))) must be Item(Tuple(Foo(String))), not Item(Tuple(Foo(String)))
  end
end

x = Bar(Tuple(Foo(String))).new
x.foo({Foo(String).new})

@crysbot
Copy link

crysbot commented Sep 2, 2024

This issue has been mentioned on Crystal Forum. There might be relevant details there:

https://forum.crystal-lang.org/t/why-is-this-failing/7161/2

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:generics
Projects
None yet
Development

No branches or pull requests

4 participants