Systematically update syntax in the design for #7254 (#7259)

Assisted-by: Claude and Antigravity with Gemini

---------

Co-authored-by: Geoff Romer <gromer@google.com>
Co-authored-by: josh11b <15258583+josh11b@users.noreply.github.com>
This commit is contained in:
Chandler Carruth
2026-07-07 00:41:06 +00:00
committed by GitHub
co-authored by Geoff Romer josh11b
parent 88160496e1
commit a2890716ba
30 changed files with 708 additions and 699 deletions
+20 -20
View File
@@ -2710,7 +2710,7 @@ has a type\* parameter `T` that can be any type that implements the `Ordered`
interface.
```carbon
fn Min[T:! Ordered](x: T, y: T) -> T {
fn Min[T: Ordered](x: T, y: T) -> T {
// Can compare `x` and `y` since they have
// type `T` known to implement `Ordered`.
return if x <= y then x else y;
@@ -2768,7 +2768,7 @@ parameter by prefixing it with the `template` keyword. Keywords matching the
contextual default are disallowed to ensure consistency.
```carbon
fn Convert[template T:! type](source: T, template U:! type) -> U {
fn Convert[template T: type](source: T, template U: type) -> U {
var converted: U = source;
return converted;
}
@@ -2784,7 +2784,7 @@ A template parameter can still use a constraint. The `Min` example could have
been declared as:
```carbon
fn TemplatedMin[template T:! Ordered](x: T, y: T) -> T {
fn TemplatedMin[template T: Ordered](x: T, y: T) -> T {
return if x <= y then x else y;
}
```
@@ -2882,7 +2882,7 @@ In this case, `Print` is not a direct member of `Circle`, but:
`Printable`.
```carbon
fn GenericPrint[T:! Printable](x: T) {
fn GenericPrint[T: Printable](x: T) {
// Look up into `T` delegates to `Printable`, so this
// finds `Printable.Print`:
x.Print();
@@ -2943,7 +2943,7 @@ A function can require type arguments to implement multiple interfaces (or other
facet types) by combining them using an ampersand (`&`):
```carbon
fn PrintMin[T:! Ordered & Printable](x: T, y: T) {
fn PrintMin[T: Ordered & Printable](x: T, y: T) {
// Can compare since type `T` implements `Ordered`.
if (x <= y) {
// Can call `Print` since type `T` implements `Printable`.
@@ -2961,7 +2961,7 @@ syntax ([1](expressions/member_access.md),
qualify the name of the member, as in:
```carbon
fn DrawTies[T:! Renderable & GameResult](x: T) {
fn DrawTies[T: Renderable & GameResult](x: T) {
if (x.(GameResult.Draw)()) {
x.(Renderable.Draw)();
}
@@ -2993,18 +2993,18 @@ class Game {
}
}
fn TemplateDraw[template T:! type](x: T) {
fn TemplateDraw[template T: type](x: T) {
// Calls `Game.Draw` when `T` is `Game`:
x.Draw();
}
fn ConstrainedTemplateDraw[template T:! Renderable](x: T) {
fn ConstrainedTemplateDraw[template T: Renderable](x: T) {
// ❌ Error when `T` is `Game`: Finds both `T.Draw` and
// `Renderable.Draw`, and they are different.
x.Draw();
}
fn CheckedGenericDraw[T:! Renderable](x: T) {
fn CheckedGenericDraw[T: Renderable](x: T) {
// Always calls `Renderable.Draw`, even when `T` is `Game`:
x.Draw();
}
@@ -3038,7 +3038,7 @@ stack.
```
interface StackInterface {
let ElementType:! Movable;
let ElementType: Movable;
fn Push(ref self, value: ElementType);
fn Pop(ref self) -> ElementType;
fn IsEmpty(self) -> bool;
@@ -3085,7 +3085,7 @@ or can be marked with the `template` keyword. For example, to define a stack
that can hold values of any type `T`:
```carbon
class Stack(T:! type) {
class Stack(T: type) {
fn Push(ref self, value: T);
fn Pop(ref self) -> T;
@@ -3107,7 +3107,7 @@ The values of type parameters are part of a type's value, and so may be deduced
in a function call, as in this example:
```carbon
fn PeekTopOfStack[T:! type](s: Stack(T)*) -> T {
fn PeekTopOfStack[T: type](s: Stack(T)*) -> T {
var top: T = s->Pop();
s->Push(top);
return top;
@@ -3128,7 +3128,7 @@ PeekTopOfStack(&int_stack);
[Choice types](#choice-types) may be parameterized similarly to classes:
```carbon
choice Result(T:! type, Error:! type) {
choice Result(T: type, Error: type) {
Success(value: T),
Failure(error: Error)
}
@@ -3140,7 +3140,7 @@ Interfaces are always parameterized by a `Self` type, but in some cases they
will have additional parameters.
```carbon
interface AddWith(U:! type);
interface AddWith(U: type);
```
Interfaces without parameters may only be implemented once for a given type, but
@@ -3163,12 +3163,12 @@ An `impl` declaration may be parameterized by adding `forall [`_compile-time
parameter list_`]` after the `impl` keyword introducer, as in:
```carbon
impl forall [T:! Printable] Vector(T) as Printable;
impl forall [Key:! Hashable, Value:! type]
impl forall [T: Printable] Vector(T) as Printable;
impl forall [Key: Hashable, Value: type]
HashMap(Key, Value) as Has(Key);
impl forall [T:! Ordered] T as PartiallyOrdered;
impl forall [T:! ImplicitAs(i32)] BigInt as AddWith(T);
impl forall [U:! type, T:! As(U)]
impl forall [T: Ordered] T as PartiallyOrdered;
impl forall [T: ImplicitAs(i32)] BigInt as AddWith(T);
impl forall [U: type, T: As(U)]
Optional(T) as As(Optional(U));
```
@@ -3384,7 +3384,7 @@ There are some situations where the common type for two types is needed:
will be set to the common type of the corresponding arguments, as in:
```carbon
fn F[T:! type](x: T, y: T);
fn F[T: type](x: T, y: T);
// Calls `F` with `T` set to the
// common type of `G()` and `H()`:
+12 -12
View File
@@ -173,7 +173,7 @@ provided for built-in types as necessary to give the semantics described above.
```
// Simple `=`.
interface AssignWith(U:! type) {
interface AssignWith(U: type) {
fn Op(ref self, other: U);
}
constraint Assign { extend AssignWith(Self); }
@@ -187,7 +187,7 @@ Given `var x: T` and `y: U`:
```
// Compound `+=`.
interface AddAssignWith(U:! type) {
interface AddAssignWith(U: type) {
fn Op(ref self, other: U);
}
constraint AddAssign { extend AddAssignWith(Self); }
@@ -195,7 +195,7 @@ constraint AddAssign { extend AddAssignWith(Self); }
```
// Compound `-=`.
interface SubAssignWith(U:! type) {
interface SubAssignWith(U: type) {
fn Op(ref self, other: U);
}
constraint SubAssign { extend SubAssignWith(Self); }
@@ -203,7 +203,7 @@ constraint SubAssign { extend SubAssignWith(Self); }
```
// Compound `*=`.
interface MulAssignWith(U:! type) {
interface MulAssignWith(U: type) {
fn Op(ref self, other: U);
}
constraint MulAssign { extend MulAssignWith(Self); }
@@ -211,7 +211,7 @@ constraint MulAssign { extend MulAssignWith(Self); }
```
// Compound `/=`.
interface DivAssignWith(U:! type) {
interface DivAssignWith(U: type) {
fn Op(ref self, other: U);
}
constraint DivAssign { extend DivAssignWith(Self); }
@@ -219,7 +219,7 @@ constraint DivAssign { extend DivAssignWith(Self); }
```
// Compound `%=`.
interface ModAssignWith(U:! type) {
interface ModAssignWith(U: type) {
fn Op(ref self, other: U);
}
constraint ModAssign { extend ModAssignWith(Self); }
@@ -246,7 +246,7 @@ Given `var x: T` and `y: U`:
```
// Compound `&=`.
interface BitAndAssignWith(U:! type) {
interface BitAndAssignWith(U: type) {
fn Op(ref self, other: U);
}
constraint BitAndAssign { extend BitAndAssignWith(Self); }
@@ -254,7 +254,7 @@ constraint BitAndAssign { extend BitAndAssignWith(Self); }
```
// Compound `|=`.
interface BitOrAssignWith(U:! type) {
interface BitOrAssignWith(U: type) {
fn Op(ref self, other: U);
}
constraint BitOrAssign { extend BitOrAssignWith(Self); }
@@ -262,7 +262,7 @@ constraint BitOrAssign { extend BitOrAssignWith(Self); }
```
// Compound `^=`.
interface BitXorAssignWith(U:! type) {
interface BitXorAssignWith(U: type) {
fn Op(ref self, other: U);
}
constraint BitXorAssign { extend BitXorAssignWith(Self); }
@@ -270,7 +270,7 @@ constraint BitXorAssign { extend BitXorAssignWith(Self); }
```
// Compound `<<=`.
interface LeftShiftAssignWith(U:! type) {
interface LeftShiftAssignWith(U: type) {
fn Op(ref self, other: U);
}
constraint LeftShiftAssign { extend LeftShiftAssignWith(Self); }
@@ -278,7 +278,7 @@ constraint LeftShiftAssign { extend LeftShiftAssignWith(Self); }
```
// Compound `>>=`.
interface RightShiftAssignWith(U:! type) {
interface RightShiftAssignWith(U: type) {
fn Op(ref self, other: U);
}
constraint RightShiftAssign { extend RightShiftAssignWith(Self); }
@@ -307,7 +307,7 @@ This defaulting is accomplished by a parameterized implementation of
`OpAssignWith(U)` defined in terms of `AssignWith` and `OpWith`:
```
impl forall [U:! type, T:! OpWith(U) where .Self impls AssignWith(.Self.Result)]
impl forall [U: type, T: OpWith(U) where .Self impls AssignWith(.Self.Result)]
T as OpAssignWith(U) {
fn Op(ref self, other: U) {
// Here, `$` is the operator described by `OpWith`.
+13 -11
View File
@@ -1001,8 +1001,8 @@ they appear in square brackets `[`...`]` as usual, while `self` remains the
first parameter in the parens `(`...`)`:
```carbon
class Wrapper(T:! type) {
fn Print[U:! type](self, x: U);
class Wrapper(T: type) {
fn Print[U: type](self, x: U);
}
```
@@ -1170,17 +1170,19 @@ class, but other kinds of type declarations, like choice types, are allowed.
### Let
Other type constants can be defined using a `let` declaration:
Other type constants can be defined using a `let` declaration with a `template`
phase modifier:
```
class MyClass {
let Pi:! f32 = 3.141592653589793;
let IndexType:! type = i32;
let template Pi: f32 = 3.141592653589793;
let template IndexType: type = i32;
}
```
The `:!` indicates that this is defining a compile-time constant, and so does
not affect the storage of instances of that class.
> **TODO**: This use of `let` and `template` is one we want to replace with a
> better construct. There is nothing "templated" about the code using these, and
> so that modifier isn't a good one even though it is the one available.
### Alias
@@ -1756,8 +1758,8 @@ call the `UnsafeDelete` method instead. Note that you may not call
```
interface Allocator {
// ...
fn Delete[T:! Deletable](ref self, p: T*);
fn UnsafeDelete[T:! Destructible](ref self, p: T*);
fn Delete[T: Deletable](ref self, p: T*);
fn UnsafeDelete[T: Destructible](ref self, p: T*);
}
```
@@ -1767,13 +1769,13 @@ checked-generic function expecting a `Deletable` type, use the
[type adapter](/docs/design/generics/details.md#adapting-types).
```
class UnsafeAllowDelete(T:! Concrete) {
class UnsafeAllowDelete(T: Concrete) {
extend adapt T;
impl as Deletable {}
}
// Example usage:
fn RequiresDeletable[T:! Deletable](p: T*);
fn RequiresDeletable[T: Deletable](p: T*);
var x: MyExtensible;
RequiresDeletable(&x as UnsafeAllowDelete(MyExtensible)*);
```
+2 -2
View File
@@ -83,8 +83,8 @@ interface:
```carbon
interface Iterate {
let ElementType:! type;
let CursorType:! type;
let ElementType: type;
let CursorType: type;
fn NewCursor(self) -> CursorType;
fn Next(self, ref cursor: CursorType) -> Optional(ElementType);
}
+11 -11
View File
@@ -219,15 +219,15 @@ following family of interfaces:
```
// Unary `-`.
interface Negate {
default let Result:! type = Self;
default let Result: type = Self;
fn Op(self) -> Result;
}
```
```
// Binary `+`.
interface AddWith(U:! type) {
default let Result:! type = Self;
interface AddWith(U: type) {
default let Result: type = Self;
fn Op(self, other: U) -> Result;
}
constraint Add {
@@ -237,8 +237,8 @@ constraint Add {
```
// Binary `-`.
interface SubWith(U:! type) {
default let Result:! type = Self;
interface SubWith(U: type) {
default let Result: type = Self;
fn Op(self, other: U) -> Result;
}
constraint Sub {
@@ -248,8 +248,8 @@ constraint Sub {
```
// Binary `*`.
interface MulWith(U:! type) {
default let Result:! type = Self;
interface MulWith(U: type) {
default let Result: type = Self;
fn Op(self, other: U) -> Result;
}
constraint Mul {
@@ -259,8 +259,8 @@ constraint Mul {
```
// Binary `/`.
interface DivWith(U:! type) {
default let Result:! type = Self;
interface DivWith(U: type) {
default let Result: type = Self;
fn Op(self, other: U) -> Result;
}
constraint Div {
@@ -270,8 +270,8 @@ constraint Div {
```
// Binary `%`.
interface ModWith(U:! type) {
default let Result:! type = Self;
interface ModWith(U: type) {
default let Result: type = Self;
fn Op(self, other: U) -> Result;
}
constraint Mod {
+1 -1
View File
@@ -165,7 +165,7 @@ Explicit casts can be defined for user-defined types such as
[classes](../classes.md) by implementing the `As` interface:
```
interface As(Dest:! type) {
interface As(Dest: type) {
fn Convert(self) -> Dest;
}
```
+11 -11
View File
@@ -197,15 +197,15 @@ implementing the following family of interfaces:
```
// Unary `^`.
interface BitComplement {
default let Result:! type = Self;
default let Result: type = Self;
fn Op(self) -> Result;
}
```
```
// Binary `&`.
interface BitAndWith(U:! type) {
default let Result:! type = Self;
interface BitAndWith(U: type) {
default let Result: type = Self;
fn Op(self, other: U) -> Result;
}
constraint BitAnd {
@@ -215,8 +215,8 @@ constraint BitAnd {
```
// Binary `|`.
interface BitOrWith(U:! type) {
default let Result:! type = Self;
interface BitOrWith(U: type) {
default let Result: type = Self;
fn Op(self, other: U) -> Result;
}
constraint BitOr {
@@ -226,8 +226,8 @@ constraint BitOr {
```
// Binary `^`.
interface BitXorWith(U:! type) {
default let Result:! type = Self;
interface BitXorWith(U: type) {
default let Result: type = Self;
fn Op(self, other: U) -> Result;
}
constraint BitXor {
@@ -237,8 +237,8 @@ constraint BitXor {
```
// Binary `<<`.
interface LeftShiftWith(U:! type) {
default let Result:! type = Self;
interface LeftShiftWith(U: type) {
default let Result: type = Self;
fn Op(self, other: U) -> Result;
}
constraint LeftShift {
@@ -248,8 +248,8 @@ constraint LeftShift {
```
// Binary `>>`.
interface RightShiftWith(U:! type) {
default let Result:! type = Self;
interface RightShiftWith(U: type) {
default let Result: type = Self;
fn Op(self, other: U) -> Result;
}
constraint RightShift {
@@ -254,7 +254,7 @@ The `EqWith` interface is used to define the semantics of the `==` and `!=`
operators for a given pair of types:
```
interface EqWith(U:! type) {
interface EqWith(U: type) {
fn Equal(self, u: U) -> bool;
default fn NotEqual(self, u: U) -> bool {
return not (self == u);
@@ -354,7 +354,7 @@ choice Ordering {
Greater,
Incomparable
}
interface OrderedWith(U:! type) {
interface OrderedWith(U: type) {
fn Compare(self, u: U) -> Ordering;
default fn Less(self, u: U) -> bool {
return self.Compare(u) == Ordering.Less;
@@ -433,8 +433,8 @@ implemented. The behaviors of such overrides should follow those of the above
default implementations, and the members of an `OrderedWith` implementation
should have no observable side-effects.
`OrderedWith` implementations should be _transitive_. That is, given `V:! type`,
`U:! OrderedWith(V)`, `T:! OrderedWith(U) & OrderedWith(V)`, `a: T`, `b: U`,
`OrderedWith` implementations should be _transitive_. That is, given `V: type`,
`U: OrderedWith(V)`, `T: OrderedWith(U) & OrderedWith(V)`, `a: T`, `b: U`,
`c: V`, then:
- If `a <= b` and `b <= c` then `a <= c`, and moreover if either `a < b` or
+13 -13
View File
@@ -75,7 +75,7 @@ The common type of two types `T` and `U` is `(T as CommonType(U)).Result`, where
defined as follows:
```
constraint CommonType(U:! CommonTypeWith(Self)) {
constraint CommonType(U: CommonTypeWith(Self)) {
extend CommonTypeWith(U) where .Result == U.Result;
}
```
@@ -87,8 +87,8 @@ The interface `CommonTypeWith` is used to customize the behavior of
`CommonType`:
```
interface CommonTypeWith(U:! type) {
let Result:! type
interface CommonTypeWith(U: type) {
let Result: type
where Self impls ImplicitAs(.Self) and
U impls ImplicitAs(.Self);
}
@@ -120,15 +120,15 @@ The interface `SymmetricCommonTypeWith` is an implementation detail of the
`CommonType` constraint. It is defined and implemented as follows:
```
interface SymmetricCommonTypeWith(U:! type) {
let Result:! type
interface SymmetricCommonTypeWith(U: type) {
let Result: type
where Self impls ImplicitAs(.Self) and
U impls ImplicitAs(.Self);
}
match_first {
impl forall [T:! type, U:! CommonTypeWith(T)]
impl forall [T: type, U: CommonTypeWith(T)]
T as SymmetricCommonTypeWith(U) where .Result = U.Result {}
impl forall [U:! type, T:! CommonTypeWith(U)]
impl forall [U: type, T: CommonTypeWith(U)]
T as SymmetricCommonTypeWith(U) where .Result = T.Result {}
}
```
@@ -139,7 +139,7 @@ declarations above are used. The `CommonType` constraint is then defined as
follows:
```
constraint CommonType(U:! SymmetricCommonTypeWith(Self)) {
constraint CommonType(U: SymmetricCommonTypeWith(Self)) {
extend SymmetricCommonTypeWith(U) where .Result == U.Result;
}
```
@@ -153,10 +153,10 @@ the `CommonType` constraint is not met. For example, given:
```
// Implementation #1
impl forall [T:! type] MyX as CommonTypeWith(T) where .Result = MyX {}
impl forall [T: type] MyX as CommonTypeWith(T) where .Result = MyX {}
// Implementation #2
impl forall [T:! type] MyY as CommonTypeWith(T) where .Result = MyY {}
impl forall [T: type] MyY as CommonTypeWith(T) where .Result = MyY {}
```
`MyX as CommonTypeWith(MyY)` will select #1, and `MyY as CommonTypeWith(MyX)`
@@ -168,7 +168,7 @@ because result types differ.
If `T` is the same type as `U`, the result is that type:
```
final impl forall [T:! type] T as CommonTypeWith(T) where .Result = T {}
final impl forall [T: type] T as CommonTypeWith(T) where .Result = T {}
```
_Note:_ This rule is intended to be considered more specialized than the other
@@ -179,7 +179,7 @@ assumed to be `T`, even in contexts where `T` involves a symbolic binding and so
the result would normally be an unknown type whose facet type is `type`.
```
fn F[T:! Hashable](c: bool, x: T, y: T) -> HashCode {
fn F[T: Hashable](c: bool, x: T, y: T) -> HashCode {
// OK, type of `if` expression is `T`.
return (if c then x else y).Hash();
}
@@ -190,7 +190,7 @@ fn F[T:! Hashable](c: bool, x: T, y: T) -> HashCode {
If `T` implicitly converts to `U`, the common type is `U`:
```
impl forall [T:! type, U:! ImplicitAs(T)]
impl forall [T: type, U: ImplicitAs(T)]
T as CommonTypeWith(U) where .Result = T {}
```
@@ -224,7 +224,7 @@ extends
[the `As` interface used to implement `as` expressions](as_expressions.md#extensibility):
```
interface ImplicitAs(Dest:! type) {
interface ImplicitAs(Dest: type) {
extend As(Dest);
// Inherited from As(Dest):
// fn Convert(self) -> Dest;
+8 -8
View File
@@ -52,13 +52,13 @@ left-to-right with all of them.
Its semantics are defined in terms of the following interfaces:
```
interface IndexWith(SubscriptType:! type) {
let ElementType:! type;
interface IndexWith(SubscriptType: type) {
let ElementType: type;
fn At(bound self, subscript: SubscriptType) -> val ElementType;
fn Ref(bound ref self, subscript: SubscriptType) -> ref ElementType;
}
interface IndirectIndexWith(SubscriptType:! type) {
interface IndirectIndexWith(SubscriptType: type) {
require Self impls IndexWith(SubscriptType);
fn Ref(bound self, subscript: SubscriptType) -> ref ElementType;
}
@@ -81,7 +81,7 @@ implement `IndirectIndexWith(I)`:
```
final impl forall
[SubscriptType:! type, T:! IndirectIndexWith(SubscriptType)]
[SubscriptType: type, T: IndirectIndexWith(SubscriptType)]
T as IndexWith(SubscriptType) {
where ElementType = T.(IndirectIndexWith(SubscriptType).ElementType);
fn At(bound self, subscript: SubscriptType) -> val ElementType {
@@ -101,9 +101,9 @@ its own definitions of `IndexWith.At` and `IndexWith.Ref`.
An array type could implement subscripting like so:
```
class Array(template T:! type, template N:! i64) {
class Array(template T: type, template N: i64) {
impl as IndexWith(like i64) {
let ElementType:! type = T;
let ElementType: type = T;
fn At(bound self, subscript: i64) -> val T;
fn Ref(bound ref self, subscript: i64) -> ref T;
}
@@ -113,9 +113,9 @@ class Array(template T:! type, template N:! i64) {
And a type such as `std::span` could look like this:
```
class Span(T:! type) {
class Span(T: type) {
impl as IndirectIndexWith(like i64) {
let ElementType:! type = T;
let ElementType: type = T;
fn Ref(bound ref self, subscript: i64) -> ref T;
}
}
+9 -10
View File
@@ -77,12 +77,11 @@ and binary integer literals, and decimal and hexadecimal real number literals.
The following types are defined in the Carbon prelude:
- `Core.BigInt`, an arbitrary-precision integer type;
- `Core.Rational(T:! type)`, a rational type, parameterized by a type used for
- `Core.Rational(T: type)`, a rational type, parameterized by a type used for
its numerator and denominator -- the exact constraints on `T` are not yet
decided;
- `Core.IntLiteral(N:! Core.BigInt)`, a type representing integer literals;
and
- `Core.FloatLiteral(X:! Core.Rational(Core.BigInt))`, a type representing
- `Core.IntLiteral(N: Core.BigInt)`, a type representing integer literals; and
- `Core.FloatLiteral(X: Core.Rational(Core.BigInt))`, a type representing
floating-point literals.
All of these types are usable during compilation. `Core.BigInt` supports the
@@ -100,13 +99,13 @@ these operations are typically heterogeneous: for example, an addition between
`Core.IntLiteral(N)` converts to any sufficiently large integer type, as if by:
```
impl forall [template N:! Core.BigInt, template M:! Core.BigInt]
impl forall [template N: Core.BigInt, template M: Core.BigInt]
Core.IntLiteral(N) as ImplicitAs(Core.Int(M))
if N >= Core.Int(M).MinValue as Core.BigInt
and N <= Core.Int(M).MaxValue as Core.BigInt {
...
}
impl forall [template N:! Core.BigInt, template M:! Core.BigInt]
impl forall [template N: Core.BigInt, template M: Core.BigInt]
Core.IntLiteral(N) as ImplicitAs(Core.UInt(M))
if N >= Core.UInt(M).MinValue as Core.BigInt
and N <= Core.UInt(M).MaxValue as Core.BigInt {
@@ -147,7 +146,7 @@ var z: f64 = 1.0 / 3.0;
// This is an error: 300 cannot be represented in type `i8`.
var c: i8 = 300;
fn F[template T:! type](v: T) {
fn F[template T: type](v: T) {
var x: i32 = v * 2;
}
@@ -158,7 +157,7 @@ F(1_000_000_000);
F(2_000_000_000);
// No storage required for the bound when it's of integer literal type.
struct Span(template T:! type, template BoundT:! type) {
struct Span(template T: type, template BoundT: type) {
var begin: T*;
var bound: BoundT;
}
@@ -176,13 +175,13 @@ fn G() -> i32 {
fn PassMeZero(_: Core.IntLiteral(0));
// Can only be called with integer literals in the given range.
fn ConvertToByte[template N:! Core.BigInt](_: Core.IntLiteral(N)) -> i8
fn ConvertToByte[template N: Core.BigInt](_: Core.IntLiteral(N)) -> i8
if N >= -128 and N <= 127 {
return N as i8;
}
// Given any int literal, produces a literal whose value is one higher.
fn OneHigher(L: Core.IntLiteral(template _:! Core.BigInt)) -> auto {
fn OneHigher(L: Core.IntLiteral(template _: Core.BigInt)) -> auto {
return L + 1;
}
// Error: 256 can't be represented in type `i8`.
+24 -24
View File
@@ -171,7 +171,7 @@ alias MyNS = MyNamespace;
fn CallMyFunction() { MyNS.MyFunction(); }
// ❌ Error: a namespace is not a value.
let MyNS2:! auto = MyNamespace;
let MyNS2: auto = MyNamespace;
fn CallMyFunction2() {
// ❌ Error: cannot perform compound member access into a namespace.
@@ -274,7 +274,7 @@ interface I {
fn F();
}
class C(T:! I) {
class C(T: I) {
extend base: T;
// `F` names `T.F` here, found in `I`.
fn G() { F(); }
@@ -295,14 +295,14 @@ completeness, as it requires `A(-1)` to be complete, which requires
`B(array(i32, -1))` to be complete, and that contains an invalid type.
```carbon
interface B(T:! type) {}
interface B(T: type) {}
interface A(N:! i32) {
interface A(N: i32) {
// Requires `B(N)` to be complete.
extend require impls B(array(i32, N)) {}
}
class C(N! i32) {
class C(N: i32) {
// Requires `A(N)` to be complete, which requires `B(N)` to be complete.
extend impl as A(N);
}
@@ -357,7 +357,7 @@ positional element of the tuple.
// ✅ `d == 43`.
let d: i32 = (41, 42, 43).(1 + 1);
// ✅ `e == 2`.
let template e:! i32 = (1, 2, 3).(0x1);
let template e: i32 = (1, 2, 3).(0x1);
// ❌ Error: no tuple element with index 4.
let f: i32 = (1, 2).(2 * 2);
@@ -404,7 +404,7 @@ fn PrintPointTwice() {
### Facet binding
A search for members of a facet binding `T:! C` treats the facet binding as an
A search for members of a facet binding `T: C` treats the facet binding as an
[archetype](/docs/design/generics/terminology.md#archetype), and finds members
of the facet `T` of facet type `C`.
@@ -415,7 +415,7 @@ interface Printable {
fn Print(self);
}
fn GenericPrint[T:! Printable](a: T) {
fn GenericPrint[T: Printable](a: T) {
// ✅ OK, type of `a` is the facet binding `T`;
// `Print` found in the facet `T as Printable`.
a.Print();
@@ -438,10 +438,10 @@ Evaluation of an expression involving the binding may still succeed, but will
result in a symbolic constant involving that binding.
```carbon
class GenericWrapper(T:! type) {
class GenericWrapper(T: type) {
var field: T;
}
fn F[T:! type](x: GenericWrapper(T)) -> T {
fn F[T: type](x: GenericWrapper(T)) -> T {
// ✅ OK, finds `GenericWrapper(T).field`.
return x.field;
}
@@ -449,7 +449,7 @@ fn F[T:! type](x: GenericWrapper(T)) -> T {
interface Renderable {
fn Draw(self);
}
fn DrawChecked[T:! Renderable](c: T) {
fn DrawChecked[T: Renderable](c: T) {
// `Draw` resolves to `(T as Renderable).Draw` or
// `T.(Renderable.Draw)`.
c.Draw();
@@ -472,7 +472,7 @@ any symbolic bindings are still unknown. The lookup results from these two
contexts are [combined](#lookup-ambiguity).
```carbon
fn DrawTemplate[template T:! type](c: T) {
fn DrawTemplate[template T: type](c: T) {
// `Draw` not found in `type`, looked up in the
// actual deduced value of `T`.
c.Draw();
@@ -492,10 +492,10 @@ the compiler can assume the body of a templated class will be the same for all
argument values:
```carbon
class TemplateWrapper(template T:! type) {
class TemplateWrapper(template T: type) {
var field: T;
}
fn G[template T:! type](x: TemplateWrapper(T)) -> T {
fn G[template T: type](x: TemplateWrapper(T)) -> T {
// ✅ Allowed, finds `TemplateWrapper(T).field`.
return x.field;
}
@@ -508,10 +508,10 @@ cases where the lookup only succeeds for specific values of `T`:
class HasField {
var field: i32;
}
class DerivingWrapper(template T:! type) {
class DerivingWrapper(template T: type) {
extend base: T;
}
fn H[template T:! type](x: DerivingWrapper(T)) -> i32 {
fn H[template T: type](x: DerivingWrapper(T)) -> i32 {
// ✅ Allowed, but no name `field` found in template
// definition of `DerivingWrapper`.
return x.field;
@@ -549,7 +549,7 @@ interface Renderable {
fn Draw(self);
}
fn DrawTemplate2[template T:! Renderable](c: T) {
fn DrawTemplate2[template T: Renderable](c: T) {
// Member lookup finds `(T as Renderable).Draw` and the
// `Draw` member of the actual deduced value of `T`, if any.
c.Draw();
@@ -577,7 +577,7 @@ class SquareWidget {
}
}
fn FlyTemplate[template T:! type](c: T) {
fn FlyTemplate[template T: type](c: T) {
c.Fly();
}
@@ -645,7 +645,7 @@ interface Addable {
// #1
fn Add(self, other: Self) -> Self;
// #2
default fn Sum[Seq:! Iterable where .ValueType = Self](seq: Seq) -> Self {
default fn Sum[Seq: Iterable where .ValueType = Self](seq: Seq) -> Self {
// ...
}
alias AliasForSum = Sum;
@@ -739,7 +739,7 @@ base class WidgetBase {
// ✅ OK, even though `WidgetBase` does not implement `Renderable`.
alias Draw = Renderable.Draw;
fn DrawAll[T:! Renderable](v: Vector(T)) {
fn DrawAll[T: Renderable](v: Vector(T)) {
for (w: T in v) {
// ✅ OK. Unqualified lookup for `Draw` finds alias `WidgetBase.Draw`
// to `Renderable.Draw`, which does not perform `impl` lookup yet.
@@ -945,11 +945,11 @@ fn CallStaticMethod(c: C) {
// same as `c.field = 1;`
c.(C.field) = 1;
// ✅ OK
let T:! type = C.Nested;
// ❌ Error: value of `:!` binding is not compile-time because it
// ✅ OK (also OK with `template`)
let generic G: type = C.Nested;
// ❌ Error: value of `generic` binding is not compile-time because it
// refers to local variable `c`.
let U:! type = c.Nested;
let generic U: type = c.Nested;
}
```
+11 -11
View File
@@ -236,8 +236,8 @@ When the return clause is provided, including when it is `-> ()`, the `return`
statement must have an expression that is convertible to the return type, and a
`return` statement must be used to end control flow of the function.
> **TODO:** Update this section to cover the requirements on the form of the
> expression.
> **TODO:** Update this section to cover the requirements on the extended type
> of the expression.
## Positional parameters
@@ -642,10 +642,10 @@ function type other than asking for the type of the function value.
fn F(x: i32) -> i32 { return x; }
// Compile-time function.
musteval fn TypeOf[T:! type](x: T) -> type { return T; }
musteval fn TypeOf[T: type](x: T) -> type { return T; }
// `F` is a first-class value with a first-class type.
let template FType:! type = TypeOf(F);
let template FType: type = TypeOf(F);
var my_f: FType = F;
```
@@ -755,15 +755,15 @@ parameters. This checking proceeds as follows:
`ref`, and
- An argument to a `ref` parameter must be prefixed with `ref`, except
in a generic context where the parameter's `ref` status may vary.
- If the parameter is a `template :!` binding, the argument expression is
- If the parameter is a `template` binding, the argument expression is
converted to have the same type as the binding and template constant
expression phase.
- If the parameter is a symbolic `:!` binding, the argument expression is
- If the parameter is a checked generic binding, the argument expression is
converted to have the same type as the binding and symbolic constant
expression phase.
- Otherwise, the parameter is pattern-matched against the argument.
If a parameter is a `:!` binding, its corresponding converted argument
If a parameter is a compile-time binding, its corresponding converted argument
expression is evaluated, and its value is added to the list of deduced
argument values before any later parameters are processed.
@@ -786,7 +786,7 @@ interface:
```carbon
interface Call(... each Arg: type) {
let Result:! type;
let Result: type;
fn Op(self, ... each arg: each Arg) -> Result;
}
```
@@ -799,7 +799,7 @@ translated into an invocation of `Call(Arg1, Arg2,` ... `ArgN).Op`, where
For example, given:
```carbon
fn Sort[T:! type, F:! Call(T, T) where .Result = Ordering]
fn Sort[T: type, F: Call(T, T) where .Result = Ordering]
(ref v: Vector(T), cmp: F) {
// ...
auto ord: auto = cmp(v[i], v[j]);
@@ -823,7 +823,7 @@ deduced parameters. The intent is for the `impl` to support indirect calls in
the same cases where the function supports direct calls, with the same meaning.
```carbon
fn TakeI32Fn[F:! Call(i32)](f: F);
fn TakeI32Fn[F: Call(i32)](f: F);
fn I64Fn(n: i64);
fn Run() {
// ✅ `I64Fn` can be called with an `i32`, because
@@ -841,7 +841,7 @@ The `Call` interface can be implemented to overload the meaning of the function
call operator for a type.
```carbon
class Func(Arg:! type) {
class Func(Arg: type) {
impl as Call((Arg,)) where .Result = () {
fn Op(self, arg: (Arg,)) { Print("hello, world"); }
}
+1 -1
View File
@@ -67,7 +67,7 @@ this:
```
package Container;
class HashSet(Key:! Hashable) { ... }
class HashSet(Key: Hashable) { ... }
```
- A `Song` type is defined in package `SongLib`.
@@ -31,9 +31,9 @@ This document explains the rationale for choosing to make
## Rewrite constraints
Rewrite constraints are [`where` clauses](details.md#where-constraints) of the
form `.AssociatedConstant = Value`. Given `T:! A where .B = C`, references to
`T.(A.B)` are rewritten to `C`. This appendix describes the precise rules
governing them.
form `.AssociatedConstant = Value`. Given a checked generic binding `T: A where .B = C`,
references to `T.(A.B)` are rewritten to `C`. This appendix describes the
precise rules governing them.
## Combining constraints with `&`
@@ -41,10 +41,9 @@ Suppose we have `X = C where .R = A` and `Y = C where .R = B`. What should
`C & X` produce? What should `X & Y` produce?
- Combining two rewrite rules with different rewrite targets results in a
facet type where the associated constant is ambiguous. Given `T:! X & Y`,
the type expression `T.R` is ambiguous between a rewrite to `A` and a
rewrite to `B`. But given `T:! X & X`, `T.R` is unambiguously rewritten to
`A`.
facet type where the associated constant is ambiguous. Given `T: X & Y`, the
type expression `T.R` is ambiguous between a rewrite to `A` and a rewrite to
`B`. But given `T: X & X`, `T.R` is unambiguously rewritten to `A`.
- Combining a constraint with a rewrite rule with a constraint with no rewrite
rule preserves the rewrite rule, so `C & X` is the same as `X`. For example,
supposing that `interface Container` extends `interface Iterable`, and
@@ -72,18 +71,18 @@ happens, the facet type `C where A and B` is interpreted as
```carbon
interface C {
let T:! type;
let U:! type;
let V:! type;
let T: type;
let U: type;
let V: type;
}
class M {
alias Me = Self;
}
// ✅ Same as `C where .T = M and .U = M.Me`, which is
// the same as `C where .T = M and .U = M`.
fn F[A:! C where .T = M and .U = .T.Me]() {}
// ❌ No member `Me` in `A.T:! type`.
fn F[A:! C where .U = .T.Me and .T = M]() {}
fn F[A: C where .T = M and .U = .T.Me]() {}
// ❌ No member `Me` in `A.T: type`.
fn F[A: C where .U = .T.Me and .T = M]() {}
```
## Combining constraints with `extend`
@@ -93,8 +92,8 @@ constraint that has rewrites.
```carbon
interface A {
let T:! type;
let U:! type;
let T: type;
let U: type;
}
interface B {
extend A where .T = .U and .U = i32;
@@ -105,7 +104,7 @@ var n: i32;
// ✅ Resolved constraint on `T` is
// `B where .(A.T) = i32 and .(A.U) = i32`.
// `T.(A.T)` is rewritten to `i32`.
fn F(T:! B) -> T.(A.T) { return n; }
fn F(generic T: B) -> T.(A.T) { return n; }
```
## Combining constraints with `require` and `impls`
@@ -118,8 +117,8 @@ are equivalent to `==` constraints:
```carbon
interface A {
let T:! type;
let U:! type;
let T: type;
let U: type;
}
constraint C {
extend A where .T = .U and .U = i32;
@@ -141,7 +140,7 @@ var n: i32;
// `T.(A.T)` is single-step equal to `T.(A.U)`, and
// `T.(A.U)` is single-step equal to `i32`, but
// `T.(A.T)` is not single-step equal to `i32`.
fn F(T:! B) -> T.(A.T) { return n; }
fn F(generic T: B) -> T.(A.T) { return n; }
```
Because `=` constraints are effectively treated as `==` constraints in an
@@ -158,7 +157,7 @@ For example:
```carbon
// Compile-time identity function.
fn Identity[T:! type](x:! T) -> T { return x; }
fn Identity[T: type](generic x: T) -> T { return x; }
interface E {
// ❌ Rewrite constraint specified directly.
@@ -177,19 +176,19 @@ is rewritten to `.Self.T`, and `.Self` is ambiguous.
```carbon
// ❌ Rewrite constraint specified directly in `impls`.
fn F[T:! A where .U impls (A where .T = i32)]();
fn F[T: A where .U impls (A where .T = i32)]();
// ❌ Reference to `.T` in same-type constraint is ambiguous:
// does this mean the outer or inner `.Self.T`?
fn G[T:! A where .U impls (A where .T == i32)]();
fn G[T: A where .U impls (A where .T == i32)]();
// ✅ Not specified directly, but does not result
// in any rewrites being performed. Return type
// is not rewritten to `i32`.
fn H[T:! type where .Self impls C]() -> T.(A.U);
fn H[T: type where .Self impls C]() -> T.(A.U);
// ✅ Return type is rewritten to `i32`.
fn I[T:! C]() -> T.(A.U);
fn I[T: C]() -> T.(A.U);
```
## Rewrite constraint resolution
@@ -200,7 +199,7 @@ constraints that apply to `T`. This happens:
- When the constraint is used explicitly when declaring a symbolic binding,
like a generic parameter or associated constant, of the form
`T:! Constraint`.
`T: Constraint`.
- When declaring that a type implements a constraint with an `impl`
declaration, such as `impl T as Constraint`. Note that this does not include
`require` ... `impls` constraints appearing in `interface` or `constraint`
@@ -224,22 +223,22 @@ abstract constraints into a set of constraints on `T`:
```carbon
interface I {
let X:! type;
let Y:! type;
let X: type;
let Y: type;
}
// ✅ `.X` in `.Y = .X` is rewritten to `i32` when initially
// forming the facet type.
// Nothing to do during constraint resolution.
fn InOrder[T:! I where .X = i32 and .Y = .X]() {}
fn InOrder[T: I where .X = i32 and .Y = .X]() {}
// ✅ Facet type has `.X = .Y` before constraint resolution.
// That rewrite is resolved to `.X = i32`.
fn Reordered[T:! I where .X = .Y and .Y = i32]() {}
fn Reordered[T: I where .X = .Y and .Y = i32]() {}
// ✅ Facet type has `.Y = .X` before constraint resolution.
// That rewrite is resolved to `.Y = i32`.
fn ReorderedIndirect[T:! (I where .X = i32) & (I where .Y = .X)]() {}
fn ReorderedIndirect[T: (I where .X = i32) & (I where .Y = .X)]() {}
// ❌ Constraint resolution fails because
// no fixed point of rewrites exists.
fn Cycle[T:! I where .X = .Y and .Y = .X]() {}
fn Cycle[T: I where .X = .Y and .Y = .X]() {}
```
To find a fixed point, we can perform rewrites on other rewrites, cycling
@@ -258,7 +257,7 @@ condition:
// `.X = .Y*`, then `.Y = .Y**`, then `.Z = .Y***`,
// then `.X = .Y**`, then detect that the `.Y` rewrite
// would apply to itself.
fn IndirectCycle[T:! I where .X = .Y and .Y = .Z* and .Z = .Y*]();
fn IndirectCycle[T: I where .X = .Y and .Y = .Z* and .Z = .Y*]();
```
After constraint resolution, no references to rewritten associated constants
@@ -269,11 +268,11 @@ The following examples each treat the two assignments of `.X` as being
identical, though they are written differently:
```carbon
fn Identical(T:! I where .X = () and .X = .Y and .Y = ()) {}
fn Identical(generic T: I where .X = () and .X = .Y and .Y = ()) {}
fn IdenticalNoCycle(T:! I where .X = () and .X = .Y and .Y = .X) {}
fn IdenticalNoCycle(generic T: I where .X = () and .X = .Y and .Y = .X) {}
fn IdenticalNested(T:! (I where .X = ()) where .X = .Y and .Y = ()) {}
fn IdenticalNested(generic T: (I where .X = ()) where .X = .Y and .Y = ()) {}
```
The rewrite constraints of the current facet type are all available, so both
@@ -285,7 +284,7 @@ But the following does not have the rewrite of `.Y` available at the time of
resolving the two rewrites of `.X`, so the rewrites are invalid:
```carbon
fn NotIdentical(T:! (I where .X = () and .X = .Y) where .Y = ()) {}
fn NotIdentical(generic T: (I where .X = () and .X = .Y) where .Y = ()) {}
```
When combining two facet types together with `&`, the rewrite constraints are
@@ -302,10 +301,10 @@ which constraint resolution would always fail. For example:
package Broken;
interface I {
let X:! type;
let Y:! type;
let X: type;
let Y: type;
}
let Bad:! auto = (I where .X = .Y) & (I where .Y = .X);
let generic Bad: auto = (I where .X = .Y) & (I where .Y = .X);
// Bad is not used here.
```
@@ -350,10 +349,10 @@ type.
```carbon
interface C {
let M:! i32;
let U:! C;
let M: i32;
let U: C;
}
fn F[T:! C](x: T) {
fn F[T: C](x: T) {
// Value is C.M in all four of these
let a: i32 = x.M;
let b: i32 = T.M;
@@ -378,7 +377,7 @@ declared type.
interface SelfIface {
fn Get(self) -> Self;
}
class UsesSelf(T:! type) {
class UsesSelf(T: type) {
// Equivalent to `fn Make() -> UsesSelf(T)*;`
fn Make() -> Self*;
impl as SelfIface;
@@ -405,33 +404,33 @@ example in detail:
```carbon
interface A {
let T:! type;
let T: type;
}
interface B {
let U:! type;
let U: type;
// More explicitly, this is of type `A where .(A.T) = Self.(B.U)`
let V:! A where .T = U;
let V: A where .T = U;
}
// Type of W is B.
fn F[W:! B](x: W) {
fn F[W: B](x: W) {
// The type of the expression `W` is `B`.
// `W.V` finds `B.V` with type `A where .(A.T) = Self.(B.U)`.
// We substitute `Self` = `W` giving the type of `u` as
// `A where .(A.T) = W.(B.U)`.
let u:! auto = W.V;
let generic u: auto = W.V;
// The type of `u` is `A where .(A.T) = W.(B.U)`.
// Lookup for `u.T` resolves it to `u.(A.T)`.
// So the result of the qualified member access is `W.(B.U)`,
// and the type of `v` is the type of `W.(B.U)`, namely `type`.
// No substitution is performed in this step.
let v:! auto = u.T;
let generic v: auto = u.T;
}
```
The more complex case of
```carbon
fn F2[Z:! B where .U = i32](x: Z);
fn F2[Z: B where .U = i32](x: Z);
```
is discussed later.
@@ -446,7 +445,7 @@ substitution of inferred parameter values into the type of a function when
type-checking a function call:
```carbon
fn F[T:! C](x: T) -> T;
fn F[T: C](x: T) -> T;
fn G(n: i32) -> i32 {
// Deduces T = i32, which is substituted
// into the type `fn (x: T) -> T` to produce
@@ -465,19 +464,19 @@ expressions, and do not do it again:
```carbon
interface IfaceHasX {
let X:! type;
let X: type;
}
class ClassHasX {
class X {}
}
interface HasAssoc {
let Assoc:! IfaceHasX;
let Assoc: IfaceHasX;
}
// Qualified name lookup finds `T.(HasAssoc.Assoc).(IfaceHasX.X)`.
fn F(T:! HasAssoc) -> T.Assoc.X;
fn F(generic T: HasAssoc) -> T.Assoc.X;
fn G(T:! HasAssoc where .Assoc = ClassHasX) {
fn G(generic T: HasAssoc where .Assoc = ClassHasX) {
// `T.Assoc` rewritten to `ClassHasX` by qualified name lookup.
// Names `ClassHasX.X`.
var a: T.Assoc.X = {};
@@ -493,11 +492,11 @@ value. It’s important that we perform this resolution:
```carbon
interface A {
let T:! type;
let T: type;
}
class K { fn Member(); }
fn H[U:! A](x: U) -> U.T;
fn J[V:! A where .T = K](y: V) {
fn H[U: A](x: U) -> U.T;
fn J[V: A where .T = K](y: V) {
// We need the interface of `H(y)` to include
// `K.Member` in order for this lookup to succeed.
H(y).Member();
@@ -536,28 +535,28 @@ Continuing an example from [qualified name lookup](#qualified-name-lookup):
```carbon
interface A {
let T:! type;
let T: type;
}
interface B {
let U:! type;
let V:! A where .T = U;
let U: type;
let V: A where .T = U;
}
// Type of the expression `Z` is `B where .(B.U) = i32`
fn F2[Z:! B where .U = i32](x: Z) {
fn F2[Z: B where .U = i32](x: Z) {
// The type of the expression `Z` is `B where .U = i32`.
// `Z.V` is looked up and finds the associated facet `(B.V)`.
// The declared type is `A where .(A.T) = Self.U`.
// We substitute `Self = Z` with rewrite `.U = i32`.
// The resulting type is `A where .(A.T) = i32`.
// So `u` is `Z.V` with type `A where .(A.T) = i32`.
let u:! auto = Z.V;
let generic u: auto = Z.V;
// The type of `u` is `A where .(A.T) = i32`.
// Lookup for `u.T` resolves it to `u.(A.T)`.
// So the result of the qualified member access is `i32`,
// and the type of `v` is the type of `i32`, namely `type`.
// No substitution is performed in this step.
let v:! auto = u.T;
let generic v: auto = u.T;
}
```
@@ -565,41 +564,41 @@ fn F2[Z:! B where .U = i32](x: Z) {
```carbon
interface Container {
let Element:! type;
let Element: type;
}
interface SliceableContainer {
extend Container;
let Slice:! Container where .Element = Self.(Container.Element);
let Slice: Container where .Element = Self.(Container.Element);
}
// ❌ Qualified name lookup rewrites this facet type to
// `SliceableContainer where .(Container.Element) = .Self.(Container.Element)`.
// Constraint resolution rejects this because this rewrite forms a cycle.
fn Bad[T:! SliceableContainer where .Element = .Slice.Element](x: T.Element) {}
fn Bad[T: SliceableContainer where .Element = .Slice.Element](x: T.Element) {}
```
```carbon
interface Helper {
let D:! type;
let D: type;
}
interface Example {
let B:! type;
let C:! Helper where .D = B;
let B: type;
let C: Helper where .D = B;
}
// ✅ `where .D = ...` by itself is fine.
// `T.C.D` is rewritten to `T.B`.
fn Allowed(T:! Example, x: T.C.D);
fn Allowed(generic T: Example, x: T.C.D);
// ❌ But combined with another rewrite, creates an infinite loop.
// `.C.D` is rewritten to `.B`, resulting in `where .B = .B`,
// which causes an error during constraint resolution.
// Using `==` instead of `=` would make this constraint redundant,
// rather than it being an error.
fn Error(T:! Example where .B = .C.D, x: T.C.D);
fn Error(generic T: Example where .B = .C.D, x: T.C.D);
```
```carbon
interface Allowed;
interface AllowedBase {
let A:! Allowed;
let A: Allowed;
}
interface Allowed {
extend AllowedBase where .A = .Self;
@@ -608,18 +607,18 @@ interface Allowed {
// In `((T.A).A).A`, the inner `T.A` is rewritten to `T`,
// resulting in `((T).A).A`, which is then rewritten to
// `(T).A`, which is then rewritten to `T`.
fn F(T:! Allowed, x: ((T.A).A).A);
fn F(generic T: Allowed, x: ((T.A).A).A);
```
```carbon
interface MoveYsRight;
constraint ForwardDeclaredConstraint(X:! MoveYsRight);
constraint ForwardDeclaredConstraint(X: MoveYsRight);
interface MoveYsRight {
let X:! MoveYsRight;
// Means `Y:! MoveYsRight where .X = X.Y`
let Y:! ForwardDeclaredConstraint(X);
let X: MoveYsRight;
// Means `Y: MoveYsRight where .X = X.Y`
let Y: ForwardDeclaredConstraint(X);
}
constraint ForwardDeclaredConstraint(X:! MoveYsRight) {
constraint ForwardDeclaredConstraint(X: MoveYsRight) {
extend MoveYsRight where .X = X.Y;
}
// ✅ The final type of `x` is `T.X.Y.Y`. It is computed as follows:
@@ -647,7 +646,7 @@ constraint ForwardDeclaredConstraint(X:! MoveYsRight) {
// - Qualified name lookup finds `MoveYsRight.X`.
// - The type of `T.Y.Y` says to rewrite that to `T.X.Y.Y`.
// - The result is `T.X.Y.Y`, of type `MoveYsRight`.
fn F4(T:! MoveYsRight, x: T.Y.Y.X);
fn F4(generic T: MoveYsRight, x: T.Y.Y.X);
```
### Termination
+8 -8
View File
@@ -204,7 +204,7 @@ defining a witness table type like:
class Vector {
// `Self` is the representation type, which is only
// known at compile time.
var Self:! type;
var Self: type;
// `fnty` is placeholder syntax for a "function type",
// so `Add` is a function that takes two `Self` parameters
// and returns a value of type `Self`.
@@ -230,9 +230,9 @@ var VectorForPoint_Inline: Vector = {
};
```
Since generic arguments (where the parameter is declared using `:!`) are passed
at compile time, the actual value of `VectorForPoint_Inline` can be used to
generate the code for functions using that impl.
Since generic arguments are passed at compile time, the actual value of
`VectorForPoint_Inline` can be used to generate the code for functions using
that impl.
### Associated facets example
@@ -245,7 +245,7 @@ interface Iterator {
}
interface Container {
let IteratorType:! Iterator;
let IteratorType: Iterator;
fn Begin(ref self) -> IteratorType;
}
```
@@ -254,15 +254,15 @@ could be represented by:
```
class Iterator {
var Self:! type;
var Self: type;
var Advance: fnty(this: Self*);
...
}
class Container {
var Self:! type;
var Self: type;
// Witness that IteratorType implements Iterator.
var IteratorType:! Iterator*;
var IteratorType: Iterator*;
// Method
var Begin: fnty (this: Self*) -> IteratorType->Self;
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -656,7 +656,7 @@ when recursion creates an infinite collection of types, such as in
or:
```carbon
fn Sort[T:! Ordered](list: List(T)) -> List(T) {
fn Sort[T: Ordered](list: List(T)) -> List(T) {
if (list.size() == 1) return list;
var chunks: List(List(T)) = FormChunks(list, sqrt(list.size()));
chunks = chunks.ApplyToEach(Sort);
+19 -19
View File
@@ -138,12 +138,12 @@ You might have one generic function that could sort any array with comparable
elements:
```
fn SortVector(T:! Comparable, a: Vector(T)*) { ... }
fn SortVector(generic T: Comparable, a: Vector(T)*) { ... }
```
The syntax above adds a `!` to indicate that the parameter named `T` is
compile-time. By default compile-time parameters are _checked_, the `template`
keyword may be added to make it a _template generic_.
The syntax above uses the `generic` keyword to indicate that the parameter named
`T` is a _checked generic_ parameter. The `template` keyword may be added instead to
make it a _template generic_.
Given an `i32` vector `iv`, `SortVector(i32, &iv)` is equivalent to
`SortInt32Vector(&iv)`. Similarly for a `String` vector `sv`,
@@ -318,7 +318,7 @@ already included in the type of the second argument. To eliminate the argument
at the call site, use a _deduced parameter_.
```
fn SortVectorDeduced[T:! Comparable](a: Vector(T)*) { ... }
fn SortVectorDeduced[T: Comparable](a: Vector(T)*) { ... }
```
The `T` parameter is defined in square brackets before the explicit parameter
@@ -341,7 +341,7 @@ call site.
```
// ERROR: can't determine `U` from explicit parameters
fn Illegal[T:! type, U:! type](x: T) -> U { ... }
fn Illegal[T: type, U: type](x: T) -> U { ... }
```
#### Facet parameters
@@ -350,7 +350,7 @@ A function with a facet parameter can have the same function body as an
unparameterized one.
```
fn PrintIt[T:! Printable](p: T*) {
fn PrintIt[T: Printable](p: T*) {
p->Print();
}
@@ -447,7 +447,7 @@ interface EndOfGame {
fn Draw(ref self);
}
fn F[T:! Renderable & EndOfGame](game_state: T*) -> (i32, i32) {
fn F[T: Renderable & EndOfGame](game_state: T*) -> (i32, i32) {
game_state->SetWinner(1);
return game_state->Center();
}
@@ -457,7 +457,7 @@ Names with conflicts can be accessed using a
[qualified member access expression](#accessing-members-of-interfaces).
```
fn BothDraws[T:! Renderable & EndOfGame](game_state: T*) {
fn BothDraws[T: Renderable & EndOfGame](game_state: T*) {
game_state->(Renderable.Draw)();
game_state->(GameState.Draw)();
}
@@ -480,7 +480,7 @@ constraint Combined {
alias SetWinner = EndOfGame.SetWinner;
}
fn CallItAll[T:! Combined](game_state: T*, int winner) {
fn CallItAll[T: Combined](game_state: T*, int winner) {
if (winner > 0) {
game_state->SetWinner(winner);
} else {
@@ -514,7 +514,7 @@ class CDCover {
it can be passed to this `PrintIt` function:
```
fn PrintIt[T:! Printable](p: T*) {
fn PrintIt[T: Printable](p: T*) {
p->Print();
}
```
@@ -567,7 +567,7 @@ convenient to use. Imagine a `Stack` interface. Different types implementing
```
interface Stack {
let ElementType:! Movable;
let ElementType: Movable;
fn Push(ref self, value: ElementType);
fn Pop(ref self) -> ElementType;
fn IsEmpty(ref self) -> bool;
@@ -582,7 +582,7 @@ can deduce the `ElementType` from the stack type.
```
// ✅ This is allowed, since the type of the stack will determine
// `ElementType`.
fn PeekAtTopOfStack[StackType:! Stack](s: StackType*)
fn PeekAtTopOfStack[StackType: Stack](s: StackType*)
-> StackType.ElementType;
```
@@ -595,7 +595,7 @@ those types to be different. An element in a hash map might have type
`Equatable(Pair(String, i64))`.
```
interface Equatable(T:! type) {
interface Equatable(T: type) {
fn IsEqual(self, compare_to: T) -> bool;
}
```
@@ -609,14 +609,14 @@ general, unless some other parameter determines `T`.
```
// ✅ This is allowed, since the value of `T` is determined by the
// `v` parameter.
fn FindInVector[T:! type, U:! Equatable(T)](v: Vector(T), needle: U)
fn FindInVector[T: type, U: Equatable(T)](v: Vector(T), needle: U)
-> Optional(i32);
// ❌ This is forbidden. Since `U` could implement `Equatable`
// multiple times, there is no way to determine the value for `T`.
// Contrast with `PeekAtTopOfStack` in the associated constant
// example.
fn CompileError[T:! type, U:! Equatable(T)](x: U) -> T;
fn CompileError[T: type, U: Equatable(T)](x: U) -> T;
```
### Constraints
@@ -624,13 +624,13 @@ fn CompileError[T:! type, U:! Equatable(T)](x: U) -> T;
Facet types can be further constrained using a `where` clause:
```
fn FindFirstPrime[T:! Container where .Element = i32]
fn FindFirstPrime[T: Container where .Element = i32]
(c: T, i: i32) -> Optional(i32) {
// The elements of `c` have type `T.Element`, which is `i32`.
...
}
fn PrintContainer[T:! Container where .Element impls Printable](c: T) {
fn PrintContainer[T: Container where .Element impls Printable](c: T) {
// The type of the elements of `c` is not known, but we do know
// that type satisfies the `Printable` interface.
...
@@ -645,7 +645,7 @@ Constraints are also used when implementing an interface to specify the values
of associated constants.
```
class Vector(T:! Movable) {
class Vector(T: Movable) {
extend impl as Stack where .ElementType = T { ... }
}
```
+14 -13
View File
@@ -210,7 +210,7 @@ alone. For example, let's say we have some overloaded function called `F` that
has two overloads:
```
fn F[template T:! type](x: T*) -> T;
fn F[template T: type](x: T*) -> T;
fn F(x: Int) -> bool;
```
@@ -309,9 +309,9 @@ The name being declared, which is the identifier to the left of the `:` is
called a _binding_, or more specifically a _runtime binding_, _compile-time
binding_, _symbolic binding_, or _template binding_. The expression to the right
defining the type of the binding pattern is called the _binding type
expression_, a kind of [type expression](#type-expression). For example, in
`generic T: Hashable`, `T` is the binding (a symbolic binding in this case), and
`Hashable` is the binding type expression.
expression_, a kind of [type expression](#type-expression). For example, in a
generic binding pattern `T: Hashable`, `T` is the binding (a symbolic binding in
this case), and `Hashable` is the binding type expression.
## Types and `type`
@@ -365,9 +365,10 @@ cases, we are concerned with the type value after the implicit conversion.
## Facet binding
We use the term _facet binding_ to refer to the name introduced by a
[compile-time binding pattern](#bindings) where the declared type is a
[facet type](#facet-type). In the binding pattern `generic T: Hashable`, `T` is
a facet binding, and the value of `T` is a [facet](#facet).
[compile-time binding pattern](#bindings) (indicated by context or keywords like
`generic` or `template`) where the declared type is a [facet type](#facet-type).
In a generic binding pattern `T: Hashable`, `T` is a facet binding, and the
value of `T` is a [facet](#facet).
## Deduced parameter
@@ -755,14 +756,14 @@ associated constants.
```
// Stack using associated facets
interface Stack {
let ElementType:! type;
let ElementType: type;
fn Push(ref self, value: ElementType);
fn Pop(ref self) -> ElementType;
}
// Works on any type implementing `Stack`. Return type
// is determined by the type's implementation of `Stack`.
fn PeekAtTopOfStack[T:! Stack](s: T*) -> T.ElementType {
fn PeekAtTopOfStack[T: Stack](s: T*) -> T.ElementType {
let ret: T.ElementType = s->Pop();
s->Push(ret);
return ret;
@@ -792,8 +793,8 @@ For example, we might have an interface that says how to perform addition with
another type:
```
interface AddWith(T:! type) {
let ResultType:! type;
interface AddWith(T: type) {
let ResultType: type;
fn Add(self, rhs: T) -> ResultType;
}
```
@@ -812,12 +813,12 @@ to be some way to determine the type to add to:
```
// ✅ This is allowed, since the value of `T` is determined by the
// `y` parameter.
fn DoAdd[T:! type, U:! AddWith(T)](x: U, y: T) -> U.ResultType {
fn DoAdd[T: type, U: AddWith(T)](x: U, y: T) -> U.ResultType {
return x.Add(y);
}
// ❌ This is forbidden, can't uniquely determine `T`.
fn CompileError[T:! type, U:! AddWith(T)](x: U) -> T;
fn CompileError[T: type, U: AddWith(T)](x: U) -> T;
```
Once the interface parameters can be determined, that determines the values for
@@ -96,7 +96,6 @@ source file:
| `,` | Separate tuple and struct elements |
| `.` | Member access |
| `:` | Name binding patterns |
| `:!` | Compile-time binding patterns |
| `;` | Statement separator |
## Alternatives considered
+2
View File
@@ -69,6 +69,7 @@ The following words are interpreted as keywords:
- `for`
- `forall`
- `friend`
- `generic`
- `if`
- `impl`
- `impls`
@@ -92,6 +93,7 @@ The following words are interpreted as keywords:
- `require`
- `return`
- `returned`
- `runtime`
- `Self`
- `self`
- `template`
+5 -5
View File
@@ -295,7 +295,7 @@ the type of the scrutinee and deduced values are substituted back into the type
before pattern matching is performed.
```carbon
fn G[T:! Type](p: T*);
fn G[T: Type](p: T*);
class X { impl as ImplicitAs(i32*); }
// ✅ Deduces `T = i32` then implicitly and
// trivially converts `p` to `i32*`.
@@ -493,7 +493,7 @@ alternative, and the arguments of the alternative match the given tuple pattern
(if any).
```carbon
choice Optional(T:! Type) {
choice Optional(T: Type) {
None,
Some(T)
}
@@ -532,7 +532,7 @@ meaningful due to a type error are instead treated as not matching. This
includes cases where an `==` fails because of a missing `EqWith` implementation.
```carbon
fn TypeName[template T:! Type](x: T) -> String {
fn TypeName[template T: Type](x: T) -> String {
match (x) {
// ✅ OK, the type of `x` is a template parameter.
case _: i32 => { return "int"; }
@@ -547,7 +547,7 @@ Cases where the match is invalid for reasons not involving the template
parameter are rejected when type-checking the template:
```carbon
fn MeaninglessMatch[template T:! Type](x: T*) {
fn MeaninglessMatch[template T: Type](x: T*) {
match (*x) {
// ✅ OK, `T` could be a tuple.
case (_: auto, _: auto) => {}
@@ -626,7 +626,7 @@ We will diagnose the following situations:
example:
```carbon
choice Optional(T:! Type) {
choice Optional(T: Type) {
None,
Some(T)
}
+7 -7
View File
@@ -49,7 +49,7 @@ than documentation), and `None`, which is empty. Choice types can also be
parameterized, [like class types](generics/details.md#parameterized-types):
```carbon
choice Optional(T:! type) {
choice Optional(T: type) {
Some(value: T),
None
}
@@ -107,11 +107,11 @@ It does so by implementing the `Match` interface, which is defined as follows:
```carbon
interface Match {
interface BaseContinuation {
let ReturnType:! type;
let ReturnType: type;
}
let template Continuation:! type;
fn Op[C:! Continuation](self, continuation: C*)
let template Continuation: type;
fn Op[C: Continuation](self, continuation: C*)
-> C.(BaseContinuation.ReturnType);
}
```
@@ -135,10 +135,10 @@ require that `Match.Op` invoke the continuation as a tail call.
For example, here's how `Optional` can be defined as a class:
```carbon
class Optional(T:! type) {
class Optional(T: type) {
// Factory functions
fn Some(value: T) -> Self;
let None:! Self;
let None: Self;
private var has_value: bool;
private var value: T;
@@ -150,7 +150,7 @@ class Optional(T:! type) {
fn None(ref self) -> ReturnType;
}
fn Op[C:! Continuation](self, continuation: C*) -> C.ReturnType {
fn Op[C: Continuation](self, continuation: C*) -> C.ReturnType {
if (self.has_value) {
return continuation->Some(self.value);
} else {
+2 -2
View File
@@ -44,7 +44,7 @@ are subject to full instantiation -- other parameters will be type checked and
bound early to the extent possible. For example:
```
class Stack(template T:! type) {
class Stack(template T: type) {
var storage: buf(T);
fn Push(ref self, value: T);
@@ -67,7 +67,7 @@ arguments. The runtime call then passes the remaining arguments to the resulting
complete definition.
```
fn Convert[template T:! type](source: T, template U:! type) -> U {
fn Convert[template T: type](source: T, template U: type) -> U {
var converted: U = source;
return converted;
}
+1 -1
View File
@@ -60,7 +60,7 @@ fn Sum(x: i32, y: i32) -> i32 {
A parenthesized template constant expression can also be used to index a tuple:
```
fn Choose(template N:! i32) -> i32 {
fn Choose(template N: i32) -> i32 {
return (1, 2, 3).(N % 3);
}
```
+7 -7
View File
@@ -1217,7 +1217,7 @@ The interface might look like:
```carbon
interface Pointer {
let ValueT:! Type;
let ValueT: Type;
fn Dereference(self) -> ValueT*;
}
```
@@ -1226,12 +1226,12 @@ Here is an example using a hypothetical `TaggedPtr` that carries some extra
integer tag next to the pointer it emulates:
```carbon
class TaggedPtr(T:! Type) {
class TaggedPtr(T: Type) {
var tag: Int32;
var ptr: T*;
}
external impl [T:! Type] TaggedPtr(T) as Pointer {
let ValueT:! T;
external impl [T: Type] TaggedPtr(T) as Pointer {
let ValueT: T;
fn Dereference(self) -> T* { return self.ptr; }
}
@@ -1248,8 +1248,8 @@ that formed by `var` declarations. This interface is implemented for normal
pointers as a no-op:
```carbon
impl [T:! Type] T* as Pointer {
let ValueT:! Type = T;
impl [T: Type] T* as Pointer {
let ValueT: Type = T;
fn Dereference(self) -> T* { return self; }
}
```
@@ -1406,7 +1406,7 @@ will require that the type containing that specifier satisfies the constraint
```carbon
interface ReferenceImplicitAs {
let T:! type;
let T: type;
fn Convert(ref self: const Self) -> T;
}
```
+40 -40
View File
@@ -67,7 +67,7 @@ This example illustrates many of the key concepts:
// Takes an arbitrary number of vectors with arbitrary element types, and
// returns a vector of tuples where the i'th element of the vector is
// a tuple of the i'th elements of the input vectors.
fn Zip[... each ElementType:! type]
fn Zip[... each ElementType: type]
(... each vector: Vector(each ElementType))
-> Vector((... each ElementType)) {
... var each iter: auto = each vector.Begin();
@@ -91,7 +91,7 @@ the number of values in the sequence.
An _each-name_ consists of the keyword `each` followed by the name of a pack,
and can only occur inside a pack expansion. On the Nth iteration of the pack
expansion, an each-name refers to the Nth element of the named pack. As a
result, a binding pattern with an each-name, such as `each ElementType:! type`,
result, a binding pattern with an each-name, such as `each ElementType: type`,
acts as a declaration of all the elements of the named pack, and thereby
implicitly acts as a declaration of the pack itself.
@@ -190,7 +190,7 @@ fragment:
```
var result: bool = true;
for (let i:! i32 in (0, 1, 2)) {
for (let generic i: i32 in (0, 1, 2)) {
result = result && F(x[:i:], y[:i:]);
if (result == false) { break; }
}
@@ -248,7 +248,7 @@ fn SumInts(... each param: i64) -> i64 {
```carbon
// Concatenates its arguments, which are all convertible to String
fn StrCat[... each T:! ConvertibleToString](... each param: each T) -> String {
fn StrCat[... each T: ConvertibleToString](... each param: each T) -> String {
var len: i64 = 0;
... len += each param.Length();
var result: String = "";
@@ -260,7 +260,7 @@ fn StrCat[... each T:! ConvertibleToString](... each param: each T) -> String {
```carbon
// Returns the minimum of its arguments, which must all have the same type T.
fn Min[T:! Comparable & Value](first: T, ... each next: T) -> T {
fn Min[T: Comparable & Value](first: T, ... each next: T) -> T {
var result: T = first;
... if (each next < result) {
result = each next;
@@ -271,7 +271,7 @@ fn Min[T:! Comparable & Value](first: T, ... each next: T) -> T {
```carbon
// Invokes f, with the tuple `args` as its arguments.
fn Apply[... each T:! type, F:! Call(... each T)]
fn Apply[... each T: type, F: Call(... each T)]
(f: F, args: (... each T)) -> auto {
return f(...expand args);
}
@@ -365,7 +365,7 @@ tuple literal is a tuple literal of the types of its segments. For example,
suppose we are trying to find the type of `z` in this code:
```carbon
fn F[... each T:! type]((... each x: Optional(each T)), (... each y: i32)) {
fn F[... each T: type]((... each x: Optional(each T)), (... each y: i32)) {
let z: auto = (0 as f32, ... each x, ... each y);
}
```
@@ -396,7 +396,7 @@ type of `z` is `(f32, ... Optional(each T), ... «i32; ‖each y‖»)`.
Now, consider a modified version of that example:
```carbon
fn F[... each T:! type]((... each x: Optional(each T)), (... each y: i32)) {
fn F[... each T: type]((... each x: Optional(each T)), (... each y: i32)) {
let (... each z: auto) = (0 as f32, ... each x, ... each y);
}
```
@@ -499,8 +499,8 @@ an each-name that is not a parameter of the enclosing
pattern can have at most one segment with deduced arity. For example:
```carbon
class C(... each T:! type) {
fn F[... each U:! type](... each t: each T, ... each u: each U);
class C(... each T: type) {
fn F[... each U: type](... each t: each T, ... each u: each U);
}
```
@@ -514,14 +514,14 @@ possible, in order to simplify the subsequent pattern matching. For example,
consider the following function declaration:
```carbon
fn Min[T:! type](first: T, ... each next: T) -> T;
fn Min[T: type](first: T, ... each next: T) -> T;
```
During typechecking, we rewrite that function signature so that it only has one
parameter:
```carbon
fn Min[T:! type](... each args: «T; ‖each next‖+1») -> T;
fn Min[T: type](... each args: «T; ‖each next‖+1») -> T;
```
(We represent the arity as `‖each next‖+1` to capture the fact that `each args`
@@ -531,7 +531,7 @@ When the pattern is heterogeneous, the merging process may be more complex. For
example:
```carbon
fn ZipAtLeastOne[First:! type, ... each Next:! type]
fn ZipAtLeastOne[First: type, ... each Next: type]
(first: Vector(First), ... each next: Vector(each Next))
-> Vector((First, ... each Next));
```
@@ -539,7 +539,7 @@ fn ZipAtLeastOne[First:! type, ... each Next:! type]
During typechecking, we transform that function signature to the following form:
```carbon
fn ZipAtLeastOne[... ⟬First, each Next⟭:! «type; ‖each next‖+1»]
fn ZipAtLeastOne[... ⟬First, each Next⟭: «type; ‖each next‖+1»]
(... each __args: Vector(⟬First, each Next⟭))
-> Vector((... ⟬First, each Next⟭));
```
@@ -549,7 +549,7 @@ with an invented name `each __Args`, so that the function has only one
parameter:
```carbon
fn ZipAtLeastOne[... each __Args:! «type; ‖each next‖+1»]
fn ZipAtLeastOne[... each __Args: «type; ‖each next‖+1»]
(... each __args: Vector(each __Args))
-> Vector((... each __Args));
```
@@ -567,7 +567,7 @@ following conditions hold:
declaration of `X`:
```carbon
fn F[... ⟬X, each Y⟭:! «type; ‖each next‖+1»]
fn F[... ⟬X, each Y⟭: «type; ‖each next‖+1»]
(... each __args: each ⟬X, each Y⟭) -> X;
```
@@ -577,7 +577,7 @@ following conditions hold:
parameter list also contains the pack literal `⟬I, each type⟭`:
```carbon
fn F[... ⟬X, each Y⟭:! ⟬I, each type⟭](... each __args: each ⟬X, each Y⟭);
fn F[... ⟬X, each Y⟭: ⟬I, each type⟭](... each __args: each ⟬X, each Y⟭);
```
Notice that as a corollary of this rule, all the names in the name pack must
@@ -595,7 +595,7 @@ same arity. For example, consider this call to `ZipAtLeastOne` (as defined in
the previous section):
```carbon
fn F[... each T:! type](... each t: Vector(each T), u: Vector(i32)) {
fn F[... each T: type](... each t: Vector(each T), u: Vector(i32)) {
ZipAtLeastOne(... each t, u);
}
```
@@ -654,7 +654,7 @@ expansion.
In this formalism, deduced arities are explicit rather than implicit, so Carbon
code must be desugared into this formalism as follows:
For each pack expansion pattern, we introduce a binding pattern `__N:! Arity` as
For each pack expansion pattern, we introduce a binding pattern `__N: Arity` as
a deduced parameter of the enclosing full pattern, where `__N` is a name chosen
to avoid collisions. Then, for each binding pattern of the form `each X: T`
within that expansion, if `T` does not contain an each-name, the binding pattern
@@ -695,7 +695,7 @@ The type of an expression or pattern can be computed as follows:
- The type of `each x: auto` is `each __X`, a newly-invented deduced parameter
of the enclosing full pattern, which behaves as if it was declared as
`... each __X:! type`.
`... each __X: type`.
- The type of an each-name expression is the type expression of the binding
pattern that declared it.
- The type of an arity coercion `«E; S»` is `«T; S»`, where `T` is the type of
@@ -808,15 +808,15 @@ _Shape equality:_ Let `(S1s)`, `(S2s)`, `(S3s)`, and `(S4s)` be shapes.
A full pattern is in _normal form_ if it contains no pack literals, and every
arity coercion is fully expanded. For example,
`[__N:! Arity](... each x: Vector(«i32; __N»))` is not in normal form, but
`[__N:! Arity](... each x: «Vector(i32); __N»)` is. Note that all user-written
`[__N: Arity](... each x: Vector(«i32; __N»))` is not in normal form, but
`[__N: Arity](... each x: «Vector(i32); __N»)` is. Note that all user-written
full patterns are in normal form. Note also that by construction, this means
that the type of the body of every pack expansion has a single scalar component.
The _canonical form_ of a full pattern is the unique normal form (if any) that
is "maximally merged", meaning that every tuple pattern and tuple literal has
the smallest number of segments. For example, the canonical form of
`[__N:! Arity](... each x: «i32; __N», y: i32)` is
`[__N:! Arity](... each __args: «i32; __N+1»)`.
`[__N: Arity](... each x: «i32; __N», y: i32)` is
`[__N: Arity](... each __args: «i32; __N+1»)`.
> **TODO:** Specify algorithm for converting a full pattern to canonical form,
> or establishing that there is no such form. See next section for a start.
@@ -848,7 +848,7 @@ parameter type.
For example, consider the following function:
```carbon
fn F[First:! type, Second:! type, ... each Next:! type]
fn F[First: type, Second: type, ... each Next: type]
(first: Vector(First), second: Vector(Second),
... each next: Vector(each Next)) -> (First, Second, ... each Next);
```
@@ -856,7 +856,7 @@ fn F[First:! type, Second:! type, ... each Next:! type]
First, we desugar the implicit arity:
```carbon
fn F[__N:! Arity, First:! type, Second:! type, ... each Next:! «type; __N»]
fn F[__N: Arity, First: type, Second: type, ... each Next: «type; __N»]
(first: Vector(First), second: Vector(Second),
... each next: Vector(each Next)) -> (First, Second, ... each Next);
```
@@ -867,32 +867,32 @@ reductions):
```carbon
// Singular pack removal (in reverse)
fn F[__N:! Arity, First:! type, Second:! type, ... ⟬each Next:! «type; __N»⟭]
fn F[__N: Arity, First: type, Second: type, ... ⟬each Next: «type; __N»⟭]
(first: Vector(First), second: Vector(Second),
... each next: Vector(⟬each Next⟭)) -> (First, Second, ... ⟬each Next⟭);
// Pack expanding
fn F[__N:! Arity, First:! type, Second:! type, ... ⟬each Next:! «type; __N»⟭]
fn F[__N: Arity, First: type, Second: type, ... ⟬each Next: «type; __N»⟭]
(first: Vector(First), second: Vector(Second),
... each next: ⟬Vector(each Next)⟭) -> (First, Second, ... ⟬each Next⟭);
// Pack expanding
fn F[__N:! Arity, First:! type, Second:! type, ... ⟬each Next:! «type; __N»⟭]
fn F[__N: Arity, First: type, Second: type, ... ⟬each Next: «type; __N»⟭]
(first: Vector(First), second: Vector(Second),
... ⟬each next: Vector(each Next)⟭) -> (First, Second, ... ⟬each Next⟭);
// Pack expansion splitting (in reverse)
fn F[__N:! Arity, First:! type, ... ⟬Second:! type, each Next:! «type; __N»⟭]
fn F[__N: Arity, First: type, ... ⟬Second: type, each Next: «type; __N»⟭]
(first: Vector(First), ... ⟬second: Vector(Second),
each next: Vector(each Next)⟭)
-> (First, ... ⟬Second, each Next⟭);
// Pack expanding (in reverse)
fn F[__N:! Arity, First:! type, ... ⟬Second, each Next⟭:! «type; __N+1»]
fn F[__N: Arity, First: type, ... ⟬Second, each Next⟭: «type; __N+1»]
(first: Vector(First), ... ⟬second, each next⟭: ⟬Vector(Second), Vector(each Next)⟭)
-> (First, ... ⟬Second, each Next⟭);
// Pack expanding (in reverse)
fn F[__N:! Arity, First:! type, ... ⟬Second, each Next⟭:! «type; __N+1»]
fn F[__N: Arity, First: type, ... ⟬Second, each Next⟭: «type; __N+1»]
(first: Vector(First), ... ⟬second, each next⟭: Vector(⟬Second, each Next⟭))
-> (First, ... ⟬Second, each Next⟭);
// Pack renaming
fn F[__N:! Arity, First:! type, ... each __A:! «type; __N+1»]
fn F[__N: Arity, First: type, ... each __A: «type; __N+1»]
(first: Vector(First), ... each __a: Vector(each __A))
-> (First, ... each __A);
```
@@ -901,31 +901,31 @@ This brings us back to a normal form, while reducing the number of tuple
segments. We can now repeat that process to merge the remaining parameter type:
```carbon
fn F[__N:! Arity, First:! type, ... ⟬each __A:! «type; __N+1»⟭]
fn F[__N: Arity, First: type, ... ⟬each __A: «type; __N+1»⟭]
(first: Vector(First), ... each __a: Vector(⟬each __A⟭))
-> (First, ... ⟬each __A⟭);
// Pack expanding
fn F[__N:! Arity, First:! type, ... ⟬each __A:! «type; __N+1»⟭]
fn F[__N: Arity, First: type, ... ⟬each __A: «type; __N+1»⟭]
(first: Vector(First), ... each __a: ⟬Vector(each __A)⟭)
-> (First, ... ⟬each __A⟭);
// Pack expanding
fn F[__N:! Arity, First:! type, ... ⟬each __A:! «type; __N+1»⟭]
fn F[__N: Arity, First: type, ... ⟬each __A: «type; __N+1»⟭]
(first: Vector(First), ... ⟬each __a: Vector(each __A)⟭)
-> (First, ... ⟬each __A⟭);
// Pack expansion splitting (in reverse)
fn F[__N:! Arity, ... ⟬First:! type, each __A:! «type; __N+1»⟭]
fn F[__N: Arity, ... ⟬First: type, each __A: «type; __N+1»⟭]
(... ⟬first: Vector(First), each __a: Vector(each __A)⟭)
-> (... ⟬First, each __A⟭);
// Pack expanding (in reverse)
fn F[__N:! Arity, ... ⟬First, each __A⟭:! «type; __N+2»⟭]
fn F[__N: Arity, ... ⟬First, each __A⟭: «type; __N+2»⟭]
(... ⟬first, each __a⟭: ⟬Vector(First), Vector(each __A)⟭)
-> (... ⟬First, each __A⟭);
// Pack expanding (in reverse)
fn F[__N:! Arity, ... ⟬First, each __A⟭:! «type; __N+2»⟭]
fn F[__N: Arity, ... ⟬First, each __A⟭: «type; __N+2»⟭]
(... ⟬first, each __a⟭: Vector(⟬First, each __A⟭))
-> (... ⟬First, each __A⟭);
// Pack renaming
fn F[__N:! Arity, ... __B:! «type; __N+2»⟭]
fn F[__N: Arity, ... __B: «type; __N+2»⟭]
(... __b: Vector(__B))
-> (... __B);
```
+2 -2
View File
@@ -23,7 +23,7 @@ A sample of quicksort in Carbon.
```cpp
package Sorting;
fn Partition[T:! Comparable & Movable](s: slice(T))
fn Partition[T: Comparable & Movable](s: slice(T))
-> i64 {
var i: i64 = -1;
@@ -36,7 +36,7 @@ fn Partition[T:! Comparable & Movable](s: slice(T))
return i;
}
fn QuickSort[T:! Comparable & Movable](s: slice(T)) {
fn QuickSort[T: Comparable & Movable](s: slice(T)) {
if (s.Size() <= 1) {
return;
}