Explorar el Código

Add import support for ImportRefUsed, for aliases. (#3878)

Note the "Cannot implicitly convert from `C*` to `C*`." error is what I
would aim to fix next. This is what had spawned the discussion of
whether to use name scopes to merge difficult-to-relate names. But I
think that's going to take more substantially more work, so the small
improvement for now.
Jon Ross-Perkins hace 2 años
padre
commit
f5e33f8b05

+ 24 - 0
toolchain/check/import_ref.cpp

@@ -415,6 +415,9 @@ class ImportRefResolver {
       case CARBON_KIND(SemIR::FunctionDecl inst): {
       case CARBON_KIND(SemIR::FunctionDecl inst): {
         return TryResolveTypedInst(inst);
         return TryResolveTypedInst(inst);
       }
       }
+      case CARBON_KIND(SemIR::ImportRefUsed inst): {
+        return TryResolveTypedInst(inst, inst_id);
+      }
       case CARBON_KIND(SemIR::InterfaceDecl inst): {
       case CARBON_KIND(SemIR::InterfaceDecl inst): {
         return TryResolveTypedInst(inst, const_id);
         return TryResolveTypedInst(inst, const_id);
       }
       }
@@ -742,6 +745,27 @@ class ImportRefResolver {
     return {context_.constant_values().Get(function_decl_id)};
     return {context_.constant_values().Get(function_decl_id)};
   }
   }
 
 
+  auto TryResolveTypedInst(SemIR::ImportRefUsed /*inst*/, SemIR::InstId inst_id)
+      -> ResolveResult {
+    auto initial_work = work_stack_.size();
+    // Return the constant for the instruction of the imported constant.
+    auto constant_id = import_ir_.constant_values().Get(inst_id);
+    if (!constant_id.is_valid()) {
+      return {SemIR::ConstantId::Error};
+    }
+    if (!constant_id.is_constant()) {
+      context_.TODO(inst_id, "Non-constant ImportRefUsed (comes up with var)");
+      return {SemIR::ConstantId::Error};
+    }
+
+    auto new_constant_id = GetLocalConstantId(constant_id.inst_id());
+    if (HasNewWork(initial_work)) {
+      return ResolveResult::Retry();
+    }
+
+    return {new_constant_id};
+  }
+
   // Make a declaration of an interface. This is done as a separate step from
   // Make a declaration of an interface. This is done as a separate step from
   // importing the interface definition in order to resolve cycles.
   // importing the interface definition in order to resolve cycles.
   auto MakeInterfaceDecl(const SemIR::Interface& import_interface)
   auto MakeInterfaceDecl(const SemIR::Interface& import_interface)

+ 184 - 16
toolchain/check/testdata/alias/import.carbon

@@ -4,39 +4,180 @@
 //
 //
 // AUTOUPDATE
 // AUTOUPDATE
 
 
-// --- a.carbon
+// --- class1.carbon
 
 
-library "a" api;
+library "class1" api;
+
+class C {}
+
+alias c_alias = C;
+
+var a: C*;
+
+// --- class2.carbon
+
+library "class2" api;
+
+import library "class1";
+
+alias c_alias_alias = c_alias;
+
+var b: c_alias*;
+
+// --- class3.carbon
+
+library "class3" api;
+
+import library "class2";
+
+var c: c_alias_alias*;
+
+// --- var1.carbon
+
+library "var1" api;
 
 
 var a: i32 = 0;
 var a: i32 = 0;
 
 
-alias b = a;
+alias a_alias = a;
+
+// --- var2.carbon
 
 
-// --- b.carbon
+library "var2" api;
 
 
-library "b" api;
+import library "var1";
 
 
-import library "a";
+alias a_alias_alias = a_alias;
 
 
-var c: i32 = b;
+var b: i32 = a_alias;
 
 
-// CHECK:STDOUT: --- a.carbon
+// --- fail_var3.carbon
+
+library "var3" api;
+
+// CHECK:STDERR: fail_var3.carbon:[[@LINE+6]]:1: In import.
+// CHECK:STDERR: import library "var2";
+// CHECK:STDERR: ^~~~~~
+// CHECK:STDERR: var2.carbon:8:5: ERROR: Semantics TODO: `Non-constant ImportRefUsed (comes up with var)`.
+// CHECK:STDERR: var b: i32 = a_alias;
+// CHECK:STDERR:     ^
+import library "var2";
+
+var c: i32 = a_alias_alias;
+
+// CHECK:STDOUT: --- class1.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT: constants {
-// CHECK:STDOUT:   %.1: i32 = int_literal 0 [template]
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %.2: type = ptr_type C [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
 // CHECK:STDOUT:     .Core = %Core
 // CHECK:STDOUT:     .Core = %Core
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .c_alias = %c_alias
 // CHECK:STDOUT:     .a = %a
 // CHECK:STDOUT:     .a = %a
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %C.ref.loc6: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %c_alias: type = bind_alias c_alias, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %C.ref.loc8: type = name_ref C, %C.decl [template = constants.%C]
+// CHECK:STDOUT:   %.loc8: type = ptr_type C [template = constants.%.2]
+// CHECK:STDOUT:   %a.var: ref C* = var a
+// CHECK:STDOUT:   %a: ref C* = bind_name a, %a.var
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- class2.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %.2: type = ptr_type C [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %import_ref.1
+// CHECK:STDOUT:     .c_alias = %import_ref.2
+// CHECK:STDOUT:     .a = %import_ref.3
+// CHECK:STDOUT:     .Core = %Core
+// CHECK:STDOUT:     .c_alias_alias = %c_alias_alias
 // CHECK:STDOUT:     .b = %b
 // CHECK:STDOUT:     .b = %b
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   }
+// CHECK:STDOUT:   %import_ref.1 = import_ref ir2, inst+2, unloaded
+// CHECK:STDOUT:   %import_ref.2: type = import_ref ir2, inst+6, loc_12 [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.3 = import_ref ir2, inst+11, unloaded
+// CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
+// CHECK:STDOUT:   %C.decl: invalid = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %import_ref.4 = import_ref ir2, inst+3, unloaded
+// CHECK:STDOUT:   %c_alias.ref.loc6: type = name_ref c_alias, %import_ref.2 [template = constants.%C]
+// CHECK:STDOUT:   %c_alias_alias: type = bind_alias c_alias_alias, %import_ref.2 [template = constants.%C]
+// CHECK:STDOUT:   %c_alias.ref.loc8: type = name_ref c_alias, %import_ref.2 [template = constants.%C]
+// CHECK:STDOUT:   %.loc8: type = ptr_type C [template = constants.%.2]
+// CHECK:STDOUT:   %b.var: ref C* = var b
+// CHECK:STDOUT:   %b: ref C* = bind_name b, %b.var
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = file.%import_ref.4
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- class3.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %.2: type = ptr_type C [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .c_alias_alias = %import_ref.1
+// CHECK:STDOUT:     .b = %import_ref.2
+// CHECK:STDOUT:     .Core = %Core
+// CHECK:STDOUT:     .c = %c
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %import_ref.1: type = import_ref ir2, inst+10, loc_11 [template = constants.%C]
+// CHECK:STDOUT:   %import_ref.2 = import_ref ir2, inst+15, unloaded
+// CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
+// CHECK:STDOUT:   %C.decl: invalid = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %import_ref.3 = import_ref ir2, inst+8, unloaded
+// CHECK:STDOUT:   %c_alias_alias.ref: type = name_ref c_alias_alias, %import_ref.1 [template = constants.%C]
+// CHECK:STDOUT:   %.loc6: type = ptr_type C [template = constants.%.2]
+// CHECK:STDOUT:   %c.var: ref C* = var c
+// CHECK:STDOUT:   %c: ref C* = bind_name c, %c.var
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = file.%import_ref.3
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- var1.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %.1: i32 = int_literal 0 [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = %Core
+// CHECK:STDOUT:     .a = %a
+// CHECK:STDOUT:     .a_alias = %a_alias
+// CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
 // CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
 // CHECK:STDOUT:   %a.var: ref i32 = var a
 // CHECK:STDOUT:   %a.var: ref i32 = var a
 // CHECK:STDOUT:   %a: ref i32 = bind_name a, %a.var
 // CHECK:STDOUT:   %a: ref i32 = bind_name a, %a.var
 // CHECK:STDOUT:   %a.ref: ref i32 = name_ref a, %a
 // CHECK:STDOUT:   %a.ref: ref i32 = name_ref a, %a
-// CHECK:STDOUT:   %b: ref i32 = bind_alias b, %a
+// CHECK:STDOUT:   %a_alias: ref i32 = bind_alias a_alias, %a
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: fn @__global_init() {
@@ -46,17 +187,44 @@ var c: i32 = b;
 // CHECK:STDOUT:   return
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT:
-// CHECK:STDOUT: --- b.carbon
+// CHECK:STDOUT: --- var2.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
 // CHECK:STDOUT:     .a = %import_ref.1
 // CHECK:STDOUT:     .a = %import_ref.1
+// CHECK:STDOUT:     .a_alias = %import_ref.2
+// CHECK:STDOUT:     .Core = %Core
+// CHECK:STDOUT:     .a_alias_alias = %a_alias_alias
+// CHECK:STDOUT:     .b = %b
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %import_ref.1 = import_ref ir2, inst+3, unloaded
+// CHECK:STDOUT:   %import_ref.2: ref i32 = import_ref ir2, inst+8, loc_12
+// CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
+// CHECK:STDOUT:   %a_alias.ref: ref i32 = name_ref a_alias, %import_ref.2
+// CHECK:STDOUT:   %a_alias_alias: ref i32 = bind_alias a_alias_alias, %import_ref.2
+// CHECK:STDOUT:   %b.var: ref i32 = var b
+// CHECK:STDOUT:   %b: ref i32 = bind_name b, %b.var
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @__global_init() {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %a_alias.ref: ref i32 = name_ref a_alias, file.%import_ref.2
+// CHECK:STDOUT:   %.loc8: i32 = bind_value %a_alias.ref
+// CHECK:STDOUT:   assign file.%b.var, %.loc8
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_var3.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .a_alias_alias = %import_ref.1
 // CHECK:STDOUT:     .b = %import_ref.2
 // CHECK:STDOUT:     .b = %import_ref.2
 // CHECK:STDOUT:     .Core = %Core
 // CHECK:STDOUT:     .Core = %Core
 // CHECK:STDOUT:     .c = %c
 // CHECK:STDOUT:     .c = %c
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.1 = import_ref ir2, inst+3, unloaded
-// CHECK:STDOUT:   %import_ref.2: ref i32 = import_ref ir2, inst+8, loc_14
+// CHECK:STDOUT:   %import_ref.1: ref i32 = import_ref ir2, inst+5, loc_14 [template = <error>]
+// CHECK:STDOUT:   %import_ref.2 = import_ref ir2, inst+7, unloaded
 // CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
 // CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
 // CHECK:STDOUT:   %c.var: ref i32 = var c
 // CHECK:STDOUT:   %c.var: ref i32 = var c
 // CHECK:STDOUT:   %c: ref i32 = bind_name c, %c.var
 // CHECK:STDOUT:   %c: ref i32 = bind_name c, %c.var
@@ -64,9 +232,9 @@ var c: i32 = b;
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %b.ref: ref i32 = name_ref b, file.%import_ref.2
-// CHECK:STDOUT:   %.loc6: i32 = bind_value %b.ref
-// CHECK:STDOUT:   assign file.%c.var, %.loc6
+// CHECK:STDOUT:   %a_alias_alias.ref: ref i32 = name_ref a_alias_alias, file.%import_ref.1 [template = <error>]
+// CHECK:STDOUT:   %.loc12: i32 = bind_value %a_alias_alias.ref
+// CHECK:STDOUT:   assign file.%c.var, %.loc12
 // CHECK:STDOUT:   return
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT:

+ 171 - 0
toolchain/check/testdata/class/import_triangle.carbon

@@ -0,0 +1,171 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// AUTOUPDATE
+
+// --- a.carbon
+
+library "a" api;
+
+class C {}
+
+// --- b.carbon
+
+library "b" api;
+
+import library "a";
+
+alias D = C;
+
+var c1: C = {};
+var d1: D* = &c1;
+
+// --- fail_c.carbon
+
+library "c" api;
+
+import library "a";
+import library "b";
+
+var c2: C = {};
+// CHECK:STDERR: fail_c.carbon:[[@LINE+3]]:1: ERROR: Cannot implicitly convert from `C*` to `C*`.
+// CHECK:STDERR: var d2: D* = &c2;
+// CHECK:STDERR: ^~~~~~~~~~~~~~~~~
+var d2: D* = &c2;
+
+// CHECK:STDOUT: --- a.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = %Core
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- b.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %.3: type = ptr_type {} [template]
+// CHECK:STDOUT:   %.4: C = struct_value () [template]
+// CHECK:STDOUT:   %.5: type = ptr_type C [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %import_ref.1
+// CHECK:STDOUT:     .Core = %Core
+// CHECK:STDOUT:     .D = %D
+// CHECK:STDOUT:     .c1 = %c1
+// CHECK:STDOUT:     .d1 = %d1
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %import_ref.1: type = import_ref ir2, inst+2, loc_12 [template = constants.%C]
+// CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
+// CHECK:STDOUT:   %C.decl: invalid = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT:   %import_ref.2 = import_ref ir2, inst+3, unloaded
+// CHECK:STDOUT:   %C.ref.loc6: type = name_ref C, %import_ref.1 [template = constants.%C]
+// CHECK:STDOUT:   %D: type = bind_alias D, %import_ref.1 [template = constants.%C]
+// CHECK:STDOUT:   %C.ref.loc8: type = name_ref C, %import_ref.1 [template = constants.%C]
+// CHECK:STDOUT:   %c1.var: ref C = var c1
+// CHECK:STDOUT:   %c1: ref C = bind_name c1, %c1.var
+// CHECK:STDOUT:   %D.ref: type = name_ref D, %D [template = constants.%C]
+// CHECK:STDOUT:   %.loc9: type = ptr_type C [template = constants.%.5]
+// CHECK:STDOUT:   %d1.var: ref C* = var d1
+// CHECK:STDOUT:   %d1: ref C* = bind_name d1, %d1.var
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = file.%import_ref.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @__global_init() {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %.loc8_14.1: {} = struct_literal ()
+// CHECK:STDOUT:   %.loc8_14.2: init C = class_init (), file.%c1.var [template = constants.%.4]
+// CHECK:STDOUT:   %.loc8_14.3: init C = converted %.loc8_14.1, %.loc8_14.2 [template = constants.%.4]
+// CHECK:STDOUT:   assign file.%c1.var, %.loc8_14.3
+// CHECK:STDOUT:   %c1.ref: ref C = name_ref c1, file.%c1
+// CHECK:STDOUT:   %.loc9: C* = addr_of %c1.ref
+// CHECK:STDOUT:   assign file.%d1.var, %.loc9
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_c.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C.1: type = class_type @C.1 [template]
+// CHECK:STDOUT:   %.1: type = struct_type {} [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %.3: type = ptr_type {} [template]
+// CHECK:STDOUT:   %.4: C = struct_value () [template]
+// CHECK:STDOUT:   %C.2: type = class_type @C.2 [template]
+// CHECK:STDOUT:   %.5: type = ptr_type C [template]
+// CHECK:STDOUT:   %.6: type = ptr_type C [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .C = %import_ref.1
+// CHECK:STDOUT:     .D = %import_ref.2
+// CHECK:STDOUT:     .c1 = %import_ref.3
+// CHECK:STDOUT:     .d1 = %import_ref.4
+// CHECK:STDOUT:     .Core = %Core
+// CHECK:STDOUT:     .c2 = %c2
+// CHECK:STDOUT:     .d2 = %d2
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %import_ref.1: type = import_ref ir2, inst+2, loc_15 [template = constants.%C.1]
+// CHECK:STDOUT:   %import_ref.2: type = import_ref ir3, inst+8, loc_23 [template = constants.%C.2]
+// CHECK:STDOUT:   %import_ref.3 = import_ref ir3, inst+13, unloaded
+// CHECK:STDOUT:   %import_ref.4 = import_ref ir3, inst+23, unloaded
+// CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
+// CHECK:STDOUT:   %C.decl.1: invalid = class_decl @C.1 [template = constants.%C.1] {}
+// CHECK:STDOUT:   %import_ref.5 = import_ref ir2, inst+3, unloaded
+// CHECK:STDOUT:   %C.ref: type = name_ref C, %import_ref.1 [template = constants.%C.1]
+// CHECK:STDOUT:   %c2.var: ref C = var c2
+// CHECK:STDOUT:   %c2: ref C = bind_name c2, %c2.var
+// CHECK:STDOUT:   %C.decl.2: invalid = class_decl @C.2 [template = constants.%C.2] {}
+// CHECK:STDOUT:   %import_ref.6 = import_ref ir3, inst+6, unloaded
+// CHECK:STDOUT:   %D.ref: type = name_ref D, %import_ref.2 [template = constants.%C.2]
+// CHECK:STDOUT:   %.loc11: type = ptr_type C [template = constants.%.5]
+// CHECK:STDOUT:   %d2.var: ref C* = var d2
+// CHECK:STDOUT:   %d2: ref C* = bind_name d2, %d2.var
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C.1 {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = file.%import_ref.5
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C.2 {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = file.%import_ref.6
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @__global_init() {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %.loc7_14.1: {} = struct_literal ()
+// CHECK:STDOUT:   %.loc7_14.2: init C = class_init (), file.%c2.var [template = constants.%.4]
+// CHECK:STDOUT:   %.loc7_14.3: init C = converted %.loc7_14.1, %.loc7_14.2 [template = constants.%.4]
+// CHECK:STDOUT:   assign file.%c2.var, %.loc7_14.3
+// CHECK:STDOUT:   %c2.ref: ref C = name_ref c2, file.%c2
+// CHECK:STDOUT:   %.loc11: C* = addr_of %c2.ref
+// CHECK:STDOUT:   assign file.%d2.var, <error>
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT: