Просмотр исходного кода

Forward `impl` declaration of an incomplete interface (#5168)

Revise rules for what is required and provided by declarations and
definitions of interfaces and impls. In particular:

-   allow `impl` declarations of incomplete interfaces, and
- shift from a "use the information from the type definition if it
happens to be complete" model to a "only use the information from the
definition in contexts where it is required to be defined or complete"
model.

Resolves questions-for-leads issues
[#4566](https://github.com/carbon-language/carbon-lang/issues/4566),
[#4672](https://github.com/carbon-language/carbon-lang/issues/4672),
[#4579](https://github.com/carbon-language/carbon-lang/issues/4579).

---------

Co-authored-by: Josh L <josh11b@users.noreply.github.com>
Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
Co-authored-by: Carbon Infra Bot <carbon-external-infra@google.com>
josh11b 1 год назад
Родитель
Сommit
ed863d6eae
1 измененных файлов с 1017 добавлено и 0 удалено
  1. 1017 0
      proposals/p5168.md

+ 1017 - 0
proposals/p5168.md

@@ -0,0 +1,1017 @@
+# Forward `impl` declaration of an incomplete interface
+
+<!--
+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
+-->
+
+[Pull request](https://github.com/carbon-language/carbon-lang/pull/5168)
+
+<!-- toc -->
+
+## Table of contents
+
+-   [Abstract](#abstract)
+-   [Problem](#problem)
+-   [Background](#background)
+    -   [Related work and past discussion](#related-work-and-past-discussion)
+    -   [Terminology](#terminology)
+    -   [Other considerations](#other-considerations)
+-   [Proposal](#proposal)
+    -   [Prior to this proposal](#prior-to-this-proposal)
+    -   [Proposed rules](#proposed-rules)
+-   [Details](#details)
+    -   [An `impl` implements a single interface](#an-impl-implements-a-single-interface)
+    -   [Associated constants may be assigned in the body of an `impl` definition](#associated-constants-may-be-assigned-in-the-body-of-an-impl-definition)
+    -   [An `impl` may be forward declared without the interface being complete](#an-impl-may-be-forward-declared-without-the-interface-being-complete)
+    -   [Interface requirements](#interface-requirements)
+    -   [Examples](#examples)
+-   [Future work](#future-work)
+    -   [Addressing the subsumption use case previously addressed by `extend` in interfaces](#addressing-the-subsumption-use-case-previously-addressed-by-extend-in-interfaces)
+    -   [Opt-in to using the interface's default definition of an associated function](#opt-in-to-using-the-interfaces-default-definition-of-an-associated-function)
+-   [Rationale](#rationale)
+-   [Alternatives considered](#alternatives-considered)
+    -   [Allow implementing multiple interfaces with a single `impl` declaration](#allow-implementing-multiple-interfaces-with-a-single-impl-declaration)
+    -   [An `impl` of an interface also implements the interfaces it extends](#an-impl-of-an-interface-also-implements-the-interfaces-it-extends)
+    -   [Use the contents of definitions if available](#use-the-contents-of-definitions-if-available)
+    -   [Delayed checking of incomplete types](#delayed-checking-of-incomplete-types)
+    -   [Allow `impl` declarations with rewrites of defined but not complete interfaces](#allow-impl-declarations-with-rewrites-of-defined-but-not-complete-interfaces)
+    -   [Can omit function declarations from `impl` body](#can-omit-function-declarations-from-impl-body)
+    -   [Different introducer for assigning associated constants in an `impl` definition](#different-introducer-for-assigning-associated-constants-in-an-impl-definition)
+
+<!-- tocstop -->
+
+## Abstract
+
+Revise rules for what is required and provided by declarations and definitions
+of interfaces and impls. In particular:
+
+-   allow `impl` declarations of incomplete interfaces, and
+-   shift from a "use the information from the type definition if it happens to
+    be complete" model to a "only use the information from the definition in
+    contexts where it is required to be defined or complete" model.
+
+Resolves questions-for-leads issues
+[#4566](https://github.com/carbon-language/carbon-lang/issues/4566),
+[#4672](https://github.com/carbon-language/carbon-lang/issues/4672),
+[#4579](https://github.com/carbon-language/carbon-lang/issues/4579).
+
+## Problem
+
+There are several kinds of entities in Carbon, and most of them support separate
+forward declaration from definition. You might declare an entity before defining
+it for a few reasons:
+
+-   Non-generic runtime functions may be called using only a declaration in an
+    api file, as long as they are defined in the corresponding impl file. This
+    hides implementation details, and allows build work to be parallelized by
+    way of separate compilation.
+-   By
+    [the information accumulation principle](https://docs.carbon-lang.dev/docs/project/principles/information_accumulation.html),
+    we don't want code to rely on information written later in the file. For
+    example, names can't be used before the declaration that introduces that
+    name. This requires the developer to order their code in a way that
+    satisfies those constraints.
+
+For example, functions and types (classes, interfaces, named constraints, and so
+on) can reference the names of any kind of type in their declaration and
+definition.
+
+In some cases, two types will reference each other, requiring forward
+declarations:
+
+A
+[more complex example with interfaces](/docs/design/generics/details.md#example-of-declaring-interfaces-with-cyclic-references)
+can be found in the generics design, that requires introducing named constraint
+forward declarations to represent constraints that can't be expressed yet.
+
+We don't want to create a situation where Carbon is introducing a lot of
+[accidental complexity](https://en.wikipedia.org/wiki/No_Silver_Bullet) into the
+programming process by creating a declaration ordering puzzle that is difficult
+or impossible to solve. We would like ordering rules that are straightforward to
+satisfy, and simple to remember.
+
+There are a few different options for ordering requirements, all of which have
+downsides:
+
+-   Light requirements are easy to satisfy, but don't provide as much
+    information to use. For example, if you don't require that an interface is
+    defined at a point, then you can't use the interface requirements from its
+    definition.
+-   Strong requirements are difficult to satisfy, and in the worst case can
+    create dependency cycles that can't be satisfied at all.
+-   We could have light requirements, but then use additional information when
+    it is available. This creates complexity. There is complexity in the
+    implementation since there are many cases to consider, and if something goes
+    wrong it could be for many different possible reasons. It increases the
+    danger of introducing coherence concerns, where reordering declarations and
+    definitions could change the meaning of the code. This gives some
+    (situational) flexibility to the developer to solve ordering problems.
+
+The design prior to this proposal often uses this last option, creating
+implementation complexity. We would like to find an alternate approach that
+gives similar flexibility without the downsides.
+
+## Background
+
+### Related work and past discussion
+
+-   [Proposal #722](https://github.com/carbon-language/carbon-lang/pull/722):
+    Nominal classes and methods
+-   [Proposal #818](https://github.com/carbon-language/carbon-lang/pull/818):
+    Constraints for generics (generics details 3)
+    -   Introduced implied constraints.
+-   [PR #1026](https://github.com/carbon-language/carbon-lang/pull/1026):
+    Clarify class declaration syntax
+-   [Proposal #1084](https://github.com/carbon-language/carbon-lang/pull/1084):
+    Generics details 9: forward declarations
+    -   See
+        [the section in the generic details design document](https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/generics/details.md#forward-declarations-and-cyclic-references)
+-   [Proposal #2760](https://github.com/carbon-language/carbon-lang/pull/2760):
+    Consistent class and interface syntax
+-   [Proposal #3762](https://github.com/carbon-language/carbon-lang/pull/3762):
+    Merging forward declarations
+-   [Proposal #3763](https://github.com/carbon-language/carbon-lang/pull/3763):
+    Matching redeclarations
+    -   Updated the rules of `impl` declarations and matching
+-   [Proposal #3980](https://github.com/carbon-language/carbon-lang/pull/3980):
+    Singular extern declarations
+-   [PR #4230](https://github.com/carbon-language/carbon-lang/pull/4230): Add
+    documentation for entity declaration design work
+-   Pending
+    [leads question #4566](https://github.com/carbon-language/carbon-lang/issues/4566):
+    Implementing multiple interfaces with a single impl definition
+    -   The currently proposed resolution includes `impl`ing an interface does
+        not `impl` the interfaces it `extend`s, reducing the need to see the
+        `interface` definition in `impl` declarations.
+-   Pending
+    [leads question #4579](https://github.com/carbon-language/carbon-lang/issues/4579):
+    When are interface requirements enforced for an `impl`?
+    -   Considers what is required and provided by `impl` forward declarations
+        and definitions. This proposal offers a resolution to these questions.
+-   Pending
+    [leads question #4672](https://github.com/carbon-language/carbon-lang/issues/4672):
+    Declaration and definition of impls and their associated functions
+    -   The currently proposed resolution includes moving assignment of
+        associated constants into the `impl` definition in the normal case,
+        reducing the need to see the `interface` definition in `impl`
+        declarations.
+-   [Proposal #5087](https://github.com/carbon-language/carbon-lang/pull/5087):
+    Qualified lookup into types being defined
+    -   Allows member access inside a type's definition, in addition to
+        afterwards. Introduces the _defined_ terminology.
+
+### Terminology
+
+-   A _declaration_ specifies information about an entity. Declarations are
+    either _forward declarations_ (which generally end with a semicolon `;`) or
+    _definitions_ (which generally end with a body enclosed in curly braces
+    `{`...`}`).
+-   We say an entity is _declared_ by the first declaration textually in the
+    source. If that declaration is a definition, we say the entity is declared
+    at the point the body begins (at the open curly `{`).
+-   We say an entity is _defined_ once the body of its definition is started (at
+    the open curly `{`). We allow name lookup into an entity once it is defined.
+    See
+    [proposal #5087: Qualified lookup into types being defined](https://github.com/carbon-language/carbon-lang/pull/5087).
+-   We say an entity is _complete_ at the end of its definition (at the close
+    curly `}`).
+-   We say a facet type is _identified_ if all the interfaces it references are
+    declared and all of its named constraints are complete. An identified facet
+    type is associated with a known set of interfaces.
+-   An _implied constraint_ is a condition that must hold if a type is used in a
+    given type expression, which we enforce in some way other than checking that
+    the condition holds at that point. For example:
+
+    ```
+    interface Hash { ... }
+    class HashSet(T:! Hash) { ... }
+
+    // `U` must satisfy the constraints on the `T` parameter to `HashSet`.
+    // In this case, we enforce it using an implied constraint, so we don't
+    // require `U impls Hash` beforehand (say by being declared `U:! Hash`).
+    fn Contains[U:! type](needle: U, haystack: HashSet(U)) -> bool;
+    // In this case, `Contains` is equivalent to this declaration that
+    // doesn't use implied constraints:
+    fn Contains[U:! type where .Self impls Hash]
+               (needle: U, haystack: HashSet(U)) -> bool;
+
+    // In this example, the implied constraint is on something more
+    // complicated than a single symbolic parameter.
+    fn F[V:! type, W:! type](x: HashSet(Pair(V, W)));
+    // is equivalent to:
+    fn F[V:! type, W:! type where Pair(V, .Self) impls Hash]
+        (x: HashSet(Pair(V, W)));
+    ```
+
+    -   We generally require that there always be a way to explicitly declare
+        constraints so implied constraints are not needed.
+    -   Implied constraints allow declarations to be more concise, particularly
+        we hope that common requirements can be omitted since they are implied.
+    -   Implied constraints are also a tool we can choose to use to say that a
+        requirement on a parameter can be enforced at a later point. In this
+        example,
+
+        ```
+        interface B {}
+        interface A;
+        class C(T:! B);
+        fn F(U:! A, x: C(U));
+
+        interface A {
+        require Self impls B;
+        }
+        ```
+
+        the symbolic type parameter `U` has a constraint that it impls `A`, and
+        we can add an implied constraint that it also impls `B` because it is
+        used as an argument to `C`. This constraint might be redundant with a
+        requirement from the definition of `A`, which may or may not have been
+        available at the point where `F` is declared. Callers have to provide
+        arguments that satisfy the additional requirement if it turns out that
+        `A` alone is not sufficient.
+
+### Other considerations
+
+Different kinds of entities have different requirements (ignoring `extern`
+declarations):
+
+-   A compile-time function must be defined before a call to it is evaluated.
+-   A generic function must be defined before the end of each file in which a
+    call to it is type-checked.
+-   Non-generic runtime functions may be defined separately. They may be forward
+    declared in an api file and defined in a corresponding impl file.
+-   Types must be complete before they are used in a function definition. This
+    includes the parameter types, the return type, the argument types of
+    functions that are called in the body, and the types of local variables.
+-   Interfaces and named constraints must be defined in the same file they are
+    declared.
+-   We want to allow some uses of classes that are declared in an api file and
+    defined in a corresponding impl file -- in particular, we treat the "pointer
+    to `C`" type `C*` to be complete even if `C` is not.
+
+Our main tool for making ordering easier is forward declarations. Declarations
+necessarily come after all the declarations of entities named in its parameter
+and return types. So declarations need to be ordered in some
+[topological sorted order](https://en.wikipedia.org/wiki/Topological_sorting)
+that respects those dependencies. This is unavoidable, though, as long as we are
+not allowing forward references, following
+[the information accumulation principle](https://docs.carbon-lang.dev/docs/project/principles/information_accumulation.html).
+
+Definitions will have all the dependencies of a declaration, plus perhaps some
+more. As a result we will want to put them later in the file. This is possible
+if a forward declaration is good enough for other declarations to use that name
+in all the ways that they need to.
+
+## Proposal
+
+The goal is to allow forward declarations in more situations, and allow them to
+satisfy requirements in more situations. In particular, we make these changes:
+
+-   We accept the proposed resolution of
+    [leads question #4566](https://github.com/carbon-language/carbon-lang/issues/4566):
+    -   An `impl` of an interface `I` does not `impl` any interface `I` extends.
+    -   A single `impl` can be for only a single interface.
+-   We accept the proposed resolution of
+    [leads question #4672](https://github.com/carbon-language/carbon-lang/issues/4672):
+    -   Assignment of associated constants is moved into the `impl` definition
+        in the normal case, though may still be present in a `where` clause at
+        the end of the declaration.
+    -   Associated constants are assigned using `where X = value;` declarations,
+        with semantics matching rewrite constraints in `where` clauses.
+    -   No part of the `impl` declaration will be excluded from syntactic match.
+    -   Every `impl` must be defined in the same file (not just the same
+        library) as its declaration.
+        -   However, the definitions of its member functions may be separate in
+            the impl file, out of line, as provided in
+            [proposal #3763](/proposals/p3763.md#out-of-line-definitions-of-associated-functions).
+-   An `impl` may be forward declared without the interface being defined.
+    -   This is enabled by not needing access to the definition to see other
+        interfaces required or extended or to see the associated constants that
+        need to be given values.
+    -   Instead we require the interface to be _identified_. This means that if
+        the facet type to the right of the `as` is given by a named constraint,
+        that named constraint needs to be complete so we can see which interface
+        it corresponds to. (It is an error if it doesn't correspond to a single
+        interface, by the resolution of
+        [#4566](https://github.com/carbon-language/carbon-lang/issues/4566).)
+    -   However, an `impl` declaration of a facet type with `.A =`... rewrite
+        constraints (for example in a `where` clause), does still require the
+        interface to be complete.
+-   We answer questions from
+    [leads issue #4579](https://github.com/carbon-language/carbon-lang/issues/4579):
+    -   Since `impl` forward declarations do not require the interface to be
+        defined, any requirements that other interfaces be defined from the
+        interface definition are ignored.
+    -   An `impl` definition of an interface `I` requires first establishing
+        that the type implements any interfaces required by `I`, but that can be
+        satisfied by an `impl` declaration.
+-   We shift from a "use the information from the type definition if it happens
+    to be complete" model to a "only use the information from the definition in
+    contexts where it is required to be defined or complete" model
+    -   However, an interface `I` containing a `require Self impls J` or
+        `extend J` declaration adds a fact that "types `T` satisfying
+        `T impls I` also satisfy `T impls J`" to the environment.
+
+These changes are intended to allow developers to write their api files in an
+order that roughly follows:
+
+-   namespace declarations in any order;
+-   other declarations in any topological dependency order;
+-   type (interface, constraint, class) definitions in any order;
+-   impl definitions in any order;
+-   function definitions, including both those that are needed in the api file
+    plus those the developer wishes to include, in any order.
+
+This would be sufficient except we have a few additional constraints, which
+remain:
+
+-   Performing member access into a type requires the type to be defined, not
+    just declared.
+-   Members of an effectively final impl may only be accessed after their value
+    has been established.
+-   A function that is called at compile time must be defined before that call
+    is executed by the compiler.
+
+### Prior to this proposal
+
+|                                                                                     | prereq                                                                                 | provides                                                                               | complete by [EOF](https://en.wikipedia.org/wiki/End-of-file) |
+| :---------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------- | :----------------------------------------------------------- |
+| `impl C as Y;`                                                                      | **`Y` complete**                                                                       | `C impls Y`                                                                            |                                                              |
+| `impl C as Y where .A =` ...                                                        | `Y` complete                                                                           | `C impls Y`                                                                            |                                                              |
+| `impl C as Y {` ... `}`                                                             | `Y` complete                                                                           | `C impls Y`                                                                            | `C`                                                          |
+| `interface I;`                                                                      |                                                                                        | `I` declared                                                                           | `I`                                                          |
+| `interface Y {` <br> ` require Self impls Z;` <br> `}`                              | **`Z` declared**                                                                       | **`Y` complete**                                                                       | `Z`                                                          |
+| `interface Y {` <br> ` require Self impls Z;` <br> `}` <br> `impl C as Y {` ... `}` | **open question [\#4579](https://github.com/carbon-language/carbon-lang/issues/4579)** | **open question [\#4579](https://github.com/carbon-language/carbon-lang/issues/4579)** |                                                              |
+| `fn F[T:! I](x: T);`                                                                | `I` declared                                                                           |                                                                                        | `F`, `I`                                                     |
+| `fn F[T:! I](x: T) {` ... `}`                                                       | `I` complete                                                                           | `F` complete                                                                           |                                                              |
+| `interface I;` <br> `class C;` <br> `class D(T:! I);` <br> `fn F(x: D(C));`         | `C impls I`                                                                            |                                                                                        | `I`, `C`?, `D`                                               |
+| `interface I;` <br> `class D(T:! I);` <br> `fn F[U:! type](x: D(U));`               |                                                                                        | `U impls I` <br> (implied constraint)                                                  | `I`, `D`, `F`                                                |
+
+### Proposed rules
+
+|                                                                                     | prereq             | provides                                                                               | complete by [EOF](https://en.wikipedia.org/wiki/End-of-file) |
+| :---------------------------------------------------------------------------------- | :----------------- | :------------------------------------------------------------------------------------- | :----------------------------------------------------------- |
+| `impl C as Y;`                                                                      | **`Y` identified** | `C impls Y`                                                                            | **`Y`, `impl C as Y`**                                       |
+| `impl C as Y where .A =` ...                                                        | `Y` complete       | `C impls Y`                                                                            | **`impl C as Y` ...**                                        |
+| `impl C as Y {` ... `}`                                                             | `Y` complete       | `C impls Y`                                                                            | `C`                                                          |
+| `interface I;`                                                                      |                    | `I` declared                                                                           | `I`                                                          |
+| `interface Y {` <br> ` require Self impls Z;` <br> `}`                              | **`Z` identified** | **for any symbolic type `T`, <br> `T impls Y` implies `T impls Z`; <br> `Y` complete** | `Z`                                                          |
+| `interface Y {` <br> ` require Self impls Z;` <br> `}` <br> `impl C as Y {` ... `}` | **`C impls Z`**    | **`C impls Y`**                                                                        |                                                              |
+| `fn F[T:! I](x: T);`                                                                | `I` declared       |                                                                                        | `F`, `I`                                                     |
+| `fn F[T:! I](x: T) {` ... `}`                                                       | `I` complete       | `F` complete                                                                           |                                                              |
+| `interface I;` <br> `class C;` <br> `class D(T:! I);` <br> `fn F(x: D(C));`         | `C impls I`        |                                                                                        | `I`, `C`?, `D`                                               |
+| `interface I;` <br> `class D(T:! I);` <br> `fn F[U:! type](x: D(U));`               |                    | `U impls I` <br> (implied constraint)                                                  | `I`, `D`, `F`                                                |
+
+> Whether classes need to be complete by the end of the file is not the subject
+> of this proposal.
+
+## Details
+
+### An `impl` implements a single interface
+
+We resolve
+[leads question #4566](https://github.com/carbon-language/carbon-lang/issues/4566)
+with two rules:
+
+-   Implementing an interface does not implement any of the interfaces it
+    extends.
+-   An impl declaration should implement a single interface.
+
+We allow facet type expressions to the right of `impl`...`as`, as long as that
+facet type corresponds to a single interface (ignoring interfaces it extends,
+which incidentally seems to
+[match Rust supertraits](https://stackoverflow.com/questions/75847426/why-do-we-need-a-separate-impl-for-a-supertrait)).
+This supports the use case of `Core.Add` actually being a named constraint
+defined in terms of `Core.AddWith`. This requires that the facet type is
+identified, at a minimum, when used in an `impl` declaration, so it can be
+resolved into the single interface actually being implemented.
+
+The "subsumption" use case of "when an interface X is implemented, Y will be
+implemented without the user having to write a separate impl definition" will
+instead be handled using
+[blanket implementations](/docs/design/generics/details.md#blanket-impl-declarations).
+There are a couple of variations:
+
+-   One interface is a strict superset of the other. In this case it would be a
+    lot less confusing/surprising if the interfaces use the same implementations
+    of functions that overlap. This is accomplished using a
+    [`final`](https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/generics/details.md#final-impl-declarations)
+    blanket implementation. For example, we will define
+    `final impl forall [T:! type, U:! ImplicitAs(T)] U as As(T)` and have
+    `As(T).Convert` forward to `ImplicitAs(T).Convert`. This way types will
+    either implement `ImplicitAs(T)` or `As(T)`, and will get an error if they
+    try to implement both.
+
+-   One interface can be implemented in terms of the other. For example, if
+    `Ordered` implies an implementation of `IsEqual`, types might still want to
+    provide an explicit definition of `IsEqual` when they can do so more
+    efficiently. This would use a non-`final` blanket implementation.
+
+Note that the orphan rule prevents this blanket impl from being written unless
+the two interfaces in a subsumption relationship are in the same library.
+Support for these use cases is
+[future work](#addressing-the-subsumption-use-case-previously-addressed-by-extend-in-interfaces).
+For now, `extend I;` in an interface definition continues to mean that `I` is
+required and the names of `I` are included as aliases, matching the meaning in
+named constraints, see "interface extension" in
+[proposal #553](https://github.com/carbon-language/carbon-lang/pull/553).
+
+### Associated constants may be assigned in the body of an `impl` definition
+
+We resolve
+[leads question #4672](https://github.com/carbon-language/carbon-lang/issues/4672)
+with the following updated rules:
+
+-   The `impl` definition must be in the same file as its owning declaration.
+-   The first declaration establishes that the type implements the interface.
+-   That declaration may optionally specify a subset of the associated constants
+    in a `where` clause. The `where` clause syntax is the same as before this
+    proposal, but the requirement that all associated constants be given their
+    final values (or accept their defaults where available) is removed.
+    -   This adds some flexibility to ordering, allowing a developer to say that
+        a type implements an interface before being able to specify the values
+        of its associated constants, while also allowing a subset to be
+        specified if some later declaration needs to access their values.
+-   Redeclarations of an `impl` no longer have any special treatment of `where`
+    clauses.
+    -   Each redeclaration is required to match syntactically, so all will have
+        the same `where` clause, if any.
+    -   The part between `impl` and the end of the declaration (marked by a `{`
+        or `;`) is the name of the `impl`. This will be used in places where we
+        want to name the `impl`, such as in an impl priority ("match first")
+        block or out-of-line definitions of `impl` members.
+-   Associated constant assignments should be encouraged to be placed in the
+    `impl` definition rather than in a `where` clause in the declaration, unless
+    needed in the declaration to resolve dependencies.
+    -   This makes the name of the `impl` shorter and easier to state.
+    -   The syntax for specifying the value of an associated constant in an
+        `impl` definition is `where X = value;`, just like a rewrite clause in a
+        `where` expression, except that `where` in this case is an introducer
+        rather than a binary operator, and the names of the associated constants
+        are in scope, so there is no need to prefix them with a period (`.`).
+-   The non-function associated constants are fixed at the closing curly `}` of
+    the `impl` definition. At that point, each associated constant that has not
+    been assigned a value is given its default value. If it does not have a
+    default, an error diagnostic is issued.
+-   The associated function declarations are fixed by the end of the `impl`
+    definition.
+    -   Only associated functions with defaults may be omitted from the `impl`
+        definition.
+    -   Not mentioning an associated function with a default in the `impl`
+        definition means the default version from the interface will be used.
+    -   Associated functions declared in the `impl` definition must have a
+        matching definition.
+    -   If the declared signature of an associated function in the `impl`
+        definition does not match the signature given in the `interface`
+        definition, but are compatible, a stub function that does the conversion
+        is generated to bridge between the two versions.
+-   Out-of-line function bodies are allowed in the impl file, even when the
+    `impl` definition is in the api file.
+    -   This parallels how function definitions are not part of the definition
+        of classes.
+-   Missing function body definitions are diagnosed at link time.
+
+### An `impl` may be forward declared without the interface being complete
+
+We have removed the reasons to require that the interfaces being implemented are
+defined for an `impl` forward declaration:
+
+-   We no longer need to see which interfaces are required or extended from the
+    definition of the interface, since the `impl` no longer implements those.
+-   We no longer need to see which associated constants are members of the
+    interface to see if a declaration specifies values for all of them.
+-   If a `where` clause is used in the declaration, the interface must be
+    defined in order to name the associated constants, but `where` clauses are
+    discouraged.
+
+However, if the facet type being implemented is a named constraint, we do need
+that to be complete so we can resolve the interface it resolves to. (It is an
+error if it doesn't correspond to a single interface, by the resolution of
+[#4566](https://github.com/carbon-language/carbon-lang/issues/4566).)
+
+This means that generally we can establish that a type implements an interface
+right after they are both declared.
+
+### Interface requirements
+
+[Leads issue #4579](https://github.com/carbon-language/carbon-lang/issues/4579)
+concerns itself with interfaces that require other interfaces to be implemented,
+as in:
+
+```
+interface Z;
+
+interface Y {
+  require Self impls Z;
+}
+```
+
+There are two sides to this: what do you have to establish about `Z` before an
+`impl` declaration or definition that a type implements `Y`, and what does a
+declaration or definition that a type implements `Y` establish about `Z`?
+
+We adopt the following rules:
+
+-   Since `impl` forward declarations do not require the interface to be
+    defined, any requirements that other interfaces be defined from the
+    interface definition are ignored.
+
+    ```
+    class C1;
+    // ✅ Allowed
+    impl C1 as Y;
+
+    // `class C1` and `impl C1 as Y` must be defined in the same file.
+    ```
+
+-   An `impl` definition of an interface `I` requires first establishing that
+    the type implements any interfaces required by `I`, but that can be
+    satisfied by an `impl` declaration.
+
+    ```
+    class C2;
+    // ❌ Invalid, must first establish `C2 impls Z`. Still invalid if
+    // `impl C2 as Z` appears later in the file.
+    impl C2 as Y {}
+
+    class C3;
+    // ✅ Allowed
+    impl C3 as Z;
+    impl C3 as Y {}
+
+    class C4;
+    // ✅ Allowed
+    impl C4 as Z {}
+    impl C4 as Y {}
+
+    // The classes and `impl C3 as Z` must be defined in the same file.
+    ```
+
+This is is aligned with the shift from a "use the information from the type
+definition if it happens to be complete" model to a "only use the information
+from the definition in contexts where it is required to be defined or complete"
+model that this proposal this is switching to. To recapture some of that context
+sensitivity, we say that the definition of an interface with requirements, like
+`Y` above, introduces the extra information that "symbolic types `T` that
+satisfy `T impls Y` also satisfy `T impls J`."
+
+For example:
+
+```
+interface Z;
+
+interface Y {
+  require Self impls Z;
+}
+
+class C(T:! Z);
+
+class D(U:! Y) {
+  // ✅ U impls Y so it also impls Z.
+  //
+  // Wouldn't use implied constraints here since `U` is
+  // from a containing scope.
+  fn F(x: C(U));
+}
+```
+
+This rule only applies to symbolic types, since we want to only say that
+concrete types implement an interface if we have a declared `impl` to witness
+that fact. Symbolic types depend on the value of some generic parameters and we
+accept that some accesses of interface members will result in symbolic values
+that will only have known values once concrete argument values are supplied for
+the generic parameters. For concrete types, the access is performed immediately,
+and it is an error if we don't have an `impl` declaration we can point to with
+the witness. For concrete types, there is no later point where an argument is
+supplied to delay these checks. For example:
+
+```
+interface Z;
+
+interface Y {
+  require Self impls Z;
+}
+
+class C(T:! Z);
+
+class D {}
+
+// ✅ Allowed, since `impl` declarations are allowed for declared
+// entities. Interface requirements are not considered.
+impl D as Y;
+
+// ❌ Error: D is not known to implement Z. The fact that Y
+// requires Z is not used since D is a concrete type.
+fn F(x: C(D));
+
+// Too late to affect the previous declaration, by the information
+// accumulation principle.
+impl D as Z;
+```
+
+Similarly, it is also an error to access a member of an `impl` of a concrete
+type that doesn't have a known value, even if it is given a value later in the
+file. For example:
+
+```
+interface I {
+  let A:! type;
+  let B:! type;
+}
+
+fn F(T:! I) -> T.A;
+
+class C {}
+class D {}
+
+impl C as I;
+
+fn G1() {
+  // ❌ Error: C impls I, but C.(I.A) is unknown.
+  var x: auto = F(C);
+  // ❌ Error: C.(I.A) is unknown.
+  let y: C.(I.A) = 0;
+  // ❌ Error: C.(I.B) is unknown.
+  let b: C.(I.B) = false;
+}
+
+impl D as I where .A = i32;
+
+fn H() {
+  // ✅ Allowed: D.(I.A) = i32;
+  var x: auto = F(D);
+  var y: D.(I.A) = 0;
+  // ❌ Error: D.(I.B) is unknown.
+  let b: D.(I.B) = false;
+}
+
+impl C as I {
+  where A = i32;
+  where B = bool;
+}
+
+fn G2() {
+  // ✅ Allowed: C.(I.A) = i32;
+  var x: auto = F(C);
+  let y: C.(I.A) = 0;
+  // ✅ Allowed: C.(I.B) = bool;
+  let b: C.(I.B) = false;
+}
+```
+
+### Examples
+
+This example shows using incomplete entities following the rules of this
+proposal:
+
+```
+interface X;
+
+// ✅ Allowed to use incomplete interfaces in function declarations.
+fn F(U:! X);
+
+class C;
+
+// ✅ Allowed to use incomplete types and interfaces in impl declarations.
+impl C as X;
+
+interface Y;
+
+interface X {
+  // ✅ Allowed to use an incomplete interface.
+  require Self impls Y;
+}
+
+// Classes must be defined before being used in a function definition.
+class C { ... }
+
+fn G() {
+  // ✅ Allowed since C is complete and we have a declaration `impl C as X;`
+  F(C);
+}
+
+// The above declarations require that `interface Y`, `fn F` (since it is
+// generic), and `impl C as X` are defined in the same file.
+interface Y { ... }
+fn F(U:! X) { ... }
+// Required for `impl C as X` definition.
+impl C as Y;
+impl C as X { ... }
+impl C as Y { }
+```
+
+This example demonstrates using associated constants and interface requirements:
+
+```
+interface X2 {
+  let A:! type;
+  let B:! type;
+}
+interface Y2 {
+  require Self impls X2;
+  // ✅ Allowed since `X2` is required and we can access
+  // its `A` member since `X2` is complete.
+  fn F() -> X2.A;
+}
+
+class C2 {}
+
+impl C2 as X2 where .A = i32;
+
+// ✅ Allowed since `C2` and `Y2` are complete, and
+// `C2 impls X2` so `C2` satisfies the requirement in `Y2`.
+impl C2 as Y2 {
+  // ✅ Allowed since the value of `C2.(X2.A)` is known to
+  // be `i32`, even though `impl C2 as X2` is not complete.
+  fn F() -> i32;
+}
+
+// There needs to be a definition of `C2 as X2 where .A = i32`
+// in the same file. The `where` clause needs to be repeated
+// verbatim, since redeclaration requires a syntactic match.
+impl C2 as X2 where .A = i32 {
+  // Remaining members of `X2` that do not have default
+  // values need to be assigned.
+  where B = i32;
+}
+```
+
+## Future work
+
+### Addressing the subsumption use case previously addressed by `extend` in interfaces
+
+We do expect to have collections of interfaces that have a stronger "extending"
+relationship than is provided by the current `extend` declaration in interfaces.
+For example, a type implementing `ImplicitAs` should not have to have a separate
+declaration that it also implements `As`. Addressing this use case is out of
+scope of this proposal, though, and will be addressed in a future proposal. This
+future proposal may include:
+
+-   A feature to copy the members of an interface into another to make the
+    subsumption use case easier to write and involve less duplication.
+
+-   A feature to define an implementation of an interface in terms of another by
+    forwarding, for similar reasons.
+
+-   A `final` version of the `match_first`/`impl_priority` feature to resolve
+    conflicts when multiple interfaces want to subsume a common interface. We
+    likely want a feature like this for function overloading as well.
+
+-   Some way of handling an `impl` that could overlap with a `final impl`, but
+    doesn't in practice.
+
+-   Possible support for implementing multiple interfaces with a single impl
+    definition, as the result of using an `&` operator or named constraint to
+    the right of `as`, as in
+    [the considered alternative](#allow-implementing-multiple-interfaces-with-a-single-impl-declaration).
+
+For now, we leave `extend` as meaning "requires plus include aliases of the
+names," matching the behavior in named constraints. But this will be
+reconsidered once we have support for this other use case.
+
+### Opt-in to using the interface's default definition of an associated function
+
+We've considered that we may want to allow an `impl` to opt into using the
+default definition of a function from the interface by writing `= default;`
+instead of an inline body in curly braces `{`...`}`. We will see if that is a
+desirable construct to add with experience. This idea was suggested in
+[issue #4672](https://github.com/carbon-language/carbon-lang/issues/4672#issuecomment-2539845620).
+
+## Rationale
+
+The specific solution was chosen to align with
+[the information accumulation principle](https://docs.carbon-lang.dev/docs/project/principles/information_accumulation.html).
+In particular, allowing `impl` declarations for incomplete interfaces gives
+additional flexibility to developers to satisfy those constraints.
+
+By reducing the different behavior based on whether a previous declaration was a
+definition, this proposal reduces complexity in the toolchain and tools that
+operate on Carbon source code. This benefits the
+[Language tools and ecosystem](/docs/project/goals.md#language-tools-and-ecosystem)
+and
+[Fast and scalable development](/docs/project/goals.md#fast-and-scalable-development)
+[Carbon goals](/docs/project/goals.md).
+
+This is intended to also help humans have a simpler mental model of the
+compiler, to help the
+[Code that is easy to read, understand, and write](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write)
+goal.
+
+## Alternatives considered
+
+The trade offs and alternatives were discussed in
+[this document](https://docs.google.com/document/d/1NNhBU5tywGkeneLmTQ4DwHyCp5vYlwTiR_wmnjn9wnM/edit)
+and in open discussion meetings on these dates:
+
+-   [2025-02-07](https://docs.google.com/document/d/1Iut5f2TQBrtBNIduF4vJYOKfw7MbS8xH_J01_Q4e6Rk/edit?resourcekey=0-mc_vh5UzrzXfU4kO-3tOjA&tab=t.0#heading=h.6ziehwl15x6a)
+-   [2025-03-04](https://docs.google.com/document/d/1Iut5f2TQBrtBNIduF4vJYOKfw7MbS8xH_J01_Q4e6Rk/edit?resourcekey=0-mc_vh5UzrzXfU4kO-3tOjA&tab=t.0#heading=h.22fvs78tr2ej)
+-   [2025-03-05](https://docs.google.com/document/d/1Iut5f2TQBrtBNIduF4vJYOKfw7MbS8xH_J01_Q4e6Rk/edit?resourcekey=0-mc_vh5UzrzXfU4kO-3tOjA&tab=t.0#heading=h.x0brmxoi93n4)
+-   [2025-03-06](https://docs.google.com/document/d/1Iut5f2TQBrtBNIduF4vJYOKfw7MbS8xH_J01_Q4e6Rk/edit?resourcekey=0-mc_vh5UzrzXfU4kO-3tOjA&tab=t.0#heading=h.lsqxlvgwdvoh)
+-   [2025-03-13](https://docs.google.com/document/d/1Iut5f2TQBrtBNIduF4vJYOKfw7MbS8xH_J01_Q4e6Rk/edit?resourcekey=0-mc_vh5UzrzXfU4kO-3tOjA&tab=t.0#heading=h.lsufbqunqul0)
+-   [2025-03-18](https://docs.google.com/document/d/1Iut5f2TQBrtBNIduF4vJYOKfw7MbS8xH_J01_Q4e6Rk/edit?resourcekey=0-mc_vh5UzrzXfU4kO-3tOjA&tab=t.0#heading=h.v0stu27nansb)
+-   [2025-03-20](https://docs.google.com/document/d/1Iut5f2TQBrtBNIduF4vJYOKfw7MbS8xH_J01_Q4e6Rk/edit?resourcekey=0-mc_vh5UzrzXfU4kO-3tOjA&tab=t.0#heading=h.jagz2i1dynjx)
+
+### Allow implementing multiple interfaces with a single `impl` declaration
+
+This was considered in
+[leads question #4566](https://github.com/carbon-language/carbon-lang/issues/4566).
+There are definite use cases for this feature, particularly arising from
+evolution. For example, you might want to split an interface into two new
+interfaces, and have a named constraint with the original name extend both so
+that existing code continues to work the same. With this proposal, those changes
+will be harder and have more steps.
+
+Two specific approaches to implementing multiple interfaces were eliminated from
+consideration in that issue:
+
+-   The "all or nothing" approach where the `impl` definition is used for all of
+    the interfaces, or none of them are. This would create too much uncertainty
+    about whether an `impl` is applicable, particularly since constraints in
+    generic code are not sensitive to whether something is specialized.
+-   The "Constrained impls" approach where an `impl` of multiple interfaces is
+    treated as a collection of `impl`s of the individual interfaces with the
+    additional constraint that no specialization changes the values of any
+    non-function associated constants of any of the interfaces. Those
+    constraints though are ultimately circular and not well defined.
+
+The remaining "independent impls" approach seemed possible. In this approach an
+impl of multiple interfaces is treated as a collection of impls of the
+individual interfaces. In particular, the definition of a member of one
+interface can assume that the other interfaces are implemented, but not that the
+associated types (or other non-function associated constants) have expected
+values. This would introduce some complexities and a number of questions would
+need to be answered around how a single `impl` definition would be split into
+definitions of the individual interfaces, how dependencies between those pieces
+would be resolved, and how these restrictions would be exposed to the user in
+diagnostics.
+
+### An `impl` of an interface also implements the interfaces it extends
+
+This was the design before this proposal, but in
+[leads question #4566](https://github.com/carbon-language/carbon-lang/issues/4566)
+we found a number of problems with that approach:
+
+-   A parameterized interface extending a non-parameterized interface, or an
+    interface with fewer parameters, leads to multiple implementations of the
+    extended interface.
+
+-   There are multiple possible semantics you might want, and having a single
+    `impl` does not provide the affordances for choosing between those options,
+    where one `impl` per interface would. For example, in
+    `impl forall [T:! type] C(T) as I & J where .(I.x) = i32 and .(J.y) = .(I.x)`,
+    if there is a specialization of `C(T)` for `I`, will `J.y` have the value
+    `i32` or the `I.x` from the specialization? In practice, the semantics of
+    rewrites mean that `.(I.x)` is replaced with `i32` at an early stage in the
+    compiler (to support things like `.(J.y) = .(I.x).D`), and so only the first
+    option is consistent. This is a particular concern for the "Independent
+    impls" option above. If this `impl` is split into two, then the different
+    possible meanings have different spellings:
+
+    -   `impl forall [T:! type] C(T) as J where .(J.y) = i32` means `J.y` will
+        be `i32` independent of any specialization of `C(T)` for `I`
+
+    -   `impl forall [T:! type where C(T) impls I] C(T) as J where .(J.y) = .(I.x)`
+        means `J.y` matches `I.x` even if `C(T)` is specialized
+
+    -   `impl forall [T:! type where C(T) impls (I where .x = i32)] C(T) as J where .(J.y) = .(I.x)`
+        means this impl won't be used unless `I.x` is `i32`. Note this last form
+        approximates the "Constrained impls" approach above, but with an
+        explicit ordering to determine the semantics, and the existing language
+        rules preventing the code from declaring cycles that would make it
+        ambiguous.
+
+-   If an interface `J` extends `I` but they are defined in distinct libraries,
+    there is no guarantee that an implementation of `J` belongs in the same
+    library as an implementation of `I` for the same type due to the orphan
+    rule.
+
+-   The current documented rule for which interfaces an impl implements is those
+    whose members are defined in the interface definition. This rule is
+    ambiguous for empty interfaces or interfaces where all the associated
+    functions have defaults. It also requires
+    [a lot of context](https://github.com/carbon-language/carbon-lang/blob/trunk/docs/project/principles/low_context_sensitivity.md)
+    to answer that question (this was intentional, to allow options for
+    refactoring an interface without having to update implementations of it). In
+    addition to being the source of readability concerns, this muddies the
+    meaning of `impl` declarations, and make the compiler implementation much
+    trickier (the compiler can't say what an impl declaration provides at the
+    point where it is written, making it hard to give that declaration a clear
+    type in the SemIR).
+
+-   Ideas we considered to determine the interfaces implemented from only the
+    impl declaration ran into problems. Without being able to control which
+    interfaces an impl is defining, then it isn't clear how to handle
+    implementing two interfaces that have common interface they both extend
+    unless you implement them both in a single impl definition (which may not
+    even be possible due to the orphan rule). Another idea we had in this space
+    was a way to say "this interface minus one of the interfaces it extends"
+    (maybe `J \ I`?).
+
+We considered some restrictions on `extend` to address some of these concerns:
+
+-   Perhaps implementing an interface only implemented the interfaces it extends
+    that have to be defined in this library by the orphan rule.
+
+-   Perhaps an interface may only extend an interface defined in the same
+    library.
+
+-   Perhaps an interface may only be extended by a single interface. This
+    precluded motivating use cases for `extend`, though, like the subtyping
+    relationships between different kinds of graphs used in
+    [the Boost Graph library](https://docs.google.com/document/d/15Brjv8NO_96jseSesqer5HbghqSTJICJ_fTaZOH0Mg4/edit?resourcekey=0-CYSbd6-xF8vYHv9m1rolEQ&tab=t.0)).
+
+Changing the meaning of `extend` is left for a future proposal, when we address
+[the subsumption use case previously addressed by `extend` in interfaces](#addressing-the-subsumption-use-case-previously-addressed-by-extend-in-interfaces).
+
+### Use the contents of definitions if available
+
+In the course of implementing the existing design, uses of "TryToCompleteType"
+function were found to be prone to leading to coherence issues. If being
+incomplete does not lead to an error, we need to establish that the results of
+the definition appearing before and after that test are the same. When there
+were multiple types involved, this led to an explosion of combinations to test.
+The new model has less conditional logic, and as a result less complexity.
+
+### Delayed checking of incomplete types
+
+We could delay checking uses of incomplete types until some later point, either
+when the type is complete, a use that requires that type to be complete, or the
+end of the file where we know the most about it. This is an option, and we might
+adopt it if we found that it was too hard in practice to satisfy the constraints
+adopted by this proposal. However it would significantly increase the complexity
+of the toolchain implementation, which would lead to a corresponding increase in
+the difficulty of understanding how the code will be interpreted.
+
+### Allow `impl` declarations with rewrites of defined but not complete interfaces
+
+We at first did not have a rule saying that `I` needed to be complete in
+`impl C as I where .X = ...`. The rationale was that accessing members of `I`
+only needed `I` to be defined, not complete. However, an `impl` declaration
+inside the definition of the interface being implemented could ultimately never
+be defined, even if we allowed the declaration. This is because the `impl`
+definition would have to be in a different scope than its declaration, as can be
+seen in this example that uses a lambda function to get a scope that can have an
+`impl` declaration inside an `interface` definition:
+
+```
+interface I {
+  let U:! type;
+  default let T:! type = (fn() -> type {
+    class C { }
+
+    // ✅ Allowed since `I` is declared, with the exception that
+    // this requires a definition before the end of the file.
+    impl C as I;
+
+    // ✅ Would be allowed since `I` is defined, including its
+    // member `U`. Again this requires a definition in this file.
+    impl C as I where .U = C;
+
+    // ❌ Neither of the above impls may be defined:
+    // - Can't be defined here since `I` is not complete.
+    // - Can't define after `I` is complete, since redeclarations
+    //   must match syntactically and have no hope of naming this
+    //   `C` that way.
+    // - In general, the impl definition would have to re-enter the
+    //   same scope.
+    impl C as I where .U = C {}
+
+    return C;
+  })();
+}
+```
+
+This simplifies the toolchain implementation of this feature, since it means we
+can create an `impl` witness for declarations that use rewrite constraints with
+the full knowledge of the interface's definition.
+
+### Can omit function declarations from `impl` body
+
+We considered saying that an `impl` definition does not need to include
+declarations that are unchanged from the interface definition. However, this
+raised a number of questions and problems:
+
+-   The `interface` definition is in a different scope from the `impl`, and
+    potentially a different file. This, combined with the evolution problems of
+    depending on the specific token sequence used in the `interface` definition,
+    suggest that we would need a different matching rule that was semantic
+    instead of syntactic.
+-   Having a different declaration matching rule was anticipated as creating a
+    bunch of difficulties once function overloading is added to Carbon,
+    particularly overloaded functions in interfaces.
+-   Without a declaration in the `impl` body, there were a number of problems
+    resolving how to handle a function in the `impl` that was compatible with
+    but a different signature from the interface, and when that different
+    signature would be used.
+-   These issues seemed to magnify if the interface had a default definition for
+    the function.
+
+### Different introducer for assigning associated constants in an `impl` definition
+
+Other options we considered were `provides`, `alias`, and whatever we eventually
+choose for [#5028](https://github.com/carbon-language/carbon-lang/issues/5028).
+We ultimately liked matching how you would assign associated constants in the
+declaration using the `where` operator and a rewrite constraint, particularly
+since we wanted to use the same semantics.