Skip to content

Commit

Permalink
Allow a path to declare a constant (crystal-lang#5883)
Browse files Browse the repository at this point in the history
* Allow a path to declare a constant

* Add spec for type keeping when creating a constant using a Path
  • Loading branch information
bew authored and RX14 committed Mar 30, 2018
1 parent f33a910 commit 5cd78fa
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 6 deletions.
70 changes: 68 additions & 2 deletions spec/compiler/semantic/const_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ require "../../spec_helper"
describe "Semantic: const" do
it "types a constant" do
input = parse("CONST = 1").as(Assign)
result = semantic input
mod = result.program
semantic input
input.target.type?.should be_nil # Don't type value until needed
end

Expand All @@ -16,6 +15,73 @@ describe "Semantic: const" do
assert_type("class Foo; A = 1; end; Foo::A") { int32 }
end

it "types a constant using Path" do
assert_type(%(
Foo::Bar = 1
Foo::Bar
)) { int32 }
end

it "types a nested constant using Path" do
assert_type(%(
class Foo
Bar::Baz = 1
end
Foo::Bar::Baz
)) { int32 }
end

it "creates container module if not exist when using Path" do
assert_type(%(
Foo::Bar = 1
Foo
)) do
foo = types["Foo"]
foo.module?.should be_true
foo.metaclass
end
end

it "keeps type of container when using Path" do
assert_type(%(
class Foo
end
Foo::Const = 1
Foo
)) do
foo = types["Foo"]
foo.class?.should be_true
foo.metaclass
end

assert_type(%(
struct Foo
end
Foo::Const = 1
Foo
)) do
foo = types["Foo"]
foo.struct?.should be_true
foo.metaclass
end

assert_type(%(
module Foo
end
Foo::Const = 1
Foo
)) do
foo = types["Foo"]
foo.module?.should be_true
foo.metaclass
end
end

it "types a constant inside a def" do
assert_type("
class Foo
Expand Down
8 changes: 4 additions & 4 deletions src/compiler/crystal/semantic/top_level_visitor.cr
Original file line number Diff line number Diff line change
Expand Up @@ -647,18 +647,18 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor
check_outside_exp node, "declare constant"
@exp_nest += 1

scope = current_type_scope(target)
scope, name = lookup_type_def_name(target)

type = scope.types[target.names.first]?
type = scope.types[name]?
if type
target.raise "already initialized constant #{type}"
end

const = Const.new(@program, scope, target.names.first, value)
const = Const.new(@program, scope, name, value)
const.private = true if target.visibility.private?
attach_doc const, node

scope.types[target.names.first] = const
scope.types[name] = const

target.target_const = const
end
Expand Down

0 comments on commit 5cd78fa

Please sign in to comment.