Skip to content

Commit

Permalink
Merge pull request #172 from soutaro/true-false
Browse files Browse the repository at this point in the history
Boolean literal may have type of `true` or `false`
  • Loading branch information
soutaro authored Jul 25, 2020
2 parents d2bba14 + c80cd43 commit 22d28ff
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 2 deletions.
4 changes: 4 additions & 0 deletions lib/steep/ast/types/literal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ def back_type
Builtin::String
when Symbol
Builtin::Symbol
when true
Builtin::TrueClass
when false
Builtin::FalseClass
else
raise "Unexpected literal type: #{value.inspect}"
end
Expand Down
17 changes: 17 additions & 0 deletions lib/steep/subtyping/check.rb
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,23 @@ def check0(relation, self_type:, assumption:, trace:, constraints:)
trace: trace,
constraints: constraints)

when relation.super_type.is_a?(AST::Types::Literal)
case
when relation.super_type.value == true && AST::Builtin::TrueClass.instance_type?(relation.sub_type)
success(constraints: constraints)
when relation.super_type.value == false && AST::Builtin::FalseClass.instance_type?(relation.sub_type)
success(constraints: constraints)
else
failure(error: Result::Failure::UnknownPairError.new(relation: relation),
trace: trace)
end

when relation.super_type.is_a?(AST::Types::Nil) && AST::Builtin::NilClass.instance_type?(relation.sub_type)
success(constraints: constraints)

when relation.sub_type.is_a?(AST::Types::Nil) && AST::Builtin::NilClass.instance_type?(relation.super_type)
success(constraints: constraints)

else
failure(error: Result::Failure::UnknownPairError.new(relation: relation),
trace: trace)
Expand Down
8 changes: 7 additions & 1 deletion lib/steep/type_construction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1094,7 +1094,13 @@ def synthesize(node, hint: nil)
end

when :true, :false
add_typing(node, type: AST::Types::Boolean.new)
ty = node.type == :true ? AST::Types::Literal.new(value: true) : AST::Types::Literal.new(value: false)

if hint && check_relation(sub_type: ty, super_type: hint).success?
add_typing(node, type: hint)
else
add_typing(node, type: AST::Types::Boolean.new)
end

when :hash
yield_self do
Expand Down
19 changes: 18 additions & 1 deletion test/subtyping_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ def foo: () { () -> String } -> Object
end
end

def test_literal0
def test_literal
with_checker do |checker|
assert_success_result checker.check(parse_relation("123", "::Integer", checker: checker), self_type: parse_type("self", checker: checker), constraints: Constraints.empty)

Expand All @@ -350,6 +350,23 @@ def test_literal0
end
end

def test_literal_bidirectional
with_checker do |checker|
assert_success_result checker.check(parse_relation("true", "::TrueClass", checker: checker), self_type: parse_type("self", checker: checker), constraints: Constraints.empty)
assert_success_result checker.check(parse_relation("::TrueClass", "true", checker: checker), self_type: parse_type("self", checker: checker), constraints: Constraints.empty)

assert_success_result checker.check(parse_relation("false", "::FalseClass", checker: checker), self_type: parse_type("self", checker: checker), constraints: Constraints.empty)
assert_success_result checker.check(parse_relation("::FalseClass", "false", checker: checker), self_type: parse_type("self", checker: checker), constraints: Constraints.empty)
end
end

def test_nil_type
with_checker do |checker|
assert_success_result checker.check(parse_relation("nil", "::NilClass", checker: checker), self_type: parse_type("self", checker: checker), constraints: Constraints.empty)
assert_success_result checker.check(parse_relation("::NilClass", "nil", checker: checker), self_type: parse_type("self", checker: checker), constraints: Constraints.empty)
end
end

def test_void
with_checker do |checker|
assert_success_result checker.check(parse_relation("void", "void", checker: checker), self_type: parse_type("self", checker: checker), constraints: Constraints.empty)
Expand Down
6 changes: 6 additions & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,12 @@ def `===`: (*untyped) -> untyped
def yield: (*untyped) -> untyped
def arity: -> Integer
end
class TrueClass
end
class FalseClass
end
EOS

def checker
Expand Down
20 changes: 20 additions & 0 deletions test/type_construction_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2656,6 +2656,26 @@ def test_rescue_bidning_typing
end
end

def test_string_or_true_false
with_checker do |checker|
source = parse_ruby(<<EOF)
# @type var x: String | FalseClass
x = false
# @type var y: String | true
y = true
EOF

with_standard_construction(checker, source) do |construction, typing|
_, _, context = construction.synthesize(source.node)

assert_no_error typing
assert_equal parse_type("::String | ::FalseClass"), context.lvar_env[:x]
assert_equal parse_type("::String | true"), context.lvar_env[:y]
end
end
end

def test_type_case_case_when
with_checker do |checker|
source = parse_ruby(<<EOF)
Expand Down

0 comments on commit 22d28ff

Please sign in to comment.