Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: crystal-lang/crystal
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 10ce3d1152e8
Choose a base ref
...
head repository: crystal-lang/crystal
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 671ecb33ce3a
Choose a head ref
  • 2 commits
  • 21 files changed
  • 1 contributor

Commits on Aug 6, 2016

  1. Compiler: invoke map_type earlier

    Ary Borenszweig committed Aug 6, 2016
    Copy the full SHA
    a3df4d8 View commit details

Commits on Aug 7, 2016

  1. Copy the full SHA
    671ecb3 View commit details
37 changes: 37 additions & 0 deletions spec/compiler/codegen/if_spec.cr
Original file line number Diff line number Diff line change
@@ -230,4 +230,41 @@ describe "Code gen: if" do
1
)).to_i.should eq(1)
end

it "restricts with || always falsey" do
run(%(
t = 1
if t.is_a?(String) || t.is_a?(String)
t
else
2
end
)).to_i.should eq(2)
end

it "considers or truthy/falsey right" do
run(%(
t = 1 || 'a'
if t.is_a?(Char) || t.is_a?(Char)
1
else
2
end
)).to_i.should eq(2)
end

it "codegens #3104" do
codegen(%(
def foo
yield
end
x = typeof(nil && 1)
foo do
if x
end
end
x
))
end
end
4 changes: 2 additions & 2 deletions spec/compiler/codegen/macro_spec.cr
Original file line number Diff line number Diff line change
@@ -1024,8 +1024,8 @@ describe "Code gen: macro" do
nil
end
me
)).to_i.should eq(123)
me || 0
), inject_primitives: false).to_i.should eq(123)
end

it "passes #826" do
15 changes: 15 additions & 0 deletions spec/compiler/codegen/nilable_cast_spec.cr
Original file line number Diff line number Diff line change
@@ -70,4 +70,19 @@ describe "Code gen: nilable cast" do
x ? 10 : 20
)).to_i.should eq(20)
end

it "codegens with NoReturn" do
codegen(%(
lib LibC
fun exit : NoReturn
end
def foo
LibC.exit.as?(Int32)
10
end
foo
))
end
end
3 changes: 2 additions & 1 deletion spec/compiler/codegen/proc_spec.cr
Original file line number Diff line number Diff line change
@@ -679,12 +679,13 @@ describe "Code gen: proc" do
it "doesn't crash on #2196" do
run(%(
x = 42
if x.is_a?(Int32)
z = if x.is_a?(Int32)
x
else
y = x
->{ y }
end
z.is_a?(Int32) ? z : 0
)).to_i.should eq(42)
end

50 changes: 0 additions & 50 deletions spec/compiler/semantic/cleanup_spec.cr
Original file line number Diff line number Diff line change
@@ -1,56 +1,6 @@
require "../../spec_helper"

describe "cleanup" do
it "keeps else of if with nil type" do
assert_after_cleanup "a = nil; if a; 1; else; 2; end",
"a = nil\na\n2"
end

it "keeps then of if with true literal" do
assert_after_cleanup "if true; 1; else; 2; end",
"1"
end

it "keeps else of if with false literal" do
assert_after_cleanup "if false; 1; else; 2; end",
"2"
end

it "keeps then of if with true assignment" do
assert_after_cleanup "if a = true; 1; else; 2; end",
"a = true\n1"
end

it "keeps else of if with false assignment" do
assert_after_cleanup "if a = false; 1; else; 2; end",
"a = false\n2"
end

it "keeps else of if with is_a? that can never hold" do
assert_after_cleanup "a = 1; if a.is_a?(Bool); 2; else 3; end",
"a = 1\n3"
end

it "keeps else of if with responds_to? that can never hold" do
assert_after_cleanup "a = 1; if a.responds_to?(:foo); 2; else 3; end",
"a = 1\n3"
end

it "keeps then of if with is_a? that is always true" do
assert_after_cleanup "a = 1; if a.is_a?(Int32); 2; end",
"a = 1\n2"
end

it "keeps then of if with is_a? that is always true" do
assert_after_cleanup "a = 1 || 1.5; if a.is_a?(Number); 2; end",
"a = if __temp_1 = 1\n __temp_1\nelse\n 1.5\nend\n2"
end

