From e7b0529957038d93f6c5223408f44401176e3185 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 26 Jun 2024 13:13:26 -0700 Subject: [PATCH] Create a `Generic` object to represent a generic. (#4081) Build a `Generic` object for generic functions. This object tracks the generic parameters that are in scope for the generic entity. Eventually it will track other information about the generic too. Add basic SemIR formatting support for generic functions. --- toolchain/check/context.cpp | 1 + toolchain/check/context.h | 3 + toolchain/check/handle_binding_pattern.cpp | 22 ++- toolchain/check/handle_function.cpp | 29 ++- toolchain/check/handle_interface.cpp | 1 + toolchain/check/import_ref.cpp | 3 + toolchain/check/scope_stack.cpp | 57 +++++- toolchain/check/scope_stack.h | 42 ++++- .../check/testdata/array/generic_empty.carbon | 3 +- .../testdata/basics/builtin_insts.carbon | 1 + .../multifile_raw_and_textual_ir.carbon | 2 + .../basics/no_prelude/multifile_raw_ir.carbon | 2 + .../no_prelude/raw_and_textual_ir.carbon | 1 + .../testdata/basics/no_prelude/raw_ir.carbon | 175 +++++++++--------- .../builtins/int/make_type_signed.carbon | 3 +- .../builtins/int/make_type_unsigned.carbon | 3 +- .../testdata/class/fail_generic_method.carbon | 6 +- .../check/testdata/class/generic/basic.carbon | 6 +- .../class/generic/fail_todo_use.carbon | 3 +- .../testdata/class/generic/import.carbon | 3 +- .../class/generic/member_inline.carbon | 3 +- .../class/generic/member_out_of_line.carbon | 24 ++- .../testdata/class/generic_method.carbon | 3 +- .../check/testdata/eval/fail_symbolic.carbon | 3 +- toolchain/check/testdata/eval/symbolic.carbon | 3 +- .../testdata/function/builtin/method.carbon | 3 +- .../no_prelude/call_from_operator.carbon | 3 +- .../generic/fail_todo_param_in_type.carbon | 3 +- .../fail_type_param_mismatch.carbon | 3 +- .../generic/no_prelude/type_param.carbon | 3 +- .../no_prelude/type_param_scope.carbon | 3 +- .../function/generic/redeclare.carbon | 21 ++- toolchain/check/testdata/impl/compound.carbon | 6 +- .../check/testdata/impl/extend_impl.carbon | 3 +- .../testdata/impl/fail_call_invalid.carbon | 3 +- .../impl/fail_extend_impl_forall.carbon | 6 +- .../testdata/impl/fail_impl_as_scope.carbon | 3 +- .../impl/fail_impl_bad_assoc_fn.carbon | 9 +- toolchain/check/testdata/impl/impl_as.carbon | 3 +- .../check/testdata/impl/impl_forall.carbon | 6 +- .../check/testdata/impl/lookup/alias.carbon | 3 +- .../lookup/fail_alias_impl_not_found.carbon | 3 +- .../lookup/fail_todo_undefined_impl.carbon | 3 +- .../check/testdata/impl/lookup/import.carbon | 3 +- .../impl/lookup/instance_method.carbon | 3 +- .../impl/lookup/no_prelude/import.carbon | 3 +- .../testdata/impl/no_prelude/basic.carbon | 3 +- .../impl/no_prelude/import_self.carbon | 3 +- .../impl/no_prelude/self_in_class.carbon | 3 +- .../impl/no_prelude/self_in_signature.carbon | 6 +- .../fail_todo_define_default_fn_inline.carbon | 6 +- ..._todo_define_default_fn_out_of_line.carbon | 6 +- .../no_prelude/as_type_of_type.carbon | 3 +- .../interface/no_prelude/basic.carbon | 3 +- .../interface/no_prelude/default_fn.carbon | 3 +- .../fail_add_member_outside_definition.carbon | 6 +- .../no_prelude/fail_lookup_undefined.carbon | 6 +- .../no_prelude/fail_member_lookup.carbon | 3 +- .../no_prelude/fail_redeclare_member.carbon | 6 +- .../no_prelude/fail_todo_facet_lookup.carbon | 9 +- .../fail_todo_generic_default_fn.carbon | 6 +- .../no_prelude/fail_todo_modifiers.carbon | 6 +- .../interface/no_prelude/generic.carbon | 15 +- .../generic_binding_after_assoc_const.carbon | 6 +- .../no_prelude/generic_import.carbon | 3 +- .../interface/no_prelude/import.carbon | 6 +- .../testdata/interface/no_prelude/self.carbon | 3 +- .../interface/todo_define_not_default.carbon | 6 +- .../testdata/namespace/fail_params.carbon | 3 +- .../testdata/return/fail_let_in_type.carbon | 3 +- toolchain/sem_ir/BUILD | 1 + toolchain/sem_ir/file.cpp | 1 + toolchain/sem_ir/file.h | 6 + toolchain/sem_ir/formatter.cpp | 11 ++ toolchain/sem_ir/function.h | 2 + toolchain/sem_ir/generic.h | 34 ++++ toolchain/sem_ir/id_kind.h | 6 +- toolchain/sem_ir/ids.h | 17 ++ toolchain/sem_ir/yaml_test.cpp | 1 + 79 files changed, 491 insertions(+), 209 deletions(-) create mode 100644 toolchain/sem_ir/generic.h 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",