From 725e80f0d3d3b6e9187b85fe9b2264c147016efb Mon Sep 17 00:00:00 2001 From: josh11b <15258583+josh11b@users.noreply.github.com> Date: Thu, 2 Jan 2025 15:56:43 -0800 Subject: [PATCH] Fix a bug importing declarations in generics (#4752) Imported declarations that are contained within a generic, such as an `impl forall...` would be given an abstract symbolic constant value instead of a concrete generic value in some cases where the function was used in an api file and impl file of the same library. This caused #4679 to fail using `ImplicitAs.Convert` transitively imported from the prelude. --------- Co-authored-by: Josh L Co-authored-by: Richard Smith --- toolchain/check/import_ref.cpp | 55 ++++++++----- .../testdata/class/generic/import.carbon | 34 ++++---- toolchain/check/testdata/struct/import.carbon | 77 +++++-------------- toolchain/check/testdata/tuple/import.carbon | 77 +++++-------------- 4 files changed, 89 insertions(+), 154 deletions(-) diff --git a/toolchain/check/import_ref.cpp b/toolchain/check/import_ref.cpp index 9760a9d524071..f8fc7d01358c4 100644 --- a/toolchain/check/import_ref.cpp +++ b/toolchain/check/import_ref.cpp @@ -187,6 +187,8 @@ class ImportRefResolver; struct ResolveResult { // The new constant value, if known. SemIR::ConstantId const_id; + // Newly created declaration whose value is being resolved, if any. + SemIR::InstId decl_id = SemIR::InstId::Invalid; // Whether resolution has been attempted once and needs to be retried. bool retry = false; @@ -194,15 +196,18 @@ struct ResolveResult { // `const_id` is specified, then this is the end of the second phase, and the // constant value will be passed to the next resolution attempt. Otherwise, // this is the end of the first phase. - static auto Retry(SemIR::ConstantId const_id = SemIR::ConstantId::Invalid) + static auto Retry(SemIR::ConstantId const_id = SemIR::ConstantId::Invalid, + SemIR::InstId decl_id = SemIR::InstId::Invalid) -> ResolveResult { - return {.const_id = const_id, .retry = true}; + return {.const_id = const_id, .decl_id = decl_id, .retry = true}; } // Produces a resolve result that provides the given constant value. Requires // that there is no new work. - static auto Done(SemIR::ConstantId const_id) -> ResolveResult { - return {.const_id = const_id}; + static auto Done(SemIR::ConstantId const_id, + SemIR::InstId decl_id = SemIR::InstId::Invalid) + -> ResolveResult { + return {.const_id = const_id, .decl_id = decl_id}; } }; } // namespace @@ -455,7 +460,7 @@ class ImportRefResolver : public ImportContext { // Step 2: resolve the instruction. initial_work_ = work_stack_.size(); - auto [new_const_id, retry] = + auto [new_const_id, _, retry] = TryResolveInst(*this, work.inst_id, existing.const_id); CARBON_CHECK(!HasNewWork() || retry); @@ -1309,7 +1314,8 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver, resolver.local_context().MakeImportedLocAndInst( AddImportIRInst(resolver, import_inst_id), {.adapted_type_inst_id = adapted_type_inst_id})); - return ResolveResult::Done(resolver.local_constant_values().Get(inst_id)); + return ResolveResult::Done(resolver.local_constant_values().Get(inst_id), + inst_id); } static auto TryResolveTypedInst(ImportRefResolver& resolver, @@ -1389,7 +1395,8 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver, resolver.local_context().GetTypeIdForTypeConstant(type_const_id), .base_type_inst_id = base_type_inst_id, .index = inst.index})); - return ResolveResult::Done(resolver.local_constant_values().Get(inst_id)); + return ResolveResult::Done(resolver.local_constant_values().Get(inst_id), + inst_id); } static auto TryResolveTypedInst(ImportRefResolver& resolver, @@ -1602,12 +1609,12 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver, auto adapt_id = import_class.adapt_id.is_valid() ? GetLocalConstantInstId(resolver, import_class.adapt_id) : SemIR::InstId::Invalid; + auto& new_class = resolver.local_classes().Get(class_id); if (resolver.HasNewWork()) { - return ResolveResult::Retry(class_const_id); + return ResolveResult::Retry(class_const_id, new_class.first_decl_id()); } - auto& new_class = resolver.local_classes().Get(class_id); new_class.parent_scope_id = parent_scope_id; new_class.implicit_param_patterns_id = GetLocalParamPatternsId( resolver, import_class.implicit_param_patterns_id); @@ -1628,7 +1635,7 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver, complete_type_witness_id, base_id, adapt_id); } - return ResolveResult::Done(class_const_id); + return ResolveResult::Done(class_const_id, new_class.first_decl_id()); } static auto TryResolveTypedInst(ImportRefResolver& resolver, @@ -1713,7 +1720,8 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver, resolver.local_context().GetTypeIdForTypeConstant(const_id), .name_id = GetLocalNameId(resolver, inst.name_id), .index = inst.index})); - return {.const_id = resolver.local_constant_values().Get(inst_id)}; + return ResolveResult::Done(resolver.local_constant_values().Get(inst_id), + inst_id); } // Make a declaration of a function. This is done as a separate step from @@ -1794,13 +1802,14 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver, import_function.implicit_param_patterns_id); LoadLocalPatternConstantIds(resolver, import_function.param_patterns_id); auto generic_data = GetLocalGenericData(resolver, import_function.generic_id); + auto& new_function = resolver.local_functions().Get(function_id); if (resolver.HasNewWork()) { - return ResolveResult::Retry(function_const_id); + return ResolveResult::Retry(function_const_id, + new_function.first_decl_id()); } // Add the function declaration. - auto& new_function = resolver.local_functions().Get(function_id); new_function.parent_scope_id = parent_scope_id; new_function.implicit_param_patterns_id = GetLocalParamPatternsId( resolver, import_function.implicit_param_patterns_id); @@ -1815,7 +1824,7 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver, new_function.definition_id = new_function.first_owning_decl_id; } - return ResolveResult::Done(function_const_id); + return ResolveResult::Done(function_const_id, new_function.first_decl_id()); } static auto TryResolveTypedInst(ImportRefResolver& resolver, @@ -1963,12 +1972,12 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver, auto constraint_const_id = GetLocalConstantId( resolver, resolver.import_constant_values().Get(import_impl.constraint_id)); + auto& new_impl = resolver.local_impls().Get(impl_id); if (resolver.HasNewWork()) { - return ResolveResult::Retry(impl_const_id); + return ResolveResult::Retry(impl_const_id, new_impl.first_decl_id()); } - auto& new_impl = resolver.local_impls().Get(impl_id); new_impl.parent_scope_id = parent_scope_id; new_impl.implicit_param_patterns_id = GetLocalParamPatternsId(resolver, import_impl.implicit_param_patterns_id); @@ -1995,7 +2004,7 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver, resolver.local_impls().GetOrAddLookupBucket(new_impl).push_back(impl_id); } - return ResolveResult::Done(impl_const_id); + return ResolveResult::Done(impl_const_id, new_impl.first_decl_id()); } static auto TryResolveTypedInst(ImportRefResolver& resolver, @@ -2135,12 +2144,13 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver, self_param_id = GetLocalConstantInstId(resolver, import_interface.self_param_id); } + auto& new_interface = resolver.local_interfaces().Get(interface_id); if (resolver.HasNewWork()) { - return ResolveResult::Retry(interface_const_id); + return ResolveResult::Retry(interface_const_id, + new_interface.first_decl_id()); } - auto& new_interface = resolver.local_interfaces().Get(interface_id); new_interface.parent_scope_id = parent_scope_id; new_interface.implicit_param_patterns_id = GetLocalParamPatternsId( resolver, import_interface.implicit_param_patterns_id); @@ -2154,7 +2164,7 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver, AddInterfaceDefinition(resolver, import_interface, new_interface, *self_param_id); } - return ResolveResult::Done(interface_const_id); + return ResolveResult::Done(interface_const_id, new_interface.first_decl_id()); } static auto TryResolveTypedInst(ImportRefResolver& resolver, @@ -2747,6 +2757,11 @@ static auto TryResolveInst(ImportRefResolver& resolver, SemIR::InstId inst_id, resolver.local_constant_values().GetInstId(result.const_id), .generic_id = GetLocalGenericId(resolver, generic_const_id), .index = symbolic_const.index}); + if (result.decl_id.is_valid()) { + // Overwrite the abstract symbolic constant given initially to the + // declaration with its final concrete symbolic value. + resolver.local_constant_values().Set(result.decl_id, result.const_id); + } } } else { // Third phase: perform a consistency check and produce the constant we diff --git a/toolchain/check/testdata/class/generic/import.carbon b/toolchain/check/testdata/class/generic/import.carbon index ed52a2d1ef6ea..8298c1ed8dfc7 100644 --- a/toolchain/check/testdata/class/generic/import.carbon +++ b/toolchain/check/testdata/class/generic/import.carbon @@ -242,10 +242,6 @@ class Class(U:! type) { // CHECK:STDOUT: --- foo.impl.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { -// CHECK:STDOUT: %N: Core.IntLiteral = bind_symbolic_name N, 0 [symbolic] -// CHECK:STDOUT: %Int: type = class_type @Int, @Int(%N) [symbolic] -// CHECK:STDOUT: %Convert.type.2: type = fn_type @Convert.2, @impl.1(%N) [symbolic] -// CHECK:STDOUT: %Convert.2: %Convert.type.2 = struct_value () [symbolic] // CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [template] // CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [template] // CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic] @@ -271,14 +267,16 @@ class Class(U:! type) { // CHECK:STDOUT: %CompleteClass.elem.2: type = unbound_element_type %CompleteClass.2, %i32 [template] // CHECK:STDOUT: %F.type.3: type = fn_type @F.1, @CompleteClass(%i32) [template] // CHECK:STDOUT: %F.3: %F.type.3 = struct_value () [template] -// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [template] +// CHECK:STDOUT: %int_1.1: Core.IntLiteral = int_value 1 [template] // CHECK:STDOUT: %struct_type.n.2: type = struct_type {.n: Core.IntLiteral} [template] // CHECK:STDOUT: %Convert.type.9: type = fn_type @Convert.1, @ImplicitAs(%i32) [template] // CHECK:STDOUT: %impl_witness.19: = impl_witness (imports.%import_ref.14), @impl.1(%int_32) [template] -// CHECK:STDOUT: %Convert.bound: = bound_method %int_1, %Convert.2 [symbolic] -// CHECK:STDOUT: %Convert.specific_fn: = specific_function %Convert.bound, @Convert.2(%N) [symbolic] -// CHECK:STDOUT: %int.convert_checked: init %Int = call %Convert.specific_fn(%int_1) [symbolic] -// CHECK:STDOUT: %CompleteClass.val: %CompleteClass.2 = struct_value (%int.convert_checked) [symbolic] +// CHECK:STDOUT: %Convert.type.10: type = fn_type @Convert.2, @impl.1(%int_32) [template] +// CHECK:STDOUT: %Convert.10: %Convert.type.10 = struct_value () [template] +// CHECK:STDOUT: %Convert.bound: = bound_method %int_1.1, %Convert.10 [template] +// CHECK:STDOUT: %Convert.specific_fn: = specific_function %Convert.bound, @Convert.2(%int_32) [template] +// CHECK:STDOUT: %int_1.2: %i32 = int_value 1 [template] +// CHECK:STDOUT: %CompleteClass.val: %CompleteClass.2 = struct_value (%int_1.2) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -374,17 +372,17 @@ class Class(U:! type) { // CHECK:STDOUT: // CHECK:STDOUT: fn @F.2() -> %return.param_patt: %CompleteClass.2 [from "foo.carbon"] { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [template = constants.%int_1] +// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [template = constants.%int_1.1] // CHECK:STDOUT: %.loc9_17.1: %struct_type.n.2 = struct_literal (%int_1) -// CHECK:STDOUT: %impl.elem0: %Convert.type.9 = impl_witness_access constants.%impl_witness.19, element0 [symbolic = constants.%Convert.2] -// CHECK:STDOUT: %Convert.bound: = bound_method %int_1, %impl.elem0 [symbolic = constants.%Convert.bound] -// CHECK:STDOUT: %Convert.specific_fn: = specific_function %Convert.bound, @Convert.2(constants.%N) [symbolic = constants.%Convert.specific_fn] -// CHECK:STDOUT: %int.convert_checked: init %Int = call %Convert.specific_fn(%int_1) [symbolic = constants.%int.convert_checked] -// CHECK:STDOUT: %.loc9_17.2: init %i32 = converted %int_1, %int.convert_checked [symbolic = constants.%int.convert_checked] +// CHECK:STDOUT: %impl.elem0: %Convert.type.9 = impl_witness_access constants.%impl_witness.19, element0 [template = constants.%Convert.10] +// CHECK:STDOUT: %Convert.bound: = bound_method %int_1, %impl.elem0 [template = constants.%Convert.bound] +// CHECK:STDOUT: %Convert.specific_fn: = specific_function %Convert.bound, @Convert.2(constants.%int_32) [template = constants.%Convert.specific_fn] +// CHECK:STDOUT: %int.convert_checked: init %i32 = call %Convert.specific_fn(%int_1) [template = constants.%int_1.2] +// CHECK:STDOUT: %.loc9_17.2: init %i32 = converted %int_1, %int.convert_checked [template = constants.%int_1.2] // CHECK:STDOUT: %.loc9_17.3: ref %i32 = class_element_access %return, element0 -// CHECK:STDOUT: %.loc9_17.4: init %i32 = initialize_from %.loc9_17.2 to %.loc9_17.3 [symbolic = constants.%int.convert_checked] -// CHECK:STDOUT: %.loc9_17.5: init %CompleteClass.2 = class_init (%.loc9_17.4), %return [symbolic = constants.%CompleteClass.val] -// CHECK:STDOUT: %.loc9_18: init %CompleteClass.2 = converted %.loc9_17.1, %.loc9_17.5 [symbolic = constants.%CompleteClass.val] +// CHECK:STDOUT: %.loc9_17.4: init %i32 = initialize_from %.loc9_17.2 to %.loc9_17.3 [template = constants.%int_1.2] +// CHECK:STDOUT: %.loc9_17.5: init %CompleteClass.2 = class_init (%.loc9_17.4), %return [template = constants.%CompleteClass.val] +// CHECK:STDOUT: %.loc9_18: init %CompleteClass.2 = converted %.loc9_17.1, %.loc9_17.5 [template = constants.%CompleteClass.val] // CHECK:STDOUT: return %.loc9_18 to %return // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/struct/import.carbon b/toolchain/check/testdata/struct/import.carbon index 11d492e2f1ead..5677496e75530 100644 --- a/toolchain/check/testdata/struct/import.carbon +++ b/toolchain/check/testdata/struct/import.carbon @@ -19,19 +19,12 @@ var b_ref: {.a: {.b: i32, .c: (i32,)}, .d: i32} = class C(S:! {.a: i32, .b: i32}) {} fn F() -> C({.a = 1, .b = 2}); -// --- fail_todo_implicit.impl.carbon +// --- implicit.impl.carbon impl package Implicit; var a: {.a: i32} = a_ref; var b: {.a: {.b: i32, .c: (i32,)}, .d: i32} = b_ref; -// CHECK:STDERR: fail_todo_implicit.impl.carbon:[[@LINE+7]]:1: error: cannot implicitly convert from `C({.a = 1, .b = 2})` to `C({.a = , .b = })` [ImplicitAsConversionFailure] -// CHECK:STDERR: var c: C({.a = 1, .b = 2}) = F(); -// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: fail_todo_implicit.impl.carbon:[[@LINE+4]]:1: note: type `C({.a = 1, .b = 2})` does not implement interface `Core.ImplicitAs(C({.a = , .b = }))` [MissingImplInMemberAccessNote] -// CHECK:STDERR: var c: C({.a = 1, .b = 2}) = F(); -// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: var c: C({.a = 1, .b = 2}) = F(); // --- fail_bad_type.impl.carbon @@ -50,10 +43,10 @@ var c_bad: C({.c = 1, .d = 2}) = F(); // --- fail_bad_value.impl.carbon impl package Implicit; -// CHECK:STDERR: fail_bad_value.impl.carbon:[[@LINE+6]]:1: error: cannot implicitly convert from `C({.a = 1, .b = 2})` to `C({.a = , .b = })` [ImplicitAsConversionFailure] +// CHECK:STDERR: fail_bad_value.impl.carbon:[[@LINE+6]]:1: error: cannot implicitly convert from `C({.a = 1, .b = 2})` to `C({.a = 3, .b = 4})` [ImplicitAsConversionFailure] // CHECK:STDERR: var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: fail_bad_value.impl.carbon:[[@LINE+3]]:1: note: type `C({.a = 1, .b = 2})` does not implement interface `Core.ImplicitAs(C({.a = , .b = }))` [MissingImplInMemberAccessNote] +// CHECK:STDERR: fail_bad_value.impl.carbon:[[@LINE+3]]:1: note: type `C({.a = 1, .b = 2})` does not implement interface `Core.ImplicitAs(C({.a = 3, .b = 4}))` [MissingImplInMemberAccessNote] // CHECK:STDERR: var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ var c_bad: C({.a = 3, .b = 4}) = F(); @@ -247,13 +240,9 @@ var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDOUT: %S.patt.loc8_9.2 => constants.%struct.4 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_implicit.impl.carbon +// CHECK:STDOUT: --- implicit.impl.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { -// CHECK:STDOUT: %N: Core.IntLiteral = bind_symbolic_name N, 0 [symbolic] -// CHECK:STDOUT: %Int: type = class_type @Int, @Int(%N) [symbolic] -// CHECK:STDOUT: %Convert.type.2: type = fn_type @Convert.2, @impl.1(%N) [symbolic] -// CHECK:STDOUT: %Convert.2: %Convert.type.2 = struct_value () [symbolic] // CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [template] // CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [template] // CHECK:STDOUT: %struct_type.a: type = struct_type {.a: %i32} [template] @@ -267,22 +256,12 @@ var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDOUT: %struct_type.a.b.1: type = struct_type {.a: %i32, .b: %i32} [template] // CHECK:STDOUT: %S: %struct_type.a.b.1 = bind_symbolic_name S, 0 [symbolic] // CHECK:STDOUT: %S.patt: %struct_type.a.b.1 = symbolic_binding_pattern S, 0 [symbolic] -// CHECK:STDOUT: %int_1.1: Core.IntLiteral = int_value 1 [template] -// CHECK:STDOUT: %int_2.1: Core.IntLiteral = int_value 2 [template] -// CHECK:STDOUT: %Convert.bound.1: = bound_method %int_1.1, %Convert.2 [symbolic] -// CHECK:STDOUT: %Convert.specific_fn.1: = specific_function %Convert.bound.1, @Convert.2(%N) [symbolic] -// CHECK:STDOUT: %int.convert_checked.1: init %Int = call %Convert.specific_fn.1(%int_1.1) [symbolic] -// CHECK:STDOUT: %Convert.bound.2: = bound_method %int_2.1, %Convert.2 [symbolic] -// CHECK:STDOUT: %Convert.specific_fn.2: = specific_function %Convert.bound.2, @Convert.2(%N) [symbolic] -// CHECK:STDOUT: %int.convert_checked.2: init %Int = call %Convert.specific_fn.2(%int_2.1) [symbolic] -// CHECK:STDOUT: %struct.1: %struct_type.a.b.1 = struct_value (%int.convert_checked.1, %int.convert_checked.2) [symbolic] -// CHECK:STDOUT: %C.2: type = class_type @C, @C(%struct.1) [symbolic] +// CHECK:STDOUT: %int_1.2: %i32 = int_value 1 [template] +// CHECK:STDOUT: %int_2.2: %i32 = int_value 2 [template] +// CHECK:STDOUT: %struct: %struct_type.a.b.1 = struct_value (%int_1.2, %int_2.2) [template] +// CHECK:STDOUT: %C.2: type = class_type @C, @C(%struct) [template] // CHECK:STDOUT: %F.type: type = fn_type @F [template] // CHECK:STDOUT: %F: %F.type = struct_value () [template] -// CHECK:STDOUT: %int_2.2: %i32 = int_value 2 [template] -// CHECK:STDOUT: %int_1.2: %i32 = int_value 1 [template] -// CHECK:STDOUT: %struct.2: %struct_type.a.b.1 = struct_value (%int_1.2, %int_2.2) [template] -// CHECK:STDOUT: %C.3: type = class_type @C, @C(%struct.2) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -335,7 +314,7 @@ var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F() -> %C.3 [from "implicit.carbon"]; +// CHECK:STDOUT: fn @F() -> %C.2 [from "implicit.carbon"]; // CHECK:STDOUT: // CHECK:STDOUT: fn @__global_init() { // CHECK:STDOUT: !entry: @@ -369,10 +348,9 @@ var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDOUT: %.loc5_52: init %struct_type.a.d.1 = converted %b_ref.ref, %.loc5_47.19 // CHECK:STDOUT: assign file.%b.var, %.loc5_52 // CHECK:STDOUT: %F.ref: %F.type = name_ref F, imports.%import_ref.4 [template = constants.%F] -// CHECK:STDOUT: %.loc13_32: ref %C.3 = temporary_storage -// CHECK:STDOUT: %F.call: init %C.3 = call %F.ref() to %.loc13_32 -// CHECK:STDOUT: %.loc13_33: %C.2 = converted %F.call, [template = ] -// CHECK:STDOUT: assign file.%c.var, +// CHECK:STDOUT: %.loc6: ref %C.2 = splice_block file.%c.var {} +// CHECK:STDOUT: %F.call: init %C.2 = call %F.ref() to %.loc6 +// CHECK:STDOUT: assign file.%c.var, %F.call // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: @@ -381,16 +359,9 @@ var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDOUT: %S.patt => constants.%S // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @C(constants.%struct.1) { -// CHECK:STDOUT: %S => constants.%struct.1 -// CHECK:STDOUT: %S.patt => constants.%struct.1 -// CHECK:STDOUT: -// CHECK:STDOUT: !definition: -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: specific @C(constants.%struct.2) { -// CHECK:STDOUT: %S => constants.%struct.2 -// CHECK:STDOUT: %S.patt => constants.%struct.2 +// CHECK:STDOUT: specific @C(constants.%struct) { +// CHECK:STDOUT: %S => constants.%struct +// CHECK:STDOUT: %S.patt => constants.%struct // CHECK:STDOUT: // CHECK:STDOUT: !definition: // CHECK:STDOUT: } @@ -483,10 +454,6 @@ var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDOUT: --- fail_bad_value.impl.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { -// CHECK:STDOUT: %N: Core.IntLiteral = bind_symbolic_name N, 0 [symbolic] -// CHECK:STDOUT: %Int: type = class_type @Int, @Int(%N) [symbolic] -// CHECK:STDOUT: %Convert.type.2: type = fn_type @Convert.2, @impl.1(%N) [symbolic] -// CHECK:STDOUT: %Convert.2: %Convert.type.2 = struct_value () [symbolic] // CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [template] // CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [template] // CHECK:STDOUT: %C.type: type = generic_class_type @C [template] @@ -496,16 +463,10 @@ var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDOUT: %struct_type.a.b.1: type = struct_type {.a: %i32, .b: %i32} [template] // CHECK:STDOUT: %S: %struct_type.a.b.1 = bind_symbolic_name S, 0 [symbolic] // CHECK:STDOUT: %S.patt: %struct_type.a.b.1 = symbolic_binding_pattern S, 0 [symbolic] -// CHECK:STDOUT: %int_3: Core.IntLiteral = int_value 3 [template] -// CHECK:STDOUT: %int_4: Core.IntLiteral = int_value 4 [template] -// CHECK:STDOUT: %Convert.bound.1: = bound_method %int_3, %Convert.2 [symbolic] -// CHECK:STDOUT: %Convert.specific_fn.1: = specific_function %Convert.bound.1, @Convert.2(%N) [symbolic] -// CHECK:STDOUT: %int.convert_checked.1: init %Int = call %Convert.specific_fn.1(%int_3) [symbolic] -// CHECK:STDOUT: %Convert.bound.2: = bound_method %int_4, %Convert.2 [symbolic] -// CHECK:STDOUT: %Convert.specific_fn.2: = specific_function %Convert.bound.2, @Convert.2(%N) [symbolic] -// CHECK:STDOUT: %int.convert_checked.2: init %Int = call %Convert.specific_fn.2(%int_4) [symbolic] -// CHECK:STDOUT: %struct.1: %struct_type.a.b.1 = struct_value (%int.convert_checked.1, %int.convert_checked.2) [symbolic] -// CHECK:STDOUT: %C.2: type = class_type @C, @C(%struct.1) [symbolic] +// CHECK:STDOUT: %int_3.2: %i32 = int_value 3 [template] +// CHECK:STDOUT: %int_4.2: %i32 = int_value 4 [template] +// CHECK:STDOUT: %struct.1: %struct_type.a.b.1 = struct_value (%int_3.2, %int_4.2) [template] +// CHECK:STDOUT: %C.2: type = class_type @C, @C(%struct.1) [template] // CHECK:STDOUT: %F.type: type = fn_type @F [template] // CHECK:STDOUT: %F: %F.type = struct_value () [template] // CHECK:STDOUT: %int_2: %i32 = int_value 2 [template] diff --git a/toolchain/check/testdata/tuple/import.carbon b/toolchain/check/testdata/tuple/import.carbon index 408e53f10c700..a86ce4654ce58 100644 --- a/toolchain/check/testdata/tuple/import.carbon +++ b/toolchain/check/testdata/tuple/import.carbon @@ -19,19 +19,12 @@ class C(X:! (i32, i32)) {} fn F() -> C((1, 2)); -// --- fail_todo_implicit.impl.carbon +// --- implicit.impl.carbon impl package Implicit; var a: (i32,) = a_ref; var b: (((i32,), i32), (i32, i32)) = b_ref; -// CHECK:STDERR: fail_todo_implicit.impl.carbon:[[@LINE+7]]:1: error: cannot implicitly convert from `C((1, 2))` to `C((, ))` [ImplicitAsConversionFailure] -// CHECK:STDERR: var c: C((1, 2)) = F(); -// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: fail_todo_implicit.impl.carbon:[[@LINE+4]]:1: note: type `C((1, 2))` does not implement interface `Core.ImplicitAs(C((, )))` [MissingImplInMemberAccessNote] -// CHECK:STDERR: var c: C((1, 2)) = F(); -// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: var c: C((1, 2)) = F(); // --- fail_bad_type.impl.carbon @@ -52,10 +45,10 @@ var c_bad: C((1, 2, 3)) = F(); impl package Implicit; -// CHECK:STDERR: fail_bad_value.impl.carbon:[[@LINE+6]]:1: error: cannot implicitly convert from `C((1, 2))` to `C((, ))` [ImplicitAsConversionFailure] +// CHECK:STDERR: fail_bad_value.impl.carbon:[[@LINE+6]]:1: error: cannot implicitly convert from `C((1, 2))` to `C((3, 4))` [ImplicitAsConversionFailure] // CHECK:STDERR: var c_bad: C((3, 4)) = F(); // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: fail_bad_value.impl.carbon:[[@LINE+3]]:1: note: type `C((1, 2))` does not implement interface `Core.ImplicitAs(C((, )))` [MissingImplInMemberAccessNote] +// CHECK:STDERR: fail_bad_value.impl.carbon:[[@LINE+3]]:1: note: type `C((1, 2))` does not implement interface `Core.ImplicitAs(C((3, 4)))` [MissingImplInMemberAccessNote] // CHECK:STDERR: var c_bad: C((3, 4)) = F(); // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~ var c_bad: C((3, 4)) = F(); @@ -265,13 +258,9 @@ var c_bad: C((3, 4)) = F(); // CHECK:STDOUT: %X.patt.loc7_9.2 => constants.%tuple.5 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_implicit.impl.carbon +// CHECK:STDOUT: --- implicit.impl.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { -// CHECK:STDOUT: %N: Core.IntLiteral = bind_symbolic_name N, 0 [symbolic] -// CHECK:STDOUT: %Int: type = class_type @Int, @Int(%N) [symbolic] -// CHECK:STDOUT: %Convert.type.2: type = fn_type @Convert.2, @impl.1(%N) [symbolic] -// CHECK:STDOUT: %Convert.2: %Convert.type.2 = struct_value () [symbolic] // CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [template] // CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [template] // CHECK:STDOUT: %tuple.type.2: type = tuple_type (%i32) [template] @@ -284,22 +273,12 @@ var c_bad: C((3, 4)) = F(); // CHECK:STDOUT: %complete_type.3: = complete_type_witness %empty_struct_type [template] // CHECK:STDOUT: %X: %tuple.type.7 = bind_symbolic_name X, 0 [symbolic] // CHECK:STDOUT: %X.patt: %tuple.type.7 = symbolic_binding_pattern X, 0 [symbolic] -// CHECK:STDOUT: %int_1.1: Core.IntLiteral = int_value 1 [template] -// CHECK:STDOUT: %int_2.1: Core.IntLiteral = int_value 2 [template] -// CHECK:STDOUT: %Convert.bound.1: = bound_method %int_1.1, %Convert.2 [symbolic] -// CHECK:STDOUT: %Convert.specific_fn.1: = specific_function %Convert.bound.1, @Convert.2(%N) [symbolic] -// CHECK:STDOUT: %int.convert_checked.1: init %Int = call %Convert.specific_fn.1(%int_1.1) [symbolic] -// CHECK:STDOUT: %Convert.bound.2: = bound_method %int_2.1, %Convert.2 [symbolic] -// CHECK:STDOUT: %Convert.specific_fn.2: = specific_function %Convert.bound.2, @Convert.2(%N) [symbolic] -// CHECK:STDOUT: %int.convert_checked.2: init %Int = call %Convert.specific_fn.2(%int_2.1) [symbolic] -// CHECK:STDOUT: %tuple.1: %tuple.type.7 = tuple_value (%int.convert_checked.1, %int.convert_checked.2) [symbolic] -// CHECK:STDOUT: %C.2: type = class_type @C, @C(%tuple.1) [symbolic] +// CHECK:STDOUT: %int_1.2: %i32 = int_value 1 [template] +// CHECK:STDOUT: %int_2.2: %i32 = int_value 2 [template] +// CHECK:STDOUT: %tuple: %tuple.type.7 = tuple_value (%int_1.2, %int_2.2) [template] +// CHECK:STDOUT: %C.2: type = class_type @C, @C(%tuple) [template] // CHECK:STDOUT: %F.type: type = fn_type @F [template] // CHECK:STDOUT: %F: %F.type = struct_value () [template] -// CHECK:STDOUT: %int_2.2: %i32 = int_value 2 [template] -// CHECK:STDOUT: %int_1.2: %i32 = int_value 1 [template] -// CHECK:STDOUT: %tuple.2: %tuple.type.7 = tuple_value (%int_1.2, %int_2.2) [template] -// CHECK:STDOUT: %C.3: type = class_type @C, @C(%tuple.2) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -352,7 +331,7 @@ var c_bad: C((3, 4)) = F(); // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F() -> %C.3 [from "implicit.carbon"]; +// CHECK:STDOUT: fn @F() -> %C.2 [from "implicit.carbon"]; // CHECK:STDOUT: // CHECK:STDOUT: fn @__global_init() { // CHECK:STDOUT: !entry: @@ -394,10 +373,9 @@ var c_bad: C((3, 4)) = F(); // CHECK:STDOUT: %.loc5_43: init %tuple.type.8 = converted %b_ref.ref, %.loc5_38.15 // CHECK:STDOUT: assign file.%b.var, %.loc5_43 // CHECK:STDOUT: %F.ref: %F.type = name_ref F, imports.%import_ref.4 [template = constants.%F] -// CHECK:STDOUT: %.loc13_22: ref %C.3 = temporary_storage -// CHECK:STDOUT: %F.call: init %C.3 = call %F.ref() to %.loc13_22 -// CHECK:STDOUT: %.loc13_23: %C.2 = converted %F.call, [template = ] -// CHECK:STDOUT: assign file.%c.var, +// CHECK:STDOUT: %.loc6: ref %C.2 = splice_block file.%c.var {} +// CHECK:STDOUT: %F.call: init %C.2 = call %F.ref() to %.loc6 +// CHECK:STDOUT: assign file.%c.var, %F.call // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: @@ -406,16 +384,9 @@ var c_bad: C((3, 4)) = F(); // CHECK:STDOUT: %X.patt => constants.%X // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @C(constants.%tuple.1) { -// CHECK:STDOUT: %X => constants.%tuple.1 -// CHECK:STDOUT: %X.patt => constants.%tuple.1 -// CHECK:STDOUT: -// CHECK:STDOUT: !definition: -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: specific @C(constants.%tuple.2) { -// CHECK:STDOUT: %X => constants.%tuple.2 -// CHECK:STDOUT: %X.patt => constants.%tuple.2 +// CHECK:STDOUT: specific @C(constants.%tuple) { +// CHECK:STDOUT: %X => constants.%tuple +// CHECK:STDOUT: %X.patt => constants.%tuple // CHECK:STDOUT: // CHECK:STDOUT: !definition: // CHECK:STDOUT: } @@ -508,10 +479,6 @@ var c_bad: C((3, 4)) = F(); // CHECK:STDOUT: --- fail_bad_value.impl.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { -// CHECK:STDOUT: %N: Core.IntLiteral = bind_symbolic_name N, 0 [symbolic] -// CHECK:STDOUT: %Int: type = class_type @Int, @Int(%N) [symbolic] -// CHECK:STDOUT: %Convert.type.2: type = fn_type @Convert.2, @impl.1(%N) [symbolic] -// CHECK:STDOUT: %Convert.2: %Convert.type.2 = struct_value () [symbolic] // CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [template] // CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [template] // CHECK:STDOUT: %C.type: type = generic_class_type @C [template] @@ -521,16 +488,10 @@ var c_bad: C((3, 4)) = F(); // CHECK:STDOUT: %tuple.type.1: type = tuple_type (%i32, %i32) [template] // CHECK:STDOUT: %X: %tuple.type.1 = bind_symbolic_name X, 0 [symbolic] // CHECK:STDOUT: %X.patt: %tuple.type.1 = symbolic_binding_pattern X, 0 [symbolic] -// CHECK:STDOUT: %int_3: Core.IntLiteral = int_value 3 [template] -// CHECK:STDOUT: %int_4: Core.IntLiteral = int_value 4 [template] -// CHECK:STDOUT: %Convert.bound.1: = bound_method %int_3, %Convert.2 [symbolic] -// CHECK:STDOUT: %Convert.specific_fn.1: = specific_function %Convert.bound.1, @Convert.2(%N) [symbolic] -// CHECK:STDOUT: %int.convert_checked.1: init %Int = call %Convert.specific_fn.1(%int_3) [symbolic] -// CHECK:STDOUT: %Convert.bound.2: = bound_method %int_4, %Convert.2 [symbolic] -// CHECK:STDOUT: %Convert.specific_fn.2: = specific_function %Convert.bound.2, @Convert.2(%N) [symbolic] -// CHECK:STDOUT: %int.convert_checked.2: init %Int = call %Convert.specific_fn.2(%int_4) [symbolic] -// CHECK:STDOUT: %tuple.1: %tuple.type.1 = tuple_value (%int.convert_checked.1, %int.convert_checked.2) [symbolic] -// CHECK:STDOUT: %C.2: type = class_type @C, @C(%tuple.1) [symbolic] +// CHECK:STDOUT: %int_3.2: %i32 = int_value 3 [template] +// CHECK:STDOUT: %int_4.2: %i32 = int_value 4 [template] +// CHECK:STDOUT: %tuple.1: %tuple.type.1 = tuple_value (%int_3.2, %int_4.2) [template] +// CHECK:STDOUT: %C.2: type = class_type @C, @C(%tuple.1) [template] // CHECK:STDOUT: %F.type: type = fn_type @F [template] // CHECK:STDOUT: %F: %F.type = struct_value () [template] // CHECK:STDOUT: %int_2: %i32 = int_value 2 [template]