Skip to content

Commit

Permalink
Showing 20 changed files with 105 additions and 74 deletions.
26 changes: 26 additions & 0 deletions spec/compiler/codegen/super_spec.cr
Original file line number Diff line number Diff line change
@@ -396,4 +396,30 @@ describe "Codegen: super" do
z.to_i
)).to_i.should eq(3)
end

it "calls super from virtual metaclass type (#2841)" do
codegen(%(
require "prelude"
abstract class Foo
def self.bar(x : Bool)
x
end
end
class Bar < Foo
def self.bar(x : Bool)
super
end
end
class Baz < Foo
def self.bar(x : Bool)
super
end
end
(Foo || Bar).bar(true)
))
end
end
19 changes: 19 additions & 0 deletions spec/compiler/codegen/tuple_spec.cr
Original file line number Diff line number Diff line change
@@ -305,4 +305,23 @@ describe "Code gen: tuple" do
Tuple(Nil, Int32).foo
)).to_string.should eq("TupleLiteral")
end

it "passes empty tuple and empty named tuple to a method (#2852)" do
codegen(%(
def foo(*binds)
baz(binds)
end
def bar(**binds)
baz(binds)
end
def baz(binds)
binds
end
foo
bar
))
end
end
6 changes: 3 additions & 3 deletions spec/compiler/crystal/tools/playground_spec.cr
Original file line number Diff line number Diff line change
@@ -58,12 +58,12 @@ describe Playground::Agent do
agent.last_message.should eq(%({"tag":32,"type":"value","line":1,"value":"5","value_type":"Int32"}))
x, y = 3, 4
agent.i(1, ["x", "y"]) { {x, y} }.should eq({3, 4})
agent.last_message.should eq(%({"tag":32,"type":"value","line":1,"value":"{3, 4}","value_type":"{Int32, Int32}","data":{"x":"3","y":"4"}}))
agent.last_message.should eq(%({"tag":32,"type":"value","line":1,"value":"{3, 4}","value_type":"Tuple(Int32, Int32)","data":{"x":"3","y":"4"}}))

agent.i(1) { nil.as(Void?) }
agent.last_message.should eq(%({"tag":32,"type":"value","line":1,"value":"nil","value_type":"Void?"}))
agent.last_message.should eq(%({"tag":32,"type":"value","line":1,"value":"nil","value_type":"(Void | Nil)"}))
agent.i(1) { a_sample_void.as(Void?) }
agent.last_message.should eq(%({"tag":32,"type":"value","line":1,"value":"nil","value_type":"Void?"}))
agent.last_message.should eq(%({"tag":32,"type":"value","line":1,"value":"nil","value_type":"(Void | Nil)"}))
agent.i(1) { a_sample_void }
agent.last_message.should eq(%({"tag":32,"type":"value","line":1,"value":"nil","value_type":"Nil"}))
end
10 changes: 5 additions & 5 deletions spec/compiler/crystal/types_spec.cr
Original file line number Diff line number Diff line change
@@ -40,11 +40,11 @@ describe "types to_s of" do
end

it "nilable reference type" do
assert_type_to_s "String?" { nilable string }
assert_type_to_s "(String | Nil)" { nilable string }
end

it "nilable value type" do
assert_type_to_s "Int32?" { nilable int32 }
assert_type_to_s "(Int32 | Nil)" { nilable int32 }
end

it "nilable type with more than two elements, Nil at the end" do
@@ -62,17 +62,17 @@ describe "types to_s of" do
end

it "in tuples" do
assert_type_to_s "{String, Int32 | String}" { tuple_of [string, union_of(string, int32)] }
assert_type_to_s "Tuple(String, Int32 | String)" { tuple_of [string, union_of(string, int32)] }
end
end

describe "should have parens" do
it "as return type" do
assert_type_to_s "( -> (Int32 | String))" { proc_of union_of(string, int32) }
assert_type_to_s "Proc((Int32 | String))" { proc_of union_of(string, int32) }
end

