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.
They are not used for impl lookup or verifying anything yet, but now
they appear in the textual semir.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
This requires declared FacetTypes to hold NamedConstraintIds (along with
a specific) that are named in an extend or impls requirement. We add
support to stringify and formatter to display the named constraints in
the facet type, and special case when a facet type contains a single
extend named constraint, like we did for a single extend interface.
This means that `RequireIndentifiedFacetType` can now fail, if the facet
type contains a forward-declared named constraint. Add the appropriate
diagnostics for each call to this function, and note the ones that
should change to `RequireCompleteFacetType` in the future with TODOs.
We also add tests for using facet types that can or can't be identified,
or completed, with named constraints in them.
Type check named constraint decls and definitions. We don't correctly
error if you put a `fn` inside them. There is no support for `require`
or `alias` yet, so there's nothing useful you can do with them yet.
We have attempted to share code between `interface` and `constraint` as
they are quite similar. First by splitting out some of
handle_interface.cpp to a separate file. Second by sharing some code
paths when you want a facet type from either one, as they both turn into
a facet type.