Skip to content

Commit

Permalink
Remove 1 item Expressions normalization (#4861)
Browse files Browse the repository at this point in the history
  • Loading branch information
makenowjust authored and Martin Verzilli committed Sep 29, 2017
1 parent 8514651 commit 8c5fb21
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 7 deletions.
15 changes: 15 additions & 0 deletions spec/compiler/normalize/expressions_spec.cr
@@ -0,0 +1,15 @@
require "../../spec_helper"

describe "Normalize: expressions" do
it "normalizes an empty expression" do
assert_normalize "begin\nend", ""
end

it "normalizes an expression" do
assert_normalize "(1 < 2).as(Bool)", "(1 < 2).as(Bool)"
end

it "normalizes expressions" do
assert_normalize "begin\n 1\n 2\nend", "1\n2"
end
end
8 changes: 8 additions & 0 deletions spec/compiler/semantic/while_spec.cr
Expand Up @@ -22,6 +22,14 @@ describe "Semantic: while" do
assert_type("while true; end") { no_return }
end

it "types while (true) as NoReturn" do
assert_type("while (true); end") { no_return }
end

it "types while ((true)) as NoReturn" do
assert_type("while ((true)); end") { no_return }
end

it "reports next cannot be used outside a while" do
assert_error "next",
"Invalid next"
Expand Down
30 changes: 25 additions & 5 deletions src/compiler/crystal/semantic/main_visitor.cr
Expand Up @@ -1737,6 +1737,9 @@ module Crystal
when Assign
target = exp.target
return target if target.is_a?(Var)
when Expressions
return unless exp = single_expression(exp)
return get_expression_var(exp)
end
nil
end
Expand Down Expand Up @@ -1843,15 +1846,17 @@ module Crystal
# block is when the condition is a Var (in the else it must be
# nil), IsA (in the else it's not that type), RespondsTo
# (in the else it doesn't respond to that message) or Not.
case cond = node.cond
case cond = single_expression(node.cond) || node.cond
when Var, IsA, RespondsTo, Not
filter_vars cond_type_filters, &.not
when Or
# Try to apply boolean logic: `!(a || b)` is `!a && !b`
cond_left = single_expression(cond.left) || cond.left
cond_right = single_expression(cond.right) || cond.right

# We can't deduce anything for sub && or || expressions
or_left_type_filters = nil if cond.left.is_a?(And) || cond.left.is_a?(Or)
or_right_type_filters = nil if cond.right.is_a?(And) || cond.right.is_a?(Or)
or_left_type_filters = nil if cond_left.is_a?(And) || cond_left.is_a?(Or)
or_right_type_filters = nil if cond_right.is_a?(And) || cond_right.is_a?(Or)

# No need to deduce anything for temp vars created by the compiler (won't be used by a user)
or_left_type_filters = nil if or_left_type_filters && or_left_type_filters.temp_var?
Expand Down Expand Up @@ -2017,8 +2022,10 @@ module Crystal
node.body.accept self
end

endless_while = node.cond.true_literal?
merge_while_vars node.cond, endless_while, before_cond_vars_copy, before_cond_vars, after_cond_vars, @vars, node.break_vars
cond = single_expression(node.cond) || node.cond

endless_while = cond.true_literal?
merge_while_vars cond, endless_while, before_cond_vars_copy, before_cond_vars, after_cond_vars, @vars, node.break_vars

@while_stack.pop
@block = old_block
Expand Down Expand Up @@ -2146,6 +2153,9 @@ module Crystal
end
when Call
return get_while_cond_assign_target(node.obj)
when Expressions
return unless node = single_expression(node)
return get_while_cond_assign_target(node)
end

nil
Expand Down Expand Up @@ -2178,6 +2188,16 @@ module Crystal
end
end

def single_expression(node)
result = nil

while node.is_a?(Expressions) && node.expressions.size == 1
result = node = node[0]
end

result
end

def end_visit(node : Break)
if last_block_kind == :ensure
node.raise "can't use break inside ensure"
Expand Down
2 changes: 0 additions & 2 deletions src/compiler/crystal/semantic/normalizer.cr
Expand Up @@ -51,8 +51,6 @@ module Crystal
case exps.size
when 0
Nop.new
when 1
exps[0]
else
node.expressions = exps
node
Expand Down

0 comments on commit 8c5fb21

Please sign in to comment.