it "as arg type" do
assert_type_to_s "((Int32 | String) -> Int32)" { proc_of union_of(string, int32), int32 }
assert_type_to_s "Proc((Int32 | String), Int32)" { proc_of union_of(string, int32), int32 }
end
end
end
2 changes: 2 additions & 0 deletions spec/compiler/parser/parser_spec.cr
Original file line number Diff line number Diff line change
@@ -136,9 +136,11 @@ describe "Parser" do
it_parses "@a, b = 1, 2", MultiAssign.new(["@a".instance_var, "b".var] of ASTNode, [1.int32, 2.int32] of ASTNode)
it_parses "@@a, b = 1, 2", MultiAssign.new(["@@a".class_var, "b".var] of ASTNode, [1.int32, 2.int32] of ASTNode)
it_parses "$a, b = 1, 2", MultiAssign.new([Global.new("$a"), "b".var] of ASTNode, [1.int32, 2.int32] of ASTNode)
it_parses "A, b = 1, 2", MultiAssign.new(["A".path, "b".var] of ASTNode, [1.int32, 2.int32] of ASTNode)

assert_syntax_error "1 == 2, a = 4"
assert_syntax_error "x : String, a = 4"
assert_syntax_error "b, 1 == 2, a = 4"

it_parses "def foo\n1\nend", Def.new("foo", body: 1.int32)
it_parses "def downto(n)\n1\nend", Def.new("downto", ["n".arg], 1.int32)
4 changes: 2 additions & 2 deletions spec/compiler/type_inference/cast_spec.cr
Original file line number Diff line number Diff line change
@@ -118,15 +118,15 @@ describe "Type inference: cast" do
f = ->{ 1 }
f as Void*
),
"can't cast ( -> Int32) to Pointer(Void)"
"can't cast Proc(Int32) to Pointer(Void)"
end

it "disallows casting pointer to fun" do
assert_error %(
a = uninitialized Void*
a as -> Int32
),
"can't cast Pointer(Void) to ( -> Int32)"
"can't cast Pointer(Void) to Proc(Int32)"
end

it "doesn't error if casting to a generic type" do
2 changes: 1 addition & 1 deletion spec/compiler/type_inference/initialize_spec.cr
Original file line number Diff line number Diff line change
@@ -107,7 +107,7 @@ describe "Type inference: initialize" do
f = Foo.new
f.lala
),
"instance variable '@x' of Foo must be Char?, not Int32"
"instance variable '@x' of Foo must be (Char | Nil), not Int32"
end

it "types instance var as nilable if not always assigned" do
2 changes: 1 addition & 1 deletion spec/compiler/type_inference/named_tuple_spec.cr
Original file line number Diff line number Diff line change
@@ -50,7 +50,7 @@ describe "Type inference: named tuples" do

it "gives error when indexing with an unknown name" do
assert_error "{x: 1, y: 'a'}[:z]",
"missing key 'z' for named tuple {x: Int32, y: Char}"
"missing key 'z' for named tuple NamedTuple(x: Int32, y: Char)"
end

it "can write generic type for NamedTuple" do
8 changes: 4 additions & 4 deletions spec/compiler/type_inference/proc_spec.cr
Original file line number Diff line number Diff line change
@@ -196,23 +196,23 @@ describe "Type inference: proc" do
f = ->(x : Int32) { x.to_f }
f as -> Float64
",
"can't cast (Int32 -> Float64) to ( -> Float64)"
"can't cast Proc(Int32, Float64) to Proc(Float64)"
end

it "disallows casting a proc type to one accepting same size argument but different output" do
assert_error "
f = ->(x : Int32) { x.to_f }
f as Int32 -> Int32
",
"can't cast (Int32 -> Float64) to (Int32 -> Int32)"
"can't cast Proc(Int32, Float64) to Proc(Int32, Int32)"
end

