Skip to content

Commit

Permalink
Propagate type filters through variables
Browse files Browse the repository at this point in the history
  • Loading branch information
Ary Borenszweig committed Jun 8, 2013
1 parent 3ee0b22 commit 7c56e1e
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 8 deletions.
8 changes: 5 additions & 3 deletions lib/crystal/type_inference.rb
Original file line number Diff line number Diff line change
Expand Up @@ -312,14 +312,16 @@ def visit_var(node)
var = lookup_var node.name
filter = build_var_filter var
node.bind_to(filter || var)
node.type_filters = {node.name => NotNilFilter}
node.type_filters = and_type_filters({node.name => NotNilFilter}, var.type_filters)
end

def build_var_filter(var)
filters = @type_filter_stack.map { |hash| hash[var.name] }.compact
return if filters.empty?

filtered_node = TypeFilteredNode.new(filters.last)
final_filter = filters.length == 1 ? filters[0] : AndTypeFilter.new(*filters)

filtered_node = TypeFilteredNode.new(final_filter)
filtered_node.bind_to var
filtered_node
end
Expand Down Expand Up @@ -409,7 +411,7 @@ def type_assign(target, value, node = nil)
var.bind_to value
end

node.type_filters = and_type_filters({target.name => NotNilFilter}, node.value.type_filters) if node
var.type_filters = node.type_filters = and_type_filters({target.name => NotNilFilter}, node.value.type_filters) if node
when InstanceVar
value.accept self

Expand Down
13 changes: 8 additions & 5 deletions lib/crystal/type_inference/filters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,20 @@ def to_s
end

class AndTypeFilter
def initialize(filter1, filter2)
@filter1 = filter1
@filter2 = filter2
def initialize(*filters)
@filters = filters.uniq
end

def apply(other)
@filter2.apply(@filter1.apply(other))
type = other
@filters.each do |filter|
type = filter.apply(type)
end
type
end

def to_s
"(#{@filter1} && #{@filter2})"
"(#{@filters.join ' && '})"
end
end

Expand Down
18 changes: 18 additions & 0 deletions spec/type_inference/nil_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,22 @@ def bar
1
)) { int }
end

it "restricts type when using previously assigned var" do
assert_type(%q(
class Foo
def bar
1
end
end
f = Foo.new || nil
x = f
if x
f.bar
else
2
end
)) { int }
end
end

0 comments on commit 7c56e1e

Please sign in to comment.