Properly diagnose ambiguous .Self in T impls X where... (#7132)

A `where` expression nested inside a `T impls X` constraint makes
`.Self` ambiguous on the right-hand side of the `where` if `T` is
anything other than `.Self`. After the `where`, the value of a `.Self`
could be `T` or could be the value of `.Self` before the `impls`
constraint: the so-called top-level value of `.Self`.

Implicit use of `.Self` in designators is always allowed, and they are
bound (and replaced by a reference) to the inner-most possible value of
`.Self`. On the right-hand side of the nested `where` above, they have
the value `T as X`.

`.Self impls ...` is also always allowed, since it acts more as a
keyword here, and it always refers to the inner-most possible value of
`.Self`.

Any other explicit use of `.Self` is diagnosed when ambiguous, in any
kind of constraint. This is done in the handling of `WhereExpr` since it
has enough context to allow `.Self impls` (which is an explicit use)
while disallowing other explicit uses. And because it has non-canonical
instructions to work with, so it is able to diagnose errors with precise
locations.

Since `.Self` is no longer going to be marked with depth modifiers, the
eval of `WhereExpr` does not need an input facet value instruction
representing `.Self` to compare with, as they are now going to all be
equivalent. So revert it back to just looking for the `PeriodSelf` name
id, through a shared helper being introduced as `IsPeriodSelf`. And drop
the period self InstId from the `WhereExpr` instruction. This causes
most of the formatted SemIR changes.

Move helpers for working with and replacing `.Self` to their own file,
out of the `facet_type.h` header/cpp files. These are working with
`.Self` facet values more than facet types, though `.Self` is a name
that only exists inside the scope of a facet type.
This commit is contained in:
Dana Jansens
2026-05-01 21:22:32 +00:00
committed by GitHub
parent 0fcbe7c6b5
commit 46bb0fecd4
46 changed files with 1008 additions and 678 deletions
@@ -80,8 +80,8 @@ let U: (type where .Self impls type).missing = {};
// CHECK:STDOUT: %.loc8_32: type = type_literal type [concrete = type]
// CHECK:STDOUT: %.Self.as_type: type = facet_access_type %.Self.ref [symbolic_self = constants.%.Self.as_type]
// CHECK:STDOUT: %.loc8_20: type = converted %.Self.ref, %.Self.as_type [symbolic_self = constants.%.Self.as_type]
// CHECK:STDOUT: %.loc8_14: type = where_expr %.Self [concrete = constants.%type] {
// CHECK:STDOUT: requirement_base_facet_type type
// CHECK:STDOUT: %.loc8_14: type = where_expr [concrete = constants.%type] {
// CHECK:STDOUT: requirement_base_facet_type %.loc8_9
// CHECK:STDOUT: requirement_impls %.loc8_20, %.loc8_32
// CHECK:STDOUT: }
// CHECK:STDOUT: %missing.ref: <error> = name_ref missing, <error> [concrete = <error>]
+2 -2
View File
@@ -174,8 +174,8 @@ interface A(T:! type) {
// CHECK:STDOUT: %impl.elem0: %C = impl_witness_access constants.%I.lookup_impl_witness, element0 [symbolic_self = constants.%impl.elem0]
// CHECK:STDOUT: %.loc16_27: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct]
// CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C]
// CHECK:STDOUT: %.loc16_14: type = where_expr %.Self [concrete = <error>] {
// CHECK:STDOUT: requirement_base_facet_type constants.%I.type
// CHECK:STDOUT: %.loc16_14: type = where_expr [concrete = <error>] {
// CHECK:STDOUT: requirement_base_facet_type %I.ref
// CHECK:STDOUT: requirement_rewrite %impl.elem0, <error>
// CHECK:STDOUT: }
// CHECK:STDOUT: }
+4 -4
View File
@@ -714,8 +714,8 @@ interface Z(T:! type) {
// CHECK:STDOUT: %impl.elem0: type = impl_witness_access constants.%Y.lookup_impl_witness, element0 [symbolic_self = constants.%impl.elem0]
// CHECK:STDOUT: %.loc7_32.1: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple]
// CHECK:STDOUT: %.loc7_32.2: type = converted %.loc7_32.1, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
// CHECK:STDOUT: %.loc7_19: type = where_expr %.Self [concrete = constants.%Y_where.type] {
// CHECK:STDOUT: requirement_base_facet_type constants.%Y.type
// CHECK:STDOUT: %.loc7_19: type = where_expr [concrete = constants.%Y_where.type] {
// CHECK:STDOUT: requirement_base_facet_type %Y.ref
// CHECK:STDOUT: requirement_rewrite %impl.elem0, %.loc7_32.2
// CHECK:STDOUT: }
// CHECK:STDOUT: }
@@ -873,8 +873,8 @@ interface Z(T:! type) {
// CHECK:STDOUT: %Self.ref: %Z.type = name_ref Self, @Z.%Self [symbolic = %Self (constants.%Self.c59)]
// CHECK:STDOUT: %Self.as_type.loc10_31: type = facet_access_type %Self.ref [symbolic = %Self.as_type.loc10_11.2 (constants.%Self.as_type)]
// CHECK:STDOUT: %.loc10_31: type = converted %Self.ref, %Self.as_type.loc10_31 [symbolic = %Self.as_type.loc10_11.2 (constants.%Self.as_type)]
// CHECK:STDOUT: %.loc10_19: type = where_expr %.Self [symbolic = %Y_where.type (constants.%Y_where.type)] {
// CHECK:STDOUT: requirement_base_facet_type constants.%Y.type
// CHECK:STDOUT: %.loc10_19: type = where_expr [symbolic = %Y_where.type (constants.%Y_where.type)] {
// CHECK:STDOUT: requirement_base_facet_type %Y.ref
// CHECK:STDOUT: requirement_rewrite %impl.elem0, %.loc10_31
// CHECK:STDOUT: }
// CHECK:STDOUT: }