it "disallows casting a proc type to one accepting same size argument but different input" do
assert_error "
f = ->(x : Int32) { x.to_f }
f as Float64 -> Float64
",
"can't cast (Int32 -> Float64) to (Float64 -> Float64)"
"can't cast Proc(Int32, Float64) to Proc(Float64, Float64)"
end

it "types proc literal hard type inference (1)" do
@@ -331,7 +331,7 @@ describe "Type inference: proc" do
alias F = Int32 -> Int32
F.new { |x, y| }
",
"wrong number of block arguments for (Int32 -> Int32)#new (given 2, expected 1)"
"wrong number of block arguments for Proc(Int32, Int32)#new (given 2, expected 1)"
end

it "says wrong return type in new on proc type" do
2 changes: 1 addition & 1 deletion spec/compiler/type_inference/splat_spec.cr
Original file line number Diff line number Diff line change
@@ -51,7 +51,7 @@ describe "Type inference: splat" do
a = {1} || {1, 2}
foo *a
),
"splatting a union ({Int32, Int32} | {Int32}) is not yet supported"
"not yet supported"
end

it "errors if splatting non-tuple type" do
8 changes: 4 additions & 4 deletions spec/compiler/type_inference/struct_spec.cr
Original file line number Diff line number Diff line change
@@ -106,7 +106,7 @@ describe "Type inference: struct" do
Test.new(Test.new(nil))
),
"recursive struct Test detected: `@test : Test?`"
"recursive struct Test detected: `@test : (Test | Nil)`"
end

it "errors on recursive struct inside module" do
@@ -118,7 +118,7 @@ describe "Type inference: struct" do
Foo::Test.new(Foo::Test.new(nil))
),
"recursive struct Foo::Test detected: `@test : Foo::Test?`"
"recursive struct Foo::Test detected: `@test : (Foo::Test | Nil)`"
end

it "errors on recursive generic struct inside module" do
@@ -130,7 +130,7 @@ describe "Type inference: struct" do
Foo::Test(Int32).new(Foo::Test(Int32).new(nil))
),
"recursive struct Foo::Test(Int32) detected: `@test : Foo::Test(Int32)?`"
"recursive struct Foo::Test(Int32) detected: `@test : (Foo::Test(Int32) | Nil)`"
end

it "errors on mutually recursive struct" do
@@ -148,7 +148,7 @@ describe "Type inference: struct" do
Foo.new(Bar.new(nil))
Bar.new(Foo.new(nil))
),
"recursive struct Foo detected: `@bar : Bar?` -> `@foo : Foo?`"
"recursive struct Foo detected: `@bar : (Bar | Nil)` -> `@foo : (Foo | Nil)`"
end

it "can't extend struct from non-abstract struct" do
2 changes: 1 addition & 1 deletion spec/compiler/type_inference/tuple_spec.cr
Original file line number Diff line number Diff line change
@@ -43,7 +43,7 @@ describe "Type inference: tuples" do

it "gives error when indexing out of range" do
assert_error "{1, 'a'}[2]",
"index out of bounds for tuple {Int32, Char} (2 not in 0..1)"
"index out of bounds for Tuple(Int32, Char) (2 not in 0..1)"
end

it "gives error when indexing out of range on empty tuple" do
8 changes: 4 additions & 4 deletions spec/std/proc_spec.cr
Original file line number Diff line number Diff line change
@@ -5,28 +5,28 @@ describe "Proc" do
str = MemoryIO.new
f = ->(x : Int32) { x.to_f }
f.to_s(str)
str.to_s.should eq("#<(Int32 -> Float64):0x#{f.pointer.address.to_s(16)}>")
str.to_s.should eq("#<Proc(Int32, Float64):0x#{f.pointer.address.to_s(16)}>")
end

it "does to_s(io) when closured" do
str = MemoryIO.new
a = 1.5
f = ->(x : Int32) { x + a }
f.to_s(str)
str.to_s.should eq("#<(Int32 -> Float64):0x#{f.pointer.address.to_s(16)}:closure>")
str.to_s.should eq("#<Proc(Int32, Float64):0x#{f.pointer.address.to_s(16)}:closure>")
end

