From a2890716ba7b73bb2bd337addceb3ac534558ee1 Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Mon, 6 Jul 2026 17:41:06 -0700 Subject: [PATCH] Systematically update syntax in the design for #7254 (#7259) Assisted-by: Claude and Antigravity with Gemini --------- Co-authored-by: Geoff Romer Co-authored-by: josh11b <15258583+josh11b@users.noreply.github.com> --- docs/design/README.md | 40 +- docs/design/assignment.md | 24 +- docs/design/classes.md | 24 +- docs/design/control_flow/loops.md | 4 +- docs/design/expressions/arithmetic.md | 22 +- docs/design/expressions/as_expressions.md | 2 +- docs/design/expressions/bitwise.md | 22 +- .../expressions/comparison_operators.md | 8 +- docs/design/expressions/if.md | 26 +- .../expressions/implicit_conversions.md | 2 +- docs/design/expressions/indexing.md | 16 +- docs/design/expressions/literals.md | 19 +- docs/design/expressions/member_access.md | 48 +- docs/design/functions.md | 22 +- docs/design/generics/appendix-coherence.md | 2 +- .../generics/appendix-rewrite-constraints.md | 159 ++-- docs/design/generics/appendix-witness.md | 16 +- docs/design/generics/details.md | 753 +++++++++--------- docs/design/generics/goals.md | 2 +- docs/design/generics/overview.md | 38 +- docs/design/generics/terminology.md | 27 +- .../lexical_conventions/symbolic_tokens.md | 1 - docs/design/lexical_conventions/words.md | 2 + docs/design/pattern_matching.md | 10 +- docs/design/sum_types.md | 14 +- docs/design/templates.md | 4 +- docs/design/tuples.md | 2 +- docs/design/values.md | 14 +- docs/design/variadics.md | 80 +- docs/images/snippets.md | 4 +- 30 files changed, 708 insertions(+), 699 deletions(-) diff --git a/docs/design/README.md b/docs/design/README.md index 381d3f3783d8..498c05757b84 100644 --- a/docs/design/README.md +++ b/docs/design/README.md @@ -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()`: diff --git a/docs/design/assignment.md b/docs/design/assignment.md index 7441cf6ceb41..57c063470a9a 100644 --- a/docs/design/assignment.md +++ b/docs/design/assignment.md @@ -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`. diff --git a/docs/design/classes.md b/docs/design/classes.md index ab960cbb5c86..21bd472ea599 100644 --- a/docs/design/classes.md +++ b/docs/design/classes.md @@ -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)*); ``` diff --git a/docs/design/control_flow/loops.md b/docs/design/control_flow/loops.md index c17f5695d0cf..72b5dac4f469 100644 --- a/docs/design/control_flow/loops.md +++ b/docs/design/control_flow/loops.md @@ -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); } diff --git a/docs/design/expressions/arithmetic.md b/docs/design/expressions/arithmetic.md index 928d8ea7244c..fbd6b3032386 100644 --- a/docs/design/expressions/arithmetic.md +++ b/docs/design/expressions/arithmetic.md @@ -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 { diff --git a/docs/design/expressions/as_expressions.md b/docs/design/expressions/as_expressions.md index 3be0bd43d866..bdc3b5110e96 100644 --- a/docs/design/expressions/as_expressions.md +++ b/docs/design/expressions/as_expressions.md @@ -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; } ``` diff --git a/docs/design/expressions/bitwise.md b/docs/design/expressions/bitwise.md index cc31526a5b76..980d36d48166 100644 --- a/docs/design/expressions/bitwise.md +++ b/docs/design/expressions/bitwise.md @@ -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 { diff --git a/docs/design/expressions/comparison_operators.md b/docs/design/expressions/comparison_operators.md index 6a52f72b943c..92c5ca3c31e9 100644 --- a/docs/design/expressions/comparison_operators.md +++ b/docs/design/expressions/comparison_operators.md @@ -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 diff --git a/docs/design/expressions/if.md b/docs/design/expressions/if.md index bd08e8fb70fe..c51043bb176a 100644 --- a/docs/design/expressions/if.md +++ b/docs/design/expressions/if.md @@ -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 {} ``` diff --git a/docs/design/expressions/implicit_conversions.md b/docs/design/expressions/implicit_conversions.md index ada4c0c976d9..03e23cf06e60 100644 --- a/docs/design/expressions/implicit_conversions.md +++ b/docs/design/expressions/implicit_conversions.md @@ -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; diff --git a/docs/design/expressions/indexing.md b/docs/design/expressions/indexing.md index 908ba18e7dc0..73bf327f6e89 100644 --- a/docs/design/expressions/indexing.md +++ b/docs/design/expressions/indexing.md @@ -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; } } diff --git a/docs/design/expressions/literals.md b/docs/design/expressions/literals.md index e224e3a467df..bb039e82c25d 100644 --- a/docs/design/expressions/literals.md +++ b/docs/design/expressions/literals.md @@ -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`. diff --git a/docs/design/expressions/member_access.md b/docs/design/expressions/member_access.md index 8209e09b5ac2..3f7bc622e98b 100644 --- a/docs/design/expressions/member_access.md +++ b/docs/design/expressions/member_access.md @@ -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; } ``` diff --git a/docs/design/functions.md b/docs/design/functions.md index aea4920d34e9..4eb7c4ebef57 100644 --- a/docs/design/functions.md +++ b/docs/design/functions.md @@ -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"); } } diff --git a/docs/design/generics/appendix-coherence.md b/docs/design/generics/appendix-coherence.md index bd45429ad066..ac521b0686fb 100644 --- a/docs/design/generics/appendix-coherence.md +++ b/docs/design/generics/appendix-coherence.md @@ -67,7 +67,7 @@ this: ``` package Container; - class HashSet(Key:! Hashable) { ... } + class HashSet(Key: Hashable) { ... } ``` - A `Song` type is defined in package `SongLib`. diff --git a/docs/design/generics/appendix-rewrite-constraints.md b/docs/design/generics/appendix-rewrite-constraints.md index 1cb91264f787..2ff05d3a2f8b 100644 --- a/docs/design/generics/appendix-rewrite-constraints.md +++ b/docs/design/generics/appendix-rewrite-constraints.md @@ -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 diff --git a/docs/design/generics/appendix-witness.md b/docs/design/generics/appendix-witness.md index 8d870979b620..d45b0be7796b 100644 --- a/docs/design/generics/appendix-witness.md +++ b/docs/design/generics/appendix-witness.md @@ -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; diff --git a/docs/design/generics/details.md b/docs/design/generics/details.md index db9dc194615d..6f20d8fc80d7 100644 --- a/docs/design/generics/details.md +++ b/docs/design/generics/details.md @@ -174,18 +174,22 @@ allow a container interface to include the type of iterators that are returned from and passed to various container methods. The function expresses that the type argument is passed in statically, basically -generating a separate function body for every different type passed in, by using -the "compile-time parameter" syntax `:!`. By default, this defines a -[checked-generics parameter](#checked-generic-functions) below. In this case, -the interface contains enough information to +generating a separate function body for every different type passed in, by +either accepting it as an +[implicit parameter](terminology.md#deduced-parameter), or marking an explicit +parameter as either `generic` or `template`. The default semantics for implicit +parameters are [checked-generics parameter](#checked-generic-functions), the +same as an explicit parameter with `generic`. In this case, the interface +contains enough information to [type and definition check](terminology.md#complete-definition-checking) the function body -- you can only call functions defined in the interface in the function body. -Alternatively, the `template` keyword can be included in the signature to make -the type a template parameter. In this case, you could just use `type` instead -of an interface and it will work as long as the function is only called with -types that allow the definition of the function to compile. +Alternatively, if the `template` keyword is used on the binding for either +implicit or explicit parameters, it becomes a _template_ generic parameter. In +this case, you could just use `type` instead of an interface and it will work as +long as the function is only called with types that allow the definition of the +function to compile. The interface bound has other benefits: @@ -675,19 +679,17 @@ Here is a function that can accept values of any type that has implemented the `Vector` interface: ```carbon -fn AddAndScaleGeneric[T:! Vector](a: T, b: T, s: f64) -> T { +fn AddAndScaleGeneric[T: Vector](a: T, b: T, s: f64) -> T { return a.Add(b).Scale(s); } var v: Point_Extend = AddAndScaleGeneric(a, w, 2.5); ``` -Here `T` is a facet whose type is `Vector`. The `:!` syntax means that `T` is a -_[compile-time binding](terminology.md#bindings)_. Here specifically it declares -a _symbolic binding_ since it did not use the `template` keyword to mark it as a -_template binding_. +Here `T` is a facet whose type is `Vector`. It declares a _symbolic binding_ +since it did not use the `template` keyword to mark it as a _template binding_. -> **References:** The `:!` syntax was accepted in -> [proposal #676](https://github.com/carbon-language/carbon-lang/pull/676). +> **References:** The syntax for compile-time bindings was decided in +> [proposal #7254](https://github.com/carbon-language/carbon-lang/pull/7254). Since this symbolic binding pattern is in a function declaration, it marks a _[checked](terminology.md#checked-versus-template-parameters) @@ -717,7 +719,7 @@ to adding a `Vector` all simple member accesses of `T`: ```carbon -fn AddAndScaleGeneric[T:! Vector](a: T, b: T, s: Double) -> T { +fn AddAndScaleGeneric[T: Vector](a: T, b: T, s: Double) -> T { return a.(Vector.Add)(b).(Vector.Scale)(s); } ``` @@ -790,7 +792,7 @@ symbolic constant. In this example of calling a checked generic from another checked generic, ```carbon -fn DoubleThreeTimes[U:! Vector](a: U) -> U { +fn DoubleThreeTimes[U: Vector](a: U) -> U { return AddAndScaleGeneric(a, a, 2.0).Scale(2.0); } ``` @@ -806,12 +808,12 @@ implementing `Vector`, and a function that takes a `GeneralPoint` and calls `AddAndScaleGeneric` with it: ```carbon -class GeneralPoint(C:! Numeric) { +class GeneralPoint(C: Numeric) { impl as Vector { ... } fn Get(self, i: i32) -> C; } -fn CallWithGeneralPoint[C:! Numeric](p: GeneralPoint(C)) -> C { +fn CallWithGeneralPoint[C: Numeric](p: GeneralPoint(C)) -> C { // `AddAndScaleGeneric` returns `T` and in these calls `T` is // deduced to be `GeneralPoint(C)`. @@ -891,7 +893,7 @@ This recovers the original type for the facet, so `(Point_Inline as Vector) as type` is `Point_Inline` again. However, when a facet type like `Vector` is used as the binding type of a -symbolic binding, as in `T:! Vector`, the +symbolic binding, the [symbolic facet binding](#symbolic-facet-bindings) `T` is disassociated with whatever facet value `T` is eventually bound to. Instead, `T` is treated as an [archetype](terminology.md#archetype), with the members and @@ -978,9 +980,9 @@ of `Self`. ```carbon interface Z {} -class UsesZ(T:! Z) {} +class UsesZ(T: Z) {} -interface Y(T:! type) {} +interface Y(T: type) {} interface X {} constraint Constraint { @@ -1035,7 +1037,7 @@ That is, `type` is the facet type with no requirements (so matches every type), and defines no names. ```carbon -fn Identity[T:! type](x: T*) -> T* { +fn Identity[T: type](x: T*) -> T* { // Can accept values of any type. But, since we know nothing about the // type, we don't know about any operations on `x` inside this function. return x; @@ -1130,10 +1132,10 @@ constraint JustPrint { require impls Printable; } -fn PrintIt[T2:! JustPrint](x2: T2) { +fn PrintIt[T2: JustPrint](x2: T2) { x2.(Printable.Print)(); } -fn PrintDrawPrint[T1:! PrintAndRender](x1: T1) { +fn PrintDrawPrint[T1: PrintAndRender](x1: T1) { // x1 implements `Printable` and `Renderable`. x1.(Printable.Print)(); x1.(Renderable.Draw)(); @@ -1168,7 +1170,7 @@ constraint { alias Draw = Renderable.Draw; } -fn PrintThenDraw[T:! Printable & Renderable](x: T) { +fn PrintThenDraw[T: Printable & Renderable](x: T) { // Can use methods of `Printable` or `Renderable` on `x` here. x.Print(); // Same as `x.(Printable.Print)();`. x.Draw(); // Same as `x.(Renderable.Draw)();`. @@ -1200,7 +1202,7 @@ interface EndOfGame { fn Draw(self); fn Winner(self, player: i32); } -fn F[T:! Renderable & EndOfGame](x: T) { +fn F[T: Renderable & EndOfGame](x: T) { // ❌ Error: Ambiguous, use either `(Renderable.Draw)` // or `(EndOfGame.Draw)`. x.Draw(); @@ -1221,7 +1223,7 @@ constraint RenderableAndEndOfGame { alias Winner = EndOfGame.Winner; } -fn RenderTieGame[T:! RenderableAndEndOfGame](x: T) { +fn RenderTieGame[T: RenderableAndEndOfGame](x: T) { // ✅ Calls `Renderable.Draw`: x.RenderableDraw(); // ✅ Calls `EndOfGame.Draw`: @@ -1293,7 +1295,7 @@ interface Iterable { require impls Equatable; } -fn DoAdvanceAndEquals[T:! Iterable](x: T) { +fn DoAdvanceAndEquals[T: Iterable](x: T) { // `x` has type `T` that implements `Iterable`, and so has `Advance`. x.Advance(); // `Iterable` requires an implementation of `Equatable`, @@ -1341,7 +1343,7 @@ interface Hashable { alias Equals = Equatable.Equals; } -fn DoHashAndEquals[T:! Hashable](x: T) { +fn DoHashAndEquals[T: Hashable](x: T) { // Now both `Hash` and `Equals` are available directly: x.Hash(); x.Equals(x); @@ -1459,7 +1461,7 @@ definitions from the `impl` of `B`. Here is an example: ```carbon interface A { - let T:! type; + let T: type; fn F(); fn G(); } @@ -1474,13 +1476,13 @@ This is equivalent to writing `B` as: ```carbon interface B { - let T:! type; + let T: type; fn F(); fn G(); fn H(); } -impl forall [U:! B] U as A { - let T:! type = U.(B.T); +impl forall [U: B] U as A { + let T: type = U.(B.T); fn F() = U.(B.F); fn G() = U.(B.G); } @@ -1500,11 +1502,11 @@ body in parameters or constraints of the interface being extended. ```carbon // A type can implement `ConvertibleTo` many times, // using different values of `T`. -interface ConvertibleTo(T:! type) { ... } +interface ConvertibleTo(T: type) { ... } // A type can only implement `PreferredConversion` once. interface PreferredConversion { - let AssociatedFacet:! type; + let AssociatedFacet: type; // `extend require impls` is in the body of an `interface` // definition. This allows extending an expression // that uses an associated facet. @@ -1823,7 +1825,7 @@ Consider a [type with a facet parameter, like a hash map](#parameterized-types): ```carbon interface Hashable { ... } -class HashMap(KeyT:! Hashable, ValueT:! type) { +class HashMap(KeyT: Hashable, ValueT: type) { fn Find(self, key: KeyT) -> Optional(ValueT); // ... } @@ -2011,7 +2013,7 @@ another interface `Difference`: interface Difference { fn Sub(self, rhs: Self) -> i32; } -class ComparableFromDifference(T:! Difference) { +class ComparableFromDifference(T: Difference) { adapt T; extend impl as Comparable { fn Less(self, rhs: Self) -> bool { @@ -2035,7 +2037,7 @@ use to the adapter instead: ```carbon class ComparableFromDifferenceFn - (T:! type, Difference:! fnty(T, T)->i32) { + (T: type, Difference: fnty(T, T)->i32) { adapt T; extend impl as Comparable { fn Less(self, rhs: Self) -> bool { @@ -2133,7 +2135,7 @@ fn Render(w: Window) { ```carbon fn Render(w: Window) { - let DrawInWindow:! Draw = Window; + let generic DrawInWindow: Draw = Window; // Implicit conversion to `w as DrawInWindow`. let d: DrawInWindow = w; d.SetPen(...); @@ -2173,7 +2175,7 @@ as an associated constant. ```carbon interface NSpacePoint { - let N:! i32; + let N: i32; // The following require: 0 <= i < N. fn Get(ref self, i: i32) -> f64; fn Set(ref self, i: i32, value: f64); @@ -2182,13 +2184,14 @@ interface NSpacePoint { } ``` -The pattern of an associated constant declaration must be a symbolic binding -pattern, and unlike other `let` declarations, an associated constant declaration -cannot have an initializer unless it's +The pattern of an associated constant declaration must be a single binding +pattern with no category or phase modifiers, and is interpreted as a checked +generic binding pattern. Unlike other `let` declarations, an associated +constant declaration cannot have an initializer unless it's [preceded by `default`](#interface-defaults): -_associated-constant-decl_ ::= `let` _identifier_ `:!` _expression_ `;` -_associated-constant-decl_ ::= `default` `let` _identifier_ `:!` _expression_ = +_associated-constant-decl_ ::= `let` _identifier_ `:` _expression_ `;` +_associated-constant-decl_ ::= `default` `let` _identifier_ `:` _expression_ = _expression_ `;` An implementation of an interface specifies values for associated constants with @@ -2228,7 +2231,7 @@ These values may be accessed as members of the type: Assert(Point2D.N == 2); Assert(Point3D.N == 3); -fn PrintPoint[PointT:! NSpacePoint](p: PointT) { +fn PrintPoint[PointT: NSpacePoint](p: PointT) { var i: i32 = 0 while (i < PointT.N) { if (i > 0) { Print(", "); } @@ -2237,7 +2240,7 @@ fn PrintPoint[PointT:! NSpacePoint](p: PointT) { } } -fn ExtractPoint[PointT:! NSpacePoint]( +fn ExtractPoint[PointT: NSpacePoint]( p: PointT, dest: Array(f64, PointT.N)*) { var i: i32 = 0; @@ -2251,9 +2254,6 @@ fn ExtractPoint[PointT:! NSpacePoint]( **Comparison with other languages:** This feature is also called [associated constants in Rust](https://doc.rust-lang.org/reference/items/associated-items.html#associated-constants). -**Aside:** The use of `:!` here means these `let` declarations will only have -compile-time and not runtime storage associated with them. - ### Associated functions Associated constants can also be _functions_. These are called _associated @@ -2282,7 +2282,7 @@ class MySerializableType { var x: MySerializableType = MySerializableType.Deserialize("3"); -fn Deserialize(T:! DeserializeFromString, serialized: String) -> T { +fn Deserialize(generic T: DeserializeFromString, serialized: String) -> T { return T.Deserialize(serialized); } var y: MySerializableType = Deserialize(MySerializableType, "4"); @@ -2308,7 +2308,7 @@ a specified name. For example: ```carbon interface StackAssociatedFacet { - let ElementType:! type; + let ElementType: type; fn Push(ref self, value: ElementType); fn Pop(ref self) -> ElementType; fn IsEmpty(ref self) -> bool; @@ -2322,7 +2322,7 @@ of `StackAssociatedFacet` must also define. For example, maybe a `DynamicArray` [parameterized type](#parameterized-types) implements `StackAssociatedFacet`: ```carbon -class DynamicArray(T:! type) { +class DynamicArray(T: type) { class IteratorType { ... } fn Begin(ref self) -> IteratorType; fn End(ref self) -> IteratorType; @@ -2372,7 +2372,7 @@ checked-generic function that operates on anything implementing that interface, for example: ```carbon -fn PeekAtTopOfStack[StackType:! StackAssociatedFacet](s: StackType*) +fn PeekAtTopOfStack[StackType: StackAssociatedFacet](s: StackType*) -> StackType.ElementType { var top: StackType.ElementType = s->Pop(); s->Push(top); @@ -2407,11 +2407,11 @@ Associated facets can also be implemented using a ```carbon interface Container { - let IteratorType:! Iterator; + let IteratorType: Iterator; ... } -class DynamicArray(T:! type) { +class DynamicArray(T: type) { ... extend impl as Container { class IteratorType { @@ -2444,7 +2444,7 @@ stack interface, instead of using associated constants, write a parameter list after the name of the interface: ```carbon -interface StackParameterized(ElementType:! type) { +interface StackParameterized(ElementType: type) { fn Push(ref self, value: ElementType); fn Pop(ref self) -> ElementType; fn IsEmpty(ref self) -> bool; @@ -2491,7 +2491,7 @@ for `StackParameterized(T)` it would generate a compile error: ```carbon // ❌ Error: can't deduce interface parameter `T`. fn BrokenPeekAtTopOfStackParameterized - [T:! type, StackType:! StackParameterized(T)] + [T: type, StackType: StackParameterized(T)] (s: StackType*) -> T { ... } ``` @@ -2501,7 +2501,7 @@ replaced by a concrete type, like `Fruit`: ```carbon fn PeekAtTopOfFruitStack - [StackType:! StackParameterized(Fruit)] + [StackType: StackParameterized(Fruit)] (s: StackType*) -> T { ... } var produce: Produce = ...; @@ -2514,11 +2514,11 @@ described [in this section](#another-type-implements-parameterized-interface): ```carbon fn PeekAtTopOfStackParameterizedImpl - (T:! type, StackType:! StackParameterized(T), s: StackType*) -> T { + (generic T: type, generic StackType: StackParameterized(T), s: StackType*) -> T { ... } -fn PeekAtTopOfStackParameterized[StackType:! type] - (s: StackType*, T:! type where StackType impls StackParameterized(T)) -> T { +fn PeekAtTopOfStackParameterized[StackType: type] + (s: StackType*, generic T: type where StackType impls StackParameterized(T)) -> T { return PeekAtTopOfStackParameterizedImpl(T, StackType, s); } @@ -2539,7 +2539,7 @@ Parameterized interfaces are useful for with multiple other types, as in: ```carbon -interface EqWith(T:! type) { +interface EqWith(T: type) { fn Equal(self, rhs: T) -> bool; ... } @@ -2554,8 +2554,8 @@ class Complex { } ``` -All interface parameters must be marked as "symbolic", using the `:!` binding -pattern syntax. This reflects these two properties of these parameters: +All interface parameters are checked by default. This reflects these two +properties of these parameters: - They must be resolved at compile-time, and so can't be passed regular dynamic values. @@ -2570,8 +2570,8 @@ type to define how the tuple-member-read operator would work, the index of the member could be an interface parameter: ```carbon -interface ReadTupleMember(index:! u32) { - let T:! type; +interface ReadTupleMember(index: u32) { + let T: type; // Returns self[index] fn Get(self) -> T; } @@ -2584,10 +2584,10 @@ indices to be associated with different values of `T`. parameters are required to always be different. For example: ```carbon -interface Map(FromType:! type, ToType:! type) { +interface Map(FromType: type, ToType: type) { fn Map(ref self, needle: FromType) -> Optional(ToType); } -class Bijection(FromType:! type, ToType:! type) { +class Bijection(FromType: type, ToType: type) { extend impl as Map(FromType, ToType) { ... } extend impl as Map(ToType, FromType) { ... } } @@ -2601,10 +2601,10 @@ contain the `impl` for the reverse map lookup, instead of implementing the `Map` interface twice: ```carbon -class Bijection(FromType:! type, ToType:! type) { +class Bijection(FromType: type, ToType: type) { extend impl as Map(FromType, ToType) { ... } } -class ReverseLookup(FromType:! type, ToType:! type) { +class ReverseLookup(FromType: type, ToType: type) { adapt Bijection(FromType, ToType); extend impl as Map(ToType, FromType) { ... } } @@ -2638,20 +2638,20 @@ The where operator can be applied to a facet type in a declaration context: ```carbon // Constraints on generic function parameters: -fn F[V:! D where ...](v: V) { ... } +fn F[V: D where ...](v: V) { ... } // Constraints on a class parameter: -class S(T:! B where ...) { +class S(T: B where ...) { // Constraints on a method: - fn G[V:! D where ...](self, v: V); + fn G[V: D where ...](self, v: V); } // Constraints on an interface parameter: -interface A(T:! B where ...) { +interface A(T: B where ...) { // Constraints on an associated facet: - let U:! C where ...; + let U: C where ...; // Constraints on an associated method: - fn G[V:! D where ...](self, v: V); + fn G[V: D where ...](self, v: V); } ``` @@ -2773,7 +2773,7 @@ to encode the return type: ```carbon interface HasAbs { extend Numeric; - let MagnitudeType:! Numeric; + let MagnitudeType: Numeric; fn Abs(self) -> MagnitudeType; } ``` @@ -2795,11 +2795,11 @@ of every interface. We can then address it using `.Self` in a `where` clause, like any other associated facet member. ```carbon -fn Relu[T:! HasAbs where .MagnitudeType = .Self](x: T) { +fn Relu[T: HasAbs where .MagnitudeType = .Self](x: T) { // T.MagnitudeType == T so the following is allowed: return (x.Abs() + x) / 2; } -fn UseContainer[T:! Container where .SliceType = .Self](c: T) -> bool { +fn UseContainer[T: Container where .SliceType = .Self](c: T) -> bool { // T.SliceType == T so `c` and `c.Slice(...)` can be compared: return c == c.Slice(...); } @@ -2811,20 +2811,20 @@ defined. ```carbon interface Container; -constraint SliceConstraint(E:! type, S:! Container); +constraint SliceConstraint(E: type, S: Container); interface Container { - let ElementType:! type; - let IteratorType:! Iterator where .ElementType = ElementType; + let ElementType: type; + let IteratorType: Iterator where .ElementType = ElementType; // `.Self` means `SliceType`. - let SliceType:! Container where .Self impls SliceConstraint(ElementType, .Self); + let SliceType: Container where .Self impls SliceConstraint(ElementType, .Self); // `Self` means the type implementing `Container`. fn GetSlice(ref self, start: IteratorType, end: IteratorType) -> SliceType; } -constraint SliceConstraint(E:! type, S:! Container) { +constraint SliceConstraint(E: type, S: Container) { extend Container where .ElementType = E and .SliceType = S; } @@ -2858,11 +2858,15 @@ constraint ContainerIsSlice { The `.Self` construct follows these rules: -- `X :!` introduces `.Self:! type`, where references to `.Self` are resolved - to `X`. This allows you to use `.Self` as an interface parameter as in - `X:! I(.Self)`. -- `A where` introduces `.Self:! A` and a `.Foo` _designator_ for each member - `Foo` of `A`. +- A generic binding `X` introduces a checked generic binding `.Self: type`, where + + references to `.Self` are resolved to `X`. This allows you to use `.Self` as + an interface parameter as in `X: I(.Self)`. +- `A where` introduces a checked generic binding `.Self: A` and a `.Foo` + + _designator_ for each + + member `Foo` of `A`. - It's an error to reference `.Self` if it refers to more than one different thing or isn't a facet. - You get the innermost, most-specific type for `.Self` if it is introduced @@ -2870,14 +2874,16 @@ The `.Self` construct follows these rules: to the same facet binding. - `.Self` may not be on the left side of the `=` in a rewrite constraint. -So in `X:! A where ...`, `.Self` is introduced twice, after the `:!` and the -`where`. This is allowed since both times it means `X`. After the `:!`, `.Self` -has the type `type`, which gets refined to `A` after the `where`. In contrast, -it is an error if `.Self` could mean two different things, as in: +So in `X: A where ...` (where `X` is a generic binding), `.Self` is + +introduced twice, after the `:` and the `where`. This is allowed since both +times it means `X`. After the `:`, `.Self` has the type `type`, which gets +refined to `A` after the `where`. In contrast, it is an error if `.Self` could +mean two different things, as in: ```carbon // ❌ Illegal: `.Self` could mean `T` or `T.A`. -fn F[T:! InterfaceA where .A impls +fn F[T: InterfaceA where .A impls (InterfaceB where .B = .Self)](x: T); ``` @@ -2888,13 +2894,13 @@ These two meanings can be disambiguated by defining a constraint InterfaceBWithSelf { extend InterfaceB where .B = Self; } -constraint InterfaceBWith(U:! InterfaceA) { +constraint InterfaceBWith(U: InterfaceA) { extend InterfaceB where .B = U; } // `T.A impls InterfaceB where .B = T.A` -fn F[T:! InterfaceA where .A impls InterfaceBWithSelf](x: T); +fn F[T: InterfaceA where .A impls InterfaceBWithSelf](x: T); // `T.A impls InterfaceB where .B = T` -fn F[T:! InterfaceA where .A impls InterfaceBWith(.Self)](x: T); +fn F[T: InterfaceA where .A impls InterfaceBWith(.Self)](x: T); ``` #### Rewrite constraints @@ -2905,18 +2911,18 @@ the name of an associated constant. `.Self` is not permitted. ```carbon interface RewriteSelf { // ❌ Error: `.Self` is not the name of an associated constant. - let Me:! type where .Self = Self; + let Me: type where .Self = Self; } interface HasAssoc { - let Assoc:! type; + let Assoc: type; } interface RewriteSingleLevel { // ✅ Uses of `A.Assoc` will be rewritten to `i32`. - let A:! HasAssoc where .Assoc = i32; + let A: HasAssoc where .Assoc = i32; } interface RewriteMultiLevel { // ❌ Error: Only one level of associated constant is permitted. - let B:! RewriteSingleLevel where .A.Assoc = i32; + let B: RewriteSingleLevel where .A.Assoc = i32; } ``` @@ -2928,15 +2934,15 @@ with any mentioned parameters substituted into that type. ```carbon interface Container { - let Element:! type; - let Slice:! Container where .Element = Element; + let Element: type; + let Slice: Container where .Element = Element; fn Add(ref self, x: Element); } // `T.Slice.Element` rewritten to `T.Element` // because type of `T.Slice` says `.Element = Element`. // `T.Element` rewritten to `i32` // because type of `T` says `.Element = i32`. -fn Add[T:! Container where .Element = i32](p: T*, y: T.Slice.Element) { +fn Add[T: Container where .Element = i32](p: T*, y: T.Slice.Element) { // ✅ Argument `y` has the same type `i32` as parameter `x` of // `T.(Container.Add)`, which is also rewritten to `i32`. p->Add(y); @@ -2949,8 +2955,8 @@ Instead, such a `where` clause is invalid when the constraint is [resolved](appendix-rewrite-constraints.md#rewrite-constraint-resolution) unless each rule for `.A` specifies the same rewrite. -Note that `T:! C where .R = i32` can result in a type `T.R` whose behavior is -different from the behavior of `T.R` given `T:! C`. For example, member lookup +Note that `T: C where .R = i32` can result in a type `T.R` whose behavior is +different from the behavior of `T.R` given `T: C`. For example, member lookup into `T.R` can find different results and operations can therefore have different behavior. However, this does not violate [coherence](/proposals/p002173-associated-constant-assignment-versus-equality.md#coherence) @@ -2981,7 +2987,7 @@ the two type expressions are treated as distinct types when type-checking a symbolic expression that refers to them. Same-type constraints are brought into scope, looked up, and resolved exactly as -if there were a `SameAs(U:! type)` interface and a `T == U` impl corresponded to +if there were a `SameAs(U: type)` interface and a `T == U` impl corresponded to `T is SameAs(U)`, except that `==` is commutative. Further, same-type equalities apply to type components, so that `X(A, B, C)` is @@ -3001,23 +3007,23 @@ accomplished by the use of `==` constraints in an `impl`, such as in the built-in implementation of `ImplicitAs`: ```carbon -final impl forall [T:! type, U:! type where .Self == T] T as ImplicitAs(U) { +final impl forall [T: type, U: type where .Self == T] T as ImplicitAs(U) { fn Convert(self, other: U) -> U { ... } } ``` > **Alternative considered:** It superficially seems like it would be convenient > if such implementations were made available implicitly –- for example, by -> writing `impl forall [T:! type] T as ImplicitAs(T)` -– but in more complex +> writing `impl forall [T: type] T as ImplicitAs(T)` -– but in more complex > examples that turns out to be problematic. Consider: > > ```carbon -> interface CommonTypeWith(U:! type) { -> let Result:! type; +> interface CommonTypeWith(U: type) { +> let Result: 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 {} > -> fn F[T:! Potato, U:! Hashable where .Self == T](x: T, y: U) -> auto { +> fn F[T: Potato, U: Hashable where .Self == T](x: T, y: U) -> auto { > // What is T.CommonTypeWith(U).Result? Is it T or U? > return (if cond then x else y).Hash(); > } @@ -3036,17 +3042,18 @@ between `C where .A = X` and `C where .A == X`: ```carbon interface EqualConverter { - let T:! type; + let T: type; fn Convert(t: T) -> Self; } -fn EqualConvert[T:! type](t: T, U:! EqualConverter where .T = T) -> U { +fn EqualConvert[T: type](t: T, generic U: EqualConverter where .T = T) -> U { + return U.Convert(t); } -impl forall [U:! type] U as EqualConverter where .T = U { +impl forall [U: type] U as EqualConverter where .T = U { fn Convert(u: U) -> U { return u; } } -impl forall [T:! type, U:! type where .Self == T] T as ImplicitAs(U) { +impl forall [T: type, U: type where .Self == T] T as ImplicitAs(U) { fn Convert(self) -> U { return EqualConvert(self, U); } } ``` @@ -3077,9 +3084,9 @@ interface Q { fn InQ(self); } interface R { fn InR(self); } interface Transitive { - let A:! P; - let B:! Q where .Self == A; - let C:! R where .Self == B; + let A: P; + let B: Q where .Self == A; + let C: R where .Self == B; fn GetA(self) -> A; fn TakesC(self, c: C); @@ -3090,7 +3097,7 @@ A cast to `B` is needed to call `TakesC` with a value of type `A`, so each step only relies on one equality: ```carbon -fn F[T:! Transitive](t: T) { +fn F[T: Transitive](t: T) { // ✅ Allowed t.TakesC(t.GetA() as T.B); @@ -3113,24 +3120,24 @@ but using `==` same-type constraints): interface Edge; interface Node; -private constraint EdgeFor(NodeT:! Node); -private constraint NodeFor(EdgeT:! Edge); +private constraint EdgeFor(NodeT: Node); +private constraint NodeFor(EdgeT: Edge); interface Edge { - let N:! NodeFor(Self); + let N: NodeFor(Self); fn GetN(self) -> N; } interface Node { - let E:! EdgeFor(Self); + let E: EdgeFor(Self); fn GetE(self) -> E; fn AddE(ref self, e: E); fn NearN(self, n: Self) -> bool; } -constraint EdgeFor(NodeT:! Node) { +constraint EdgeFor(NodeT: Node) { extend Edge where .N == NodeT; } -constraint NodeFor(EdgeT:! Edge) { +constraint NodeFor(EdgeT: Edge) { extend Node where .E == EdgeT; } ``` @@ -3139,7 +3146,7 @@ and a function `H` taking a value with some type implementing the `Node` interface, then the following would be legal statements in `H`: ```carbon -fn H[N:! Node](n: N) { +fn H[N: Node](n: N) { // ✅ Legal: argument has type `N.E`, matches parameter n.AddE(n.GetE()); @@ -3216,14 +3223,14 @@ an `interface` definition or a function body, as in: ```carbon interface Edge { - let N:! type; + let N: type; } interface Node { - let E:! type; + let E: type; } interface Graph { - let E:! Edge; - let N:! Node where .E == E and E.N == .Self; + let E: Edge; + let N: Node where .E == E and E.N == .Self; observe E == N.E == E.N.E == N.E.N.E; // ... } @@ -3261,9 +3268,9 @@ interface Q { fn InQ(self); } interface R { fn InR(self); } interface Transitive { - let A:! P; - let B:! Q where .Self == A; - let C:! R where .Self == B; + let A: P; + let B: Q where .Self == A; + let C: R where .Self == B; fn GetA(self) -> A; fn TakesC(self, c: C); @@ -3273,7 +3280,7 @@ interface Transitive { observe A == B == C; } -fn F[T:! Transitive](t: T) { +fn F[T: Transitive](t: T) { var a: T.A = t.GetA(); // ✅ Allowed: `T.A` values implicitly convert to @@ -3294,9 +3301,9 @@ type, that is solely determined by the definition of the type. Continuing the previous example: ```carbon -fn TakesPQR[U:! P & Q & R](u: U); +fn TakesPQR[U: P & Q & R](u: U); -fn G[T:! Transitive](t: T) { +fn G[T: Transitive](t: T) { var a: T.A = t.GetA(); // ✅ Allowed: `T.A` implements `P` and @@ -3345,12 +3352,12 @@ must satisfy the `Ordered` interface, using an `impls` constraint: ```carbon interface Container { - let ElementType:! type; + let ElementType: type; ... } fn SortContainer - [ContainerType:! Container where .ElementType impls Ordered] + [ContainerType: Container where .ElementType impls Ordered] (container_to_sort: ContainerType*); ``` @@ -3381,7 +3388,7 @@ An implements constraint can be applied to [`.Self`](#recursive-constraints), as in `I where .Self impls C`. This has the same requirements as `I & C`, but that `where` clause does not affect the API. This means that a [symbolic facet binding](#symbolic-facet-bindings) with that facet type, so `T` -in `T:! I where .Self impls C`, is represented by an +in `T: I where .Self impls C`, is represented by an [archetype](terminology.md#archetype) that implements both `I` and `C`, but only [extends](terminology.md#extending-an-impl) `I`. @@ -3391,11 +3398,11 @@ Imagine we have a checked-generic function that accepts an arbitrary [`HashMap` parameterized type](#parameterized-types): ```carbon -fn LookUp[KeyT:! type](hm: HashMap(KeyT, i32)*, +fn LookUp[KeyT: type](hm: HashMap(KeyT, i32)*, k: KeyT) -> i32; -fn PrintValueOrDefault[KeyT:! Printable, - ValueT:! Printable & HasDefault] +fn PrintValueOrDefault[KeyT: Printable, + ValueT: Printable & HasDefault] (map: HashMap(KeyT, ValueT), key: KeyT); ``` @@ -3404,7 +3411,7 @@ The `KeyT` in these declarations does not visibly satisfy the requirements of ```carbon class HashMap( - KeyT:! Hashable & Eq & Movable, + KeyT: Hashable & Eq & Movable, ...) { ... } ``` @@ -3414,14 +3421,14 @@ Effectively that means that these functions are automatically rewritten to add a ```carbon fn LookUp[ - KeyT:! type + KeyT: type where .Self impls Hashable & Eq & Movable] (hm: HashMap(KeyT, i32)*, k: KeyT) -> i32; fn PrintValueOrDefault[ - KeyT:! Printable + KeyT: Printable where .Self impls Hashable & Eq & Movable, - ValueT:! Printable & HasDefault] + ValueT: Printable & HasDefault] (map: HashMap(KeyT, ValueT), key: KeyT); ``` @@ -3448,7 +3455,7 @@ limited to a single signature. Consider this interface declaration: ```carbon interface GraphNode { - let Edge:! type; + let Edge: type; fn EdgesFrom(self) -> HashSet(Edge); } ``` @@ -3480,8 +3487,8 @@ equal and satisfy an interface: ```carbon fn EqualContainers - [CT1:! Container, - CT2:! Container where .ElementType impls HasEquality + [CT1: Container, + CT2: Container where .ElementType impls HasEquality and .ElementType = CT1.ElementType] (c1: CT1*, c2: CT2*) -> bool; ``` @@ -3504,14 +3511,14 @@ in these declarations: ```carbon // With `=` rewrite constraint: fn Contains_Rewrite - [SC:! SortedContainer, - CT:! Container where .ElementType = SC.ElementType] + [SC: SortedContainer, + CT: Container where .ElementType = SC.ElementType] (haystack: SC, needles: CT) -> bool; // With `==` same-type constraint: fn Contains_SameType - [SC:! SortedContainer, - CT:! Container where .ElementType == SC.ElementType] + [SC: SortedContainer, + CT: Container where .ElementType == SC.ElementType] (haystack: SC, needles: CT) -> bool; ``` @@ -3539,8 +3546,8 @@ declared first and the `where` clause is attached to `SortedContainer`: ```carbon fn Contains_SameType_Equivalent - [CT:! Container, - SC:! SortedContainer where .ElementType == CT.ElementType] + [CT: Container, + SC: SortedContainer where .ElementType == CT.ElementType] (haystack: SC, needles: CT) -> bool; ``` @@ -3560,25 +3567,25 @@ declared last. So: ```carbon // ❌ Error: `where A == B` does not use `.Self` or a designator -fn F[A:! type, B:! type, C:! type where A == B](a: A, b: B, c: C); +fn F[A: type, B: type, C: type where A == B](a: A, b: B, c: C); ``` must be replaced by: ```carbon // ✅ Allowed -fn F[A:! type, B:! type where A == .Self, C:! type](a: A, b: B, c: C); +fn F[A: type, B: type where A == .Self, C: type](a: A, b: B, c: C); ``` This includes `where` clauses used in an `impl` declaration: ```carbon // ❌ Error: `where T impls B` does not use `.Self` or a designator -impl forall [T:! type] T as A where T impls B {} +impl forall [T: type] T as A where T impls B {} // ✅ Allowed -impl forall [T:! type where .Self impls B] T as A {} +impl forall [T: type where .Self impls B] T as A {} // ✅ Allowed -impl forall [T:! B] T as A {} +impl forall [T: B] T as A {} ``` This clarifies the meaning of the `where` clause and reduces the number of @@ -3591,29 +3598,29 @@ clause must contain a designator. ```carbon // ✅ Allowed -fn F(T:! type where C(.Self) impls (A & B)); +fn F(generic T: type where C(.Self) impls (A & B)); // Which is the same as: -fn F(T:! (type where C(.Self) impls A) and (type where C(.Self) impls B)); +fn F(generic T: (type where C(.Self) impls A) and (type where C(.Self) impls B)); // ✅ Allowed -fn F(T:! type where C impls (A(.Self) & B(.Self))); +fn F(generic T: type where C impls (A(.Self) & B(.Self))); // Which is the same as: -fn F(T:! (type where C impls A(.Self)) and (type where C impls B(.Self))); +fn F(generic T: (type where C impls A(.Self)) and (type where C impls B(.Self))); // ❌ Error: `where C impls A` does not use `.Self` or a designator -fn F(T:! type where C impls (A & B(.Self))); +fn F(generic T: type where C impls (A & B(.Self))); // Which is the same as: -fn F(T:! (type where C impls A) & (type where C impls B(.Self))); +fn F(generic T: (type where C impls A) & (type where C impls B(.Self))); // ✅ Allowed -fn F(T:! type where C impls A(.Self) and X == .Self); +fn F(generic T: type where C impls A(.Self) and X == .Self); // Which is the same as: -fn F(T:! (type where C impls A(.Self)) & (type where X == .Self)); +fn F(generic T: (type where C impls A(.Self)) & (type where X == .Self)); // ❌ Error: `where X == Y` does not use `.Self` or a designator -fn F(T:! type where C impls A(.Self) and X == Y); +fn F(generic T: type where C impls A(.Self) and X == Y); // Which is the same as: -fn F(T:! (type where C impls A(.Self)) & (type where X == Y)); +fn F(generic T: (type where C impls A(.Self)) & (type where X == Y)); ``` **Alternative considered:** This rule was added in proposal @@ -3653,7 +3660,7 @@ interface Graph { that implement the `Stack` interface with integer elements, as in: ```carbon - fn SumIntStack[T:! Stack where .ElementType = i32] + fn SumIntStack[T: Stack where .ElementType = i32] (s: T*) -> i32 { var sum: i32 = 0; while (!s->IsEmpty()) { @@ -3673,8 +3680,8 @@ interface Graph { ```carbon interface PointCloud { - let Dim:! i32; - let PointT:! NSpacePoint where .N = Dim; + let Dim: i32; + let PointT: NSpacePoint where .N = Dim; } ``` @@ -3688,12 +3695,12 @@ interface Graph { ```carbon interface Iterator { - let ElementType:! type; + let ElementType: type; ... } interface Container { - let ElementType:! type; - let IteratorType:! Iterator where .ElementType = ElementType; + let ElementType: type; + let IteratorType: Iterator where .ElementType = ElementType; ... } ``` @@ -3702,8 +3709,8 @@ interface Graph { parameter: ```carbon - fn Map[CT:! Container, - FT:! Function where .InputType = CT.ElementType] + fn Map[CT: Container, + FT: Function where .InputType = CT.ElementType] (c: CT, f: FT) -> Vector(FT.OutputType); ``` @@ -3712,8 +3719,8 @@ interface Graph { ```carbon interface PairInterface { - let Left:! type; - let Right:! type; + let Left: type; + let Right: type; } ``` @@ -3729,7 +3736,7 @@ interface Graph { ```carbon interface IteratorInterface { ... } interface ContainerInterface { - let IteratorType:! IteratorInterface; + let IteratorType: IteratorInterface; // ... } interface RandomAccessIterator { @@ -3743,7 +3750,7 @@ interface Graph { `RandomAccessIterator`: ```carbon - fn F[ContainerType:! ContainerInterface + fn F[ContainerType: ContainerInterface where .IteratorType impls RandomAccessIterator] (c: ContainerType); ``` @@ -3757,7 +3764,7 @@ the result to implement a specific interface. ```carbon // A parameterized type -class DynArray(T:! type) { ... } +class DynArray(T: type) { ... } interface Printable { fn Print(self); } @@ -3767,7 +3774,7 @@ impl DynArray(String) as Printable { ... } // Constraint: `T` such that `DynArray(T)` implements `Printable` fn PrintThree - [T:! type where DynArray(.Self) impls Printable] + [T: type where DynArray(.Self) impls Printable] (a: T, b: T, c: T) { // Create a `DynArray(T)` of size 3. var v: auto = DynArray(T).Make(a, b, c); @@ -3795,11 +3802,11 @@ to the right of the `impls`. For example, we might need a type parameter `T` to support explicit conversion from an `i32`: ```carbon -interface As(T:! type) { +interface As(T: type) { fn Convert(self) -> T; } -fn Double[T:! Mul where i32 impls As(.Self)](x: T) -> T { +fn Double[T: Mul where i32 impls As(.Self)](x: T) -> T { return x * ((2 as i32) as T); } ``` @@ -3821,7 +3828,7 @@ them, needs them to be `Hashable` and so on. To say "`T` is a type where `HashSet(T)` is legal," we can write: ```carbon -fn NumDistinct[T:! type where HashSet(.Self) impls type] +fn NumDistinct[T: type where HashSet(.Self) impls type] (a: T, b: T, c: T) -> i32 { var set: HashSet(T); set.Add(a); @@ -3843,13 +3850,13 @@ named two different ways: - Using `let template` as in: ```carbon - let template NameOfConstraint:! auto = C where ; + let template NameOfConstraint: auto = C where ; ``` or, since the type of a facet type is `type`: ```carbon - let template NameOfConstraint:! type = C where ; + let template NameOfConstraint: type = C where ; ``` - Using a [named constraint](#named-constraints) with the `constraint` keyword @@ -3884,16 +3891,16 @@ include beyond [interfaces implemented](#facet-types) and Given a type `T`, `Extends(T)` is a facet type whose values are facets that are (transitively) [derived from](/docs/design/classes.md#inheritance) `T`. That is, -`U:! Extends(T)` means `U` has an `extend base: T;` declaration, or there is a +`U: Extends(T)` means `U` has an `extend base: T;` declaration, or there is a chain of `extend base` declarations connecting `T` to `U`. ```carbon base class BaseType { ... } -fn F[T:! Extends(BaseType)](p: T*); -fn UpCast[U:! type] - (p: U*, V:! type where U impls Extends(.Self)) -> V*; -fn DownCast[X:! type](p: X*, Y:! Extends(X)) -> Y*; +fn F[T: Extends(BaseType)](p: T*); +fn UpCast[U: type] + (p: U*, generic V: type where U impls Extends(.Self)) -> V*; +fn DownCast[X: type](p: X*, generic Y: Extends(X)) -> Y*; class DerivedType { extend base: BaseType; @@ -3915,9 +3922,9 @@ Assert(DownCast(p, DerivedType) == &d); use in `where` clauses: ```carbon -fn F[T:! type where .Self extends BaseType](p: T*); -fn UpCast[T:! type](p: T*, U:! type where T extends .Self) -> U*; -fn DownCast[T:! type](p: T*, U:! type where .Self extends T) -> U*; +fn F[T: type where .Self extends BaseType](p: T*); +fn UpCast[T: type](p: T*, generic U: type where T extends .Self) -> U*; +fn DownCast[T: type](p: T*, generic U: type where .Self extends T) -> U*; ``` **Comparison to other languages:** In Swift, you can @@ -3942,7 +3949,7 @@ Specifically, given two types `T1` and `T2`, they are equivalent if may not be deduced. Specifically, this code would be illegal: ```carbon -fn Illegal[U:! type, T:! CompatibleWith(U)](x: T*) ... +fn Illegal[U: type, T: CompatibleWith(U)](x: T*) ... ``` In general there would be multiple choices for `U` given a specific `T` here, @@ -3950,7 +3957,7 @@ and no good way of picking one. However, similar code is allowed if there is another way of determining `U`: ```carbon -fn Allowed[U:! type, T:! CompatibleWith(U)](x: U*, y: T*) ... +fn Allowed[U: type, T: CompatibleWith(U)](x: U*, y: T*) ... ``` #### Same implementation restriction @@ -3964,7 +3971,7 @@ the same way as the type `U`. For example, if we have a type `HashSet(T)`: ```carbon -class HashSet(T:! Hashable) { ... } +class HashSet(T: Hashable) { ... } ``` Then `HashSet(T)` may be cast to `HashSet(U)` if @@ -3982,9 +3989,9 @@ choice CompareResult { Less, Equal, Greater } interface Ordered { fn Compare(self, rhs: Self) -> CompareResult; } -fn CombinedLess[T:! type](a: T, b: T, - U:! CompatibleWith(T) & Ordered, - V:! CompatibleWith(T) & Ordered) -> bool { +fn CombinedLess[T: type](a: T, b: T, + generic U: CompatibleWith(T) & Ordered, + generic V: CompatibleWith(T) & Ordered) -> bool { match ((a as U).Compare(b as U)) { case .Less => { return True; } case .Greater => { return False; } @@ -4010,8 +4017,8 @@ assert(CombinedLess(s1, s2, SongByArtist, SongByTitle) == True); > variadics: > > ```carbon -> fn CombinedCompare[T:! type] -> (a: T, b: T, ... each CompareT:! CompatibleWith(T) & Ordered) +> fn CombinedCompare[T: type] +> (a: T, b: T, ... generic each CompareT: CompatibleWith(T) & Ordered) > -> CompareResult { > ... block { > let result: CompareResult = @@ -4037,8 +4044,8 @@ combine `CompatibleWith` with [type adaptation](#adapting-types) and ```carbon class ThenCompare( - T:! type, - ... each CompareT:! CompatibleWith(T) & Ordered) { + T: type, + ... each CompareT: CompatibleWith(T) & Ordered) { adapt T; extend impl as Ordered { fn Compare(self, rhs: Self) -> CompareResult { @@ -4054,7 +4061,7 @@ class ThenCompare( } } -let template SongByArtistThenTitle:! auto = +let template SongByArtistThenTitle: auto = ThenCompare(Song, SongByArtist, SongByTitle); var s1: Song = ...; var s2: SongByArtistThenTitle = @@ -4111,7 +4118,7 @@ class Name { ... } -fn F[T:! type](x: T*) { // T is unsized. +fn F[T: type](x: T*) { // T is unsized. // ✅ Allowed: may access unsized values through a pointer. var y: T* = x; // ❌ Illegal: T is unsized. @@ -4177,7 +4184,7 @@ function call. ```carbon fn SymbolicLet(...) { ... - let T:! C = U; + let generic T: C = U; X; Y; Z; @@ -4191,7 +4198,7 @@ concrete type `U` to the erased type `T`, as in: ```carbon let x: i32 = 7; -let T:! Add = i32; +let generic T: Add = i32; // ✅ Allowed to convert `i32` values to `T`. let y: T = x; ``` @@ -4205,7 +4212,7 @@ This makes the `SymbolicLet` function roughly equivalent to: ```carbon fn SymbolicLet(...) { ... - fn Closure(T:! C where .Self == U) { + fn Closure(generic T: C where .Self == U) { X; Y; Z; @@ -4228,7 +4235,7 @@ keyword before the binding pattern, as in: ```carbon fn TemplateLet(...) { ... - let template T:! C = U; + let template T: C = U; X; Y; Z; @@ -4241,7 +4248,7 @@ roughly equivalent to: ```carbon fn TemplateLet(...) { ... - fn Closure(template T:! C) { + fn Closure(template T: C) { X; Y; Z; @@ -4290,7 +4297,7 @@ Interfaces may be implemented for a [parameterized type](#parameterized-types). This can be done lexically in the class's scope: ```carbon -class Vector(T:! type) { +class Vector(T: type) { impl as Iterable where .ElementType = T { ... } @@ -4301,7 +4308,7 @@ This is equivalent to naming the implementing type between `impl` and `as`, though this form is not allowed after `extend`: ```carbon -class Vector(T:! type) { +class Vector(T: type) { impl Vector(T) as Iterable where .ElementType = T { ... } @@ -4312,7 +4319,7 @@ An out-of-line `impl` declaration must declare all parameters in a `forall` clause: ```carbon -impl forall [T:! type] Vector(T) as Iterable +impl forall [T: type] Vector(T) as Iterable where .ElementType = T { ... } @@ -4322,7 +4329,7 @@ The parameter for the type can be used as an argument to the interface being implemented, with or without `extend`: ```carbon -class HashMap(KeyT:! Hashable, ValueT:! type) { +class HashMap(KeyT: Hashable, ValueT: type) { extend impl as Has(KeyT) { ... } impl as Contains(HashSet(KeyT)) { ... } } @@ -4331,10 +4338,10 @@ class HashMap(KeyT:! Hashable, ValueT:! type) { or out-of-line the same `forall` parameter can be passed to both: ```carbon -class HashMap(KeyT:! Hashable, ValueT:! type) { ... } -impl forall [KeyT:! Hashable, ValueT:! type] +class HashMap(KeyT: Hashable, ValueT: type) { ... } +impl forall [KeyT: Hashable, ValueT: type] HashMap(KeyT, ValueT) as Has(KeyT) { ... } -impl forall [KeyT:! Hashable, ValueT:! type] +impl forall [KeyT: Hashable, ValueT: type] HashMap(KeyT, ValueT) as Contains(HashSet(KeyT)) { ... } ``` @@ -4360,11 +4367,11 @@ the `as` in the declaration: interface Printable { fn Print(self); } -class Vector(T:! type) { ... } +class Vector(T: type) { ... } -// By saying "T:! Printable" instead of "T:! type" here, +// By saying "T: Printable" instead of "T: type" here, // we constrain `T` to be `Printable` for this impl. -impl forall [T:! Printable] Vector(T) as Printable { +impl forall [T: Printable] Vector(T) as Printable { fn Print(self) { for (let a: T in self) { // Can call `Print` on `a` since the constraint @@ -4379,9 +4386,9 @@ Note that no `forall` clause or type may be specified when declaring an `impl` with the [`extend`](#extend-impl) keyword: ```carbon -class Array(T:! type, template N:! i64) { +class Array(T: type, template N: i64) { // ❌ Illegal: nothing allowed before `as` after `extend impl`: - extend impl forall [P:! Printable] Array(P, N) as Printable { ... } + extend impl forall [P: Printable] Array(P, N) as Printable { ... } } ``` @@ -4392,10 +4399,10 @@ Instead, the class can declare aliases to members of the interface. Those aliases will only be usable when the type implements the interface. ```carbon -class Array(T:! type, template N:! i64) { +class Array(T: type, template N: i64) { alias Print = Printable.Print; } -impl forall [P:! Printable] Array(P, N) as Printable { ... } +impl forall [P: Printable] Array(P, N) as Printable { ... } impl String as Printable { ... } var can_print: Array(String, 2) = ("Hello ", "world"); @@ -4417,10 +4424,10 @@ It is legal to declare or define a conditional impl lexically inside the class scope without `extend`, as in: ```carbon -class Array(T:! type, template N:! i64) { +class Array(T: type, template N: i64) { // ✅ Allowed: non-extending impl defined in class scope may // use `forall` and may specify a type. - impl forall [P:! Printable] Array(P, N) as Printable { ... } + impl forall [P: Printable] Array(P, N) as Printable { ... } } ``` @@ -4438,16 +4445,16 @@ example, the interface `Foo(T)` is only implemented when the two types are equal. ```carbon -interface Foo(T:! type) { ... } -class Pair(T:! type, U:! type) { ... } -impl forall [T:! type] Pair(T, T) as Foo(T) { ... } +interface Foo(T: type) { ... } +class Pair(T: type, U: type) { ... } +impl forall [T: type] Pair(T, T) as Foo(T) { ... } ``` As before, you may also define the `impl` inline, but it may not be combined with the `extend` keyword: ```carbon -class Pair(T:! type, U:! type) { +class Pair(T: type, U: type) { impl Pair(T, T) as Foo(T) { ... } } ``` @@ -4456,7 +4463,7 @@ class Pair(T:! type, U:! type) { as there is no overlap in the conditions: ```carbon -class X(T:! type) { +class X(T: type) { // ✅ Allowed: `X(T).F` consistently means `X(T).(Foo.F)` // even though that may have different definitions for // different values of `T`. @@ -4489,13 +4496,13 @@ than one root type, so the `impl` declaration will use a type variable for the `PartiallyOrdered`. ```carbon - impl forall [T:! Ordered] T as PartiallyOrdered { ... } + impl forall [T: Ordered] T as PartiallyOrdered { ... } ``` - `T` implements `CommonType(T)` for all `T` ```carbon - impl forall [T:! type] T as CommonType(T) + impl forall [T: type] T as CommonType(T) where .Result = T { } ``` @@ -4527,10 +4534,10 @@ add the `i32` to the `BigInt` value. ```carbon class BigInt { - impl forall [T:! ImplicitAs(i32)] as AddTo(T) { ... } + impl forall [T: ImplicitAs(i32)] as AddTo(T) { ... } } // Or out-of-line: -impl forall [T:! ImplicitAs(i32)] BigInt as AddTo(T) { ... } +impl forall [T: ImplicitAs(i32)] BigInt as AddTo(T) { ... } ``` Wildcard impl declarations may never be declared using [`extend`](#extend-impl), @@ -4543,7 +4550,7 @@ example, if `T` implements `As(U)`, then this implements `As(Optional(U))` for `Optional(T)`: ```carbon -impl forall [U:! type, T:! As(U)] +impl forall [U: type, T: As(U)] Optional(T) as As(Optional(U)) { ... } ``` @@ -4575,7 +4582,7 @@ parameters and replacing type parameters by a `?`. The type structure of this declaration: ```carbon -impl forall [T:! ..., U:! ...] Foo(T, i32) as Bar(String, U) { ... } +impl forall [T: ..., U: ...] Foo(T, i32) as Bar(String, U) { ... } ``` is: @@ -4632,10 +4639,10 @@ enclosing generic. ```carbon interface Z {} -interface Y(T:! type) {} +interface Y(T: type) {} class A {} -fn F(T:! type) { +fn F(generic T: type) { class B { class C {} } // Accepted; anchored by the name `B`. @@ -4798,8 +4805,8 @@ prioritization block that matches is selected. > ```carbon > match_first { > // If T is Foo prioritized ahead of T is Bar -> impl forall [T:! Foo] T as Bar { ... } -> impl forall [T:! Baz] T as Bar { ... } +> impl forall [T: Foo] T as Bar { ... } +> impl forall [T: Baz] T as Bar { ... } > } > ``` @@ -4857,15 +4864,15 @@ erase too much information when considering this graph, that these `impl` declarations are not considered to form cycles with themselves: ```carbon -impl forall [T:! Printable] Optional(T) as Printable; -impl forall [T:! type, U:! ComparableTo(T)] U as ComparableTo(Optional(T)); +impl forall [T: Printable] Optional(T) as Printable; +impl forall [T: type, U: ComparableTo(T)] U as ComparableTo(Optional(T)); ``` **Example:** If `T` implements `ComparableWith(U)`, then `U` should implement `ComparableWith(T)`. ```carbon -impl forall [U:! type, T:! ComparableWith(U)] +impl forall [U: type, T: ComparableWith(U)] U as ComparableWith(T); ``` @@ -4881,11 +4888,11 @@ class Y {} class N {} interface True {} impl Y as True {} -interface Z(T:! type) { let Cond:! type; } +interface Z(T: type) { let Cond: type; } match_first { - impl forall [T:! type, U:! Z(T) where .Cond impls True] T as Z(U) + impl forall [T: type, U: Z(T) where .Cond impls True] T as Z(U) where .Cond = N { } - impl forall [T:! type, U:! type] T as Z(U) + impl forall [T: type, U: type] T as Z(U) where .Cond = Y { } } ``` @@ -4910,13 +4917,13 @@ There is no reason to prefer one of these outcomes over the other. class A {} class B {} class C {} -interface D(T:! type) { let Cond:! type; } +interface D(T: type) { let Cond: type; } match_first { - impl forall [T:! type, U:! D(T) where .Cond = B] T as D(U) + impl forall [T: type, U: D(T) where .Cond = B] T as D(U) where .Cond = C { } - impl forall [T:! type, U:! D(T) where .Cond = A] T as D(U) + impl forall [T: type, U: D(T) where .Cond = A] T as D(U) where .Cond = B { } - impl forall [T:! type, U:! type] T as D(U) + impl forall [T: type, U: type] T as D(U) where .Cond = A { } } ``` @@ -4969,7 +4976,7 @@ forever. be the result of a single impl: ```carbon -impl forall [A:! type where Optional(.Self) impls B] A as B { ... } +impl forall [A: type where Optional(.Self) impls B] A as B { ... } ``` This problem can also result from a chain of `impl` declarations, as in @@ -5009,7 +5016,7 @@ can't repeat exactly, Consider the example from before, ```carbon -impl forall [A:! type where Optional(.Self) impls B] A as B; +impl forall [A: type where Optional(.Self) impls B] A as B; ``` This `impl` declaration matches the query `i32 impls B` as long as @@ -5026,15 +5033,15 @@ considered since there is a more specialized `impl` declaration that is preferred by the [type-structure overlap rule](#overlap-rule), as in: ``` -impl forall [A:! type where Optional(.Self) impls B] A as B; +impl forall [A: type where Optional(.Self) impls B] A as B; impl Optional(bool) as B; // OK, because we never consider the first `impl` // declaration when looking for `Optional(bool) impls I`. -let U:! B = bool; +let generic U: B = bool; // Error: cycle with `i32 impls B` depending on // `Optional(i32) impls B`, using the same `impl` // declaration, as before. -let V:! B = i32; +let generic V: B = i32; ``` > **Note:** @@ -5114,25 +5121,25 @@ call to a generic function, such as using an operator: ```carbon // Interface defining the behavior of the prefix-* operator interface Deref { - let Result:! type; + let Result: type; fn Op(self) -> Result; } // Types implementing `Deref` -class Ptr(T:! type) { +class Ptr(T: type) { ... impl as Deref where .Result = T { fn Op(self) -> Result { ... } } } -class Optional(T:! type) { +class Optional(T: type) { ... impl as Deref where .Result = T { fn Op(self) -> Result { ... } } } -fn F[T:! type](x: T) { +fn F[T: type](x: T) { // uses Ptr(T) and Optional(T) in implementation } ``` @@ -5144,7 +5151,7 @@ practice have to add a constraint, which is both verbose and exposes what should be implementation details: ```carbon -fn F[T:! type where Optional(T).(Deref.Result) == .Self +fn F[T: type where Optional(T).(Deref.Result) == .Self and Ptr(T).(Deref.Result) == .Self](x: T) { // uses Ptr(T) and Optional(T) in implementation } @@ -5154,14 +5161,14 @@ To mark an impl as not able to be specialized, prefix it with the keyword `final`: ```carbon -class Ptr(T:! type) { +class Ptr(T: type) { ... // Note: added `final` final impl as Deref where .Result = T { fn Op(self) -> Result { ... } } } -class Optional(T:! type) { +class Optional(T: type) { ... // Note: added `final` final impl as Deref where .Result = T { @@ -5184,11 +5191,11 @@ computed between two non-`template` `impl` declaration by corresponding parts. For example, the intersection of these two declarations ```carbon -final impl forall [T:! type] +final impl forall [T: type] T as CommonTypeWith(T) where .Result = T {} -impl forall [V:! type, U:! CommonTypeWith(V)] +impl forall [V: type, U: CommonTypeWith(V)] Vec(U) as CommonTypeWith(Vec(V)) where .Result = Vec(U.Result) {} ``` @@ -5206,7 +5213,7 @@ specialized so it can use the assignments of the associated constants in that impl definition. ```carbon -fn F[T:! type](x: T) { +fn F[T: type](x: T) { var p: Ptr(T) = ...; // *p has type `T` var o: Optional(T) = ...; @@ -5372,7 +5379,7 @@ An interface or named constraint may be forward declared subject to these rules: If `C` is the name of an incomplete interface or named constraint, then it can be used in the following contexts: -- ✅ `T:! C` +- ✅ `T: C` where `T` is a checked binding. - ✅ `C & D` - There may be conflicts between `C` and `D` making this invalid that will only be discovered once they are both complete. @@ -5380,25 +5387,25 @@ be used in the following contexts: `constraint `...` { require` ... `impls C; }` - Nothing implied by implementing `C` will be visible until `C` is complete. -- ✅ `T:! C` ... `T impls C` -- ✅ `T:! A & C` ... `T impls C` +- ✅ `T: C` ... `T impls C` where `T` is a checked binding. +- ✅ `T: A & C` ... `T impls C` where `T` is a checked binding. - This includes constructs requiring `T impls C` such as `T as C` or - `U:! C = T`. + `U: C = T`. - ✅ `impl `...` as C;` - Checking that all associated constants of `C` are correctly assigned values will be delayed until `C` is complete. An incomplete `C` cannot be used in the following contexts: -- ❌ `T:! C` ... `T.X` -- ❌ `T:! C where `... +- ❌ `T: C` ... `T.X` where `T` is a checked binding. +- ❌ `T: C where `... where `T` is a checked binding. - ❌ `class `...` { extend impl as C; }` - ❌ `interface `...` { extend require impls C; }` or `constraint `...` { extend require impls C; }` - An `extend` declaration requires the target scope to be complete. See [`extend` in member access](../expressions/member_access.md#extend). -- ❌ `T:! C` ... `T impls A` where `A` is an interface or named constraint - different from `C` +- ❌ `T: C` ... `T impls A` where `T` is a checked binding, and `A` is an + interface or named constraint different from `C` - Need to see the definition of `C` to see if it implies `A`. - ❌ `impl` ... `as C {` ... `}` @@ -5496,8 +5503,8 @@ expressions match along with scope, this should match the type name and [optional parameter expression](#parameterized-types) after `class`. So in `class MyClass { ... }`, `Self` is rewritten to `MyClass`. In - `class Vector(T:! Movable) { ... }`, `Self` is rewritten to - `forall [T:! Movable] Vector(T)`. + `class Vector(T: Movable) { ... }`, `Self` is rewritten to + `forall [T: Movable] Vector(T)`. - 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 @@ -5537,16 +5544,16 @@ class MyClass; // Definition of interfaces that were previously declared interface Interface1 { - let T1:! type; + let T1: type; } interface Interface2 { - let T2:! type; + let T2: type; } interface Interface3 { - let T3:! type; + let T3: type; } interface Interface4 { - let T4:! type; + let T4: type; } // Out-of-line forward declarations @@ -5556,10 +5563,10 @@ impl MyClass as Interface3 where .T3 = f32; impl MyClass as Interface4 where .T4 = String; interface Interface5 { - let T5:! type; + let T5: type; } interface Interface6 { - let T6:! type; + let T6: type; } // Definition of the previously declared class type @@ -5625,26 +5632,26 @@ interface Node; // Forward declare named constraints used in // interface definitions. -private constraint EdgeFor(N:! Node); -private constraint NodeFor(E:! Edge); +private constraint EdgeFor(N: Node); +private constraint NodeFor(E: Edge); // Define interfaces using named constraints. interface Edge { - let NodeT:! NodeFor(Self); + let NodeT: NodeFor(Self); fn Head(self) -> NodeT; } interface Node { - let EdgeT:! EdgeFor(Self); + let EdgeT: EdgeFor(Self); fn Edges(self) -> DynArray(EdgeT); } // 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) { +constraint EdgeFor(N: Node) { extend Edge where .NodeT = N; } -constraint NodeFor(E:! Edge) { +constraint NodeFor(E: Edge) { extend Node where .EdgeT = E; } ``` @@ -5660,12 +5667,12 @@ constraint NodeFor(E:! Edge) { > interface Node; > > interface Edge { -> let NodeT:! Node where .EdgeT = Self; +> let NodeT: Node where .EdgeT = Self; > fn Head(self) -> NodeT; > } > > interface Node { -> let EdgeT:! Movable & Edge where .NodeT = Self; +> let EdgeT: Movable & Edge where .NodeT = Self; > fn Edges(self) -> DynArray(EdgeT); > } > ``` @@ -5679,8 +5686,8 @@ instead include that requirement in the body of the interface. ```carbon // 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; +interface CommonType(T: type) { + let Result: type; // Instead add the requirement inside the definition. require T impls CommonType(Self); } @@ -5692,8 +5699,8 @@ constraints on members of `CommonType` are allowed, and that this [must involve `Self`](#interface-requiring-other-interfaces-revisited). ```carbon -interface CommonType(T:! type) { - let Result:! type; +interface CommonType(T: type) { + let Result: type; // ❌ Illegal: `CommonType` is incomplete require T impls CommonType(Self) where .Result == Result; } @@ -5704,16 +5711,16 @@ 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). ```carbon -private constraint CommonTypeResult(T:! type, R:! type); +private constraint CommonTypeResult(T: type, R: type); -interface CommonType(T:! type) { - let Result:! type; +interface CommonType(T: type) { + let Result: type; // ✅ Allowed: `CommonTypeResult` is incomplete, but // no members are accessed. require T impls CommonTypeResult(Self, Result); } -constraint CommonTypeResult(T:! type, R:! type) { +constraint CommonTypeResult(T: type, R: type) { extend CommonType(T) where .Result == R; } ``` @@ -5772,8 +5779,8 @@ Defaults may also be provided for associated constants, such as associated facets, and interface parameters, using the `= ` syntax. ```carbon -interface Add(Right:! type = Self) { - default let Result:! type = Self; +interface Add(Right: type = Self) { + default let Result: type = Self; fn DoAdd(self, right: Right) -> Result; } @@ -5802,8 +5809,8 @@ More generally, default expressions may reference other associated constants or ```carbon interface Iterator { - let Element:! type; - default let Pointer:! type = Element*; + let Element: type; + default let Pointer: type = Element*; } ``` @@ -5836,7 +5843,7 @@ interface TotalOrder { // Any type that implements `TotalOrder` also has at // least this implementation of `PartialOrder`: -impl forall [T:! TotalOrder] T as PartialOrder { +impl forall [T: TotalOrder] T as PartialOrder { fn PartialLess(self, right: Self) -> bool { return self.TotalLess(right); } @@ -5876,11 +5883,11 @@ class String { } } -interface Add(T:! type = Self) { +interface Add(T: type = Self) { // `AddWith` *always* equals `T` - final let AddWith:! type = T; + final let AddWith: type = T; // Has a *default* of `Self` - default let Result:! type = Self; + default let Result: type = Self; fn DoAdd(self, right: AddWith) -> Result; } ``` @@ -5939,7 +5946,7 @@ says that if `Self` implements `IntLike`, then `i32` must implement `As(Self)`. Similarly, ```carbon -interface CommonTypeWith(T:! type) { +interface CommonTypeWith(T: type) { require T impls CommonTypeWith(Self); // ... } @@ -5987,7 +5994,7 @@ definition can be broader instead of being required to match exactly. // impl of `Equatable` for `Vector(i32)` in this file. impl Vector(i32) as Iterable { ... } -fn RequiresEquatable[T:! Equatable](x: T) { ... } +fn RequiresEquatable[T: Equatable](x: T) { ... } fn ProcessVector(v: Vector(i32)) { // ✅ Allowed since `Vector(i32)` is known to // implement `Equatable`. @@ -5996,14 +6003,14 @@ fn ProcessVector(v: Vector(i32)) { // Satisfies the requirement that `Vector(i32)` must // implement `Equatable` since `i32 impls Equatable`. -impl forall [T:! Equatable] Vector(T) as Equatable { ... } +impl forall [T: Equatable] Vector(T) as Equatable { ... } ``` In some cases, the interface's requirement can be trivially satisfied by the implementation itself, as in: ```carbon -impl forall [T:! type] T as CommonTypeWith(T) { ... } +impl forall [T: type] T as CommonTypeWith(T) { ... } ``` Here is an example where the requirement of interface `Iterable` that the type @@ -6011,11 +6018,11 @@ implements interface `Equatable` is satisfied by a constraint in the `impl` declaration: ```carbon -class Foo(T:! type) {} +class Foo(T: type) {} // This is allowed because we know that an `impl Foo(T) as Equatable` // will exist for all types `T` for which this impl is used, even // though there's neither an imported impl nor an impl in this file. -impl forall [T:! type where Foo(T) impls Equatable] +impl forall [T: type where Foo(T) impls Equatable] Foo(T) as Iterable {} ``` @@ -6036,10 +6043,10 @@ satisfy. Consider an interface `B` that has a requirement that interface `A` is also implemented. ```carbon -interface A(T:! type) { - let Result:! type; +interface A(T: type) { + let Result: type; } -interface B(T:! type) { +interface B(T: type) { require impls A(T) where .Result == i32; } ``` @@ -6081,9 +6088,9 @@ interface B { require impls A; } interface C { require impls B; } interface D { require impls C; } -fn RequiresA[T:! A](x: T); -fn RequiresC[T:! C](x: T); -fn RequiresD[T:! D](x: T) { +fn RequiresA[T: A](x: T); +fn RequiresC[T: C](x: T); +fn RequiresD[T: D](x: T) { // ✅ Allowed: `D` directly requires `C` to be implemented. RequiresC(x); @@ -6124,14 +6131,14 @@ interface B { } interface C { } interface D { } -impl forall [T:! A] T as B { } -impl forall [T:! B] T as C { } -impl forall [T:! C] T as D { } +impl forall [T: A] T as B { } +impl forall [T: B] T as C { } +impl forall [T: C] T as D { } -fn RequiresD[T:! D](x: T); -fn RequiresB[T:! B](x: T); +fn RequiresD[T: D](x: T); +fn RequiresB[T: B](x: T); -fn RequiresA[T:! A](x: T) { +fn RequiresA[T: A](x: T) { // ✅ Allowed: There is a blanket implementation // of `B` for types implementing `A`. RequiresB(x); @@ -6169,7 +6176,7 @@ interface I { fn F(); } -fn G(T:! I, U:! type where .Self == T) { +fn G(generic T: I, generic U: type where .Self == T) { // ❌ Illegal: No implementation of `I` for `U`. U.(I.F)(); @@ -6196,7 +6203,7 @@ to overload the unary `-` operator: ```carbon // Unary `-`. interface Negate { - default let Result:! type = Self; + default let Result: type = Self; fn Op(self) -> Result; } ``` @@ -6219,7 +6226,7 @@ expression, implement the [`As` interface](/docs/design/expressions/as_expressions.md#extensibility): ```carbon -interface As(Dest:! type) { +interface As(Dest: type) { fn Convert(self) -> Dest; } ``` @@ -6234,8 +6241,8 @@ _type_ of the right-hand operand instead of its _value_. Consider ```carbon // 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; } ``` @@ -6258,12 +6265,12 @@ standard library will provide [adapters](#adapting-types) for defining the second implementation from the first, as in: ```carbon -interface OrderedWith(U:! type) { +interface OrderedWith(U: type) { fn Compare(self, u: U) -> Ordering; // ... } -class ReverseComparison(T:! type, U:! OrderedWith(T)) { +class ReverseComparison(T: type, U: OrderedWith(T)) { adapt T; extend impl as OrderedWith(U) { fn Compare(self, u: U) -> Ordering { @@ -6300,16 +6307,16 @@ impl EvenInt as IntLike; impl EvenInt as OrderedWith(EvenInt); // Allow `EvenInt` to be compared with anything that // implements `IntLike`, in either order. -impl forall [T:! IntLike] EvenInt as OrderedWith(T); -impl forall [T:! IntLike] T as OrderedWith(EvenInt); +impl forall [T: IntLike] EvenInt as OrderedWith(T); +impl forall [T: IntLike] T as OrderedWith(EvenInt); class PositiveInt { ... } impl PositiveInt as IntLike; impl PositiveInt as OrderedWith(PositiveInt); // Allow `PositiveInt` to be compared with anything that // implements `IntLike`, in either order. -impl forall [T:! IntLike] PositiveInt as OrderedWith(T); -impl forall [T:! IntLike] T as OrderedWith(PositiveInt); +impl forall [T: IntLike] PositiveInt as OrderedWith(T); +impl forall [T: IntLike] T as OrderedWith(PositiveInt); ``` Then the compiler will favor selecting the implementation based on the type of @@ -6365,7 +6372,7 @@ conversion. The implementation is for types that implement the ```carbon // "Implementation Two" -impl forall [T:! ImplicitAs(f64)] +impl forall [T: ImplicitAs(f64)] Meters as MulWith(T) where .Result = Meters { fn Op(self, other: T) -> Result { // Carbon will implicitly convert `other` from type @@ -6436,7 +6443,7 @@ impl like Meters as MulWith(like f64) is equivalent to "implementation one", "implementation two", and: ```carbon -impl forall [T:! ImplicitAs(Meters)] +impl forall [T: ImplicitAs(Meters)] T as MulWith(f64) where .Result = Meters { fn Op(self, other: f64) -> Result { // Will implicitly convert `self` to `Meters` in @@ -6463,13 +6470,13 @@ is equivalent to: impl Meters as MulWith(f64) where .Result = Meters; // First `like` replaced with a wildcard. -impl forall [T:! ImplicitAs(Meters)] +impl forall [T: ImplicitAs(Meters)] T as MulWith(f64) where .Result = Meters; // Second `like` replaced with a wildcard. Same as the // declaration part of "implementation two", without the // body of the definition. -impl forall [T:! ImplicitAs(f64)] +impl forall [T: ImplicitAs(f64)] Meters as MulWith(T) where .Result = Meters; ``` @@ -6491,8 +6498,8 @@ Which will generate implementations with declarations: ```carbon impl Vector(String) as Printable; -impl forall [T:! ImplicitAs(Vector(String))] T as Printable; -impl forall [T:! ImplicitAs(String)] Vector(T) as Printable; +impl forall [T: ImplicitAs(Vector(String))] T as Printable; +impl forall [T: ImplicitAs(String)] Vector(T) as Printable; ``` The generated implementations must be legal or the `like` is illegal. For @@ -6505,7 +6512,7 @@ use of `like` is illegal: ```carbon // ❌ Illegal: Can't convert a value with type -// `Vector(T:! ImplicitAs(String))` +// `Vector(T: ImplicitAs(String))` // to `Vector(String)` for `self` // parameter of `Printable.Print`. impl Vector(like String) as Printable; @@ -6523,11 +6530,11 @@ parameters must be able to be determined due to being repeated outside of the impl like Meters as Printable; // ❌ Illegal: No other way to determine `T` -impl forall [T:! IntLike] like T as Printable; +impl forall [T: IntLike] like T as Printable; // ❌ Illegal: `T` being used in a `where` clause // is insufficient. -impl forall [T:! IntLike] like T +impl forall [T: IntLike] like T as MulWith(i64) where .Result = T; // ❌ Illegal: `like` can't be used in a `where` @@ -6537,14 +6544,14 @@ impl Meters as MulWith(f64) // ✅ Allowed: `T` can be determined by another // part of the query. -impl forall [T:! IntLike] like T +impl forall [T: IntLike] like T as MulWith(T) where .Result = T; -impl forall [T:! IntLike] T +impl forall [T: IntLike] T as MulWith(like T) where .Result = T; // ✅ Allowed: Only one `like` used at a time, so this // is equivalent to the above two examples. -impl forall [T:! IntLike] like T +impl forall [T: IntLike] like T as MulWith(like T) where .Result = T; ``` @@ -6558,8 +6565,8 @@ of its elements: ```carbon class HashMap( - KeyT:! Hashable & Eq & Movable, - ValueT:! Movable) { + KeyT: Hashable & Eq & Movable, + ValueT: Movable) { // `Self` is `HashMap(KeyT, ValueT)`. // Class parameters may be used in function signatures. @@ -6574,9 +6581,9 @@ class HashMap( } ``` -Note that, unlike functions, every parameter to a type must be a compile-time -binding, either symbolic using `:!` or template using `template`...`:!`, not -runtime, with a plain `:`. +Note that parameters to a type are treated as checked generic parameters by +default. They can be marked as template parameters with the `template` modifier, +but the `runtime` modifier is not permitted. Two types are the same if they have the same name and the same arguments, after applying aliases and [rewrite constraints](#rewrite-constraints). Carbon's @@ -6590,7 +6597,7 @@ Unlike an [interface's parameters](#parameterized-interfaces), a type's parameters may be [deduced](terminology.md#deduced-parameter), as in: ```carbon -fn ContainsKey[KeyT:! Movable, ValueT:! Movable] +fn ContainsKey[KeyT: Movable, ValueT: Movable] (haystack: HashMap(KeyT, ValueT), needle: KeyT) -> bool { ... } fn MyMapContains(s: String) { @@ -6620,8 +6627,8 @@ example, this `Set(T)` type may be compared to anything implementing the `Container` interface as long as the element types match: ```carbon -class Set(T:! Ordered) { - fn Less[U:! Container with .ElementType = T](self, u: U) -> bool; +class Set(T: Ordered) { + fn Less[U: Container with .ElementType = T](self, u: U) -> bool; // ... } ``` @@ -6637,9 +6644,9 @@ how to define a dynamically sized array type that only has a `Sort` method if its elements implement the `Ordered` interface: ```carbon -class DynArray(T:! type) { +class DynArray(T: type) { // `DynArray(T)` has a `Sort()` method if `T impls Ordered`. - fn Sort[C:! Ordered](ref self: DynArray(C)); + fn Sort[C: Ordered](ref self: DynArray(C)); } ``` @@ -6673,7 +6680,7 @@ storage of `Optional(T)` for type `T`," written here as `OptionalStorage`: ```carbon interface OptionalStorage { - let Storage:! type; + let Storage: type; fn MakeNone() -> Storage; fn Make(x: Self) -> Storage; fn IsNone(x: Storage) -> bool; @@ -6686,7 +6693,7 @@ The default implementation of this interface is provided by a ```carbon // Default blanket implementation -impl forall [T:! Movable] T as OptionalStorage +impl forall [T: Movable] T as OptionalStorage where .Storage = (bool, T) { ... } @@ -6698,7 +6705,7 @@ patterns: ```carbon // Specialization for pointers, using nullptr == None -final impl forall [T:! type] T* as OptionalStorage +final impl forall [T: type] T* as OptionalStorage where .Storage = Array(Byte, sizeof(T*)) { ... } @@ -6714,7 +6721,7 @@ the interface is not marked `private`. Then the implementation of `Optional(T)` can delegate to `OptionalStorage` for anything that can vary with `T`: ```carbon -class Optional(T:! Movable) { +class Optional(T: Movable) { fn None() -> Self { return {.storage = T.(OptionalStorage.MakeNone)()}; } @@ -6735,8 +6742,8 @@ argument type implements `OptionalStorage`: ```carbon // ✅ Allowed: `T` just needs to be `Movable` to form `Optional(T)`. -// A `T:! OptionalStorage` constraint is not required. -fn First[T:! Movable & Eq](v: Vector(T)) -> Optional(T); +// A `T: OptionalStorage` constraint is not required. +fn First[T: Movable & Eq](v: Vector(T)) -> Optional(T); ``` Adding `OptionalStorage` to the constraints on the parameter to `Optional` would @@ -6748,8 +6755,8 @@ definition of `Optional`, since it has no name conflicts with the members of `Movable`: ```carbon -class Optional(T:! Movable) { - private let U:! Movable & OptionalStorage = T; +class Optional(T: Movable) { + private let U: Movable & OptionalStorage = T; fn None() -> Self { return {.storage = U.MakeNone()}; } diff --git a/docs/design/generics/goals.md b/docs/design/generics/goals.md index 3f78e47d89c4..ceee9ce1e8b3 100644 --- a/docs/design/generics/goals.md +++ b/docs/design/generics/goals.md @@ -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); diff --git a/docs/design/generics/overview.md b/docs/design/generics/overview.md index 099edf289aa6..5716bb97292e 100644 --- a/docs/design/generics/overview.md +++ b/docs/design/generics/overview.md @@ -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 { ... } } ``` diff --git a/docs/design/generics/terminology.md b/docs/design/generics/terminology.md index 6a158a9c0f05..0325b5ea06aa 100644 --- a/docs/design/generics/terminology.md +++ b/docs/design/generics/terminology.md @@ -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 diff --git a/docs/design/lexical_conventions/symbolic_tokens.md b/docs/design/lexical_conventions/symbolic_tokens.md index eea088b08a0f..89f72284f15a 100644 --- a/docs/design/lexical_conventions/symbolic_tokens.md +++ b/docs/design/lexical_conventions/symbolic_tokens.md @@ -96,7 +96,6 @@ source file: | `,` | Separate tuple and struct elements | | `.` | Member access | | `:` | Name binding patterns | -| `:!` | Compile-time binding patterns | | `;` | Statement separator | ## Alternatives considered diff --git a/docs/design/lexical_conventions/words.md b/docs/design/lexical_conventions/words.md index aebf4b98dd60..02b135f97123 100644 --- a/docs/design/lexical_conventions/words.md +++ b/docs/design/lexical_conventions/words.md @@ -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` diff --git a/docs/design/pattern_matching.md b/docs/design/pattern_matching.md index 11c26210a84b..8181ac8bfe1f 100644 --- a/docs/design/pattern_matching.md +++ b/docs/design/pattern_matching.md @@ -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) } diff --git a/docs/design/sum_types.md b/docs/design/sum_types.md index 92f07e2bc9ac..e8d2de0f7299 100644 --- a/docs/design/sum_types.md +++ b/docs/design/sum_types.md @@ -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 { diff --git a/docs/design/templates.md b/docs/design/templates.md index b2f7f700b6f6..7e6f1918f0fd 100644 --- a/docs/design/templates.md +++ b/docs/design/templates.md @@ -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; } diff --git a/docs/design/tuples.md b/docs/design/tuples.md index d36f331947a4..5c67300226d8 100644 --- a/docs/design/tuples.md +++ b/docs/design/tuples.md @@ -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); } ``` diff --git a/docs/design/values.md b/docs/design/values.md index 20eb62855bbd..9eda5584a578 100644 --- a/docs/design/values.md +++ b/docs/design/values.md @@ -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; } ``` diff --git a/docs/design/variadics.md b/docs/design/variadics.md index ee9b1e4662d5..25cf9abe8077 100644 --- a/docs/design/variadics.md +++ b/docs/design/variadics.md @@ -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); ``` diff --git a/docs/images/snippets.md b/docs/images/snippets.md index d49b00d93a0d..774ad9cf6140 100644 --- a/docs/images/snippets.md +++ b/docs/images/snippets.md @@ -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; }