Skip to content

Commit

Permalink
Allow getting a TypeNode's name without type vars
Browse files Browse the repository at this point in the history
  • Loading branch information
Blacksmoke16 committed Jan 7, 2020
1 parent 12a1053 commit 8d2b6e3
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 7 deletions.
60 changes: 56 additions & 4 deletions spec/compiler/macro/macro_methods_spec.cr
Expand Up @@ -11,7 +11,7 @@ private def declare_class_var(container : ClassVarContainer, name, var_type : Ty
end

module Crystal
describe "macro methods" do
describe Macro do
describe "node methods" do
describe "location" do
location = Location.new("foo.cr", 1, 2)
Expand Down Expand Up @@ -1212,9 +1212,61 @@ module Crystal
end
end

it "executes name" do
assert_macro("x", "{{x.name}}", "String") do |program|
[TypeNode.new(program.string)] of ASTNode
describe "#name" do
describe "simple type" do
it "returns the name of the type" do
assert_macro("x", "{{x.name}}", "String") do |program|
[TypeNode.new(program.string)] of ASTNode
end
end
end

describe "namespaced type" do
it "should return the FQN of the type" do
assert_macro("type", "{{type.name}}", "SomeModule::SomeType") do |program|
mod = NonGenericModuleType.new(program, program, "SomeModule")

klass = NonGenericClassType.new(program, mod, "SomeType", program.reference)

[TypeNode.new(klass)] of ASTNode
end
end
end

describe "generic type" do
it "includes the generic_args of the type by default" do
assert_macro("klass", "{{klass.name}}", "SomeType(A, B)") do |program|
[TypeNode.new(GenericClassType.new(program, program, "SomeType", program.object, ["A", "B"]))] of ASTNode
end
end
end

describe :generic_args do
describe true do
it "includes the generic_args of the type" do
assert_macro("klass", "{{klass.name(generic_args: true)}}", "SomeType(A, B)") do |program|
[TypeNode.new(GenericClassType.new(program, program, "SomeType", program.object, ["A", "B"]))] of ASTNode
end
end
end

describe false do
it "does not include the generic_args of the type" do
assert_macro("klass", "{{klass.name(generic_args: false)}}", "SomeType") do |program|
[TypeNode.new(GenericClassType.new(program, program, "SomeType", program.object, ["A", "B"]))] of ASTNode
end
end
end

describe "with an invalid type argument" do
it "should raise the proper exception" do
expect_raises(Crystal::TypeException, "named argument 'generic_args' to TypeNode#name must be a bool, not NumberLiteral") do
assert_macro("x", "{{x.name(generic_args: 99)}}", "String") do |program|
[TypeNode.new(program.string)] of ASTNode
end
end
end
end
end
end

Expand Down
14 changes: 12 additions & 2 deletions src/compiler/crystal/macros.cr
Expand Up @@ -1725,8 +1725,18 @@ module Crystal::Macros
def union_types : ArrayLiteral(TypeNode)
end

# Returns the fully qualified name of this type.
def name : MacroId
# Returns the fully qualified name of this type. Optionally without *generic_args* if `self` is a generic type; see `#type_vars`.
#
# ```
# class Foo(T); end
#
# module Bar::Baz; end
#
# {{Bar::Baz.name}} # => Bar::Baz
# {{Foo.name}} # => Foo(T)
# {{Foo.name(generic_args: false)}} # => Foo
# ```
def name(*, generic_args : BoolLiteral = true) : MacroId
end

# Returns the type variables of the generic type. If the type is not
Expand Down
12 changes: 11 additions & 1 deletion src/compiler/crystal/macros/methods.cr
Expand Up @@ -1519,7 +1519,17 @@ module Crystal
when "union_types"
interpret_argless_method(method, args) { TypeNode.union_types(self) }
when "name"
interpret_argless_method(method, args) { MacroId.new(type.devirtualize.to_s) }
interpret_argless_method(method, args) do
generic_args = if named_args && (generic_arg = named_args["generic_args"]?)
generic_arg
else
BoolLiteral.new true
end

raise "named argument 'generic_args' to TypeNode#name must be a bool, not #{generic_args.class_desc}" unless generic_args.is_a?(BoolLiteral)

MacroId.new(type.devirtualize.to_s(generic_args: generic_args.value))
end
when "type_vars"
interpret_argless_method(method, args) { TypeNode.type_vars(type) }
when "instance_vars"
Expand Down
6 changes: 6 additions & 0 deletions src/compiler/crystal/types.cr
Expand Up @@ -719,6 +719,12 @@ module Crystal
nil
end

def to_s(*, generic_args : Bool = true)
String.build do |io|
to_s_with_options io, generic_args: generic_args
end
end

def inspect(io : IO) : Nil
to_s(io)
end
Expand Down

0 comments on commit 8d2b6e3

Please sign in to comment.