Browse Source

Explain more on the difference of where constraints (#4551)

This adds language to explain where the types of constraints can or can
not appear (attached-to an impl-as vs in-a type expression). And
describes the impact of using a rewrite vs same-type constraint inside
the body of the affected code, and thus why a rewrite is preferable when
the constraint is of a single facet type.
Dana Jansens 1 year ago
parent
commit
4cf2c07f7d
1 changed files with 28 additions and 10 deletions
  1. 28 10
      docs/design/generics/details.md

+ 28 - 10
docs/design/generics/details.md

@@ -2326,7 +2326,7 @@ fn PeekAtTopOfStackParameterizedImpl
   ...
 }
 fn PeekAtTopOfStackParameterized[StackType:! type]
-    (s: StackType*, T:! type where StackType is StackParameterized(T)) -> T {
+    (s: StackType*, T:! type where StackType impls StackParameterized(T)) -> T {
   return PeekAtTopOfStackParameterizedImpl(T, StackType, s);
 }
 
@@ -2505,8 +2505,21 @@ binary operator:
 -   _Same-type constraints_: `where`...`==`...
 -   _Implements constraints_: `where`...`impls`...
 
+And there are two positions that `where` can be written:
+
+-   At the end of an `impl as` declaration, before the body of the impl.
+    ```carbon
+    impl Class as Interface where .A = i32 { ... }
+    ```
+-   Inside a type expression.
+    ```carbon
+    fn F[T: Interface where .A impls OtherInterface](t: T) { ... }
+    ```
+
 A rewrite constraint is written `where .A = B`, where `A` is the name of an
-[associated constant](#associated-constants) which is rewritten to `B`.
+[associated constant](#associated-constants) which is rewritten to `B`. Any use
+of `.A` thereafter is the same as using `B`, including direct access to the API
+of `B`.
 
 The "dot followed by the name of a member" construct, like `.A`, is called a
 _designator_. The name of the designator is looked up in the constraint, and
@@ -2518,15 +2531,20 @@ constraint.
 > constraint is satisfied.
 
 A same-type constraint is written `where X == Y`, where `X` and `Y` both name
-facets. The constraint is that `X as type` must be the same as `Y as type`. In
-cases where a constraint may be written in either form, prefer a rewrite
-constraint over a same-type constraint. Note that switching between the two
-forms does not change which types satisfies the constraint, and so is a
-compatible change for callers.
+facets. The constraint is that `X as type` must be the same as `Y as type`. It
+would normally only be used in the type expression position.
+
+A same-type constraint does not rewrite the type on the left-hand side to the
+right-hand side, and they are still treated as distinct types. A value of type
+`X` [would need to be cast](#satisfying-both-facet-types) to `Y` in order to use
+the API of `Y`. So for constraint clauses that name a single facet type on the
+right-hand side, using a rewrite constraint is preferred. Note that switching
+between the two forms does not change which types satisfies the constraint, and
+so is a compatible change for callers.
 
 An implements constraint is written `where T impls C`, where `T` is a facet and
 `C` is a facet type. The constraint is that `T` satisfies the requirements of
-`C`.
+`C`. It would normally only be used in the type expression position.
 
 **References:** The definition of rewrite and same-type constraints were in
 [proposal #2173](https://github.com/carbon-language/carbon-lang/pull/2173).
@@ -2600,7 +2618,7 @@ interface Container {
   let IteratorType:! Iterator where .ElementType = ElementType;
 
   // `.Self` means `SliceType`.
-  let SliceType:! Container where .Self is SliceConstraint(ElementType, .Self);
+  let SliceType:! Container where .Self impls SliceConstraint(ElementType, .Self);
 
   // `Self` means the type implementing `Container`.
   fn GetSlice[addr self: Self*]
@@ -2989,7 +3007,7 @@ notionally does much the same thing as
 impl A as SameAs(C) { ... }
 ```
 
-where the `impl` makes use of `A is SameAs(B)` and `B is SameAs(C)`.
+where the `impl` makes use of `A impls SameAs(B)` and `B impls SameAs(C)`.
 
 In general, an `observe` declaration lists a sequence of
 [type expressions](terminology.md#type-expression) that are equal by some