From 29e1b711dc76efec1265f7e3ad2983c68b8c837d Mon Sep 17 00:00:00 2001 From: Quinton Miller Date: Mon, 24 Feb 2025 03:49:28 +0800 Subject: [PATCH] Add file name to file-private metaclass types during codegen (#15505) File-private types with the same name get collapsed into a single type during codegen, which messes up any dispatch over them: only one of their type IDs is considered, and the other is assumed to be unreachable. Adding the file name as namespace keeps them apart. --- spec/compiler/codegen/class_spec.cr | 32 +++++++++++++++++++++++++++++ src/compiler/crystal/types.cr | 6 ++++++ 2 files changed, 38 insertions(+) diff --git a/spec/compiler/codegen/class_spec.cr b/spec/compiler/codegen/class_spec.cr index c6c697f29e29..e16788d453b4 100644 --- a/spec/compiler/codegen/class_spec.cr +++ b/spec/compiler/codegen/class_spec.cr @@ -659,6 +659,38 @@ describe "Code gen: class" do )).to_string.should eq("Baz") end + it "does not combine types with same name but different file scopes (#15503)" do + run(<<-CRYSTAL, Int32, filename: "foo.cr").should eq(11) + module Foo + def self.foo + 1 + end + end + + alias Bar = Foo + + {% Bar %} # forces immediate resolution of `Bar` + + private module Foo + def self.foo + 10 + end + end + + module Baz + def self.foo + 100 + end + end + + def foo(x) + x.foo + end + + foo(Foo || Baz) &+ foo(Bar || Baz) + CRYSTAL + end + it "builds generic class bug" do codegen(%( abstract class Base diff --git a/src/compiler/crystal/types.cr b/src/compiler/crystal/types.cr index 7df02924793f..dc2be80b0ae2 100644 --- a/src/compiler/crystal/types.cr +++ b/src/compiler/crystal/types.cr @@ -2935,6 +2935,12 @@ module Crystal end def to_s_with_options(io : IO, skip_union_parens : Bool = false, generic_args : Bool = true, codegen : Bool = false) : Nil + if codegen + if (namespace = instance_type.namespace).is_a?(FileModule) + namespace.to_s_with_options(io, generic_args: false, codegen: codegen) + io << "::" + end + end io << @name end