diff --git a/toolchain/check/context.cpp b/toolchain/check/context.cpp index 963258af3b29..27bc38751d7c 100644 --- a/toolchain/check/context.cpp +++ b/toolchain/check/context.cpp @@ -633,6 +633,7 @@ auto Context::FinalizeGlobalInit() -> void { {.name_id = SemIR::NameId::ForIdentifier(name_id), .parent_scope_id = SemIR::NameScopeId::Package, .decl_id = SemIR::InstId::Invalid, + .generic_id = SemIR::GenericId::Invalid, .implicit_param_refs_id = SemIR::InstBlockId::Invalid, .param_refs_id = SemIR::InstBlockId::Empty, .return_storage_id = SemIR::InstId::Invalid, diff --git a/toolchain/check/context.h b/toolchain/check/context.h index 6f6637cb8c34..3cd097b58cd9 100644 --- a/toolchain/check/context.h +++ b/toolchain/check/context.h @@ -387,6 +387,9 @@ class Context { return sem_ir().interfaces(); } auto impls() -> SemIR::ImplStore& { return sem_ir().impls(); } + auto generics() -> ValueStore& { + return sem_ir().generics(); + } auto import_irs() -> ValueStore& { return sem_ir().import_irs(); } diff --git a/toolchain/check/handle_binding_pattern.cpp b/toolchain/check/handle_binding_pattern.cpp index 70b2ea13798e..66f6f5be0c25 100644 --- a/toolchain/check/handle_binding_pattern.cpp +++ b/toolchain/check/handle_binding_pattern.cpp @@ -59,6 +59,15 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id, } }; + // Push the binding onto the node stack and, if necessary, onto the scope + // stack. + auto push_bind_name = [&](SemIR::InstId bind_id) { + context.node_stack().Push(node_id, bind_id); + if (is_generic && !is_associated_constant) { + context.scope_stack().PushCompileTimeBinding(bind_id); + } + }; + // A `self` binding can only appear in an implicit parameter list. if (name_id == SemIR::NameId::SelfValue && !context.node_stack().PeekIs()) { @@ -133,7 +142,7 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id, name_node, {.type_id = cast_type_id, .name_id = name_id}); } auto bind_id = context.AddInst(make_bind_name(cast_type_id, value_id)); - context.node_stack().Push(node_id, bind_id); + push_bind_name(bind_id); if (context_node_kind == Parse::NodeKind::ReturnedModifier) { RegisterReturnedVar(context, bind_id); @@ -150,14 +159,14 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id, auto param_id = context.AddInst( name_node, {.type_id = cast_type_id, .name_id = name_id}); auto bind_id = context.AddInst(make_bind_name(cast_type_id, param_id)); + push_bind_name(bind_id); // TODO: Bindings should come into scope immediately in other contexts // too. context.AddNameToLookup(name_id, bind_id); - context.node_stack().Push(node_id, bind_id); break; } - case Parse::NodeKind::LetIntroducer: + case Parse::NodeKind::LetIntroducer: { cast_type_id = context.AsCompleteType(cast_type_id, [&] { CARBON_DIAGNOSTIC(IncompleteTypeInLetDecl, Error, "`let` binding has incomplete type `{0}`.", @@ -169,10 +178,11 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id, // formed its initializer. // TODO: For general pattern parsing, we'll need to create a block to hold // the `let` pattern before we see the initializer. - context.node_stack().Push( - node_id, context.AddPlaceholderInstInNoBlock( - make_bind_name(cast_type_id, SemIR::InstId::Invalid))); + auto bind_id = context.AddPlaceholderInstInNoBlock( + make_bind_name(cast_type_id, SemIR::InstId::Invalid)); + push_bind_name(bind_id); break; + } default: CARBON_FATAL() << "Found a pattern binding in unexpected context " diff --git a/toolchain/check/handle_function.cpp b/toolchain/check/handle_function.cpp index e9e072c4f236..ff9b20561b8f 100644 --- a/toolchain/check/handle_function.cpp +++ b/toolchain/check/handle_function.cpp @@ -13,10 +13,10 @@ #include "toolchain/check/merge.h" #include "toolchain/check/modifiers.h" #include "toolchain/check/name_component.h" -#include "toolchain/parse/tree_node_diagnostic_converter.h" #include "toolchain/sem_ir/builtin_function_kind.h" #include "toolchain/sem_ir/entry_point.h" #include "toolchain/sem_ir/function.h" +#include "toolchain/sem_ir/generic.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/typed_insts.h" @@ -240,18 +240,23 @@ static auto BuildFunctionDecl(Context& context, // Add the function declaration. auto function_decl = SemIR::FunctionDecl{ SemIR::TypeId::Invalid, SemIR::FunctionId::Invalid, decl_block_id}; + auto decl_id = + context.AddPlaceholderInst(SemIR::LocIdAndInst(node_id, function_decl)); + + // Build the function entity. This will be merged into an existing function if + // there is one, or otherwise added to the function store. auto function_info = SemIR::Function{ .name_id = name_context.name_id_for_new_inst(), .parent_scope_id = name_context.parent_scope_id_for_new_inst(), - .decl_id = context.AddPlaceholderInst( - SemIR::LocIdAndInst(node_id, function_decl)), + .decl_id = decl_id, + .generic_id = SemIR::GenericId::Invalid, .implicit_param_refs_id = name.implicit_params_id, .param_refs_id = name.params_id, .return_storage_id = return_storage_id, .is_extern = is_extern, .return_slot = return_slot}; if (is_definition) { - function_info.definition_id = function_info.decl_id; + function_info.definition_id = decl_id; } TryMergeRedecl(context, node_id, name_context.prev_inst_id(), function_decl, @@ -259,6 +264,14 @@ static auto BuildFunctionDecl(Context& context, // Create a new function if this isn't a valid redeclaration. if (!function_decl.function_id.is_valid()) { + // For a generic function, build the corresponding Generic entity. + if (!context.scope_stack().compile_time_binding_stack().empty()) { + function_info.generic_id = context.generics().Add(SemIR::Generic{ + .decl_id = decl_id, + .bindings_id = context.inst_blocks().Add( + context.scope_stack().compile_time_binding_stack())}); + } + function_decl.function_id = context.functions().Add(function_info); } else { // TODO: Validate that the redeclaration doesn't set an access modifier. @@ -266,7 +279,7 @@ static auto BuildFunctionDecl(Context& context, function_decl.type_id = context.GetFunctionType(function_decl.function_id); // Write the function ID into the FunctionDecl. - context.ReplaceInstBeforeConstantUse(function_info.decl_id, function_decl); + context.ReplaceInstBeforeConstantUse(decl_id, function_decl); // Check if we need to add this to name lookup, now that the function decl is // done. @@ -278,7 +291,7 @@ static auto BuildFunctionDecl(Context& context, if (auto interface_scope = parent_scope_inst->TryAs()) { lookup_result_id = BuildAssociatedEntity( - context, interface_scope->interface_id, function_info.decl_id); + context, interface_scope->interface_id, decl_id); } } @@ -304,10 +317,10 @@ static auto BuildFunctionDecl(Context& context, } if (!is_definition && context.IsImplFile() && !is_extern) { - context.definitions_required().push_back(function_info.decl_id); + context.definitions_required().push_back(decl_id); } - return {function_decl.function_id, function_info.decl_id}; + return {function_decl.function_id, decl_id}; } auto HandleFunctionDecl(Context& context, Parse::FunctionDeclId node_id) diff --git a/toolchain/check/handle_interface.cpp b/toolchain/check/handle_interface.cpp index 24697da8a411..73efce22ad6b 100644 --- a/toolchain/check/handle_interface.cpp +++ b/toolchain/check/handle_interface.cpp @@ -161,6 +161,7 @@ auto HandleInterfaceDefinitionStart(Context& context, SemIR::LocId::Invalid, {.type_id = self_type_id, .bind_name_id = bind_name_id, .value_id = SemIR::InstId::Invalid}); + context.scope_stack().PushCompileTimeBinding(interface_info.self_param_id); context.name_scopes().AddRequiredName(interface_info.scope_id, SemIR::NameId::SelfType, interface_info.self_param_id); diff --git a/toolchain/check/import_ref.cpp b/toolchain/check/import_ref.cpp index a0f64dafc8da..f2919ac1d039 100644 --- a/toolchain/check/import_ref.cpp +++ b/toolchain/check/import_ref.cpp @@ -1068,6 +1068,8 @@ class ImportRefResolver { : function.decl_id); auto function_decl_id = context_.AddPlaceholderInstInNoBlock( SemIR::LocIdAndInst(import_ir_inst_id, function_decl)); + // TODO: Implement import for generics. + auto generic_id = SemIR::GenericId::Invalid; auto new_return_storage = SemIR::InstId::Invalid; if (function.return_storage_id.is_valid()) { @@ -1083,6 +1085,7 @@ class ImportRefResolver { {.name_id = GetLocalNameId(function.name_id), .parent_scope_id = parent_scope_id, .decl_id = function_decl_id, + .generic_id = generic_id, .implicit_param_refs_id = GetLocalParamRefsId( function.implicit_param_refs_id, implicit_param_const_ids), .param_refs_id = diff --git a/toolchain/check/scope_stack.cpp b/toolchain/check/scope_stack.cpp index 5f45ae102b7d..afb1ec8ccf2d 100644 --- a/toolchain/check/scope_stack.cpp +++ b/toolchain/check/scope_stack.cpp @@ -56,6 +56,16 @@ auto ScopeStack::Pop() -> void { CARBON_CHECK(return_scope_stack_.back().returned_var.is_valid()); return_scope_stack_.back().returned_var = SemIR::InstId::Invalid; } + + CARBON_CHECK(scope.next_compile_time_bind_index.index == + static_cast(compile_time_binding_stack_.size())) + << "Wrong number of entries in compile-time binding stack, have " + << compile_time_binding_stack_.size() << ", expected " + << scope.next_compile_time_bind_index.index; + compile_time_binding_stack_.truncate( + scope_stack_.empty() + ? 0 + : scope_stack_.back().next_compile_time_bind_index.index); } auto ScopeStack::PopTo(ScopeIndex index) -> void { @@ -147,13 +157,35 @@ auto ScopeStack::SetReturnedVarOrGetExisting(SemIR::InstId inst_id) auto ScopeStack::Suspend() -> SuspendedScope { CARBON_CHECK(!scope_stack_.empty()) << "No scope to suspend"; SuspendedScope result = {.entry = scope_stack_.pop_back_val(), - .suspended_lookups = {}}; + .suspended_items = {}}; if (result.entry.scope_id.is_valid()) { non_lexical_scope_stack_.pop_back(); } + + auto remaining_compile_time_bindings = + scope_stack_.empty() + ? 0 + : scope_stack_.back().next_compile_time_bind_index.index; + + result.suspended_items.reserve(result.entry.names.size() + + compile_time_binding_stack_.size() - + remaining_compile_time_bindings); for (auto name_id : result.entry.names) { - result.suspended_lookups.push_back(lexical_lookup_.Suspend(name_id)); + auto [index, inst_id] = lexical_lookup_.Suspend(name_id); + CARBON_CHECK(index != + SuspendedScope::ScopeItem::IndexForCompileTimeBinding); + result.suspended_items.push_back({.index = index, .inst_id = inst_id}); } + + // Move any compile-time bindings into the suspended scope. + for (auto inst_id : llvm::ArrayRef(compile_time_binding_stack_) + .drop_back(remaining_compile_time_bindings)) { + result.suspended_items.push_back( + {.index = SuspendedScope::ScopeItem::IndexForCompileTimeBinding, + .inst_id = inst_id}); + } + compile_time_binding_stack_.truncate(remaining_compile_time_bindings); + // This would be easy to support if we had a need, but currently we do not. CARBON_CHECK(!result.entry.has_returned_var) << "Should not suspend a scope with a returned var."; @@ -161,13 +193,22 @@ auto ScopeStack::Suspend() -> SuspendedScope { } auto ScopeStack::Restore(SuspendedScope scope) -> void { - for (auto entry : scope.suspended_lookups) { - // clang-tidy warns that the `std::move` below has no effect. While that's - // true, this `move` defends against the suspended lookup growing more state - // later. - // NOLINTNEXTLINE(performance-move-const-arg) - lexical_lookup_.Restore(std::move(entry), scope.entry.index); + for (auto [index, inst_id] : scope.suspended_items) { + if (index == SuspendedScope::ScopeItem::IndexForCompileTimeBinding) { + compile_time_binding_stack_.push_back(inst_id); + } else { + lexical_lookup_.Restore({.index = index, .inst_id = inst_id}, + scope.entry.index); + } } + + CARBON_CHECK(scope.entry.next_compile_time_bind_index.index == + static_cast(compile_time_binding_stack_.size())) + << "Wrong number of entries in compile-time binding stack " + "when restoring, have " + << compile_time_binding_stack_.size() << ", expected " + << scope.entry.next_compile_time_bind_index.index; + if (scope.entry.scope_id.is_valid()) { non_lexical_scope_stack_.push_back({.scope_index = scope.entry.index, .name_scope_id = scope.entry.scope_id}); diff --git a/toolchain/check/scope_stack.h b/toolchain/check/scope_stack.h index 3857bea920d3..b5667cb6b384 100644 --- a/toolchain/check/scope_stack.h +++ b/toolchain/check/scope_stack.h @@ -115,13 +115,20 @@ class ScopeStack { auto LookupOrAddName(SemIR::NameId name_id, SemIR::InstId target_id) -> SemIR::InstId; - // Adds a compile-time binding in the current scope, and returns its index. + // Prepares to add a compile-time binding in the current scope, and returns + // its index. The added binding must then be pushed using + // `PushCompileTimeBinding`. auto AddCompileTimeBinding() -> SemIR::CompileTimeBindIndex { auto index = scope_stack_.back().next_compile_time_bind_index; ++scope_stack_.back().next_compile_time_bind_index.index; return index; } + // Pushes a compile-time binding into the current scope. + auto PushCompileTimeBinding(SemIR::InstId bind_id) -> void { + compile_time_binding_stack_.push_back(bind_id); + } + // Temporarily removes the top of the stack and its lexical lookup results. auto Suspend() -> SuspendedScope; @@ -139,6 +146,10 @@ class ScopeStack { return break_continue_stack_; } + auto compile_time_binding_stack() -> llvm::SmallVector& { + return compile_time_binding_stack_; + } + private: // An entry in scope_stack_. struct ScopeStackEntry { @@ -195,6 +206,9 @@ class ScopeStack { // the information in scope_stack_. llvm::SmallVector non_lexical_scope_stack_; + // A stack of the current compile time bindings. + llvm::SmallVector compile_time_binding_stack_; + // The index of the next scope that will be pushed onto scope_stack_. The // first is always the package scope. ScopeIndex next_scope_index_ = ScopeIndex::Package; @@ -204,12 +218,30 @@ class ScopeStack { }; struct ScopeStack::SuspendedScope { + // An item that was suspended within this scope. This represents either a + // lexical lookup entry in this scope, or a compile time binding entry in this + // scope. + // + // TODO: For compile-time bindings, the common case is that they will both + // have a suspended lexical lookup entry and a suspended compile time binding + // entry. We should be able to store that as a single ScopeItem rather than + // two. + struct ScopeItem { + static constexpr uint32_t IndexForCompileTimeBinding = -1; + + // The scope index for a LexicalLookup::SuspendedResult, or + // CompileTimeBindingIndex for a suspended compile time binding. + uint32_t index; + // The instruction within the scope. + SemIR::InstId inst_id; + }; + // The suspended scope stack entry. ScopeStackEntry entry; - // The lexical lookups for the suspended entry. The inline size is an attempt - // to keep the size of a `SuspendedFunction` reasonable while avoiding heap - // allocations most of the time. - llvm::SmallVector suspended_lookups; + // The list of items that were within this scope when it was suspended. The + // inline size is an attempt to keep the size of a `SuspendedFunction` + // reasonable while avoiding heap allocations most of the time. + llvm::SmallVector suspended_items; }; } // namespace Carbon::Check diff --git a/toolchain/check/testdata/array/generic_empty.carbon b/toolchain/check/testdata/array/generic_empty.carbon index 1d918824cc50..9009e9f2cced 100644 --- a/toolchain/check/testdata/array/generic_empty.carbon +++ b/toolchain/check/testdata/array/generic_empty.carbon @@ -38,7 +38,8 @@ fn G(T:! type) { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @G(%T: type) { +// CHECK:STDOUT: fn @G(%T: type) +// CHECK:STDOUT: generic [%T: type] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %T.ref: type = name_ref T, %T [symbolic = constants.%T] // CHECK:STDOUT: %.loc13_16: i32 = int_literal 0 [template = constants.%.2] diff --git a/toolchain/check/testdata/basics/builtin_insts.carbon b/toolchain/check/testdata/basics/builtin_insts.carbon index cfcac92bccf3..822332601c6b 100644 --- a/toolchain/check/testdata/basics/builtin_insts.carbon +++ b/toolchain/check/testdata/basics/builtin_insts.carbon @@ -19,6 +19,7 @@ // CHECK:STDOUT: bind_names: {} // CHECK:STDOUT: functions: {} // CHECK:STDOUT: classes: {} +// CHECK:STDOUT: generics: {} // CHECK:STDOUT: types: // CHECK:STDOUT: type0: {constant: template instNamespaceType, value_rep: {kind: copy, type: type0}} // CHECK:STDOUT: type_blocks: {} diff --git a/toolchain/check/testdata/basics/no_prelude/multifile_raw_and_textual_ir.carbon b/toolchain/check/testdata/basics/no_prelude/multifile_raw_and_textual_ir.carbon index b122bbc982a8..75df1b4349cd 100644 --- a/toolchain/check/testdata/basics/no_prelude/multifile_raw_and_textual_ir.carbon +++ b/toolchain/check/testdata/basics/no_prelude/multifile_raw_and_textual_ir.carbon @@ -32,6 +32,7 @@ fn B() {} // CHECK:STDOUT: functions: // CHECK:STDOUT: function0: {name: name0, parent_scope: name_scope0, param_refs: empty, body: [block3]} // CHECK:STDOUT: classes: {} +// CHECK:STDOUT: generics: {} // CHECK:STDOUT: types: // CHECK:STDOUT: type0: {constant: template instNamespaceType, value_rep: {kind: copy, type: type0}} // CHECK:STDOUT: type1: {constant: template inst+2, value_rep: {kind: none, type: type2}} @@ -93,6 +94,7 @@ fn B() {} // CHECK:STDOUT: functions: // CHECK:STDOUT: function0: {name: name0, parent_scope: name_scope0, param_refs: empty, body: [block3]} // CHECK:STDOUT: classes: {} +// CHECK:STDOUT: generics: {} // CHECK:STDOUT: types: // CHECK:STDOUT: type0: {constant: template instNamespaceType, value_rep: {kind: copy, type: type0}} // CHECK:STDOUT: type1: {constant: template inst+2, value_rep: {kind: none, type: type2}} diff --git a/toolchain/check/testdata/basics/no_prelude/multifile_raw_ir.carbon b/toolchain/check/testdata/basics/no_prelude/multifile_raw_ir.carbon index 31a6f5d2d582..5a34aa4e9c39 100644 --- a/toolchain/check/testdata/basics/no_prelude/multifile_raw_ir.carbon +++ b/toolchain/check/testdata/basics/no_prelude/multifile_raw_ir.carbon @@ -32,6 +32,7 @@ fn B() {} // CHECK:STDOUT: functions: // CHECK:STDOUT: function0: {name: name0, parent_scope: name_scope0, param_refs: empty, body: [block3]} // CHECK:STDOUT: classes: {} +// CHECK:STDOUT: generics: {} // CHECK:STDOUT: types: // CHECK:STDOUT: type0: {constant: template instNamespaceType, value_rep: {kind: copy, type: type0}} // CHECK:STDOUT: type1: {constant: template inst+2, value_rep: {kind: none, type: type2}} @@ -72,6 +73,7 @@ fn B() {} // CHECK:STDOUT: functions: // CHECK:STDOUT: function0: {name: name0, parent_scope: name_scope0, param_refs: empty, body: [block3]} // CHECK:STDOUT: classes: {} +// CHECK:STDOUT: generics: {} // CHECK:STDOUT: types: // CHECK:STDOUT: type0: {constant: template instNamespaceType, value_rep: {kind: copy, type: type0}} // CHECK:STDOUT: type1: {constant: template inst+2, value_rep: {kind: none, type: type2}} diff --git a/toolchain/check/testdata/basics/no_prelude/raw_and_textual_ir.carbon b/toolchain/check/testdata/basics/no_prelude/raw_and_textual_ir.carbon index d445991ff8dc..67b8cb57777b 100644 --- a/toolchain/check/testdata/basics/no_prelude/raw_and_textual_ir.carbon +++ b/toolchain/check/testdata/basics/no_prelude/raw_and_textual_ir.carbon @@ -27,6 +27,7 @@ fn Foo(n: ()) -> ((), ()) { // CHECK:STDOUT: functions: // CHECK:STDOUT: function0: {name: name0, parent_scope: name_scope0, param_refs: block3, return_storage: inst+13, return_slot: present, body: [block6]} // CHECK:STDOUT: classes: {} +// CHECK:STDOUT: generics: {} // CHECK:STDOUT: types: // CHECK:STDOUT: type0: {constant: template instNamespaceType, value_rep: {kind: copy, type: type0}} // CHECK:STDOUT: type1: {constant: template inst+1, value_rep: {kind: none, type: type1}} diff --git a/toolchain/check/testdata/basics/no_prelude/raw_ir.carbon b/toolchain/check/testdata/basics/no_prelude/raw_ir.carbon index 011b538cfb1c..76af7a9fdc0a 100644 --- a/toolchain/check/testdata/basics/no_prelude/raw_ir.carbon +++ b/toolchain/check/testdata/basics/no_prelude/raw_ir.carbon @@ -12,7 +12,7 @@ // TIP: To dump output, run: // TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/basics/no_prelude/raw_ir.carbon -fn Foo(n: ()) -> ((), ()) { +fn Foo[T:! type](n: T) -> (T, ()) { return (n, ()); } @@ -21,123 +21,128 @@ fn Foo(n: ()) -> ((), ()) { // CHECK:STDOUT: sem_ir: // CHECK:STDOUT: import_irs_size: 1 // CHECK:STDOUT: name_scopes: -// CHECK:STDOUT: name_scope0: {inst: inst+0, parent_scope: name_scope, has_error: false, extended_scopes: [], names: {name0: inst+14}} +// CHECK:STDOUT: name_scope0: {inst: inst+0, parent_scope: name_scope, has_error: false, extended_scopes: [], names: {name0: inst+16}} // CHECK:STDOUT: bind_names: -// CHECK:STDOUT: bindName0: {name: name1, parent_scope: name_scope, index: compTimeBind} +// CHECK:STDOUT: bindName0: {name: name1, parent_scope: name_scope, index: compTimeBind0} +// CHECK:STDOUT: bindName1: {name: name2, parent_scope: name_scope, index: compTimeBind} // CHECK:STDOUT: functions: -// CHECK:STDOUT: function0: {name: name0, parent_scope: name_scope0, param_refs: block3, return_storage: inst+13, return_slot: present, body: [block6]} +// CHECK:STDOUT: function0: {name: name0, parent_scope: name_scope0, param_refs: block4, return_storage: inst+15, return_slot: present, body: [block8]} // CHECK:STDOUT: classes: {} +// CHECK:STDOUT: generics: +// CHECK:STDOUT: generic0: {decl: inst+16, bindings: block7} // CHECK:STDOUT: types: // CHECK:STDOUT: type0: {constant: template instNamespaceType, value_rep: {kind: copy, type: type0}} -// CHECK:STDOUT: type1: {constant: template inst+1, value_rep: {kind: none, type: type1}} -// CHECK:STDOUT: type2: {constant: template inst+8, value_rep: {kind: pointer, type: type4}} -// CHECK:STDOUT: type3: {constant: template inst+15, value_rep: {kind: none, type: type1}} -// CHECK:STDOUT: type4: {constant: template inst+17, value_rep: {kind: copy, type: type4}} +// CHECK:STDOUT: type1: {constant: symbolic inst+3, value_rep: {kind: copy, type: type1}} +// CHECK:STDOUT: type2: {constant: template inst+8, value_rep: {kind: none, type: type2}} +// CHECK:STDOUT: type3: {constant: template inst+10, value_rep: {kind: unknown, type: type}} +// CHECK:STDOUT: type4: {constant: symbolic inst+13, value_rep: {kind: pointer, type: type6}} +// CHECK:STDOUT: type5: {constant: template inst+17, value_rep: {kind: none, type: type2}} +// CHECK:STDOUT: type6: {constant: symbolic inst+19, value_rep: {kind: copy, type: type6}} // CHECK:STDOUT: type_blocks: // CHECK:STDOUT: typeBlock0: {} // CHECK:STDOUT: typeBlock1: +// CHECK:STDOUT: 0: typeTypeType +// CHECK:STDOUT: 1: type2 +// CHECK:STDOUT: typeBlock2: // CHECK:STDOUT: 0: type1 -// CHECK:STDOUT: 1: type1 +// CHECK:STDOUT: 1: type2 // CHECK:STDOUT: insts: // CHECK:STDOUT: 'inst+0': {kind: Namespace, arg0: name_scope0, arg1: inst, type: type0} -// CHECK:STDOUT: 'inst+1': {kind: TupleType, arg0: typeBlock0, type: typeTypeType} -// CHECK:STDOUT: 'inst+2': {kind: TupleLiteral, arg0: empty, type: type1} -// CHECK:STDOUT: 'inst+3': {kind: Converted, arg0: inst+2, arg1: inst+1, type: typeTypeType} -// CHECK:STDOUT: 'inst+4': {kind: Param, arg0: name1, type: type1} -// CHECK:STDOUT: 'inst+5': {kind: BindName, arg0: bindName0, arg1: inst+4, type: type1} -// CHECK:STDOUT: 'inst+6': {kind: TupleLiteral, arg0: empty, type: type1} -// CHECK:STDOUT: 'inst+7': {kind: TupleLiteral, arg0: empty, type: type1} -// CHECK:STDOUT: 'inst+8': {kind: TupleType, arg0: typeBlock1, type: typeTypeType} -// CHECK:STDOUT: 'inst+9': {kind: TupleLiteral, arg0: block4, type: type2} -// CHECK:STDOUT: 'inst+10': {kind: Converted, arg0: inst+6, arg1: inst+1, type: typeTypeType} -// CHECK:STDOUT: 'inst+11': {kind: Converted, arg0: inst+7, arg1: inst+1, type: typeTypeType} +// CHECK:STDOUT: 'inst+1': {kind: Param, arg0: name1, type: typeTypeType} +// CHECK:STDOUT: 'inst+2': {kind: BindSymbolicName, arg0: bindName0, arg1: inst+1, type: typeTypeType} +// CHECK:STDOUT: 'inst+3': {kind: BindSymbolicName, arg0: bindName0, arg1: inst, type: typeTypeType} +// CHECK:STDOUT: 'inst+4': {kind: NameRef, arg0: name1, arg1: inst+2, type: typeTypeType} +// CHECK:STDOUT: 'inst+5': {kind: Param, arg0: name2, type: type1} +// CHECK:STDOUT: 'inst+6': {kind: BindName, arg0: bindName1, arg1: inst+5, type: type1} +// CHECK:STDOUT: 'inst+7': {kind: NameRef, arg0: name1, arg1: inst+2, type: typeTypeType} +// CHECK:STDOUT: 'inst+8': {kind: TupleType, arg0: typeBlock0, type: typeTypeType} +// CHECK:STDOUT: 'inst+9': {kind: TupleLiteral, arg0: empty, type: type2} +// CHECK:STDOUT: 'inst+10': {kind: TupleType, arg0: typeBlock1, type: typeTypeType} +// CHECK:STDOUT: 'inst+11': {kind: TupleLiteral, arg0: block5, type: type3} // CHECK:STDOUT: 'inst+12': {kind: Converted, arg0: inst+9, arg1: inst+8, type: typeTypeType} -// CHECK:STDOUT: 'inst+13': {kind: VarStorage, arg0: nameReturnSlot, type: type2} -// CHECK:STDOUT: 'inst+14': {kind: FunctionDecl, arg0: function0, arg1: block5, type: type3} -// CHECK:STDOUT: 'inst+15': {kind: FunctionType, arg0: function0, type: typeTypeType} -// CHECK:STDOUT: 'inst+16': {kind: StructValue, arg0: empty, type: type3} -// CHECK:STDOUT: 'inst+17': {kind: PointerType, arg0: type2, type: typeTypeType} -// CHECK:STDOUT: 'inst+18': {kind: NameRef, arg0: name1, arg1: inst+5, type: type1} -// CHECK:STDOUT: 'inst+19': {kind: TupleLiteral, arg0: empty, type: type1} -// CHECK:STDOUT: 'inst+20': {kind: TupleLiteral, arg0: block7, type: type2} -// CHECK:STDOUT: 'inst+21': {kind: TupleAccess, arg0: inst+13, arg1: element0, type: type1} -// CHECK:STDOUT: 'inst+22': {kind: TupleInit, arg0: block8, arg1: inst+21, type: type1} -// CHECK:STDOUT: 'inst+23': {kind: TupleValue, arg0: block9, type: type1} -// CHECK:STDOUT: 'inst+24': {kind: Converted, arg0: inst+18, arg1: inst+22, type: type1} -// CHECK:STDOUT: 'inst+25': {kind: TupleAccess, arg0: inst+13, arg1: element1, type: type1} -// CHECK:STDOUT: 'inst+26': {kind: TupleInit, arg0: empty, arg1: inst+25, type: type1} -// CHECK:STDOUT: 'inst+27': {kind: Converted, arg0: inst+19, arg1: inst+26, type: type1} -// CHECK:STDOUT: 'inst+28': {kind: TupleInit, arg0: block10, arg1: inst+13, type: type2} -// CHECK:STDOUT: 'inst+29': {kind: TupleValue, arg0: block11, type: type2} -// CHECK:STDOUT: 'inst+30': {kind: Converted, arg0: inst+20, arg1: inst+28, type: type2} -// CHECK:STDOUT: 'inst+31': {kind: ReturnExpr, arg0: inst+30, arg1: inst+13} +// CHECK:STDOUT: 'inst+13': {kind: TupleType, arg0: typeBlock2, type: typeTypeType} +// CHECK:STDOUT: 'inst+14': {kind: Converted, arg0: inst+11, arg1: inst+13, type: typeTypeType} +// CHECK:STDOUT: 'inst+15': {kind: VarStorage, arg0: nameReturnSlot, type: type4} +// CHECK:STDOUT: 'inst+16': {kind: FunctionDecl, arg0: function0, arg1: block6, type: type5} +// CHECK:STDOUT: 'inst+17': {kind: FunctionType, arg0: function0, type: typeTypeType} +// CHECK:STDOUT: 'inst+18': {kind: StructValue, arg0: empty, type: type5} +// CHECK:STDOUT: 'inst+19': {kind: PointerType, arg0: type4, type: typeTypeType} +// CHECK:STDOUT: 'inst+20': {kind: NameRef, arg0: name2, arg1: inst+6, type: type1} +// CHECK:STDOUT: 'inst+21': {kind: TupleLiteral, arg0: empty, type: type2} +// CHECK:STDOUT: 'inst+22': {kind: TupleLiteral, arg0: block9, type: type4} +// CHECK:STDOUT: 'inst+23': {kind: TupleAccess, arg0: inst+15, arg1: element0, type: type1} +// CHECK:STDOUT: 'inst+24': {kind: InitializeFrom, arg0: inst+20, arg1: inst+23, type: type1} +// CHECK:STDOUT: 'inst+25': {kind: TupleAccess, arg0: inst+15, arg1: element1, type: type2} +// CHECK:STDOUT: 'inst+26': {kind: TupleInit, arg0: empty, arg1: inst+25, type: type2} +// CHECK:STDOUT: 'inst+27': {kind: TupleValue, arg0: block11, type: type2} +// CHECK:STDOUT: 'inst+28': {kind: Converted, arg0: inst+21, arg1: inst+26, type: type2} +// CHECK:STDOUT: 'inst+29': {kind: TupleInit, arg0: block10, arg1: inst+15, type: type4} +// CHECK:STDOUT: 'inst+30': {kind: Converted, arg0: inst+22, arg1: inst+29, type: type4} +// CHECK:STDOUT: 'inst+31': {kind: ReturnExpr, arg0: inst+30, arg1: inst+15} // CHECK:STDOUT: constant_values: // CHECK:STDOUT: 'inst+0': template inst+0 -// CHECK:STDOUT: 'inst+1': template inst+1 -// CHECK:STDOUT: 'inst+3': template inst+1 +// CHECK:STDOUT: 'inst+2': symbolic inst+3 +// CHECK:STDOUT: 'inst+3': symbolic inst+3 +// CHECK:STDOUT: 'inst+4': symbolic inst+3 +// CHECK:STDOUT: 'inst+7': symbolic inst+3 // CHECK:STDOUT: 'inst+8': template inst+8 -// CHECK:STDOUT: 'inst+10': template inst+1 -// CHECK:STDOUT: 'inst+11': template inst+1 +// CHECK:STDOUT: 'inst+10': template inst+10 // CHECK:STDOUT: 'inst+12': template inst+8 -// CHECK:STDOUT: 'inst+14': template inst+16 -// CHECK:STDOUT: 'inst+15': template inst+15 -// CHECK:STDOUT: 'inst+16': template inst+16 +// CHECK:STDOUT: 'inst+13': symbolic inst+13 +// CHECK:STDOUT: 'inst+14': symbolic inst+13 +// CHECK:STDOUT: 'inst+16': template inst+18 // CHECK:STDOUT: 'inst+17': template inst+17 -// CHECK:STDOUT: 'inst+22': template inst+23 -// CHECK:STDOUT: 'inst+23': template inst+23 -// CHECK:STDOUT: 'inst+24': template inst+23 -// CHECK:STDOUT: 'inst+26': template inst+23 -// CHECK:STDOUT: 'inst+27': template inst+23 -// CHECK:STDOUT: 'inst+28': template inst+29 -// CHECK:STDOUT: 'inst+29': template inst+29 -// CHECK:STDOUT: 'inst+30': template inst+29 +// CHECK:STDOUT: 'inst+18': template inst+18 +// CHECK:STDOUT: 'inst+19': symbolic inst+19 +// CHECK:STDOUT: 'inst+26': template inst+27 +// CHECK:STDOUT: 'inst+27': template inst+27 +// CHECK:STDOUT: 'inst+28': template inst+27 // CHECK:STDOUT: inst_blocks: // CHECK:STDOUT: empty: {} // CHECK:STDOUT: exports: -// CHECK:STDOUT: 0: inst+14 +// CHECK:STDOUT: 0: inst+16 // CHECK:STDOUT: global_init: {} // CHECK:STDOUT: block3: -// CHECK:STDOUT: 0: inst+5 +// CHECK:STDOUT: 0: inst+2 // CHECK:STDOUT: block4: // CHECK:STDOUT: 0: inst+6 -// CHECK:STDOUT: 1: inst+7 // CHECK:STDOUT: block5: -// CHECK:STDOUT: 0: inst+2 -// CHECK:STDOUT: 1: inst+3 +// CHECK:STDOUT: 0: inst+7 +// CHECK:STDOUT: 1: inst+9 +// CHECK:STDOUT: block6: +// CHECK:STDOUT: 0: inst+1 +// CHECK:STDOUT: 1: inst+2 // CHECK:STDOUT: 2: inst+4 // CHECK:STDOUT: 3: inst+5 // CHECK:STDOUT: 4: inst+6 // CHECK:STDOUT: 5: inst+7 // CHECK:STDOUT: 6: inst+9 -// CHECK:STDOUT: 7: inst+10 -// CHECK:STDOUT: 8: inst+11 -// CHECK:STDOUT: 9: inst+12 -// CHECK:STDOUT: 10: inst+13 -// CHECK:STDOUT: block6: -// CHECK:STDOUT: 0: inst+18 -// CHECK:STDOUT: 1: inst+19 -// CHECK:STDOUT: 2: inst+20 -// CHECK:STDOUT: 3: inst+21 -// CHECK:STDOUT: 4: inst+22 -// CHECK:STDOUT: 5: inst+24 -// CHECK:STDOUT: 6: inst+25 -// CHECK:STDOUT: 7: inst+26 -// CHECK:STDOUT: 8: inst+27 -// CHECK:STDOUT: 9: inst+28 -// CHECK:STDOUT: 10: inst+30 -// CHECK:STDOUT: 11: inst+31 +// CHECK:STDOUT: 7: inst+11 +// CHECK:STDOUT: 8: inst+12 +// CHECK:STDOUT: 9: inst+14 +// CHECK:STDOUT: 10: inst+15 // CHECK:STDOUT: block7: -// CHECK:STDOUT: 0: inst+18 -// CHECK:STDOUT: 1: inst+19 -// CHECK:STDOUT: block8: {} -// CHECK:STDOUT: block9: {} +// CHECK:STDOUT: 0: inst+2 +// CHECK:STDOUT: block8: +// CHECK:STDOUT: 0: inst+20 +// CHECK:STDOUT: 1: inst+21 +// CHECK:STDOUT: 2: inst+22 +// CHECK:STDOUT: 3: inst+23 +// CHECK:STDOUT: 4: inst+24 +// CHECK:STDOUT: 5: inst+25 +// CHECK:STDOUT: 6: inst+26 +// CHECK:STDOUT: 7: inst+28 +// CHECK:STDOUT: 8: inst+29 +// CHECK:STDOUT: 9: inst+30 +// CHECK:STDOUT: 10: inst+31 +// CHECK:STDOUT: block9: +// CHECK:STDOUT: 0: inst+20 +// CHECK:STDOUT: 1: inst+21 // CHECK:STDOUT: block10: // CHECK:STDOUT: 0: inst+24 -// CHECK:STDOUT: 1: inst+27 -// CHECK:STDOUT: block11: -// CHECK:STDOUT: 0: inst+23 -// CHECK:STDOUT: 1: inst+23 +// CHECK:STDOUT: 1: inst+28 +// CHECK:STDOUT: block11: {} // CHECK:STDOUT: block12: // CHECK:STDOUT: 0: inst+0 -// CHECK:STDOUT: 1: inst+14 +// CHECK:STDOUT: 1: inst+16 // CHECK:STDOUT: ... diff --git a/toolchain/check/testdata/builtins/int/make_type_signed.carbon b/toolchain/check/testdata/builtins/int/make_type_signed.carbon index 03a78bd8934a..75487da8c4ec 100644 --- a/toolchain/check/testdata/builtins/int/make_type_signed.carbon +++ b/toolchain/check/testdata/builtins/int/make_type_signed.carbon @@ -201,7 +201,8 @@ var m: Int(1000000000); // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Symbolic(%N: i32, %x: %.6) -> %.6 { +// CHECK:STDOUT: fn @Symbolic(%N: i32, %x: %.6) -> %.6 +// CHECK:STDOUT: generic [%N: i32] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %x.ref: %.6 = name_ref x, %x // CHECK:STDOUT: return %x.ref diff --git a/toolchain/check/testdata/builtins/int/make_type_unsigned.carbon b/toolchain/check/testdata/builtins/int/make_type_unsigned.carbon index a304d6672fc0..fdcc3e0598e6 100644 --- a/toolchain/check/testdata/builtins/int/make_type_unsigned.carbon +++ b/toolchain/check/testdata/builtins/int/make_type_unsigned.carbon @@ -201,7 +201,8 @@ var m: UInt(1000000000); // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Symbolic(%N: i32, %x: %.6) -> %.6 { +// CHECK:STDOUT: fn @Symbolic(%N: i32, %x: %.6) -> %.6 +// CHECK:STDOUT: generic [%N: i32] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %x.ref: %.6 = name_ref x, %x // CHECK:STDOUT: return %x.ref diff --git a/toolchain/check/testdata/class/fail_generic_method.carbon b/toolchain/check/testdata/class/fail_generic_method.carbon index 6233cacf7d95..2125fdc31c72 100644 --- a/toolchain/check/testdata/class/fail_generic_method.carbon +++ b/toolchain/check/testdata/class/fail_generic_method.carbon @@ -94,11 +94,13 @@ fn Class(N:! i32).F[self: Self](n: T) {} // CHECK:STDOUT: .F = %F.decl // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F[@Class.%self.loc13_8.2: %Class.2](@Class.%n.loc13_20.2: %T); +// CHECK:STDOUT: fn @F[@Class.%self.loc13_8.2: %Class.2](@Class.%n.loc13_20.2: %T) +// CHECK:STDOUT: generic [file.%T.loc11_13.2: type]; // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @.1[%self: ](%n: ) { +// CHECK:STDOUT: fn @.1[%self: ](%n: ) +// CHECK:STDOUT: generic [file.%N.loc32_10.2: i32] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/class/generic/basic.carbon b/toolchain/check/testdata/class/generic/basic.carbon index 05e7fb581d01..b33bf81162d4 100644 --- a/toolchain/check/testdata/class/generic/basic.carbon +++ b/toolchain/check/testdata/class/generic/basic.carbon @@ -81,7 +81,8 @@ class Class(T:! type) { // CHECK:STDOUT: .k = %.loc21 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @GetAddr[addr @Class.%self.loc12_19.3: %.2]() -> %.3 { +// CHECK:STDOUT: fn @GetAddr[addr @Class.%self.loc12_19.3: %.2]() -> %.3 +// CHECK:STDOUT: generic [file.%T.loc11_13.2: type] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %self.ref: %.2 = name_ref self, @Class.%self.loc12_19.3 // CHECK:STDOUT: %.loc13_17.1: ref %Class.2 = deref %self.ref @@ -91,7 +92,8 @@ class Class(T:! type) { // CHECK:STDOUT: return %.loc13_12 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @GetValue[@Class.%self.loc17_15.2: %Class.2]() -> %T { +// CHECK:STDOUT: fn @GetValue[@Class.%self.loc17_15.2: %Class.2]() -> %T +// CHECK:STDOUT: generic [file.%T.loc11_13.2: type] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %self.ref: %Class.2 = name_ref self, @Class.%self.loc17_15.2 // CHECK:STDOUT: %k.ref: %.4 = name_ref k, @Class.%.loc21 [template = @Class.%.loc21] diff --git a/toolchain/check/testdata/class/generic/fail_todo_use.carbon b/toolchain/check/testdata/class/generic/fail_todo_use.carbon index b7f428bfc478..1b875887da60 100644 --- a/toolchain/check/testdata/class/generic/fail_todo_use.carbon +++ b/toolchain/check/testdata/class/generic/fail_todo_use.carbon @@ -102,7 +102,8 @@ fn Run() -> i32 { // CHECK:STDOUT: .k = %.loc16 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Get[addr @Class.%self.loc12_15.3: %.2]() -> %.3 { +// CHECK:STDOUT: fn @Get[addr @Class.%self.loc12_15.3: %.2]() -> %.3 +// CHECK:STDOUT: generic [file.%T.loc11_13.2: type] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %self.ref: %.2 = name_ref self, @Class.%self.loc12_15.3 // CHECK:STDOUT: %.loc13_17.1: ref %Class.2 = deref %self.ref diff --git a/toolchain/check/testdata/class/generic/import.carbon b/toolchain/check/testdata/class/generic/import.carbon index 8c0d94baaa0d..9627bf0394a6 100644 --- a/toolchain/check/testdata/class/generic/import.carbon +++ b/toolchain/check/testdata/class/generic/import.carbon @@ -164,7 +164,8 @@ class Class(U:! type) { // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1() -> i32 { +// CHECK:STDOUT: fn @F.1() -> i32 +// CHECK:STDOUT: generic [file.%T.loc6_21.2: type] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %.loc8: i32 = int_literal 0 [template = constants.%.4] // CHECK:STDOUT: return %.loc8 diff --git a/toolchain/check/testdata/class/generic/member_inline.carbon b/toolchain/check/testdata/class/generic/member_inline.carbon index 27ad417968de..2bd2b86c568e 100644 --- a/toolchain/check/testdata/class/generic/member_inline.carbon +++ b/toolchain/check/testdata/class/generic/member_inline.carbon @@ -53,7 +53,8 @@ class Class(T:! type) { // CHECK:STDOUT: .F = %F.decl // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(@Class.%n.loc12_8.2: %T) -> %T { +// CHECK:STDOUT: fn @F(@Class.%n.loc12_8.2: %T) -> %T +// CHECK:STDOUT: generic [file.%T.loc11_13.2: type] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %n.ref: %T = name_ref n, @Class.%n.loc12_8.2 // CHECK:STDOUT: return %n.ref diff --git a/toolchain/check/testdata/class/generic/member_out_of_line.carbon b/toolchain/check/testdata/class/generic/member_out_of_line.carbon index dd8d1344fa19..0a3ea0bd493f 100644 --- a/toolchain/check/testdata/class/generic/member_out_of_line.carbon +++ b/toolchain/check/testdata/class/generic/member_out_of_line.carbon @@ -147,7 +147,8 @@ fn Generic(T:! ()).WrongType() {} // CHECK:STDOUT: .F = %F.decl // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(%n: %T) -> %T { +// CHECK:STDOUT: fn @F(%n: %T) -> %T +// CHECK:STDOUT: generic [file.%T.loc4_13.2: type] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %n.ref: %T = name_ref n, %n // CHECK:STDOUT: return %n.ref @@ -223,7 +224,8 @@ fn Generic(T:! ()).WrongType() {} // CHECK:STDOUT: .F = %F.decl // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F[%self: %B.2](%a: %T) { +// CHECK:STDOUT: fn @F[%self: %B.2](%a: %T) +// CHECK:STDOUT: generic [file.%T.loc4_9.2: type, @A.%N.loc5_11.2: %T] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } @@ -264,7 +266,8 @@ fn Generic(T:! ()).WrongType() {} // CHECK:STDOUT: // CHECK:STDOUT: fn @F(); // CHECK:STDOUT: -// CHECK:STDOUT: fn @.1() { +// CHECK:STDOUT: fn @.1() +// CHECK:STDOUT: generic [file.%T.loc15_15.2: type] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } @@ -305,7 +308,8 @@ fn Generic(T:! ()).WrongType() {} // CHECK:STDOUT: .TooFew = %TooFew.decl // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @TooFew(); +// CHECK:STDOUT: fn @TooFew() +// CHECK:STDOUT: generic [file.%T.loc4_15.2: type]; // CHECK:STDOUT: // CHECK:STDOUT: fn @.1() { // CHECK:STDOUT: !entry: @@ -354,9 +358,11 @@ fn Generic(T:! ()).WrongType() {} // CHECK:STDOUT: .TooMany = %TooMany.decl // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @TooMany(); +// CHECK:STDOUT: fn @TooMany() +// CHECK:STDOUT: generic [file.%T.loc4_15.2: type]; // CHECK:STDOUT: -// CHECK:STDOUT: fn @.1() { +// CHECK:STDOUT: fn @.1() +// CHECK:STDOUT: generic [file.%T.loc15_12.2: type, file.%U.loc15_22.2: type] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } @@ -403,9 +409,11 @@ fn Generic(T:! ()).WrongType() {} // CHECK:STDOUT: .WrongType = %WrongType.decl // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @WrongType(); +// CHECK:STDOUT: fn @WrongType() +// CHECK:STDOUT: generic [file.%T.loc4_15.2: type]; // CHECK:STDOUT: -// CHECK:STDOUT: fn @.1() { +// CHECK:STDOUT: fn @.1() +// CHECK:STDOUT: generic [file.%T.loc14_12.2: %.1] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/class/generic_method.carbon b/toolchain/check/testdata/class/generic_method.carbon index 4836663a7c79..7edc5103c3fb 100644 --- a/toolchain/check/testdata/class/generic_method.carbon +++ b/toolchain/check/testdata/class/generic_method.carbon @@ -70,7 +70,8 @@ fn Class(T:! type).F[self: Self](n: T) {} // CHECK:STDOUT: .F = %F.decl // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F[%self: %Class.2](%n: %T) { +// CHECK:STDOUT: fn @F[%self: %Class.2](%n: %T) +// CHECK:STDOUT: generic [file.%T.loc11_13.2: type] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/eval/fail_symbolic.carbon b/toolchain/check/testdata/eval/fail_symbolic.carbon index 1a245c0cfbfb..3f1fe9331e6c 100644 --- a/toolchain/check/testdata/eval/fail_symbolic.carbon +++ b/toolchain/check/testdata/eval/fail_symbolic.carbon @@ -46,7 +46,8 @@ fn G(N:! i32) { // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @G(%N: i32) { +// CHECK:STDOUT: fn @G(%N: i32) +// CHECK:STDOUT: generic [%N: i32] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %int.make_type_32: init type = call constants.%Int32() [template = i32] // CHECK:STDOUT: %N.ref: i32 = name_ref N, %N [symbolic = constants.%N] diff --git a/toolchain/check/testdata/eval/symbolic.carbon b/toolchain/check/testdata/eval/symbolic.carbon index 11974c071a1a..c91a603b8ee5 100644 --- a/toolchain/check/testdata/eval/symbolic.carbon +++ b/toolchain/check/testdata/eval/symbolic.carbon @@ -46,7 +46,8 @@ fn F(T:! type) { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(%T: type) { +// CHECK:STDOUT: fn @F(%T: type) +// CHECK:STDOUT: generic [%T: type] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %T.ref.loc13_11: type = name_ref T, %T [symbolic = constants.%T] // CHECK:STDOUT: %.loc13_12: type = ptr_type %T [symbolic = constants.%.2] diff --git a/toolchain/check/testdata/function/builtin/method.carbon b/toolchain/check/testdata/function/builtin/method.carbon index b01348683e6f..00b987a41aef 100644 --- a/toolchain/check/testdata/function/builtin/method.carbon +++ b/toolchain/check/testdata/function/builtin/method.carbon @@ -125,7 +125,8 @@ var arr: [i32; 1.(I.F)(2)]; // CHECK:STDOUT: witness = %.1 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1[@I.%self.loc12_8.2: %Self](@I.%other.loc12_20.2: %Self) -> %Self; +// CHECK:STDOUT: fn @F.1[@I.%self.loc12_8.2: %Self](@I.%other.loc12_20.2: %Self) -> %Self +// CHECK:STDOUT: generic [@I.%Self: %.1]; // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/builtin/no_prelude/call_from_operator.carbon b/toolchain/check/testdata/function/builtin/no_prelude/call_from_operator.carbon index ea0441235359..8519c436d533 100644 --- a/toolchain/check/testdata/function/builtin/no_prelude/call_from_operator.carbon +++ b/toolchain/check/testdata/function/builtin/no_prelude/call_from_operator.carbon @@ -83,7 +83,8 @@ var arr: [i32; 1 + 2] = (3, 4, 3 + 4); // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op[@Add.%self.loc7_9.2: %Self](@Add.%other.loc7_21.2: %Self) -> %Self; +// CHECK:STDOUT: fn @Op[@Add.%self.loc7_9.2: %Self](@Add.%other.loc7_21.2: %Self) -> %Self +// CHECK:STDOUT: generic [@Add.%Self: %.2]; // CHECK:STDOUT: // CHECK:STDOUT: --- user.carbon // CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/generic/fail_todo_param_in_type.carbon b/toolchain/check/testdata/function/generic/fail_todo_param_in_type.carbon index c4dd2aa0ae4e..d1df97374df6 100644 --- a/toolchain/check/testdata/function/generic/fail_todo_param_in_type.carbon +++ b/toolchain/check/testdata/function/generic/fail_todo_param_in_type.carbon @@ -51,5 +51,6 @@ fn F(N:! i32, a: [i32; N]*); // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(%N: i32, %a: ); +// CHECK:STDOUT: fn @F(%N: i32, %a: ) +// CHECK:STDOUT: generic [%N: i32]; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/generic/no_prelude/fail_type_param_mismatch.carbon b/toolchain/check/testdata/function/generic/no_prelude/fail_type_param_mismatch.carbon index 09ca3baaaba0..2aeaea5a801f 100644 --- a/toolchain/check/testdata/function/generic/no_prelude/fail_type_param_mismatch.carbon +++ b/toolchain/check/testdata/function/generic/no_prelude/fail_type_param_mismatch.carbon @@ -39,7 +39,8 @@ fn F(T:! type, U:! type) { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(%T: type, %U: type) { +// CHECK:STDOUT: fn @F(%T: type, %U: type) +// CHECK:STDOUT: generic [%T: type, %U: type] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %T.ref: type = name_ref T, %T [symbolic = constants.%T] // CHECK:STDOUT: %.loc12: type = ptr_type %T [symbolic = constants.%.2] diff --git a/toolchain/check/testdata/function/generic/no_prelude/type_param.carbon b/toolchain/check/testdata/function/generic/no_prelude/type_param.carbon index 476e523435ed..49c28072dd00 100644 --- a/toolchain/check/testdata/function/generic/no_prelude/type_param.carbon +++ b/toolchain/check/testdata/function/generic/no_prelude/type_param.carbon @@ -33,7 +33,8 @@ fn F(T:! type) { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(%T: type) { +// CHECK:STDOUT: fn @F(%T: type) +// CHECK:STDOUT: generic [%T: type] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %T.ref.loc12: type = name_ref T, %T [symbolic = constants.%T] // CHECK:STDOUT: %.loc12: type = ptr_type %T [symbolic = constants.%.2] diff --git a/toolchain/check/testdata/function/generic/no_prelude/type_param_scope.carbon b/toolchain/check/testdata/function/generic/no_prelude/type_param_scope.carbon index c5dfc1d922dc..2df8ce4719cf 100644 --- a/toolchain/check/testdata/function/generic/no_prelude/type_param_scope.carbon +++ b/toolchain/check/testdata/function/generic/no_prelude/type_param_scope.carbon @@ -37,7 +37,8 @@ fn F(T:! type, n: T) -> T { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(%T: type, %n: %T) -> %T { +// CHECK:STDOUT: fn @F(%T: type, %n: %T) -> %T +// CHECK:STDOUT: generic [%T: type] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %T.ref: type = name_ref T, %T [symbolic = constants.%T] // CHECK:STDOUT: %n.ref: %T = name_ref n, %n diff --git a/toolchain/check/testdata/function/generic/redeclare.carbon b/toolchain/check/testdata/function/generic/redeclare.carbon index 694b0ee83f09..ac240f5e4ddc 100644 --- a/toolchain/check/testdata/function/generic/redeclare.carbon +++ b/toolchain/check/testdata/function/generic/redeclare.carbon @@ -133,7 +133,8 @@ fn F(U:! type, T:! type) -> U* { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(%T: type) -> %.1 { +// CHECK:STDOUT: fn @F(%T: type) -> %.1 +// CHECK:STDOUT: generic [file.%T.loc4_6.2: type] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl.loc4 [template = constants.%F] // CHECK:STDOUT: %T.ref: type = name_ref T, %T [symbolic = constants.%T] @@ -183,9 +184,11 @@ fn F(U:! type, T:! type) -> U* { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(%T: type, %U: type) -> %.1; +// CHECK:STDOUT: fn @F(%T: type, %U: type) -> %.1 +// CHECK:STDOUT: generic [%T: type, %U: type]; // CHECK:STDOUT: -// CHECK:STDOUT: fn @.1(%T: type, %U: type) -> %.3 { +// CHECK:STDOUT: fn @.1(%T: type, %U: type) -> %.3 +// CHECK:STDOUT: generic [%T: type, %U: type] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] // CHECK:STDOUT: %T.ref: type = name_ref T, %T [symbolic = constants.%T] @@ -235,9 +238,11 @@ fn F(U:! type, T:! type) -> U* { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(%T: type, %U: type) -> %.1; +// CHECK:STDOUT: fn @F(%T: type, %U: type) -> %.1 +// CHECK:STDOUT: generic [%T: type, %U: type]; // CHECK:STDOUT: -// CHECK:STDOUT: fn @.1(%U: type, %T: type) -> %.3 { +// CHECK:STDOUT: fn @.1(%U: type, %T: type) -> %.3 +// CHECK:STDOUT: generic [%U: type, %T: type] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] // CHECK:STDOUT: %T.ref: type = name_ref T, %T [symbolic = constants.%T.2] @@ -287,9 +292,11 @@ fn F(U:! type, T:! type) -> U* { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(%T: type, %U: type) -> %.1; +// CHECK:STDOUT: fn @F(%T: type, %U: type) -> %.1 +// CHECK:STDOUT: generic [%T: type, %U: type]; // CHECK:STDOUT: -// CHECK:STDOUT: fn @.1(%U: type, %T: type) -> %.3 { +// CHECK:STDOUT: fn @.1(%U: type, %T: type) -> %.3 +// CHECK:STDOUT: generic [%U: type, %T: type] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] // CHECK:STDOUT: %T.ref: type = name_ref T, %T [symbolic = constants.%T.2] diff --git a/toolchain/check/testdata/impl/compound.carbon b/toolchain/check/testdata/impl/compound.carbon index 79bf7401455f..ee67860048c9 100644 --- a/toolchain/check/testdata/impl/compound.carbon +++ b/toolchain/check/testdata/impl/compound.carbon @@ -158,9 +158,11 @@ fn InstanceCallIndirect(p: i32*) { // CHECK:STDOUT: witness = %.1 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1(); +// CHECK:STDOUT: fn @F.1() +// CHECK:STDOUT: generic [@Simple.%Self: %.1]; // CHECK:STDOUT: -// CHECK:STDOUT: fn @G.1[@Simple.%self.loc13_8.2: %Self](); +// CHECK:STDOUT: fn @G.1[@Simple.%self.loc13_8.2: %Self]() +// CHECK:STDOUT: generic [@Simple.%Self: %.1]; // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/impl/extend_impl.carbon b/toolchain/check/testdata/impl/extend_impl.carbon index b5033f3bf243..d8292434708e 100644 --- a/toolchain/check/testdata/impl/extend_impl.carbon +++ b/toolchain/check/testdata/impl/extend_impl.carbon @@ -90,7 +90,8 @@ fn G(c: C) { // CHECK:STDOUT: extend name_scope2 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1(); +// CHECK:STDOUT: fn @F.1() +// CHECK:STDOUT: generic [@HasF.%Self: %.1]; // CHECK:STDOUT: // CHECK:STDOUT: fn @F.2() { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/impl/fail_call_invalid.carbon b/toolchain/check/testdata/impl/fail_call_invalid.carbon index 083b97ea90a8..5bfb47f7e45d 100644 --- a/toolchain/check/testdata/impl/fail_call_invalid.carbon +++ b/toolchain/check/testdata/impl/fail_call_invalid.carbon @@ -96,7 +96,8 @@ fn InstanceCall(n: i32) { // CHECK:STDOUT: witness = %.1 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @G.1[@Simple.%self.loc12_8.2: %Self](); +// CHECK:STDOUT: fn @G.1[@Simple.%self.loc12_8.2: %Self]() +// CHECK:STDOUT: generic [@Simple.%Self: %.1]; // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/impl/fail_extend_impl_forall.carbon b/toolchain/check/testdata/impl/fail_extend_impl_forall.carbon index 53cde3453480..d072bcae284e 100644 --- a/toolchain/check/testdata/impl/fail_extend_impl_forall.carbon +++ b/toolchain/check/testdata/impl/fail_extend_impl_forall.carbon @@ -99,9 +99,11 @@ class C { // CHECK:STDOUT: has_error // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1(@GenericInterface.%x.loc12_8.2: %T); +// CHECK:STDOUT: fn @F.1(@GenericInterface.%x.loc12_8.2: %T) +// CHECK:STDOUT: generic [file.%T.loc11_28.2: type, @GenericInterface.%Self: %GenericInterface]; // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.2(@impl.%x.loc20_10.2: %T) { +// CHECK:STDOUT: fn @F.2(@impl.%x.loc20_10.2: %T) +// CHECK:STDOUT: generic [@C.%T.loc19_23.2: type] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/impl/fail_impl_as_scope.carbon b/toolchain/check/testdata/impl/fail_impl_as_scope.carbon index c6650edcfa15..bbde55d042cf 100644 --- a/toolchain/check/testdata/impl/fail_impl_as_scope.carbon +++ b/toolchain/check/testdata/impl/fail_impl_as_scope.carbon @@ -66,7 +66,8 @@ impl as Simple { // CHECK:STDOUT: witness = %.1 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1(); +// CHECK:STDOUT: fn @F.1() +// CHECK:STDOUT: generic [@Simple.%Self: %.1]; // CHECK:STDOUT: // CHECK:STDOUT: fn @F.2() { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/impl/fail_impl_bad_assoc_fn.carbon b/toolchain/check/testdata/impl/fail_impl_bad_assoc_fn.carbon index 42b48845a1df..f4813254a47f 100644 --- a/toolchain/check/testdata/impl/fail_impl_bad_assoc_fn.carbon +++ b/toolchain/check/testdata/impl/fail_impl_bad_assoc_fn.carbon @@ -844,7 +844,8 @@ class SelfNestedBadReturnType { // CHECK:STDOUT: .Self = constants.%SelfNestedBadReturnType // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1(); +// CHECK:STDOUT: fn @F.1() +// CHECK:STDOUT: generic [@I.%Self: %.1]; // CHECK:STDOUT: // CHECK:STDOUT: fn @PossiblyF(); // CHECK:STDOUT: @@ -856,7 +857,8 @@ class SelfNestedBadReturnType { // CHECK:STDOUT: // CHECK:STDOUT: fn @F.4() -> bool; // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.5[@J.%self.loc93_20.2: bool](@J.%b.loc93_32.2: bool) -> bool; +// CHECK:STDOUT: fn @F.5[@J.%self.loc93_20.2: bool](@J.%b.loc93_32.2: bool) -> bool +// CHECK:STDOUT: generic [@J.%Self: %.6]; // CHECK:STDOUT: // CHECK:STDOUT: fn @F.6[@impl.7.%self.loc104_10.2: bool]() -> bool; // CHECK:STDOUT: @@ -874,7 +876,8 @@ class SelfNestedBadReturnType { // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.13(@SelfNested.%x.loc188_8.2: %.13) -> %.15; +// CHECK:STDOUT: fn @F.13(@SelfNested.%x.loc188_8.2: %.13) -> %.15 +// CHECK:STDOUT: generic [@SelfNested.%Self: %.9]; // CHECK:STDOUT: // CHECK:STDOUT: fn @F.14(@impl.14.%x.loc200_10.2: %.20) -> %.21; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/impl/impl_as.carbon b/toolchain/check/testdata/impl/impl_as.carbon index 283e3af4bb14..ae9a46bfbc37 100644 --- a/toolchain/check/testdata/impl/impl_as.carbon +++ b/toolchain/check/testdata/impl/impl_as.carbon @@ -80,7 +80,8 @@ class C { // CHECK:STDOUT: .Self = constants.%C // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1(); +// CHECK:STDOUT: fn @F.1() +// CHECK:STDOUT: generic [@Simple.%Self: %.1]; // CHECK:STDOUT: // CHECK:STDOUT: fn @F.2() { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/impl/impl_forall.carbon b/toolchain/check/testdata/impl/impl_forall.carbon index c3a67fc05e0d..46548e357483 100644 --- a/toolchain/check/testdata/impl/impl_forall.carbon +++ b/toolchain/check/testdata/impl/impl_forall.carbon @@ -67,9 +67,11 @@ impl forall [T:! type] T as Simple { // CHECK:STDOUT: witness = %.1 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1(); +// CHECK:STDOUT: fn @F.1() +// CHECK:STDOUT: generic [@Simple.%Self: %.1]; // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.2() { +// CHECK:STDOUT: fn @F.2() +// CHECK:STDOUT: generic [file.%T.loc15_14.2: type] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/impl/lookup/alias.carbon b/toolchain/check/testdata/impl/lookup/alias.carbon index fb8f2bc4fee3..975659e6ebe6 100644 --- a/toolchain/check/testdata/impl/lookup/alias.carbon +++ b/toolchain/check/testdata/impl/lookup/alias.carbon @@ -96,7 +96,8 @@ fn G(c: C) { // CHECK:STDOUT: .G = %G // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1(); +// CHECK:STDOUT: fn @F.1() +// CHECK:STDOUT: generic [@HasF.%Self: %.1]; // CHECK:STDOUT: // CHECK:STDOUT: fn @F.2() { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/impl/lookup/fail_alias_impl_not_found.carbon b/toolchain/check/testdata/impl/lookup/fail_alias_impl_not_found.carbon index 9733947d94b0..8df409ffe6c8 100644 --- a/toolchain/check/testdata/impl/lookup/fail_alias_impl_not_found.carbon +++ b/toolchain/check/testdata/impl/lookup/fail_alias_impl_not_found.carbon @@ -83,7 +83,8 @@ fn F(c: C) { // CHECK:STDOUT: .F = %F // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1(); +// CHECK:STDOUT: fn @F.1() +// CHECK:STDOUT: generic [@I.%Self: %.1]; // CHECK:STDOUT: // CHECK:STDOUT: fn @F.2(%c: %C) { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/impl/lookup/fail_todo_undefined_impl.carbon b/toolchain/check/testdata/impl/lookup/fail_todo_undefined_impl.carbon index 1ce85dc0c2b4..583cda943e2b 100644 --- a/toolchain/check/testdata/impl/lookup/fail_todo_undefined_impl.carbon +++ b/toolchain/check/testdata/impl/lookup/fail_todo_undefined_impl.carbon @@ -102,7 +102,8 @@ impl C as I { // CHECK:STDOUT: extend name_scope2 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1(); +// CHECK:STDOUT: fn @F.1() +// CHECK:STDOUT: generic [@I.%Self: %.1]; // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/impl/lookup/import.carbon b/toolchain/check/testdata/impl/lookup/import.carbon index 3e3348fcc0a7..5fa0354d0ba7 100644 --- a/toolchain/check/testdata/impl/lookup/import.carbon +++ b/toolchain/check/testdata/impl/lookup/import.carbon @@ -87,7 +87,8 @@ fn G(c: Impl.C) { // CHECK:STDOUT: .Self = constants.%C // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1(); +// CHECK:STDOUT: fn @F.1() +// CHECK:STDOUT: generic [@HasF.%Self: %.1]; // CHECK:STDOUT: // CHECK:STDOUT: fn @F.2() { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/impl/lookup/instance_method.carbon b/toolchain/check/testdata/impl/lookup/instance_method.carbon index 53e313debdb2..67f06b8d5a4a 100644 --- a/toolchain/check/testdata/impl/lookup/instance_method.carbon +++ b/toolchain/check/testdata/impl/lookup/instance_method.carbon @@ -121,7 +121,8 @@ fn F(c: C) -> i32 { // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1[@I.%self.loc14_8.2: %Self]() -> i32; +// CHECK:STDOUT: fn @F.1[@I.%self.loc14_8.2: %Self]() -> i32 +// CHECK:STDOUT: generic [@I.%Self: %.1]; // CHECK:STDOUT: // CHECK:STDOUT: fn @F.2[@impl.%self.loc19_10.2: %C]() -> i32; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/impl/lookup/no_prelude/import.carbon b/toolchain/check/testdata/impl/lookup/no_prelude/import.carbon index a219cdcee38e..392e71173335 100644 --- a/toolchain/check/testdata/impl/lookup/no_prelude/import.carbon +++ b/toolchain/check/testdata/impl/lookup/no_prelude/import.carbon @@ -85,7 +85,8 @@ fn G(c: Impl.C) { // CHECK:STDOUT: .Self = constants.%C // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1(); +// CHECK:STDOUT: fn @F.1() +// CHECK:STDOUT: generic [@HasF.%Self: %.1]; // CHECK:STDOUT: // CHECK:STDOUT: fn @F.2() { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/impl/no_prelude/basic.carbon b/toolchain/check/testdata/impl/no_prelude/basic.carbon index ced230f49ccb..12ade12b81a2 100644 --- a/toolchain/check/testdata/impl/no_prelude/basic.carbon +++ b/toolchain/check/testdata/impl/no_prelude/basic.carbon @@ -73,7 +73,8 @@ impl C as Simple { // CHECK:STDOUT: .Self = constants.%C // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1(); +// CHECK:STDOUT: fn @F.1() +// CHECK:STDOUT: generic [@Simple.%Self: %.1]; // CHECK:STDOUT: // CHECK:STDOUT: fn @F.2() { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/impl/no_prelude/import_self.carbon b/toolchain/check/testdata/impl/no_prelude/import_self.carbon index 16ede55feb11..4f2a7f62ffea 100644 --- a/toolchain/check/testdata/impl/no_prelude/import_self.carbon +++ b/toolchain/check/testdata/impl/no_prelude/import_self.carbon @@ -75,7 +75,8 @@ fn F(x: (), y: ()) -> () { // CHECK:STDOUT: witness = (%Op.decl) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op[@Add.%self.loc5_9.2: %Self](@Add.%other.loc5_21.2: %Self) -> %Self; +// CHECK:STDOUT: fn @Op[@Add.%self.loc5_9.2: %Self](@Add.%other.loc5_21.2: %Self) -> %Self +// CHECK:STDOUT: generic [@Add.%Self: %.1]; // CHECK:STDOUT: // CHECK:STDOUT: --- b.carbon // CHECK:STDOUT: diff --git a/toolchain/check/testdata/impl/no_prelude/self_in_class.carbon b/toolchain/check/testdata/impl/no_prelude/self_in_class.carbon index 93f160827cb4..72c8f17daefe 100644 --- a/toolchain/check/testdata/impl/no_prelude/self_in_class.carbon +++ b/toolchain/check/testdata/impl/no_prelude/self_in_class.carbon @@ -96,7 +96,8 @@ class A { // CHECK:STDOUT: .Self = constants.%A // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Make.1() -> %Self; +// CHECK:STDOUT: fn @Make.1() -> %Self +// CHECK:STDOUT: generic [@DefaultConstructible.%Self: %.1]; // CHECK:STDOUT: // CHECK:STDOUT: fn @Make.2() -> @impl.%return.var: %C { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/impl/no_prelude/self_in_signature.carbon b/toolchain/check/testdata/impl/no_prelude/self_in_signature.carbon index 3b464a1a2c35..a77ad9e15c17 100644 --- a/toolchain/check/testdata/impl/no_prelude/self_in_signature.carbon +++ b/toolchain/check/testdata/impl/no_prelude/self_in_signature.carbon @@ -249,7 +249,8 @@ impl D as SelfNested { // CHECK:STDOUT: .Self = constants.%D // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1[@UseSelf.%self.loc12_8.2: %Self.1](@UseSelf.%x.loc12_20.2: %Self.1) -> %Self.1; +// CHECK:STDOUT: fn @F.1[@UseSelf.%self.loc12_8.2: %Self.1](@UseSelf.%x.loc12_20.2: %Self.1) -> %Self.1 +// CHECK:STDOUT: generic [@UseSelf.%Self: %.1]; // CHECK:STDOUT: // CHECK:STDOUT: fn @F.2[@impl.1.%self.loc20_8.2: %C](@impl.1.%x.loc20_17.2: %C) -> @impl.1.%return.var: %C { // CHECK:STDOUT: !entry: @@ -267,7 +268,8 @@ impl D as SelfNested { // CHECK:STDOUT: return %.loc24_48 to @impl.2.%return.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.4(@SelfNested.%x.loc28_8.2: %.13); +// CHECK:STDOUT: fn @F.4(@SelfNested.%x.loc28_8.2: %.13) +// CHECK:STDOUT: generic [@SelfNested.%Self: %.9]; // CHECK:STDOUT: // CHECK:STDOUT: fn @F.5(@impl.3.%x.loc32_8.2: %.18); // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/fail_todo_define_default_fn_inline.carbon b/toolchain/check/testdata/interface/fail_todo_define_default_fn_inline.carbon index 89bb18e686b1..b79ba923d07e 100644 --- a/toolchain/check/testdata/interface/fail_todo_define_default_fn_inline.carbon +++ b/toolchain/check/testdata/interface/fail_todo_define_default_fn_inline.carbon @@ -80,12 +80,14 @@ interface Interface { // CHECK:STDOUT: witness = (%F.decl, %G.decl) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: fn @F() +// CHECK:STDOUT: generic [@Interface.%Self: %.1] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @G(@Interface.%a.loc21_16.2: i32, @Interface.%b.loc21_24.2: i32) -> i32 = "int.sadd"; +// CHECK:STDOUT: fn @G(@Interface.%a.loc21_16.2: i32, @Interface.%b.loc21_24.2: i32) -> i32 = "int.sadd" +// CHECK:STDOUT: generic [@Interface.%Self: %.1]; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/fail_todo_define_default_fn_out_of_line.carbon b/toolchain/check/testdata/interface/fail_todo_define_default_fn_out_of_line.carbon index 92e4438c1731..82672f3fb505 100644 --- a/toolchain/check/testdata/interface/fail_todo_define_default_fn_out_of_line.carbon +++ b/toolchain/check/testdata/interface/fail_todo_define_default_fn_out_of_line.carbon @@ -122,11 +122,13 @@ fn Interface.G(a: i32, b: i32) -> i32 = "int.sadd"; // CHECK:STDOUT: witness = (%F.decl, %G.decl) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(); +// CHECK:STDOUT: fn @F() +// CHECK:STDOUT: generic [@Interface.%Self: %.1]; // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @G(@Interface.%a.loc22_16.2: i32, @Interface.%b.loc22_24.2: i32) -> i32; +// CHECK:STDOUT: fn @G(@Interface.%a.loc22_16.2: i32, @Interface.%b.loc22_24.2: i32) -> i32 +// CHECK:STDOUT: generic [@Interface.%Self: %.1]; // CHECK:STDOUT: // CHECK:STDOUT: fn @.1() { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/interface/no_prelude/as_type_of_type.carbon b/toolchain/check/testdata/interface/no_prelude/as_type_of_type.carbon index f068af9bee07..f8ab906ee58f 100644 --- a/toolchain/check/testdata/interface/no_prelude/as_type_of_type.carbon +++ b/toolchain/check/testdata/interface/no_prelude/as_type_of_type.carbon @@ -46,7 +46,8 @@ fn F(T:! Empty) { // CHECK:STDOUT: witness = () // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(%T: %.1) { +// CHECK:STDOUT: fn @F(%T: %.1) +// CHECK:STDOUT: generic [%T: %.1] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %T.ref: %.1 = name_ref T, %T [symbolic = constants.%T] // CHECK:STDOUT: %.loc14_10.1: type = facet_type_access %T.ref [symbolic = constants.%T] diff --git a/toolchain/check/testdata/interface/no_prelude/basic.carbon b/toolchain/check/testdata/interface/no_prelude/basic.carbon index 7862ec213874..25bdcc082b45 100644 --- a/toolchain/check/testdata/interface/no_prelude/basic.carbon +++ b/toolchain/check/testdata/interface/no_prelude/basic.carbon @@ -60,5 +60,6 @@ interface ForwardDeclared { // CHECK:STDOUT: witness = (%F.decl) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(); +// CHECK:STDOUT: fn @F() +// CHECK:STDOUT: generic [@ForwardDeclared.%Self: %.2]; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/no_prelude/default_fn.carbon b/toolchain/check/testdata/interface/no_prelude/default_fn.carbon index 629d855785a6..201a7b2df67c 100644 --- a/toolchain/check/testdata/interface/no_prelude/default_fn.carbon +++ b/toolchain/check/testdata/interface/no_prelude/default_fn.carbon @@ -81,7 +81,8 @@ class C { // CHECK:STDOUT: .I = %I.decl // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1() { +// CHECK:STDOUT: fn @F.1() +// CHECK:STDOUT: generic [@I.%Self: %.1] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [template = constants.%C] // CHECK:STDOUT: %c.var: ref %C = var c diff --git a/toolchain/check/testdata/interface/no_prelude/fail_add_member_outside_definition.carbon b/toolchain/check/testdata/interface/no_prelude/fail_add_member_outside_definition.carbon index a8b258d08ac3..5c31aaf39860 100644 --- a/toolchain/check/testdata/interface/no_prelude/fail_add_member_outside_definition.carbon +++ b/toolchain/check/testdata/interface/no_prelude/fail_add_member_outside_definition.carbon @@ -94,7 +94,9 @@ interface Outer { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @.1(); +// CHECK:STDOUT: fn @.1() +// CHECK:STDOUT: generic [@Outer.%Self: %.3, @Inner.%Self: %.4]; // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.2(); +// CHECK:STDOUT: fn @F.2() +// CHECK:STDOUT: generic [@Outer.%Self: %.3]; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/no_prelude/fail_lookup_undefined.carbon b/toolchain/check/testdata/interface/no_prelude/fail_lookup_undefined.carbon index 5a9ec18e2110..8f03a04ad5da 100644 --- a/toolchain/check/testdata/interface/no_prelude/fail_lookup_undefined.carbon +++ b/toolchain/check/testdata/interface/no_prelude/fail_lookup_undefined.carbon @@ -107,7 +107,9 @@ interface BeingDefined { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @H() -> ; +// CHECK:STDOUT: fn @H() -> +// CHECK:STDOUT: generic [@BeingDefined.%Self: %.4]; // CHECK:STDOUT: -// CHECK:STDOUT: fn @.2(); +// CHECK:STDOUT: fn @.2() +// CHECK:STDOUT: generic [@BeingDefined.%Self: %.4]; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/no_prelude/fail_member_lookup.carbon b/toolchain/check/testdata/interface/no_prelude/fail_member_lookup.carbon index e58c67919590..a6f76d67a2bd 100644 --- a/toolchain/check/testdata/interface/no_prelude/fail_member_lookup.carbon +++ b/toolchain/check/testdata/interface/no_prelude/fail_member_lookup.carbon @@ -66,7 +66,8 @@ fn F() { // CHECK:STDOUT: witness = (%F.decl, %T) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1(); +// CHECK:STDOUT: fn @F.1() +// CHECK:STDOUT: generic [@Interface.%Self: %.1]; // CHECK:STDOUT: // CHECK:STDOUT: fn @F.2() { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/interface/no_prelude/fail_redeclare_member.carbon b/toolchain/check/testdata/interface/no_prelude/fail_redeclare_member.carbon index 8a31eb2f1145..cb7b0851cab8 100644 --- a/toolchain/check/testdata/interface/no_prelude/fail_redeclare_member.carbon +++ b/toolchain/check/testdata/interface/no_prelude/fail_redeclare_member.carbon @@ -52,7 +52,9 @@ interface Interface { // CHECK:STDOUT: witness = (%F.decl) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(); +// CHECK:STDOUT: fn @F() +// CHECK:STDOUT: generic [@Interface.%Self: %.1]; // CHECK:STDOUT: -// CHECK:STDOUT: fn @.1(); +// CHECK:STDOUT: fn @.1() +// CHECK:STDOUT: generic [@Interface.%Self: %.1]; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/no_prelude/fail_todo_facet_lookup.carbon b/toolchain/check/testdata/interface/no_prelude/fail_todo_facet_lookup.carbon index fd35cb19731c..7b176e5be3c2 100644 --- a/toolchain/check/testdata/interface/no_prelude/fail_todo_facet_lookup.carbon +++ b/toolchain/check/testdata/interface/no_prelude/fail_todo_facet_lookup.carbon @@ -77,16 +77,19 @@ fn CallFacet(T:! Interface, x: T) { // CHECK:STDOUT: witness = (%F.decl) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(); +// CHECK:STDOUT: fn @F() +// CHECK:STDOUT: generic [@Interface.%Self: %.1]; // CHECK:STDOUT: -// CHECK:STDOUT: fn @CallStatic(%T: %.1) { +// CHECK:STDOUT: fn @CallStatic(%T: %.1) +// CHECK:STDOUT: generic [%T: %.1] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %T.ref: %.1 = name_ref T, %T [symbolic = constants.%T] // CHECK:STDOUT: %F.ref: %.3 = name_ref F, @Interface.%.loc11 [template = constants.%.4] // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @CallFacet(%T: %.1, %x: %T) { +// CHECK:STDOUT: fn @CallFacet(%T: %.1, %x: %T) +// CHECK:STDOUT: generic [%T: %.1] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %x.ref: %T = name_ref x, %x // CHECK:STDOUT: return diff --git a/toolchain/check/testdata/interface/no_prelude/fail_todo_generic_default_fn.carbon b/toolchain/check/testdata/interface/no_prelude/fail_todo_generic_default_fn.carbon index fcbe183c4c9f..f91330e34883 100644 --- a/toolchain/check/testdata/interface/no_prelude/fail_todo_generic_default_fn.carbon +++ b/toolchain/check/testdata/interface/no_prelude/fail_todo_generic_default_fn.carbon @@ -90,9 +90,11 @@ fn I(T:! type).F[self: Self]() -> Self { return self; } // CHECK:STDOUT: witness = (%F.decl) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F[@I.%self.loc22_8.2: ]() -> ; +// CHECK:STDOUT: fn @F[@I.%self.loc22_8.2: ]() -> +// CHECK:STDOUT: generic [file.%T.loc11_13.2: type, @I.%Self: %I]; // CHECK:STDOUT: -// CHECK:STDOUT: fn @.1[%self: ]() -> { +// CHECK:STDOUT: fn @.1[%self: ]() -> +// CHECK:STDOUT: generic [file.%T.loc39_6.2: type] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %self.ref: = name_ref self, %self // CHECK:STDOUT: return diff --git a/toolchain/check/testdata/interface/no_prelude/fail_todo_modifiers.carbon b/toolchain/check/testdata/interface/no_prelude/fail_todo_modifiers.carbon index cb2df1b34a9c..3f9a2835bab1 100644 --- a/toolchain/check/testdata/interface/no_prelude/fail_todo_modifiers.carbon +++ b/toolchain/check/testdata/interface/no_prelude/fail_todo_modifiers.carbon @@ -57,12 +57,14 @@ interface Modifiers { // CHECK:STDOUT: witness = (%Final.decl, %Default.decl) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Final() { +// CHECK:STDOUT: fn @Final() +// CHECK:STDOUT: generic [@Modifiers.%Self: %.1] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Default() { +// CHECK:STDOUT: fn @Default() +// CHECK:STDOUT: generic [@Modifiers.%Self: %.1] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/interface/no_prelude/generic.carbon b/toolchain/check/testdata/interface/no_prelude/generic.carbon index 22968c08fb41..e3e9003f00f0 100644 --- a/toolchain/check/testdata/interface/no_prelude/generic.carbon +++ b/toolchain/check/testdata/interface/no_prelude/generic.carbon @@ -209,7 +209,8 @@ fn G(T:! Generic(B)) { // CHECK:STDOUT: .Self = constants.%C // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1() -> %X; +// CHECK:STDOUT: fn @F.1() -> %X +// CHECK:STDOUT: generic [file.%T.loc8_23.2: type, @WithAssocFn.%Self: %WithAssocFn]; // CHECK:STDOUT: // CHECK:STDOUT: fn @F.2() -> @impl.2.%return.var: %X { // CHECK:STDOUT: !entry: @@ -219,9 +220,11 @@ fn G(T:! Generic(B)) { // CHECK:STDOUT: return %.loc17_16 to @impl.2.%return.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Receive(%T: %.5); +// CHECK:STDOUT: fn @Receive(%T: %.5) +// CHECK:STDOUT: generic [%T: %.5]; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Pass(%T: %.5) { +// CHECK:STDOUT: fn @Pass(%T: %.5) +// CHECK:STDOUT: generic [%T: %.5] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Receive.ref: %Receive.type = name_ref Receive, file.%Receive.decl [template = constants.%Receive] // CHECK:STDOUT: %T.ref: %.5 = name_ref T, %T [symbolic = constants.%T.2] @@ -302,9 +305,11 @@ fn G(T:! Generic(B)) { // CHECK:STDOUT: .Self = constants.%B // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(%T: %.3); +// CHECK:STDOUT: fn @F(%T: %.3) +// CHECK:STDOUT: generic [%T: %.3]; // CHECK:STDOUT: -// CHECK:STDOUT: fn @G(%T: %.4) { +// CHECK:STDOUT: fn @G(%T: %.4) +// CHECK:STDOUT: generic [%T: %.4] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] // CHECK:STDOUT: %T.ref: %.4 = name_ref T, %T [symbolic = constants.%T.3] diff --git a/toolchain/check/testdata/interface/no_prelude/generic_binding_after_assoc_const.carbon b/toolchain/check/testdata/interface/no_prelude/generic_binding_after_assoc_const.carbon index 0ed1d8d6c42e..252f1cc1e35d 100644 --- a/toolchain/check/testdata/interface/no_prelude/generic_binding_after_assoc_const.carbon +++ b/toolchain/check/testdata/interface/no_prelude/generic_binding_after_assoc_const.carbon @@ -65,7 +65,9 @@ interface I { // CHECK:STDOUT: witness = (%F.decl, %U, %G.decl) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(@I.%T.loc12_8.2: type); +// CHECK:STDOUT: fn @F(@I.%T.loc12_8.2: type) +// CHECK:STDOUT: generic [@I.%Self: %.1, @I.%T.loc12_8.2: type]; // CHECK:STDOUT: -// CHECK:STDOUT: fn @G(@I.%T.loc16_8.2: type); +// CHECK:STDOUT: fn @G(@I.%T.loc16_8.2: type) +// CHECK:STDOUT: generic [@I.%Self: %.1, @I.%T.loc16_8.2: type]; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/no_prelude/generic_import.carbon b/toolchain/check/testdata/interface/no_prelude/generic_import.carbon index b696858fe7b6..dab3be7163a4 100644 --- a/toolchain/check/testdata/interface/no_prelude/generic_import.carbon +++ b/toolchain/check/testdata/interface/no_prelude/generic_import.carbon @@ -62,7 +62,8 @@ impl C as AddWith(C) { // CHECK:STDOUT: witness = (%F.decl) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(); +// CHECK:STDOUT: fn @F() +// CHECK:STDOUT: generic [file.%T.loc4_19.2: type, @AddWith.%Self: %AddWith]; // CHECK:STDOUT: // CHECK:STDOUT: --- b.carbon // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/no_prelude/import.carbon b/toolchain/check/testdata/interface/no_prelude/import.carbon index 1d50456ca740..aa553d3968f1 100644 --- a/toolchain/check/testdata/interface/no_prelude/import.carbon +++ b/toolchain/check/testdata/interface/no_prelude/import.carbon @@ -126,9 +126,11 @@ var f: ForwardDeclared* = &f_ref.f; // CHECK:STDOUT: witness = (%T, %F.decl) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1(); +// CHECK:STDOUT: fn @F.1() +// CHECK:STDOUT: generic [@Basic.%Self: %.2]; // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.2(); +// CHECK:STDOUT: fn @F.2() +// CHECK:STDOUT: generic [@ForwardDeclared.%Self: %.8]; // CHECK:STDOUT: // CHECK:STDOUT: --- b.carbon // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/no_prelude/self.carbon b/toolchain/check/testdata/interface/no_prelude/self.carbon index ddb193bae8ef..30205d46ba9c 100644 --- a/toolchain/check/testdata/interface/no_prelude/self.carbon +++ b/toolchain/check/testdata/interface/no_prelude/self.carbon @@ -52,5 +52,6 @@ interface UseSelf { // CHECK:STDOUT: witness = (%F.decl) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F[@UseSelf.%self.loc12_8.2: %Self]() -> %Self; +// CHECK:STDOUT: fn @F[@UseSelf.%self.loc12_8.2: %Self]() -> %Self +// CHECK:STDOUT: generic [@UseSelf.%Self: %.1]; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/todo_define_not_default.carbon b/toolchain/check/testdata/interface/todo_define_not_default.carbon index ceed03c73b7a..740a5c966407 100644 --- a/toolchain/check/testdata/interface/todo_define_not_default.carbon +++ b/toolchain/check/testdata/interface/todo_define_not_default.carbon @@ -106,12 +106,14 @@ interface I { // CHECK:STDOUT: witness = (%F.decl, %G.decl, %T, %N) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: fn @F() +// CHECK:STDOUT: generic [@I.%Self: %.1] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @G(@I.%a.loc14_8.2: i32, @I.%b.loc14_16.2: i32) -> i32 = "int.sadd"; +// CHECK:STDOUT: fn @G(@I.%a.loc14_8.2: i32, @I.%b.loc14_16.2: i32) -> i32 = "int.sadd" +// CHECK:STDOUT: generic [@I.%Self: %.1]; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/namespace/fail_params.carbon b/toolchain/check/testdata/namespace/fail_params.carbon index c5cd7df31c46..e8e4dd86581d 100644 --- a/toolchain/check/testdata/namespace/fail_params.carbon +++ b/toolchain/check/testdata/namespace/fail_params.carbon @@ -91,7 +91,8 @@ fn D(T:! type).F() {} // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @.1() { +// CHECK:STDOUT: fn @.1() +// CHECK:STDOUT: generic [file.%T.loc39_6.2: type] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/return/fail_let_in_type.carbon b/toolchain/check/testdata/return/fail_let_in_type.carbon index 8d87fe2e1c00..8fcea802f85a 100644 --- a/toolchain/check/testdata/return/fail_let_in_type.carbon +++ b/toolchain/check/testdata/return/fail_let_in_type.carbon @@ -54,7 +54,8 @@ fn FirstPerfectNumber() -> z { return 6; } // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @HalfDozen() -> %y { +// CHECK:STDOUT: fn @HalfDozen() -> %y +// CHECK:STDOUT: generic [: type] { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %.loc24: i32 = int_literal 6 [template = constants.%.2] // CHECK:STDOUT: return diff --git a/toolchain/sem_ir/BUILD b/toolchain/sem_ir/BUILD index 27194fb06fea..2faf056fbe34 100644 --- a/toolchain/sem_ir/BUILD +++ b/toolchain/sem_ir/BUILD @@ -94,6 +94,7 @@ cc_library( "copy_on_write_block.h", "file.h", "function.h", + "generic.h", "impl.h", "import_ir.h", "interface.h", diff --git a/toolchain/sem_ir/file.cpp b/toolchain/sem_ir/file.cpp index a016ce6c7c32..e0628745dbc0 100644 --- a/toolchain/sem_ir/file.cpp +++ b/toolchain/sem_ir/file.cpp @@ -140,6 +140,7 @@ auto File::OutputYaml(bool include_builtins) const -> Yaml::OutputMapping { map.Add("bind_names", bind_names_.OutputYaml()); map.Add("functions", functions_.OutputYaml()); map.Add("classes", classes_.OutputYaml()); + map.Add("generics", generics_.OutputYaml()); map.Add("types", types_.OutputYaml()); map.Add("type_blocks", type_blocks_.OutputYaml()); map.Add("insts", diff --git a/toolchain/sem_ir/file.h b/toolchain/sem_ir/file.h index 364ef825c30a..7b84bfe8761f 100644 --- a/toolchain/sem_ir/file.h +++ b/toolchain/sem_ir/file.h @@ -16,6 +16,7 @@ #include "toolchain/sem_ir/class.h" #include "toolchain/sem_ir/constant.h" #include "toolchain/sem_ir/function.h" +#include "toolchain/sem_ir/generic.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/impl.h" #include "toolchain/sem_ir/import_ir.h" @@ -128,6 +129,8 @@ class File : public Printable { } auto impls() -> ImplStore& { return impls_; } auto impls() const -> const ImplStore& { return impls_; } + auto generics() -> ValueStore& { return generics_; } + auto generics() const -> const ValueStore& { return generics_; } auto import_irs() -> ValueStore& { return import_irs_; } auto import_irs() const -> const ValueStore& { return import_irs_; @@ -208,6 +211,9 @@ class File : public Printable { // Storage for impls. ImplStore impls_; + // Storage for generics. + ValueStore generics_; + // Related IRs. There are some fixed entries at the start; see ImportIRId. ValueStore import_irs_; diff --git a/toolchain/sem_ir/formatter.cpp b/toolchain/sem_ir/formatter.cpp index c77696848ff8..0c85ad94e796 100644 --- a/toolchain/sem_ir/formatter.cpp +++ b/toolchain/sem_ir/formatter.cpp @@ -262,6 +262,11 @@ class Formatter { out_ << "\""; } + if (fn.generic_id.is_valid()) { + out_ << "\n "; + FormatGeneric(fn.generic_id); + } + if (!fn.body_block_ids.empty()) { out_ << ' '; OpenBrace(); @@ -281,6 +286,12 @@ class Formatter { } } + auto FormatGeneric(GenericId generic_id) -> void { + out_ << "generic ["; + FormatParamList(sem_ir_.generics().Get(generic_id).bindings_id); + out_ << "]"; + } + auto FormatParamList(InstBlockId param_refs_id) -> void { llvm::ListSeparator sep; for (InstId param_id : sem_ir_.inst_blocks().Get(param_refs_id)) { diff --git a/toolchain/sem_ir/function.h b/toolchain/sem_ir/function.h index d297514a5441..2bfae715a1fe 100644 --- a/toolchain/sem_ir/function.h +++ b/toolchain/sem_ir/function.h @@ -84,6 +84,8 @@ struct Function : public Printable { NameScopeId parent_scope_id; // The first declaration of the function. This is a FunctionDecl. InstId decl_id; + // If this is a generic function, information about the generic. + GenericId generic_id; // A block containing a single reference instruction per implicit parameter. InstBlockId implicit_param_refs_id; // A block containing a single reference instruction per parameter. diff --git a/toolchain/sem_ir/generic.h b/toolchain/sem_ir/generic.h new file mode 100644 index 000000000000..6508e70667cc --- /dev/null +++ b/toolchain/sem_ir/generic.h @@ -0,0 +1,34 @@ +// 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 + +#ifndef CARBON_TOOLCHAIN_SEM_IR_GENERIC_H_ +#define CARBON_TOOLCHAIN_SEM_IR_GENERIC_H_ + +#include "toolchain/sem_ir/ids.h" + +namespace Carbon::SemIR { + +// Information for a generic entity, such as a generic class, a generic +// interface, or generic function. +// +// Note that this includes both checked generics and template generics. +struct Generic : public Printable { + auto Print(llvm::raw_ostream& out) const -> void { + out << "{decl: " << decl_id << ", bindings: " << bindings_id << "}"; + } + + // The following members always have values, and do not change throughout the + // lifetime of the generic. + + // The first declaration of the generic entity. + InstId decl_id; + // A block containing the IDs of compile time bindings in this generic scope. + // The index in this block will match the `bind_index` in the name binding + // instruction's `BindNameInfo`. + InstBlockId bindings_id; +}; + +} // namespace Carbon::SemIR + +#endif // CARBON_TOOLCHAIN_SEM_IR_GENERIC_H_ diff --git a/toolchain/sem_ir/id_kind.h b/toolchain/sem_ir/id_kind.h index e4f76de0c8e8..b80b932d7245 100644 --- a/toolchain/sem_ir/id_kind.h +++ b/toolchain/sem_ir/id_kind.h @@ -121,9 +121,9 @@ using IdKind = TypeEnum< IntId, RealId, FloatId, StringLiteralValueId, // From sem_ir/id.h. InstId, ConstantId, BindNameId, CompileTimeBindIndex, FunctionId, ClassId, - InterfaceId, ImplId, ImportIRId, ImportIRInstId, LocId, BoolValue, IntKind, - NameId, NameScopeId, InstBlockId, TypeId, TypeBlockId, ElementIndex, - FloatKind>; + InterfaceId, ImplId, GenericId, ImportIRId, ImportIRInstId, LocId, + BoolValue, IntKind, NameId, NameScopeId, InstBlockId, TypeId, TypeBlockId, + ElementIndex, FloatKind>; } // namespace Carbon::SemIR diff --git a/toolchain/sem_ir/ids.h b/toolchain/sem_ir/ids.h index f93f2adb0911..053ecc5aac4f 100644 --- a/toolchain/sem_ir/ids.h +++ b/toolchain/sem_ir/ids.h @@ -21,6 +21,7 @@ class Inst; struct BindNameInfo; struct Class; struct Function; +struct Generic; struct ImportIR; struct ImportIRInst; struct Interface; @@ -283,6 +284,22 @@ struct ImplId : public IdBase, public Printable { constexpr ImplId ImplId::Invalid = ImplId(InvalidIndex); +// The ID of a generic. +struct GenericId : public IdBase, public Printable { + using ValueType = Generic; + + // An explicitly invalid ID. + static const GenericId Invalid; + + using IdBase::IdBase; + auto Print(llvm::raw_ostream& out) const -> void { + out << "generic"; + IdBase::Print(out); + } +}; + +constexpr GenericId GenericId::Invalid = GenericId(InvalidIndex); + // The ID of an IR within the set of imported IRs, both direct and indirect. struct ImportIRId : public IdBase, public Printable { using ValueType = ImportIR; diff --git a/toolchain/sem_ir/yaml_test.cpp b/toolchain/sem_ir/yaml_test.cpp index 17dffd6caae0..45dd839981d5 100644 --- a/toolchain/sem_ir/yaml_test.cpp +++ b/toolchain/sem_ir/yaml_test.cpp @@ -62,6 +62,7 @@ TEST(SemIRTest, YAML) { Pair("bind_names", Yaml::Mapping(SizeIs(1))), Pair("functions", Yaml::Mapping(SizeIs(1))), Pair("classes", Yaml::Mapping(SizeIs(0))), + Pair("generics", Yaml::Mapping(SizeIs(0))), Pair("types", Yaml::Mapping(Each(type_builtin))), Pair("type_blocks", Yaml::Mapping(SizeIs(Ge(1)))), Pair("insts",