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: f802c37bf6d6
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: 30a1f96bb685
Choose a head ref
  • 4 commits
  • 11 files changed
  • 1 contributor

Commits on Dec 3, 2016

  1. Compiler: fixed missing variable in macros with type declaration and …

    …uninitialized var
    Ary Borenszweig committed Dec 3, 2016
    Copy the full SHA
    ee85746 View commit details
  2. Copy the full SHA
    a88b931 View commit details
  3. Add Slice.empty

    Ary Borenszweig committed Dec 3, 2016
    Copy the full SHA
    0cf28a8 View commit details
  4. Reformat Reference#pretty_inspect

    Ary Borenszweig committed Dec 3, 2016
    Copy the full SHA
    30a1f96 View commit details
7 changes: 7 additions & 0 deletions spec/compiler/codegen/type_declaration_spec.cr
Original file line number Diff line number Diff line change
@@ -62,4 +62,11 @@ describe "Code gen: type declaration" do
Foo.new.x
)).to_i.should eq(42)
end

it "declares and initializes var" do
run(%(
a : Int32 = 42
a
)).to_i.should eq(42)
end
end
7 changes: 0 additions & 7 deletions spec/compiler/semantic/instance_var_spec.cr
Original file line number Diff line number Diff line change
@@ -4240,13 +4240,6 @@ describe "Semantic: instance var" do
"can't declare variable of generic non-instantiated type Foo"
end

it "errors (for now) when typing a local variable" do
assert_error %(
x : Int32
),
"declaring the type of a local variable is not yet supported"
end

it "errors when typing an instance variable inside a method" do
assert_error %(
def foo
11 changes: 11 additions & 0 deletions spec/compiler/semantic/macro_spec.cr
Original file line number Diff line number Diff line change
@@ -947,4 +947,15 @@ describe "Semantic: macro" do
),
"undefined method 'foo'"
end

it "uses uninitialized variable with macros" do
assert_type(%(
macro foo(x)
{{x}}
end
a = uninitialized Int32
foo(a)
)) { int32 }
end
end
64 changes: 63 additions & 1 deletion spec/compiler/semantic/var_spec.cr
Original file line number Diff line number Diff line change
@@ -42,7 +42,7 @@ describe "Semantic: var" do

it "reports variable always nil" do
assert_error "1 == 2 ? (a = 1) : a",
"read before definition of local variable 'a'"
"read before assignment to local variable 'a'"
end

it "lets type on else side of if with a Bool | Nil union" do
@@ -66,4 +66,66 @@ describe "Semantic: var" do
),
"can't read from _"
end

it "declares local variable with value" do
assert_type(%(
a : Int32 = 0
a
)) { int32 }
end

it "declares local variable and then assigns it" do
assert_type(%(
a : Int32
a = 0
a
)) { int32 }
end

it "declares local variable and immediately reads it" do
assert_error %(
a : Int32
a
),
"read before assignment to local variable 'a'"
end

it "declares local variable and assigns it with if" do
assert_type(%(
a : Int32
if 1 == 2
a = 0
else
a = 1
end
a
)) { int32 }
end

it "declares local variable but doesn't assign it in all branches" do
assert_error %(
a : Int32
if 1 == 2
a = 0
end
a
),
"type must be Int32"
end

it "declares local variable and assigns wrong type" do
assert_error %(
a : Int32
a = true
),
"type must be Int32"
end

it "errors if variable already exists" do
assert_error %(
a = true
a : Int32
),
"variable 'a' already declared"
end
end
5 changes: 5 additions & 0 deletions spec/std/slice_spec.cr
Original file line number Diff line number Diff line change
@@ -357,6 +357,11 @@ describe "Slice" do
b = [1, 2, 3]
3.times { a.includes?(b.shift).should be_true }
end

it "creates empty slice" do
slice = Slice(Int32).empty
slice.empty?.should be_true
end
end

private def itself(*args)
30 changes: 19 additions & 11 deletions src/compiler/crystal/codegen/codegen.cr
Original file line number Diff line number Diff line change
@@ -833,20 +833,24 @@ module Crystal
return false if node.discarded?

target, value = node.target, node.value
codegen_assign(target, value, node)
end

case target
when Underscore
accept value
return false
when Path
const = target.target_const.not_nil!
if const.used? && !const.simple?
initialize_const(const)
end
@last = llvm_nil
return false
def codegen_assign(target : Underscore, value, node)
accept value
false
end

