Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add lib functions earlier so that they are visible in top-level macros #12848

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions spec/compiler/semantic/lib_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -962,4 +962,18 @@ describe "Semantic: lib" do
),
"passing Void return value of lib fun call has no effect"
end

it "can list lib functions at the top level (#12395)" do
assert_type(%(
lib LibFoo
fun foo
end

{% if LibFoo.methods.size == 1 %}
true
{% else %}
1
{% end %}
)) { bool }
end
end
9 changes: 8 additions & 1 deletion src/compiler/crystal/semantic/top_level_visitor.cr
Original file line number Diff line number Diff line change
Expand Up @@ -914,7 +914,12 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor

annotations = read_annotations

external = External.new(node.name, ([] of Arg), node.body, node.real_name).at(node)
# We'll resolve the external args types later, in TypeDeclarationVisitor
external_args = node.args.map do |arg|
Arg.new(arg.name).at(arg.location)
end

external = External.new(node.name, external_args, node.body, node.real_name).at(node)

call_convention = nil
process_def_annotations(external, annotations) do |annotation_type, ann|
Expand Down Expand Up @@ -947,6 +952,8 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor
external.fun_def = node
node.external = external

current_type.add_def(external)

false
end

Expand Down
8 changes: 4 additions & 4 deletions src/compiler/crystal/semantic/type_declaration_visitor.cr
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,16 @@ class Crystal::TypeDeclarationVisitor < Crystal::SemanticVisitor
def visit(node : FunDef)
external = node.external

node.args.each do |arg|
node.args.each_with_index do |arg, index|
restriction = arg.restriction.not_nil!
arg_type = lookup_type(restriction)
arg_type = check_allowed_in_lib(restriction, arg_type)
if arg_type.remove_typedef.void?
restriction.raise "can't use Void as parameter type"
end
external.args << Arg.new(arg.name, type: arg_type).at(arg.location)

# The external args were added in TopLevelVisitor
external.args[index].type = arg_type
end

node_return_type = node.return_type
Expand All @@ -131,8 +133,6 @@ class Crystal::TypeDeclarationVisitor < Crystal::SemanticVisitor
old_external = add_external external
old_external.dead = true if old_external

current_type.add_def(external)

if current_type.is_a?(Program)
key = DefInstanceKey.new external.object_id, external.args.map(&.type), nil, nil
program.add_def_instance key, external
Expand Down