Skip to content

Commit

Permalink
Fix TopLevelVisitor adding existing ClassDef type to current scope (
Browse files Browse the repository at this point in the history
#15067)

When a type is reopened, the compiler adds it as nested type to the current scope (i.e. where it's reopened). That's wrong because the reopened type is already scoped to the location of the original location and this could lead to cycles.

For example, the following program would crash the compiler with an infinite recursion:
```cr
class Foo
  alias Bar = Foo

  class Bar
  end
end
```

This fix makes sure to only add newly defined types to the current scope, not reopened ones. All other visitor methods which defined types already do this, only `ClassDef` was unconditionally adding to the current scope.
  • Loading branch information
straight-shoota authored Oct 8, 2024
1 parent 401eb47 commit dddc0dc
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 1 deletion.
16 changes: 16 additions & 0 deletions spec/compiler/semantic/alias_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,22 @@ describe "Semantic: alias" do
Bar.bar
)) { int32 }
end

it "reopens #{type} through alias within itself" do
assert_type <<-CRYSTAL { int32 }
#{type} Foo
alias Bar = Foo
#{type} Bar
def self.bar
1
end
end
end
Foo.bar
CRYSTAL
end
end

%w(class struct).each do |type|
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/crystal/semantic/top_level_visitor.cr
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,9 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor
if superclass.is_a?(GenericClassInstanceType)
superclass.generic_type.add_subclass(type)
end
scope.types[name] = type
end

scope.types[name] = type
node.resolved_type = type

process_annotations(annotations) do |annotation_type, ann|
Expand Down

0 comments on commit dddc0dc

Please sign in to comment.