def codegen_assign(target : Path, value, node)
const = target.target_const.not_nil!
if const.used? && !const.simple?
initialize_const(const)
end
@last = llvm_nil
false
end

def codegen_assign(target, value, node)
target_type = target.type?

# This means it's an instance variable initialize of a generic type,
@@ -995,6 +999,10 @@ module Crystal
case var
when Var
declare_var var

if value = node.value
codegen_assign(var, value, node)
end
when Global
if value = node.value
request_value do
28 changes: 25 additions & 3 deletions src/compiler/crystal/semantic/main_visitor.cr
Original file line number Diff line number Diff line change
@@ -336,14 +336,36 @@ module Crystal
special_var = define_special_var(node.name, program.nil_var)
node.bind_to special_var
else
node.raise "read before definition of local variable '#{node.name}'"
node.raise "read before assignment to local variable '#{node.name}'"
end
end

def visit(node : TypeDeclaration)
case var = node.var
when Var
node.raise "declaring the type of a local variable is not yet supported"
if @meta_vars[var.name]?
node.raise "variable '#{var.name}' already declared"
end

meta_var = new_meta_var(var.name)
meta_var.type = @program.no_return

var.bind_to(meta_var)
@meta_vars[var.name] = meta_var

@in_type_args += 1
node.declared_type.accept self
@in_type_args -= 1

if declared_type = node.declared_type.type?
meta_var.freeze_type = declared_type
else
node.raise "can't infer type of type declaration"
end

if value = node.value
type_assign(var, value, node)
end
when InstanceVar
if @untyped_def
node.raise "declaring the type of an instance variable must be done at the class level"
@@ -398,7 +420,7 @@ module Crystal
var_type = check_declare_var_type node, declared_type, "a variable"
var.type = var_type
else
var.type = program.no_return
node.raise "can't infer type of type declaration"
end

meta_var = @meta_vars[var.name] ||= new_meta_var(var.name)
12 changes: 11 additions & 1 deletion src/compiler/crystal/semantic/top_level_visitor.cr
Original file line number Diff line number Diff line change
@@ -711,7 +711,17 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor
false
end

def visit(node : TypeDeclaration | UninitializedVar)
def visit(node : TypeDeclaration)
if (var = node.var).is_a?(Var)
@vars[var.name] = MetaVar.new(var.name)
end
false
end

def visit(node : UninitializedVar)
if (var = node.var).is_a?(Var)
@vars[var.name] = MetaVar.new(var.name)
end
false
end

7 changes: 1 addition & 6 deletions src/compiler/crystal/semantic/type_declaration_visitor.cr
Original file line number Diff line number Diff line change
@@ -149,12 +149,7 @@ class Crystal::TypeDeclarationVisitor < Crystal::SemanticVisitor
def visit(node : TypeDeclaration)
case var = node.var
when Var
if @in_c_struct_or_union
declare_c_struct_or_union_field(node)
return false
end

node.raise "declaring the type of a local variable is not yet supported"
declare_c_struct_or_union_field(node) if @in_c_struct_or_union
when InstanceVar
declare_instance_var(node, var)
when ClassVar
20 changes: 10 additions & 10 deletions src/reference.cr
Original file line number Diff line number Diff line change
@@ -77,17 +77,17 @@ class Reference
executed = exec_recursive(:pretty_print) do
pp.surround(prefix, ">", left_break: " ", right_break: nil) do
{% for ivar, i in @type.instance_vars.map(&.name).sort %}
{% if i > 0 %}
pp.comma
{% end %}
pp.group do
pp.text "@{{ivar.id}}="
pp.nest do
pp.breakable ""
@{{ivar.id}}.pretty_print(pp)
end
end
{% if i > 0 %}
pp.comma
{% end %}
pp.group do
pp.text "@{{ivar.id}}="
pp.nest do
pp.breakable ""
@{{ivar.id}}.pretty_print(pp)
end
end
{% end %}
end
end
unless executed
10 changes: 10 additions & 0 deletions src/slice.cr
Original file line number Diff line number Diff line change
@@ -113,6 +113,16 @@ struct Slice(T)
new(size) { value }
end

# Creates an empty slice.
#
# ```
# slice = Slice(UInt8).empty
# slice.size # => 0
# ```
def self.empty
new(Pointer(T).null, 0)
end

# Returns a new slice that i *offset* elements apart from this slice.
#
# ```