it "keeps then of if with responds_to? that is always true" do
assert_after_cleanup "struct Int; def +(other); end; end; a = 1; if a.responds_to?(:\"+\"); 2; end",
"struct Int\n def +(other)\n end\nend\na = 1\n2"
end

it "errors if assigning var to itself" do
assert_error "a = 1; a = a", "expression has no effect"
end
2 changes: 1 addition & 1 deletion spec/compiler/semantic/doc_spec.cr
Original file line number Diff line number Diff line change
@@ -286,7 +286,7 @@ describe "Semantic: doc" do
# Hello
foo
), wants_doc: true
), wants_doc: true, inject_primitives: false
program = result.program
foo = program.types["Foo"]
foo.doc.should eq("Hello")
8 changes: 4 additions & 4 deletions spec/compiler/semantic/exception_spec.cr
Original file line number Diff line number Diff line change
@@ -215,9 +215,9 @@ describe "Semantic: exception" do
p n
end
n
)) { no_return }
)) { int32 }
mod = result.program
eh = result.node.as(Expressions).expressions[-1]
eh = result.node.as(Expressions).expressions[-2]
call_p_n = eh.as(ExceptionHandler).ensure.not_nil!.as(Call)
call_p_n.args.first.type.should eq(mod.nilable(mod.int32))
end
@@ -233,9 +233,9 @@ describe "Semantic: exception" do
p n
end
n
)) { no_return }
)) { int32 }
mod = result.program
eh = result.node.as(Expressions).expressions[-1]
eh = result.node.as(Expressions).expressions[-2]
call_p_n = eh.as(ExceptionHandler).ensure.not_nil!.as(Call)
call_p_n.args.first.type.should eq(mod.nilable(mod.int32))
end
4 changes: 2 additions & 2 deletions spec/compiler/semantic/if_spec.cr
Original file line number Diff line number Diff line change
@@ -78,7 +78,7 @@ describe "Semantic: if" do
n
end
n
)) { int32 }
)) { union_of(int32, float64) }
end

it "restricts the type of the right hand side of an || when using is_a? (#1728)" do
@@ -198,6 +198,6 @@ describe "Semantic: if" do
else
2
end
)) { int32 }
)) { union_of(bool, int32) }
end
end
2 changes: 1 addition & 1 deletion spec/compiler/semantic/initialize_spec.cr
Original file line number Diff line number Diff line change
@@ -465,7 +465,7 @@ describe "Semantic: initialize" do
foo = Foo.new
foo.x
)) { no_return }
)) { int32 }
end

it "doesn't type instance var as nilable if not used in method call" do
2 changes: 1 addition & 1 deletion spec/compiler/semantic/macro_spec.cr
Original file line number Diff line number Diff line change
@@ -466,7 +466,7 @@ describe "Semantic: macro" do
end
me
)) { symbol }
)) { nilable symbol }
end

it "errors if declares macro inside if" do
2 changes: 1 addition & 1 deletion spec/compiler/semantic/nilable_cast_spec.cr
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ describe "Semantic: nilable cast" do
it "types as?" do
assert_type(%(
1.as?(Float64)
)) { nil_type }
)) { nilable float64 }
end

it "types as? with union" do
2 changes: 1 addition & 1 deletion spec/compiler/semantic/no_return_spec.cr
Original file line number Diff line number Diff line change
@@ -317,6 +317,6 @@ describe "Semantic: NoReturn" do
end
baz
)) { no_return }
)) { int32 }
end
end
8 changes: 4 additions & 4 deletions spec/compiler/semantic/return_spec.cr
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ describe "Semantic: return" do
end

it "infers return type with many returns (1)" do
assert_type("def foo; if true; return 1; end; 'a'; end; foo") { int32 }
assert_type("def foo; if true; return 1; end; 'a'; end; foo") { union_of(int32, char) }
end

it "infers return type with many returns (2)" do
@@ -26,7 +26,7 @@ describe "Semantic: return" do
end
bar
)) { nil_type }
)) { nilable int32 }
end