it "does to_s" do
str = MemoryIO.new
f = ->(x : Int32) { x.to_f }
f.to_s.should eq("#<(Int32 -> Float64):0x#{f.pointer.address.to_s(16)}>")
f.to_s.should eq("#<Proc(Int32, Float64):0x#{f.pointer.address.to_s(16)}>")
end

it "does to_s when closured" do
str = MemoryIO.new
a = 1.5
f = ->(x : Int32) { x + a }
f.to_s.should eq("#<(Int32 -> Float64):0x#{f.pointer.address.to_s(16)}:closure>")
f.to_s.should eq("#<Proc(Int32, Float64):0x#{f.pointer.address.to_s(16)}:closure>")
end

it "gets pointer" do
6 changes: 5 additions & 1 deletion spec/std/tuple_spec.cr
Original file line number Diff line number Diff line change
@@ -270,7 +270,11 @@ describe "Tuple" do

it "does types" do
tuple = {1, 'a', "hello"}
tuple.types.to_s.should eq("{Int32, Char, String}")
{% if Crystal::VERSION == "0.18.0" %}
tuple.types.to_s.should eq("Tuple(Int32, Char, String)")
{% else %}
tuple.types.to_s.should eq("{Int32, Char, String}")
{% end %}
end

it "does ===" do
14 changes: 4 additions & 10 deletions src/compiler/crystal/codegen/ast.cr
Original file line number Diff line number Diff line change
@@ -39,14 +39,14 @@ module Crystal

if owner = @owner
if owner.metaclass?
owner.instance_type.llvm_name(str)
self_type.instance_type.llvm_name(str)
if original_owner != self_type
str << "@"
original_owner.instance_type.llvm_name(str)
end
str << "::"
elsif !owner.is_a?(Crystal::Program)
owner.llvm_name(str)
self_type.llvm_name(str)
if original_owner != self_type
str << "@"
original_owner.llvm_name(str)
@@ -63,22 +63,16 @@ module Crystal
next_def = next_def.next
end

needs_self_type = self_type.try &.passed_as_self?

if args.size > 0 || needs_self_type || uses_block_arg
if args.size > 0 || uses_block_arg
str << "<"
if needs_self_type
self_type.not_nil!.llvm_name(str)
end
if args.size > 0
str << ", " if needs_self_type
args.each_with_index do |arg, i|
str << ", " if i > 0
arg.type.llvm_name(str)
end
end
if uses_block_arg
str << ", " if needs_self_type || args.size > 0
str << ", " if args.size > 0
str << "&"
block_arg.not_nil!.type.llvm_name(str)
end
2 changes: 1 addition & 1 deletion src/compiler/crystal/semantic/call.cr
Original file line number Diff line number Diff line change
@@ -484,7 +484,7 @@ class Crystal::Call
elsif instance_type.size == 0
raise "index '#{arg}' out of bounds for empty tuple"
else
raise "index out of bounds for tuple #{owner} (#{arg} not in 0..#{instance_type.size - 1})"
raise "index out of bounds for #{owner} (#{arg} not in 0..#{instance_type.size - 1})"
end
end
nil
9 changes: 7 additions & 2 deletions src/compiler/crystal/syntax/parser.cr
Original file line number Diff line number Diff line change
@@ -123,7 +123,12 @@ module Crystal
i += 1

next_token_skip_space_or_newline
exps << (last = parse_op_assign(allow_ops: false))
last = parse_op_assign(allow_ops: false)
if assign_index == -1 && !multi_assign_target?(last)
unexpected_token
end

exps << last
skip_space
end

@@ -163,7 +168,7 @@ module Crystal

def multi_assign_target?(exp)
case exp
when Underscore, Var, InstanceVar, ClassVar, Global, Assign
when Underscore, Var, InstanceVar, ClassVar, Global, Path, Assign
true
when Call
!exp.has_parenthesis && (
Loading

0 comments on commit 26d1f03

Please sign in to comment.