Skip to content

Commit

Permalink
Let all unbounded type params bounded by Object?
Browse files Browse the repository at this point in the history
  • Loading branch information
soutaro committed Sep 6, 2024
1 parent 16362db commit 31bc526
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 26 deletions.
2 changes: 1 addition & 1 deletion lib/steep/interface/builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def validate_fvs(name, type)
end

def upper_bound(a)
variable_bounds.fetch(a, nil)
variable_bounds.fetch(a, AST::Builtin::Object.instance_type)
end
end

Expand Down
2 changes: 2 additions & 0 deletions lib/steep/interface/type_param.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
module Steep
module Interface
class TypeParam
IMPLICIT_UPPER_BOUND = AST::Builtin.optional(AST::Builtin::Object.instance_type)

attr_reader :name
attr_reader :upper_bound
attr_reader :variance
Expand Down
22 changes: 10 additions & 12 deletions lib/steep/subtyping/check.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def push_variable_bounds(params)
def variable_upper_bound(name)
@bounds.reverse_each do |hash|
if hash.key?(name)
return hash[name]
return hash.fetch(name)
end
end

Expand Down Expand Up @@ -334,17 +334,14 @@ def check_type0(relation)
end

when relation.super_type.is_a?(AST::Types::Var) && constraints.unknown?(relation.super_type.name)
if ub = variable_upper_bound(relation.super_type.name)
Expand(relation) do
check_type(Relation.new(sub_type: relation.sub_type, super_type: ub))
end.tap do |result|
if result.success?
constraints.add(relation.super_type.name, sub_type: relation.sub_type)
end
ub = variable_upper_bound(relation.super_type.name) || Interface::TypeParam::IMPLICIT_UPPER_BOUND

Expand(relation) do
check_type(Relation.new(sub_type: relation.sub_type, super_type: ub))
end.tap do |result|
if result.success?
constraints.add(relation.super_type.name, sub_type: relation.sub_type)
end
else
constraints.add(relation.super_type.name, sub_type: relation.sub_type)
Success(relation)
end

when relation.sub_type.is_a?(AST::Types::Var) && constraints.unknown?(relation.sub_type.name)
Expand Down Expand Up @@ -390,8 +387,9 @@ def check_type0(relation)
end
end

when relation.sub_type.is_a?(AST::Types::Var) && ub = variable_upper_bound(relation.sub_type.name)
when relation.sub_type.is_a?(AST::Types::Var)
Expand(relation) do
ub = variable_upper_bound(relation.sub_type.name) || Interface::TypeParam::IMPLICIT_UPPER_BOUND
check_type(Relation.new(sub_type: ub, super_type: relation.super_type))
end

Expand Down
23 changes: 10 additions & 13 deletions lib/steep/type_construction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3846,20 +3846,17 @@ def try_method_type(node, receiver_type:, method_name:, method_overload:, argume

type_args.each_with_index do |type, index|
param = method_type.type_params[index]
if param.upper_bound
if result = no_subtyping?(sub_type: type.value, super_type: param.upper_bound)
args_ << AST::Builtin.any_type
constr.typing.add_error(
Diagnostic::Ruby::TypeArgumentMismatchError.new(
type_arg: type.value,
type_param: param,
result: result,
location: type.location
)
upper_bound = param.upper_bound || Interface::TypeParam::IMPLICIT_UPPER_BOUND
if result = no_subtyping?(sub_type: type.value, super_type: upper_bound)
args_ << AST::Builtin.any_type
constr.typing.add_error(
Diagnostic::Ruby::TypeArgumentMismatchError.new(
type_arg: type.value,
type_param: param,
result: result,
location: type.location
)
else
args_ << type.value
end
)
else
args_ << type.value
end
Expand Down
6 changes: 6 additions & 0 deletions sig/steep/interface/type_param.rbs
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
module Steep
module Interface
class TypeParam
# Implicit upper bound given to unqualified generic parameter
#
# It's `Object?` currently.
#
IMPLICIT_UPPER_BOUND: AST::Types::t

type loc = RBS::Location[untyped, untyped]

type variance = RBS::AST::TypeParam::variance
Expand Down
30 changes: 30 additions & 0 deletions test/type_check_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2186,4 +2186,34 @@ def foo(x)
YAML
)
end

def test_generics_upperbound_implicitly_object
run_type_check_test(
signatures: {
"a.rbs" => <<~RBS
class Foo
def foo: [X] (X) -> void
end
RBS
},
code: {
"a.rb" => <<~RUBY
class Foo
def foo(x)
x.nil?
end
end
foo = Foo.new
foo.foo("")
foo.foo(NilClass.new)
RUBY
},
expectations: <<~YAML
---
- file: a.rb
diagnostics: []
YAML
)
end
end

0 comments on commit 31bc526

Please sign in to comment.