it "can use type var as return type (#1226)" do
@@ -130,7 +130,7 @@ describe "Semantic: return" do
foo = Foo.new
foo.bar
)) { no_return }
)) { int32 }
end

it "types bug (#1823)" do
@@ -166,7 +166,7 @@ describe "Semantic: return" do
end
test
)) { types["Bar"] }
)) { nilable types["Bar"] }
end

it "can use free var in return type (#2492)" do
4 changes: 2 additions & 2 deletions spec/spec_helper.cr
Original file line number Diff line number Diff line change
@@ -150,8 +150,8 @@ def assert_type(str, flags = nil, inject_primitives = true)
result
end

def semantic(code : String, wants_doc = false)
code = inject_primitives(code)
def semantic(code : String, wants_doc = false, inject_primitives = true)
code = inject_primitives(code) if inject_primitives
semantic parse(code, wants_doc: wants_doc), wants_doc: wants_doc
end

6 changes: 6 additions & 0 deletions src/compiler/crystal/codegen/cast.cr
Original file line number Diff line number Diff line change
@@ -70,6 +70,8 @@ require "./codegen"

class Crystal::CodeGenVisitor
def assign(target_pointer, target_type, value_type, value)
return if @builder.end

target_type = target_type.remove_indirection
value_type = value_type.remove_indirection

@@ -271,6 +273,8 @@ class Crystal::CodeGenVisitor
end

def downcast(value, to_type, from_type : Type, already_loaded)
return llvm_nil if @builder.end

from_type = from_type.remove_indirection
to_type = to_type.remove_indirection

@@ -397,6 +401,8 @@ class Crystal::CodeGenVisitor
end

def upcast(value, to_type, from_type)
return llvm_nil if @builder.end

from_type = from_type.remove_indirection
to_type = to_type.remove_indirection

30 changes: 29 additions & 1 deletion src/compiler/crystal/codegen/codegen.cr
Original file line number Diff line number Diff line change
@@ -262,6 +262,10 @@ module Crystal
node.accept visitor
end

def visit_any(node)
!@builder.end
end

def type
context.type.not_nil!
end
@@ -564,6 +568,8 @@ module Crystal
end

def codegen_return(type : Type)
return if @builder.end

method_type = context.return_type.not_nil!
if method_type.void?
ret
@@ -659,6 +665,24 @@ module Crystal
end

def visit(node : If)
if node.truthy?
node.cond.accept self
node.then.accept self
if (node_type = node.type?) && (then_type = node.then.type?)
@last = upcast(@last, node_type, then_type)
end
return false
end

if node.falsey?
node.cond.accept self
node.else.accept self
if (node_type = node.type?) && (else_type = node.else.type?)
@last = upcast(@last, node_type, else_type)
end
return false
end

then_block, else_block = new_blocks "then", "else"

request_value do
@@ -1114,7 +1138,11 @@ module Crystal
resulting_type = node.type
non_nilable_type = node.non_nilable_type

if node.upcast?
filtered_type = obj_type.filter_by(to_type)

if !filtered_type
@last = upcast llvm_nil, resulting_type, @program.nil
elsif node.upcast?
@last = upcast last_value, non_nilable_type, obj_type
@last = upcast @last, resulting_type, non_nilable_type
elsif obj_type != non_nilable_type
4 changes: 4 additions & 0 deletions src/compiler/crystal/codegen/phi.cr
Original file line number Diff line number Diff line change
@@ -51,6 +51,10 @@ class Crystal::CodeGenVisitor
return
end

if @codegen.builder.end
return
end

if @needs_value
unless @node_type.try(&.void?) || @node_type.try(&.nil_type?)
value = @codegen.upcast value, @node_type.not_nil!, type
6 changes: 6 additions & 0 deletions src/compiler/crystal/semantic/ast.cr
Original file line number Diff line number Diff line change
@@ -338,6 +338,12 @@ module Crystal
# This is set to `true` for an `If` that was created from an `||` expression.
property? or = false

# This is set to `true` when the compiler is sure that the condition is truthy
property? truthy = false

# This is set to `true` when the compiler is sure that the condition is falsey
property? falsey = false

def clone_without_location
a_if = previous_def
a_if.and = and?
Loading