diff --git a/toolchain/check/generic.cpp b/toolchain/check/generic.cpp index f502ee9bccf84..b7bb57afc51c3 100644 --- a/toolchain/check/generic.cpp +++ b/toolchain/check/generic.cpp @@ -295,6 +295,10 @@ auto RebuildGenericEvalBlock(Context& context, SemIR::GenericId generic_id, return context.inst_block_stack().Pop(); } +auto DiscardGenericDecl(Context& context) -> void { + context.generic_region_stack().Pop(); +} + auto FinishGenericDecl(Context& context, SemIR::InstId decl_id) -> SemIR::GenericId { auto all_bindings = diff --git a/toolchain/check/generic.h b/toolchain/check/generic.h index a0d4c22814820..85d5f9f12343f 100644 --- a/toolchain/check/generic.h +++ b/toolchain/check/generic.h @@ -16,6 +16,11 @@ auto StartGenericDecl(Context& context) -> void; // Start processing a declaration or definition that might be a generic entity. auto StartGenericDefinition(Context& context) -> void; +// Discard the information about the current generic entity. This should be +// called instead of `FinishGenericDecl` if the corresponding `Generic` object +// would not actually be used, or when recovering from an error. +auto DiscardGenericDecl(Context& context) -> void; + // Finish processing a potentially generic declaration and produce a // corresponding generic object. Returns SemIR::GenericId::Invalid if this // declaration is not actually generic. diff --git a/toolchain/check/handle_where.cpp b/toolchain/check/handle_where.cpp index 5f229bfc58839..31a3f790ca9c3 100644 --- a/toolchain/check/handle_where.cpp +++ b/toolchain/check/handle_where.cpp @@ -4,6 +4,7 @@ #include "toolchain/check/context.h" #include "toolchain/check/convert.h" +#include "toolchain/check/generic.h" #include "toolchain/check/handle.h" namespace Carbon::Check { @@ -22,6 +23,8 @@ auto HandleParseNode(Context& context, Parse::WhereOperandId /*node_id*/) // Introduce a name scope so that we can remove the `.Self` entry we are // adding to name lookup at the end of the `where` expression. context.scope_stack().Push(); + // Create a generic region containing `.Self` and the constraints. + StartGenericDecl(context); // Introduce `.Self` as a symbolic binding. Its type is the value of the // expression to the left of `where`, so `MyInterface` in the example above. // Because there is no equivalent non-symbolic value, we use `Invalid` as @@ -74,6 +77,9 @@ auto HandleParseNode(Context& /*context*/, Parse::RequirementAndId /*node_id*/) } auto HandleParseNode(Context& context, Parse::WhereExprId /*node_id*/) -> bool { + // Discard the generic region containing `.Self` and the constraints. + // TODO: Decide if we want to build a `Generic` object for this. + DiscardGenericDecl(context); // Remove `PeriodSelf` from name lookup, undoing the `Push` done for the // `WhereOperand`. context.scope_stack().Pop(); diff --git a/toolchain/check/testdata/where_expr/constraints.carbon b/toolchain/check/testdata/where_expr/constraints.carbon index 3ce5e1b4cee55..1f7a78fbf524f 100644 --- a/toolchain/check/testdata/where_expr/constraints.carbon +++ b/toolchain/check/testdata/where_expr/constraints.carbon @@ -138,8 +138,8 @@ fn NotEmptyStruct() { // CHECK:STDOUT: %T.patt: %.2 = symbolic_binding_pattern T 0 // CHECK:STDOUT: } { // CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [template = constants.%.2] -// CHECK:STDOUT: %.Self.1: %.2 = bind_symbolic_name .Self 0 [symbolic = %.Self.2 (constants.%.Self.1)] -// CHECK:STDOUT: %.Self.ref: %.2 = name_ref .Self, %.Self.1 [symbolic = %.Self.2 (constants.%.Self.1)] +// CHECK:STDOUT: %.Self: %.2 = bind_symbolic_name .Self 0 [symbolic = constants.%.Self.1] +// CHECK:STDOUT: %.Self.ref: %.2 = name_ref .Self, %.Self [symbolic = constants.%.Self.1] // CHECK:STDOUT: %Member.ref: %.3 = name_ref Member, @I.%.loc7 [template = constants.%.4] // CHECK:STDOUT: %.loc11: %.8 = struct_literal () // CHECK:STDOUT: %T.param: %.2 = param T, runtime_param @@ -149,8 +149,8 @@ fn NotEmptyStruct() { // CHECK:STDOUT: %U.patt: %.2 = symbolic_binding_pattern U 0 // CHECK:STDOUT: } { // CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [template = constants.%.2] -// CHECK:STDOUT: %.Self.1: %.2 = bind_symbolic_name .Self 0 [symbolic = %.Self.2 (constants.%.Self.1)] -// CHECK:STDOUT: %.Self.ref: %.2 = name_ref .Self, %.Self.1 [symbolic = %.Self.2 (constants.%.Self.1)] +// CHECK:STDOUT: %.Self: %.2 = bind_symbolic_name .Self 0 [symbolic = constants.%.Self.1] +// CHECK:STDOUT: %.Self.ref: %.2 = name_ref .Self, %.Self [symbolic = constants.%.Self.1] // CHECK:STDOUT: %.loc13: %.5 = tuple_literal () // CHECK:STDOUT: %U.param: %.2 = param U, runtime_param // CHECK:STDOUT: %U.loc13: %.2 = bind_symbolic_name U 0, %U.param [symbolic = %U.1 (constants.%U)] @@ -159,8 +159,8 @@ fn NotEmptyStruct() { // CHECK:STDOUT: %V.patt: %.1 = symbolic_binding_pattern V 0 // CHECK:STDOUT: } { // CHECK:STDOUT: %J.ref: type = name_ref J, file.%J.decl [template = constants.%.1] -// CHECK:STDOUT: %.Self.1: %.1 = bind_symbolic_name .Self 0 [symbolic = %.Self.2 (constants.%.Self.2)] -// CHECK:STDOUT: %.Self.ref: %.1 = name_ref .Self, %.Self.1 [symbolic = %.Self.2 (constants.%.Self.2)] +// CHECK:STDOUT: %.Self: %.1 = bind_symbolic_name .Self 0 [symbolic = constants.%.Self.2] +// CHECK:STDOUT: %.Self.ref: %.1 = name_ref .Self, %.Self [symbolic = constants.%.Self.2] // CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [template = constants.%.2] // CHECK:STDOUT: %V.param: %.1 = param V, runtime_param // CHECK:STDOUT: %V.loc15: %.1 = bind_symbolic_name V 0, %V.param [symbolic = %V.1 (constants.%V)] @@ -169,13 +169,13 @@ fn NotEmptyStruct() { // CHECK:STDOUT: %W.patt: %.2 = symbolic_binding_pattern W 0 // CHECK:STDOUT: } { // CHECK:STDOUT: %I.ref.loc17_12: type = name_ref I, file.%I.decl [template = constants.%.2] -// CHECK:STDOUT: %.Self.1: %.2 = bind_symbolic_name .Self 0 [symbolic = %.Self.2 (constants.%.Self.1)] -// CHECK:STDOUT: %.Self.ref.loc17_20: %.2 = name_ref .Self, %.Self.1 [symbolic = %.Self.2 (constants.%.Self.1)] +// CHECK:STDOUT: %.Self: %.2 = bind_symbolic_name .Self 0 [symbolic = constants.%.Self.1] +// CHECK:STDOUT: %.Self.ref.loc17_20: %.2 = name_ref .Self, %.Self [symbolic = constants.%.Self.1] // CHECK:STDOUT: %Second.ref.loc17_20: %.6 = name_ref Second, @I.%.loc8 [template = constants.%.7] // CHECK:STDOUT: %I.ref.loc17_34: type = name_ref I, file.%I.decl [template = constants.%.2] -// CHECK:STDOUT: %.Self.ref.loc17_40: %.2 = name_ref .Self, %.Self.1 [symbolic = %.Self.2 (constants.%.Self.1)] +// CHECK:STDOUT: %.Self.ref.loc17_40: %.2 = name_ref .Self, %.Self [symbolic = constants.%.Self.1] // CHECK:STDOUT: %Member.ref: %.3 = name_ref Member, @I.%.loc7 [template = constants.%.4] -// CHECK:STDOUT: %.Self.ref.loc17_50: %.2 = name_ref .Self, %.Self.1 [symbolic = %.Self.2 (constants.%.Self.1)] +// CHECK:STDOUT: %.Self.ref.loc17_50: %.2 = name_ref .Self, %.Self [symbolic = constants.%.Self.1] // CHECK:STDOUT: %Second.ref.loc17_50: %.6 = name_ref Second, @I.%.loc8 [template = constants.%.7] // CHECK:STDOUT: %W.param: %.2 = param W, runtime_param // CHECK:STDOUT: %W.loc17: %.2 = bind_symbolic_name W 0, %W.param [symbolic = %W.1 (constants.%W)] @@ -206,50 +206,42 @@ fn NotEmptyStruct() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic fn @Equal(%T.loc11: %.2) { -// CHECK:STDOUT: %.Self.2: %.2 = bind_symbolic_name .Self 0 [symbolic = %.Self.2 (constants.%.Self.1)] // CHECK:STDOUT: %T.1: %.2 = bind_symbolic_name T 0 [symbolic = %T.1 (constants.%T)] // CHECK:STDOUT: // CHECK:STDOUT: fn(%T.loc11: %.2); // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic fn @EqualEqual(%U.loc13: %.2) { -// CHECK:STDOUT: %.Self.2: %.2 = bind_symbolic_name .Self 0 [symbolic = %.Self.2 (constants.%.Self.1)] // CHECK:STDOUT: %U.1: %.2 = bind_symbolic_name U 0 [symbolic = %U.1 (constants.%U)] // CHECK:STDOUT: // CHECK:STDOUT: fn(%U.loc13: %.2); // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic fn @Impls(%V.loc15: %.1) { -// CHECK:STDOUT: %.Self.2: %.1 = bind_symbolic_name .Self 0 [symbolic = %.Self.2 (constants.%.Self.2)] // CHECK:STDOUT: %V.1: %.1 = bind_symbolic_name V 0 [symbolic = %V.1 (constants.%V)] // CHECK:STDOUT: // CHECK:STDOUT: fn(%V.loc15: %.1); // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic fn @And(%W.loc17: %.2) { -// CHECK:STDOUT: %.Self.2: %.2 = bind_symbolic_name .Self 0 [symbolic = %.Self.2 (constants.%.Self.1)] // CHECK:STDOUT: %W.1: %.2 = bind_symbolic_name W 0 [symbolic = %W.1 (constants.%W)] // CHECK:STDOUT: // CHECK:STDOUT: fn(%W.loc17: %.2); // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Equal(constants.%T) { -// CHECK:STDOUT: %.Self.2 => constants.%T // CHECK:STDOUT: %T.1 => constants.%T // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @EqualEqual(constants.%U) { -// CHECK:STDOUT: %.Self.2 => constants.%U // CHECK:STDOUT: %U.1 => constants.%U // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Impls(constants.%V) { -// CHECK:STDOUT: %.Self.2 => constants.%V // CHECK:STDOUT: %V.1 => constants.%V // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @And(constants.%W) { -// CHECK:STDOUT: %.Self.2 => constants.%W // CHECK:STDOUT: %W.1 => constants.%W // CHECK:STDOUT: } // CHECK:STDOUT: @@ -272,9 +264,9 @@ fn NotEmptyStruct() { // CHECK:STDOUT: %import_ref.1 = import_ref Main//state_constraints, inst+3, unloaded // CHECK:STDOUT: %import_ref.2: type = import_ref Main//state_constraints, inst+7, loaded [template = constants.%.1] // CHECK:STDOUT: %import_ref.3 = import_ref Main//state_constraints, inst+32, unloaded -// CHECK:STDOUT: %import_ref.4 = import_ref Main//state_constraints, inst+45, unloaded -// CHECK:STDOUT: %import_ref.5 = import_ref Main//state_constraints, inst+59, unloaded -// CHECK:STDOUT: %import_ref.6 = import_ref Main//state_constraints, inst+77, unloaded +// CHECK:STDOUT: %import_ref.4 = import_ref Main//state_constraints, inst+44, unloaded +// CHECK:STDOUT: %import_ref.5 = import_ref Main//state_constraints, inst+57, unloaded +// CHECK:STDOUT: %import_ref.6 = import_ref Main//state_constraints, inst+74, unloaded // CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { // CHECK:STDOUT: import Core//prelude // CHECK:STDOUT: import Core//prelude/operators @@ -310,8 +302,8 @@ fn NotEmptyStruct() { // CHECK:STDOUT: %X.patt: %.1 = symbolic_binding_pattern X 0 // CHECK:STDOUT: } { // CHECK:STDOUT: %I.ref: type = name_ref I, imports.%import_ref.2 [template = constants.%.1] -// CHECK:STDOUT: %.Self.1: %.1 = bind_symbolic_name .Self 0 [symbolic = %.Self.2 (constants.%.Self)] -// CHECK:STDOUT: %.Self.ref: %.1 = name_ref .Self, %.Self.1 [symbolic = %.Self.2 (constants.%.Self)] +// CHECK:STDOUT: %.Self: %.1 = bind_symbolic_name .Self 0 [symbolic = constants.%.Self] +// CHECK:STDOUT: %.Self.ref: %.1 = name_ref .Self, %.Self [symbolic = constants.%.Self] // CHECK:STDOUT: %Member.ref: %.3 = name_ref Member, imports.%import_ref.8 [template = constants.%.4] // CHECK:STDOUT: %.loc8: i32 = int_literal 2 [template = constants.%.5] // CHECK:STDOUT: %X.param: %.1 = param X, runtime_param @@ -328,14 +320,12 @@ fn NotEmptyStruct() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic fn @TypeMismatch(%X.loc8: %.1) { -// CHECK:STDOUT: %.Self.2: %.1 = bind_symbolic_name .Self 0 [symbolic = %.Self.2 (constants.%.Self)] // CHECK:STDOUT: %X.1: %.1 = bind_symbolic_name X 0 [symbolic = %X.1 (constants.%X)] // CHECK:STDOUT: // CHECK:STDOUT: fn(%X.loc8: %.1); // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @TypeMismatch(constants.%X) { -// CHECK:STDOUT: %.Self.2 => constants.%X // CHECK:STDOUT: %X.1 => constants.%X // CHECK:STDOUT: } // CHECK:STDOUT: @@ -354,7 +344,6 @@ fn NotEmptyStruct() { // CHECK:STDOUT: %Impls.type: type = fn_type @Impls [template] // CHECK:STDOUT: %Impls: %Impls.type = struct_value () [template] // CHECK:STDOUT: %V: %.3 = bind_symbolic_name V 0 [symbolic] -// CHECK:STDOUT: %.Self.1: %.3 = bind_symbolic_name .Self 0 [symbolic] // CHECK:STDOUT: %ImplicitAs.type: type = generic_interface_type @ImplicitAs [template] // CHECK:STDOUT: %ImplicitAs: %ImplicitAs.type = struct_value () [template] // CHECK:STDOUT: %Dest: type = bind_symbolic_name Dest 0 [symbolic] @@ -371,7 +360,7 @@ fn NotEmptyStruct() { // CHECK:STDOUT: %.10: type = assoc_entity_type %.9, %Convert.type.2 [template] // CHECK:STDOUT: %.11: %.10 = assoc_entity element0, imports.%import_ref.12 [template] // CHECK:STDOUT: %.12: %.7 = assoc_entity element0, imports.%import_ref.13 [symbolic] -// CHECK:STDOUT: %.Self.2: %.3 = bind_symbolic_name .Self 0 [symbolic] +// CHECK:STDOUT: %.Self: %.3 = bind_symbolic_name .Self 0 [symbolic] // CHECK:STDOUT: %Y: %.3 = bind_symbolic_name Y 0 [symbolic] // CHECK:STDOUT: %EmptyStruct.type: type = fn_type @EmptyStruct [template] // CHECK:STDOUT: %EmptyStruct: %EmptyStruct.type = struct_value () [template] @@ -383,9 +372,9 @@ fn NotEmptyStruct() { // CHECK:STDOUT: %import_ref.1: type = import_ref Main//state_constraints, inst+3, loaded [template = constants.%.3] // CHECK:STDOUT: %import_ref.2 = import_ref Main//state_constraints, inst+7, unloaded // CHECK:STDOUT: %import_ref.3 = import_ref Main//state_constraints, inst+32, unloaded -// CHECK:STDOUT: %import_ref.4 = import_ref Main//state_constraints, inst+45, unloaded -// CHECK:STDOUT: %import_ref.5: %Impls.type = import_ref Main//state_constraints, inst+59, loaded [template = constants.%Impls] -// CHECK:STDOUT: %import_ref.6 = import_ref Main//state_constraints, inst+77, unloaded +// CHECK:STDOUT: %import_ref.4 = import_ref Main//state_constraints, inst+44, unloaded +// CHECK:STDOUT: %import_ref.5: %Impls.type = import_ref Main//state_constraints, inst+57, loaded [template = constants.%Impls] +// CHECK:STDOUT: %import_ref.6 = import_ref Main//state_constraints, inst+74, unloaded // CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { // CHECK:STDOUT: .ImplicitAs = %import_ref.8 // CHECK:STDOUT: import Core//prelude @@ -432,8 +421,8 @@ fn NotEmptyStruct() { // CHECK:STDOUT: %Y.patt: %.3 = symbolic_binding_pattern Y 0 // CHECK:STDOUT: } { // CHECK:STDOUT: %J.ref: type = name_ref J, imports.%import_ref.1 [template = constants.%.3] -// CHECK:STDOUT: %.Self.1: %.3 = bind_symbolic_name .Self 0 [symbolic = %.Self.2 (constants.%.Self.2)] -// CHECK:STDOUT: %.Self.ref: %.3 = name_ref .Self, %.Self.1 [symbolic = %.Self.2 (constants.%.Self.2)] +// CHECK:STDOUT: %.Self: %.3 = bind_symbolic_name .Self 0 [symbolic = constants.%.Self] +// CHECK:STDOUT: %.Self.ref: %.3 = name_ref .Self, %.Self [symbolic = constants.%.Self] // CHECK:STDOUT: %.loc26: %.1 = struct_literal () // CHECK:STDOUT: %Y.param: %.3 = param Y, runtime_param // CHECK:STDOUT: %Y.loc26: %.3 = bind_symbolic_name Y 0, %Y.param [symbolic = %Y.1 (constants.%Y)] @@ -492,7 +481,6 @@ fn NotEmptyStruct() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic fn @Impls(constants.%V: %.3) { -// CHECK:STDOUT: %.Self: %.3 = bind_symbolic_name .Self 0 [symbolic = %.Self (constants.%.Self.1)] // CHECK:STDOUT: %V.2: %.3 = bind_symbolic_name V 0 [symbolic = %V.2 (constants.%V)] // CHECK:STDOUT: // CHECK:STDOUT: fn(%V.1: %.3); @@ -507,7 +495,6 @@ fn NotEmptyStruct() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic fn @EmptyStruct(%Y.loc26: %.3) { -// CHECK:STDOUT: %.Self.2: %.3 = bind_symbolic_name .Self 0 [symbolic = %.Self.2 (constants.%.Self.2)] // CHECK:STDOUT: %Y.1: %.3 = bind_symbolic_name Y 0 [symbolic = %Y.1 (constants.%Y)] // CHECK:STDOUT: // CHECK:STDOUT: fn(%Y.loc26: %.3); @@ -525,7 +512,6 @@ fn NotEmptyStruct() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Impls(constants.%V) { -// CHECK:STDOUT: %.Self => constants.%V // CHECK:STDOUT: %V.2 => constants.%V // CHECK:STDOUT: } // CHECK:STDOUT: @@ -560,7 +546,6 @@ fn NotEmptyStruct() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @EmptyStruct(constants.%Y) { -// CHECK:STDOUT: %.Self.2 => constants.%Y // CHECK:STDOUT: %Y.1 => constants.%Y // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/where_expr/no_prelude/designator.carbon b/toolchain/check/testdata/where_expr/no_prelude/designator.carbon index cfb7ff8d7e8f7..01771c6cc0eac 100644 --- a/toolchain/check/testdata/where_expr/no_prelude/designator.carbon +++ b/toolchain/check/testdata/where_expr/no_prelude/designator.carbon @@ -120,8 +120,8 @@ class D { // CHECK:STDOUT: %T.patt: %.1 = symbolic_binding_pattern T 0 // CHECK:STDOUT: } { // CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [template = constants.%.1] -// CHECK:STDOUT: %.Self.1: %.1 = bind_symbolic_name .Self 0 [symbolic = %.Self.2 (constants.%.Self.1)] -// CHECK:STDOUT: %.Self.ref: %.1 = name_ref .Self, %.Self.1 [symbolic = %.Self.2 (constants.%.Self.1)] +// CHECK:STDOUT: %.Self: %.1 = bind_symbolic_name .Self 0 [symbolic = constants.%.Self.1] +// CHECK:STDOUT: %.Self.ref: %.1 = name_ref .Self, %.Self [symbolic = constants.%.Self.1] // CHECK:STDOUT: %.loc8: %.4 = tuple_literal () // CHECK:STDOUT: %T.param: %.1 = param T, runtime_param // CHECK:STDOUT: %T.loc8: %.1 = bind_symbolic_name T 0, %T.param [symbolic = %T.1 (constants.%T)] @@ -130,8 +130,8 @@ class D { // CHECK:STDOUT: %U.patt: %.1 = symbolic_binding_pattern U 0 // CHECK:STDOUT: } { // CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [template = constants.%.1] -// CHECK:STDOUT: %.Self.1: %.1 = bind_symbolic_name .Self 0 [symbolic = %.Self.2 (constants.%.Self.1)] -// CHECK:STDOUT: %.Self.ref: %.1 = name_ref .Self, %.Self.1 [symbolic = %.Self.2 (constants.%.Self.1)] +// CHECK:STDOUT: %.Self: %.1 = bind_symbolic_name .Self 0 [symbolic = constants.%.Self.1] +// CHECK:STDOUT: %.Self.ref: %.1 = name_ref .Self, %.Self [symbolic = constants.%.Self.1] // CHECK:STDOUT: %Member.ref: %.2 = name_ref Member, @I.%.loc5 [template = constants.%.3] // CHECK:STDOUT: %.loc10: %.5 = struct_literal () // CHECK:STDOUT: %U.param: %.1 = param U, runtime_param @@ -140,8 +140,8 @@ class D { // CHECK:STDOUT: %TypeSelfImpls.decl: %TypeSelfImpls.type = fn_decl @TypeSelfImpls [template = constants.%TypeSelfImpls] { // CHECK:STDOUT: %V.patt: type = symbolic_binding_pattern V 0 // CHECK:STDOUT: } { -// CHECK:STDOUT: %.Self.1: type = bind_symbolic_name .Self 0 [symbolic = %.Self.2 (constants.%.Self.2)] -// CHECK:STDOUT: %.Self.ref: type = name_ref .Self, %.Self.1 [symbolic = %.Self.2 (constants.%.Self.2)] +// CHECK:STDOUT: %.Self: type = bind_symbolic_name .Self 0 [symbolic = constants.%.Self.2] +// CHECK:STDOUT: %.Self.ref: type = name_ref .Self, %.Self [symbolic = constants.%.Self.2] // CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [template = constants.%.1] // CHECK:STDOUT: %V.param: type = param V, runtime_param // CHECK:STDOUT: %V.loc12: type = bind_symbolic_name V 0, %V.param [symbolic = %V.1 (constants.%V)] @@ -160,38 +160,32 @@ class D { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic fn @PeriodSelf(%T.loc8: %.1) { -// CHECK:STDOUT: %.Self.2: %.1 = bind_symbolic_name .Self 0 [symbolic = %.Self.2 (constants.%.Self.1)] // CHECK:STDOUT: %T.1: %.1 = bind_symbolic_name T 0 [symbolic = %T.1 (constants.%T)] // CHECK:STDOUT: // CHECK:STDOUT: fn(%T.loc8: %.1); // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic fn @PeriodMember(%U.loc10: %.1) { -// CHECK:STDOUT: %.Self.2: %.1 = bind_symbolic_name .Self 0 [symbolic = %.Self.2 (constants.%.Self.1)] // CHECK:STDOUT: %U.1: %.1 = bind_symbolic_name U 0 [symbolic = %U.1 (constants.%U)] // CHECK:STDOUT: // CHECK:STDOUT: fn(%U.loc10: %.1); // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic fn @TypeSelfImpls(%V.loc12: type) { -// CHECK:STDOUT: %.Self.2: type = bind_symbolic_name .Self 0 [symbolic = %.Self.2 (constants.%.Self.2)] // CHECK:STDOUT: %V.1: type = bind_symbolic_name V 0 [symbolic = %V.1 (constants.%V)] // CHECK:STDOUT: // CHECK:STDOUT: fn(%V.loc12: type); // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @PeriodSelf(constants.%T) { -// CHECK:STDOUT: %.Self.2 => constants.%T // CHECK:STDOUT: %T.1 => constants.%T // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @PeriodMember(constants.%U) { -// CHECK:STDOUT: %.Self.2 => constants.%U // CHECK:STDOUT: %U.1 => constants.%U // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @TypeSelfImpls(constants.%V) { -// CHECK:STDOUT: %.Self.2 => constants.%V // CHECK:STDOUT: %V.1 => constants.%V // CHECK:STDOUT: } // CHECK:STDOUT: @@ -220,8 +214,8 @@ class D { // CHECK:STDOUT: %W.patt: %.1 = symbolic_binding_pattern W 0 // CHECK:STDOUT: } { // CHECK:STDOUT: %J.ref: type = name_ref J, file.%J.decl [template = constants.%.1] -// CHECK:STDOUT: %.Self.1: %.1 = bind_symbolic_name .Self 0 [symbolic = %.Self.2 (constants.%.Self)] -// CHECK:STDOUT: %.Self.ref: %.1 = name_ref .Self, %.Self.1 [symbolic = %.Self.2 (constants.%.Self)] +// CHECK:STDOUT: %.Self: %.1 = bind_symbolic_name .Self 0 [symbolic = constants.%.Self] +// CHECK:STDOUT: %.Self.ref: %.1 = name_ref .Self, %.Self [symbolic = constants.%.Self] // CHECK:STDOUT: %Mismatch.ref: = name_ref Mismatch, [template = ] // CHECK:STDOUT: %.loc12: %.5 = struct_literal () // CHECK:STDOUT: %W.param: %.1 = param W, runtime_param @@ -241,14 +235,12 @@ class D { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic fn @PeriodMismatch(%W.loc12: %.1) { -// CHECK:STDOUT: %.Self.2: %.1 = bind_symbolic_name .Self 0 [symbolic = %.Self.2 (constants.%.Self)] // CHECK:STDOUT: %W.1: %.1 = bind_symbolic_name W 0 [symbolic = %W.1 (constants.%W)] // CHECK:STDOUT: // CHECK:STDOUT: fn(%W.loc12: %.1); // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @PeriodMismatch(constants.%W) { -// CHECK:STDOUT: %.Self.2 => constants.%W // CHECK:STDOUT: %W.1 => constants.%W // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/where_expr/no_prelude/non_generic.carbon b/toolchain/check/testdata/where_expr/no_prelude/non_generic.carbon new file mode 100644 index 0000000000000..31f619aee5af8 --- /dev/null +++ b/toolchain/check/testdata/where_expr/no_prelude/non_generic.carbon @@ -0,0 +1,64 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/where_expr/no_prelude/non_generic.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/where_expr/no_prelude/non_generic.carbon + +interface I { let T:! type; } + +// Ensure that we don't crash when checking this `where` in a non-generic context. +fn NotGenericF(U: I where .T = {}) {} + +// CHECK:STDOUT: --- non_generic.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = interface_type @I [template] +// CHECK:STDOUT: %Self: %.1 = bind_symbolic_name Self 0 [symbolic] +// CHECK:STDOUT: %.2: type = assoc_entity_type %.1, type [template] +// CHECK:STDOUT: %.3: %.2 = assoc_entity element0, @I.%T [template] +// CHECK:STDOUT: %.Self: %.1 = bind_symbolic_name .Self 0 [symbolic] +// CHECK:STDOUT: %.4: type = tuple_type () [template] +// CHECK:STDOUT: %.5: type = struct_type {} [template] +// CHECK:STDOUT: %NotGenericF.type: type = fn_type @NotGenericF [template] +// CHECK:STDOUT: %NotGenericF: %NotGenericF.type = struct_value () [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .I = %I.decl +// CHECK:STDOUT: .NotGenericF = %NotGenericF.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %I.decl: type = interface_decl @I [template = constants.%.1] {} {} +// CHECK:STDOUT: %NotGenericF.decl: %NotGenericF.type = fn_decl @NotGenericF [template = constants.%NotGenericF] { +// CHECK:STDOUT: %U.patt: %.1 = binding_pattern U +// CHECK:STDOUT: } { +// CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [template = constants.%.1] +// CHECK:STDOUT: %.Self: %.1 = bind_symbolic_name .Self 0 [symbolic = constants.%.Self] +// CHECK:STDOUT: %.Self.ref: %.1 = name_ref .Self, %.Self [symbolic = constants.%.Self] +// CHECK:STDOUT: %T.ref: %.2 = name_ref T, @I.%.loc11 [template = constants.%.3] +// CHECK:STDOUT: %.loc12: %.5 = struct_literal () +// CHECK:STDOUT: %U.param: %.1 = param U, runtime_param0 +// CHECK:STDOUT: %U: %.1 = bind_name U, %U.param +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @I { +// CHECK:STDOUT: %Self: %.1 = bind_symbolic_name Self 0 [symbolic = constants.%Self] +// CHECK:STDOUT: %T: type = assoc_const_decl T [template] +// CHECK:STDOUT: %.loc11: %.2 = assoc_entity element0, %T [template = constants.%.3] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .T = %.loc11 +// CHECK:STDOUT: witness = (%T) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @NotGenericF(%U: %.1) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: