Explorar el Código

Generics details 9: forward declarations (#1084)

Allow interfaces and implementations to be forward declared.

```
// Forward declare interface `F`
interface F;
class C {
  // Forward declare `C` implements `F`
  impl as F;
}
// Definitions corresponding to forward declarations
interface F { ... }
impl C as F { ... }
```

To allow members of interfaces with default definitions to be forward declared, prefix them with the keyword `default`, following #1082.

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
josh11b hace 4 años
padre
commit
06174c51f4
Se han modificado 3 ficheros con 618 adiciones y 50 borrados
  1. 377 46
      docs/design/generics/details.md
  2. 8 4
      docs/design/generics/overview.md
  3. 233 0
      proposals/p1084.md

+ 377 - 46
docs/design/generics/details.md

@@ -61,7 +61,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
         -   [Another type implements parameterized interface](#another-type-implements-parameterized-interface)
     -   [Implied constraints](#implied-constraints)
         -   [Must be legal type argument constraints](#must-be-legal-type-argument-constraints)
-    -   [Open question: referencing names in the interface being defined](#open-question-referencing-names-in-the-interface-being-defined)
+    -   [Referencing names in the interface being defined](#referencing-names-in-the-interface-being-defined)
     -   [Manual type equality](#manual-type-equality)
         -   [`observe` declarations](#observe-declarations)
 -   [Other constraints as type-of-types](#other-constraints-as-type-of-types)
@@ -92,6 +92,13 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
     -   [`final` impls](#final-impls)
         -   [Libraries that can contain `final` impls](#libraries-that-can-contain-final-impls)
     -   [Comparison to Rust](#comparison-to-rust)
+-   [Forward declarations and cyclic references](#forward-declarations-and-cyclic-references)
+    -   [Declaring interfaces and named constraints](#declaring-interfaces-and-named-constraints)
+    -   [Declaring implementations](#declaring-implementations)
+    -   [Matching and agreeing](#matching-and-agreeing)
+    -   [Declaration examples](#declaration-examples)
+    -   [Example of declaring interfaces with cyclic references](#example-of-declaring-interfaces-with-cyclic-references)
+    -   [Interfaces with parameters constrained by the same interface](#interfaces-with-parameters-constrained-by-the-same-interface)
 -   [Interface members with definitions](#interface-members-with-definitions)
     -   [Interface defaults](#interface-defaults)
     -   [`final` members](#final-members)
@@ -114,7 +121,6 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
     -   [Bridge for C++ customization points](#bridge-for-c-customization-points)
     -   [Variadic arguments](#variadic-arguments)
     -   [Range constraints on generic integers](#range-constraints-on-generic-integers)
-    -   [Separate declaration and definition of impl](#separate-declaration-and-definition-of-impl)
 -   [References](#references)
 
 <!-- tocstop -->
@@ -2946,10 +2952,10 @@ fn NumDistinct[T:! Type where HashSet(.Self) is Type]
 This has the same advantages over repeating the constraints on `HashSet`
 arguments in the type of `T` as the general implied constraints above.
 
-### Open question: referencing names in the interface being defined
+### Referencing names in the interface being defined
 
-Should the constraint in a `where` clause be required to only reference earlier
-names from this scope, as in this example?
+The constraint in a `where` clause is required to only reference earlier names
+from this scope, as in this example:
 
 ```
 interface Graph {
@@ -2958,22 +2964,6 @@ interface Graph {
 }
 ```
 
-The downside is that if you could reference later names, there is a more
-pleasingly symmetric formulation of those same constraints:
-
-```
-interface Graph {
-  let E: Edge where .V == V;
-  let V: Vert where .E == E;
-}
-```
-
-**TODO:** Revisit this question once issue
-[#472: Open question: Calling functions defined later in the same file](https://github.com/carbon-language/carbon-lang/issues/472)
-and proposal
-[#875: Principle: information accumulation](https://github.com/carbon-language/carbon-lang/pull/875)
-are resolved.
-
 ### Manual type equality
 
 Imagine we have some function with generic parameters:
@@ -3937,7 +3927,8 @@ Since at most one library can define impls with a given type structure, all
 impls with a given type structure must be in the same library. Furthermore by
 the [impl declaration access rules](#access), they will be defined in the API
 file for the library if they could match any query from outside the library. If
-there is more than one impl with that type structure, they must be written
+there is more than one impl with that type structure, they must be
+[defined](#implementing-interfaces) or [declared](#declaring-implementations)
 together in a prioritization block. Once a type structure is selected for a
 query, the first impl in the prioritization block that matches is selected.
 
@@ -4286,12 +4277,329 @@ differences between the Carbon and Rust plans:
     ordering on type structures, picking one as higher priority even without one
     being more specific in the sense of only applying to a subset of types.
 
+## Forward declarations and cyclic references
+
+Interfaces, named constraints, and their implementations may be forward declared
+and then later defined. This is needed to allow cyclic references, for example
+when declaring the edges and nodes of a graph. It is also a tool that may be
+used to make code more readable.
+
+The [interface](#interfaces), [named constraint](#named-constraints), and
+[implementation](#implementing-interfaces) sections describe the syntax for
+their _definition_, which consists of a declaration followed by a body contained
+in curly braces `{` ... `}`. A _forward declaration_ is a declaration followed
+by a semicolon `;`. A forward declaration is a promise that the entity being
+declared will be defined later. Between the first declaration of an entity,
+which may be in a forward declaration or the first part of a definition, and the
+end of the definition the interface or implementation is called _incomplete_.
+There are additional restrictions on how the name of an incomplete entity may be
+used.
+
+### Declaring interfaces and named constraints
+
+The declaration for an interface or named constraint consists of:
+
+-   an optional access-control keyword like `private`,
+-   the keyword introducer `interface`, `constraint`, or `template constraint`,
+-   the name of the interface or constraint, and
+-   the parameter list, if any.
+
+The name of an interface or constraint can not be used until its first
+declaration is complete. In particular, it is illegal to use the name of the
+interface in its parameter list. There is a
+[workaround](#interfaces-with-parameters-constrained-by-the-same-interface) for
+the use cases when this would come up.
+
+An expression forming a constraint, such as `C & D`, is incomplete if any of the
+interfaces or constraints used in the expression are incomplete. A constraint
+expression using a [`where` clause](#where-constraints), like `C where ...`, is
+invalid if `C` is incomplete, since there is no way to look up member names of
+`C` that appear after `where`.
+
+An interface or named constraint may be forward declared subject to these rules:
+
+-   The definition must be in the same file as the declaration.
+-   Only the first declaration may have an access-control keyword.
+-   An incomplete interface or named constraint may be used as constraints in
+    declarations of types, functions, interfaces, or named constraints. This
+    includes an `impl as` or `extends` declaration inside an interface or named
+    constraint, but excludes specifying the values for associated constants
+    because that would involve name lookup into the incomplete constraint.
+-   An attempt to define the body of a generic function using an incomplete
+    interface or named constraint is illegal.
+-   An attempt to call a generic function using an incomplete interface or named
+    constraint in its signature is illegal.
+-   Any name lookup into an incomplete interface or named constraint is an
+    error. For example, it is illegal to attempt to access a member of an
+    interface using `MyInterface.MemberName` or constrain a member using a
+    `where` clause.
+
+### Declaring implementations
+
+The declaration of an interface implementation consists of:
+
+-   optional modifier keywords `final`, `external`,
+-   the keyword introducer `impl`,
+-   an optional deduced parameter list in square brackets `[`...`]`,
+-   a type, including an optional parameter pattern,
+-   the keyword `as`, and
+-   a [type-of-type](#type-of-types), including an optional
+    [parameter pattern](#parameterized-interfaces) and
+    [`where` clause](#where-constraints) assigning
+    [associated constants](#associated-constants) and
+    [associated types](#associated-types).
+
+An implementation of an interface for a type may be forward declared subject to
+these rules:
+
+-   The definition must be in the same library as the declaration. They must
+    either be in the same file, or the declaration can be in the API file and
+    the definition in an impl file. **Future work:** Carbon may require the
+    definition of [parameterized impls](#parameterized-impls) to be in the API
+    file, to support separate compilation.
+-   If there is both a forward declaration and a definition, only the first
+    declaration must specify the assignment of associated constants with a
+    `where` clause. Later declarations may omit the `where` clause by writing
+    `where _` instead.
+-   You may forward declare an implementation of a defined interface but not an
+    incomplete interface. This allows the assignment of associated constants in
+    the `impl` declaration to be verified. An impl forward declaration may be
+    for any declared type, whether it is incomplete or defined. Note that this
+    does not apply to `impl as` declarations in an interface or named constraint
+    definition, as those are considered interface requirements not forward
+    declarations.
+-   Every internal implementation must be declared (or defined) inside the scope
+    of the class definition. It may also be declared before the class definition
+    or defined afterwards. Note that the class itself is incomplete in the scope
+    of the class definition, but member function bodies defined inline are
+    processed
+    [as if they appeared immediately after the end of the outermost enclosing class](/docs/project/principles/information_accumulation.md#exceptions).
+-   For [coherence](goals.md#coherence), we require that any impl that matches
+    an [impl lookup](#impl-lookup) query in the same file, must be declared
+    before the query. This can be done with a definition or a forward
+    declaration.
+
+### Matching and agreeing
+
+Carbon needs to determine if two declarations match in order to say which
+definition a forward declaration corresponds to and to verify that nothing is
+defined twice. Declarations that match must also agree, meaning they are
+consistent with each other.
+
+Interface and named constraint declarations match if their names are the same
+after name and alias resolution. To agree:
+
+-   The introducer keyword or keywords much be the same.
+-   The types and order of parameters in the parameter list, if any, must match.
+    The parameter names may be omitted, but if they are included in both
+    declarations, they must match.
+-   Types agree if they correspond to the same expression tree, after name and
+    alias resolution and canonicalization of parentheses. Note that no other
+    evaluation of type expressions is performed.
+
+Interface implementation declarations match if the type and interface
+expressions match:
+
+-   If the type part is omitted, it is rewritten to `Self` in the context of the
+    declaration.
+-   `Self` is rewritted to its meaning in the scope it is used. In a class
+    scope, this should match the type name and optional parameter expression
+    after `class`. So in `class MyClass extends MyBase { ... }`, `Self` is
+    rewritten to `MyClass`. In `class Vector(T:! Movable) { ... }`, `Self` is
+    rewritten to `Vector(T:! Movable)`.
+-   Types match if they have the same name after name and alias resolution and
+    the same parameters, or are the same type parameter.
+-   Interfaces match if they have the same name after name and alias resolution
+    and the same parameters. Note that a named constraint that is equivalent to
+    an interface, as in `constraint Equivalent { extends MyInterface; }`, is not
+    considered to match.
+
+For implementations to agree:
+
+-   The presence of modifier keywords such as `external` before `impl` must
+    match between a forward declaration and definition.
+-   If either declaration includes a `where` clause, they must both include one.
+    If neither uses `where _`, they must match in that they produce the
+    associated constants with the same values considered separately.
+
+### Declaration examples
+
+```
+// Forward declaration of interfaces
+interface Interface1;
+interface Interface2;
+interface Interface3;
+interface Interface4;
+interface Interface5;
+interface Interface6;
+
+// Forward declaration of class type
+class MyClass;
+
+// ❌ Illegal: Can't declare implementation of incomplete
+//             interface.
+// external impl MyClass as Interface1;
+
+// Definition of interfaces that were previously declared
+interface Interface1 {
+  let T1:! Type;
+}
+interface Interface2 {
+  let T2:! Type;
+}
+interface Interface3 {
+  let T3:! Type;
+}
+interface Interface4 {
+  let T4:! Type;
+}
+
+// Forward declaration of external implementations
+external impl MyClass as Interface1 where .T1 = i32;
+external impl MyClass as Interface2 where .T2 = bool;
+
+// Forward declaration of an internal implementation
+impl MyClass as Interface3 where .T3 = f32;
+impl MyClass as Interface4 where .T4 = String;
+
+interface Interface5 {
+  let T5:! Type;
+}
+interface Interface6 {
+  let T6:! Type;
+}
+
+// Definition of the previously declared class type
+class MyClass {
+  // Definition of previously declared external impl.
+  // Note: no need to repeat assignments to associated
+  // constants.
+  external impl as Interface1 where _ { }
+
+  // Definition of previously declared internal impl.
+  // Note: allowed even though `MyClass` is incomplete.
+  // Note: allowed but not required to repeat `where`
+  // clause.
+  impl as Interface3 where .T3 = f32 { }
+
+  // Redeclaration of previously declared internal impl.
+  // Every internal implementation must be declared in
+  // the class definition.
+  impl as Interface4 where _;
+
+  // Forward declaration of external implementation.
+  external impl MyClass as Interface5 where .T5 = u64;
+
+  // Forward declaration of internal implementation.
+  impl MyClass as Interface6 where .T6 = u8;
+}
+
+// It would be legal to move the following definitions
+// from the API file to the implementation file for
+// this library.
+
+// Definition of previously declared external impls.
+external impl MyClass as Interface2 where _ { }
+external impl MyClass as Interface5 where _ { }
+
+// Definition of previously declared internal impls.
+impl MyClass as Interface4 where _ { }
+impl MyClass as Interface6 where _ { }
+```
+
+### Example of declaring interfaces with cyclic references
+
+In this example, `Node` has an `EdgeType` associated type that is constrained to
+implement `Edge`, and `Edge` has a `NodeType` associated type that is
+constrained to implement `Node`. Furthermore, the `NodeType` of an `EdgeType` is
+the original type, and the other way around. This is accomplished by naming and
+then forward declaring the constraints that can't be stated directly:
+
+```
+// Forward declare interfaces used in
+// parameter lists of constraints.
+interface Edge;
+interface Node;
+
+// Forward declare named constraints used in
+// interface definitions.
+private constraint EdgeFor(N:! Node);
+private constraint NodeFor(E:! Edge);
+
+// Define interfaces using named constraints.
+interface Edge {
+  let NodeType:! NodeFor(Self);
+  fn Head[me: Self]() -> NodeType;
+}
+interface Node {
+  let EdgeType:! EdgeFor(Self);
+  fn Edges[me: Self]() -> Vector(EdgeType);
+}
+
+// Now that the interfaces are defined, can
+// refer to members of the interface, so it is
+// now legal to define the named constraints.
+constraint EdgeFor(N:! Node) {
+  extends Edge where .NodeType == N;
+}
+constraint NodeFor(E:! Edge) {
+  extends Node where .EdgeType == E;
+}
+```
+
+### Interfaces with parameters constrained by the same interface
+
+To work around
+[the restriction about not being able to name an interface in its parameter list](#declaring-interfaces-and-named-constraints),
+instead include that requirement in the body of the interface.
+
+```
+// Want to require that `T` satisfies `CommonType(Self)`,
+// but that can't be done in the parameter list.
+interface CommonType(T:! Type) {
+  let Result:! Type;
+  // Instead add the requirement inside the definition.
+  impl T as CommonType(Self);
+}
+```
+
+Note however that `CommonType` is still incomplete inside its definition, so no
+constraints on members of `CommonType` are allowed.
+
+```
+interface CommonType(T:! Type) {
+  let Result:! Type;
+  // ❌ Illegal: `CommonType` is incomplete
+  impl T as CommonType(Self) where .Result == Result;
+}
+```
+
+Instead, a forward-declared named constraint can be used in place of the
+constraint that can only be defined later. This is
+[the same strategy used to work around cyclic references](#example-of-declaring-interfaces-with-cyclic-references).
+
+```
+private constraint CommonTypeResult(T:! Type, R:! Type);
+
+interface CommonType(T:! Type) {
+  let Result:! Type;
+  // ✅ Allowed: `CommonTypeResult` is incomplete, but
+  //             no members are accessed.
+  impl T as CommonTypeResult(Self, Result);
+}
+
+constraint CommonTypeResult(T:! Type, R:! Type) {
+  extends CommonType(T) where .Result == R;
+}
+```
+
 ## Interface members with definitions
 
 Interfaces may provide definitions for members, such as a function body for an
 associated function or method or a value for an associated constant. If these
-definitions may be overridden in implementations, they are called "defaults."
-Otherwise they are called "final members."
+definitions may be overridden in implementations, they are called "defaults" and
+prefixed with the `default` keyword. Otherwise they are called "final members"
+and prefixed with the `final` keyword.
 
 ### Interface defaults
 
@@ -4303,12 +4611,28 @@ interface Vector {
   fn Add[me: Self](b: Self) -> Self;
   fn Scale[me: Self](v: f64) -> Self;
   // Default definition of `Invert` calls `Scale`.
-  fn Invert[me: Self]() -> Self {
+  default fn Invert[me: Self]() -> Self {
     return me.Scale(-1.0);
   }
 }
 ```
 
+A default function or method may also be defined out of line, later in the same
+file as the interface definition:
+
+```
+interface Vector {
+  fn Add[me: Self](b: Self) -> Self;
+  fn Scale[me: Self](v: f64) -> Self;
+  default fn Invert[me: Self]() -> Self;
+}
+// `Vector` is considered complete at this point,
+// even though `Vector.Invert` is still incomplete.
+fn Vector.Invert[me: Self]() -> Self {
+  return me.Scale(-1.0);
+}
+```
+
 An impl of that interface for a type may omit a definition of `Invert` to use
 the default, or provide a definition to override the default.
 
@@ -4324,7 +4648,7 @@ types, and interface parameters, using the `= <default value>` syntax.
 
 ```
 interface Add(Right:! Type = Self) {
-  let Result:! Type = Self;
+  default let Result:! Type = Self;
   fn DoAdd[me: Self](right: Right) -> Result;
 }
 
@@ -4354,7 +4678,7 @@ More generally, default expressions may reference other associated types or
 ```
 interface Iterator {
   let Element:! Type;
-  let Pointer:! Type = Element*;
+  default let Pointer:! Type = Element*;
 }
 ```
 
@@ -4363,11 +4687,11 @@ interface.
 
 ```
 interface TotalOrder {
-  fn TotalLess[me: Self](right: Self) -> Bool;
+  fn TotalLess[me: Self](right: Self) -> bool;
   // ❌ Illegal: May not provide definition
   //             for required interface.
-  impl PartialOrder {
-    fn PartialLess[me: Self](right: Self) -> Bool {
+  impl as PartialOrder {
+    fn PartialLess[me: Self](right: Self) -> bool {
       return me.TotalLess(right);
     }
   }
@@ -4379,12 +4703,12 @@ instead:
 
 ```
 interface TotalOrder {
-  fn TotalLess[me: Self](right: Self) -> Bool;
-  impl PartialOrder;
+  fn TotalLess[me: Self](right: Self) -> bool;
+  impl as PartialOrder;
 }
 
 external impl [T:! TotalOrder] T as PartialOrder {
-  fn PartialLess[me: Self](right: Self) -> Bool {
+  fn PartialLess[me: Self](right: Self) -> bool {
     return me.TotalLess(right);
   }
 }
@@ -4408,18 +4732,18 @@ overridden in impls.
 
 ```
 interface TotalOrder {
-  fn TotalLess[me: Self](right: Self) -> Bool;
-  final fn TotalGreater[me: Self](right: Self) -> Bool {
+  fn TotalLess[me: Self](right: Self) -> bool;
+  final fn TotalGreater[me: Self](right: Self) -> bool {
     return right.TotalLess(me);
   }
 }
 
 class String {
   impl as TotalOrder {
-    fn TotalLess[me: Self](right: Self) -> Bool { ... }
+    fn TotalLess[me: Self](right: Self) -> bool { ... }
     // ❌ Illegal: May not provide definition of final
     //             method `TotalGreater`.
-    fn TotalGreater[me: Self](right: Self) -> Bool { ... }
+    fn TotalGreater[me: Self](right: Self) -> bool { ... }
   }
 }
 
@@ -4432,6 +4756,20 @@ interface Add(T:! Type = Self) {
 }
 ```
 
+Final members may also be defined out-of-line:
+
+```
+interface TotalOrder {
+  fn TotalLess[me: Self](right: Self) -> bool;
+  final fn TotalGreater[me: Self](right: Self) -> bool;
+}
+// `TotalOrder` is considered complete at this point, even
+// though `TotalOrder.TotalGreater` is not yet defined.
+fn TotalOrder.TotalGreater[me: Self](right: Self) -> bool {
+ return right.TotalLess(me);
+}
+```
+
 There are a few reasons for this feature:
 
 -   When overriding would be inappropriate.
@@ -4891,14 +5229,6 @@ between multiple generic integer parameters. For example, if `J < K` and
 secondary syntactic concern about how to write this kind of constraint on a
 parameter, as opposed to an associated type, as in `N:! u32 where ___ >= 2`.
 
-### Separate declaration and definition of impl
-
-There is a desire to support a short declaration that a type implements an
-interface without giving a full definition of that implementation for API files.
-Everything needed for type checking is provided in the interface definition,
-except for the assignments to associated constants and types, and so those must
-be included in the declaration as well.
-
 ## References
 
 -   [#553: Generics details part 1](https://github.com/carbon-language/carbon-lang/pull/553)
@@ -4909,5 +5239,6 @@ be included in the declaration as well.
 -   [#950: Generic details 6: remove facets](https://github.com/carbon-language/carbon-lang/pull/950)
 -   [#983: Generic details 7: final impls](https://github.com/carbon-language/carbon-lang/pull/983)
 -   [#990: Generics details 8: interface default and final members](https://github.com/carbon-language/carbon-lang/pull/990)
--   [#1013: Generics: Set associated constants using where constraints](https://github.com/carbon-language/carbon-lang/pull/1013)
+-   [#1013: Generics: Set associated constants using `where` constraints](https://github.com/carbon-language/carbon-lang/pull/1013)
+-   [#1084: Generics details 9: forward declarations](https://github.com/carbon-language/carbon-lang/pull/1084)
 -   [#1144: Generic details 11: operator overloading](https://github.com/carbon-language/carbon-lang/pull/1144)

+ 8 - 4
docs/design/generics/overview.md

@@ -163,6 +163,12 @@ interface Comparable {
 }
 ```
 
+Functions and methods may be given a default implementation by prefixing the
+declaration with `default` and putting the function body in curly braces
+`{`...`}` in place of the terminating `;` of the function declaration. To
+prevent that implementation from being overridden, use `final` instead of
+`default`.
+
 Interfaces describe functionality, but not data; no variables may be declared in
 an interface.
 
@@ -648,12 +654,9 @@ external impl Distance as MultipliableWith(like f64) ...
 
 ## Future work
 
--   Support functions should have a way to accept types that types that vary at
-    runtime.
+-   Functions should have a way to accept types that vary at runtime.
 -   You should have the ability to mark entities as `upcoming` or `deprecated`
     to support evolution.
--   There should be a way to provide default implementations of methods in
-    interfaces and other ways to reuse code across implementations.
 -   There should be a way to define generic associated and higher-ranked/kinded
     types.
 
@@ -665,3 +668,4 @@ external impl Distance as MultipliableWith(like f64) ...
 -   [#920: Generic parameterized impls (details 5)](https://github.com/carbon-language/carbon-lang/pull/920)
 -   [#950: Generic details 6: remove facets](https://github.com/carbon-language/carbon-lang/pull/950)
 -   [#1013: Generics: Set associated constants using `where` constraints](https://github.com/carbon-language/carbon-lang/pull/1013)
+-   [#1084: Generics details 9: forward declarations](https://github.com/carbon-language/carbon-lang/pull/1084)

+ 233 - 0
proposals/p1084.md

@@ -0,0 +1,233 @@
+# Generics details 9: forward declarations
+
+<!--
+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/1084)
+
+<!-- toc -->
+
+## Table of contents
+
+-   [Problem](#problem)
+-   [Background](#background)
+-   [Proposal](#proposal)
+-   [Rationale based on Carbon's goals](#rationale-based-on-carbons-goals)
+-   [Alternatives considered](#alternatives-considered)
+    -   [No `default` keyword on interface members](#no-default-keyword-on-interface-members)
+    -   [Declaring an implementation of an incomplete interface](#declaring-an-implementation-of-an-incomplete-interface)
+    -   [Allow definition of private interfaces in separate impl file](#allow-definition-of-private-interfaces-in-separate-impl-file)
+    -   [No implementations for incomplete types](#no-implementations-for-incomplete-types)
+    -   [No forward declaration of named constraints](#no-forward-declaration-of-named-constraints)
+    -   [Repeating `private` in both declaration and definition](#repeating-private-in-both-declaration-and-definition)
+    -   [Allow function bodies using incomplete interfaces](#allow-function-bodies-using-incomplete-interfaces)
+    -   [Don't require parameter names to match](#dont-require-parameter-names-to-match)
+    -   [Allow deduced parameters to vary](#allow-deduced-parameters-to-vary)
+
+<!-- tocstop -->
+
+## Problem
+
+Developers want to organize their code for readability and convenience. For
+example, they may want to present the public API of their type in a concise way.
+That includes the ability to say a type implements an interface without
+repeating the full contents of that interface.
+
+The Carbon compiler can give better diagnostics if it can assume every
+identifier it encounters refers to some earlier declaration in the file.
+However, sometimes multiple entities will reference each other in a cycle so no
+one entity can be defined first.
+
+## Background
+
+We have decided to tackle these problems in a manner similar to C++ by
+supporting forward declarations:
+
+-   [issue #472: Open question: Calling functions defined later in the same file](https://github.com/carbon-language/carbon-lang/issues/472)
+-   [proposal #875: Principle: information accumulation](https://github.com/carbon-language/carbon-lang/pull/875).
+
+Use of the `default` keyword in `interface` definitions to allow defaulted
+members to be defined out-of-line was originally proposed in
+[withdrawn proposal #1034](https://github.com/carbon-language/carbon-lang/pull/1034).
+
+This proposal implements the decisions in
+[issue #1132: How do we match forward declarations with their definitions?](https://github.com/carbon-language/carbon-lang/issues/1132)
+as they apply to generic interfaces, implementations, and so on.
+
+## Proposal
+
+This proposal makes changes to these sections of the
+[generics details design document](/docs/design/generics/details.md):
+
+-   [Forward declarations and cyclic references](/docs/design/generics/details.md#forward-declarations-and-cyclic-references)
+    section added
+-   [Interface members with definitions](/docs/design/generics/details.md#interface-members-with-definitions)
+    section added to
+
+## Rationale based on Carbon's goals
+
+Forward declarations are intended to advance these goals:
+
+-   [Language tools and ecosystem](/docs/project/goals.md#language-tools-and-ecosystem),
+    by making Carbon easier to interpret by tooling in a single top-down pass.
+-   [Code that is easy to read, understand, and write](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write),
+    by allowing developers to separate declaration from definition when
+    organizing the presentation of their code, and imposing constraints that
+    allow readers to interpret the code with less skipping around.
+-   [Fast and scalable development](/docs/project/goals.md#fast-and-scalable-development)
+    from potential build performance improvements that come from allowing an
+    `impl` to be defined in the `impl` file instead of the `api` file.
+
+The rationale behind using forward declarations are covered in more detail in:
+
+-   [issue #472: Open question: Calling functions defined later in the same file](https://github.com/carbon-language/carbon-lang/issues/472)
+-   [proposal #875: Principle: information accumulation](https://github.com/carbon-language/carbon-lang/pull/875).
+
+## Alternatives considered
+
+### No `default` keyword on interface members
+
+Without the `default` keyword, default definitions would always have to be
+inline. We discussed this in
+[the #syntax channel on Discord](https://discord.com/channels/655572317891461132/709488742942900284/941408009689641010)
+which eventually led to the
+[question-for-leads issue #1082: Use `default` keyword in interface defaults?](https://github.com/carbon-language/carbon-lang/issues/1082).
+
+The conclusion was that we did want to support forward declarations of default
+interface members. To make it so that users would have a single place to look to
+see whether the member had a definition even when it might be out of line, we
+decided to use a `default` keyword as a prefix of the declaration. We considered
+putting the keyword at the end of the declaration, but we decided it was more
+readable if it wasn't next to the return type. It was also more consistent with
+`final`, an alternative to `default`, which also now supports forward
+declaration.
+
+### Declaring an implementation of an incomplete interface
+
+We did not have any use cases for forward declaring an impl of an incomplete
+interface, and so we took the conservative position of forbidding that. We could
+add this feature in the future if use cases were found, but clearly we can't
+have impl definitions until the interface is defined.
+
+### Allow definition of private interfaces in separate impl file
+
+This proposal requires the definition of an interface to be in the same file as
+any declaration of it. We
+[anticipate](https://github.com/carbon-language/carbon-lang/pull/1084#discussion_r824214281)
+the possibility that we will find a use case for declaring a private interface
+in an API file that is defined in the corresponding impl file. An example where
+this may arise is if the constraint is only used when defining private members
+of an exported class. We would be willing to change if we see demand for this in
+the future.
+
+### No implementations for incomplete types
+
+For simplicity, generally Carbon entities should either be "incomplete" or
+"defined" and never "partially defined". However, the set of interfaces
+implemented for a type is by necessity only ever partially known by the nature
+of being the
+[one static open extension mechanism](https://github.com/carbon-language/carbon-lang/pull/998)
+in Carbon. As a result, we felt there was more leeway for implementing
+interfaces for incomplete types. This happens incidentally when implementing the
+interface inline in the scope of a class definition. We also wanted to allow it
+in the case where there was only a forward declaration of the type in an API
+file.
+
+### No forward declaration of named constraints
+
+We considered omitting the ability to forward declare named constraints, but we
+discovered that ability made declaring interfaces with cyclic dependencies
+easier and cleaner. Without this feature,
+[the graph example of cyclic references](/docs/design/generics/details.md#example-of-declaring-interfaces-with-cyclic-references)
+looked like this instead:
+
+```
+// Forward declaration of interface
+interface EdgeInterface;
+
+// Definition that only uses the declaration of
+// `EdgeInterface`, not its definition.
+interface NodeBootstrap {
+  let EdgeType:! EdgeInterface;
+  fn Edges[me: Self]() -> Vector(EdgeType);
+}
+
+// Now can define `EdgeInterface` in terms of
+// `NodeBootstrap`.
+interface EdgeInterface {
+  let NodeType:! NodeBootstrap where .EdgeType == Self;
+  fn Head[me: Self]() -> NodeType;
+}
+
+// Make `NodeInterface` a named constraint defined in
+// terms of `NodeBootstrap`, adding in constraints that
+// couldn't be written until `EdgeInterface` was defined.
+constraint NodeInterface {
+  extends NodeBootsrap where .EdgeType.NodeType == Self;
+}
+```
+
+We did not like how the definition of `NodeInterface` was split into two pieces,
+making it harder to understand what it contained.
+
+This question was discussed in
+[the #generics channel on Discord](https://discord.com/channels/655572317891461132/941071822756143115/951288264315265114).
+
+### Repeating `private` in both declaration and definition
+
+We considered repeating the access-control keyword `private` as a prefix of all
+`impl` declarations and definitions. The
+[current rule](/docs/design/generics/details.md#declaring-interfaces-and-named-constraints)
+only marks the first declaration or definition, which is consistent with
+[the policy of not repeating access-control keywords stated in an API file in an impl file](/docs/design/code_and_name_organization#exporting-entities-from-an-api-file).
+
+This was discussed in
+[the #syntax channel on Discord](https://discord.com/channels/655572317891461132/709488742942900284/951520959544823868),
+but this decision should be considered provisional since it was not considered
+deeply. We would be open to revisiting this decision in the future, once we had
+some experience with it.
+
+### Allow function bodies using incomplete interfaces
+
+We
+[considered](https://docs.google.com/document/d/1cRrhRrmaUf2hVi2lFcHsYo2j0jI6t9RGZoYjWhRxp14/edit?resourcekey=0-xWHBEZ8zIqnJiB4yfBSLfA#heading=h.oqmpxtubjmkm)
+allowing a function definition to use an incomplete interface. One concern was
+whether the criteria for when the function body depended on something in the
+interface's definition would be too subtle for developers to reason about. We
+eventually concluded that, unless using a monomorphization compilation strategy,
+efficient code generation for a generic function would need to use the
+interface's definition. For example, an interface that represented a single
+function call might use a function pointer instead of a witness table. This same
+argument led to the requirement that the interface's definition be visible at
+call sites as well.
+
+### Don't require parameter names to match
+
+We decided to diverge from C++ in requiring parameter names to match between
+declarations for a few reasons:
+
+-   wanting to avoid the confusion that we've experienced when they don't match,
+    noting that common C++ lint tools ask to make them match;
+-   wanting reflection to return a single parameter name for a parameter; and
+-   wanting the parameter names to be consistent with the single docstring we
+    expect to associate with a function.
+
+This was discussed in
+[open discussion on 2022-03-14](https://docs.google.com/document/d/1cRrhRrmaUf2hVi2lFcHsYo2j0jI6t9RGZoYjWhRxp14/edit?resourcekey=0-xWHBEZ8zIqnJiB4yfBSLfA#heading=h.oqmpxtubjmkm)
+and
+[question-for-leads issue #1132](https://github.com/carbon-language/carbon-lang/issues/1132).
+
+### Allow deduced parameters to vary
+
+We decided to apply
+[the same matching requirements for other parameter names](#dont-require-parameter-names-to-match)
+to deduced parameters for consistency. We may in the future allow some rewrites
+between equivalent expressions, such as between `Vector(T:! Type)` and
+`[T:! Type] Vector(T)`, but for now we are starting with the more restrictive
+rule. This was discussed in
+[open discussion on 2022-03-24](https://docs.google.com/document/d/1cRrhRrmaUf2hVi2lFcHsYo2j0jI6t9RGZoYjWhRxp14/edit?resourcekey=0-xWHBEZ8zIqnJiB4yfBSLfA#heading=h.w4zgqvarhnbn)
+and in
+[#syntax channel on Discord](https://discord.com/channels/655572317891461132/709488742942900284/953798170750615622).