From 1a1bfd2eb24ddab909f8faf56f5c8c5d0f3c92de Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 10 Oct 2024 13:52:46 -0700 Subject: [PATCH] Track and resolve the specific callee in a call to a generic function (#4395) Add a new `specific_function` instruction that represents a generic function plus its deduced argument list as a callee in a function call. The new instruction can only appear as the immediate operand of a call instruction, so we give it a builtin placeholder type. At the end of each file, require definitions for all specific functions used in that file. Resolve the generic with the argument list to produce those specific function definitions as needed, and diagnose if the generic doesn't have a definition available. A few tests are updated in cases where they declared and used generic functions but didn't previously provide a function definition. --- toolchain/check/call.cpp | 18 +- toolchain/check/check.cpp | 38 +- toolchain/check/context.cpp | 1 + toolchain/check/eval.cpp | 9 +- .../testdata/basics/builtin_insts.carbon | 2 + .../testdata/class/generic/import.carbon | 12 +- .../class/generic/member_access.carbon | 59 +- .../class/generic/method_deduce.carbon | 160 ++++- .../check/testdata/class/generic/self.carbon | 65 +- toolchain/check/testdata/deduce/array.carbon | 40 +- .../check/testdata/deduce/generic_type.carbon | 143 ++++- .../check/testdata/deduce/int_float.carbon | 6 +- toolchain/check/testdata/deduce/tuple.carbon | 62 +- .../testdata/deduce/type_operator.carbon | 555 +++++++++++------- .../testdata/function/generic/deduce.carbon | 203 +++++-- .../function/generic/no_prelude/call.carbon | 142 +++-- .../function/generic/redeclare.carbon | 13 +- .../function/generic/resolve_used.carbon | 127 ++++ .../function/generic/return_slot.carbon | 101 +++- .../function/generic/undefined.carbon | 332 +++++++++++ .../check/testdata/impl/lookup/generic.carbon | 35 +- .../impl/lookup/no_prelude/impl_forall.carbon | 12 +- .../no_prelude/assoc_const_in_generic.carbon | 38 +- .../interface/no_prelude/generic.carbon | 20 +- .../operators/overloaded/implicit_as.carbon | 44 +- toolchain/diagnostics/diagnostic_kind.def | 2 + toolchain/lower/constant.cpp | 5 + toolchain/lower/file_context.cpp | 1 + toolchain/sem_ir/builtin_inst_kind.def | 3 + toolchain/sem_ir/file.cpp | 1 + toolchain/sem_ir/function.cpp | 11 +- toolchain/sem_ir/function.h | 4 +- toolchain/sem_ir/inst_kind.def | 3 +- toolchain/sem_ir/stringify_type.cpp | 1 + toolchain/sem_ir/typed_insts.h | 21 + 35 files changed, 1761 insertions(+), 528 deletions(-) create mode 100644 toolchain/check/testdata/function/generic/resolve_used.carbon create mode 100644 toolchain/check/testdata/function/generic/undefined.carbon diff --git a/toolchain/check/call.cpp b/toolchain/check/call.cpp index 7bf6e657b03a..f2180cc50589 100644 --- a/toolchain/check/call.cpp +++ b/toolchain/check/call.cpp @@ -9,6 +9,8 @@ #include "toolchain/check/convert.h" #include "toolchain/check/deduce.h" #include "toolchain/check/function.h" +#include "toolchain/sem_ir/builtin_function_kind.h" +#include "toolchain/sem_ir/builtin_inst_kind.h" #include "toolchain/sem_ir/entity_with_params_base.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/inst.h" @@ -24,8 +26,8 @@ namespace Carbon::Check { // `self_id` and `arg_ids` are the self argument and explicit arguments in the // call. // -// Returns a SpecificId for the specific callee, or `nullopt` if an error has -// been diagnosed. +// Returns a `SpecificId` for the specific callee, `SpecificId::Invalid` if the +// callee is not generic, or `nullopt` if an error has been diagnosed. static auto ResolveCalleeInCall(Context& context, SemIR::LocId loc_id, const SemIR::EntityWithParamsBase& entity, llvm::StringLiteral entity_kind_for_diagnostic, @@ -141,10 +143,20 @@ auto PerformCall(Context& context, SemIR::LocId loc_id, SemIR::InstId callee_id, // for the call. auto callee_specific_id = ResolveCalleeInCall( context, loc_id, callable, "function", callable.generic_id, - callee_function.specific_id, callee_function.self_id, arg_ids); + callee_function.enclosing_specific_id, callee_function.self_id, arg_ids); if (!callee_specific_id) { return SemIR::InstId::BuiltinError; } + if (callee_specific_id->is_valid()) { + callee_id = + context.AddInst(context.insts().GetLocId(callee_id), + SemIR::SpecificFunction{ + .type_id = context.GetBuiltinType( + SemIR::BuiltinInstKind::SpecificFunctionType), + .callee_id = callee_id, + .specific_id = *callee_specific_id}); + context.definitions_required().push_back(callee_id); + } // If there is a return slot, build storage for the result. SemIR::InstId return_storage_id = SemIR::InstId::Invalid; diff --git a/toolchain/check/check.cpp b/toolchain/check/check.cpp index 7f26358445e5..12e6c661a9b0 100644 --- a/toolchain/check/check.cpp +++ b/toolchain/check/check.cpp @@ -16,6 +16,7 @@ #include "toolchain/check/context.h" #include "toolchain/check/diagnostic_helpers.h" #include "toolchain/check/function.h" +#include "toolchain/check/generic.h" #include "toolchain/check/handle.h" #include "toolchain/check/import.h" #include "toolchain/check/import_ref.h" @@ -783,14 +784,18 @@ auto NodeIdTraversal::Next() -> std::optional { } } -// Emits a diagnostic for each declaration in context.definitions_required() -// that doesn't have a definition. -static auto DiagnoseMissingDefinitions(Context& context, - Context::DiagnosticEmitter& emitter) +// Checks that each required definition is available. If the definition can be +// generated by resolving a specific, does so, otherwise emits a diagnostic for +// each declaration in context.definitions_required() that doesn't have a +// definition. +static auto CheckRequiredDefinitions(Context& context, + Context::DiagnosticEmitter& emitter) -> void { CARBON_DIAGNOSTIC(MissingDefinitionInImpl, Error, "no definition found for declaration in impl file"); - for (SemIR::InstId decl_inst_id : context.definitions_required()) { + // Note that more required definitions can be added during this loop. + for (size_t i = 0; i != context.definitions_required().size(); ++i) { + SemIR::InstId decl_inst_id = context.definitions_required()[i]; SemIR::Inst decl_inst = context.insts().Get(decl_inst_id); CARBON_KIND_SWITCH(context.insts().Get(decl_inst_id)) { case CARBON_KIND(SemIR::ClassDecl class_decl): { @@ -817,6 +822,25 @@ static auto DiagnoseMissingDefinitions(Context& context, // triggering https://github.com/carbon-language/carbon-lang/issues/4071 CARBON_FATAL("TODO: Support interfaces in DiagnoseMissingDefinitions"); } + case CARBON_KIND(SemIR::SpecificFunction specific_function): { + if (!ResolveSpecificDefinition(context, + specific_function.specific_id)) { + CARBON_DIAGNOSTIC(MissingGenericFunctionDefinition, Error, + "use of undefined generic function"); + CARBON_DIAGNOSTIC(MissingGenericFunctionDefinitionHere, Note, + "generic function declared here"); + auto generic_decl_id = + context.generics() + .Get(context.specifics() + .Get(specific_function.specific_id) + .generic_id) + .decl_id; + emitter.Build(decl_inst_id, MissingGenericFunctionDefinition) + .Note(generic_decl_id, MissingGenericFunctionDefinitionHere) + .Emit(); + } + break; + } default: { CARBON_FATAL("Unexpected inst in definitions_required: {0}", decl_inst); } @@ -908,9 +932,9 @@ static auto CheckParseTree( return; } - context.Finalize(); + CheckRequiredDefinitions(context, emitter); - DiagnoseMissingDefinitions(context, emitter); + context.Finalize(); context.VerifyOnFinish(); diff --git a/toolchain/check/context.cpp b/toolchain/check/context.cpp index ad86f004c7fc..a5ca5a4da21f 100644 --- a/toolchain/check/context.cpp +++ b/toolchain/check/context.cpp @@ -918,6 +918,7 @@ class TypeCompleter { case SemIR::BuiltinInstKind::NamespaceType: case SemIR::BuiltinInstKind::BoundMethodType: case SemIR::BuiltinInstKind::WitnessType: + case SemIR::BuiltinInstKind::SpecificFunctionType: return MakeCopyValueRepr(type_id); case SemIR::BuiltinInstKind::StringType: diff --git a/toolchain/check/eval.cpp b/toolchain/check/eval.cpp index 2ca131bc33be..b43471baf7f1 100644 --- a/toolchain/check/eval.cpp +++ b/toolchain/check/eval.cpp @@ -1190,8 +1190,9 @@ static auto TryEvalInstInContext(EvalContext& eval_context, return RebuildAndValidateIfFieldsAreConstant( eval_context, inst, [&](SemIR::IntType result) { - return ValidateIntType(eval_context.context(), - int_type.bit_width_id, result); + return ValidateIntType( + eval_context.context(), + inst_id.is_valid() ? inst_id : int_type.bit_width_id, result); }, &SemIR::IntType::bit_width_id); } @@ -1207,6 +1208,10 @@ static auto TryEvalInstInContext(EvalContext& eval_context, }, &SemIR::FloatType::bit_width_id); } + case SemIR::SpecificFunction::Kind: + return RebuildIfFieldsAreConstant(eval_context, inst, + &SemIR::SpecificFunction::callee_id, + &SemIR::SpecificFunction::specific_id); case SemIR::StructType::Kind: return RebuildIfFieldsAreConstant(eval_context, inst, &SemIR::StructType::fields_id); diff --git a/toolchain/check/testdata/basics/builtin_insts.carbon b/toolchain/check/testdata/basics/builtin_insts.carbon index 9b55fde946bf..72082629142c 100644 --- a/toolchain/check/testdata/basics/builtin_insts.carbon +++ b/toolchain/check/testdata/basics/builtin_insts.carbon @@ -36,6 +36,7 @@ // CHECK:STDOUT: instFloatType: {kind: BuiltinInst, arg0: FloatType, type: typeTypeType} // CHECK:STDOUT: instStringType: {kind: BuiltinInst, arg0: StringType, type: typeTypeType} // CHECK:STDOUT: instBoundMethodType: {kind: BuiltinInst, arg0: BoundMethodType, type: typeTypeType} +// CHECK:STDOUT: instSpecificFunctionType: {kind: BuiltinInst, arg0: SpecificFunctionType, type: typeTypeType} // CHECK:STDOUT: instNamespaceType: {kind: BuiltinInst, arg0: NamespaceType, type: typeTypeType} // CHECK:STDOUT: instWitnessType: {kind: BuiltinInst, arg0: WitnessType, type: typeTypeType} // CHECK:STDOUT: 'inst+0': {kind: Namespace, arg0: name_scope0, arg1: inst, type: type(instNamespaceType)} @@ -47,6 +48,7 @@ // CHECK:STDOUT: instFloatType: templateConstant(instFloatType) // CHECK:STDOUT: instStringType: templateConstant(instStringType) // CHECK:STDOUT: instBoundMethodType: templateConstant(instBoundMethodType) +// CHECK:STDOUT: instSpecificFunctionType: templateConstant(instSpecificFunctionType) // CHECK:STDOUT: instNamespaceType: templateConstant(instNamespaceType) // CHECK:STDOUT: instWitnessType: templateConstant(instWitnessType) // CHECK:STDOUT: 'inst+0': templateConstant(inst+0) diff --git a/toolchain/check/testdata/class/generic/import.carbon b/toolchain/check/testdata/class/generic/import.carbon index 0b9a5231d9f0..08ee4a47a675 100644 --- a/toolchain/check/testdata/class/generic/import.carbon +++ b/toolchain/check/testdata/class/generic/import.carbon @@ -419,6 +419,7 @@ class Class(U:! type) { // CHECK:STDOUT: %.6: type = ptr_type %.2 [template] // CHECK:STDOUT: %F.type.3: type = fn_type @F.2 [template] // CHECK:STDOUT: %F.3: %F.type.3 = struct_value () [template] +// CHECK:STDOUT: %.7: = specific_function %F.2, @F.1(i32) [template] // CHECK:STDOUT: %UseField.type: type = fn_type @UseField [template] // CHECK:STDOUT: %UseField: %UseField.type = struct_value () [template] // CHECK:STDOUT: } @@ -502,9 +503,10 @@ class Class(U:! type) { // CHECK:STDOUT: %F.call.loc6: init %CompleteClass.3 = call %F.ref.loc6() to %.loc6_7 // CHECK:STDOUT: assign %v.var, %F.call.loc6 // CHECK:STDOUT: %v.ref: ref %CompleteClass.3 = name_ref v, %v -// CHECK:STDOUT: %.loc7_11: %F.type.2 = specific_constant imports.%import_ref.7, @CompleteClass(i32) [template = constants.%F.2] -// CHECK:STDOUT: %F.ref.loc7: %F.type.2 = name_ref F, %.loc7_11 [template = constants.%F.2] -// CHECK:STDOUT: %F.call.loc7: init i32 = call %F.ref.loc7() +// CHECK:STDOUT: %.loc7_11.1: %F.type.2 = specific_constant imports.%import_ref.7, @CompleteClass(i32) [template = constants.%F.2] +// CHECK:STDOUT: %F.ref.loc7: %F.type.2 = name_ref F, %.loc7_11.1 [template = constants.%F.2] +// CHECK:STDOUT: %.loc7_11.2: = specific_function %F.ref.loc7, @F.1(i32) [template = constants.%.7] +// CHECK:STDOUT: %F.call.loc7: init i32 = call %.loc7_11.2() // CHECK:STDOUT: %.loc7_15.1: i32 = value_of_initializer %F.call.loc7 // CHECK:STDOUT: %.loc7_15.2: i32 = converted %F.call.loc7, %.loc7_15.1 // CHECK:STDOUT: return %.loc7_15.2 @@ -564,7 +566,9 @@ class Class(U:! type) { // CHECK:STDOUT: %F => constants.%F.2 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @F.1(i32) {} +// CHECK:STDOUT: specific @F.1(i32) { +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_generic_arg_mismatch.carbon // CHECK:STDOUT: diff --git a/toolchain/check/testdata/class/generic/member_access.carbon b/toolchain/check/testdata/class/generic/member_access.carbon index 75e885c0b23b..18e2b6a85aad 100644 --- a/toolchain/check/testdata/class/generic/member_access.carbon +++ b/toolchain/check/testdata/class/generic/member_access.carbon @@ -268,7 +268,8 @@ fn StaticMemberFunctionCall(T:! type) -> Class(T) { // CHECK:STDOUT: %.loc15_11.1: %Get.type.2 = specific_constant @Class.%Get.decl, @Class(i32) [template = constants.%Get.2] // CHECK:STDOUT: %Get.ref: %Get.type.2 = name_ref Get, %.loc15_11.1 [template = constants.%Get.2] // CHECK:STDOUT: %.loc15_11.2: = bound_method %x.ref, %Get.ref -// CHECK:STDOUT: %Get.call: init i32 = call %.loc15_11.2(%x.ref) +// CHECK:STDOUT: %.loc15_11.3: = specific_function %.loc15_11.2, @Get(i32) +// CHECK:STDOUT: %Get.call: init i32 = call %.loc15_11.3(%x.ref) // CHECK:STDOUT: %.loc15_17.1: i32 = value_of_initializer %Get.call // CHECK:STDOUT: %.loc15_17.2: i32 = converted %Get.call, %.loc15_17.1 // CHECK:STDOUT: return %.loc15_17.2 @@ -281,8 +282,9 @@ fn StaticMemberFunctionCall(T:! type) -> Class(T) { // CHECK:STDOUT: %.loc19_12.2: %GetAddr.type.2 = specific_constant @Class.%GetAddr.decl, @Class(i32) [template = constants.%GetAddr.2] // CHECK:STDOUT: %GetAddr.ref: %GetAddr.type.2 = name_ref GetAddr, %.loc19_12.2 [template = constants.%GetAddr.2] // CHECK:STDOUT: %.loc19_12.3: = bound_method %.loc19_12.1, %GetAddr.ref -// CHECK:STDOUT: %.loc19_12.4: %.12 = addr_of %.loc19_12.1 -// CHECK:STDOUT: %GetAddr.call: init %.13 = call %.loc19_12.3(%.loc19_12.4) +// CHECK:STDOUT: %.loc19_12.4: = specific_function %.loc19_12.3, @GetAddr(i32) +// CHECK:STDOUT: %.loc19_12.5: %.12 = addr_of %.loc19_12.1 +// CHECK:STDOUT: %GetAddr.call: init %.13 = call %.loc19_12.4(%.loc19_12.5) // CHECK:STDOUT: %.loc19_21.1: %.13 = value_of_initializer %GetAddr.call // CHECK:STDOUT: %.loc19_21.2: %.13 = converted %GetAddr.call, %.loc19_21.1 // CHECK:STDOUT: %.loc19_10.1: ref i32 = deref %.loc19_21.2 @@ -345,6 +347,9 @@ fn StaticMemberFunctionCall(T:! type) -> Class(T) { // CHECK:STDOUT: specific @Get(i32) { // CHECK:STDOUT: %T => i32 // CHECK:STDOUT: %Class => constants.%Class.3 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc5_42.3 => constants.%.8 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @GetAddr(i32) { @@ -352,6 +357,9 @@ fn StaticMemberFunctionCall(T:! type) -> Class(T) { // CHECK:STDOUT: %Class => constants.%Class.3 // CHECK:STDOUT: %.loc7_29.1 => constants.%.12 // CHECK:STDOUT: %.loc7_38.1 => constants.%.13 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc7_54.3 => constants.%.8 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_todo_static_member_fn_call.carbon @@ -370,6 +378,7 @@ fn StaticMemberFunctionCall(T:! type) -> Class(T) { // CHECK:STDOUT: %struct: %Class.2 = struct_value () [symbolic] // CHECK:STDOUT: %StaticMemberFunctionCall.type: type = fn_type @StaticMemberFunctionCall [template] // CHECK:STDOUT: %StaticMemberFunctionCall: %StaticMemberFunctionCall.type = struct_value () [template] +// CHECK:STDOUT: %.5: = specific_function %Make, @Make(%T) [symbolic] // CHECK:STDOUT: %ImplicitAs.type.1: type = generic_interface_type @ImplicitAs [template] // CHECK:STDOUT: %ImplicitAs: %ImplicitAs.type.1 = struct_value () [template] // CHECK:STDOUT: %Dest: type = bind_symbolic_name Dest, 0 [symbolic] @@ -378,14 +387,14 @@ fn StaticMemberFunctionCall(T:! type) -> Class(T) { // CHECK:STDOUT: %Self.2: %ImplicitAs.type.2 = bind_symbolic_name Self, 1 [symbolic] // CHECK:STDOUT: %Convert.type.1: type = fn_type @Convert, @ImplicitAs(%Dest) [symbolic] // CHECK:STDOUT: %Convert.1: %Convert.type.1 = struct_value () [symbolic] -// CHECK:STDOUT: %.5: type = assoc_entity_type %ImplicitAs.type.2, %Convert.type.1 [symbolic] -// CHECK:STDOUT: %.6: %.5 = assoc_entity element0, imports.%import_ref.5 [symbolic] +// CHECK:STDOUT: %.6: type = assoc_entity_type %ImplicitAs.type.2, %Convert.type.1 [symbolic] +// CHECK:STDOUT: %.7: %.6 = assoc_entity element0, imports.%import_ref.5 [symbolic] // CHECK:STDOUT: %ImplicitAs.type.3: type = interface_type @ImplicitAs, @ImplicitAs(%Class.2) [symbolic] // CHECK:STDOUT: %Convert.type.2: type = fn_type @Convert, @ImplicitAs(%Class.2) [symbolic] // CHECK:STDOUT: %Convert.2: %Convert.type.2 = struct_value () [symbolic] -// CHECK:STDOUT: %.7: type = assoc_entity_type %ImplicitAs.type.3, %Convert.type.2 [symbolic] -// CHECK:STDOUT: %.8: %.7 = assoc_entity element0, imports.%import_ref.5 [symbolic] -// CHECK:STDOUT: %.9: %.5 = assoc_entity element0, imports.%import_ref.6 [symbolic] +// CHECK:STDOUT: %.8: type = assoc_entity_type %ImplicitAs.type.3, %Convert.type.2 [symbolic] +// CHECK:STDOUT: %.9: %.8 = assoc_entity element0, imports.%import_ref.5 [symbolic] +// CHECK:STDOUT: %.10: %.6 = assoc_entity element0, imports.%import_ref.6 [symbolic] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -402,7 +411,7 @@ fn StaticMemberFunctionCall(T:! type) -> Class(T) { // CHECK:STDOUT: } // CHECK:STDOUT: %import_ref.1: %ImplicitAs.type.1 = import_ref Core//prelude/operators/as, inst+40, loaded [template = constants.%ImplicitAs] // CHECK:STDOUT: %import_ref.2 = import_ref Core//prelude/operators/as, inst+45, unloaded -// CHECK:STDOUT: %import_ref.3: @ImplicitAs.%.1 (%.5) = import_ref Core//prelude/operators/as, inst+63, loaded [symbolic = @ImplicitAs.%.2 (constants.%.9)] +// CHECK:STDOUT: %import_ref.3: @ImplicitAs.%.1 (%.6) = import_ref Core//prelude/operators/as, inst+63, loaded [symbolic = @ImplicitAs.%.2 (constants.%.10)] // CHECK:STDOUT: %import_ref.4 = import_ref Core//prelude/operators/as, inst+56, unloaded // CHECK:STDOUT: %import_ref.5 = import_ref Core//prelude/operators/as, inst+56, unloaded // CHECK:STDOUT: %import_ref.6 = import_ref Core//prelude/operators/as, inst+56, unloaded @@ -441,8 +450,8 @@ fn StaticMemberFunctionCall(T:! type) -> Class(T) { // CHECK:STDOUT: %Self: %ImplicitAs.type.2 = bind_symbolic_name Self, 1 [symbolic = %Self (constants.%Self.2)] // CHECK:STDOUT: %Convert.type: type = fn_type @Convert, @ImplicitAs(%Dest) [symbolic = %Convert.type (constants.%Convert.type.1)] // CHECK:STDOUT: %Convert: @ImplicitAs.%Convert.type (%Convert.type.1) = struct_value () [symbolic = %Convert (constants.%Convert.1)] -// CHECK:STDOUT: %.1: type = assoc_entity_type @ImplicitAs.%ImplicitAs.type (%ImplicitAs.type.2), @ImplicitAs.%Convert.type (%Convert.type.1) [symbolic = %.1 (constants.%.5)] -// CHECK:STDOUT: %.2: @ImplicitAs.%.1 (%.5) = assoc_entity element0, imports.%import_ref.5 [symbolic = %.2 (constants.%.6)] +// CHECK:STDOUT: %.1: type = assoc_entity_type @ImplicitAs.%ImplicitAs.type (%ImplicitAs.type.2), @ImplicitAs.%Convert.type (%Convert.type.1) [symbolic = %.1 (constants.%.6)] +// CHECK:STDOUT: %.2: @ImplicitAs.%.1 (%.6) = assoc_entity element0, imports.%import_ref.5 [symbolic = %.2 (constants.%.7)] // CHECK:STDOUT: // CHECK:STDOUT: interface { // CHECK:STDOUT: !members: @@ -497,23 +506,25 @@ fn StaticMemberFunctionCall(T:! type) -> Class(T) { // CHECK:STDOUT: !definition: // CHECK:STDOUT: %Make.type: type = fn_type @Make, @Class(%T.loc8_29.2) [symbolic = %Make.type (constants.%Make.type)] // CHECK:STDOUT: %Make: @StaticMemberFunctionCall.%Make.type (%Make.type) = struct_value () [symbolic = %Make (constants.%Make)] +// CHECK:STDOUT: %.loc15_18.3: = specific_function %Make, @Make(%T.loc8_29.2) [symbolic = %.loc15_18.3 (constants.%.5)] // CHECK:STDOUT: %ImplicitAs.type.loc15_25.2: type = interface_type @ImplicitAs, @ImplicitAs(%Class.loc8_47.2) [symbolic = %ImplicitAs.type.loc15_25.2 (constants.%ImplicitAs.type.3)] // CHECK:STDOUT: %Convert.type: type = fn_type @Convert, @ImplicitAs(%Class.loc8_47.2) [symbolic = %Convert.type (constants.%Convert.type.2)] -// CHECK:STDOUT: %.loc15_25.3: type = assoc_entity_type @StaticMemberFunctionCall.%ImplicitAs.type.loc15_25.2 (%ImplicitAs.type.3), @StaticMemberFunctionCall.%Convert.type (%Convert.type.2) [symbolic = %.loc15_25.3 (constants.%.7)] -// CHECK:STDOUT: %.loc15_25.4: @StaticMemberFunctionCall.%.loc15_25.3 (%.7) = assoc_entity element0, imports.%import_ref.5 [symbolic = %.loc15_25.4 (constants.%.8)] +// CHECK:STDOUT: %.loc15_25.3: type = assoc_entity_type @StaticMemberFunctionCall.%ImplicitAs.type.loc15_25.2 (%ImplicitAs.type.3), @StaticMemberFunctionCall.%Convert.type (%Convert.type.2) [symbolic = %.loc15_25.3 (constants.%.8)] +// CHECK:STDOUT: %.loc15_25.4: @StaticMemberFunctionCall.%.loc15_25.3 (%.8) = assoc_entity element0, imports.%import_ref.5 [symbolic = %.loc15_25.4 (constants.%.9)] // CHECK:STDOUT: // CHECK:STDOUT: fn(%T.loc8_29.1: type) -> %return: @StaticMemberFunctionCall.%Class.loc8_47.2 (%Class.2) { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Class.ref.loc15: %Class.type = name_ref Class, file.%Class.decl [template = constants.%Class.1] // CHECK:STDOUT: %T.ref.loc15: type = name_ref T, %T.loc8_29.1 [symbolic = %T.loc8_29.2 (constants.%T)] // CHECK:STDOUT: %Class.loc15: type = class_type @Class, @Class(constants.%T) [symbolic = %Class.loc8_47.2 (constants.%Class.2)] -// CHECK:STDOUT: %.loc15_18: @StaticMemberFunctionCall.%Make.type (%Make.type) = specific_constant @Class.%Make.decl, @Class(constants.%T) [symbolic = %Make (constants.%Make)] -// CHECK:STDOUT: %Make.ref: @StaticMemberFunctionCall.%Make.type (%Make.type) = name_ref Make, %.loc15_18 [symbolic = %Make (constants.%Make)] +// CHECK:STDOUT: %.loc15_18.1: @StaticMemberFunctionCall.%Make.type (%Make.type) = specific_constant @Class.%Make.decl, @Class(constants.%T) [symbolic = %Make (constants.%Make)] +// CHECK:STDOUT: %Make.ref: @StaticMemberFunctionCall.%Make.type (%Make.type) = name_ref Make, %.loc15_18.1 [symbolic = %Make (constants.%Make)] +// CHECK:STDOUT: %.loc15_18.2: = specific_function %Make.ref, @Make(constants.%T) [symbolic = %.loc15_18.3 (constants.%.5)] // CHECK:STDOUT: %.loc15_23.1: ref @StaticMemberFunctionCall.%Class.loc8_47.2 (%Class.2) = temporary_storage -// CHECK:STDOUT: %Make.call: init @StaticMemberFunctionCall.%Class.loc8_47.2 (%Class.2) = call %Make.ref() to %.loc15_23.1 +// CHECK:STDOUT: %Make.call: init @StaticMemberFunctionCall.%Class.loc8_47.2 (%Class.2) = call %.loc15_18.2() to %.loc15_23.1 // CHECK:STDOUT: %ImplicitAs.type.loc15_25.1: type = interface_type @ImplicitAs, @ImplicitAs(constants.%Class.2) [symbolic = %ImplicitAs.type.loc15_25.2 (constants.%ImplicitAs.type.3)] -// CHECK:STDOUT: %.loc15_25.1: @StaticMemberFunctionCall.%.loc15_25.3 (%.7) = specific_constant imports.%import_ref.3, @ImplicitAs(constants.%Class.2) [symbolic = %.loc15_25.4 (constants.%.8)] -// CHECK:STDOUT: %Convert.ref: @StaticMemberFunctionCall.%.loc15_25.3 (%.7) = name_ref Convert, %.loc15_25.1 [symbolic = %.loc15_25.4 (constants.%.8)] +// CHECK:STDOUT: %.loc15_25.1: @StaticMemberFunctionCall.%.loc15_25.3 (%.8) = specific_constant imports.%import_ref.3, @ImplicitAs(constants.%Class.2) [symbolic = %.loc15_25.4 (constants.%.9)] +// CHECK:STDOUT: %Convert.ref: @StaticMemberFunctionCall.%.loc15_25.3 (%.8) = name_ref Convert, %.loc15_25.1 [symbolic = %.loc15_25.4 (constants.%.9)] // CHECK:STDOUT: %.loc15_23.2: ref @StaticMemberFunctionCall.%Class.loc8_47.2 (%Class.2) = temporary %.loc15_23.1, %Make.call // CHECK:STDOUT: %.loc15_25.2: @StaticMemberFunctionCall.%Class.loc8_47.2 (%Class.2) = converted %Make.call, [template = ] // CHECK:STDOUT: return to %return @@ -543,6 +554,9 @@ fn StaticMemberFunctionCall(T:! type) -> Class(T) { // CHECK:STDOUT: specific @Make(constants.%T) { // CHECK:STDOUT: %T => constants.%T // CHECK:STDOUT: %Class.loc5_21.1 => constants.%Class.2 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %struct => constants.%struct // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Class(@Class.%T.loc4_13.2) { @@ -584,8 +598,13 @@ fn StaticMemberFunctionCall(T:! type) -> Class(T) { // CHECK:STDOUT: %Self => constants.%Self.2 // CHECK:STDOUT: %Convert.type => constants.%Convert.type.2 // CHECK:STDOUT: %Convert => constants.%Convert.2 -// CHECK:STDOUT: %.1 => constants.%.7 -// CHECK:STDOUT: %.2 => constants.%.8 +// CHECK:STDOUT: %.1 => constants.%.8 +// CHECK:STDOUT: %.2 => constants.%.9 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Make(@StaticMemberFunctionCall.%T.loc8_29.2) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: %Class.loc5_21.1 => constants.%Class.2 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @ImplicitAs(@StaticMemberFunctionCall.%Class.loc8_47.2) { diff --git a/toolchain/check/testdata/class/generic/method_deduce.carbon b/toolchain/check/testdata/class/generic/method_deduce.carbon index 20c46588c9fb..81b1db19c516 100644 --- a/toolchain/check/testdata/class/generic/method_deduce.carbon +++ b/toolchain/check/testdata/class/generic/method_deduce.carbon @@ -12,8 +12,8 @@ class A {} class B {} class Class(T:! type) { - fn Get(U:! type) -> (T, U); - fn GetNoDeduce(x: T, U:! type) -> (T, U); + fn Get(U:! type) -> (T, U) { return Get(U); } + fn GetNoDeduce(x: T, U:! type) -> (T, U) { return GetNoDeduce(x, U); } } fn CallGenericMethod(c: Class(A)) -> (A, B) { @@ -43,19 +43,24 @@ fn CallGenericMethodWithNonDeducedParam(c: Class(A)) -> (A, B) { // CHECK:STDOUT: %Get.1: %Get.type.1 = struct_value () [symbolic] // CHECK:STDOUT: %GetNoDeduce.type.1: type = fn_type @GetNoDeduce, @Class(%T) [symbolic] // CHECK:STDOUT: %GetNoDeduce.1: %GetNoDeduce.type.1 = struct_value () [symbolic] +// CHECK:STDOUT: %.6: type = ptr_type %.5 [symbolic] +// CHECK:STDOUT: %.7: = specific_function %Get.1, @Get(%T, %U) [symbolic] +// CHECK:STDOUT: %.8: = specific_function %GetNoDeduce.1, @GetNoDeduce(%T, %U) [symbolic] // CHECK:STDOUT: %Class.3: type = class_type @Class, @Class(%A) [template] -// CHECK:STDOUT: %.6: type = tuple_type (%A, %B) [template] +// CHECK:STDOUT: %.9: type = tuple_type (%A, %B) [template] // CHECK:STDOUT: %CallGenericMethod.type: type = fn_type @CallGenericMethod [template] // CHECK:STDOUT: %CallGenericMethod: %CallGenericMethod.type = struct_value () [template] -// CHECK:STDOUT: %.7: type = ptr_type %.1 [template] -// CHECK:STDOUT: %.8: type = tuple_type (%.7, %.7) [template] -// CHECK:STDOUT: %.9: type = ptr_type %.8 [template] +// CHECK:STDOUT: %.10: type = ptr_type %.1 [template] +// CHECK:STDOUT: %.11: type = tuple_type (%.10, %.10) [template] +// CHECK:STDOUT: %.12: type = ptr_type %.11 [template] // CHECK:STDOUT: %Get.type.2: type = fn_type @Get, @Class(%A) [template] // CHECK:STDOUT: %Get.2: %Get.type.2 = struct_value () [template] // CHECK:STDOUT: %GetNoDeduce.type.2: type = fn_type @GetNoDeduce, @Class(%A) [template] // CHECK:STDOUT: %GetNoDeduce.2: %GetNoDeduce.type.2 = struct_value () [template] +// CHECK:STDOUT: %.13: = specific_function %Get.2, @Get(%A, %B) [template] // CHECK:STDOUT: %CallGenericMethodWithNonDeducedParam.type: type = fn_type @CallGenericMethodWithNonDeducedParam [template] // CHECK:STDOUT: %CallGenericMethodWithNonDeducedParam: %CallGenericMethodWithNonDeducedParam.type = struct_value () [template] +// CHECK:STDOUT: %.14: = specific_function %GetNoDeduce.2, @GetNoDeduce(%A, %B) [template] // CHECK:STDOUT: %struct: %A = struct_value () [template] // CHECK:STDOUT: } // CHECK:STDOUT: @@ -101,8 +106,8 @@ fn CallGenericMethodWithNonDeducedParam(c: Class(A)) -> (A, B) { // CHECK:STDOUT: %A.ref.loc19_39: type = name_ref A, file.%A.decl [template = constants.%A] // CHECK:STDOUT: %B.ref.loc19: type = name_ref B, file.%B.decl [template = constants.%B] // CHECK:STDOUT: %.loc19_43.1: %.4 = tuple_literal (%A.ref.loc19_39, %B.ref.loc19) -// CHECK:STDOUT: %.loc19_43.2: type = converted %.loc19_43.1, constants.%.6 [template = constants.%.6] -// CHECK:STDOUT: %return: ref %.6 = var +// CHECK:STDOUT: %.loc19_43.2: type = converted %.loc19_43.1, constants.%.9 [template = constants.%.9] +// CHECK:STDOUT: %return: ref %.9 = var // CHECK:STDOUT: } // CHECK:STDOUT: %CallGenericMethodWithNonDeducedParam.decl: %CallGenericMethodWithNonDeducedParam.type = fn_decl @CallGenericMethodWithNonDeducedParam [template = constants.%CallGenericMethodWithNonDeducedParam] { // CHECK:STDOUT: %c.patt: %Class.3 = binding_pattern c @@ -115,8 +120,8 @@ fn CallGenericMethodWithNonDeducedParam(c: Class(A)) -> (A, B) { // CHECK:STDOUT: %A.ref.loc23_58: type = name_ref A, file.%A.decl [template = constants.%A] // CHECK:STDOUT: %B.ref.loc23: type = name_ref B, file.%B.decl [template = constants.%B] // CHECK:STDOUT: %.loc23_62.1: %.4 = tuple_literal (%A.ref.loc23_58, %B.ref.loc23) -// CHECK:STDOUT: %.loc23_62.2: type = converted %.loc23_62.1, constants.%.6 [template = constants.%.6] -// CHECK:STDOUT: %return: ref %.6 = var +// CHECK:STDOUT: %.loc23_62.2: type = converted %.loc23_62.1, constants.%.9 [template = constants.%.9] +// CHECK:STDOUT: %return: ref %.9 = var // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: @@ -150,8 +155,8 @@ fn CallGenericMethodWithNonDeducedParam(c: Class(A)) -> (A, B) { // CHECK:STDOUT: %U.param: type = param U, runtime_param // CHECK:STDOUT: %U.loc15_10.1: type = bind_symbolic_name U, 1, %U.param [symbolic = %U.loc15_10.2 (constants.%U)] // CHECK:STDOUT: %T.ref: type = name_ref T, @Class.%T.loc14_13.1 [symbolic = %T (constants.%T)] -// CHECK:STDOUT: %U.ref: type = name_ref U, %U.loc15_10.1 [symbolic = %U.loc15_10.2 (constants.%U)] -// CHECK:STDOUT: %.loc15_28.2: %.4 = tuple_literal (%T.ref, %U.ref) +// CHECK:STDOUT: %U.ref.loc15_27: type = name_ref U, %U.loc15_10.1 [symbolic = %U.loc15_10.2 (constants.%U)] +// CHECK:STDOUT: %.loc15_28.2: %.4 = tuple_literal (%T.ref, %U.ref.loc15_27) // CHECK:STDOUT: %.loc15_28.3: type = converted %.loc15_28.2, constants.%.5 [symbolic = %.loc15_28.1 (constants.%.5)] // CHECK:STDOUT: %return: ref @Get.%.loc15_28.1 (%.5) = var // CHECK:STDOUT: } @@ -165,8 +170,8 @@ fn CallGenericMethodWithNonDeducedParam(c: Class(A)) -> (A, B) { // CHECK:STDOUT: %U.param: type = param U, runtime_param // CHECK:STDOUT: %U.loc16_24.1: type = bind_symbolic_name U, 1, %U.param [symbolic = %U.loc16_24.2 (constants.%U)] // CHECK:STDOUT: %T.ref.loc16_38: type = name_ref T, @Class.%T.loc14_13.1 [symbolic = %T (constants.%T)] -// CHECK:STDOUT: %U.ref: type = name_ref U, %U.loc16_24.1 [symbolic = %U.loc16_24.2 (constants.%U)] -// CHECK:STDOUT: %.loc16_42.2: %.4 = tuple_literal (%T.ref.loc16_38, %U.ref) +// CHECK:STDOUT: %U.ref.loc16_41: type = name_ref U, %U.loc16_24.1 [symbolic = %U.loc16_24.2 (constants.%U)] +// CHECK:STDOUT: %.loc16_42.2: %.4 = tuple_literal (%T.ref.loc16_38, %U.ref.loc16_41) // CHECK:STDOUT: %.loc16_42.3: type = converted %.loc16_42.2, constants.%.5 [symbolic = %.loc16_42.1 (constants.%.5)] // CHECK:STDOUT: %return: ref @GetNoDeduce.%.loc16_42.1 (%.5) = var // CHECK:STDOUT: } @@ -184,7 +189,32 @@ fn CallGenericMethodWithNonDeducedParam(c: Class(A)) -> (A, B) { // CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)] // CHECK:STDOUT: %.loc15_28.1: type = tuple_type (@Get.%T (%T), @Get.%U.loc15_10.2 (%U)) [symbolic = %.loc15_28.1 (constants.%.5)] // CHECK:STDOUT: -// CHECK:STDOUT: fn(%U.loc15_10.1: type) -> @Get.%.loc15_28.1 (%.5); +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %Get.type: type = fn_type @Get, @Class(%T) [symbolic = %Get.type (constants.%Get.type.1)] +// CHECK:STDOUT: %Get: @Get.%Get.type (%Get.type.1) = struct_value () [symbolic = %Get (constants.%Get.1)] +// CHECK:STDOUT: %.loc15_39.3: = specific_function %Get, @Get(%T, %U.loc15_10.2) [symbolic = %.loc15_39.3 (constants.%.7)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn(%U.loc15_10.1: type) -> %return: @Get.%.loc15_28.1 (%.5) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc15_39.1: @Get.%Get.type (%Get.type.1) = specific_constant @Class.%Get.decl, @Class(constants.%T) [symbolic = %Get (constants.%Get.1)] +// CHECK:STDOUT: %Get.ref: @Get.%Get.type (%Get.type.1) = name_ref Get, %.loc15_39.1 [symbolic = %Get (constants.%Get.1)] +// CHECK:STDOUT: %U.ref.loc15_43: type = name_ref U, %U.loc15_10.1 [symbolic = %U.loc15_10.2 (constants.%U)] +// CHECK:STDOUT: %.loc15_39.2: = specific_function %Get.ref, @Get(constants.%T, constants.%U) [symbolic = %.loc15_39.3 (constants.%.7)] +// CHECK:STDOUT: %.loc15_42.1: ref @Get.%.loc15_28.1 (%.5) = temporary_storage +// CHECK:STDOUT: %Get.call: init @Get.%.loc15_28.1 (%.5) = call %.loc15_39.2() to %.loc15_42.1 +// CHECK:STDOUT: %.loc15_42.2: ref @Get.%.loc15_28.1 (%.5) = temporary %.loc15_42.1, %Get.call +// CHECK:STDOUT: %.loc15_42.3: ref @Get.%T (%T) = tuple_access %.loc15_42.2, element0 +// CHECK:STDOUT: %.loc15_42.4: @Get.%T (%T) = bind_value %.loc15_42.3 +// CHECK:STDOUT: %.loc15_42.5: ref @Get.%T (%T) = tuple_access %return, element0 +// CHECK:STDOUT: %.loc15_42.6: init @Get.%T (%T) = initialize_from %.loc15_42.4 to %.loc15_42.5 +// CHECK:STDOUT: %.loc15_42.7: ref @Get.%U.loc15_10.2 (%U) = tuple_access %.loc15_42.2, element1 +// CHECK:STDOUT: %.loc15_42.8: @Get.%U.loc15_10.2 (%U) = bind_value %.loc15_42.7 +// CHECK:STDOUT: %.loc15_42.9: ref @Get.%U.loc15_10.2 (%U) = tuple_access %return, element1 +// CHECK:STDOUT: %.loc15_42.10: init @Get.%U.loc15_10.2 (%U) = initialize_from %.loc15_42.8 to %.loc15_42.9 +// CHECK:STDOUT: %.loc15_42.11: init @Get.%.loc15_28.1 (%.5) = tuple_init (%.loc15_42.6, %.loc15_42.10) to %return +// CHECK:STDOUT: %.loc15_45: init @Get.%.loc15_28.1 (%.5) = converted %Get.call, %.loc15_42.11 +// CHECK:STDOUT: return %.loc15_45 to %return +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic fn @GetNoDeduce(@Class.%T.loc14_13.1: type, %U.loc16_24.1: type) { @@ -192,57 +222,121 @@ fn CallGenericMethodWithNonDeducedParam(c: Class(A)) -> (A, B) { // CHECK:STDOUT: %U.loc16_24.2: type = bind_symbolic_name U, 1 [symbolic = %U.loc16_24.2 (constants.%U)] // CHECK:STDOUT: %.loc16_42.1: type = tuple_type (@GetNoDeduce.%T (%T), @GetNoDeduce.%U.loc16_24.2 (%U)) [symbolic = %.loc16_42.1 (constants.%.5)] // CHECK:STDOUT: -// CHECK:STDOUT: fn(%x: @GetNoDeduce.%T (%T), %U.loc16_24.1: type) -> @GetNoDeduce.%.loc16_42.1 (%.5); +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %GetNoDeduce.type: type = fn_type @GetNoDeduce, @Class(%T) [symbolic = %GetNoDeduce.type (constants.%GetNoDeduce.type.1)] +// CHECK:STDOUT: %GetNoDeduce: @GetNoDeduce.%GetNoDeduce.type (%GetNoDeduce.type.1) = struct_value () [symbolic = %GetNoDeduce (constants.%GetNoDeduce.1)] +// CHECK:STDOUT: %.loc16_53.3: = specific_function %GetNoDeduce, @GetNoDeduce(%T, %U.loc16_24.2) [symbolic = %.loc16_53.3 (constants.%.8)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn(%x: @GetNoDeduce.%T (%T), %U.loc16_24.1: type) -> %return: @GetNoDeduce.%.loc16_42.1 (%.5) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc16_53.1: @GetNoDeduce.%GetNoDeduce.type (%GetNoDeduce.type.1) = specific_constant @Class.%GetNoDeduce.decl, @Class(constants.%T) [symbolic = %GetNoDeduce (constants.%GetNoDeduce.1)] +// CHECK:STDOUT: %GetNoDeduce.ref: @GetNoDeduce.%GetNoDeduce.type (%GetNoDeduce.type.1) = name_ref GetNoDeduce, %.loc16_53.1 [symbolic = %GetNoDeduce (constants.%GetNoDeduce.1)] +// CHECK:STDOUT: %x.ref: @GetNoDeduce.%T (%T) = name_ref x, %x +// CHECK:STDOUT: %U.ref.loc16_68: type = name_ref U, %U.loc16_24.1 [symbolic = %U.loc16_24.2 (constants.%U)] +// CHECK:STDOUT: %.loc16_53.2: = specific_function %GetNoDeduce.ref, @GetNoDeduce(constants.%T, constants.%U) [symbolic = %.loc16_53.3 (constants.%.8)] +// CHECK:STDOUT: %.loc16_64.1: ref @GetNoDeduce.%.loc16_42.1 (%.5) = temporary_storage +// CHECK:STDOUT: %GetNoDeduce.call: init @GetNoDeduce.%.loc16_42.1 (%.5) = call %.loc16_53.2(%x.ref) to %.loc16_64.1 +// CHECK:STDOUT: %.loc16_64.2: ref @GetNoDeduce.%.loc16_42.1 (%.5) = temporary %.loc16_64.1, %GetNoDeduce.call +// CHECK:STDOUT: %.loc16_64.3: ref @GetNoDeduce.%T (%T) = tuple_access %.loc16_64.2, element0 +// CHECK:STDOUT: %.loc16_64.4: @GetNoDeduce.%T (%T) = bind_value %.loc16_64.3 +// CHECK:STDOUT: %.loc16_64.5: ref @GetNoDeduce.%T (%T) = tuple_access %return, element0 +// CHECK:STDOUT: %.loc16_64.6: init @GetNoDeduce.%T (%T) = initialize_from %.loc16_64.4 to %.loc16_64.5 +// CHECK:STDOUT: %.loc16_64.7: ref @GetNoDeduce.%U.loc16_24.2 (%U) = tuple_access %.loc16_64.2, element1 +// CHECK:STDOUT: %.loc16_64.8: @GetNoDeduce.%U.loc16_24.2 (%U) = bind_value %.loc16_64.7 +// CHECK:STDOUT: %.loc16_64.9: ref @GetNoDeduce.%U.loc16_24.2 (%U) = tuple_access %return, element1 +// CHECK:STDOUT: %.loc16_64.10: init @GetNoDeduce.%U.loc16_24.2 (%U) = initialize_from %.loc16_64.8 to %.loc16_64.9 +// CHECK:STDOUT: %.loc16_64.11: init @GetNoDeduce.%.loc16_42.1 (%.5) = tuple_init (%.loc16_64.6, %.loc16_64.10) to %return +// CHECK:STDOUT: %.loc16_70: init @GetNoDeduce.%.loc16_42.1 (%.5) = converted %GetNoDeduce.call, %.loc16_64.11 +// CHECK:STDOUT: return %.loc16_70 to %return +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @CallGenericMethod(%c: %Class.3) -> %return: %.6 { +// CHECK:STDOUT: fn @CallGenericMethod(%c: %Class.3) -> %return: %.9 { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %c.ref: %Class.3 = name_ref c, %c -// CHECK:STDOUT: %.loc20: %Get.type.2 = specific_constant @Class.%Get.decl, @Class(constants.%A) [template = constants.%Get.2] -// CHECK:STDOUT: %Get.ref: %Get.type.2 = name_ref Get, %.loc20 [template = constants.%Get.2] +// CHECK:STDOUT: %.loc20_11.1: %Get.type.2 = specific_constant @Class.%Get.decl, @Class(constants.%A) [template = constants.%Get.2] +// CHECK:STDOUT: %Get.ref: %Get.type.2 = name_ref Get, %.loc20_11.1 [template = constants.%Get.2] // CHECK:STDOUT: %B.ref.loc20: type = name_ref B, file.%B.decl [template = constants.%B] -// CHECK:STDOUT: %.loc19_35: ref %.6 = splice_block %return {} -// CHECK:STDOUT: %Get.call: init %.6 = call %Get.ref() to %.loc19_35 +// CHECK:STDOUT: %.loc20_11.2: = specific_function %Get.ref, @Get(constants.%A, constants.%B) [template = constants.%.13] +// CHECK:STDOUT: %.loc19_35: ref %.9 = splice_block %return {} +// CHECK:STDOUT: %Get.call: init %.9 = call %.loc20_11.2() to %.loc19_35 // CHECK:STDOUT: return %Get.call to %return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @CallGenericMethodWithNonDeducedParam(%c: %Class.3) -> %return: %.6 { +// CHECK:STDOUT: fn @CallGenericMethodWithNonDeducedParam(%c: %Class.3) -> %return: %.9 { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %c.ref: %Class.3 = name_ref c, %c -// CHECK:STDOUT: %.loc24_11: %GetNoDeduce.type.2 = specific_constant @Class.%GetNoDeduce.decl, @Class(constants.%A) [template = constants.%GetNoDeduce.2] -// CHECK:STDOUT: %GetNoDeduce.ref: %GetNoDeduce.type.2 = name_ref GetNoDeduce, %.loc24_11 [template = constants.%GetNoDeduce.2] +// CHECK:STDOUT: %.loc24_11.1: %GetNoDeduce.type.2 = specific_constant @Class.%GetNoDeduce.decl, @Class(constants.%A) [template = constants.%GetNoDeduce.2] +// CHECK:STDOUT: %GetNoDeduce.ref: %GetNoDeduce.type.2 = name_ref GetNoDeduce, %.loc24_11.1 [template = constants.%GetNoDeduce.2] // CHECK:STDOUT: %.loc24_25.1: %.1 = struct_literal () // CHECK:STDOUT: %B.ref.loc24: type = name_ref B, file.%B.decl [template = constants.%B] -// CHECK:STDOUT: %.loc23_54: ref %.6 = splice_block %return {} +// CHECK:STDOUT: %.loc24_11.2: = specific_function %GetNoDeduce.ref, @GetNoDeduce(constants.%A, constants.%B) [template = constants.%.14] +// CHECK:STDOUT: %.loc23_54: ref %.9 = splice_block %return {} // CHECK:STDOUT: %.loc24_25.2: ref %A = temporary_storage // CHECK:STDOUT: %.loc24_25.3: init %A = class_init (), %.loc24_25.2 [template = constants.%struct] // CHECK:STDOUT: %.loc24_25.4: ref %A = temporary %.loc24_25.2, %.loc24_25.3 // CHECK:STDOUT: %.loc24_23.1: ref %A = converted %.loc24_25.1, %.loc24_25.4 // CHECK:STDOUT: %.loc24_23.2: %A = bind_value %.loc24_23.1 -// CHECK:STDOUT: %GetNoDeduce.call: init %.6 = call %GetNoDeduce.ref(%.loc24_23.2) to %.loc23_54 +// CHECK:STDOUT: %GetNoDeduce.call: init %.9 = call %.loc24_11.2(%.loc24_23.2) to %.loc23_54 // CHECK:STDOUT: return %GetNoDeduce.call to %return // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Class(constants.%T) { // CHECK:STDOUT: %T.loc14_13.2 => constants.%T +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %Get.type => constants.%Get.type.1 +// CHECK:STDOUT: %Get => constants.%Get.1 +// CHECK:STDOUT: %GetNoDeduce.type => constants.%GetNoDeduce.type.1 +// CHECK:STDOUT: %GetNoDeduce => constants.%GetNoDeduce.1 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Get(constants.%T, constants.%U) { // CHECK:STDOUT: %U.loc15_10.2 => constants.%U // CHECK:STDOUT: %T => constants.%T // CHECK:STDOUT: %.loc15_28.1 => constants.%.5 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %Get.type => constants.%Get.type.1 +// CHECK:STDOUT: %Get => constants.%Get.1 +// CHECK:STDOUT: %.loc15_39.3 => constants.%.7 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @GetNoDeduce(constants.%T, constants.%U) { // CHECK:STDOUT: %T => constants.%T // CHECK:STDOUT: %U.loc16_24.2 => constants.%U // CHECK:STDOUT: %.loc16_42.1 => constants.%.5 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %GetNoDeduce.type => constants.%GetNoDeduce.type.1 +// CHECK:STDOUT: %GetNoDeduce => constants.%GetNoDeduce.1 +// CHECK:STDOUT: %.loc16_53.3 => constants.%.8 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Class(@Class.%T.loc14_13.2) { // CHECK:STDOUT: %T.loc14_13.2 => constants.%T // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Class(@Get.%T) { +// CHECK:STDOUT: %T.loc14_13.2 => constants.%T +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Get(@Get.%T, @Get.%U.loc15_10.2) { +// CHECK:STDOUT: %U.loc15_10.2 => constants.%U +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: %.loc15_28.1 => constants.%.5 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Class(@GetNoDeduce.%T) { +// CHECK:STDOUT: %T.loc14_13.2 => constants.%T +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @GetNoDeduce(@GetNoDeduce.%T, @GetNoDeduce.%U.loc16_24.2) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: %U.loc16_24.2 => constants.%U +// CHECK:STDOUT: %.loc16_42.1 => constants.%.5 +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: specific @Class(constants.%A) { // CHECK:STDOUT: %T.loc14_13.2 => constants.%A // CHECK:STDOUT: @@ -256,12 +350,22 @@ fn CallGenericMethodWithNonDeducedParam(c: Class(A)) -> (A, B) { // CHECK:STDOUT: specific @Get(constants.%A, constants.%B) { // CHECK:STDOUT: %U.loc15_10.2 => constants.%B // CHECK:STDOUT: %T => constants.%A -// CHECK:STDOUT: %.loc15_28.1 => constants.%.6 +// CHECK:STDOUT: %.loc15_28.1 => constants.%.9 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %Get.type => constants.%Get.type.2 +// CHECK:STDOUT: %Get => constants.%Get.2 +// CHECK:STDOUT: %.loc15_39.3 => constants.%.13 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @GetNoDeduce(constants.%A, constants.%B) { // CHECK:STDOUT: %T => constants.%A // CHECK:STDOUT: %U.loc16_24.2 => constants.%B -// CHECK:STDOUT: %.loc16_42.1 => constants.%.6 +// CHECK:STDOUT: %.loc16_42.1 => constants.%.9 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %GetNoDeduce.type => constants.%GetNoDeduce.type.2 +// CHECK:STDOUT: %GetNoDeduce => constants.%GetNoDeduce.2 +// CHECK:STDOUT: %.loc16_53.3 => constants.%.14 // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/class/generic/self.carbon b/toolchain/check/testdata/class/generic/self.carbon index 99ef28fee0f0..e72bd766f34d 100644 --- a/toolchain/check/testdata/class/generic/self.carbon +++ b/toolchain/check/testdata/class/generic/self.carbon @@ -11,8 +11,8 @@ class Class(T:! type) { // `Self` is the same as `Class(T)` here. // TODO: Find a better way to test two types are the same. - fn MakeSelf() -> Self; - fn MakeClass() -> Class(T); + fn MakeSelf() -> Self { return {}; } + fn MakeClass() -> Class(T) { return {}; } fn F() { var c: Class(T) = MakeSelf(); var s: Self = MakeClass(); @@ -36,6 +36,9 @@ class Class(T:! type) { // CHECK:STDOUT: %.2: type = struct_type {} [template] // CHECK:STDOUT: %.3: = complete_type_witness %.2 [template] // CHECK:STDOUT: %.4: type = ptr_type %.2 [template] +// CHECK:STDOUT: %struct: %Class.2 = struct_value () [symbolic] +// CHECK:STDOUT: %.5: = specific_function %MakeSelf, @MakeSelf(%T) [symbolic] +// CHECK:STDOUT: %.6: = specific_function %MakeClass, @MakeClass(%T) [symbolic] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -78,8 +81,8 @@ class Class(T:! type) { // CHECK:STDOUT: // CHECK:STDOUT: class { // CHECK:STDOUT: %MakeSelf.decl: @Class.%MakeSelf.type (%MakeSelf.type) = fn_decl @MakeSelf [symbolic = @Class.%MakeSelf (constants.%MakeSelf)] {} { -// CHECK:STDOUT: %.loc14: type = specific_constant constants.%Class.2, @Class(constants.%T) [symbolic = %Class (constants.%Class.2)] -// CHECK:STDOUT: %Self.ref: type = name_ref Self, %.loc14 [symbolic = %Class (constants.%Class.2)] +// CHECK:STDOUT: %.loc14_20: type = specific_constant constants.%Class.2, @Class(constants.%T) [symbolic = %Class (constants.%Class.2)] +// CHECK:STDOUT: %Self.ref: type = name_ref Self, %.loc14_20 [symbolic = %Class (constants.%Class.2)] // CHECK:STDOUT: %return: ref @MakeSelf.%Class (%Class.2) = var // CHECK:STDOUT: } // CHECK:STDOUT: %MakeClass.decl: @Class.%MakeClass.type (%MakeClass.type) = fn_decl @MakeClass [symbolic = @Class.%MakeClass (constants.%MakeClass)] {} { @@ -103,14 +106,32 @@ class Class(T:! type) { // CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)] // CHECK:STDOUT: %Class: type = class_type @Class, @Class(%T) [symbolic = %Class (constants.%Class.2)] // CHECK:STDOUT: -// CHECK:STDOUT: fn() -> @MakeSelf.%Class (%Class.2); +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %struct: @MakeSelf.%Class (%Class.2) = struct_value () [symbolic = %struct (constants.%struct)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn() -> %return: @MakeSelf.%Class (%Class.2) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc14_35.1: %.2 = struct_literal () +// CHECK:STDOUT: %.loc14_35.2: init @MakeSelf.%Class (%Class.2) = class_init (), %return [symbolic = %struct (constants.%struct)] +// CHECK:STDOUT: %.loc14_36: init @MakeSelf.%Class (%Class.2) = converted %.loc14_35.1, %.loc14_35.2 [symbolic = %struct (constants.%struct)] +// CHECK:STDOUT: return %.loc14_36 to %return +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic fn @MakeClass(@Class.%T.loc11_13.1: type) { // CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)] // CHECK:STDOUT: %Class.loc15_26.1: type = class_type @Class, @Class(%T) [symbolic = %Class.loc15_26.1 (constants.%Class.2)] // CHECK:STDOUT: -// CHECK:STDOUT: fn() -> @MakeClass.%Class.loc15_26.1 (%Class.2); +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %struct: @MakeClass.%Class.loc15_26.1 (%Class.2) = struct_value () [symbolic = %struct (constants.%struct)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn() -> %return: @MakeClass.%Class.loc15_26.1 (%Class.2) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc15_40.1: %.2 = struct_literal () +// CHECK:STDOUT: %.loc15_40.2: init @MakeClass.%Class.loc15_26.1 (%Class.2) = class_init (), %return [symbolic = %struct (constants.%struct)] +// CHECK:STDOUT: %.loc15_41: init @MakeClass.%Class.loc15_26.1 (%Class.2) = converted %.loc15_40.1, %.loc15_40.2 [symbolic = %struct (constants.%struct)] +// CHECK:STDOUT: return %.loc15_41 to %return +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic fn @F(@Class.%T.loc11_13.1: type) { @@ -119,8 +140,10 @@ class Class(T:! type) { // CHECK:STDOUT: %Class.loc17_17.2: type = class_type @Class, @Class(%T) [symbolic = %Class.loc17_17.2 (constants.%Class.2)] // CHECK:STDOUT: %MakeSelf.type: type = fn_type @MakeSelf, @Class(%T) [symbolic = %MakeSelf.type (constants.%MakeSelf.type)] // CHECK:STDOUT: %MakeSelf: @F.%MakeSelf.type (%MakeSelf.type) = struct_value () [symbolic = %MakeSelf (constants.%MakeSelf)] +// CHECK:STDOUT: %.loc17_23.3: = specific_function %MakeSelf, @MakeSelf(%T) [symbolic = %.loc17_23.3 (constants.%.5)] // CHECK:STDOUT: %MakeClass.type: type = fn_type @MakeClass, @Class(%T) [symbolic = %MakeClass.type (constants.%MakeClass.type)] // CHECK:STDOUT: %MakeClass: @F.%MakeClass.type (%MakeClass.type) = struct_value () [symbolic = %MakeClass (constants.%MakeClass)] +// CHECK:STDOUT: %.loc18_19.3: = specific_function %MakeClass, @MakeClass(%T) [symbolic = %.loc18_19.3 (constants.%.6)] // CHECK:STDOUT: // CHECK:STDOUT: fn() { // CHECK:STDOUT: !entry: @@ -129,19 +152,21 @@ class Class(T:! type) { // CHECK:STDOUT: %Class.loc17_17.1: type = class_type @Class, @Class(constants.%T) [symbolic = %Class.loc17_17.2 (constants.%Class.2)] // CHECK:STDOUT: %c.var: ref @F.%Class.loc17_17.2 (%Class.2) = var c // CHECK:STDOUT: %c: ref @F.%Class.loc17_17.2 (%Class.2) = bind_name c, %c.var -// CHECK:STDOUT: %.loc17_23: @F.%MakeSelf.type (%MakeSelf.type) = specific_constant @Class.%MakeSelf.decl, @Class(constants.%T) [symbolic = %MakeSelf (constants.%MakeSelf)] -// CHECK:STDOUT: %MakeSelf.ref: @F.%MakeSelf.type (%MakeSelf.type) = name_ref MakeSelf, %.loc17_23 [symbolic = %MakeSelf (constants.%MakeSelf)] +// CHECK:STDOUT: %.loc17_23.1: @F.%MakeSelf.type (%MakeSelf.type) = specific_constant @Class.%MakeSelf.decl, @Class(constants.%T) [symbolic = %MakeSelf (constants.%MakeSelf)] +// CHECK:STDOUT: %MakeSelf.ref: @F.%MakeSelf.type (%MakeSelf.type) = name_ref MakeSelf, %.loc17_23.1 [symbolic = %MakeSelf (constants.%MakeSelf)] +// CHECK:STDOUT: %.loc17_23.2: = specific_function %MakeSelf.ref, @MakeSelf(constants.%T) [symbolic = %.loc17_23.3 (constants.%.5)] // CHECK:STDOUT: %.loc17_9: ref @F.%Class.loc17_17.2 (%Class.2) = splice_block %c.var {} -// CHECK:STDOUT: %MakeSelf.call: init @F.%Class.loc17_17.2 (%Class.2) = call %MakeSelf.ref() to %.loc17_9 +// CHECK:STDOUT: %MakeSelf.call: init @F.%Class.loc17_17.2 (%Class.2) = call %.loc17_23.2() to %.loc17_9 // CHECK:STDOUT: assign %c.var, %MakeSelf.call // CHECK:STDOUT: %.loc18_12: type = specific_constant constants.%Class.2, @Class(constants.%T) [symbolic = %Class.loc17_17.2 (constants.%Class.2)] // CHECK:STDOUT: %Self.ref: type = name_ref Self, %.loc18_12 [symbolic = %Class.loc17_17.2 (constants.%Class.2)] // CHECK:STDOUT: %s.var: ref @F.%Class.loc17_17.2 (%Class.2) = var s // CHECK:STDOUT: %s: ref @F.%Class.loc17_17.2 (%Class.2) = bind_name s, %s.var -// CHECK:STDOUT: %.loc18_19: @F.%MakeClass.type (%MakeClass.type) = specific_constant @Class.%MakeClass.decl, @Class(constants.%T) [symbolic = %MakeClass (constants.%MakeClass)] -// CHECK:STDOUT: %MakeClass.ref: @F.%MakeClass.type (%MakeClass.type) = name_ref MakeClass, %.loc18_19 [symbolic = %MakeClass (constants.%MakeClass)] +// CHECK:STDOUT: %.loc18_19.1: @F.%MakeClass.type (%MakeClass.type) = specific_constant @Class.%MakeClass.decl, @Class(constants.%T) [symbolic = %MakeClass (constants.%MakeClass)] +// CHECK:STDOUT: %MakeClass.ref: @F.%MakeClass.type (%MakeClass.type) = name_ref MakeClass, %.loc18_19.1 [symbolic = %MakeClass (constants.%MakeClass)] +// CHECK:STDOUT: %.loc18_19.2: = specific_function %MakeClass.ref, @MakeClass(constants.%T) [symbolic = %.loc18_19.3 (constants.%.6)] // CHECK:STDOUT: %.loc18_9: ref @F.%Class.loc17_17.2 (%Class.2) = splice_block %s.var {} -// CHECK:STDOUT: %MakeClass.call: init @F.%Class.loc17_17.2 (%Class.2) = call %MakeClass.ref() to %.loc18_9 +// CHECK:STDOUT: %MakeClass.call: init @F.%Class.loc17_17.2 (%Class.2) = call %.loc18_19.2() to %.loc18_9 // CHECK:STDOUT: assign %s.var, %MakeClass.call // CHECK:STDOUT: return // CHECK:STDOUT: } @@ -166,6 +191,9 @@ class Class(T:! type) { // CHECK:STDOUT: specific @MakeSelf(constants.%T) { // CHECK:STDOUT: %T => constants.%T // CHECK:STDOUT: %Class => constants.%Class.2 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %struct => constants.%struct // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Class(@MakeClass.%T) { @@ -175,6 +203,9 @@ class Class(T:! type) { // CHECK:STDOUT: specific @MakeClass(constants.%T) { // CHECK:STDOUT: %T => constants.%T // CHECK:STDOUT: %Class.loc15_26.1 => constants.%Class.2 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %struct => constants.%struct // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @F(constants.%T) {} @@ -187,3 +218,13 @@ class Class(T:! type) { // CHECK:STDOUT: %T.loc11_13.2 => constants.%T // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @MakeSelf(@F.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: %Class => constants.%Class.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @MakeClass(@F.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: %Class.loc15_26.1 => constants.%Class.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/deduce/array.carbon b/toolchain/check/testdata/deduce/array.carbon index 667f0993274e..18a593fd2e5c 100644 --- a/toolchain/check/testdata/deduce/array.carbon +++ b/toolchain/check/testdata/deduce/array.carbon @@ -121,6 +121,7 @@ fn G() -> C { // CHECK:STDOUT: %.12: i32 = int_literal 1 [template] // CHECK:STDOUT: %.13: i32 = int_literal 2 [template] // CHECK:STDOUT: %array: %.9 = tuple_value (%struct, %struct, %struct) [template] +// CHECK:STDOUT: %.14: = specific_function %F, @F(%C) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -217,9 +218,10 @@ fn G() -> C { // CHECK:STDOUT: assign %a.var, %.loc9_31 // CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] // CHECK:STDOUT: %a.ref: ref %.9 = name_ref a, %a +// CHECK:STDOUT: %.loc10_10: = specific_function %F.ref, @F(constants.%C) [template = constants.%.14] // CHECK:STDOUT: %.loc8: ref %C = splice_block %return {} -// CHECK:STDOUT: %.loc10: %.9 = bind_value %a.ref -// CHECK:STDOUT: %F.call: init %C = call %F.ref(%.loc10) to %.loc8 +// CHECK:STDOUT: %.loc10_12: %.9 = bind_value %a.ref +// CHECK:STDOUT: %F.call: init %C = call %.loc10_10(%.loc10_12) to %.loc8 // CHECK:STDOUT: return %F.call to %return // CHECK:STDOUT: } // CHECK:STDOUT: @@ -231,6 +233,8 @@ fn G() -> C { // CHECK:STDOUT: specific @F(constants.%C) { // CHECK:STDOUT: %T.loc6_6.2 => constants.%C // CHECK:STDOUT: %.loc6_24.2 => constants.%.9 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_todo_bound_only.carbon @@ -518,7 +522,8 @@ fn G() -> C { // CHECK:STDOUT: %.13: i32 = int_literal 1 [template] // CHECK:STDOUT: %array: %.10 = tuple_value (%struct, %struct, %struct) [template] // CHECK:STDOUT: %.14: type = array_type %.3, %C [template] -// CHECK:STDOUT: %.15: type = ptr_type %.14 [template] +// CHECK:STDOUT: %.15: = specific_function %F, @F(%C) [template] +// CHECK:STDOUT: %.16: type = ptr_type %.14 [template] // CHECK:STDOUT: %ImplicitAs.type.1: type = generic_interface_type @ImplicitAs [template] // CHECK:STDOUT: %ImplicitAs: %ImplicitAs.type.1 = struct_value () [template] // CHECK:STDOUT: %Dest: type = bind_symbolic_name Dest, 0 [symbolic] @@ -527,14 +532,14 @@ fn G() -> C { // CHECK:STDOUT: %Self.2: %ImplicitAs.type.2 = bind_symbolic_name Self, 1 [symbolic] // CHECK:STDOUT: %Convert.type.1: type = fn_type @Convert, @ImplicitAs(%Dest) [symbolic] // CHECK:STDOUT: %Convert.1: %Convert.type.1 = struct_value () [symbolic] -// CHECK:STDOUT: %.16: type = assoc_entity_type %ImplicitAs.type.2, %Convert.type.1 [symbolic] -// CHECK:STDOUT: %.17: %.16 = assoc_entity element0, imports.%import_ref.5 [symbolic] +// CHECK:STDOUT: %.17: type = assoc_entity_type %ImplicitAs.type.2, %Convert.type.1 [symbolic] +// CHECK:STDOUT: %.18: %.17 = assoc_entity element0, imports.%import_ref.5 [symbolic] // CHECK:STDOUT: %ImplicitAs.type.3: type = interface_type @ImplicitAs, @ImplicitAs(%.14) [template] // CHECK:STDOUT: %Convert.type.2: type = fn_type @Convert, @ImplicitAs(%.14) [template] // CHECK:STDOUT: %Convert.2: %Convert.type.2 = struct_value () [template] -// CHECK:STDOUT: %.18: type = assoc_entity_type %ImplicitAs.type.3, %Convert.type.2 [template] -// CHECK:STDOUT: %.19: %.18 = assoc_entity element0, imports.%import_ref.5 [template] -// CHECK:STDOUT: %.20: %.16 = assoc_entity element0, imports.%import_ref.6 [symbolic] +// CHECK:STDOUT: %.19: type = assoc_entity_type %ImplicitAs.type.3, %Convert.type.2 [template] +// CHECK:STDOUT: %.20: %.19 = assoc_entity element0, imports.%import_ref.5 [template] +// CHECK:STDOUT: %.21: %.17 = assoc_entity element0, imports.%import_ref.6 [symbolic] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -551,7 +556,7 @@ fn G() -> C { // CHECK:STDOUT: } // CHECK:STDOUT: %import_ref.1: %ImplicitAs.type.1 = import_ref Core//prelude/operators/as, inst+40, loaded [template = constants.%ImplicitAs] // CHECK:STDOUT: %import_ref.2 = import_ref Core//prelude/operators/as, inst+45, unloaded -// CHECK:STDOUT: %import_ref.3: @ImplicitAs.%.1 (%.16) = import_ref Core//prelude/operators/as, inst+63, loaded [symbolic = @ImplicitAs.%.2 (constants.%.20)] +// CHECK:STDOUT: %import_ref.3: @ImplicitAs.%.1 (%.17) = import_ref Core//prelude/operators/as, inst+63, loaded [symbolic = @ImplicitAs.%.2 (constants.%.21)] // CHECK:STDOUT: %import_ref.4 = import_ref Core//prelude/operators/as, inst+56, unloaded // CHECK:STDOUT: %import_ref.5 = import_ref Core//prelude/operators/as, inst+56, unloaded // CHECK:STDOUT: %import_ref.6 = import_ref Core//prelude/operators/as, inst+56, unloaded @@ -594,8 +599,8 @@ fn G() -> C { // CHECK:STDOUT: %Self: %ImplicitAs.type.2 = bind_symbolic_name Self, 1 [symbolic = %Self (constants.%Self.2)] // CHECK:STDOUT: %Convert.type: type = fn_type @Convert, @ImplicitAs(%Dest) [symbolic = %Convert.type (constants.%Convert.type.1)] // CHECK:STDOUT: %Convert: @ImplicitAs.%Convert.type (%Convert.type.1) = struct_value () [symbolic = %Convert (constants.%Convert.1)] -// CHECK:STDOUT: %.1: type = assoc_entity_type @ImplicitAs.%ImplicitAs.type (%ImplicitAs.type.2), @ImplicitAs.%Convert.type (%Convert.type.1) [symbolic = %.1 (constants.%.16)] -// CHECK:STDOUT: %.2: @ImplicitAs.%.1 (%.16) = assoc_entity element0, imports.%import_ref.5 [symbolic = %.2 (constants.%.17)] +// CHECK:STDOUT: %.1: type = assoc_entity_type @ImplicitAs.%ImplicitAs.type (%ImplicitAs.type.2), @ImplicitAs.%Convert.type (%Convert.type.1) [symbolic = %.1 (constants.%.17)] +// CHECK:STDOUT: %.2: @ImplicitAs.%.1 (%.17) = assoc_entity element0, imports.%import_ref.5 [symbolic = %.2 (constants.%.18)] // CHECK:STDOUT: // CHECK:STDOUT: interface { // CHECK:STDOUT: !members: @@ -657,12 +662,13 @@ fn G() -> C { // CHECK:STDOUT: assign %a.var, %.loc10_31 // CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] // CHECK:STDOUT: %a.ref: ref %.10 = name_ref a, %a +// CHECK:STDOUT: %.loc21_10: = specific_function %F.ref, @F(constants.%C) [template = constants.%.15] // CHECK:STDOUT: %.loc21_11.1: ref %C = temporary_storage // CHECK:STDOUT: %ImplicitAs.type: type = interface_type @ImplicitAs, @ImplicitAs(constants.%.14) [template = constants.%ImplicitAs.type.3] -// CHECK:STDOUT: %.loc21_11.2: %.18 = specific_constant imports.%import_ref.3, @ImplicitAs(constants.%.14) [template = constants.%.19] -// CHECK:STDOUT: %Convert.ref: %.18 = name_ref Convert, %.loc21_11.2 [template = constants.%.19] +// CHECK:STDOUT: %.loc21_11.2: %.19 = specific_constant imports.%import_ref.3, @ImplicitAs(constants.%.14) [template = constants.%.20] +// CHECK:STDOUT: %Convert.ref: %.19 = name_ref Convert, %.loc21_11.2 [template = constants.%.20] // CHECK:STDOUT: %.loc21_11.3: %.14 = converted %a.ref, [template = ] -// CHECK:STDOUT: %F.call: init %C = call %F.ref() [template = ] +// CHECK:STDOUT: %F.call: init %C = call %.loc21_10() [template = ] // CHECK:STDOUT: return %F.call to %return // CHECK:STDOUT: } // CHECK:STDOUT: @@ -682,6 +688,8 @@ fn G() -> C { // CHECK:STDOUT: specific @F(constants.%C) { // CHECK:STDOUT: %T.loc6_6.2 => constants.%C // CHECK:STDOUT: %.loc6_24.2 => constants.%.14 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @ImplicitAs(constants.%Dest) { @@ -710,8 +718,8 @@ fn G() -> C { // CHECK:STDOUT: %Self => constants.%Self.2 // CHECK:STDOUT: %Convert.type => constants.%Convert.type.2 // CHECK:STDOUT: %Convert => constants.%Convert.2 -// CHECK:STDOUT: %.1 => constants.%.18 -// CHECK:STDOUT: %.2 => constants.%.19 +// CHECK:STDOUT: %.1 => constants.%.19 +// CHECK:STDOUT: %.2 => constants.%.20 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_type_mismatch.carbon diff --git a/toolchain/check/testdata/deduce/generic_type.carbon b/toolchain/check/testdata/deduce/generic_type.carbon index 48f827fedf49..11207e072134 100644 --- a/toolchain/check/testdata/deduce/generic_type.carbon +++ b/toolchain/check/testdata/deduce/generic_type.carbon @@ -15,7 +15,7 @@ library "[[@TEST_NAME]]"; class C(T:! type) {} class D {} -fn F[T:! type](p: C(T)) -> T; +fn F[T:! type](p: C(T)) -> T { return F(p); } fn G(p: C(D)) -> D { return F(p); @@ -28,7 +28,7 @@ library "[[@TEST_NAME]]"; class I(T:! type) {} class C {} -fn F[T:! type](p: I(T)) -> C; +fn F[T:! type](p: I(T)) -> C { return F(p); } fn G(p: I(C)) -> C { return F(p); @@ -47,7 +47,7 @@ class D {} // C++ doesn't permit deducing `T` here because `Outer` might be specialized. // But that's not possible in Carbon, so we can deduce `T`. -fn F[T:! type, U:! type](p: Outer(T).Inner(U)) -> (T, U); +fn F[T:! type, U:! type](p: Outer(T).Inner(U)) -> (T, U) { return F(p); } fn G(p: Outer(C).Inner(D)) -> (C, D) { return F(p); @@ -78,10 +78,12 @@ fn G() -> i32 { // CHECK:STDOUT: %D: type = class_type @D [template] // CHECK:STDOUT: %F.type: type = fn_type @F [template] // CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: %.4: type = ptr_type %.2 [template] +// CHECK:STDOUT: %.5: = specific_function %F, @F(%T) [symbolic] // CHECK:STDOUT: %C.3: type = class_type @C, @C(%D) [template] // CHECK:STDOUT: %G.type: type = fn_type @G [template] // CHECK:STDOUT: %G: %G.type = struct_value () [template] -// CHECK:STDOUT: %.4: type = ptr_type %.2 [template] +// CHECK:STDOUT: %.6: = specific_function %F, @F(%D) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -164,20 +166,35 @@ fn G() -> i32 { // CHECK:STDOUT: %T.loc7_6.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc7_6.2 (constants.%T)] // CHECK:STDOUT: %C.loc7_20.2: type = class_type @C, @C(%T.loc7_6.2) [symbolic = %C.loc7_20.2 (constants.%C.2)] // CHECK:STDOUT: -// CHECK:STDOUT: fn[%T.loc7_6.1: type](%p: @F.%C.loc7_20.2 (%C.2)) -> @F.%T.loc7_6.2 (%T); +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc7_39.2: = specific_function constants.%F, @F(%T.loc7_6.2) [symbolic = %.loc7_39.2 (constants.%.5)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%T.loc7_6.1: type](%p: @F.%C.loc7_20.2 (%C.2)) -> @F.%T.loc7_6.2 (%T) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] +// CHECK:STDOUT: %p.ref: @F.%C.loc7_20.2 (%C.2) = name_ref p, %p +// CHECK:STDOUT: %.loc7_39.1: = specific_function %F.ref, @F(constants.%T) [symbolic = %.loc7_39.2 (constants.%.5)] +// CHECK:STDOUT: %F.call: init @F.%T.loc7_6.2 (%T) = call %.loc7_39.1(%p.ref) +// CHECK:STDOUT: %.loc7_43.1: @F.%T.loc7_6.2 (%T) = value_of_initializer %F.call +// CHECK:STDOUT: %.loc7_43.2: @F.%T.loc7_6.2 (%T) = converted %F.call, %.loc7_43.1 +// CHECK:STDOUT: return %.loc7_43.2 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @G(%p: %C.3) -> %return: %D { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] // CHECK:STDOUT: %p.ref: %C.3 = name_ref p, %p +// CHECK:STDOUT: %.loc10: = specific_function %F.ref, @F(constants.%D) [template = constants.%.6] // CHECK:STDOUT: %.loc9: ref %D = splice_block %return {} -// CHECK:STDOUT: %F.call: init %D = call %F.ref(%p.ref) to %.loc9 +// CHECK:STDOUT: %F.call: init %D = call %.loc10(%p.ref) to %.loc9 // CHECK:STDOUT: return %F.call to %return // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @C(constants.%T) { // CHECK:STDOUT: %T.loc4_9.2 => constants.%T +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @C(@F.%T.loc7_6.2) { @@ -187,6 +204,14 @@ fn G() -> i32 { // CHECK:STDOUT: specific @F(constants.%T) { // CHECK:STDOUT: %T.loc7_6.2 => constants.%T // CHECK:STDOUT: %C.loc7_20.2 => constants.%C.2 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc7_39.2 => constants.%.5 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F(@F.%T.loc7_6.2) { +// CHECK:STDOUT: %T.loc7_6.2 => constants.%T +// CHECK:STDOUT: %C.loc7_20.2 => constants.%C.2 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @C(constants.%D) { @@ -198,6 +223,9 @@ fn G() -> i32 { // CHECK:STDOUT: specific @F(constants.%D) { // CHECK:STDOUT: %T.loc7_6.2 => constants.%D // CHECK:STDOUT: %C.loc7_20.2 => constants.%C.3 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc7_39.2 => constants.%.6 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- interface.carbon @@ -213,10 +241,12 @@ fn G() -> i32 { // CHECK:STDOUT: %C: type = class_type @C [template] // CHECK:STDOUT: %F.type: type = fn_type @F [template] // CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: %.4: type = ptr_type %.2 [template] +// CHECK:STDOUT: %.5: = specific_function %F, @F(%T) [symbolic] // CHECK:STDOUT: %I.3: type = class_type @I, @I(%C) [template] // CHECK:STDOUT: %G.type: type = fn_type @G [template] // CHECK:STDOUT: %G: %G.type = struct_value () [template] -// CHECK:STDOUT: %.4: type = ptr_type %.2 [template] +// CHECK:STDOUT: %.6: = specific_function %F, @F(%C) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -299,20 +329,34 @@ fn G() -> i32 { // CHECK:STDOUT: %T.loc7_6.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc7_6.2 (constants.%T)] // CHECK:STDOUT: %I.loc7_20.2: type = class_type @I, @I(%T.loc7_6.2) [symbolic = %I.loc7_20.2 (constants.%I.2)] // CHECK:STDOUT: -// CHECK:STDOUT: fn[%T.loc7_6.1: type](%p: @F.%I.loc7_20.2 (%I.2)) -> %C; +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc7_39.2: = specific_function constants.%F, @F(%T.loc7_6.2) [symbolic = %.loc7_39.2 (constants.%.5)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%T.loc7_6.1: type](%p: @F.%I.loc7_20.2 (%I.2)) -> %return: %C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] +// CHECK:STDOUT: %p.ref: @F.%I.loc7_20.2 (%I.2) = name_ref p, %p +// CHECK:STDOUT: %.loc7_39.1: = specific_function %F.ref, @F(constants.%T) [symbolic = %.loc7_39.2 (constants.%.5)] +// CHECK:STDOUT: %.loc7_25: ref %C = splice_block %return {} +// CHECK:STDOUT: %F.call: init %C = call %.loc7_39.1(%p.ref) to %.loc7_25 +// CHECK:STDOUT: return %F.call to %return +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @G(%p: %I.3) -> %return: %C { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] // CHECK:STDOUT: %p.ref: %I.3 = name_ref p, %p +// CHECK:STDOUT: %.loc10: = specific_function %F.ref, @F(constants.%C) [template = constants.%.6] // CHECK:STDOUT: %.loc9: ref %C = splice_block %return {} -// CHECK:STDOUT: %F.call: init %C = call %F.ref(%p.ref) to %.loc9 +// CHECK:STDOUT: %F.call: init %C = call %.loc10(%p.ref) to %.loc9 // CHECK:STDOUT: return %F.call to %return // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @I(constants.%T) { // CHECK:STDOUT: %T.loc4_9.2 => constants.%T +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @I(@F.%T.loc7_6.2) { @@ -322,6 +366,14 @@ fn G() -> i32 { // CHECK:STDOUT: specific @F(constants.%T) { // CHECK:STDOUT: %T.loc7_6.2 => constants.%T // CHECK:STDOUT: %I.loc7_20.2 => constants.%I.2 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc7_39.2 => constants.%.5 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F(@F.%T.loc7_6.2) { +// CHECK:STDOUT: %T.loc7_6.2 => constants.%T +// CHECK:STDOUT: %I.loc7_20.2 => constants.%I.2 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @I(constants.%C) { @@ -333,6 +385,9 @@ fn G() -> i32 { // CHECK:STDOUT: specific @F(constants.%C) { // CHECK:STDOUT: %T.loc7_6.2 => constants.%C // CHECK:STDOUT: %I.loc7_20.2 => constants.%I.3 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc7_39.2 => constants.%.6 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- nested.carbon @@ -356,15 +411,18 @@ fn G() -> i32 { // CHECK:STDOUT: %.6: type = tuple_type (%T, %U) [symbolic] // CHECK:STDOUT: %F.type: type = fn_type @F [template] // CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: %.7: type = ptr_type %.6 [symbolic] +// CHECK:STDOUT: %.8: = specific_function %F, @F(%T, %U) [symbolic] // CHECK:STDOUT: %Outer.3: type = class_type @Outer, @Outer(%C) [template] // CHECK:STDOUT: %Inner.type.2: type = generic_class_type @Inner, @Outer(%C) [template] // CHECK:STDOUT: %Inner.3: %Inner.type.2 = struct_value () [template] // CHECK:STDOUT: %Inner.4: type = class_type @Inner, @Inner(%C, %D) [template] -// CHECK:STDOUT: %.7: type = tuple_type (%C, %D) [template] +// CHECK:STDOUT: %.9: type = tuple_type (%C, %D) [template] // CHECK:STDOUT: %G.type: type = fn_type @G [template] // CHECK:STDOUT: %G: %G.type = struct_value () [template] -// CHECK:STDOUT: %.8: type = tuple_type (%.4, %.4) [template] -// CHECK:STDOUT: %.9: type = ptr_type %.8 [template] +// CHECK:STDOUT: %.10: type = tuple_type (%.4, %.4) [template] +// CHECK:STDOUT: %.11: type = ptr_type %.10 [template] +// CHECK:STDOUT: %.12: = specific_function %F, @F(%C, %D) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -437,8 +495,8 @@ fn G() -> i32 { // CHECK:STDOUT: %C.ref.loc15_32: type = name_ref C, file.%C.decl [template = constants.%C] // CHECK:STDOUT: %D.ref.loc15_35: type = name_ref D, file.%D.decl [template = constants.%D] // CHECK:STDOUT: %.loc15_36.1: %.5 = tuple_literal (%C.ref.loc15_32, %D.ref.loc15_35) -// CHECK:STDOUT: %.loc15_36.2: type = converted %.loc15_36.1, constants.%.7 [template = constants.%.7] -// CHECK:STDOUT: %return: ref %.7 = var +// CHECK:STDOUT: %.loc15_36.2: type = converted %.loc15_36.1, constants.%.9 [template = constants.%.9] +// CHECK:STDOUT: %return: ref %.9 = var // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: @@ -500,15 +558,38 @@ fn G() -> i32 { // CHECK:STDOUT: %Inner.loc13_43.2: type = class_type @Inner, @Inner(%T.loc13_6.2, %U.loc13_16.2) [symbolic = %Inner.loc13_43.2 (constants.%Inner.2)] // CHECK:STDOUT: %.loc13_56.3: type = tuple_type (@F.%T.loc13_6.2 (%T), @F.%U.loc13_16.2 (%U)) [symbolic = %.loc13_56.3 (constants.%.6)] // CHECK:STDOUT: -// CHECK:STDOUT: fn[%T.loc13_6.1: type, %U.loc13_16.1: type](%p: @F.%Inner.loc13_43.2 (%Inner.2)) -> @F.%.loc13_56.3 (%.6); +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc13_67.2: = specific_function constants.%F, @F(%T.loc13_6.2, %U.loc13_16.2) [symbolic = %.loc13_67.2 (constants.%.8)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%T.loc13_6.1: type, %U.loc13_16.1: type](%p: @F.%Inner.loc13_43.2 (%Inner.2)) -> %return: @F.%.loc13_56.3 (%.6) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] +// CHECK:STDOUT: %p.ref: @F.%Inner.loc13_43.2 (%Inner.2) = name_ref p, %p +// CHECK:STDOUT: %.loc13_67.1: = specific_function %F.ref, @F(constants.%T, constants.%U) [symbolic = %.loc13_67.2 (constants.%.8)] +// CHECK:STDOUT: %.loc13_68.1: ref @F.%.loc13_56.3 (%.6) = temporary_storage +// CHECK:STDOUT: %F.call: init @F.%.loc13_56.3 (%.6) = call %.loc13_67.1(%p.ref) to %.loc13_68.1 +// CHECK:STDOUT: %.loc13_68.2: ref @F.%.loc13_56.3 (%.6) = temporary %.loc13_68.1, %F.call +// CHECK:STDOUT: %.loc13_68.3: ref @F.%T.loc13_6.2 (%T) = tuple_access %.loc13_68.2, element0 +// CHECK:STDOUT: %.loc13_68.4: @F.%T.loc13_6.2 (%T) = bind_value %.loc13_68.3 +// CHECK:STDOUT: %.loc13_68.5: ref @F.%T.loc13_6.2 (%T) = tuple_access %return, element0 +// CHECK:STDOUT: %.loc13_68.6: init @F.%T.loc13_6.2 (%T) = initialize_from %.loc13_68.4 to %.loc13_68.5 +// CHECK:STDOUT: %.loc13_68.7: ref @F.%U.loc13_16.2 (%U) = tuple_access %.loc13_68.2, element1 +// CHECK:STDOUT: %.loc13_68.8: @F.%U.loc13_16.2 (%U) = bind_value %.loc13_68.7 +// CHECK:STDOUT: %.loc13_68.9: ref @F.%U.loc13_16.2 (%U) = tuple_access %return, element1 +// CHECK:STDOUT: %.loc13_68.10: init @F.%U.loc13_16.2 (%U) = initialize_from %.loc13_68.8 to %.loc13_68.9 +// CHECK:STDOUT: %.loc13_68.11: init @F.%.loc13_56.3 (%.6) = tuple_init (%.loc13_68.6, %.loc13_68.10) to %return +// CHECK:STDOUT: %.loc13_71: init @F.%.loc13_56.3 (%.6) = converted %F.call, %.loc13_68.11 +// CHECK:STDOUT: return %.loc13_71 to %return +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @G(%p: %Inner.4) -> %return: %.7 { +// CHECK:STDOUT: fn @G(%p: %Inner.4) -> %return: %.9 { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] // CHECK:STDOUT: %p.ref: %Inner.4 = name_ref p, %p -// CHECK:STDOUT: %.loc15_28: ref %.7 = splice_block %return {} -// CHECK:STDOUT: %F.call: init %.7 = call %F.ref(%p.ref) to %.loc15_28 +// CHECK:STDOUT: %.loc16: = specific_function %F.ref, @F(constants.%C, constants.%D) [template = constants.%.12] +// CHECK:STDOUT: %.loc15_28: ref %.9 = splice_block %return {} +// CHECK:STDOUT: %F.call: init %.9 = call %.loc16(%p.ref) to %.loc15_28 // CHECK:STDOUT: return %F.call to %return // CHECK:STDOUT: } // CHECK:STDOUT: @@ -522,6 +603,8 @@ fn G() -> i32 { // CHECK:STDOUT: // CHECK:STDOUT: specific @Inner(constants.%T, constants.%U) { // CHECK:STDOUT: %U.loc5_15.2 => constants.%U +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Outer(@Outer.%T.loc4_13.2) { @@ -544,6 +627,19 @@ fn G() -> i32 { // CHECK:STDOUT: %Inner.loc13_37 => constants.%Inner.1 // CHECK:STDOUT: %Inner.loc13_43.2 => constants.%Inner.2 // CHECK:STDOUT: %.loc13_56.3 => constants.%.6 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc13_67.2 => constants.%.8 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F(@F.%T.loc13_6.2, @F.%U.loc13_16.2) { +// CHECK:STDOUT: %T.loc13_6.2 => constants.%T +// CHECK:STDOUT: %U.loc13_16.2 => constants.%U +// CHECK:STDOUT: %Outer.loc13_34.2 => constants.%Outer.2 +// CHECK:STDOUT: %Inner.type => constants.%Inner.type.1 +// CHECK:STDOUT: %Inner.loc13_37 => constants.%Inner.1 +// CHECK:STDOUT: %Inner.loc13_43.2 => constants.%Inner.2 +// CHECK:STDOUT: %.loc13_56.3 => constants.%.6 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Outer(constants.%C) { @@ -567,7 +663,10 @@ fn G() -> i32 { // CHECK:STDOUT: %Inner.type => constants.%Inner.type.2 // CHECK:STDOUT: %Inner.loc13_37 => constants.%Inner.3 // CHECK:STDOUT: %Inner.loc13_43.2 => constants.%Inner.4 -// CHECK:STDOUT: %.loc13_56.3 => constants.%.7 +// CHECK:STDOUT: %.loc13_56.3 => constants.%.9 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc13_67.2 => constants.%.12 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- nontype.carbon @@ -590,6 +689,7 @@ fn G() -> i32 { // CHECK:STDOUT: %.5: i32 = int_literal 0 [template] // CHECK:STDOUT: %WithNontype.3: type = class_type @WithNontype, @WithNontype(%.5) [template] // CHECK:STDOUT: %struct: %WithNontype.3 = struct_value () [template] +// CHECK:STDOUT: %.6: = specific_function %F, @F(%.5) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -690,8 +790,9 @@ fn G() -> i32 { // CHECK:STDOUT: %.loc9_13.3: init %WithNontype.3 = class_init (), %.loc9_13.2 [template = constants.%struct] // CHECK:STDOUT: %.loc9_13.4: ref %WithNontype.3 = temporary %.loc9_13.2, %.loc9_13.3 // CHECK:STDOUT: %.loc9_15.1: ref %WithNontype.3 = converted %.loc9_13.1, %.loc9_13.4 +// CHECK:STDOUT: %.loc9_10: = specific_function %F.ref, @F(constants.%.5) [template = constants.%.6] // CHECK:STDOUT: %.loc9_15.2: %WithNontype.3 = bind_value %.loc9_15.1 -// CHECK:STDOUT: %F.call: init i32 = call %F.ref(%.loc9_15.2) +// CHECK:STDOUT: %F.call: init i32 = call %.loc9_10(%.loc9_15.2) // CHECK:STDOUT: %.loc9_33.1: i32 = value_of_initializer %F.call // CHECK:STDOUT: %.loc9_33.2: i32 = converted %F.call, %.loc9_33.1 // CHECK:STDOUT: return %.loc9_33.2 @@ -721,5 +822,7 @@ fn G() -> i32 { // CHECK:STDOUT: specific @F(constants.%.5) { // CHECK:STDOUT: %N.loc6_6.2 => constants.%.5 // CHECK:STDOUT: %WithNontype.loc6_29.2 => constants.%WithNontype.3 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/deduce/int_float.carbon b/toolchain/check/testdata/deduce/int_float.carbon index 8101eb12adc9..797e14b7efc7 100644 --- a/toolchain/check/testdata/deduce/int_float.carbon +++ b/toolchain/check/testdata/deduce/int_float.carbon @@ -52,6 +52,7 @@ fn G(a: f64) -> i32 { // CHECK:STDOUT: %.4: type = int_type signed, %.3 [template] // CHECK:STDOUT: %G.type: type = fn_type @G [template] // CHECK:STDOUT: %G: %G.type = struct_value () [template] +// CHECK:STDOUT: %.5: = specific_function %F, @F(%.3) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -137,7 +138,8 @@ fn G(a: f64) -> i32 { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] // CHECK:STDOUT: %a.ref: %.4 = name_ref a, %a -// CHECK:STDOUT: %F.call: init i32 = call %F.ref(%a.ref) +// CHECK:STDOUT: %.loc9_10: = specific_function %F.ref, @F(constants.%.3) [template = constants.%.5] +// CHECK:STDOUT: %F.call: init i32 = call %.loc9_10(%a.ref) // CHECK:STDOUT: %.loc9_14.1: i32 = value_of_initializer %F.call // CHECK:STDOUT: %.loc9_14.2: i32 = converted %F.call, %.loc9_14.1 // CHECK:STDOUT: return %.loc9_14.2 @@ -151,6 +153,8 @@ fn G(a: f64) -> i32 { // CHECK:STDOUT: specific @F(constants.%.3) { // CHECK:STDOUT: %N.loc4_6.2 => constants.%.3 // CHECK:STDOUT: %.loc4_26 => constants.%.4 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_todo_float.carbon diff --git a/toolchain/check/testdata/deduce/tuple.carbon b/toolchain/check/testdata/deduce/tuple.carbon index 3edfa1571991..799099c3e40f 100644 --- a/toolchain/check/testdata/deduce/tuple.carbon +++ b/toolchain/check/testdata/deduce/tuple.carbon @@ -15,7 +15,7 @@ library "[[@TEST_NAME]]"; class C {} class D {} -fn F[T:! type, U:! type](pair: (T, U)) -> U; +fn F[T:! type, U:! type](pair: (T, U)) -> U { return F(pair); } fn G(pair: (C, D)) -> D { return F(pair); @@ -66,12 +66,15 @@ fn G(pair: (C, D)) -> D { // CHECK:STDOUT: %F.type: type = fn_type @F [template] // CHECK:STDOUT: %.5: type = tuple_type () [template] // CHECK:STDOUT: %F: %F.type = struct_value () [template] -// CHECK:STDOUT: %.6: type = tuple_type (%C, %D) [template] +// CHECK:STDOUT: %.6: type = ptr_type %.4 [symbolic] +// CHECK:STDOUT: %.7: = specific_function %F, @F(%T, %U) [symbolic] +// CHECK:STDOUT: %.8: type = tuple_type (%C, %D) [template] // CHECK:STDOUT: %G.type: type = fn_type @G [template] // CHECK:STDOUT: %G: %G.type = struct_value () [template] -// CHECK:STDOUT: %.7: type = ptr_type %.1 [template] -// CHECK:STDOUT: %.8: type = tuple_type (%.7, %.7) [template] -// CHECK:STDOUT: %.9: type = ptr_type %.8 [template] +// CHECK:STDOUT: %.9: type = ptr_type %.1 [template] +// CHECK:STDOUT: %.10: type = tuple_type (%.9, %.9) [template] +// CHECK:STDOUT: %.11: type = ptr_type %.10 [template] +// CHECK:STDOUT: %.12: = specific_function %F, @F(%C, %D) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -117,14 +120,14 @@ fn G(pair: (C, D)) -> D { // CHECK:STDOUT: %return: ref @F.%U.loc7_16.2 (%U) = var // CHECK:STDOUT: } // CHECK:STDOUT: %G.decl: %G.type = fn_decl @G [template = constants.%G] { -// CHECK:STDOUT: %pair.patt: %.6 = binding_pattern pair +// CHECK:STDOUT: %pair.patt: %.8 = binding_pattern pair // CHECK:STDOUT: } { // CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [template = constants.%C] // CHECK:STDOUT: %D.ref.loc9_16: type = name_ref D, file.%D.decl [template = constants.%D] // CHECK:STDOUT: %.loc9_17.1: %.3 = tuple_literal (%C.ref, %D.ref.loc9_16) -// CHECK:STDOUT: %.loc9_17.2: type = converted %.loc9_17.1, constants.%.6 [template = constants.%.6] -// CHECK:STDOUT: %pair.param: %.6 = param pair, runtime_param0 -// CHECK:STDOUT: %pair: %.6 = bind_name pair, %pair.param +// CHECK:STDOUT: %.loc9_17.2: type = converted %.loc9_17.1, constants.%.8 [template = constants.%.8] +// CHECK:STDOUT: %pair.param: %.8 = param pair, runtime_param0 +// CHECK:STDOUT: %pair: %.8 = bind_name pair, %pair.param // CHECK:STDOUT: %D.ref.loc9_23: type = name_ref D, file.%D.decl [template = constants.%D] // CHECK:STDOUT: %return: ref %D = var // CHECK:STDOUT: } @@ -149,15 +152,28 @@ fn G(pair: (C, D)) -> D { // CHECK:STDOUT: %U.loc7_16.2: type = bind_symbolic_name U, 1 [symbolic = %U.loc7_16.2 (constants.%U)] // CHECK:STDOUT: %.loc7_37.3: type = tuple_type (@F.%T.loc7_6.2 (%T), @F.%U.loc7_16.2 (%U)) [symbolic = %.loc7_37.3 (constants.%.4)] // CHECK:STDOUT: -// CHECK:STDOUT: fn[%T.loc7_6.1: type, %U.loc7_16.1: type](%pair: @F.%.loc7_37.3 (%.4)) -> @F.%U.loc7_16.2 (%U); +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc7_54.2: = specific_function constants.%F, @F(%T.loc7_6.2, %U.loc7_16.2) [symbolic = %.loc7_54.2 (constants.%.7)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%T.loc7_6.1: type, %U.loc7_16.1: type](%pair: @F.%.loc7_37.3 (%.4)) -> @F.%U.loc7_16.2 (%U) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] +// CHECK:STDOUT: %pair.ref: @F.%.loc7_37.3 (%.4) = name_ref pair, %pair +// CHECK:STDOUT: %.loc7_54.1: = specific_function %F.ref, @F(constants.%T, constants.%U) [symbolic = %.loc7_54.2 (constants.%.7)] +// CHECK:STDOUT: %F.call: init @F.%U.loc7_16.2 (%U) = call %.loc7_54.1(%pair.ref) +// CHECK:STDOUT: %.loc7_61.1: @F.%U.loc7_16.2 (%U) = value_of_initializer %F.call +// CHECK:STDOUT: %.loc7_61.2: @F.%U.loc7_16.2 (%U) = converted %F.call, %.loc7_61.1 +// CHECK:STDOUT: return %.loc7_61.2 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @G(%pair: %.6) -> %return: %D { +// CHECK:STDOUT: fn @G(%pair: %.8) -> %return: %D { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] -// CHECK:STDOUT: %pair.ref: %.6 = name_ref pair, %pair +// CHECK:STDOUT: %pair.ref: %.8 = name_ref pair, %pair +// CHECK:STDOUT: %.loc10: = specific_function %F.ref, @F(constants.%C, constants.%D) [template = constants.%.12] // CHECK:STDOUT: %.loc9_20: ref %D = splice_block %return {} -// CHECK:STDOUT: %F.call: init %D = call %F.ref(%pair.ref) to %.loc9_20 +// CHECK:STDOUT: %F.call: init %D = call %.loc10(%pair.ref) to %.loc9_20 // CHECK:STDOUT: return %F.call to %return // CHECK:STDOUT: } // CHECK:STDOUT: @@ -165,12 +181,24 @@ fn G(pair: (C, D)) -> D { // CHECK:STDOUT: %T.loc7_6.2 => constants.%T // CHECK:STDOUT: %U.loc7_16.2 => constants.%U // CHECK:STDOUT: %.loc7_37.3 => constants.%.4 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc7_54.2 => constants.%.7 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F(@F.%T.loc7_6.2, @F.%U.loc7_16.2) { +// CHECK:STDOUT: %T.loc7_6.2 => constants.%T +// CHECK:STDOUT: %U.loc7_16.2 => constants.%U +// CHECK:STDOUT: %.loc7_37.3 => constants.%.4 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @F(constants.%C, constants.%D) { // CHECK:STDOUT: %T.loc7_6.2 => constants.%C // CHECK:STDOUT: %U.loc7_16.2 => constants.%D -// CHECK:STDOUT: %.loc7_37.3 => constants.%.6 +// CHECK:STDOUT: %.loc7_37.3 => constants.%.8 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc7_54.2 => constants.%.12 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- tuple_value.carbon @@ -201,6 +229,7 @@ fn G(pair: (C, D)) -> D { // CHECK:STDOUT: %HasPair.4: type = class_type @HasPair, @HasPair(%tuple.2) [template] // CHECK:STDOUT: %G.type: type = fn_type @G [template] // CHECK:STDOUT: %G: %G.type = struct_value () [template] +// CHECK:STDOUT: %.10: = specific_function %F, @F(%.8, %.9) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -322,7 +351,8 @@ fn G(pair: (C, D)) -> D { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] // CHECK:STDOUT: %h.ref: %HasPair.4 = name_ref h, %h -// CHECK:STDOUT: %F.call: init i32 = call %F.ref(%h.ref) +// CHECK:STDOUT: %.loc9_10: = specific_function %F.ref, @F(constants.%.8, constants.%.9) [template = constants.%.10] +// CHECK:STDOUT: %F.call: init i32 = call %.loc9_10(%h.ref) // CHECK:STDOUT: %.loc9_14.1: i32 = value_of_initializer %F.call // CHECK:STDOUT: %.loc9_14.2: i32 = converted %F.call, %.loc9_14.1 // CHECK:STDOUT: return %.loc9_14.2 @@ -360,6 +390,8 @@ fn G(pair: (C, D)) -> D { // CHECK:STDOUT: %B.loc6_15.2 => constants.%.9 // CHECK:STDOUT: %tuple.loc6_40.2 => constants.%tuple.2 // CHECK:STDOUT: %HasPair.loc6_34.2 => constants.%HasPair.4 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_inconsistent.carbon diff --git a/toolchain/check/testdata/deduce/type_operator.carbon b/toolchain/check/testdata/deduce/type_operator.carbon index c72f0bdf94c8..99dc595a0a70 100644 --- a/toolchain/check/testdata/deduce/type_operator.carbon +++ b/toolchain/check/testdata/deduce/type_operator.carbon @@ -14,7 +14,7 @@ library "[[@TEST_NAME]]"; class C {} -fn F[T:! type](p: T*) -> T; +fn F[T:! type](p: T*) -> T { return F(p); } fn G(p: C*) -> C { return F(p); @@ -26,7 +26,7 @@ library "[[@TEST_NAME]]"; class C {} -fn F[T:! type](p: const T*) -> T; +fn F[T:! type](p: const T*) -> T { return F(p); } fn G(p: const C*) -> C { return F(p); @@ -38,7 +38,7 @@ library "[[@TEST_NAME]]"; class C {} -fn F[T:! type](p: T*) -> T; +fn F[T:! type](p: T*) -> T { return F(p); } fn G(p: const C*) -> const C { return F(p); @@ -50,15 +50,15 @@ library "[[@TEST_NAME]]"; class C {} -fn F[T:! type](p: const T*) -> T; +fn F[T:! type](p: const T*) -> T { return F(p); } fn G(p: C*) -> const C { // CHECK:STDERR: fail_const_from_nonconst.carbon:[[@LINE+6]]:10: error: cannot deduce value for generic parameter `T` // CHECK:STDERR: return F(p); // CHECK:STDERR: ^~ // CHECK:STDERR: fail_const_from_nonconst.carbon:[[@LINE-6]]:1: note: while deducing parameters of generic declared here - // CHECK:STDERR: fn F[T:! type](p: const T*) -> T; - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fn F[T:! type](p: const T*) -> T { return F(p); } + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ return F(p); } @@ -73,10 +73,12 @@ fn G(p: C*) -> const C { // CHECK:STDOUT: %F.type: type = fn_type @F [template] // CHECK:STDOUT: %.4: type = tuple_type () [template] // CHECK:STDOUT: %F: %F.type = struct_value () [template] -// CHECK:STDOUT: %.5: type = ptr_type %C [template] +// CHECK:STDOUT: %.5: = specific_function %F, @F(%T) [symbolic] +// CHECK:STDOUT: %.6: type = ptr_type %C [template] // CHECK:STDOUT: %G.type: type = fn_type @G [template] // CHECK:STDOUT: %G: %G.type = struct_value () [template] -// CHECK:STDOUT: %.6: type = ptr_type %.1 [template] +// CHECK:STDOUT: %.7: type = ptr_type %.1 [template] +// CHECK:STDOUT: %.8: = specific_function %F, @F(%C) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -115,12 +117,12 @@ fn G(p: C*) -> const C { // CHECK:STDOUT: %return: ref @F.%T.loc6_6.2 (%T) = var // CHECK:STDOUT: } // CHECK:STDOUT: %G.decl: %G.type = fn_decl @G [template = constants.%G] { -// CHECK:STDOUT: %p.patt: %.5 = binding_pattern p +// CHECK:STDOUT: %p.patt: %.6 = binding_pattern p // CHECK:STDOUT: } { // CHECK:STDOUT: %C.ref.loc8_9: type = name_ref C, file.%C.decl [template = constants.%C] -// CHECK:STDOUT: %.loc8_10: type = ptr_type %C [template = constants.%.5] -// CHECK:STDOUT: %p.param: %.5 = param p, runtime_param0 -// CHECK:STDOUT: %p: %.5 = bind_name p, %p.param +// CHECK:STDOUT: %.loc8_10: type = ptr_type %C [template = constants.%.6] +// CHECK:STDOUT: %p.param: %.6 = param p, runtime_param0 +// CHECK:STDOUT: %p: %.6 = bind_name p, %p.param // CHECK:STDOUT: %C.ref.loc8_16: type = name_ref C, file.%C.decl [template = constants.%C] // CHECK:STDOUT: %return: ref %C = var // CHECK:STDOUT: } @@ -137,26 +139,50 @@ fn G(p: C*) -> const C { // CHECK:STDOUT: %T.loc6_6.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc6_6.2 (constants.%T)] // CHECK:STDOUT: %.loc6_20.2: type = ptr_type @F.%T.loc6_6.2 (%T) [symbolic = %.loc6_20.2 (constants.%.3)] // CHECK:STDOUT: -// CHECK:STDOUT: fn[%T.loc6_6.1: type](%p: @F.%.loc6_20.2 (%.3)) -> @F.%T.loc6_6.2 (%T); +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc6_37.2: = specific_function constants.%F, @F(%T.loc6_6.2) [symbolic = %.loc6_37.2 (constants.%.5)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%T.loc6_6.1: type](%p: @F.%.loc6_20.2 (%.3)) -> @F.%T.loc6_6.2 (%T) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] +// CHECK:STDOUT: %p.ref: @F.%.loc6_20.2 (%.3) = name_ref p, %p +// CHECK:STDOUT: %.loc6_37.1: = specific_function %F.ref, @F(constants.%T) [symbolic = %.loc6_37.2 (constants.%.5)] +// CHECK:STDOUT: %F.call: init @F.%T.loc6_6.2 (%T) = call %.loc6_37.1(%p.ref) +// CHECK:STDOUT: %.loc6_41.1: @F.%T.loc6_6.2 (%T) = value_of_initializer %F.call +// CHECK:STDOUT: %.loc6_41.2: @F.%T.loc6_6.2 (%T) = converted %F.call, %.loc6_41.1 +// CHECK:STDOUT: return %.loc6_41.2 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @G(%p: %.5) -> %return: %C { +// CHECK:STDOUT: fn @G(%p: %.6) -> %return: %C { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] -// CHECK:STDOUT: %p.ref: %.5 = name_ref p, %p +// CHECK:STDOUT: %p.ref: %.6 = name_ref p, %p +// CHECK:STDOUT: %.loc9: = specific_function %F.ref, @F(constants.%C) [template = constants.%.8] // CHECK:STDOUT: %.loc8_13: ref %C = splice_block %return {} -// CHECK:STDOUT: %F.call: init %C = call %F.ref(%p.ref) to %.loc8_13 +// CHECK:STDOUT: %F.call: init %C = call %.loc9(%p.ref) to %.loc8_13 // CHECK:STDOUT: return %F.call to %return // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @F(constants.%T) { // CHECK:STDOUT: %T.loc6_6.2 => constants.%T // CHECK:STDOUT: %.loc6_20.2 => constants.%.3 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc6_37.2 => constants.%.5 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F(@F.%T.loc6_6.2) { +// CHECK:STDOUT: %T.loc6_6.2 => constants.%T +// CHECK:STDOUT: %.loc6_20.2 => constants.%.3 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @F(constants.%C) { // CHECK:STDOUT: %T.loc6_6.2 => constants.%C -// CHECK:STDOUT: %.loc6_20.2 => constants.%.5 +// CHECK:STDOUT: %.loc6_20.2 => constants.%.6 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc6_37.2 => constants.%.8 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- const.carbon @@ -171,11 +197,269 @@ fn G(p: C*) -> const C { // CHECK:STDOUT: %F.type: type = fn_type @F [template] // CHECK:STDOUT: %.5: type = tuple_type () [template] // CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: %.6: = specific_function %F, @F(%T) [symbolic] +// CHECK:STDOUT: %.7: type = const_type %C [template] +// CHECK:STDOUT: %.8: type = ptr_type %.7 [template] +// CHECK:STDOUT: %G.type: type = fn_type @G [template] +// CHECK:STDOUT: %G: %G.type = struct_value () [template] +// CHECK:STDOUT: %.9: type = ptr_type %.1 [template] +// CHECK:STDOUT: %.10: = specific_function %F, @F(%C) [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/operators +// CHECK:STDOUT: import Core//prelude/types +// CHECK:STDOUT: import Core//prelude/operators/arithmetic +// CHECK:STDOUT: import Core//prelude/operators/as +// CHECK:STDOUT: import Core//prelude/operators/bitwise +// CHECK:STDOUT: import Core//prelude/operators/comparison +// CHECK:STDOUT: import Core//prelude/types/bool +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: .G = %G.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} {} +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] { +// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 +// CHECK:STDOUT: %p.patt: @F.%.loc6_26.2 (%.4) = binding_pattern p +// CHECK:STDOUT: } { +// CHECK:STDOUT: %T.param: type = param T, runtime_param +// CHECK:STDOUT: %T.loc6_6.1: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc6_6.2 (constants.%T)] +// CHECK:STDOUT: %T.ref.loc6_25: type = name_ref T, %T.loc6_6.1 [symbolic = %T.loc6_6.2 (constants.%T)] +// CHECK:STDOUT: %.loc6_19.1: type = const_type %T [symbolic = %.loc6_19.2 (constants.%.3)] +// CHECK:STDOUT: %.loc6_26.1: type = ptr_type %.3 [symbolic = %.loc6_26.2 (constants.%.4)] +// CHECK:STDOUT: %p.param: @F.%.loc6_26.2 (%.4) = param p, runtime_param0 +// CHECK:STDOUT: %p: @F.%.loc6_26.2 (%.4) = bind_name p, %p.param +// CHECK:STDOUT: %T.ref.loc6_32: type = name_ref T, %T.loc6_6.1 [symbolic = %T.loc6_6.2 (constants.%T)] +// CHECK:STDOUT: %return: ref @F.%T.loc6_6.2 (%T) = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %G.decl: %G.type = fn_decl @G [template = constants.%G] { +// CHECK:STDOUT: %p.patt: %.8 = binding_pattern p +// CHECK:STDOUT: } { +// CHECK:STDOUT: %C.ref.loc8_15: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc8_9: type = const_type %C [template = constants.%.7] +// CHECK:STDOUT: %.loc8_16: type = ptr_type %.7 [template = constants.%.8] +// CHECK:STDOUT: %p.param: %.8 = param p, runtime_param0 +// CHECK:STDOUT: %p: %.8 = bind_name p, %p.param +// CHECK:STDOUT: %C.ref.loc8_22: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %return: ref %C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: %.loc4: = complete_type_witness %.1 [template = constants.%.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @F(%T.loc6_6.1: type) { +// CHECK:STDOUT: %T.loc6_6.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc6_6.2 (constants.%T)] +// CHECK:STDOUT: %.loc6_19.2: type = const_type @F.%T.loc6_6.2 (%T) [symbolic = %.loc6_19.2 (constants.%.3)] +// CHECK:STDOUT: %.loc6_26.2: type = ptr_type @F.%.loc6_19.2 (%.3) [symbolic = %.loc6_26.2 (constants.%.4)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc6_43.2: = specific_function constants.%F, @F(%T.loc6_6.2) [symbolic = %.loc6_43.2 (constants.%.6)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%T.loc6_6.1: type](%p: @F.%.loc6_26.2 (%.4)) -> @F.%T.loc6_6.2 (%T) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] +// CHECK:STDOUT: %p.ref: @F.%.loc6_26.2 (%.4) = name_ref p, %p +// CHECK:STDOUT: %.loc6_43.1: = specific_function %F.ref, @F(constants.%T) [symbolic = %.loc6_43.2 (constants.%.6)] +// CHECK:STDOUT: %F.call: init @F.%T.loc6_6.2 (%T) = call %.loc6_43.1(%p.ref) +// CHECK:STDOUT: %.loc6_47.1: @F.%T.loc6_6.2 (%T) = value_of_initializer %F.call +// CHECK:STDOUT: %.loc6_47.2: @F.%T.loc6_6.2 (%T) = converted %F.call, %.loc6_47.1 +// CHECK:STDOUT: return %.loc6_47.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @G(%p: %.8) -> %return: %C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] +// CHECK:STDOUT: %p.ref: %.8 = name_ref p, %p +// CHECK:STDOUT: %.loc9: = specific_function %F.ref, @F(constants.%C) [template = constants.%.10] +// CHECK:STDOUT: %.loc8_19: ref %C = splice_block %return {} +// CHECK:STDOUT: %F.call: init %C = call %.loc9(%p.ref) to %.loc8_19 +// CHECK:STDOUT: return %F.call to %return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F(constants.%T) { +// CHECK:STDOUT: %T.loc6_6.2 => constants.%T +// CHECK:STDOUT: %.loc6_19.2 => constants.%.3 +// CHECK:STDOUT: %.loc6_26.2 => constants.%.4 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc6_43.2 => constants.%.6 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F(@F.%T.loc6_6.2) { +// CHECK:STDOUT: %T.loc6_6.2 => constants.%T +// CHECK:STDOUT: %.loc6_19.2 => constants.%.3 +// CHECK:STDOUT: %.loc6_26.2 => constants.%.4 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F(constants.%C) { +// CHECK:STDOUT: %T.loc6_6.2 => constants.%C +// CHECK:STDOUT: %.loc6_19.2 => constants.%.7 +// CHECK:STDOUT: %.loc6_26.2 => constants.%.8 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc6_43.2 => constants.%.10 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- nonconst_from_const.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: = complete_type_witness %.1 [template] +// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic] +// CHECK:STDOUT: %.3: type = ptr_type %T [symbolic] +// CHECK:STDOUT: %F.type: type = fn_type @F [template] +// CHECK:STDOUT: %.4: type = tuple_type () [template] +// CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: %.5: = specific_function %F, @F(%T) [symbolic] // CHECK:STDOUT: %.6: type = const_type %C [template] // CHECK:STDOUT: %.7: type = ptr_type %.6 [template] // CHECK:STDOUT: %G.type: type = fn_type @G [template] // CHECK:STDOUT: %G: %G.type = struct_value () [template] // CHECK:STDOUT: %.8: type = ptr_type %.1 [template] +// CHECK:STDOUT: %.9: = specific_function %F, @F(%.6) [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/operators +// CHECK:STDOUT: import Core//prelude/types +// CHECK:STDOUT: import Core//prelude/operators/arithmetic +// CHECK:STDOUT: import Core//prelude/operators/as +// CHECK:STDOUT: import Core//prelude/operators/bitwise +// CHECK:STDOUT: import Core//prelude/operators/comparison +// CHECK:STDOUT: import Core//prelude/types/bool +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: .G = %G.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} {} +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] { +// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 +// CHECK:STDOUT: %p.patt: @F.%.loc6_20.2 (%.3) = binding_pattern p +// CHECK:STDOUT: } { +// CHECK:STDOUT: %T.param: type = param T, runtime_param +// CHECK:STDOUT: %T.loc6_6.1: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc6_6.2 (constants.%T)] +// CHECK:STDOUT: %T.ref.loc6_19: type = name_ref T, %T.loc6_6.1 [symbolic = %T.loc6_6.2 (constants.%T)] +// CHECK:STDOUT: %.loc6_20.1: type = ptr_type %T [symbolic = %.loc6_20.2 (constants.%.3)] +// CHECK:STDOUT: %p.param: @F.%.loc6_20.2 (%.3) = param p, runtime_param0 +// CHECK:STDOUT: %p: @F.%.loc6_20.2 (%.3) = bind_name p, %p.param +// CHECK:STDOUT: %T.ref.loc6_26: type = name_ref T, %T.loc6_6.1 [symbolic = %T.loc6_6.2 (constants.%T)] +// CHECK:STDOUT: %return: ref @F.%T.loc6_6.2 (%T) = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %G.decl: %G.type = fn_decl @G [template = constants.%G] { +// CHECK:STDOUT: %p.patt: %.7 = binding_pattern p +// CHECK:STDOUT: } { +// CHECK:STDOUT: %C.ref.loc8_15: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc8_9: type = const_type %C [template = constants.%.6] +// CHECK:STDOUT: %.loc8_16: type = ptr_type %.6 [template = constants.%.7] +// CHECK:STDOUT: %p.param: %.7 = param p, runtime_param0 +// CHECK:STDOUT: %p: %.7 = bind_name p, %p.param +// CHECK:STDOUT: %C.ref.loc8_28: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc8_22: type = const_type %C [template = constants.%.6] +// CHECK:STDOUT: %return: ref %.6 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: %.loc4: = complete_type_witness %.1 [template = constants.%.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @F(%T.loc6_6.1: type) { +// CHECK:STDOUT: %T.loc6_6.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc6_6.2 (constants.%T)] +// CHECK:STDOUT: %.loc6_20.2: type = ptr_type @F.%T.loc6_6.2 (%T) [symbolic = %.loc6_20.2 (constants.%.3)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc6_37.2: = specific_function constants.%F, @F(%T.loc6_6.2) [symbolic = %.loc6_37.2 (constants.%.5)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%T.loc6_6.1: type](%p: @F.%.loc6_20.2 (%.3)) -> @F.%T.loc6_6.2 (%T) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] +// CHECK:STDOUT: %p.ref: @F.%.loc6_20.2 (%.3) = name_ref p, %p +// CHECK:STDOUT: %.loc6_37.1: = specific_function %F.ref, @F(constants.%T) [symbolic = %.loc6_37.2 (constants.%.5)] +// CHECK:STDOUT: %F.call: init @F.%T.loc6_6.2 (%T) = call %.loc6_37.1(%p.ref) +// CHECK:STDOUT: %.loc6_41.1: @F.%T.loc6_6.2 (%T) = value_of_initializer %F.call +// CHECK:STDOUT: %.loc6_41.2: @F.%T.loc6_6.2 (%T) = converted %F.call, %.loc6_41.1 +// CHECK:STDOUT: return %.loc6_41.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @G(%p: %.7) -> %return: %.6 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] +// CHECK:STDOUT: %p.ref: %.7 = name_ref p, %p +// CHECK:STDOUT: %.loc9: = specific_function %F.ref, @F(constants.%.6) [template = constants.%.9] +// CHECK:STDOUT: %.loc8_19: ref %.6 = splice_block %return {} +// CHECK:STDOUT: %F.call: init %.6 = call %.loc9(%p.ref) to %.loc8_19 +// CHECK:STDOUT: return %F.call to %return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F(constants.%T) { +// CHECK:STDOUT: %T.loc6_6.2 => constants.%T +// CHECK:STDOUT: %.loc6_20.2 => constants.%.3 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc6_37.2 => constants.%.5 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F(@F.%T.loc6_6.2) { +// CHECK:STDOUT: %T.loc6_6.2 => constants.%T +// CHECK:STDOUT: %.loc6_20.2 => constants.%.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F(constants.%.6) { +// CHECK:STDOUT: %T.loc6_6.2 => constants.%.6 +// CHECK:STDOUT: %.loc6_20.2 => constants.%.7 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc6_37.2 => constants.%.9 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_const_from_nonconst.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: = complete_type_witness %.1 [template] +// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic] +// CHECK:STDOUT: %.3: type = const_type %T [symbolic] +// CHECK:STDOUT: %.4: type = ptr_type %.3 [symbolic] +// CHECK:STDOUT: %F.type: type = fn_type @F [template] +// CHECK:STDOUT: %.5: type = tuple_type () [template] +// CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: %.6: = specific_function %F, @F(%T) [symbolic] +// CHECK:STDOUT: %.7: type = ptr_type %C [template] +// CHECK:STDOUT: %.8: type = const_type %C [template] +// CHECK:STDOUT: %G.type: type = fn_type @G [template] +// CHECK:STDOUT: %G: %G.type = struct_value () [template] +// CHECK:STDOUT: %.9: type = ptr_type %.1 [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -217,13 +501,13 @@ fn G(p: C*) -> const C { // CHECK:STDOUT: %G.decl: %G.type = fn_decl @G [template = constants.%G] { // CHECK:STDOUT: %p.patt: %.7 = binding_pattern p // CHECK:STDOUT: } { -// CHECK:STDOUT: %C.ref.loc8_15: type = name_ref C, file.%C.decl [template = constants.%C] -// CHECK:STDOUT: %.loc8_9: type = const_type %C [template = constants.%.6] -// CHECK:STDOUT: %.loc8_16: type = ptr_type %.6 [template = constants.%.7] +// CHECK:STDOUT: %C.ref.loc8_9: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc8_10: type = ptr_type %C [template = constants.%.7] // CHECK:STDOUT: %p.param: %.7 = param p, runtime_param0 // CHECK:STDOUT: %p: %.7 = bind_name p, %p.param // CHECK:STDOUT: %C.ref.loc8_22: type = name_ref C, file.%C.decl [template = constants.%C] -// CHECK:STDOUT: %return: ref %C = var +// CHECK:STDOUT: %.loc8_16: type = const_type %C [template = constants.%.8] +// CHECK:STDOUT: %return: ref %.8 = var // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: @@ -239,217 +523,25 @@ fn G(p: C*) -> const C { // CHECK:STDOUT: %.loc6_19.2: type = const_type @F.%T.loc6_6.2 (%T) [symbolic = %.loc6_19.2 (constants.%.3)] // CHECK:STDOUT: %.loc6_26.2: type = ptr_type @F.%.loc6_19.2 (%.3) [symbolic = %.loc6_26.2 (constants.%.4)] // CHECK:STDOUT: -// CHECK:STDOUT: fn[%T.loc6_6.1: type](%p: @F.%.loc6_26.2 (%.4)) -> @F.%T.loc6_6.2 (%T); +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc6_43.2: = specific_function constants.%F, @F(%T.loc6_6.2) [symbolic = %.loc6_43.2 (constants.%.6)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%T.loc6_6.1: type](%p: @F.%.loc6_26.2 (%.4)) -> @F.%T.loc6_6.2 (%T) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] +// CHECK:STDOUT: %p.ref: @F.%.loc6_26.2 (%.4) = name_ref p, %p +// CHECK:STDOUT: %.loc6_43.1: = specific_function %F.ref, @F(constants.%T) [symbolic = %.loc6_43.2 (constants.%.6)] +// CHECK:STDOUT: %F.call: init @F.%T.loc6_6.2 (%T) = call %.loc6_43.1(%p.ref) +// CHECK:STDOUT: %.loc6_47.1: @F.%T.loc6_6.2 (%T) = value_of_initializer %F.call +// CHECK:STDOUT: %.loc6_47.2: @F.%T.loc6_6.2 (%T) = converted %F.call, %.loc6_47.1 +// CHECK:STDOUT: return %.loc6_47.2 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @G(%p: %.7) -> %return: %C { +// CHECK:STDOUT: fn @G(%p: %.7) -> %return: %.8 { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] // CHECK:STDOUT: %p.ref: %.7 = name_ref p, %p -// CHECK:STDOUT: %.loc8_19: ref %C = splice_block %return {} -// CHECK:STDOUT: %F.call: init %C = call %F.ref(%p.ref) to %.loc8_19 -// CHECK:STDOUT: return %F.call to %return -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: specific @F(constants.%T) { -// CHECK:STDOUT: %T.loc6_6.2 => constants.%T -// CHECK:STDOUT: %.loc6_19.2 => constants.%.3 -// CHECK:STDOUT: %.loc6_26.2 => constants.%.4 -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: specific @F(constants.%C) { -// CHECK:STDOUT: %T.loc6_6.2 => constants.%C -// CHECK:STDOUT: %.loc6_19.2 => constants.%.6 -// CHECK:STDOUT: %.loc6_26.2 => constants.%.7 -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: --- nonconst_from_const.carbon -// CHECK:STDOUT: -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %C: type = class_type @C [template] -// CHECK:STDOUT: %.1: type = struct_type {} [template] -// CHECK:STDOUT: %.2: = complete_type_witness %.1 [template] -// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic] -// CHECK:STDOUT: %.3: type = ptr_type %T [symbolic] -// CHECK:STDOUT: %F.type: type = fn_type @F [template] -// CHECK:STDOUT: %.4: type = tuple_type () [template] -// CHECK:STDOUT: %F: %F.type = struct_value () [template] -// CHECK:STDOUT: %.5: type = const_type %C [template] -// CHECK:STDOUT: %.6: type = ptr_type %.5 [template] -// CHECK:STDOUT: %G.type: type = fn_type @G [template] -// CHECK:STDOUT: %G: %G.type = struct_value () [template] -// CHECK:STDOUT: %.7: type = ptr_type %.1 [template] -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: imports { -// CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { -// CHECK:STDOUT: import Core//prelude -// CHECK:STDOUT: import Core//prelude/operators -// CHECK:STDOUT: import Core//prelude/types -// CHECK:STDOUT: import Core//prelude/operators/arithmetic -// CHECK:STDOUT: import Core//prelude/operators/as -// CHECK:STDOUT: import Core//prelude/operators/bitwise -// CHECK:STDOUT: import Core//prelude/operators/comparison -// CHECK:STDOUT: import Core//prelude/types/bool -// CHECK:STDOUT: } -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace [template] { -// CHECK:STDOUT: .Core = imports.%Core -// CHECK:STDOUT: .C = %C.decl -// CHECK:STDOUT: .F = %F.decl -// CHECK:STDOUT: .G = %G.decl -// CHECK:STDOUT: } -// CHECK:STDOUT: %Core.import = import Core -// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} {} -// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] { -// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 -// CHECK:STDOUT: %p.patt: @F.%.loc6_20.2 (%.3) = binding_pattern p -// CHECK:STDOUT: } { -// CHECK:STDOUT: %T.param: type = param T, runtime_param -// CHECK:STDOUT: %T.loc6_6.1: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc6_6.2 (constants.%T)] -// CHECK:STDOUT: %T.ref.loc6_19: type = name_ref T, %T.loc6_6.1 [symbolic = %T.loc6_6.2 (constants.%T)] -// CHECK:STDOUT: %.loc6_20.1: type = ptr_type %T [symbolic = %.loc6_20.2 (constants.%.3)] -// CHECK:STDOUT: %p.param: @F.%.loc6_20.2 (%.3) = param p, runtime_param0 -// CHECK:STDOUT: %p: @F.%.loc6_20.2 (%.3) = bind_name p, %p.param -// CHECK:STDOUT: %T.ref.loc6_26: type = name_ref T, %T.loc6_6.1 [symbolic = %T.loc6_6.2 (constants.%T)] -// CHECK:STDOUT: %return: ref @F.%T.loc6_6.2 (%T) = var -// CHECK:STDOUT: } -// CHECK:STDOUT: %G.decl: %G.type = fn_decl @G [template = constants.%G] { -// CHECK:STDOUT: %p.patt: %.6 = binding_pattern p -// CHECK:STDOUT: } { -// CHECK:STDOUT: %C.ref.loc8_15: type = name_ref C, file.%C.decl [template = constants.%C] -// CHECK:STDOUT: %.loc8_9: type = const_type %C [template = constants.%.5] -// CHECK:STDOUT: %.loc8_16: type = ptr_type %.5 [template = constants.%.6] -// CHECK:STDOUT: %p.param: %.6 = param p, runtime_param0 -// CHECK:STDOUT: %p: %.6 = bind_name p, %p.param -// CHECK:STDOUT: %C.ref.loc8_28: type = name_ref C, file.%C.decl [template = constants.%C] -// CHECK:STDOUT: %.loc8_22: type = const_type %C [template = constants.%.5] -// CHECK:STDOUT: %return: ref %.5 = var -// CHECK:STDOUT: } -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: class @C { -// CHECK:STDOUT: %.loc4: = complete_type_witness %.1 [template = constants.%.2] -// CHECK:STDOUT: -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = constants.%C -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: generic fn @F(%T.loc6_6.1: type) { -// CHECK:STDOUT: %T.loc6_6.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc6_6.2 (constants.%T)] -// CHECK:STDOUT: %.loc6_20.2: type = ptr_type @F.%T.loc6_6.2 (%T) [symbolic = %.loc6_20.2 (constants.%.3)] -// CHECK:STDOUT: -// CHECK:STDOUT: fn[%T.loc6_6.1: type](%p: @F.%.loc6_20.2 (%.3)) -> @F.%T.loc6_6.2 (%T); -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: fn @G(%p: %.6) -> %return: %.5 { -// CHECK:STDOUT: !entry: -// CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] -// CHECK:STDOUT: %p.ref: %.6 = name_ref p, %p -// CHECK:STDOUT: %.loc8_19: ref %.5 = splice_block %return {} -// CHECK:STDOUT: %F.call: init %.5 = call %F.ref(%p.ref) to %.loc8_19 -// CHECK:STDOUT: return %F.call to %return -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: specific @F(constants.%T) { -// CHECK:STDOUT: %T.loc6_6.2 => constants.%T -// CHECK:STDOUT: %.loc6_20.2 => constants.%.3 -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: specific @F(constants.%.5) { -// CHECK:STDOUT: %T.loc6_6.2 => constants.%.5 -// CHECK:STDOUT: %.loc6_20.2 => constants.%.6 -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: --- fail_const_from_nonconst.carbon -// CHECK:STDOUT: -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %C: type = class_type @C [template] -// CHECK:STDOUT: %.1: type = struct_type {} [template] -// CHECK:STDOUT: %.2: = complete_type_witness %.1 [template] -// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic] -// CHECK:STDOUT: %.3: type = const_type %T [symbolic] -// CHECK:STDOUT: %.4: type = ptr_type %.3 [symbolic] -// CHECK:STDOUT: %F.type: type = fn_type @F [template] -// CHECK:STDOUT: %.5: type = tuple_type () [template] -// CHECK:STDOUT: %F: %F.type = struct_value () [template] -// CHECK:STDOUT: %.6: type = ptr_type %C [template] -// CHECK:STDOUT: %.7: type = const_type %C [template] -// CHECK:STDOUT: %G.type: type = fn_type @G [template] -// CHECK:STDOUT: %G: %G.type = struct_value () [template] -// CHECK:STDOUT: %.8: type = ptr_type %.1 [template] -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: imports { -// CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { -// CHECK:STDOUT: import Core//prelude -// CHECK:STDOUT: import Core//prelude/operators -// CHECK:STDOUT: import Core//prelude/types -// CHECK:STDOUT: import Core//prelude/operators/arithmetic -// CHECK:STDOUT: import Core//prelude/operators/as -// CHECK:STDOUT: import Core//prelude/operators/bitwise -// CHECK:STDOUT: import Core//prelude/operators/comparison -// CHECK:STDOUT: import Core//prelude/types/bool -// CHECK:STDOUT: } -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace [template] { -// CHECK:STDOUT: .Core = imports.%Core -// CHECK:STDOUT: .C = %C.decl -// CHECK:STDOUT: .F = %F.decl -// CHECK:STDOUT: .G = %G.decl -// CHECK:STDOUT: } -// CHECK:STDOUT: %Core.import = import Core -// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} {} -// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] { -// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 -// CHECK:STDOUT: %p.patt: @F.%.loc6_26.2 (%.4) = binding_pattern p -// CHECK:STDOUT: } { -// CHECK:STDOUT: %T.param: type = param T, runtime_param -// CHECK:STDOUT: %T.loc6_6.1: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc6_6.2 (constants.%T)] -// CHECK:STDOUT: %T.ref.loc6_25: type = name_ref T, %T.loc6_6.1 [symbolic = %T.loc6_6.2 (constants.%T)] -// CHECK:STDOUT: %.loc6_19.1: type = const_type %T [symbolic = %.loc6_19.2 (constants.%.3)] -// CHECK:STDOUT: %.loc6_26.1: type = ptr_type %.3 [symbolic = %.loc6_26.2 (constants.%.4)] -// CHECK:STDOUT: %p.param: @F.%.loc6_26.2 (%.4) = param p, runtime_param0 -// CHECK:STDOUT: %p: @F.%.loc6_26.2 (%.4) = bind_name p, %p.param -// CHECK:STDOUT: %T.ref.loc6_32: type = name_ref T, %T.loc6_6.1 [symbolic = %T.loc6_6.2 (constants.%T)] -// CHECK:STDOUT: %return: ref @F.%T.loc6_6.2 (%T) = var -// CHECK:STDOUT: } -// CHECK:STDOUT: %G.decl: %G.type = fn_decl @G [template = constants.%G] { -// CHECK:STDOUT: %p.patt: %.6 = binding_pattern p -// CHECK:STDOUT: } { -// CHECK:STDOUT: %C.ref.loc8_9: type = name_ref C, file.%C.decl [template = constants.%C] -// CHECK:STDOUT: %.loc8_10: type = ptr_type %C [template = constants.%.6] -// CHECK:STDOUT: %p.param: %.6 = param p, runtime_param0 -// CHECK:STDOUT: %p: %.6 = bind_name p, %p.param -// CHECK:STDOUT: %C.ref.loc8_22: type = name_ref C, file.%C.decl [template = constants.%C] -// CHECK:STDOUT: %.loc8_16: type = const_type %C [template = constants.%.7] -// CHECK:STDOUT: %return: ref %.7 = var -// CHECK:STDOUT: } -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: class @C { -// CHECK:STDOUT: %.loc4: = complete_type_witness %.1 [template = constants.%.2] -// CHECK:STDOUT: -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = constants.%C -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: generic fn @F(%T.loc6_6.1: type) { -// CHECK:STDOUT: %T.loc6_6.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc6_6.2 (constants.%T)] -// CHECK:STDOUT: %.loc6_19.2: type = const_type @F.%T.loc6_6.2 (%T) [symbolic = %.loc6_19.2 (constants.%.3)] -// CHECK:STDOUT: %.loc6_26.2: type = ptr_type @F.%.loc6_19.2 (%.3) [symbolic = %.loc6_26.2 (constants.%.4)] -// CHECK:STDOUT: -// CHECK:STDOUT: fn[%T.loc6_6.1: type](%p: @F.%.loc6_26.2 (%.4)) -> @F.%T.loc6_6.2 (%T); -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: fn @G(%p: %.6) -> %return: %.7 { -// CHECK:STDOUT: !entry: -// CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] -// CHECK:STDOUT: %p.ref: %.6 = name_ref p, %p // CHECK:STDOUT: return to %return // CHECK:STDOUT: } // CHECK:STDOUT: @@ -457,5 +549,14 @@ fn G(p: C*) -> const C { // CHECK:STDOUT: %T.loc6_6.2 => constants.%T // CHECK:STDOUT: %.loc6_19.2 => constants.%.3 // CHECK:STDOUT: %.loc6_26.2 => constants.%.4 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc6_43.2 => constants.%.6 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F(@F.%T.loc6_6.2) { +// CHECK:STDOUT: %T.loc6_6.2 => constants.%T +// CHECK:STDOUT: %.loc6_19.2 => constants.%.3 +// CHECK:STDOUT: %.loc6_26.2 => constants.%.4 // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/generic/deduce.carbon b/toolchain/check/testdata/function/generic/deduce.carbon index e469895b5f89..be0ae533cdeb 100644 --- a/toolchain/check/testdata/function/generic/deduce.carbon +++ b/toolchain/check/testdata/function/generic/deduce.carbon @@ -12,7 +12,7 @@ library "[[@TEST_NAME]]"; -fn ExplicitGenericParam(T:! type) -> T*; +fn ExplicitGenericParam(T:! type) -> T* { return ExplicitGenericParam(T); } fn CallExplicitGenericParam() -> i32* { return ExplicitGenericParam(i32); @@ -46,7 +46,7 @@ fn CallExplicitAndAlsoDeduced(n: i32) -> i32* { library "[[@TEST_NAME]]"; -fn ImplicitGenericParam[T:! type](x: T) -> T*; +fn ImplicitGenericParam[T:! type](x: T) -> T* { return ImplicitGenericParam(x); } fn CallImplicitGenericParam(n: i32) -> i32* { return ImplicitGenericParam(n); @@ -56,7 +56,7 @@ fn CallImplicitGenericParam(n: i32) -> i32* { library "[[@TEST_NAME]]"; -fn TupleParam[T:! type](x: (T, i32)); +fn TupleParam[T:! type](x: (T, i32)) {} fn CallTupleParam() { TupleParam((1, 2)); @@ -66,15 +66,15 @@ fn CallTupleParam() { library "[[@TEST_NAME]]"; -fn StructParam[T:! type](x: {.a: T, .b: i32}); +fn StructParam[T:! type](x: {.a: T, .b: i32}) {} fn CallStructParam() { // CHECK:STDERR: fail_todo_deduce_nested_struct.carbon:[[@LINE+7]]:3: error: cannot deduce value for generic parameter `T` // CHECK:STDERR: StructParam({.a = 1, .b = 2}); // CHECK:STDERR: ^~~~~~~~~~~~ // CHECK:STDERR: fail_todo_deduce_nested_struct.carbon:[[@LINE-6]]:1: note: while deducing parameters of generic declared here - // CHECK:STDERR: fn StructParam[T:! type](x: {.a: T, .b: i32}); - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fn StructParam[T:! type](x: {.a: T, .b: i32}) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: StructParam({.a = 1, .b = 2}); } @@ -122,15 +122,18 @@ fn CallImplicitNotDeducible() { // CHECK:STDOUT: %ExplicitGenericParam.type: type = fn_type @ExplicitGenericParam [template] // CHECK:STDOUT: %.2: type = tuple_type () [template] // CHECK:STDOUT: %ExplicitGenericParam: %ExplicitGenericParam.type = struct_value () [template] +// CHECK:STDOUT: %.3: = specific_function %ExplicitGenericParam, @ExplicitGenericParam(%T) [symbolic] // CHECK:STDOUT: %Int32.type: type = fn_type @Int32 [template] // CHECK:STDOUT: %Int32: %Int32.type = struct_value () [template] -// CHECK:STDOUT: %.3: type = ptr_type i32 [template] +// CHECK:STDOUT: %.4: type = ptr_type i32 [template] // CHECK:STDOUT: %CallExplicitGenericParam.type: type = fn_type @CallExplicitGenericParam [template] // CHECK:STDOUT: %CallExplicitGenericParam: %CallExplicitGenericParam.type = struct_value () [template] -// CHECK:STDOUT: %.4: type = struct_type {.a: %T} [symbolic] -// CHECK:STDOUT: %.5: type = ptr_type %.4 [symbolic] +// CHECK:STDOUT: %.5: = specific_function %ExplicitGenericParam, @ExplicitGenericParam(i32) [template] +// CHECK:STDOUT: %.6: type = struct_type {.a: %T} [symbolic] +// CHECK:STDOUT: %.7: type = ptr_type %.6 [symbolic] // CHECK:STDOUT: %CallExplicitGenericParamWithGenericArg.type: type = fn_type @CallExplicitGenericParamWithGenericArg [template] // CHECK:STDOUT: %CallExplicitGenericParamWithGenericArg: %CallExplicitGenericParamWithGenericArg.type = struct_value () [template] +// CHECK:STDOUT: %.8: = specific_function %ExplicitGenericParam, @ExplicitGenericParam(%.6) [symbolic] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -161,7 +164,7 @@ fn CallImplicitNotDeducible() { // CHECK:STDOUT: } { // CHECK:STDOUT: %T.param: type = param T, runtime_param // CHECK:STDOUT: %T.loc4_25.1: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc4_25.2 (constants.%T)] -// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc4_25.1 [symbolic = %T.loc4_25.2 (constants.%T)] +// CHECK:STDOUT: %T.ref.loc4_38: type = name_ref T, %T.loc4_25.1 [symbolic = %T.loc4_25.2 (constants.%T)] // CHECK:STDOUT: %.loc4_39.1: type = ptr_type %T [symbolic = %.loc4_39.2 (constants.%.1)] // CHECK:STDOUT: %return: ref @ExplicitGenericParam.%.loc4_39.2 (%.1) = var // CHECK:STDOUT: } @@ -169,8 +172,8 @@ fn CallImplicitNotDeducible() { // CHECK:STDOUT: %int.make_type_32.loc6: init type = call constants.%Int32() [template = i32] // CHECK:STDOUT: %.loc6_37.1: type = value_of_initializer %int.make_type_32.loc6 [template = i32] // CHECK:STDOUT: %.loc6_37.2: type = converted %int.make_type_32.loc6, %.loc6_37.1 [template = i32] -// CHECK:STDOUT: %.loc6_37.3: type = ptr_type i32 [template = constants.%.3] -// CHECK:STDOUT: %return: ref %.3 = var +// CHECK:STDOUT: %.loc6_37.3: type = ptr_type i32 [template = constants.%.4] +// CHECK:STDOUT: %return: ref %.4 = var // CHECK:STDOUT: } // CHECK:STDOUT: %CallExplicitGenericParamWithGenericArg.decl: %CallExplicitGenericParamWithGenericArg.type = fn_decl @CallExplicitGenericParamWithGenericArg [template = constants.%CallExplicitGenericParamWithGenericArg] { // CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 @@ -178,9 +181,9 @@ fn CallImplicitNotDeducible() { // CHECK:STDOUT: %T.param: type = param T, runtime_param // CHECK:STDOUT: %T.loc10_43.1: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc10_43.2 (constants.%T)] // CHECK:STDOUT: %T.ref.loc10: type = name_ref T, %T.loc10_43.1 [symbolic = %T.loc10_43.2 (constants.%T)] -// CHECK:STDOUT: %.loc10_62.1: type = struct_type {.a: %T} [symbolic = %.loc10_62.2 (constants.%.4)] -// CHECK:STDOUT: %.loc10_63.1: type = ptr_type %.4 [symbolic = %.loc10_63.2 (constants.%.5)] -// CHECK:STDOUT: %return: ref @CallExplicitGenericParamWithGenericArg.%.loc10_63.2 (%.5) = var +// CHECK:STDOUT: %.loc10_62.1: type = struct_type {.a: %T} [symbolic = %.loc10_62.2 (constants.%.6)] +// CHECK:STDOUT: %.loc10_63.1: type = ptr_type %.6 [symbolic = %.loc10_63.2 (constants.%.7)] +// CHECK:STDOUT: %return: ref @CallExplicitGenericParamWithGenericArg.%.loc10_63.2 (%.7) = var // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: @@ -188,38 +191,53 @@ fn CallImplicitNotDeducible() { // CHECK:STDOUT: %T.loc4_25.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc4_25.2 (constants.%T)] // CHECK:STDOUT: %.loc4_39.2: type = ptr_type @ExplicitGenericParam.%T.loc4_25.2 (%T) [symbolic = %.loc4_39.2 (constants.%.1)] // CHECK:STDOUT: -// CHECK:STDOUT: fn(%T.loc4_25.1: type) -> @ExplicitGenericParam.%.loc4_39.2 (%.1); +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc4_50.2: = specific_function constants.%ExplicitGenericParam, @ExplicitGenericParam(%T.loc4_25.2) [symbolic = %.loc4_50.2 (constants.%.3)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn(%T.loc4_25.1: type) -> @ExplicitGenericParam.%.loc4_39.2 (%.1) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %ExplicitGenericParam.ref: %ExplicitGenericParam.type = name_ref ExplicitGenericParam, file.%ExplicitGenericParam.decl [template = constants.%ExplicitGenericParam] +// CHECK:STDOUT: %T.ref.loc4_71: type = name_ref T, %T.loc4_25.1 [symbolic = %T.loc4_25.2 (constants.%T)] +// CHECK:STDOUT: %.loc4_50.1: = specific_function %ExplicitGenericParam.ref, @ExplicitGenericParam(constants.%T) [symbolic = %.loc4_50.2 (constants.%.3)] +// CHECK:STDOUT: %ExplicitGenericParam.call: init @ExplicitGenericParam.%.loc4_39.2 (%.1) = call %.loc4_50.1() +// CHECK:STDOUT: %.loc4_73.1: @ExplicitGenericParam.%.loc4_39.2 (%.1) = value_of_initializer %ExplicitGenericParam.call +// CHECK:STDOUT: %.loc4_73.2: @ExplicitGenericParam.%.loc4_39.2 (%.1) = converted %ExplicitGenericParam.call, %.loc4_73.1 +// CHECK:STDOUT: return %.loc4_73.2 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @CallExplicitGenericParam() -> %.3 { +// CHECK:STDOUT: fn @CallExplicitGenericParam() -> %.4 { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %ExplicitGenericParam.ref: %ExplicitGenericParam.type = name_ref ExplicitGenericParam, file.%ExplicitGenericParam.decl [template = constants.%ExplicitGenericParam] // CHECK:STDOUT: %int.make_type_32.loc7: init type = call constants.%Int32() [template = i32] // CHECK:STDOUT: %.loc7_30.1: type = value_of_initializer %int.make_type_32.loc7 [template = i32] // CHECK:STDOUT: %.loc7_30.2: type = converted %int.make_type_32.loc7, %.loc7_30.1 [template = i32] -// CHECK:STDOUT: %ExplicitGenericParam.call: init %.3 = call %ExplicitGenericParam.ref() -// CHECK:STDOUT: %.loc7_35.1: %.3 = value_of_initializer %ExplicitGenericParam.call -// CHECK:STDOUT: %.loc7_35.2: %.3 = converted %ExplicitGenericParam.call, %.loc7_35.1 +// CHECK:STDOUT: %.loc7_10: = specific_function %ExplicitGenericParam.ref, @ExplicitGenericParam(i32) [template = constants.%.5] +// CHECK:STDOUT: %ExplicitGenericParam.call: init %.4 = call %.loc7_10() +// CHECK:STDOUT: %.loc7_35.1: %.4 = value_of_initializer %ExplicitGenericParam.call +// CHECK:STDOUT: %.loc7_35.2: %.4 = converted %ExplicitGenericParam.call, %.loc7_35.1 // CHECK:STDOUT: return %.loc7_35.2 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic fn @CallExplicitGenericParamWithGenericArg(%T.loc10_43.1: type) { // CHECK:STDOUT: %T.loc10_43.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc10_43.2 (constants.%T)] -// CHECK:STDOUT: %.loc10_62.2: type = struct_type {.a: @CallExplicitGenericParamWithGenericArg.%T.loc10_43.2 (%T)} [symbolic = %.loc10_62.2 (constants.%.4)] -// CHECK:STDOUT: %.loc10_63.2: type = ptr_type @CallExplicitGenericParamWithGenericArg.%.loc10_62.2 (%.4) [symbolic = %.loc10_63.2 (constants.%.5)] +// CHECK:STDOUT: %.loc10_62.2: type = struct_type {.a: @CallExplicitGenericParamWithGenericArg.%T.loc10_43.2 (%T)} [symbolic = %.loc10_62.2 (constants.%.6)] +// CHECK:STDOUT: %.loc10_63.2: type = ptr_type @CallExplicitGenericParamWithGenericArg.%.loc10_62.2 (%.6) [symbolic = %.loc10_63.2 (constants.%.7)] // CHECK:STDOUT: // CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc11_10.2: = specific_function constants.%ExplicitGenericParam, @ExplicitGenericParam(%.loc10_62.2) [symbolic = %.loc11_10.2 (constants.%.8)] // CHECK:STDOUT: -// CHECK:STDOUT: fn(%T.loc10_43.1: type) -> @CallExplicitGenericParamWithGenericArg.%.loc10_63.2 (%.5) { +// CHECK:STDOUT: fn(%T.loc10_43.1: type) -> @CallExplicitGenericParamWithGenericArg.%.loc10_63.2 (%.7) { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %ExplicitGenericParam.ref: %ExplicitGenericParam.type = name_ref ExplicitGenericParam, file.%ExplicitGenericParam.decl [template = constants.%ExplicitGenericParam] // CHECK:STDOUT: %T.ref.loc11: type = name_ref T, %T.loc10_43.1 [symbolic = %T.loc10_43.2 (constants.%T)] -// CHECK:STDOUT: %.loc11_37: type = struct_type {.a: %T} [symbolic = %.loc10_62.2 (constants.%.4)] -// CHECK:STDOUT: %ExplicitGenericParam.call: init @CallExplicitGenericParamWithGenericArg.%.loc10_63.2 (%.5) = call %ExplicitGenericParam.ref() -// CHECK:STDOUT: %.loc11_39.1: @CallExplicitGenericParamWithGenericArg.%.loc10_63.2 (%.5) = value_of_initializer %ExplicitGenericParam.call -// CHECK:STDOUT: %.loc11_39.2: @CallExplicitGenericParamWithGenericArg.%.loc10_63.2 (%.5) = converted %ExplicitGenericParam.call, %.loc11_39.1 +// CHECK:STDOUT: %.loc11_37: type = struct_type {.a: %T} [symbolic = %.loc10_62.2 (constants.%.6)] +// CHECK:STDOUT: %.loc11_10.1: = specific_function %ExplicitGenericParam.ref, @ExplicitGenericParam(constants.%.6) [symbolic = %.loc11_10.2 (constants.%.8)] +// CHECK:STDOUT: %ExplicitGenericParam.call: init @CallExplicitGenericParamWithGenericArg.%.loc10_63.2 (%.7) = call %.loc11_10.1() +// CHECK:STDOUT: %.loc11_39.1: @CallExplicitGenericParamWithGenericArg.%.loc10_63.2 (%.7) = value_of_initializer %ExplicitGenericParam.call +// CHECK:STDOUT: %.loc11_39.2: @CallExplicitGenericParamWithGenericArg.%.loc10_63.2 (%.7) = converted %ExplicitGenericParam.call, %.loc11_39.1 // CHECK:STDOUT: return %.loc11_39.2 // CHECK:STDOUT: } // CHECK:STDOUT: } @@ -227,22 +245,41 @@ fn CallImplicitNotDeducible() { // CHECK:STDOUT: specific @ExplicitGenericParam(constants.%T) { // CHECK:STDOUT: %T.loc4_25.2 => constants.%T // CHECK:STDOUT: %.loc4_39.2 => constants.%.1 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc4_50.2 => constants.%.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @ExplicitGenericParam(@ExplicitGenericParam.%T.loc4_25.2) { +// CHECK:STDOUT: %T.loc4_25.2 => constants.%T +// CHECK:STDOUT: %.loc4_39.2 => constants.%.1 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @ExplicitGenericParam(i32) { // CHECK:STDOUT: %T.loc4_25.2 => i32 -// CHECK:STDOUT: %.loc4_39.2 => constants.%.3 +// CHECK:STDOUT: %.loc4_39.2 => constants.%.4 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc4_50.2 => constants.%.5 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @CallExplicitGenericParamWithGenericArg(constants.%T) { // CHECK:STDOUT: %T.loc10_43.2 => constants.%T -// CHECK:STDOUT: %.loc10_62.2 => constants.%.4 -// CHECK:STDOUT: %.loc10_63.2 => constants.%.5 +// CHECK:STDOUT: %.loc10_62.2 => constants.%.6 +// CHECK:STDOUT: %.loc10_63.2 => constants.%.7 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @ExplicitGenericParam(constants.%.4) { -// CHECK:STDOUT: %T.loc4_25.2 => constants.%.4 -// CHECK:STDOUT: %.loc4_39.2 => constants.%.5 +// CHECK:STDOUT: specific @ExplicitGenericParam(constants.%.6) { +// CHECK:STDOUT: %T.loc4_25.2 => constants.%.6 +// CHECK:STDOUT: %.loc4_39.2 => constants.%.7 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc4_50.2 => constants.%.8 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @ExplicitGenericParam(@CallExplicitGenericParamWithGenericArg.%.loc10_62.2) { +// CHECK:STDOUT: %T.loc4_25.2 => constants.%.6 +// CHECK:STDOUT: %.loc4_39.2 => constants.%.7 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_todo_explicit_vs_deduced.carbon @@ -353,11 +390,13 @@ fn CallImplicitNotDeducible() { // CHECK:STDOUT: %ImplicitGenericParam.type: type = fn_type @ImplicitGenericParam [template] // CHECK:STDOUT: %.2: type = tuple_type () [template] // CHECK:STDOUT: %ImplicitGenericParam: %ImplicitGenericParam.type = struct_value () [template] +// CHECK:STDOUT: %.3: = specific_function %ImplicitGenericParam, @ImplicitGenericParam(%T) [symbolic] // CHECK:STDOUT: %Int32.type: type = fn_type @Int32 [template] // CHECK:STDOUT: %Int32: %Int32.type = struct_value () [template] -// CHECK:STDOUT: %.3: type = ptr_type i32 [template] +// CHECK:STDOUT: %.4: type = ptr_type i32 [template] // CHECK:STDOUT: %CallImplicitGenericParam.type: type = fn_type @CallImplicitGenericParam [template] // CHECK:STDOUT: %CallImplicitGenericParam: %CallImplicitGenericParam.type = struct_value () [template] +// CHECK:STDOUT: %.5: = specific_function %ImplicitGenericParam, @ImplicitGenericParam(i32) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -406,8 +445,8 @@ fn CallImplicitNotDeducible() { // CHECK:STDOUT: %int.make_type_32.loc6_40: init type = call constants.%Int32() [template = i32] // CHECK:STDOUT: %.loc6_43.1: type = value_of_initializer %int.make_type_32.loc6_40 [template = i32] // CHECK:STDOUT: %.loc6_43.2: type = converted %int.make_type_32.loc6_40, %.loc6_43.1 [template = i32] -// CHECK:STDOUT: %.loc6_43.3: type = ptr_type i32 [template = constants.%.3] -// CHECK:STDOUT: %return: ref %.3 = var +// CHECK:STDOUT: %.loc6_43.3: type = ptr_type i32 [template = constants.%.4] +// CHECK:STDOUT: %return: ref %.4 = var // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: @@ -415,29 +454,53 @@ fn CallImplicitNotDeducible() { // CHECK:STDOUT: %T.loc4_25.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc4_25.2 (constants.%T)] // CHECK:STDOUT: %.loc4_45.2: type = ptr_type @ImplicitGenericParam.%T.loc4_25.2 (%T) [symbolic = %.loc4_45.2 (constants.%.1)] // CHECK:STDOUT: -// CHECK:STDOUT: fn[%T.loc4_25.1: type](%x: @ImplicitGenericParam.%T.loc4_25.2 (%T)) -> @ImplicitGenericParam.%.loc4_45.2 (%.1); +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc4_56.2: = specific_function constants.%ImplicitGenericParam, @ImplicitGenericParam(%T.loc4_25.2) [symbolic = %.loc4_56.2 (constants.%.3)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%T.loc4_25.1: type](%x: @ImplicitGenericParam.%T.loc4_25.2 (%T)) -> @ImplicitGenericParam.%.loc4_45.2 (%.1) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %ImplicitGenericParam.ref: %ImplicitGenericParam.type = name_ref ImplicitGenericParam, file.%ImplicitGenericParam.decl [template = constants.%ImplicitGenericParam] +// CHECK:STDOUT: %x.ref: @ImplicitGenericParam.%T.loc4_25.2 (%T) = name_ref x, %x +// CHECK:STDOUT: %.loc4_56.1: = specific_function %ImplicitGenericParam.ref, @ImplicitGenericParam(constants.%T) [symbolic = %.loc4_56.2 (constants.%.3)] +// CHECK:STDOUT: %ImplicitGenericParam.call: init @ImplicitGenericParam.%.loc4_45.2 (%.1) = call %.loc4_56.1(%x.ref) +// CHECK:STDOUT: %.loc4_79.1: @ImplicitGenericParam.%.loc4_45.2 (%.1) = value_of_initializer %ImplicitGenericParam.call +// CHECK:STDOUT: %.loc4_79.2: @ImplicitGenericParam.%.loc4_45.2 (%.1) = converted %ImplicitGenericParam.call, %.loc4_79.1 +// CHECK:STDOUT: return %.loc4_79.2 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @CallImplicitGenericParam(%n: i32) -> %.3 { +// CHECK:STDOUT: fn @CallImplicitGenericParam(%n: i32) -> %.4 { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %ImplicitGenericParam.ref: %ImplicitGenericParam.type = name_ref ImplicitGenericParam, file.%ImplicitGenericParam.decl [template = constants.%ImplicitGenericParam] // CHECK:STDOUT: %n.ref: i32 = name_ref n, %n -// CHECK:STDOUT: %ImplicitGenericParam.call: init %.3 = call %ImplicitGenericParam.ref(%n.ref) -// CHECK:STDOUT: %.loc7_33.1: %.3 = value_of_initializer %ImplicitGenericParam.call -// CHECK:STDOUT: %.loc7_33.2: %.3 = converted %ImplicitGenericParam.call, %.loc7_33.1 +// CHECK:STDOUT: %.loc7_10: = specific_function %ImplicitGenericParam.ref, @ImplicitGenericParam(i32) [template = constants.%.5] +// CHECK:STDOUT: %ImplicitGenericParam.call: init %.4 = call %.loc7_10(%n.ref) +// CHECK:STDOUT: %.loc7_33.1: %.4 = value_of_initializer %ImplicitGenericParam.call +// CHECK:STDOUT: %.loc7_33.2: %.4 = converted %ImplicitGenericParam.call, %.loc7_33.1 // CHECK:STDOUT: return %.loc7_33.2 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @ImplicitGenericParam(constants.%T) { // CHECK:STDOUT: %T.loc4_25.2 => constants.%T // CHECK:STDOUT: %.loc4_45.2 => constants.%.1 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc4_56.2 => constants.%.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @ImplicitGenericParam(@ImplicitGenericParam.%T.loc4_25.2) { +// CHECK:STDOUT: %T.loc4_25.2 => constants.%T +// CHECK:STDOUT: %.loc4_45.2 => constants.%.1 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @ImplicitGenericParam(i32) { // CHECK:STDOUT: %T.loc4_25.2 => i32 -// CHECK:STDOUT: %.loc4_45.2 => constants.%.3 +// CHECK:STDOUT: %.loc4_45.2 => constants.%.4 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc4_56.2 => constants.%.5 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- deduce_nested_tuple.carbon @@ -451,13 +514,15 @@ fn CallImplicitNotDeducible() { // CHECK:STDOUT: %.3: type = tuple_type (%T, i32) [symbolic] // CHECK:STDOUT: %TupleParam.type: type = fn_type @TupleParam [template] // CHECK:STDOUT: %TupleParam: %TupleParam.type = struct_value () [template] +// CHECK:STDOUT: %.4: type = ptr_type %.3 [symbolic] // CHECK:STDOUT: %CallTupleParam.type: type = fn_type @CallTupleParam [template] // CHECK:STDOUT: %CallTupleParam: %CallTupleParam.type = struct_value () [template] -// CHECK:STDOUT: %.4: i32 = int_literal 1 [template] -// CHECK:STDOUT: %.5: i32 = int_literal 2 [template] -// CHECK:STDOUT: %.6: type = tuple_type (i32, i32) [template] -// CHECK:STDOUT: %.7: type = ptr_type %.6 [template] -// CHECK:STDOUT: %tuple: %.6 = tuple_value (%.4, %.5) [template] +// CHECK:STDOUT: %.5: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.6: i32 = int_literal 2 [template] +// CHECK:STDOUT: %.7: type = tuple_type (i32, i32) [template] +// CHECK:STDOUT: %.8: = specific_function %TupleParam, @TupleParam(i32) [template] +// CHECK:STDOUT: %.9: type = ptr_type %.7 [template] +// CHECK:STDOUT: %tuple: %.7 = tuple_value (%.5, %.6) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -506,18 +571,24 @@ fn CallImplicitNotDeducible() { // CHECK:STDOUT: %T.loc4_15.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc4_15.2 (constants.%T)] // CHECK:STDOUT: %.loc4_35.5: type = tuple_type (@TupleParam.%T.loc4_15.2 (%T), i32) [symbolic = %.loc4_35.5 (constants.%.3)] // CHECK:STDOUT: -// CHECK:STDOUT: fn[%T.loc4_15.1: type](%x: @TupleParam.%.loc4_35.5 (%.3)); +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%T.loc4_15.1: type](%x: @TupleParam.%.loc4_35.5 (%.3)) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @CallTupleParam() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %TupleParam.ref: %TupleParam.type = name_ref TupleParam, file.%TupleParam.decl [template = constants.%TupleParam] -// CHECK:STDOUT: %.loc7_15: i32 = int_literal 1 [template = constants.%.4] -// CHECK:STDOUT: %.loc7_18: i32 = int_literal 2 [template = constants.%.5] -// CHECK:STDOUT: %.loc7_19: %.6 = tuple_literal (%.loc7_15, %.loc7_18) -// CHECK:STDOUT: %tuple: %.6 = tuple_value (%.loc7_15, %.loc7_18) [template = constants.%tuple] -// CHECK:STDOUT: %.loc7_13: %.6 = converted %.loc7_19, %tuple [template = constants.%tuple] -// CHECK:STDOUT: %TupleParam.call: init %.1 = call %TupleParam.ref(%.loc7_13) +// CHECK:STDOUT: %.loc7_15: i32 = int_literal 1 [template = constants.%.5] +// CHECK:STDOUT: %.loc7_18: i32 = int_literal 2 [template = constants.%.6] +// CHECK:STDOUT: %.loc7_19: %.7 = tuple_literal (%.loc7_15, %.loc7_18) +// CHECK:STDOUT: %.loc7_3: = specific_function %TupleParam.ref, @TupleParam(i32) [template = constants.%.8] +// CHECK:STDOUT: %tuple: %.7 = tuple_value (%.loc7_15, %.loc7_18) [template = constants.%tuple] +// CHECK:STDOUT: %.loc7_13: %.7 = converted %.loc7_19, %tuple [template = constants.%tuple] +// CHECK:STDOUT: %TupleParam.call: init %.1 = call %.loc7_3(%.loc7_13) // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: @@ -528,7 +599,9 @@ fn CallImplicitNotDeducible() { // CHECK:STDOUT: // CHECK:STDOUT: specific @TupleParam(i32) { // CHECK:STDOUT: %T.loc4_15.2 => i32 -// CHECK:STDOUT: %.loc4_35.5 => constants.%.6 +// CHECK:STDOUT: %.loc4_35.5 => constants.%.7 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_todo_deduce_nested_struct.carbon @@ -541,11 +614,12 @@ fn CallImplicitNotDeducible() { // CHECK:STDOUT: %.2: type = struct_type {.a: %T, .b: i32} [symbolic] // CHECK:STDOUT: %StructParam.type: type = fn_type @StructParam [template] // CHECK:STDOUT: %StructParam: %StructParam.type = struct_value () [template] +// CHECK:STDOUT: %.3: type = ptr_type %.2 [symbolic] // CHECK:STDOUT: %CallStructParam.type: type = fn_type @CallStructParam [template] // CHECK:STDOUT: %CallStructParam: %CallStructParam.type = struct_value () [template] -// CHECK:STDOUT: %.3: i32 = int_literal 1 [template] -// CHECK:STDOUT: %.4: i32 = int_literal 2 [template] -// CHECK:STDOUT: %.5: type = struct_type {.a: i32, .b: i32} [template] +// CHECK:STDOUT: %.4: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.5: i32 = int_literal 2 [template] +// CHECK:STDOUT: %.6: type = struct_type {.a: i32, .b: i32} [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -593,15 +667,20 @@ fn CallImplicitNotDeducible() { // CHECK:STDOUT: %T.loc4_16.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc4_16.2 (constants.%T)] // CHECK:STDOUT: %.loc4_44.2: type = struct_type {.a: @StructParam.%T.loc4_16.2 (%T), .b: i32} [symbolic = %.loc4_44.2 (constants.%.2)] // CHECK:STDOUT: -// CHECK:STDOUT: fn[%T.loc4_16.1: type](%x: @StructParam.%.loc4_44.2 (%.2)); +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%T.loc4_16.1: type](%x: @StructParam.%.loc4_44.2 (%.2)) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @CallStructParam() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %StructParam.ref: %StructParam.type = name_ref StructParam, file.%StructParam.decl [template = constants.%StructParam] -// CHECK:STDOUT: %.loc14_21: i32 = int_literal 1 [template = constants.%.3] -// CHECK:STDOUT: %.loc14_29: i32 = int_literal 2 [template = constants.%.4] -// CHECK:STDOUT: %.loc14_30: %.5 = struct_literal (%.loc14_21, %.loc14_29) +// CHECK:STDOUT: %.loc14_21: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc14_29: i32 = int_literal 2 [template = constants.%.5] +// CHECK:STDOUT: %.loc14_30: %.6 = struct_literal (%.loc14_21, %.loc14_29) // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/generic/no_prelude/call.carbon b/toolchain/check/testdata/function/generic/no_prelude/call.carbon index 77d57deaafa9..5b5111908e15 100644 --- a/toolchain/check/testdata/function/generic/no_prelude/call.carbon +++ b/toolchain/check/testdata/function/generic/no_prelude/call.carbon @@ -61,15 +61,18 @@ fn CallSpecific(x: C) -> C { // CHECK:STDOUT: %Function: %Function.type = struct_value () [template] // CHECK:STDOUT: %CallGeneric.type: type = fn_type @CallGeneric [template] // CHECK:STDOUT: %CallGeneric: %CallGeneric.type = struct_value () [template] -// CHECK:STDOUT: %.2: type = ptr_type %T [symbolic] +// CHECK:STDOUT: %.2: = specific_function %Function, @Function(%T) [symbolic] +// CHECK:STDOUT: %.3: type = ptr_type %T [symbolic] // CHECK:STDOUT: %CallGenericPtr.type: type = fn_type @CallGenericPtr [template] // CHECK:STDOUT: %CallGenericPtr: %CallGenericPtr.type = struct_value () [template] +// CHECK:STDOUT: %.4: = specific_function %Function, @Function(%.3) [symbolic] // CHECK:STDOUT: %C: type = class_type @C [template] -// CHECK:STDOUT: %.3: type = struct_type {} [template] -// CHECK:STDOUT: %.4: = complete_type_witness %.3 [template] +// CHECK:STDOUT: %.5: type = struct_type {} [template] +// CHECK:STDOUT: %.6: = complete_type_witness %.5 [template] // CHECK:STDOUT: %CallSpecific.type: type = fn_type @CallSpecific [template] // CHECK:STDOUT: %CallSpecific: %CallSpecific.type = struct_value () [template] -// CHECK:STDOUT: %.5: type = ptr_type %.3 [template] +// CHECK:STDOUT: %.7: type = ptr_type %.5 [template] +// CHECK:STDOUT: %.8: = specific_function %Function, @Function(%C) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -106,17 +109,17 @@ fn CallSpecific(x: C) -> C { // CHECK:STDOUT: } // CHECK:STDOUT: %CallGenericPtr.decl: %CallGenericPtr.type = fn_decl @CallGenericPtr [template = constants.%CallGenericPtr] { // CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 -// CHECK:STDOUT: %x.patt: @CallGenericPtr.%.loc12_33.2 (%.2) = binding_pattern x +// CHECK:STDOUT: %x.patt: @CallGenericPtr.%.loc12_33.2 (%.3) = binding_pattern x // CHECK:STDOUT: } { // CHECK:STDOUT: %T.param: type = param T, runtime_param // CHECK:STDOUT: %T.loc12_19.1: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc12_19.2 (constants.%T)] // CHECK:STDOUT: %T.ref.loc12_32: type = name_ref T, %T.loc12_19.1 [symbolic = %T.loc12_19.2 (constants.%T)] -// CHECK:STDOUT: %.loc12_33.1: type = ptr_type %T [symbolic = %.loc12_33.2 (constants.%.2)] -// CHECK:STDOUT: %x.param: @CallGenericPtr.%.loc12_33.2 (%.2) = param x, runtime_param0 -// CHECK:STDOUT: %x: @CallGenericPtr.%.loc12_33.2 (%.2) = bind_name x, %x.param +// CHECK:STDOUT: %.loc12_33.1: type = ptr_type %T [symbolic = %.loc12_33.2 (constants.%.3)] +// CHECK:STDOUT: %x.param: @CallGenericPtr.%.loc12_33.2 (%.3) = param x, runtime_param0 +// CHECK:STDOUT: %x: @CallGenericPtr.%.loc12_33.2 (%.3) = bind_name x, %x.param // CHECK:STDOUT: %T.ref.loc12_39: type = name_ref T, %T.loc12_19.1 [symbolic = %T.loc12_19.2 (constants.%T)] -// CHECK:STDOUT: %.loc12_40: type = ptr_type %T [symbolic = %.loc12_33.2 (constants.%.2)] -// CHECK:STDOUT: %return: ref @CallGenericPtr.%.loc12_33.2 (%.2) = var +// CHECK:STDOUT: %.loc12_40: type = ptr_type %T [symbolic = %.loc12_33.2 (constants.%.3)] +// CHECK:STDOUT: %return: ref @CallGenericPtr.%.loc12_33.2 (%.3) = var // CHECK:STDOUT: } // CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} {} // CHECK:STDOUT: %CallSpecific.decl: %CallSpecific.type = fn_decl @CallSpecific [template = constants.%CallSpecific] { @@ -131,7 +134,7 @@ fn CallSpecific(x: C) -> C { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: class @C { -// CHECK:STDOUT: %.loc16: = complete_type_witness %.3 [template = constants.%.4] +// CHECK:STDOUT: %.loc16: = complete_type_witness %.5 [template = constants.%.6] // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = constants.%C @@ -153,13 +156,15 @@ fn CallSpecific(x: C) -> C { // CHECK:STDOUT: %T.loc8_16.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc8_16.2 (constants.%T)] // CHECK:STDOUT: // CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc9_10.2: = specific_function constants.%Function, @Function(%T.loc8_16.2) [symbolic = %.loc9_10.2 (constants.%.2)] // CHECK:STDOUT: // CHECK:STDOUT: fn(%T.loc8_16.1: type, %x: @CallGeneric.%T.loc8_16.2 (%T)) -> @CallGeneric.%T.loc8_16.2 (%T) { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Function.ref: %Function.type = name_ref Function, file.%Function.decl [template = constants.%Function] // CHECK:STDOUT: %T.ref.loc9: type = name_ref T, %T.loc8_16.1 [symbolic = %T.loc8_16.2 (constants.%T)] // CHECK:STDOUT: %x.ref: @CallGeneric.%T.loc8_16.2 (%T) = name_ref x, %x -// CHECK:STDOUT: %Function.call: init @CallGeneric.%T.loc8_16.2 (%T) = call %Function.ref(%x.ref) +// CHECK:STDOUT: %.loc9_10.1: = specific_function %Function.ref, @Function(constants.%T) [symbolic = %.loc9_10.2 (constants.%.2)] +// CHECK:STDOUT: %Function.call: init @CallGeneric.%T.loc8_16.2 (%T) = call %.loc9_10.1(%x.ref) // CHECK:STDOUT: %.loc9_24.1: @CallGeneric.%T.loc8_16.2 (%T) = value_of_initializer %Function.call // CHECK:STDOUT: %.loc9_24.2: @CallGeneric.%T.loc8_16.2 (%T) = converted %Function.call, %.loc9_24.1 // CHECK:STDOUT: return %.loc9_24.2 @@ -168,19 +173,21 @@ fn CallSpecific(x: C) -> C { // CHECK:STDOUT: // CHECK:STDOUT: generic fn @CallGenericPtr(%T.loc12_19.1: type) { // CHECK:STDOUT: %T.loc12_19.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc12_19.2 (constants.%T)] -// CHECK:STDOUT: %.loc12_33.2: type = ptr_type @CallGenericPtr.%T.loc12_19.2 (%T) [symbolic = %.loc12_33.2 (constants.%.2)] +// CHECK:STDOUT: %.loc12_33.2: type = ptr_type @CallGenericPtr.%T.loc12_19.2 (%T) [symbolic = %.loc12_33.2 (constants.%.3)] // CHECK:STDOUT: // CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc13_10.2: = specific_function constants.%Function, @Function(%.loc12_33.2) [symbolic = %.loc13_10.2 (constants.%.4)] // CHECK:STDOUT: -// CHECK:STDOUT: fn(%T.loc12_19.1: type, %x: @CallGenericPtr.%.loc12_33.2 (%.2)) -> @CallGenericPtr.%.loc12_33.2 (%.2) { +// CHECK:STDOUT: fn(%T.loc12_19.1: type, %x: @CallGenericPtr.%.loc12_33.2 (%.3)) -> @CallGenericPtr.%.loc12_33.2 (%.3) { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Function.ref: %Function.type = name_ref Function, file.%Function.decl [template = constants.%Function] // CHECK:STDOUT: %T.ref.loc13: type = name_ref T, %T.loc12_19.1 [symbolic = %T.loc12_19.2 (constants.%T)] -// CHECK:STDOUT: %.loc13_20: type = ptr_type %T [symbolic = %.loc12_33.2 (constants.%.2)] -// CHECK:STDOUT: %x.ref: @CallGenericPtr.%.loc12_33.2 (%.2) = name_ref x, %x -// CHECK:STDOUT: %Function.call: init @CallGenericPtr.%.loc12_33.2 (%.2) = call %Function.ref(%x.ref) -// CHECK:STDOUT: %.loc13_25.1: @CallGenericPtr.%.loc12_33.2 (%.2) = value_of_initializer %Function.call -// CHECK:STDOUT: %.loc13_25.2: @CallGenericPtr.%.loc12_33.2 (%.2) = converted %Function.call, %.loc13_25.1 +// CHECK:STDOUT: %.loc13_20: type = ptr_type %T [symbolic = %.loc12_33.2 (constants.%.3)] +// CHECK:STDOUT: %x.ref: @CallGenericPtr.%.loc12_33.2 (%.3) = name_ref x, %x +// CHECK:STDOUT: %.loc13_10.1: = specific_function %Function.ref, @Function(constants.%.3) [symbolic = %.loc13_10.2 (constants.%.4)] +// CHECK:STDOUT: %Function.call: init @CallGenericPtr.%.loc12_33.2 (%.3) = call %.loc13_10.1(%x.ref) +// CHECK:STDOUT: %.loc13_25.1: @CallGenericPtr.%.loc12_33.2 (%.3) = value_of_initializer %Function.call +// CHECK:STDOUT: %.loc13_25.2: @CallGenericPtr.%.loc12_33.2 (%.3) = converted %Function.call, %.loc13_25.1 // CHECK:STDOUT: return %.loc13_25.2 // CHECK:STDOUT: } // CHECK:STDOUT: } @@ -190,30 +197,45 @@ fn CallSpecific(x: C) -> C { // CHECK:STDOUT: %Function.ref: %Function.type = name_ref Function, file.%Function.decl [template = constants.%Function] // CHECK:STDOUT: %C.ref.loc19: type = name_ref C, file.%C.decl [template = constants.%C] // CHECK:STDOUT: %x.ref: %C = name_ref x, %x +// CHECK:STDOUT: %.loc19: = specific_function %Function.ref, @Function(constants.%C) [template = constants.%.8] // CHECK:STDOUT: %.loc18: ref %C = splice_block %return {} -// CHECK:STDOUT: %Function.call: init %C = call %Function.ref(%x.ref) to %.loc18 +// CHECK:STDOUT: %Function.call: init %C = call %.loc19(%x.ref) to %.loc18 // CHECK:STDOUT: return %Function.call to %return // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Function(constants.%T) { // CHECK:STDOUT: %T.loc4_13.2 => constants.%T +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @CallGeneric(constants.%T) { // CHECK:STDOUT: %T.loc8_16.2 => constants.%T // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @CallGenericPtr(constants.%T) { -// CHECK:STDOUT: %T.loc12_19.2 => constants.%T -// CHECK:STDOUT: %.loc12_33.2 => constants.%.2 +// CHECK:STDOUT: specific @Function(@CallGeneric.%T.loc8_16.2) { +// CHECK:STDOUT: %T.loc4_13.2 => constants.%T // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @Function(constants.%.2) { -// CHECK:STDOUT: %T.loc4_13.2 => constants.%.2 +// CHECK:STDOUT: specific @CallGenericPtr(constants.%T) { +// CHECK:STDOUT: %T.loc12_19.2 => constants.%T +// CHECK:STDOUT: %.loc12_33.2 => constants.%.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Function(constants.%.3) { +// CHECK:STDOUT: %T.loc4_13.2 => constants.%.3 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Function(@CallGenericPtr.%.loc12_33.2) { +// CHECK:STDOUT: %T.loc4_13.2 => constants.%.3 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Function(constants.%C) { // CHECK:STDOUT: %T.loc4_13.2 => constants.%C +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- deduced.carbon @@ -225,15 +247,18 @@ fn CallSpecific(x: C) -> C { // CHECK:STDOUT: %Function: %Function.type = struct_value () [template] // CHECK:STDOUT: %CallGeneric.type: type = fn_type @CallGeneric [template] // CHECK:STDOUT: %CallGeneric: %CallGeneric.type = struct_value () [template] -// CHECK:STDOUT: %.2: type = ptr_type %T [symbolic] +// CHECK:STDOUT: %.2: = specific_function %Function, @Function(%T) [symbolic] +// CHECK:STDOUT: %.3: type = ptr_type %T [symbolic] // CHECK:STDOUT: %CallGenericPtr.type: type = fn_type @CallGenericPtr [template] // CHECK:STDOUT: %CallGenericPtr: %CallGenericPtr.type = struct_value () [template] +// CHECK:STDOUT: %.4: = specific_function %Function, @Function(%.3) [symbolic] // CHECK:STDOUT: %C: type = class_type @C [template] -// CHECK:STDOUT: %.3: type = struct_type {} [template] -// CHECK:STDOUT: %.4: = complete_type_witness %.3 [template] +// CHECK:STDOUT: %.5: type = struct_type {} [template] +// CHECK:STDOUT: %.6: = complete_type_witness %.5 [template] // CHECK:STDOUT: %CallSpecific.type: type = fn_type @CallSpecific [template] // CHECK:STDOUT: %CallSpecific: %CallSpecific.type = struct_value () [template] -// CHECK:STDOUT: %.5: type = ptr_type %.3 [template] +// CHECK:STDOUT: %.7: type = ptr_type %.5 [template] +// CHECK:STDOUT: %.8: = specific_function %Function, @Function(%C) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -270,17 +295,17 @@ fn CallSpecific(x: C) -> C { // CHECK:STDOUT: } // CHECK:STDOUT: %CallGenericPtr.decl: %CallGenericPtr.type = fn_decl @CallGenericPtr [template = constants.%CallGenericPtr] { // CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 -// CHECK:STDOUT: %x.patt: @CallGenericPtr.%.loc12_33.2 (%.2) = binding_pattern x +// CHECK:STDOUT: %x.patt: @CallGenericPtr.%.loc12_33.2 (%.3) = binding_pattern x // CHECK:STDOUT: } { // CHECK:STDOUT: %T.param: type = param T, runtime_param // CHECK:STDOUT: %T.loc12_19.1: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc12_19.2 (constants.%T)] // CHECK:STDOUT: %T.ref.loc12_32: type = name_ref T, %T.loc12_19.1 [symbolic = %T.loc12_19.2 (constants.%T)] -// CHECK:STDOUT: %.loc12_33.1: type = ptr_type %T [symbolic = %.loc12_33.2 (constants.%.2)] -// CHECK:STDOUT: %x.param: @CallGenericPtr.%.loc12_33.2 (%.2) = param x, runtime_param0 -// CHECK:STDOUT: %x: @CallGenericPtr.%.loc12_33.2 (%.2) = bind_name x, %x.param +// CHECK:STDOUT: %.loc12_33.1: type = ptr_type %T [symbolic = %.loc12_33.2 (constants.%.3)] +// CHECK:STDOUT: %x.param: @CallGenericPtr.%.loc12_33.2 (%.3) = param x, runtime_param0 +// CHECK:STDOUT: %x: @CallGenericPtr.%.loc12_33.2 (%.3) = bind_name x, %x.param // CHECK:STDOUT: %T.ref.loc12_39: type = name_ref T, %T.loc12_19.1 [symbolic = %T.loc12_19.2 (constants.%T)] -// CHECK:STDOUT: %.loc12_40: type = ptr_type %T [symbolic = %.loc12_33.2 (constants.%.2)] -// CHECK:STDOUT: %return: ref @CallGenericPtr.%.loc12_33.2 (%.2) = var +// CHECK:STDOUT: %.loc12_40: type = ptr_type %T [symbolic = %.loc12_33.2 (constants.%.3)] +// CHECK:STDOUT: %return: ref @CallGenericPtr.%.loc12_33.2 (%.3) = var // CHECK:STDOUT: } // CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} {} // CHECK:STDOUT: %CallSpecific.decl: %CallSpecific.type = fn_decl @CallSpecific [template = constants.%CallSpecific] { @@ -295,7 +320,7 @@ fn CallSpecific(x: C) -> C { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: class @C { -// CHECK:STDOUT: %.loc16: = complete_type_witness %.3 [template = constants.%.4] +// CHECK:STDOUT: %.loc16: = complete_type_witness %.5 [template = constants.%.6] // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = constants.%C @@ -317,12 +342,14 @@ fn CallSpecific(x: C) -> C { // CHECK:STDOUT: %T.loc8_16.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc8_16.2 (constants.%T)] // CHECK:STDOUT: // CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc9_10.2: = specific_function constants.%Function, @Function(%T.loc8_16.2) [symbolic = %.loc9_10.2 (constants.%.2)] // CHECK:STDOUT: // CHECK:STDOUT: fn(%T.loc8_16.1: type, %x: @CallGeneric.%T.loc8_16.2 (%T)) -> @CallGeneric.%T.loc8_16.2 (%T) { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Function.ref: %Function.type = name_ref Function, file.%Function.decl [template = constants.%Function] // CHECK:STDOUT: %x.ref: @CallGeneric.%T.loc8_16.2 (%T) = name_ref x, %x -// CHECK:STDOUT: %Function.call: init @CallGeneric.%T.loc8_16.2 (%T) = call %Function.ref(%x.ref) +// CHECK:STDOUT: %.loc9_10.1: = specific_function %Function.ref, @Function(constants.%T) [symbolic = %.loc9_10.2 (constants.%.2)] +// CHECK:STDOUT: %Function.call: init @CallGeneric.%T.loc8_16.2 (%T) = call %.loc9_10.1(%x.ref) // CHECK:STDOUT: %.loc9_21.1: @CallGeneric.%T.loc8_16.2 (%T) = value_of_initializer %Function.call // CHECK:STDOUT: %.loc9_21.2: @CallGeneric.%T.loc8_16.2 (%T) = converted %Function.call, %.loc9_21.1 // CHECK:STDOUT: return %.loc9_21.2 @@ -331,17 +358,19 @@ fn CallSpecific(x: C) -> C { // CHECK:STDOUT: // CHECK:STDOUT: generic fn @CallGenericPtr(%T.loc12_19.1: type) { // CHECK:STDOUT: %T.loc12_19.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc12_19.2 (constants.%T)] -// CHECK:STDOUT: %.loc12_33.2: type = ptr_type @CallGenericPtr.%T.loc12_19.2 (%T) [symbolic = %.loc12_33.2 (constants.%.2)] +// CHECK:STDOUT: %.loc12_33.2: type = ptr_type @CallGenericPtr.%T.loc12_19.2 (%T) [symbolic = %.loc12_33.2 (constants.%.3)] // CHECK:STDOUT: // CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc13_10.2: = specific_function constants.%Function, @Function(%.loc12_33.2) [symbolic = %.loc13_10.2 (constants.%.4)] // CHECK:STDOUT: -// CHECK:STDOUT: fn(%T.loc12_19.1: type, %x: @CallGenericPtr.%.loc12_33.2 (%.2)) -> @CallGenericPtr.%.loc12_33.2 (%.2) { +// CHECK:STDOUT: fn(%T.loc12_19.1: type, %x: @CallGenericPtr.%.loc12_33.2 (%.3)) -> @CallGenericPtr.%.loc12_33.2 (%.3) { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Function.ref: %Function.type = name_ref Function, file.%Function.decl [template = constants.%Function] -// CHECK:STDOUT: %x.ref: @CallGenericPtr.%.loc12_33.2 (%.2) = name_ref x, %x -// CHECK:STDOUT: %Function.call: init @CallGenericPtr.%.loc12_33.2 (%.2) = call %Function.ref(%x.ref) -// CHECK:STDOUT: %.loc13_21.1: @CallGenericPtr.%.loc12_33.2 (%.2) = value_of_initializer %Function.call -// CHECK:STDOUT: %.loc13_21.2: @CallGenericPtr.%.loc12_33.2 (%.2) = converted %Function.call, %.loc13_21.1 +// CHECK:STDOUT: %x.ref: @CallGenericPtr.%.loc12_33.2 (%.3) = name_ref x, %x +// CHECK:STDOUT: %.loc13_10.1: = specific_function %Function.ref, @Function(constants.%.3) [symbolic = %.loc13_10.2 (constants.%.4)] +// CHECK:STDOUT: %Function.call: init @CallGenericPtr.%.loc12_33.2 (%.3) = call %.loc13_10.1(%x.ref) +// CHECK:STDOUT: %.loc13_21.1: @CallGenericPtr.%.loc12_33.2 (%.3) = value_of_initializer %Function.call +// CHECK:STDOUT: %.loc13_21.2: @CallGenericPtr.%.loc12_33.2 (%.3) = converted %Function.call, %.loc13_21.1 // CHECK:STDOUT: return %.loc13_21.2 // CHECK:STDOUT: } // CHECK:STDOUT: } @@ -350,29 +379,44 @@ fn CallSpecific(x: C) -> C { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Function.ref: %Function.type = name_ref Function, file.%Function.decl [template = constants.%Function] // CHECK:STDOUT: %x.ref: %C = name_ref x, %x +// CHECK:STDOUT: %.loc19: = specific_function %Function.ref, @Function(constants.%C) [template = constants.%.8] // CHECK:STDOUT: %.loc18: ref %C = splice_block %return {} -// CHECK:STDOUT: %Function.call: init %C = call %Function.ref(%x.ref) to %.loc18 +// CHECK:STDOUT: %Function.call: init %C = call %.loc19(%x.ref) to %.loc18 // CHECK:STDOUT: return %Function.call to %return // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Function(constants.%T) { // CHECK:STDOUT: %T.loc4_13.2 => constants.%T +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @CallGeneric(constants.%T) { // CHECK:STDOUT: %T.loc8_16.2 => constants.%T // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @CallGenericPtr(constants.%T) { -// CHECK:STDOUT: %T.loc12_19.2 => constants.%T -// CHECK:STDOUT: %.loc12_33.2 => constants.%.2 +// CHECK:STDOUT: specific @Function(@CallGeneric.%T.loc8_16.2) { +// CHECK:STDOUT: %T.loc4_13.2 => constants.%T // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @Function(constants.%.2) { -// CHECK:STDOUT: %T.loc4_13.2 => constants.%.2 +// CHECK:STDOUT: specific @CallGenericPtr(constants.%T) { +// CHECK:STDOUT: %T.loc12_19.2 => constants.%T +// CHECK:STDOUT: %.loc12_33.2 => constants.%.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Function(constants.%.3) { +// CHECK:STDOUT: %T.loc4_13.2 => constants.%.3 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Function(@CallGenericPtr.%.loc12_33.2) { +// CHECK:STDOUT: %T.loc4_13.2 => constants.%.3 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Function(constants.%C) { // CHECK:STDOUT: %T.loc4_13.2 => constants.%C +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/generic/redeclare.carbon b/toolchain/check/testdata/function/generic/redeclare.carbon index 67a1f9a5309c..e890c7eaa3f4 100644 --- a/toolchain/check/testdata/function/generic/redeclare.carbon +++ b/toolchain/check/testdata/function/generic/redeclare.carbon @@ -97,6 +97,7 @@ fn F(U:! type, T:! type) -> U* { // CHECK:STDOUT: %F.type: type = fn_type @F [template] // CHECK:STDOUT: %.2: type = tuple_type () [template] // CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: %.3: = specific_function %F, @F(%T) [symbolic] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -143,12 +144,14 @@ fn F(U:! type, T:! type) -> U* { // CHECK:STDOUT: %.loc4_20.2: type = ptr_type @F.%T.loc4_6.2 (%T) [symbolic = %.loc4_20.2 (constants.%.1)] // CHECK:STDOUT: // CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc7_10.2: = specific_function constants.%F, @F(%T.loc4_6.2) [symbolic = %.loc7_10.2 (constants.%.3)] // CHECK:STDOUT: // CHECK:STDOUT: fn(%T.loc6: type) -> %.1 { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl.loc4 [template = constants.%F] // CHECK:STDOUT: %T.ref.loc7: type = name_ref T, %T.loc6 [symbolic = %T.loc4_6.2 (constants.%T)] -// CHECK:STDOUT: %F.call: init @F.%.loc4_20.2 (%.1) = call %F.ref() +// CHECK:STDOUT: %.loc7_10.1: = specific_function %F.ref, @F(constants.%T) [symbolic = %.loc7_10.2 (constants.%.3)] +// CHECK:STDOUT: %F.call: init @F.%.loc4_20.2 (%.1) = call %.loc7_10.1() // CHECK:STDOUT: %.loc7_14.1: @F.%.loc4_20.2 (%.1) = value_of_initializer %F.call // CHECK:STDOUT: %.loc7_14.2: @F.%.loc4_20.2 (%.1) = converted %F.call, %.loc7_14.1 // CHECK:STDOUT: return %.loc7_14.2 @@ -158,6 +161,14 @@ fn F(U:! type, T:! type) -> U* { // CHECK:STDOUT: specific @F(constants.%T) { // CHECK:STDOUT: %T.loc4_6.2 => constants.%T // CHECK:STDOUT: %.loc4_20.2 => constants.%.1 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc7_10.2 => constants.%.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F(@F.%T.loc4_6.2) { +// CHECK:STDOUT: %T.loc4_6.2 => constants.%T +// CHECK:STDOUT: %.loc4_20.2 => constants.%.1 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_different_return_type.carbon diff --git a/toolchain/check/testdata/function/generic/resolve_used.carbon b/toolchain/check/testdata/function/generic/resolve_used.carbon new file mode 100644 index 000000000000..b493b6726e63 --- /dev/null +++ b/toolchain/check/testdata/function/generic/resolve_used.carbon @@ -0,0 +1,127 @@ +// 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 +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/function/generic/resolve_used.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/function/generic/resolve_used.carbon + +// --- fail_call_monomorphization_error.carbon + +library "[[@TEST_NAME]]"; + +fn ErrorIfNIsZero(N:! i32) { + // Check that we resolve the definition of a used specific function by + // ensuring we produce an error when doing so. Notionally this error is + // produced as a result of instantiating the `Core.Int` template, although + // that's not how we currently model `Core.Int`. + // CHECK:STDERR: fail_call_monomorphization_error.carbon:[[@LINE+3]]:10: error: integer type width of 0 is not positive + // CHECK:STDERR: var v: Core.Int(N); + // CHECK:STDERR: ^~~~~~~~~ + var v: Core.Int(N); +} + +fn CallNegative() { + ErrorIfNIsZero(0); +} + +// CHECK:STDOUT: --- fail_call_monomorphization_error.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Int32.type: type = fn_type @Int32 [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %Int32: %Int32.type = struct_value () [template] +// CHECK:STDOUT: %N: i32 = bind_symbolic_name N, 0 [symbolic] +// CHECK:STDOUT: %ErrorIfNIsZero.type: type = fn_type @ErrorIfNIsZero [template] +// CHECK:STDOUT: %ErrorIfNIsZero: %ErrorIfNIsZero.type = struct_value () [template] +// CHECK:STDOUT: %Int.type: type = fn_type @Int [template] +// CHECK:STDOUT: %Int: %Int.type = struct_value () [template] +// CHECK:STDOUT: %.2: type = int_type signed, %N [symbolic] +// CHECK:STDOUT: %CallNegative.type: type = fn_type @CallNegative [template] +// CHECK:STDOUT: %CallNegative: %CallNegative.type = struct_value () [template] +// CHECK:STDOUT: %.3: i32 = int_literal 0 [template] +// CHECK:STDOUT: %.4: = specific_function %ErrorIfNIsZero, @ErrorIfNIsZero(%.3) [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { +// CHECK:STDOUT: .Int32 = %import_ref.1 +// CHECK:STDOUT: .Int = %import_ref.2 +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/operators +// CHECK:STDOUT: import Core//prelude/types +// CHECK:STDOUT: import Core//prelude/operators/arithmetic +// CHECK:STDOUT: import Core//prelude/operators/as +// CHECK:STDOUT: import Core//prelude/operators/bitwise +// CHECK:STDOUT: import Core//prelude/operators/comparison +// CHECK:STDOUT: import Core//prelude/types/bool +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.1: %Int32.type = import_ref Core//prelude/types, inst+4, loaded [template = constants.%Int32] +// CHECK:STDOUT: %import_ref.2: %Int.type = import_ref Core//prelude/types, inst+15, loaded [template = constants.%Int] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .ErrorIfNIsZero = %ErrorIfNIsZero.decl +// CHECK:STDOUT: .CallNegative = %CallNegative.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %ErrorIfNIsZero.decl: %ErrorIfNIsZero.type = fn_decl @ErrorIfNIsZero [template = constants.%ErrorIfNIsZero] { +// CHECK:STDOUT: %N.patt: i32 = symbolic_binding_pattern N, 0 +// CHECK:STDOUT: } { +// CHECK:STDOUT: %int.make_type_32: init type = call constants.%Int32() [template = i32] +// CHECK:STDOUT: %.loc4_23.1: type = value_of_initializer %int.make_type_32 [template = i32] +// CHECK:STDOUT: %.loc4_23.2: type = converted %int.make_type_32, %.loc4_23.1 [template = i32] +// CHECK:STDOUT: %N.param: i32 = param N, runtime_param +// CHECK:STDOUT: %N.loc4_19.1: i32 = bind_symbolic_name N, 0, %N.param [symbolic = %N.loc4_19.2 (constants.%N)] +// CHECK:STDOUT: } +// CHECK:STDOUT: %CallNegative.decl: %CallNegative.type = fn_decl @CallNegative [template = constants.%CallNegative] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @ErrorIfNIsZero(%N.loc4_19.1: i32) { +// CHECK:STDOUT: %N.loc4_19.2: i32 = bind_symbolic_name N, 0 [symbolic = %N.loc4_19.2 (constants.%N)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc12_18: type = int_type signed, %N.loc4_19.2 [symbolic = %.loc12_18 (constants.%.2)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn(%N.loc4_19.1: i32) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Core.ref: = name_ref Core, imports.%Core [template = imports.%Core] +// CHECK:STDOUT: %Int.ref: %Int.type = name_ref Int, imports.%import_ref.2 [template = constants.%Int] +// CHECK:STDOUT: %N.ref: i32 = name_ref N, %N.loc4_19.1 [symbolic = %N.loc4_19.2 (constants.%N)] +// CHECK:STDOUT: %int.make_type_signed: init type = call %Int.ref(%N.ref) [symbolic = %.loc12_18 (constants.%.2)] +// CHECK:STDOUT: %.loc12_20.1: type = value_of_initializer %int.make_type_signed [symbolic = %.loc12_18 (constants.%.2)] +// CHECK:STDOUT: %.loc12_20.2: type = converted %int.make_type_signed, %.loc12_20.1 [symbolic = %.loc12_18 (constants.%.2)] +// CHECK:STDOUT: %v.var: ref @ErrorIfNIsZero.%.loc12_18 (%.2) = var v +// CHECK:STDOUT: %v: ref @ErrorIfNIsZero.%.loc12_18 (%.2) = bind_name v, %v.var +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Int(%size: i32) -> type = "int.make_type_signed"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @CallNegative() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %ErrorIfNIsZero.ref: %ErrorIfNIsZero.type = name_ref ErrorIfNIsZero, file.%ErrorIfNIsZero.decl [template = constants.%ErrorIfNIsZero] +// CHECK:STDOUT: %.loc16_18: i32 = int_literal 0 [template = constants.%.3] +// CHECK:STDOUT: %.loc16_3: = specific_function %ErrorIfNIsZero.ref, @ErrorIfNIsZero(constants.%.3) [template = constants.%.4] +// CHECK:STDOUT: %ErrorIfNIsZero.call: init %.1 = call %.loc16_3() +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @ErrorIfNIsZero(constants.%N) { +// CHECK:STDOUT: %N.loc4_19.2 => constants.%N +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @ErrorIfNIsZero(constants.%.3) { +// CHECK:STDOUT: %N.loc4_19.2 => constants.%.3 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc12_18 => +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/generic/return_slot.carbon b/toolchain/check/testdata/function/generic/return_slot.carbon index a708c41f6fdb..22da7e024d39 100644 --- a/toolchain/check/testdata/function/generic/return_slot.carbon +++ b/toolchain/check/testdata/function/generic/return_slot.carbon @@ -9,7 +9,7 @@ // TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/function/generic/return_slot.carbon class Wrap(T:! type) { - fn Make() -> T; + fn Make() -> T { return Make(); } } class C { var arr: [i32; 100]; } @@ -32,29 +32,33 @@ fn G() { // CHECK:STDOUT: %Make.1: %Make.type.1 = struct_value () [symbolic] // CHECK:STDOUT: %.2: type = struct_type {} [template] // CHECK:STDOUT: %.3: = complete_type_witness %.2 [template] +// CHECK:STDOUT: %.4: = specific_function %Make.1, @Make(%T) [symbolic] // CHECK:STDOUT: %C: type = class_type @C [template] // CHECK:STDOUT: %Int32.type: type = fn_type @Int32 [template] // CHECK:STDOUT: %Int32: %Int32.type = struct_value () [template] -// CHECK:STDOUT: %.4: i32 = int_literal 100 [template] -// CHECK:STDOUT: %.5: type = array_type %.4, i32 [template] -// CHECK:STDOUT: %.6: type = ptr_type %.5 [template] -// CHECK:STDOUT: %.7: type = unbound_element_type %C, %.5 [template] -// CHECK:STDOUT: %.8: type = struct_type {.arr: %.5} [template] -// CHECK:STDOUT: %.9: = complete_type_witness %.8 [template] +// CHECK:STDOUT: %.5: i32 = int_literal 100 [template] +// CHECK:STDOUT: %.6: type = array_type %.5, i32 [template] +// CHECK:STDOUT: %.7: type = ptr_type %.6 [template] +// CHECK:STDOUT: %.8: type = unbound_element_type %C, %.6 [template] +// CHECK:STDOUT: %.9: type = struct_type {.arr: %.6} [template] +// CHECK:STDOUT: %.10: = complete_type_witness %.9 [template] // CHECK:STDOUT: %G.type: type = fn_type @G [template] // CHECK:STDOUT: %G: %G.type = struct_value () [template] // CHECK:STDOUT: %Wrap.3: type = class_type @Wrap, @Wrap(i32) [template] // CHECK:STDOUT: %Make.type.2: type = fn_type @Make, @Wrap(i32) [template] // CHECK:STDOUT: %Make.2: %Make.type.2 = struct_value () [template] -// CHECK:STDOUT: %.10: type = ptr_type %.2 [template] +// CHECK:STDOUT: %.11: type = ptr_type %.2 [template] +// CHECK:STDOUT: %.12: = specific_function %Make.2, @Make(i32) [template] // CHECK:STDOUT: %Wrap.4: type = class_type @Wrap, @Wrap(%.1) [template] // CHECK:STDOUT: %Make.type.3: type = fn_type @Make, @Wrap(%.1) [template] // CHECK:STDOUT: %Make.3: %Make.type.3 = struct_value () [template] -// CHECK:STDOUT: %.11: type = struct_type {.arr: %.6} [template] -// CHECK:STDOUT: %.12: type = ptr_type %.8 [template] +// CHECK:STDOUT: %.13: = specific_function %Make.3, @Make(%.1) [template] +// CHECK:STDOUT: %.14: type = struct_type {.arr: %.7} [template] +// CHECK:STDOUT: %.15: type = ptr_type %.9 [template] // CHECK:STDOUT: %Wrap.5: type = class_type @Wrap, @Wrap(%C) [template] // CHECK:STDOUT: %Make.type.4: type = fn_type @Make, @Wrap(%C) [template] // CHECK:STDOUT: %Make.4: %Make.type.4 = struct_value () [template] +// CHECK:STDOUT: %.16: = specific_function %Make.4, @Make(%C) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -112,12 +116,12 @@ fn G() { // CHECK:STDOUT: // CHECK:STDOUT: class @C { // CHECK:STDOUT: %int.make_type_32: init type = call constants.%Int32() [template = i32] -// CHECK:STDOUT: %.loc15_26: i32 = int_literal 100 [template = constants.%.4] +// CHECK:STDOUT: %.loc15_26: i32 = int_literal 100 [template = constants.%.5] // CHECK:STDOUT: %.loc15_21.1: type = value_of_initializer %int.make_type_32 [template = i32] // CHECK:STDOUT: %.loc15_21.2: type = converted %int.make_type_32, %.loc15_21.1 [template = i32] -// CHECK:STDOUT: %.loc15_29: type = array_type %.loc15_26, i32 [template = constants.%.5] -// CHECK:STDOUT: %.loc15_18: %.7 = field_decl arr, element0 [template] -// CHECK:STDOUT: %.loc15_32: = complete_type_witness %.8 [template = constants.%.9] +// CHECK:STDOUT: %.loc15_29: type = array_type %.loc15_26, i32 [template = constants.%.6] +// CHECK:STDOUT: %.loc15_18: %.8 = field_decl arr, element0 [template] +// CHECK:STDOUT: %.loc15_32: = complete_type_witness %.9 [template = constants.%.10] // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = constants.%C @@ -127,7 +131,21 @@ fn G() { // CHECK:STDOUT: generic fn @Make(@Wrap.%T.loc11_12.1: type) { // CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)] // CHECK:STDOUT: -// CHECK:STDOUT: fn() -> @Make.%T (%T); +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %Make.type: type = fn_type @Make, @Wrap(%T) [symbolic = %Make.type (constants.%Make.type.1)] +// CHECK:STDOUT: %Make: @Make.%Make.type (%Make.type.1) = struct_value () [symbolic = %Make (constants.%Make.1)] +// CHECK:STDOUT: %.loc12_27.3: = specific_function %Make, @Make(%T) [symbolic = %.loc12_27.3 (constants.%.4)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn() -> @Make.%T (%T) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc12_27.1: @Make.%Make.type (%Make.type.1) = specific_constant @Wrap.%Make.decl, @Wrap(constants.%T) [symbolic = %Make (constants.%Make.1)] +// CHECK:STDOUT: %Make.ref: @Make.%Make.type (%Make.type.1) = name_ref Make, %.loc12_27.1 [symbolic = %Make (constants.%Make.1)] +// CHECK:STDOUT: %.loc12_27.2: = specific_function %Make.ref, @Make(constants.%T) [symbolic = %.loc12_27.3 (constants.%.4)] +// CHECK:STDOUT: %Make.call: init @Make.%T (%T) = call %.loc12_27.2() +// CHECK:STDOUT: %.loc12_33.1: @Make.%T (%T) = value_of_initializer %Make.call +// CHECK:STDOUT: %.loc12_33.2: @Make.%T (%T) = converted %Make.call, %.loc12_33.1 +// CHECK:STDOUT: return %.loc12_33.2 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; @@ -144,9 +162,10 @@ fn G() { // CHECK:STDOUT: %.loc18_20.1: type = value_of_initializer %int.make_type_32.loc18_21 [template = i32] // CHECK:STDOUT: %.loc18_20.2: type = converted %int.make_type_32.loc18_21, %.loc18_20.1 [template = i32] // CHECK:STDOUT: %Wrap.loc18: type = class_type @Wrap, @Wrap(i32) [template = constants.%Wrap.3] -// CHECK:STDOUT: %.loc18_25: %Make.type.2 = specific_constant @Wrap.%Make.decl, @Wrap(i32) [template = constants.%Make.2] -// CHECK:STDOUT: %Make.ref.loc18: %Make.type.2 = name_ref Make, %.loc18_25 [template = constants.%Make.2] -// CHECK:STDOUT: %Make.call.loc18: init i32 = call %Make.ref.loc18() +// CHECK:STDOUT: %.loc18_25.1: %Make.type.2 = specific_constant @Wrap.%Make.decl, @Wrap(i32) [template = constants.%Make.2] +// CHECK:STDOUT: %Make.ref.loc18: %Make.type.2 = name_ref Make, %.loc18_25.1 [template = constants.%Make.2] +// CHECK:STDOUT: %.loc18_25.2: = specific_function %Make.ref.loc18, @Make(i32) [template = constants.%.12] +// CHECK:STDOUT: %Make.call.loc18: init i32 = call %.loc18_25.2() // CHECK:STDOUT: assign %a.var, %Make.call.loc18 // CHECK:STDOUT: %.loc19_11.1: %.1 = tuple_literal () // CHECK:STDOUT: %.loc19_11.2: type = converted %.loc19_11.1, constants.%.1 [template = constants.%.1] @@ -156,9 +175,10 @@ fn G() { // CHECK:STDOUT: %.loc19_21: %.1 = tuple_literal () // CHECK:STDOUT: %.loc19_19: type = converted %.loc19_21, constants.%.1 [template = constants.%.1] // CHECK:STDOUT: %Wrap.loc19: type = class_type @Wrap, @Wrap(constants.%.1) [template = constants.%Wrap.4] -// CHECK:STDOUT: %.loc19_23: %Make.type.3 = specific_constant @Wrap.%Make.decl, @Wrap(constants.%.1) [template = constants.%Make.3] -// CHECK:STDOUT: %Make.ref.loc19: %Make.type.3 = name_ref Make, %.loc19_23 [template = constants.%Make.3] -// CHECK:STDOUT: %Make.call.loc19: init %.1 = call %Make.ref.loc19() +// CHECK:STDOUT: %.loc19_23.1: %Make.type.3 = specific_constant @Wrap.%Make.decl, @Wrap(constants.%.1) [template = constants.%Make.3] +// CHECK:STDOUT: %Make.ref.loc19: %Make.type.3 = name_ref Make, %.loc19_23.1 [template = constants.%Make.3] +// CHECK:STDOUT: %.loc19_23.2: = specific_function %Make.ref.loc19, @Make(constants.%.1) [template = constants.%.13] +// CHECK:STDOUT: %Make.call.loc19: init %.1 = call %.loc19_23.2() // CHECK:STDOUT: assign %b.var, %Make.call.loc19 // CHECK:STDOUT: %C.ref.loc20_10: type = name_ref C, file.%C.decl [template = constants.%C] // CHECK:STDOUT: %c.var: ref %C = var c @@ -166,26 +186,44 @@ fn G() { // CHECK:STDOUT: %Wrap.ref.loc20: %Wrap.type = name_ref Wrap, file.%Wrap.decl [template = constants.%Wrap.1] // CHECK:STDOUT: %C.ref.loc20_19: type = name_ref C, file.%C.decl [template = constants.%C] // CHECK:STDOUT: %Wrap.loc20: type = class_type @Wrap, @Wrap(constants.%C) [template = constants.%Wrap.5] -// CHECK:STDOUT: %.loc20_21: %Make.type.4 = specific_constant @Wrap.%Make.decl, @Wrap(constants.%C) [template = constants.%Make.4] -// CHECK:STDOUT: %Make.ref.loc20: %Make.type.4 = name_ref Make, %.loc20_21 [template = constants.%Make.4] +// CHECK:STDOUT: %.loc20_21.1: %Make.type.4 = specific_constant @Wrap.%Make.decl, @Wrap(constants.%C) [template = constants.%Make.4] +// CHECK:STDOUT: %Make.ref.loc20: %Make.type.4 = name_ref Make, %.loc20_21.1 [template = constants.%Make.4] +// CHECK:STDOUT: %.loc20_21.2: = specific_function %Make.ref.loc20, @Make(constants.%C) [template = constants.%.16] // CHECK:STDOUT: %.loc20_7: ref %C = splice_block %c.var {} -// CHECK:STDOUT: %Make.call.loc20: init %C = call %Make.ref.loc20() to %.loc20_7 +// CHECK:STDOUT: %Make.call.loc20: init %C = call %.loc20_21.2() to %.loc20_7 // CHECK:STDOUT: assign %c.var, %Make.call.loc20 // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Wrap(constants.%T) { // CHECK:STDOUT: %T.loc11_12.2 => constants.%T +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %Make.type => constants.%Make.type.1 +// CHECK:STDOUT: %Make => constants.%Make.1 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Make(constants.%T) { // CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %Make.type => constants.%Make.type.1 +// CHECK:STDOUT: %Make => constants.%Make.1 +// CHECK:STDOUT: %.loc12_27.3 => constants.%.4 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Wrap(@Wrap.%T.loc11_12.2) { // CHECK:STDOUT: %T.loc11_12.2 => constants.%T // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Wrap(@Make.%T) { +// CHECK:STDOUT: %T.loc11_12.2 => constants.%T +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Make(@Make.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: specific @Wrap(i32) { // CHECK:STDOUT: %T.loc11_12.2 => i32 // CHECK:STDOUT: @@ -196,6 +234,11 @@ fn G() { // CHECK:STDOUT: // CHECK:STDOUT: specific @Make(i32) { // CHECK:STDOUT: %T => i32 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %Make.type => constants.%Make.type.2 +// CHECK:STDOUT: %Make => constants.%Make.2 +// CHECK:STDOUT: %.loc12_27.3 => constants.%.12 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Wrap(constants.%.1) { @@ -208,6 +251,11 @@ fn G() { // CHECK:STDOUT: // CHECK:STDOUT: specific @Make(constants.%.1) { // CHECK:STDOUT: %T => constants.%.1 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %Make.type => constants.%Make.type.3 +// CHECK:STDOUT: %Make => constants.%Make.3 +// CHECK:STDOUT: %.loc12_27.3 => constants.%.13 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Wrap(constants.%C) { @@ -220,5 +268,10 @@ fn G() { // CHECK:STDOUT: // CHECK:STDOUT: specific @Make(constants.%C) { // CHECK:STDOUT: %T => constants.%C +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %Make.type => constants.%Make.type.4 +// CHECK:STDOUT: %Make => constants.%Make.4 +// CHECK:STDOUT: %.loc12_27.3 => constants.%.16 // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/generic/undefined.carbon b/toolchain/check/testdata/function/generic/undefined.carbon new file mode 100644 index 000000000000..b8d13c6ecd00 --- /dev/null +++ b/toolchain/check/testdata/function/generic/undefined.carbon @@ -0,0 +1,332 @@ +// 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 +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/function/generic/undefined.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/function/generic/undefined.carbon + +// --- call_defined.carbon + +library "[[@TEST_NAME]]"; + +fn Defined[T:! type](x: T) -> T { + return x; +} + +fn CallDefined() -> i32 { + return Defined(0); +} + +// --- call_defined_late.carbon + +library "[[@TEST_NAME]]"; + +fn Defined[T:! type](x: T) -> T; + +fn CallDefined() -> i32 { + return Defined(0); +} + +fn Defined[T:! type](x: T) -> T { + return x; +} + +// --- fail_call_undefined.carbon + +library "[[@TEST_NAME]]"; + +fn Undefined[T:! type](x: T) -> T; + +fn CallUndefined() -> i32 { + // CHECK:STDERR: fail_call_undefined.carbon:[[@LINE+6]]:10: error: use of undefined generic function + // CHECK:STDERR: return Undefined(0); + // CHECK:STDERR: ^~~~~~~~~ + // CHECK:STDERR: fail_call_undefined.carbon:[[@LINE-6]]:1: note: generic function declared here + // CHECK:STDERR: fn Undefined[T:! type](x: T) -> T; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + return Undefined(0); +} + +// CHECK:STDOUT: --- call_defined.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic] +// CHECK:STDOUT: %Defined.type: type = fn_type @Defined [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %Defined: %Defined.type = struct_value () [template] +// CHECK:STDOUT: %Int32.type: type = fn_type @Int32 [template] +// CHECK:STDOUT: %Int32: %Int32.type = struct_value () [template] +// CHECK:STDOUT: %CallDefined.type: type = fn_type @CallDefined [template] +// CHECK:STDOUT: %CallDefined: %CallDefined.type = struct_value () [template] +// CHECK:STDOUT: %.2: i32 = int_literal 0 [template] +// CHECK:STDOUT: %.3: = specific_function %Defined, @Defined(i32) [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { +// CHECK:STDOUT: .Int32 = %import_ref +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/operators +// CHECK:STDOUT: import Core//prelude/types +// CHECK:STDOUT: import Core//prelude/operators/arithmetic +// CHECK:STDOUT: import Core//prelude/operators/as +// CHECK:STDOUT: import Core//prelude/operators/bitwise +// CHECK:STDOUT: import Core//prelude/operators/comparison +// CHECK:STDOUT: import Core//prelude/types/bool +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref: %Int32.type = import_ref Core//prelude/types, inst+4, loaded [template = constants.%Int32] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .Defined = %Defined.decl +// CHECK:STDOUT: .CallDefined = %CallDefined.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %Defined.decl: %Defined.type = fn_decl @Defined [template = constants.%Defined] { +// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 +// CHECK:STDOUT: %x.patt: @Defined.%T.loc4_12.2 (%T) = binding_pattern x +// CHECK:STDOUT: } { +// CHECK:STDOUT: %T.param: type = param T, runtime_param +// CHECK:STDOUT: %T.loc4_12.1: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc4_12.2 (constants.%T)] +// CHECK:STDOUT: %T.ref.loc4_25: type = name_ref T, %T.loc4_12.1 [symbolic = %T.loc4_12.2 (constants.%T)] +// CHECK:STDOUT: %x.param: @Defined.%T.loc4_12.2 (%T) = param x, runtime_param0 +// CHECK:STDOUT: %x: @Defined.%T.loc4_12.2 (%T) = bind_name x, %x.param +// CHECK:STDOUT: %T.ref.loc4_31: type = name_ref T, %T.loc4_12.1 [symbolic = %T.loc4_12.2 (constants.%T)] +// CHECK:STDOUT: %return: ref @Defined.%T.loc4_12.2 (%T) = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %CallDefined.decl: %CallDefined.type = fn_decl @CallDefined [template = constants.%CallDefined] {} { +// CHECK:STDOUT: %int.make_type_32: init type = call constants.%Int32() [template = i32] +// CHECK:STDOUT: %.loc8_21.1: type = value_of_initializer %int.make_type_32 [template = i32] +// CHECK:STDOUT: %.loc8_21.2: type = converted %int.make_type_32, %.loc8_21.1 [template = i32] +// CHECK:STDOUT: %return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @Defined(%T.loc4_12.1: type) { +// CHECK:STDOUT: %T.loc4_12.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc4_12.2 (constants.%T)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%T.loc4_12.1: type](%x: @Defined.%T.loc4_12.2 (%T)) -> @Defined.%T.loc4_12.2 (%T) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %x.ref: @Defined.%T.loc4_12.2 (%T) = name_ref x, %x +// CHECK:STDOUT: return %x.ref +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @CallDefined() -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Defined.ref: %Defined.type = name_ref Defined, file.%Defined.decl [template = constants.%Defined] +// CHECK:STDOUT: %.loc9_18: i32 = int_literal 0 [template = constants.%.2] +// CHECK:STDOUT: %.loc9_10: = specific_function %Defined.ref, @Defined(i32) [template = constants.%.3] +// CHECK:STDOUT: %Defined.call: init i32 = call %.loc9_10(%.loc9_18) +// CHECK:STDOUT: %.loc9_20.1: i32 = value_of_initializer %Defined.call +// CHECK:STDOUT: %.loc9_20.2: i32 = converted %Defined.call, %.loc9_20.1 +// CHECK:STDOUT: return %.loc9_20.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Defined(constants.%T) { +// CHECK:STDOUT: %T.loc4_12.2 => constants.%T +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Defined(i32) { +// CHECK:STDOUT: %T.loc4_12.2 => i32 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- call_defined_late.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic] +// CHECK:STDOUT: %Defined.type: type = fn_type @Defined [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %Defined: %Defined.type = struct_value () [template] +// CHECK:STDOUT: %Int32.type: type = fn_type @Int32 [template] +// CHECK:STDOUT: %Int32: %Int32.type = struct_value () [template] +// CHECK:STDOUT: %CallDefined.type: type = fn_type @CallDefined [template] +// CHECK:STDOUT: %CallDefined: %CallDefined.type = struct_value () [template] +// CHECK:STDOUT: %.2: i32 = int_literal 0 [template] +// CHECK:STDOUT: %.3: = specific_function %Defined, @Defined(i32) [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { +// CHECK:STDOUT: .Int32 = %import_ref +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/operators +// CHECK:STDOUT: import Core//prelude/types +// CHECK:STDOUT: import Core//prelude/operators/arithmetic +// CHECK:STDOUT: import Core//prelude/operators/as +// CHECK:STDOUT: import Core//prelude/operators/bitwise +// CHECK:STDOUT: import Core//prelude/operators/comparison +// CHECK:STDOUT: import Core//prelude/types/bool +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref: %Int32.type = import_ref Core//prelude/types, inst+4, loaded [template = constants.%Int32] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .Defined = %Defined.decl.loc4 +// CHECK:STDOUT: .CallDefined = %CallDefined.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %Defined.decl.loc4: %Defined.type = fn_decl @Defined [template = constants.%Defined] { +// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 +// CHECK:STDOUT: %x.patt: %T = binding_pattern x +// CHECK:STDOUT: } { +// CHECK:STDOUT: %T.param.loc4: type = param T, runtime_param +// CHECK:STDOUT: %T.loc4_12.1: type = bind_symbolic_name T, 0, %T.param.loc4 [symbolic = %T.loc4_12.2 (constants.%T)] +// CHECK:STDOUT: %T.ref.loc4_25: type = name_ref T, %T.loc4_12.1 [symbolic = %T.loc4_12.2 (constants.%T)] +// CHECK:STDOUT: %x.param.loc4: @Defined.%T.loc4_12.2 (%T) = param x, runtime_param0 +// CHECK:STDOUT: %x.loc4: @Defined.%T.loc4_12.2 (%T) = bind_name x, %x.param.loc4 +// CHECK:STDOUT: %T.ref.loc4_31: type = name_ref T, %T.loc4_12.1 [symbolic = %T.loc4_12.2 (constants.%T)] +// CHECK:STDOUT: %return.var.loc4: ref @Defined.%T.loc4_12.2 (%T) = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %CallDefined.decl: %CallDefined.type = fn_decl @CallDefined [template = constants.%CallDefined] {} { +// CHECK:STDOUT: %int.make_type_32: init type = call constants.%Int32() [template = i32] +// CHECK:STDOUT: %.loc6_21.1: type = value_of_initializer %int.make_type_32 [template = i32] +// CHECK:STDOUT: %.loc6_21.2: type = converted %int.make_type_32, %.loc6_21.1 [template = i32] +// CHECK:STDOUT: %return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Defined.decl.loc10: %Defined.type = fn_decl @Defined [template = constants.%Defined] { +// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 +// CHECK:STDOUT: %x.patt: %T = binding_pattern x +// CHECK:STDOUT: } { +// CHECK:STDOUT: %T.param.loc10: type = param T, runtime_param +// CHECK:STDOUT: %T.loc10: type = bind_symbolic_name T, 0, %T.param.loc10 [symbolic = constants.%T] +// CHECK:STDOUT: %T.ref.loc10_25: type = name_ref T, %T.loc10 [symbolic = constants.%T] +// CHECK:STDOUT: %x.param.loc10: %T = param x, runtime_param0 +// CHECK:STDOUT: %x.loc10: %T = bind_name x, %x.param.loc10 +// CHECK:STDOUT: %T.ref.loc10_31: type = name_ref T, %T.loc10 [symbolic = constants.%T] +// CHECK:STDOUT: %return: ref %T = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @Defined(%T.loc4_12.1: type) { +// CHECK:STDOUT: %T.loc4_12.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc4_12.2 (constants.%T)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%T.loc10: type](%x.loc10: %T) -> %T { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %x.ref: @Defined.%T.loc4_12.2 (%T) = name_ref x, %x.loc10 +// CHECK:STDOUT: return %x.ref +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @CallDefined() -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Defined.ref: %Defined.type = name_ref Defined, file.%Defined.decl.loc4 [template = constants.%Defined] +// CHECK:STDOUT: %.loc7_18: i32 = int_literal 0 [template = constants.%.2] +// CHECK:STDOUT: %.loc7_10: = specific_function %Defined.ref, @Defined(i32) [template = constants.%.3] +// CHECK:STDOUT: %Defined.call: init i32 = call %.loc7_10(%.loc7_18) +// CHECK:STDOUT: %.loc7_20.1: i32 = value_of_initializer %Defined.call +// CHECK:STDOUT: %.loc7_20.2: i32 = converted %Defined.call, %.loc7_20.1 +// CHECK:STDOUT: return %.loc7_20.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Defined(constants.%T) { +// CHECK:STDOUT: %T.loc4_12.2 => constants.%T +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Defined(i32) { +// CHECK:STDOUT: %T.loc4_12.2 => i32 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_call_undefined.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic] +// CHECK:STDOUT: %Undefined.type: type = fn_type @Undefined [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %Undefined: %Undefined.type = struct_value () [template] +// CHECK:STDOUT: %Int32.type: type = fn_type @Int32 [template] +// CHECK:STDOUT: %Int32: %Int32.type = struct_value () [template] +// CHECK:STDOUT: %CallUndefined.type: type = fn_type @CallUndefined [template] +// CHECK:STDOUT: %CallUndefined: %CallUndefined.type = struct_value () [template] +// CHECK:STDOUT: %.2: i32 = int_literal 0 [template] +// CHECK:STDOUT: %.3: = specific_function %Undefined, @Undefined(i32) [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { +// CHECK:STDOUT: .Int32 = %import_ref +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/operators +// CHECK:STDOUT: import Core//prelude/types +// CHECK:STDOUT: import Core//prelude/operators/arithmetic +// CHECK:STDOUT: import Core//prelude/operators/as +// CHECK:STDOUT: import Core//prelude/operators/bitwise +// CHECK:STDOUT: import Core//prelude/operators/comparison +// CHECK:STDOUT: import Core//prelude/types/bool +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref: %Int32.type = import_ref Core//prelude/types, inst+4, loaded [template = constants.%Int32] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .Undefined = %Undefined.decl +// CHECK:STDOUT: .CallUndefined = %CallUndefined.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %Undefined.decl: %Undefined.type = fn_decl @Undefined [template = constants.%Undefined] { +// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 +// CHECK:STDOUT: %x.patt: @Undefined.%T.loc4_14.2 (%T) = binding_pattern x +// CHECK:STDOUT: } { +// CHECK:STDOUT: %T.param: type = param T, runtime_param +// CHECK:STDOUT: %T.loc4_14.1: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc4_14.2 (constants.%T)] +// CHECK:STDOUT: %T.ref.loc4_27: type = name_ref T, %T.loc4_14.1 [symbolic = %T.loc4_14.2 (constants.%T)] +// CHECK:STDOUT: %x.param: @Undefined.%T.loc4_14.2 (%T) = param x, runtime_param0 +// CHECK:STDOUT: %x: @Undefined.%T.loc4_14.2 (%T) = bind_name x, %x.param +// CHECK:STDOUT: %T.ref.loc4_33: type = name_ref T, %T.loc4_14.1 [symbolic = %T.loc4_14.2 (constants.%T)] +// CHECK:STDOUT: %return: ref @Undefined.%T.loc4_14.2 (%T) = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %CallUndefined.decl: %CallUndefined.type = fn_decl @CallUndefined [template = constants.%CallUndefined] {} { +// CHECK:STDOUT: %int.make_type_32: init type = call constants.%Int32() [template = i32] +// CHECK:STDOUT: %.loc6_23.1: type = value_of_initializer %int.make_type_32 [template = i32] +// CHECK:STDOUT: %.loc6_23.2: type = converted %int.make_type_32, %.loc6_23.1 [template = i32] +// CHECK:STDOUT: %return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @Undefined(%T.loc4_14.1: type) { +// CHECK:STDOUT: %T.loc4_14.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc4_14.2 (constants.%T)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%T.loc4_14.1: type](%x: @Undefined.%T.loc4_14.2 (%T)) -> @Undefined.%T.loc4_14.2 (%T); +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @CallUndefined() -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Undefined.ref: %Undefined.type = name_ref Undefined, file.%Undefined.decl [template = constants.%Undefined] +// CHECK:STDOUT: %.loc13_20: i32 = int_literal 0 [template = constants.%.2] +// CHECK:STDOUT: %.loc13_10: = specific_function %Undefined.ref, @Undefined(i32) [template = constants.%.3] +// CHECK:STDOUT: %Undefined.call: init i32 = call %.loc13_10(%.loc13_20) +// CHECK:STDOUT: %.loc13_22.1: i32 = value_of_initializer %Undefined.call +// CHECK:STDOUT: %.loc13_22.2: i32 = converted %Undefined.call, %.loc13_22.1 +// CHECK:STDOUT: return %.loc13_22.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Undefined(constants.%T) { +// CHECK:STDOUT: %T.loc4_14.2 => constants.%T +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Undefined(i32) { +// CHECK:STDOUT: %T.loc4_14.2 => i32 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/impl/lookup/generic.carbon b/toolchain/check/testdata/impl/lookup/generic.carbon index d1aa8cb04fc9..ad7110b91cd4 100644 --- a/toolchain/check/testdata/impl/lookup/generic.carbon +++ b/toolchain/check/testdata/impl/lookup/generic.carbon @@ -141,6 +141,7 @@ fn G(x: A) { // CHECK:STDOUT: %F.type.3: type = fn_type @F.2, @impl(%.5) [template] // CHECK:STDOUT: %F.3: %F.type.3 = struct_value () [template] // CHECK:STDOUT: %.6: = interface_witness (%F.3) [template] +// CHECK:STDOUT: %.7: = specific_function %F.3, @F.2(%.5) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -230,8 +231,9 @@ fn G(x: A) { // CHECK:STDOUT: %x.ref: %.5 = name_ref x, %x // CHECK:STDOUT: %HasF.ref: type = name_ref HasF, file.%HasF.decl [template = constants.%HasF.type] // CHECK:STDOUT: %F.ref: %.2 = name_ref F, @HasF.%.loc5 [template = constants.%.3] -// CHECK:STDOUT: %.loc13: %F.type.1 = interface_witness_access constants.%.6, element0 [template = constants.%F.3] -// CHECK:STDOUT: %F.call: init %.1 = call %.loc13() +// CHECK:STDOUT: %.loc13_4.1: %F.type.1 = interface_witness_access constants.%.6, element0 [template = constants.%F.3] +// CHECK:STDOUT: %.loc13_4.2: = specific_function %.loc13_4.1, @F.2(constants.%.5) [template = constants.%.7] +// CHECK:STDOUT: %F.call: init %.1 = call %.loc13_4.2() // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: @@ -263,7 +265,9 @@ fn G(x: A) { // CHECK:STDOUT: %.loc8_34.2 => constants.%.6 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @F.2(constants.%.5) {} +// CHECK:STDOUT: specific @F.2(constants.%.5) { +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- deduced_type_subst.carbon // CHECK:STDOUT: @@ -404,7 +408,8 @@ fn G(x: A) { // CHECK:STDOUT: %F.ref: %.2 = name_ref F, @HasF.%.loc5 [template = constants.%.3] // CHECK:STDOUT: %.loc13_11.1: %F.type.1 = interface_witness_access constants.%.6, element0 [template = constants.%F.3] // CHECK:STDOUT: %.loc13_11.2: = bound_method %x.ref, %.loc13_11.1 -// CHECK:STDOUT: %F.call: init %.5 = call %.loc13_11.2(%x.ref) +// CHECK:STDOUT: %.loc13_11.3: = specific_function %.loc13_11.2, @F.2(constants.%.5) +// CHECK:STDOUT: %F.call: init %.5 = call %.loc13_11.3(%x.ref) // CHECK:STDOUT: %.loc13_20.1: ref %.5 = temporary_storage // CHECK:STDOUT: %.loc13_20.2: ref %.5 = temporary %.loc13_20.1, %F.call // CHECK:STDOUT: %struct: %.5 = struct_value () [template = constants.%struct] @@ -448,6 +453,8 @@ fn G(x: A) { // CHECK:STDOUT: // CHECK:STDOUT: specific @F.2(constants.%.5) { // CHECK:STDOUT: %T => constants.%.5 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- deduced_type_argument.carbon @@ -476,6 +483,7 @@ fn G(x: A) { // CHECK:STDOUT: %F.type.3: type = fn_type @F.2, @impl(%.4) [template] // CHECK:STDOUT: %F.3: %F.type.3 = struct_value () [template] // CHECK:STDOUT: %.8: = interface_witness (%F.3) [template] +// CHECK:STDOUT: %.9: = specific_function %F.3, @F.2(%.4) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -590,8 +598,9 @@ fn G(x: A) { // CHECK:STDOUT: %x.ref: %C.3 = name_ref x, %x // CHECK:STDOUT: %HasF.ref: type = name_ref HasF, file.%HasF.decl [template = constants.%HasF.type] // CHECK:STDOUT: %F.ref: %.2 = name_ref F, @HasF.%.loc5 [template = constants.%.3] -// CHECK:STDOUT: %.loc15: %F.type.1 = interface_witness_access constants.%.8, element0 [template = constants.%F.3] -// CHECK:STDOUT: %F.call: init %.1 = call %.loc15() +// CHECK:STDOUT: %.loc15_4.1: %F.type.1 = interface_witness_access constants.%.8, element0 [template = constants.%F.3] +// CHECK:STDOUT: %.loc15_4.2: = specific_function %.loc15_4.1, @F.2(constants.%.4) [template = constants.%.9] +// CHECK:STDOUT: %F.call: init %.1 = call %.loc15_4.2() // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: @@ -640,7 +649,9 @@ fn G(x: A) { // CHECK:STDOUT: %.loc10_37.2 => constants.%.8 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @F.2(constants.%.4) {} +// CHECK:STDOUT: specific @F.2(constants.%.4) { +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- deduced_interface_argument.carbon // CHECK:STDOUT: @@ -669,6 +680,7 @@ fn G(x: A) { // CHECK:STDOUT: %F.type.4: type = fn_type @F.2, @impl(%.4) [template] // CHECK:STDOUT: %F.4: %F.type.4 = struct_value () [template] // CHECK:STDOUT: %.8: = interface_witness (%F.4) [template] +// CHECK:STDOUT: %.9: = specific_function %F.4, @F.2(%.4) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -783,8 +795,9 @@ fn G(x: A) { // CHECK:STDOUT: %HasF.type: type = interface_type @HasF, @HasF(constants.%.4) [template = constants.%HasF.type.3] // CHECK:STDOUT: %.loc13_14: %.6 = specific_constant @HasF.%.loc5_9.1, @HasF(constants.%.4) [template = constants.%.7] // CHECK:STDOUT: %F.ref: %.6 = name_ref F, %.loc13_14 [template = constants.%.7] -// CHECK:STDOUT: %.loc13_4: %F.type.3 = interface_witness_access constants.%.8, element0 [template = constants.%F.4] -// CHECK:STDOUT: %F.call: init %.1 = call %.loc13_4() +// CHECK:STDOUT: %.loc13_4.1: %F.type.3 = interface_witness_access constants.%.8, element0 [template = constants.%F.4] +// CHECK:STDOUT: %.loc13_4.2: = specific_function %.loc13_4.1, @F.2(constants.%.4) [template = constants.%.9] +// CHECK:STDOUT: %F.call: init %.1 = call %.loc13_4.2() // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: @@ -851,7 +864,9 @@ fn G(x: A) { // CHECK:STDOUT: %.loc8_38.2 => constants.%.8 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @F.2(constants.%.4) {} +// CHECK:STDOUT: specific @F.2(constants.%.4) { +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_incomplete_deduction.carbon // CHECK:STDOUT: diff --git a/toolchain/check/testdata/impl/lookup/no_prelude/impl_forall.carbon b/toolchain/check/testdata/impl/lookup/no_prelude/impl_forall.carbon index e909a1ae9836..e6a16057b2d0 100644 --- a/toolchain/check/testdata/impl/lookup/no_prelude/impl_forall.carbon +++ b/toolchain/check/testdata/impl/lookup/no_prelude/impl_forall.carbon @@ -291,7 +291,8 @@ fn TestSpecific(a: A({})) -> {} { // CHECK:STDOUT: %F.ref: @TestGeneric.%.loc17_17.2 (%.18) = name_ref F, %.loc17_17.1 [symbolic = %.loc17_17.3 (constants.%.19)] // CHECK:STDOUT: %.loc17_11.1: @TestGeneric.%F.type.loc17_17 (%F.type.4) = interface_witness_access constants.%.20, element0 [symbolic = %F (constants.%F.5)] // CHECK:STDOUT: %.loc17_11.2: = bound_method %a.ref, %.loc17_11.1 -// CHECK:STDOUT: %F.call: init @TestGeneric.%W.loc16_16.2 (%W) = call %.loc17_11.2(%a.ref) +// CHECK:STDOUT: %.loc17_11.3: = specific_function %.loc17_11.2, @F.2(constants.%W) +// CHECK:STDOUT: %F.call: init @TestGeneric.%W.loc16_16.2 (%W) = call %.loc17_11.3(%a.ref) // CHECK:STDOUT: %.loc17_22.1: @TestGeneric.%W.loc16_16.2 (%W) = value_of_initializer %F.call // CHECK:STDOUT: %.loc17_22.2: @TestGeneric.%W.loc16_16.2 (%W) = converted %F.call, %.loc17_22.1 // CHECK:STDOUT: return %.loc17_22.2 @@ -309,7 +310,8 @@ fn TestSpecific(a: A({})) -> {} { // CHECK:STDOUT: %F.ref: %.27 = name_ref F, %.loc21_18 [template = constants.%.28] // CHECK:STDOUT: %.loc21_11.1: %F.type.6 = interface_witness_access constants.%.29, element0 [template = constants.%F.7] // CHECK:STDOUT: %.loc21_11.2: = bound_method %a.ref, %.loc21_11.1 -// CHECK:STDOUT: %F.call: init %.21 = call %.loc21_11.2(%a.ref) +// CHECK:STDOUT: %.loc21_11.3: = specific_function %.loc21_11.2, @F.2(constants.%.21) +// CHECK:STDOUT: %F.call: init %.21 = call %.loc21_11.3(%a.ref) // CHECK:STDOUT: %.loc21_21.1: ref %.21 = temporary_storage // CHECK:STDOUT: %.loc21_21.2: ref %.21 = temporary %.loc21_21.1, %F.call // CHECK:STDOUT: %struct: %.21 = struct_value () [template = constants.%struct] @@ -450,6 +452,9 @@ fn TestSpecific(a: A({})) -> {} { // CHECK:STDOUT: specific @F.2(constants.%W) { // CHECK:STDOUT: %V => constants.%W // CHECK:STDOUT: %A => constants.%A.4 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc12_16.3 => constants.%.14 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @I(@TestGeneric.%W.loc16_16.2) { @@ -498,5 +503,8 @@ fn TestSpecific(a: A({})) -> {} { // CHECK:STDOUT: specific @F.2(constants.%.21) { // CHECK:STDOUT: %V => constants.%.21 // CHECK:STDOUT: %A => constants.%A.5 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc12_16.3 => constants.%.22 // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/no_prelude/assoc_const_in_generic.carbon b/toolchain/check/testdata/interface/no_prelude/assoc_const_in_generic.carbon index c87380911dc7..8df253eb9378 100644 --- a/toolchain/check/testdata/interface/no_prelude/assoc_const_in_generic.carbon +++ b/toolchain/check/testdata/interface/no_prelude/assoc_const_in_generic.carbon @@ -33,15 +33,20 @@ fn H() { // CHECK:STDOUT: %I.type.2: type = interface_type @I, @I(%T) [symbolic] // CHECK:STDOUT: %Self: %I.type.2 = bind_symbolic_name Self, 1 [symbolic] // CHECK:STDOUT: %U: type = bind_symbolic_name U, 2 [symbolic] -// CHECK:STDOUT: %F.type: type = fn_type @F, @I(%T) [symbolic] -// CHECK:STDOUT: %F: %F.type = struct_value () [symbolic] -// CHECK:STDOUT: %.2: type = assoc_entity_type %I.type.2, %F.type [symbolic] +// CHECK:STDOUT: %F.type.1: type = fn_type @F, @I(%T) [symbolic] +// CHECK:STDOUT: %F: %F.type.1 = struct_value () [symbolic] +// CHECK:STDOUT: %.2: type = assoc_entity_type %I.type.2, %F.type.1 [symbolic] // CHECK:STDOUT: %.3: %.2 = assoc_entity element0, @I.%F.decl [symbolic] // CHECK:STDOUT: %G.type: type = fn_type @G [template] // CHECK:STDOUT: %G: %G.type = struct_value () [template] // CHECK:STDOUT: %H.type: type = fn_type @H [template] // CHECK:STDOUT: %H: %H.type = struct_value () [template] // CHECK:STDOUT: %.4: type = struct_type {} [template] +// CHECK:STDOUT: %.5: = specific_function %G, @G(%.4) [template] +// CHECK:STDOUT: %I.type.3: type = interface_type @I, @I(%.4) [template] +// CHECK:STDOUT: %F.type.2: type = fn_type @F, @I(%.4) [template] +// CHECK:STDOUT: %.6: type = assoc_entity_type %I.type.3, %F.type.2 [template] +// CHECK:STDOUT: %.7: %.6 = assoc_entity element0, @I.%F.decl [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -71,14 +76,14 @@ fn H() { // CHECK:STDOUT: !definition: // CHECK:STDOUT: %I.type: type = interface_type @I, @I(%T.loc11_13.2) [symbolic = %I.type (constants.%I.type.2)] // CHECK:STDOUT: %Self.2: %I.type.2 = bind_symbolic_name Self, 1 [symbolic = %Self.2 (constants.%Self)] -// CHECK:STDOUT: %F.type: type = fn_type @F, @I(%T.loc11_13.2) [symbolic = %F.type (constants.%F.type)] -// CHECK:STDOUT: %F: @I.%F.type (%F.type) = struct_value () [symbolic = %F (constants.%F)] -// CHECK:STDOUT: %.loc12_22.2: type = assoc_entity_type @I.%I.type (%I.type.2), @I.%F.type (%F.type) [symbolic = %.loc12_22.2 (constants.%.2)] +// CHECK:STDOUT: %F.type: type = fn_type @F, @I(%T.loc11_13.2) [symbolic = %F.type (constants.%F.type.1)] +// CHECK:STDOUT: %F: @I.%F.type (%F.type.1) = struct_value () [symbolic = %F (constants.%F)] +// CHECK:STDOUT: %.loc12_22.2: type = assoc_entity_type @I.%I.type (%I.type.2), @I.%F.type (%F.type.1) [symbolic = %.loc12_22.2 (constants.%.2)] // CHECK:STDOUT: %.loc12_22.3: @I.%.loc12_22.2 (%.2) = assoc_entity element0, %F.decl [symbolic = %.loc12_22.3 (constants.%.3)] // CHECK:STDOUT: // CHECK:STDOUT: interface { // CHECK:STDOUT: %Self.1: @I.%I.type (%I.type.2) = bind_symbolic_name Self, 1 [symbolic = %Self.2 (constants.%Self)] -// CHECK:STDOUT: %F.decl: @I.%F.type (%F.type) = fn_decl @F [symbolic = @I.%F (constants.%F)] { +// CHECK:STDOUT: %F.decl: @I.%F.type (%F.type.1) = fn_decl @F [symbolic = @I.%F (constants.%F)] { // CHECK:STDOUT: %U.patt: type = symbolic_binding_pattern U, 2 // CHECK:STDOUT: } { // CHECK:STDOUT: %U.param: type = param U, runtime_param @@ -106,8 +111,8 @@ fn H() { // CHECK:STDOUT: // CHECK:STDOUT: !definition: // CHECK:STDOUT: %I.type.loc19_4.2: type = interface_type @I, @I(%T.loc15_6.2) [symbolic = %I.type.loc19_4.2 (constants.%I.type.2)] -// CHECK:STDOUT: %F.type: type = fn_type @F, @I(%T.loc15_6.2) [symbolic = %F.type (constants.%F.type)] -// CHECK:STDOUT: %.loc19_7.2: type = assoc_entity_type @G.%I.type.loc19_4.2 (%I.type.2), @G.%F.type (%F.type) [symbolic = %.loc19_7.2 (constants.%.2)] +// CHECK:STDOUT: %F.type: type = fn_type @F, @I(%T.loc15_6.2) [symbolic = %F.type (constants.%F.type.1)] +// CHECK:STDOUT: %.loc19_7.2: type = assoc_entity_type @G.%I.type.loc19_4.2 (%I.type.2), @G.%F.type (%F.type.1) [symbolic = %.loc19_7.2 (constants.%.2)] // CHECK:STDOUT: %.loc19_7.3: @G.%.loc19_7.2 (%.2) = assoc_entity element0, @I.%F.decl [symbolic = %.loc19_7.3 (constants.%.3)] // CHECK:STDOUT: // CHECK:STDOUT: fn(%T.loc15_6.1: type) { @@ -126,7 +131,8 @@ fn H() { // CHECK:STDOUT: %G.ref: %G.type = name_ref G, file.%G.decl [template = constants.%G] // CHECK:STDOUT: %.loc23_6: %.4 = struct_literal () // CHECK:STDOUT: %.loc23_4: type = converted %.loc23_6, constants.%.4 [template = constants.%.4] -// CHECK:STDOUT: %G.call: init %.1 = call %G.ref() +// CHECK:STDOUT: %.loc23_3: = specific_function %G.ref, @G(constants.%.4) [template = constants.%.5] +// CHECK:STDOUT: %G.call: init %.1 = call %.loc23_3() // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: @@ -136,7 +142,7 @@ fn H() { // CHECK:STDOUT: !definition: // CHECK:STDOUT: %I.type => constants.%I.type.2 // CHECK:STDOUT: %Self.2 => constants.%Self -// CHECK:STDOUT: %F.type => constants.%F.type +// CHECK:STDOUT: %F.type => constants.%F.type.1 // CHECK:STDOUT: %F => constants.%F // CHECK:STDOUT: %.loc12_22.2 => constants.%.2 // CHECK:STDOUT: %.loc12_22.3 => constants.%.3 @@ -160,5 +166,15 @@ fn H() { // CHECK:STDOUT: // CHECK:STDOUT: specific @G(constants.%.4) { // CHECK:STDOUT: %T.loc15_6.2 => constants.%.4 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %I.type.loc19_4.2 => constants.%I.type.3 +// CHECK:STDOUT: %F.type => constants.%F.type.2 +// CHECK:STDOUT: %.loc19_7.2 => constants.%.6 +// CHECK:STDOUT: %.loc19_7.3 => constants.%.7 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @I(constants.%.4) { +// CHECK:STDOUT: %T.loc11_13.2 => constants.%.4 // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/no_prelude/generic.carbon b/toolchain/check/testdata/interface/no_prelude/generic.carbon index db9666aa6e57..c24967ec32cc 100644 --- a/toolchain/check/testdata/interface/no_prelude/generic.carbon +++ b/toolchain/check/testdata/interface/no_prelude/generic.carbon @@ -32,7 +32,7 @@ class C { interface WithImplicitArgs[T:! type](N:! T); -fn Receive(T:! Simple(C)); +fn Receive(T:! Simple(C)) {} fn Pass(T:! Simple(C)) { Receive(T); } @@ -99,6 +99,7 @@ fn G(T:! Generic(B)) { // CHECK:STDOUT: %Receive: %Receive.type = struct_value () [template] // CHECK:STDOUT: %Pass.type: type = fn_type @Pass [template] // CHECK:STDOUT: %Pass: %Pass.type = struct_value () [template] +// CHECK:STDOUT: %.11: = specific_function %Receive, @Receive(%T.2) [symbolic] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -265,19 +266,26 @@ fn G(T:! Generic(B)) { // CHECK:STDOUT: generic fn @Receive(%T.loc24_12.1: %Simple.type.3) { // CHECK:STDOUT: %T.loc24_12.2: %Simple.type.3 = bind_symbolic_name T, 0 [symbolic = %T.loc24_12.2 (constants.%T.2)] // CHECK:STDOUT: -// CHECK:STDOUT: fn(%T.loc24_12.1: %Simple.type.3); +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: fn(%T.loc24_12.1: %Simple.type.3) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic fn @Pass(%T.loc25_9.1: %Simple.type.3) { // CHECK:STDOUT: %T.loc25_9.2: %Simple.type.3 = bind_symbolic_name T, 0 [symbolic = %T.loc25_9.2 (constants.%T.2)] // CHECK:STDOUT: // CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc26_3.2: = specific_function constants.%Receive, @Receive(%T.loc25_9.2) [symbolic = %.loc26_3.2 (constants.%.11)] // CHECK:STDOUT: // CHECK:STDOUT: fn(%T.loc25_9.1: %Simple.type.3) { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Receive.ref: %Receive.type = name_ref Receive, file.%Receive.decl [template = constants.%Receive] // CHECK:STDOUT: %T.ref: %Simple.type.3 = name_ref T, %T.loc25_9.1 [symbolic = %T.loc25_9.2 (constants.%T.2)] -// CHECK:STDOUT: %Receive.call: init %.1 = call %Receive.ref() +// CHECK:STDOUT: %.loc26_3.1: = specific_function %Receive.ref, @Receive(constants.%T.2) [symbolic = %.loc26_3.2 (constants.%.11)] +// CHECK:STDOUT: %Receive.call: init %.1 = call %.loc26_3.1() // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: } @@ -329,12 +337,18 @@ fn G(T:! Generic(B)) { // CHECK:STDOUT: // CHECK:STDOUT: specific @Receive(constants.%T.2) { // CHECK:STDOUT: %T.loc24_12.2 => constants.%T.2 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Pass(constants.%T.2) { // CHECK:STDOUT: %T.loc25_9.2 => constants.%T.2 // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Receive(@Pass.%T.loc25_9.2) { +// CHECK:STDOUT: %T.loc24_12.2 => constants.%T.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: --- fail_mismatched_args.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { diff --git a/toolchain/check/testdata/operators/overloaded/implicit_as.carbon b/toolchain/check/testdata/operators/overloaded/implicit_as.carbon index e2d3430c0347..e71dd99d607f 100644 --- a/toolchain/check/testdata/operators/overloaded/implicit_as.carbon +++ b/toolchain/check/testdata/operators/overloaded/implicit_as.carbon @@ -24,7 +24,7 @@ impl X as Core.ImplicitAs(i32) { // ... once we stop deducing `T` from the type of the second argument in this case. fn Sink_i32(n: i32); fn Sink_X(x: X); -fn Source(T:! type) -> T; +fn Source(T:! type) -> T { return Source(T); } fn Test() { Sink_i32(Source(X)); @@ -75,9 +75,12 @@ fn Test() { // CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic] // CHECK:STDOUT: %Source.type: type = fn_type @Source [template] // CHECK:STDOUT: %Source: %Source.type = struct_value () [template] +// CHECK:STDOUT: %.14: = specific_function %Source, @Source(%T) [symbolic] // CHECK:STDOUT: %Test.type: type = fn_type @Test [template] // CHECK:STDOUT: %Test: %Test.type = struct_value () [template] -// CHECK:STDOUT: %.14: %.5 = assoc_entity element0, imports.%import_ref.7 [symbolic] +// CHECK:STDOUT: %.15: = specific_function %Source, @Source(%X) [template] +// CHECK:STDOUT: %.16: %.5 = assoc_entity element0, imports.%import_ref.7 [symbolic] +// CHECK:STDOUT: %.17: = specific_function %Source, @Source(i32) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -96,7 +99,7 @@ fn Test() { // CHECK:STDOUT: %import_ref.1: %Int32.type = import_ref Core//prelude/types, inst+4, loaded [template = constants.%Int32] // CHECK:STDOUT: %import_ref.2: %ImplicitAs.type.1 = import_ref Core//prelude/operators/as, inst+40, loaded [template = constants.%ImplicitAs] // CHECK:STDOUT: %import_ref.3 = import_ref Core//prelude/operators/as, inst+45, unloaded -// CHECK:STDOUT: %import_ref.4: @ImplicitAs.%.1 (%.5) = import_ref Core//prelude/operators/as, inst+63, loaded [symbolic = @ImplicitAs.%.2 (constants.%.14)] +// CHECK:STDOUT: %import_ref.4: @ImplicitAs.%.1 (%.5) = import_ref Core//prelude/operators/as, inst+63, loaded [symbolic = @ImplicitAs.%.2 (constants.%.16)] // CHECK:STDOUT: %import_ref.5: @ImplicitAs.%Convert.type (%Convert.type.1) = import_ref Core//prelude/operators/as, inst+56, loaded [symbolic = @ImplicitAs.%Convert (constants.%Convert.1)] // CHECK:STDOUT: %import_ref.6 = import_ref Core//prelude/operators/as, inst+56, unloaded // CHECK:STDOUT: %import_ref.7 = import_ref Core//prelude/operators/as, inst+56, unloaded @@ -152,7 +155,7 @@ fn Test() { // CHECK:STDOUT: } { // CHECK:STDOUT: %T.param: type = param T, runtime_param // CHECK:STDOUT: %T.loc27_11.1: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc27_11.2 (constants.%T)] -// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc27_11.1 [symbolic = %T.loc27_11.2 (constants.%T)] +// CHECK:STDOUT: %T.ref.loc27_24: type = name_ref T, %T.loc27_11.1 [symbolic = %T.loc27_11.2 (constants.%T)] // CHECK:STDOUT: %return: ref @Source.%T.loc27_11.2 (%T) = var // CHECK:STDOUT: } // CHECK:STDOUT: %Test.decl: %Test.type = fn_decl @Test [template = constants.%Test] {} {} @@ -264,7 +267,19 @@ fn Test() { // CHECK:STDOUT: generic fn @Source(%T.loc27_11.1: type) { // CHECK:STDOUT: %T.loc27_11.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc27_11.2 (constants.%T)] // CHECK:STDOUT: -// CHECK:STDOUT: fn(%T.loc27_11.1: type) -> @Source.%T.loc27_11.2 (%T); +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc27_35.2: = specific_function constants.%Source, @Source(%T.loc27_11.2) [symbolic = %.loc27_35.2 (constants.%.14)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn(%T.loc27_11.1: type) -> @Source.%T.loc27_11.2 (%T) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Source.ref: %Source.type = name_ref Source, file.%Source.decl [template = constants.%Source] +// CHECK:STDOUT: %T.ref.loc27_42: type = name_ref T, %T.loc27_11.1 [symbolic = %T.loc27_11.2 (constants.%T)] +// CHECK:STDOUT: %.loc27_35.1: = specific_function %Source.ref, @Source(constants.%T) [symbolic = %.loc27_35.2 (constants.%.14)] +// CHECK:STDOUT: %Source.call: init @Source.%T.loc27_11.2 (%T) = call %.loc27_35.1() +// CHECK:STDOUT: %.loc27_44.1: @Source.%T.loc27_11.2 (%T) = value_of_initializer %Source.call +// CHECK:STDOUT: %.loc27_44.2: @Source.%T.loc27_11.2 (%T) = converted %Source.call, %.loc27_44.1 +// CHECK:STDOUT: return %.loc27_44.2 +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Test() { @@ -272,8 +287,9 @@ fn Test() { // CHECK:STDOUT: %Sink_i32.ref: %Sink_i32.type = name_ref Sink_i32, file.%Sink_i32.decl [template = constants.%Sink_i32] // CHECK:STDOUT: %Source.ref.loc30: %Source.type = name_ref Source, file.%Source.decl [template = constants.%Source] // CHECK:STDOUT: %X.ref: type = name_ref X, file.%X.decl [template = constants.%X] +// CHECK:STDOUT: %.loc30_12: = specific_function %Source.ref.loc30, @Source(constants.%X) [template = constants.%.15] // CHECK:STDOUT: %.loc30_18.1: ref %X = temporary_storage -// CHECK:STDOUT: %Source.call.loc30: init %X = call %Source.ref.loc30() to %.loc30_18.1 +// CHECK:STDOUT: %Source.call.loc30: init %X = call %.loc30_12() to %.loc30_18.1 // CHECK:STDOUT: %ImplicitAs.type.loc30: type = interface_type @ImplicitAs, @ImplicitAs(i32) [template = constants.%ImplicitAs.type.4] // CHECK:STDOUT: %.loc30_11.1: %.11 = specific_constant imports.%import_ref.4, @ImplicitAs(i32) [template = constants.%.12] // CHECK:STDOUT: %Convert.ref.loc30: %.11 = name_ref Convert, %.loc30_11.1 [template = constants.%.12] @@ -292,7 +308,8 @@ fn Test() { // CHECK:STDOUT: %int.make_type_32: init type = call constants.%Int32() [template = i32] // CHECK:STDOUT: %.loc31_16.1: type = value_of_initializer %int.make_type_32 [template = i32] // CHECK:STDOUT: %.loc31_16.2: type = converted %int.make_type_32, %.loc31_16.1 [template = i32] -// CHECK:STDOUT: %Source.call.loc31: init i32 = call %Source.ref.loc31() +// CHECK:STDOUT: %.loc31_10: = specific_function %Source.ref.loc31, @Source(i32) [template = constants.%.17] +// CHECK:STDOUT: %Source.call.loc31: init i32 = call %.loc31_10() // CHECK:STDOUT: %ImplicitAs.type.loc31: type = interface_type @ImplicitAs, @ImplicitAs(constants.%X) [template = constants.%ImplicitAs.type.3] // CHECK:STDOUT: %.loc31_9.1: %.7 = specific_constant imports.%import_ref.4, @ImplicitAs(constants.%X) [template = constants.%.8] // CHECK:STDOUT: %Convert.ref.loc31: %.7 = name_ref Convert, %.loc31_9.1 [template = constants.%.8] @@ -366,13 +383,26 @@ fn Test() { // CHECK:STDOUT: // CHECK:STDOUT: specific @Source(constants.%T) { // CHECK:STDOUT: %T.loc27_11.2 => constants.%T +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc27_35.2 => constants.%.14 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Source(@Source.%T.loc27_11.2) { +// CHECK:STDOUT: %T.loc27_11.2 => constants.%T // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Source(constants.%X) { // CHECK:STDOUT: %T.loc27_11.2 => constants.%X +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc27_35.2 => constants.%.15 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Source(i32) { // CHECK:STDOUT: %T.loc27_11.2 => i32 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc27_35.2 => constants.%.17 // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/diagnostics/diagnostic_kind.def b/toolchain/diagnostics/diagnostic_kind.def index 4d8fb15fd3f9..47ed671815a5 100644 --- a/toolchain/diagnostics/diagnostic_kind.def +++ b/toolchain/diagnostics/diagnostic_kind.def @@ -159,6 +159,8 @@ CARBON_DIAGNOSTIC_KIND(RepeatedImport) CARBON_DIAGNOSTIC_KIND(FirstImported) CARBON_DIAGNOSTIC_KIND(ExportFromImpl) CARBON_DIAGNOSTIC_KIND(MissingDefinitionInImpl) +CARBON_DIAGNOSTIC_KIND(MissingGenericFunctionDefinition) +CARBON_DIAGNOSTIC_KIND(MissingGenericFunctionDefinitionHere) // Merge-related redeclaration checking. CARBON_DIAGNOSTIC_KIND(RedeclPrevDecl) diff --git a/toolchain/lower/constant.cpp b/toolchain/lower/constant.cpp index bd28cfc3289a..43694e15d320 100644 --- a/toolchain/lower/constant.cpp +++ b/toolchain/lower/constant.cpp @@ -215,6 +215,11 @@ static auto EmitAsConstant(ConstantContext& context, SemIR::Namespace inst) return context.GetUnusedConstant(inst.type_id); } +static auto EmitAsConstant(ConstantContext& /*context*/, + SemIR::SpecificFunction inst) -> llvm::Constant* { + CARBON_FATAL("TODO: Add support: {0}", inst); +} + static auto EmitAsConstant(ConstantContext& /*context*/, SemIR::StringLiteral inst) -> llvm::Constant* { CARBON_FATAL("TODO: Add support: {0}", inst); diff --git a/toolchain/lower/file_context.cpp b/toolchain/lower/file_context.cpp index 79af16bef963..f6c2320cf3b0 100644 --- a/toolchain/lower/file_context.cpp +++ b/toolchain/lower/file_context.cpp @@ -412,6 +412,7 @@ static auto BuildTypeForInst(FileContext& context, SemIR::BuiltinInst inst) // storage // (`i8`) versus for `bool` values (`i1`). return llvm::Type::getInt1Ty(context.llvm_context()); + case SemIR::BuiltinInstKind::SpecificFunctionType: case SemIR::BuiltinInstKind::StringType: // TODO: Decide how we want to represent `StringType`. return llvm::PointerType::get(context.llvm_context(), 0); diff --git a/toolchain/sem_ir/builtin_inst_kind.def b/toolchain/sem_ir/builtin_inst_kind.def index 2132c8b006fd..caad3419ec41 100644 --- a/toolchain/sem_ir/builtin_inst_kind.def +++ b/toolchain/sem_ir/builtin_inst_kind.def @@ -67,6 +67,9 @@ CARBON_SEM_IR_BUILTIN_INST_KIND(StringType, "String") // The type of bound method values. CARBON_SEM_IR_BUILTIN_INST_KIND(BoundMethodType, "") +// The type of specific functions. +CARBON_SEM_IR_BUILTIN_INST_KIND(SpecificFunctionType, "") + // The type of namespace and imported package names. CARBON_SEM_IR_BUILTIN_INST_KIND(NamespaceType, "") diff --git a/toolchain/sem_ir/file.cpp b/toolchain/sem_ir/file.cpp index a62c4c2f5c7b..7f3ef404aec2 100644 --- a/toolchain/sem_ir/file.cpp +++ b/toolchain/sem_ir/file.cpp @@ -270,6 +270,7 @@ auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory { case IntType::Kind: case Param::Kind: case PointerType::Kind: + case SpecificFunction::Kind: case StringLiteral::Kind: case StructValue::Kind: case StructType::Kind: diff --git a/toolchain/sem_ir/function.cpp b/toolchain/sem_ir/function.cpp index e99a93824f08..9a80ffc2cc2a 100644 --- a/toolchain/sem_ir/function.cpp +++ b/toolchain/sem_ir/function.cpp @@ -12,10 +12,17 @@ namespace Carbon::SemIR { auto GetCalleeFunction(const File& sem_ir, InstId callee_id) -> CalleeFunction { CalleeFunction result = {.function_id = FunctionId::Invalid, - .specific_id = SpecificId::Invalid, + .enclosing_specific_id = SpecificId::Invalid, + .resolved_specific_id = SpecificId::Invalid, .self_id = InstId::Invalid, .is_error = false}; + if (auto specific_function = + sem_ir.insts().TryGetAs(callee_id)) { + result.resolved_specific_id = specific_function->specific_id; + callee_id = specific_function->callee_id; + } + if (auto bound_method = sem_ir.insts().TryGetAs(callee_id)) { result.self_id = bound_method->object_id; callee_id = bound_method->function_id; @@ -38,7 +45,7 @@ auto GetCalleeFunction(const File& sem_ir, InstId callee_id) -> CalleeFunction { } result.function_id = fn_type->function_id; - result.specific_id = fn_type->specific_id; + result.enclosing_specific_id = fn_type->specific_id; return result; } diff --git a/toolchain/sem_ir/function.h b/toolchain/sem_ir/function.h index 5b1f3bb92bb5..34d64affa4d4 100644 --- a/toolchain/sem_ir/function.h +++ b/toolchain/sem_ir/function.h @@ -93,7 +93,9 @@ struct CalleeFunction { // The function. Invalid if not a function. SemIR::FunctionId function_id; // The specific that contains the function. - SemIR::SpecificId specific_id; + SemIR::SpecificId enclosing_specific_id; + // The specific for the callee itself, in a resolved call. + SemIR::SpecificId resolved_specific_id; // The bound `self` parameter. Invalid if not a method. SemIR::InstId self_id; // True if an error instruction was found. diff --git a/toolchain/sem_ir/inst_kind.def b/toolchain/sem_ir/inst_kind.def index e0aa75be79b3..c1a9c022c936 100644 --- a/toolchain/sem_ir/inst_kind.def +++ b/toolchain/sem_ir/inst_kind.def @@ -64,7 +64,6 @@ CARBON_SEM_IR_INST_KIND(ImportDecl) CARBON_SEM_IR_INST_KIND(ImportRefUnloaded) CARBON_SEM_IR_INST_KIND(ImportRefLoaded) CARBON_SEM_IR_INST_KIND(InitializeFrom) -CARBON_SEM_IR_INST_KIND(SpecificConstant) CARBON_SEM_IR_INST_KIND(InterfaceDecl) CARBON_SEM_IR_INST_KIND(InterfaceType) CARBON_SEM_IR_INST_KIND(InterfaceWitness) @@ -80,6 +79,8 @@ CARBON_SEM_IR_INST_KIND(RequirementEquivalent) CARBON_SEM_IR_INST_KIND(RequirementImpls) CARBON_SEM_IR_INST_KIND(ReturnExpr) CARBON_SEM_IR_INST_KIND(Return) +CARBON_SEM_IR_INST_KIND(SpecificConstant) +CARBON_SEM_IR_INST_KIND(SpecificFunction) CARBON_SEM_IR_INST_KIND(SpliceBlock) CARBON_SEM_IR_INST_KIND(StringLiteral) CARBON_SEM_IR_INST_KIND(StructAccess) diff --git a/toolchain/sem_ir/stringify_type.cpp b/toolchain/sem_ir/stringify_type.cpp index 04b042e7dd78..647253cd047c 100644 --- a/toolchain/sem_ir/stringify_type.cpp +++ b/toolchain/sem_ir/stringify_type.cpp @@ -305,6 +305,7 @@ auto StringifyTypeExpr(const SemIR::File& outer_sem_ir, InstId outer_inst_id) case RequirementRewrite::Kind: case Return::Kind: case ReturnExpr::Kind: + case SpecificFunction::Kind: case SpliceBlock::Kind: case StringLiteral::Kind: case StructAccess::Kind: diff --git a/toolchain/sem_ir/typed_insts.h b/toolchain/sem_ir/typed_insts.h index f5288eb92f32..52887a9f8d3d 100644 --- a/toolchain/sem_ir/typed_insts.h +++ b/toolchain/sem_ir/typed_insts.h @@ -910,6 +910,27 @@ struct SpecificConstant { SpecificId specific_id; }; +// A specific instance of a generic function. This represents the callee in a +// call instruction that is calling a generic function, where the specific +// arguments of the function have been deduced. +// +// TODO: This value corresponds to the `(FunctionType as Call(...)).Op` function +// in the overloaded calls design. Eventually we should represent it more +// directly as a member of the `Call` interface. +struct SpecificFunction { + static constexpr auto Kind = InstKind::SpecificFunction.Define( + {.ir_name = "specific_function", + .constant_kind = InstConstantKind::Always}); + + // Always the builtin SpecificFunctionType. + TypeId type_id; + // The expression denoting the callee. + InstId callee_id; + // The specific instance of the generic callee that will be called, including + // all the compile-time arguments. + SpecificId specific_id; +}; + // Splices a block into the location where this appears. This may be an // expression, producing a result with a given type. For example, when // constructing from aggregates we may figure out which conversions are required