From c71534fc707ba03f4eca1589548d006b4ef6a59e Mon Sep 17 00:00:00 2001 From: Quinton Miller Date: Sun, 27 Nov 2022 21:29:03 +0800 Subject: [PATCH 1/3] Redefine defs when constant and number in generic arguments are equal --- spec/compiler/semantic/restrictions_spec.cr | 40 ++++++++++++++++ src/compiler/crystal/semantic/restrictions.cr | 46 +++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/spec/compiler/semantic/restrictions_spec.cr b/spec/compiler/semantic/restrictions_spec.cr index 139f881cc447..4a3bd01b3694 100644 --- a/spec/compiler/semantic/restrictions_spec.cr +++ b/spec/compiler/semantic/restrictions_spec.cr @@ -548,6 +548,46 @@ describe "Restrictions" do end end + describe "Path vs NumberLiteral" do + it "inserts constant before number literal of same value with generic arguments" do + assert_type(<<-CR) { bool } + X = 1 + + class Foo(N) + end + + def foo(a : Foo(1)) + 'a' + end + + def foo(a : Foo(X)) + true + end + + foo(Foo(1).new) + CR + end + + it "inserts number literal before constant of same value with generic arguments" do + assert_type(<<-CR) { bool } + X = 1 + + class Foo(N) + end + + def foo(a : Foo(X)) + 'a' + end + + def foo(a : Foo(1)) + true + end + + foo(Foo(1).new) + CR + end + end + describe "free variables" do it "inserts path before free variable with same name" do assert_type(<<-CR) { tuple_of([char, bool]) } diff --git a/src/compiler/crystal/semantic/restrictions.cr b/src/compiler/crystal/semantic/restrictions.cr index 5e157e3ef200..fca3e70a5f7b 100644 --- a/src/compiler/crystal/semantic/restrictions.cr +++ b/src/compiler/crystal/semantic/restrictions.cr @@ -605,11 +605,57 @@ module Crystal false end + def restriction_of?(other : NumberLiteral, owner, self_free_vars = nil, other_free_vars = nil) + # this happens when `self` and `other` are generic arguments: + # + # ``` + # X = 1 + # + # def foo(param : StaticArray(Int32, X)) + # end + # + # def foo(param : StaticArray(Int32, 1)) + # end + # ``` + case self_type = owner.lookup_path(self) + when Const + self_type.value == other + when NumberLiteral + self_type == other + else + false + end + end + def restriction_of?(other, owner, self_free_vars = nil, other_free_vars = nil) false end end + class NumberLiteral + def restriction_of?(other : Path, owner, self_free_vars = nil, other_free_vars = nil) + # this happens when `self` and `other` are generic arguments: + # + # ``` + # X = 1 + # + # def foo(param : StaticArray(Int32, 1)) + # end + # + # def foo(param : StaticArray(Int32, X)) + # end + # ``` + case other_type = owner.lookup_path(other) + when Const + other_type.value == self + when NumberLiteral + other_type == self + else + false + end + end + end + class Union def restriction_of?(other, owner, self_free_vars = nil, other_free_vars = nil) # For a union to be considered before another restriction, From 66756cf372d84acf34c31d83936c881df01110ec Mon Sep 17 00:00:00 2001 From: Quinton Miller Date: Sun, 27 Nov 2022 22:00:10 +0800 Subject: [PATCH 2/3] don't match free vars --- src/compiler/crystal/semantic/restrictions.cr | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/compiler/crystal/semantic/restrictions.cr b/src/compiler/crystal/semantic/restrictions.cr index fca3e70a5f7b..c2cfc9065a9a 100644 --- a/src/compiler/crystal/semantic/restrictions.cr +++ b/src/compiler/crystal/semantic/restrictions.cr @@ -606,6 +606,8 @@ module Crystal end def restriction_of?(other : NumberLiteral, owner, self_free_vars = nil, other_free_vars = nil) + return false if self_free_vars && self.single_name?.try { |name| self_free_vars.includes?(name) } + # this happens when `self` and `other` are generic arguments: # # ``` @@ -634,6 +636,8 @@ module Crystal class NumberLiteral def restriction_of?(other : Path, owner, self_free_vars = nil, other_free_vars = nil) + return false if other_free_vars && other.single_name?.try { |name| other_free_vars.includes?(name) } + # this happens when `self` and `other` are generic arguments: # # ``` From 60e001acdbf0a8648250b7f865fdf07e826e35bf Mon Sep 17 00:00:00 2001 From: Quinton Miller Date: Sun, 27 Nov 2022 22:10:50 +0800 Subject: [PATCH 3/3] fixup --- spec/compiler/semantic/restrictions_spec.cr | 37 +++++++++++++++++++ src/compiler/crystal/semantic/restrictions.cr | 2 - 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/spec/compiler/semantic/restrictions_spec.cr b/spec/compiler/semantic/restrictions_spec.cr index 4a3bd01b3694..4336b142b8ca 100644 --- a/spec/compiler/semantic/restrictions_spec.cr +++ b/spec/compiler/semantic/restrictions_spec.cr @@ -617,6 +617,43 @@ describe "Restrictions" do CR end + # TODO: enable in #12784 + pending "inserts constant before free variable with same name" do + assert_type(<<-CR) { tuple_of([char, bool]) } + class Foo(T); end + + X = 1 + + def foo(x : Foo(X)) forall X + true + end + + def foo(x : Foo(X)) + 'a' + end + + {foo(Foo(1).new), foo(Foo(2).new)} + CR + end + + pending "keeps constant before free variable with same name" do + assert_type(<<-CR) { tuple_of([char, bool]) } + class Foo(T); end + + X = 1 + + def foo(x : Foo(X)) + 'a' + end + + def foo(x : Foo(X)) forall X + true + end + + {foo(Foo(1).new), foo(Foo(2).new)} + CR + end + it "inserts path before free variable even if free var resolves to a more specialized type" do assert_type(<<-CR) { tuple_of([int32, int32, bool]) } class Foo diff --git a/src/compiler/crystal/semantic/restrictions.cr b/src/compiler/crystal/semantic/restrictions.cr index c2cfc9065a9a..523030444d2e 100644 --- a/src/compiler/crystal/semantic/restrictions.cr +++ b/src/compiler/crystal/semantic/restrictions.cr @@ -636,8 +636,6 @@ module Crystal class NumberLiteral def restriction_of?(other : Path, owner, self_free_vars = nil, other_free_vars = nil) - return false if other_free_vars && other.single_name?.try { |name| other_free_vars.includes?(name) } - # this happens when `self` and `other` are generic arguments: # # ```