|
|
@@ -112,6 +112,7 @@ 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 -->
|
|
|
@@ -1900,13 +1901,13 @@ interface NSpacePoint {
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-Implementations of `NSpacePoint` for different types might have different values
|
|
|
-for `N`:
|
|
|
+An implementation of an interface specifies values for associated constants with
|
|
|
+a [`where` clause](#where-constraints). For example, implementations of
|
|
|
+`NSpacePoint` for different types might have different values for `N`:
|
|
|
|
|
|
```
|
|
|
class Point2D {
|
|
|
- impl as NSpacePoint {
|
|
|
- let N:! i32 = 2;
|
|
|
+ impl as NSpacePoint where .N = 2 {
|
|
|
fn Get[addr me: Self*](i: i32) -> f64 { ... }
|
|
|
fn Set[addr me: Self*](i: i32, value: f64) { ... }
|
|
|
fn SetAll[addr me: Self*](value: Array(f64, 2)) { ... }
|
|
|
@@ -1914,8 +1915,7 @@ class Point2D {
|
|
|
}
|
|
|
|
|
|
class Point3D {
|
|
|
- impl as NSpacePoint {
|
|
|
- let N:! i32 = 3;
|
|
|
+ impl as NSpacePoint where .N = 3 {
|
|
|
fn Get[addr me: Self*](i: i32) -> f64 { ... }
|
|
|
fn Set[addr me: Self*](i: i32, value: f64) { ... }
|
|
|
fn SetAll[addr me: Self*](value: Array(f64, 3)) { ... }
|
|
|
@@ -1923,7 +1923,16 @@ class Point3D {
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-And these values may be accessed as members of the type:
|
|
|
+Multiple assignments to associated constants may be joined using the `and`
|
|
|
+keyword. The list of assignments is subject to two restrictions:
|
|
|
+
|
|
|
+- An implementation of an interface cannot specify a value for a
|
|
|
+ [`final`](#final-members) associated constant.
|
|
|
+- If an associated constant doesn't have a
|
|
|
+ [default value](#interface-defaults), every implementation must specify its
|
|
|
+ value.
|
|
|
+
|
|
|
+These values may be accessed as members of the type:
|
|
|
|
|
|
```
|
|
|
Assert(Point2D.N == 2);
|
|
|
@@ -2021,9 +2030,8 @@ class DynamicArray(T:! Type) {
|
|
|
fn Insert[addr me: Self*](pos: IteratorType, value: T);
|
|
|
fn Remove[addr me: Self*](pos: IteratorType);
|
|
|
|
|
|
- impl as StackAssociatedType {
|
|
|
- // Set the associated type `ElementType` to `T`.
|
|
|
- let ElementType:! Type = T;
|
|
|
+ // Set the associated type `ElementType` to `T`.
|
|
|
+ impl as StackAssociatedType where .ElementType = T {
|
|
|
fn Push[addr me: Self*](value: ElementType) {
|
|
|
me->Insert(me->End(), value);
|
|
|
}
|
|
|
@@ -2442,6 +2450,10 @@ constraint Point2DInterface {
|
|
|
}
|
|
|
```
|
|
|
|
|
|
+This syntax is also used to specify the values of
|
|
|
+[associated constants](#associated-constants) when implementing an interface for
|
|
|
+a type.
|
|
|
+
|
|
|
**Concern:** Using `=` for this use case is not consistent with other `where`
|
|
|
clauses that write a boolean expression that evaluates to `true` when the
|
|
|
constraint is satisfied.
|
|
|
@@ -2486,6 +2498,9 @@ constraint IntStack {
|
|
|
}
|
|
|
```
|
|
|
|
|
|
+This syntax is also used to specify the values of
|
|
|
+[associated types](#associated-types) when implementing an interface for a type.
|
|
|
+
|
|
|
##### Equal generic types
|
|
|
|
|
|
Alternatively, two generic types could be constrained to be equal to each other,
|
|
|
@@ -3534,8 +3549,7 @@ lexically in the class' scope:
|
|
|
|
|
|
```
|
|
|
class Vector(T:! Type) {
|
|
|
- impl as Iterable {
|
|
|
- let ElementType:! Type = T;
|
|
|
+ impl as Iterable where .ElementType = T {
|
|
|
...
|
|
|
}
|
|
|
}
|
|
|
@@ -3545,8 +3559,7 @@ This is equivalent to naming the type between `impl` and `as`:
|
|
|
|
|
|
```
|
|
|
class Vector(T:! Type) {
|
|
|
- impl Vector(T) as Iterable {
|
|
|
- let ElementType:! Type = T;
|
|
|
+ impl Vector(T) as Iterable where .ElementType = T {
|
|
|
...
|
|
|
}
|
|
|
}
|
|
|
@@ -3556,13 +3569,13 @@ An impl may be declared [external](#external-impl) by adding an `external`
|
|
|
keyword before `impl`. External impls may also be declared out-of-line:
|
|
|
|
|
|
```
|
|
|
-external impl [T:! Type] Vector(T) as Iterable {
|
|
|
- let ElementType:! Type = T;
|
|
|
+external impl [T:! Type] Vector(T) as Iterable
|
|
|
+ where .ElementType = T {
|
|
|
...
|
|
|
}
|
|
|
// This syntax is also allowed:
|
|
|
-external impl Vector(T:! Type) as Iterable {
|
|
|
- let ElementType:! Type = T;
|
|
|
+external impl Vector(T:! Type) as Iterable
|
|
|
+ where .ElementType = T {
|
|
|
...
|
|
|
}
|
|
|
```
|
|
|
@@ -3758,9 +3771,8 @@ where blanket impls arise:
|
|
|
- `T` implements `CommonType(T)` for all `T`
|
|
|
|
|
|
```
|
|
|
- external impl [T:! Type] T as CommonType(T) {
|
|
|
- let Result:! auto = T;
|
|
|
- }
|
|
|
+ external impl [T:! Type] T as CommonType(T)
|
|
|
+ where .Result = T { }
|
|
|
```
|
|
|
|
|
|
This means that every type is the common type with itself.
|
|
|
@@ -3857,6 +3869,8 @@ parameters are replaced the declarations are normalized as follows:
|
|
|
between the `impl` and `as` keywords if the type is left out.
|
|
|
- Pointer types `T*` are replaced with `Ptr(T)`.
|
|
|
- The `external` keyword is removed, if present.
|
|
|
+- Any `where` clauses that are setting associated constants or types are
|
|
|
+ removed.
|
|
|
|
|
|
The type structure will always contain a single interface name, which is the
|
|
|
name of the interface being implemented, and some number of type names. Type
|
|
|
@@ -3995,12 +4009,10 @@ interface True {}
|
|
|
impl Y as True {}
|
|
|
interface Z(T:! Type) { let Cond:! Type; }
|
|
|
match_first {
|
|
|
- impl [T:! Type, U:! Z(T) where .Cond is True] T as Z(U) {
|
|
|
- let Cond:! Type = N;
|
|
|
- }
|
|
|
- impl [T:! Type, U:! Type] T as Z(U) {
|
|
|
- let Cond:! Type = Y;
|
|
|
- }
|
|
|
+ impl [T:! Type, U:! Z(T) where .Cond is True] T as Z(U)
|
|
|
+ where .Cond = N { }
|
|
|
+ impl [T:! Type, U:! Type] T as Z(U)
|
|
|
+ where .Cond = Y { }
|
|
|
}
|
|
|
```
|
|
|
|
|
|
@@ -4026,15 +4038,12 @@ class B {}
|
|
|
class C {}
|
|
|
interface D(T:! Type) { let Cond:! Type; }
|
|
|
match_first {
|
|
|
- impl [T:! Type, U:! D(T) where .Cond = B] T as D(U) {
|
|
|
- let Cond:! Type = C;
|
|
|
- }
|
|
|
- impl [T:! Type, U:! D(T) where .Cond = A] T as D(U) {
|
|
|
- let Cond:! Type = B;
|
|
|
- }
|
|
|
- impl [T:! Type, U:! Type] T as D(U) {
|
|
|
- let Cond:! Type = A;
|
|
|
- }
|
|
|
+ impl [T:! Type, U:! D(T) where .Cond = B] T as D(U)
|
|
|
+ where .Cond = C { }
|
|
|
+ impl [T:! Type, U:! D(T) where .Cond = A] T as D(U)
|
|
|
+ where .Cond = B { }
|
|
|
+ impl [T:! Type, U:! Type] T as D(U)
|
|
|
+ where .Cond = A { }
|
|
|
}
|
|
|
```
|
|
|
|
|
|
@@ -4121,15 +4130,13 @@ interface Deref {
|
|
|
// Types implementing `Deref`
|
|
|
class Ptr(T:! Type) {
|
|
|
...
|
|
|
- external impl as Deref {
|
|
|
- let Result:! Type = T;
|
|
|
+ external impl as Deref where .Result = T {
|
|
|
fn DoDeref[me: Self]() -> Result { ... }
|
|
|
}
|
|
|
}
|
|
|
class Optional(T:! Type) {
|
|
|
...
|
|
|
- external impl as Deref {
|
|
|
- let Result:! Type = T;
|
|
|
+ external impl as Deref where .Result = T {
|
|
|
fn DoDeref[me: Self]() -> Result { ... }
|
|
|
}
|
|
|
}
|
|
|
@@ -4159,16 +4166,14 @@ To mark an impl as not able to be specialized, prefix it with the keyword
|
|
|
class Ptr(T:! Type) {
|
|
|
...
|
|
|
// Note: added `final`
|
|
|
- final external impl as Deref {
|
|
|
- let Result:! Type = T;
|
|
|
+ final external impl as Deref where .Result = T {
|
|
|
fn DoDeref[me: Self]() -> Result { ... }
|
|
|
}
|
|
|
}
|
|
|
class Optional(T:! Type) {
|
|
|
...
|
|
|
// Note: added `final`
|
|
|
- final external impl as Deref {
|
|
|
- let Result:! Type = T;
|
|
|
+ final external impl as Deref where .Result = T {
|
|
|
fn DoDeref[me: Self]() -> Result { ... }
|
|
|
}
|
|
|
}
|
|
|
@@ -4539,6 +4544,14 @@ 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)
|
|
|
@@ -4549,3 +4562,4 @@ parameter, as opposed to an associated type, as in `N:! u32 where ___ >= 2`.
|
|
|
- [#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)
|