Add an interface-with-self generic to each interface and same for constraints (#6667)

Currently each interface has a `Self` facet internally that becomes a
binding to every entity inside the interface: associated constants,
functions, and require decls. Each of these has to be independently
generic as a result. This makes is challenging in extended name lookup
to move into an extended scope of an interface, as we have a specific
for the interface, but the names within require a different specific
that includes a `Self` facet value.

We generalize this relationship by adding a second generic to Interface,
called `generic_with_self`. When we want to work with entities inside
the interface, we move from the interface-without-specific to the
interface-with-self specific by adding a Self to the specific. This is
done independently of any particular entity inside the Interface, as
those entities are now all members of the interface-with-self generic.

Associated constants no longer need a generic of their own, as they do
not have separate generic bindings. Functions retain a generic, but if
the function has no generic arguments, it will have no bindings of its
own now.

Require decls retain a generic so that their specific can be
instantiated separately from the interface. Requiring the interface to
be complete does not require the types in a require decl to be complete
unless it is modified by `extend`. So we allow them to be completed
later by keeping them in a separate generic.

Named constraints look like interfaces and gain the additional inner
generic-with-self, with the same relationship to require decls.

This removes the need for name lookup to perform Substitution of a Self
facet into the extended scope instruction. Instead, the
`SpecificConstant` instruction inserted by a `require` decl is part of
the interface-with-self generic. When looking through a FacetType for
extended scopes, for each interface, we push the scope with the specific
for the interface-with-self. Then the constant value of the
`SpecificConstant` is correctly modified by the provided self
automatically through applying that specific.
This commit is contained in:
Dana Jansens
2026-02-19 16:24:07 +00:00
committed by GitHub
parent e5b094fdad
commit 917a6ea971
419 changed files with 18175 additions and 11940 deletions
@@ -76,8 +76,8 @@ fn Run() {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %.loc37_20.1.temp = alloca i1, align 1, !dbg !23
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc37_20.1.temp), !dbg !23
// CHECK:STDOUT: %I.F.call = call i1 @"_CF.X.Main:I.Main"(), !dbg !23
// CHECK:STDOUT: %.loc37_20.2 = zext i1 %I.F.call to i8, !dbg !23
// CHECK:STDOUT: %I.WithSelf.F.call = call i1 @"_CF.X.Main:I.Main"(), !dbg !23
// CHECK:STDOUT: %.loc37_20.2 = zext i1 %I.WithSelf.F.call to i8, !dbg !23
// CHECK:STDOUT: store i8 %.loc37_20.2, ptr %.loc37_20.1.temp, align 1, !dbg !23
// CHECK:STDOUT: %.loc37_20.3 = load i8, ptr %.loc37_20.1.temp, align 1, !dbg !23
// CHECK:STDOUT: %.loc37_20.31 = trunc i8 %.loc37_20.3 to i1, !dbg !23
@@ -89,8 +89,8 @@ fn Run() {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %.loc37_20.1.temp = alloca i32, align 4, !dbg !26
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc37_20.1.temp), !dbg !26
// CHECK:STDOUT: %I.F.call = call i32 @"_CF.Y.Main:I.Main"(), !dbg !26
// CHECK:STDOUT: store i32 %I.F.call, ptr %.loc37_20.1.temp, align 4, !dbg !26
// CHECK:STDOUT: %I.WithSelf.F.call = call i32 @"_CF.Y.Main:I.Main"(), !dbg !26
// CHECK:STDOUT: store i32 %I.WithSelf.F.call, ptr %.loc37_20.1.temp, align 4, !dbg !26
// CHECK:STDOUT: %.loc37_20.3 = load i32, ptr %.loc37_20.1.temp, align 4, !dbg !26
// CHECK:STDOUT: ret void, !dbg !27
// CHECK:STDOUT: }
@@ -63,8 +63,8 @@ fn G() {
// CHECK:STDOUT: ; Function Attrs: nounwind
// CHECK:STDOUT: define linkonce_odr i32 @_CCallGenericMethod.Main.416a86e385b6ba35(i32 %x) #0 !dbg !17 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %SomeInterface.F.call = call i32 @"_CF.ImplsSomeInterface.Main:SomeInterface.b88d1103f417c6d4.Main"(i32 %x), !dbg !20
// CHECK:STDOUT: ret i32 %SomeInterface.F.call, !dbg !21
// CHECK:STDOUT: %SomeInterface.WithSelf.F.call = call i32 @"_CF.ImplsSomeInterface.Main:SomeInterface.b88d1103f417c6d4.Main"(i32 %x), !dbg !20
// CHECK:STDOUT: ret i32 %SomeInterface.WithSelf.F.call, !dbg !21
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: attributes #0 = { nounwind }
@@ -171,10 +171,10 @@ fn F_nested_tuple(a: ((i32, i32), X)) -> ((i32, i32), X) {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %_.var = alloca i32, align 4, !dbg !63
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %_.var), !dbg !63
// CHECK:STDOUT: %Copy.Op.call.loc18 = call i32 @"_COp.Int.be1e879c1ad406d8.Core:Copy.Main"(i32 %a), !dbg !64
// CHECK:STDOUT: store i32 %Copy.Op.call.loc18, ptr %_.var, align 4, !dbg !63
// CHECK:STDOUT: %Copy.Op.call.loc19 = call i32 @"_COp.Int.be1e879c1ad406d8.Core:Copy.Main"(i32 %a), !dbg !65
// CHECK:STDOUT: ret i32 %Copy.Op.call.loc19, !dbg !66
// CHECK:STDOUT: %Copy.WithSelf.Op.call.loc18 = call i32 @"_COp.Int.be1e879c1ad406d8.Core:Copy.Main"(i32 %a), !dbg !64
// CHECK:STDOUT: store i32 %Copy.WithSelf.Op.call.loc18, ptr %_.var, align 4, !dbg !63
// CHECK:STDOUT: %Copy.WithSelf.Op.call.loc19 = call i32 @"_COp.Int.be1e879c1ad406d8.Core:Copy.Main"(i32 %a), !dbg !65
// CHECK:STDOUT: ret i32 %Copy.WithSelf.Op.call.loc19, !dbg !66
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: nounwind