Open Blacksmoke16 opened 4 years ago
https://github.com/athena-framework/athena/runs/476846691?check_suite_focus=true
Causing CI to fail on GH actions, however I can't seem to reproduce locally :/
Reduced:
https://play.crystal-lang.org/#/r/8nf1
abstract struct Param; end
struct Parameter(T) < Param
getter default : T?
def initialize(@default : T? = nil); end
end
parameters = [Parameter(Int32?).new] of Param
parameters.map do |param|
1 || param.default
end
parameters = [Parameter(Bool).new(default: true)] of Param
crystal test.cr --error-trace
In test.cr:15:14
15 | parameters = [Parameter(Bool).new(default: true)] of Param
^----
Error: instantiating 'Array(Param).class#build(Int32)'
In test.cr:15:14
15 | parameters = [Parameter(Bool).new(default: true)] of Param
^----
Error: instantiating 'Array(Param).class#build(Int32)'
In test.cr:15:15
15 | parameters = [Parameter(Bool).new(default: true)] of Param
^
Error: type must be (Int32 | Nil), not (Bool | Int32 | Nil)
In test.cr:11:16
11 | parameters.map do |param|
^
Error: type must be (Int32 | Nil), not (Bool | Int32 | Nil)
EDIT: Here's the callstack
["src/compiler/crystal/semantic/bindings.cr:70:7 in 'raise_frozen_type'",
"src/compiler/crystal/semantic/bindings.cr:40:9 in 'set_type'",
"src/compiler/crystal/semantic/bindings.cr:50:7 in 'set_type_from'",
"src/compiler/crystal/semantic/bindings.cr:199:9 in 'update'",
"src/compiler/crystal/semantic/bindings.cr:184:31 in 'notify_observers'",
"src/compiler/crystal/semantic/bindings.cr:212:9 in 'propagate'",
"src/compiler/crystal/semantic/bindings.cr:186:31 in 'notify_observers'",
"src/compiler/crystal/semantic/bindings.cr:212:9 in 'propagate'",
"src/compiler/crystal/semantic/bindings.cr:186:31 in 'notify_observers'",
"src/compiler/crystal/semantic/bindings.cr:212:9 in 'propagate'",
"src/compiler/crystal/semantic/bindings.cr:143:7 in 'bind_to'",
"src/compiler/crystal/semantic/call.cr:100:5 in 'recalculate'",
"src/compiler/crystal/semantic/call.cr:691:5 in 'on_new_subclass'",
"src/compiler/crystal/types.cr:1015:44 in 'notify_subclass_added'",
"src/compiler/crystal/types.cr:1202:7 in 'add_subclass'",
"src/compiler/crystal/types.cr:2002:7 in 'after_initialize'",
"src/compiler/crystal/types.cr:1545:7 in 'instantiate'",
"src/compiler/crystal/semantic/bindings.cr:549:26 in 'update'",
"src/compiler/crystal/semantic/bindings.cr:465:5 in 'update'",
"src/compiler/crystal/semantic/main_visitor.cr:295:7 in 'visit'",
"src/compiler/crystal/syntax/visitor.cr:27:12 in 'accept'",
"src/compiler/crystal/semantic/main_visitor.cr:1299:11 in 'visit'",
"src/compiler/crystal/syntax/visitor.cr:27:12 in 'accept'",
"src/compiler/crystal/semantic/main_visitor.cr:1308:21 in 'visit'",
"src/compiler/crystal/syntax/visitor.cr:27:12 in 'accept'",
"src/compiler/crystal/syntax/ast.cr:169:27 in 'accept_children'",
"src/compiler/crystal/syntax/visitor.cr:28:11 in 'accept'",
"src/compiler/crystal/semantic/main_visitor.cr:1121:7 in 'visit'",
"src/compiler/crystal/syntax/visitor.cr:27:12 in 'accept'",
"src/compiler/crystal/semantic/main_visitor.cr:1042:13 in 'visit'",
"src/compiler/crystal/syntax/visitor.cr:27:12 in 'accept'",
"src/compiler/crystal/syntax/ast.cr:169:27 in 'accept_children'",
"src/compiler/crystal/syntax/visitor.cr:28:11 in 'accept'",
"src/compiler/crystal/semantic/main_visitor.cr:1299:11 in 'visit'",
"src/compiler/crystal/syntax/visitor.cr:27:12 in 'accept'",
"src/compiler/crystal/semantic/main_visitor.cr:1308:21 in 'visit'",
"src/compiler/crystal/syntax/visitor.cr:27:12 in 'accept'",
"src/compiler/crystal/syntax/ast.cr:169:27 in 'accept_children'",
"src/compiler/crystal/syntax/visitor.cr:28:11 in 'accept'",
"src/compiler/crystal/semantic/call.cr:422:13 in 'instantiate'",
"src/compiler/crystal/semantic/call.cr:311:5 in 'lookup_matches_in_type'",
"src/compiler/crystal/semantic/call.cr:260:3 in 'lookup_matches_in_type:search_in_parents:with_literals'",
"src/compiler/crystal/semantic/call.cr:239:5 in 'lookup_matches_in'",
"src/compiler/crystal/semantic/call.cr:238:3 in 'lookup_matches_in:with_literals'",
"src/compiler/crystal/semantic/call.cr:195:7 in 'lookup_matches_without_splat'",
"src/compiler/crystal/semantic/call.cr:130:7 in 'lookup_matches:with_literals'",
"src/compiler/crystal/semantic/call.cr:119:5 in 'lookup_matches'",
"src/compiler/crystal/semantic/call.cr:91:5 in 'recalculate'",
"src/compiler/crystal/semantic/main_visitor.cr:1349:7 in 'visit'",
"src/compiler/crystal/syntax/visitor.cr:27:12 in 'accept'",
"src/compiler/crystal/semantic/main_visitor.cr:3043:7 in 'expand'",
"src/compiler/crystal/semantic/main_visitor.cr:2966:9 in 'visit'",
"src/compiler/crystal/syntax/visitor.cr:27:12 in 'accept'",
"src/compiler/crystal/semantic/main_visitor.cr:752:7 in 'type_assign'",
"src/compiler/crystal/semantic/main_visitor.cr:751:5 in 'type_assign'",
"src/compiler/crystal/semantic/main_visitor.cr:740:7 in 'visit'",
"src/compiler/crystal/syntax/visitor.cr:27:12 in 'accept'",
"src/compiler/crystal/syntax/ast.cr:169:27 in 'accept_children'",
"src/compiler/crystal/syntax/visitor.cr:28:11 in 'accept'",
"src/compiler/crystal/semantic/main_visitor.cr:6:7 in 'visit_main'",
"src/compiler/crystal/semantic/main_visitor.cr:5:5 in 'visit_main:process_finished_hooks:cleanup'",
"src/compiler/crystal/semantic.cr:22:7 in 'semantic'",
"src/compiler/crystal/compiler.cr:169:7 in 'compile'",
"src/compiler/crystal/command.cr:275:3 in 'compile'",
"src/compiler/crystal/command.cr:191:14 in 'run_command'",
"src/compiler/crystal/command.cr:106:7 in 'run'",
"src/compiler/crystal/command.cr:49:5 in 'run'",
"src/compiler/crystal/command.cr:48:3 in 'run'",
"src/compiler/crystal.cr:8:1 in '__crystal_main'",
"src/crystal/main.cr:106:5 in 'main_user_code'",
"src/crystal/main.cr:92:7 in 'main'",
"src/crystal/main.cr:115:3 in 'main'",
"__libc_start_main",
"_start",
"???"]
Seems to be related to the Block
? Added some pp
before raise_frozen_type
pp freeze_type, typeof(freeze_type), type, typeof(type), self, typeof(self)
(Int32 | Nil)
Crystal::Type
(Bool | Int32 | Nil)
Crystal::Type
do |param|
1 || param.default
end
Crystal::ASTNode
Anything obvious come to mind @asterite?
@asterite One thing I noticed is this only happens with #map
. #compact_map
, #each
, etc work fine.
abstract struct Param; end
struct Parameter(T) < Param
getter default : T
def initialize(@default : T); end
end
parameters = [Parameter(Int32).new(1)] of Param
pp parameters.map &.default
parameters = [Parameter(Bool).new(default: true)] of Param
This seems to indicate this is some issue with free variables given the #map
is defined as
def map(&block : T -> U) forall U
Array(U).new(size) { |i| yield @buffer[i] }
end
While #compact_map
uses the type of the first element in the array to define the type of the array; ary = [] of typeof((yield first).not_nil!)
.
SO, a workaround for this issue would be to define a custom iterator method to use instead of #map
.
Something like:
class Array
def map_first
ary = [] of typeof((yield first).not_nil!)
each do |e|
ary << yield e
end
ary
end
end
abstract struct Param; end
struct Parameter(T) < Param
getter default : T
def initialize(@default : T); end
end
parameters = [Parameter(Int32).new(1)] of Param
pp parameters.map_first &.default # => [1]
parameters = [Parameter(Bool).new(default: true)] of Param
pp parameters.map_first &.default # => [true]
@Blacksmoke16 Yes, that's exactly the issue.
The problem is that U
is computed once and is not recomputed once T
changes, and that's why you get the error. There are some bindings between nodes missing, but I have to figure out where they go and why when I tried to fix it it didn't work.
Reduced more:
module SomeInterface
abstract def foo(& : _ -> Nil) : Nil
end
class Example
include SomeInterface
def foo(& : -> Nil) : Nil
yield 1 || "foo"
end
end
Example.new.foo do |v|
pp v
end
In test.cr:13:17
13 | Example.new.foo do |v|
^
Error: type must be Nil, not (Int32 | String)
Looks like https://github.com/crystal-lang/crystal/issues/8812#issuecomment-731864946 context was fixed at some point as it works fine as of 1.1.1
. The other two reproductions do not however.
https://play.crystal-lang.org/#/r/8kjf
Related, If I change
Param
andParameter(T)
types to modules, it complies but then theInt32?
type is used twice within the map.https://play.crystal-lang.org/#/r/8kjg
@asterite mentioned in Gitter