Skip to content

Commit

Permalink
Redefine defs when constant and number in generic arguments are equal (
Browse files Browse the repository at this point in the history
  • Loading branch information
HertzDevil authored Dec 1, 2022
1 parent 312e369 commit 926e89c
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 0 deletions.
77 changes: 77 additions & 0 deletions spec/compiler/semantic/restrictions_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -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]) }
Expand Down Expand Up @@ -577,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
Expand Down
48 changes: 48 additions & 0 deletions src/compiler/crystal/semantic/restrictions.cr
Original file line number Diff line number Diff line change
Expand Up @@ -605,11 +605,59 @@ module Crystal
false
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:
#
# ```
# 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,
Expand Down

0 comments on commit 926e89c

Please sign in to comment.