From 10c9c89273ba942f0738d12f56939912a0017b64 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Fri, 16 Dec 2022 08:39:07 -0300 Subject: [PATCH] Add lib functions earlier so that they are visible in top-level macros --- spec/compiler/semantic/lib_spec.cr | 14 ++++++++++++++ src/compiler/crystal/semantic/top_level_visitor.cr | 9 ++++++++- .../crystal/semantic/type_declaration_visitor.cr | 8 ++++---- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/spec/compiler/semantic/lib_spec.cr b/spec/compiler/semantic/lib_spec.cr index 70c2a7b11819..1ee3c7aa99c6 100644 --- a/spec/compiler/semantic/lib_spec.cr +++ b/spec/compiler/semantic/lib_spec.cr @@ -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 diff --git a/src/compiler/crystal/semantic/top_level_visitor.cr b/src/compiler/crystal/semantic/top_level_visitor.cr index a3e4fbdd4a2c..dea95f0f9494 100644 --- a/src/compiler/crystal/semantic/top_level_visitor.cr +++ b/src/compiler/crystal/semantic/top_level_visitor.cr @@ -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| @@ -947,6 +952,8 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor external.fun_def = node node.external = external + current_type.add_def(external) + false end diff --git a/src/compiler/crystal/semantic/type_declaration_visitor.cr b/src/compiler/crystal/semantic/type_declaration_visitor.cr index db557ee6d634..bcb3a63e6eb6 100644 --- a/src/compiler/crystal/semantic/type_declaration_visitor.cr +++ b/src/compiler/crystal/semantic/type_declaration_visitor.cr @@ -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 @@ -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