diff --git a/docs/design/assignment.md b/docs/design/assignment.md index 6171a47479c9e..309cd24709af7 100644 --- a/docs/design/assignment.md +++ b/docs/design/assignment.md @@ -173,73 +173,121 @@ provided for built-in types as necessary to give the semantics described above. ### Simple assignment ``` +package Core; + // Simple `=`. -interface AssignWith(U:! type) { - fn Op[addr self: Self*](other: U); +interface AssignWithPrimitive + (implicit_into U:! NoRefForm) { + fn Op[ref self: Self](other:? U); +} +constraint AssignWith(U:! type) { + extend require impls + AssignWithPrimitive(form(val U)); +} +constraint Assign { + extend require impls AssignWith(Self); } -constraint Assign { extend AssignWith(Self); } ``` -Given `var x: T` and `y: U`: - -- The statement `x = y;` is rewritten to `x.(AssignWith(U).Op)(y);`. +The statement `x = y;` is rewritten to +`x.(AssignWithPrimitive(formof(y)).Op)(y);`. ### Arithmetic ``` // Compound `+=`. -interface AddAssignWith(U:! type) { - fn Op[addr self: Self*](other: U); +interface AddAssignWithPrimitive + (implicit_into U:! NoRefForm) { + fn Op[ref self: Self](other:? U); +} +constraint AddAssignWith(U:! type) { + extend require impls + AddAssignWithPrimitive(form(val U)); +} +constraint AddAssign { + extend require impls AddAssignWith(Self); } -constraint AddAssign { extend AddAssignWith(Self); } ``` ``` // Compound `-=`. -interface SubAssignWith(U:! type) { - fn Op[addr self: Self*](other: U); +interface SubAssignWithPrimitive + (implicit_into U:! NoRefForm) { + fn Op[ref self: Self](other:? U); +} +constraint SubAssignWith(U:! type) { + extend require impls + SubAssignWithPrimitive(form(val U)); +} +constraint SubAssign { + extend require impls SubAssignWith(Self); } -constraint SubAssign { extend SubAssignWith(Self); } ``` ``` // Compound `*=`. -interface MulAssignWith(U:! type) { - fn Op[addr self: Self*](other: U); +interface MulAssignWithPrimitive + (implicit_into U:! NoRefForm) { + fn Op[ref self: Self](other:? U); +} +constraint MulAssignWith(U:! type) { + extend require impls + MulAssignWithPrimitive(form(val U)); +} +constraint MulAssign { + extend require impls MulAssignWith(Self); } -constraint MulAssign { extend MulAssignWith(Self); } ``` ``` // Compound `/=`. -interface DivAssignWith(U:! type) { - fn Op[addr self: Self*](other: U); +interface DivAssignWithPrimitive + (implicit_into U:! NoRefForm) { + fn Op[ref self: Self](other:? U); +} +constraint DivAssignWith(U:! type) { + extend require impls + DivAssignWithPrimitive(form(val U)); +} +constraint DivAssign { + extend require impls DivAssignWith(Self); } -constraint DivAssign { extend DivAssignWith(Self); } ``` ``` // Compound `%=`. -interface ModAssignWith(U:! type) { - fn Op[addr self: Self*](other: U); +interface ModAssignWithPrimitive + (implicit_into U:! NoRefForm) { + fn Op[ref self: Self](other:? U); +} +constraint ModAssignWith(U:! type) { + extend require impls + ModAssignWithPrimitive(form(val U)); +} +constraint ModAssign { + extend require impls ModAssignWith(Self); } -constraint ModAssign { extend ModAssignWith(Self); } ``` ``` // Increment `++`. -interface Inc { fn Op[addr self: Self*](); } +interface Inc { fn Op[ref self: Self](); } // Decrement `++`. -interface Dec { fn Op[addr self: Self*](); } +interface Dec { fn Op[ref self: Self](); } ``` -Given `var x: T` and `y: U`: +These assignment statements are rewritten as follows: -- The statement `x += y;` is rewritten to `x.(AddAssignWith(U).Op)(y);`. -- The statement `x -= y;` is rewritten to `x.(SubAssignWith(U).Op)(y);`. -- The statement `x *= y;` is rewritten to `x.(MulAssignWith(U).Op)(y);`. -- The statement `x /= y;` is rewritten to `x.(DivAssignWith(U).Op)(y);`. -- The statement `x %= y;` is rewritten to `x.(ModAssignWith(U).Op)(y);`. +- The statement `x += y;` is rewritten to + `x.(AddAssignWithPrimitive(formof(y)).Op)(y);`. +- The statement `x -= y;` is rewritten to + `x.(SubAssignWithPrimitive(formof(y)).Op)(y);`. +- The statement `x *= y;` is rewritten to + `x.(MulAssignWithPrimitive(formof(y)).Op)(y);`. +- The statement `x /= y;` is rewritten to + `x.(DivAssignWithPrimitive(formof(y)).Op)(y);`. +- The statement `x %= y;` is rewritten to + `x.(ModAssignWithPrimitive(formof(y)).Op)(y);`. - The statement `++x;` is rewritten to `x.(Inc.Op)();`. - The statement `--x;` is rewritten to `x.(Dec.Op)();`. @@ -247,53 +295,92 @@ Given `var x: T` and `y: U`: ``` // Compound `&=`. -interface BitAndAssignWith(U:! type) { - fn Op[addr self: Self*](other: U); +interface BitAndAssignWithPrimitive + (implicit_into U:! NoRefForm) { + fn Op[ref self: Self](other:? U); +} +constraint BitAndAssignWith(U:! type) { + extend require impls + BitAndAssignWithPrimitive(form(val U)); +} +constraint BitAndAssign { + extend require impls BitAndAssignWith(Self); } -constraint BitAndAssign { extend BitAndAssignWith(Self); } ``` ``` // Compound `|=`. -interface BitOrAssignWith(U:! type) { - fn Op[addr self: Self*](other: U); +interface BitOrAssignWithPrimitive + (implicit_into U:! NoRefForm) { + fn Op[ref self: Self](other:? U); +} +constraint BitOrAssignWith(U:! type) { + extend require impls + BitOrAssignWithPrimitive(form(val U)); +} +constraint BitOrAssign { + extend require impls BitOrAssignWith(Self); } -constraint BitOrAssign { extend BitOrAssignWith(Self); } ``` ``` // Compound `^=`. -interface BitXorAssignWith(U:! type) { - fn Op[addr self: Self*](other: U); +interface BitXorAssignWithPrimitive + (implicit_into U:! NoRefForm) { + fn Op[ref self: Self](other:? U); +} +constraint BitXorAssignWith(U:! type) { + extend require impls + BitXorAssignWithPrimitive(form(val U)); +} +constraint BitXorAssign { + extend require impls BitXorAssignWith(Self); } -constraint BitXorAssign { extend BitXorAssignWith(Self); } ``` ``` // Compound `<<=`. -interface LeftShiftAssignWith(U:! type) { - fn Op[addr self: Self*](other: U); +interface LeftShiftAssignWithPrimitive + (implicit_into U:! NoRefForm) { + fn Op[ref self: Self](other:? U); +} +constraint LeftShiftAssignWith(U:! type) { + extend require impls + LeftShiftAssignWithPrimitive(form(val U)); +} +constraint LeftShiftAssign { + extend require impls LeftShiftAssignWith(Self); } -constraint LeftShiftAssign { extend LeftShiftAssignWith(Self); } ``` ``` // Compound `>>=`. -interface RightShiftAssignWith(U:! type) { - fn Op[addr self: Self*](other: U); +interface RightShiftAssignWithPrimitive + (implicit_into U:! NoRefForm) { + fn Op[ref self: Self](other:? U); +} +constraint RightShiftAssignWith(U:! type) { + extend require impls + RightShiftAssignWithPrimitive(form(val U)); +} +constraint RightShiftAssign { + extend require impls + RightShiftAssignWith(Self); } -constraint RightShiftAssign { extend RightShiftAssignWith(Self); } ``` -Given `var x: T` and `y: U`: +These assignment statements are rewritten as follows: -- The statement `x &= y;` is rewritten to `x.(BitAndAssignWith(U).Op)(y);`. -- The statement `x |= y;` is rewritten to `x.(BitOrAssignWith(U).Op)(y);`. -- The statement `x ^= y;` is rewritten to `x.(BitXorAssignWith(U).Op)(y);`. +- The statement `x &= y;` is rewritten to + `x.(BitAndAssignWithPrimitive(formof(y)).Op)(y);`. +- The statement `x |= y;` is rewritten to + `x.(BitOrAssignWithPrimitive(formof(y)).Op)(y);`. +- The statement `x ^= y;` is rewritten to + `x.(BitXorAssignWithPrimitive(formof(y)).Op)(y);`. - The statement `x <<= y;` is rewritten to - `x.(LeftShiftAssignWith(U).Op)(y);`. + `x.(LeftShiftAssignWithPrimitive(formof(y)).Op)(y);`. - The statement `x >>= y;` is rewritten to - `x.(RightShiftAssignWith(U).Op)(y)`;. + `x.(RightShiftAssignWithPrimitive(formof(y)).Op)(y)`;. Implementations of these interfaces are provided for built-in types as necessary to give the semantics described above. @@ -310,9 +397,9 @@ This defaulting is accomplished by a parameterized implementation of ``` impl forall [U:! type, T:! OpWith(U) where .Self impls AssignWith(.Self.Result)] T as OpAssignWith(U) { - fn Op[addr self: Self*](other: U) { + fn Op[ref self: Self](other: U) { // Here, `$` is the operator described by `OpWith`. - *self = *self $ other; + self = self $ other; } } ``` @@ -321,11 +408,11 @@ If a more efficient form of compound assignment is possible for a type, a more specific `impl` can be provided: ``` -impl like MyString as AddWith(like MyString) { +impl anchor MyString as AddWith(anchor MyString) { // Allocate new memory and perform addition. } -impl MyString as AddAssignWith(like MyString) { +impl MyString as AddAssignWith(MyString) { // Reuse existing storage where possible. } ``` @@ -355,3 +442,5 @@ impl MyString as AddAssignWith(like MyString) { [#1191: Bitwise and shift operators](https://github.com/carbon-language/carbon-lang/pull/1191) - Proposal [#2511: Assignment statements](https://github.com/carbon-language/carbon-lang/pull/2511) +- Proposal + [#5389: Generic across forms](https://github.com/carbon-language/carbon-lang/pull/5389) diff --git a/docs/design/expressions/arithmetic.md b/docs/design/expressions/arithmetic.md index 68290634f702a..721f84045bc98 100644 --- a/docs/design/expressions/arithmetic.md +++ b/docs/design/expressions/arithmetic.md @@ -191,18 +191,39 @@ Arithmetic operators can be provided for user-defined types by implementing the following family of interfaces: ``` +package Core; + // Unary `-`. -interface Negate { - default let Result:! type = Self; - fn Op[self: Self]() -> Result; +interface NegatePrimitive[implicit_into anchor Self:! NoRefForm] { + default let implicit_from ResultForm:! NoRefForm + = form(var Self.type); + fn Op[bound self:? Self]() + ->? ResultForm; + +} +constraint Negate { + let Result:! type; + extend require form(val Self) impls + NegatePrimitive + where .ResultForm = form(var Result); } ``` ``` // Binary `+`. -interface AddWith(U:! type) { - default let Result:! type = Self; - fn Op[self: Self](other: U) -> Result; +interface AddWithPrimitive + [implicit_into Self:! NoRefForm] + (implicit_into U:! NoRefForm) { + default let implicit_from ResultForm:! NoRefForm + = form(var Self.type); + fn Op[self:? Self](other:? U) + ->? ResultForm; +} +constraint AddWith(U:! type) { + let Result:! type; + extend require form(val Self) impls + AddWithPrimitive + where .ResultForm = form(var Result); } constraint Add { extend AddWith(Self) where .Result = Self; @@ -211,9 +232,19 @@ constraint Add { ``` // Binary `-`. -interface SubWith(U:! type) { - default let Result:! type = Self; - fn Op[self: Self](other: U) -> Result; +interface SubWithPrimitive + [implicit_into Self:! NoRefForm] + (implicit_into U:! NoRefForm) { + default let implicit_from ResultForm:! NoRefForm + = form(var Self.type); + fn Op[self:? Self](other:? U) + ->? ResultForm; +} +constraint SubWith(U:! type) { + let Result:! type; + extend require form(val Self) impls + SubWithPrimitive + where .ResultForm = form(var Result); } constraint Sub { extend SubWith(Self) where .Result = Self; @@ -222,9 +253,19 @@ constraint Sub { ``` // Binary `*`. -interface MulWith(U:! type) { - default let Result:! type = Self; - fn Op[self: Self](other: U) -> Result; +interface MulWithPrimitive + [implicit_into Self:! NoRefForm] + (implicit_into U:! NoRefForm) { + default let implicit_from ResultForm:! NoRefForm + = form(var Self.type); + fn Op[self:? Self](other:? U) + ->? ResultForm; +} +constraint MulWith(U:! type) { + let Result:! type; + extend require form(val Self) impls + MulWithPrimitive + where .ResultForm = form(var Result); } constraint Mul { extend MulWith(Self) where .Result = Self; @@ -233,9 +274,19 @@ constraint Mul { ``` // Binary `/`. -interface DivWith(U:! type) { - default let Result:! type = Self; - fn Op[self: Self](other: U) -> Result; +interface DivWithPrimitive + [implicit_into Self:! NoRefForm] + (implicit_into U:! NoRefForm) { + default let implicit_from ResultForm:! NoRefForm + = form(var Self.type); + fn Op[self:? Self](other:? U) + ->? ResultForm; +} +constraint DivWith(U:! type) { + let Result:! type; + extend require form(val Self) impls + DivWithPrimitive + where .ResultForm = form(var Result); } constraint Div { extend DivWith(Self) where .Result = Self; @@ -244,23 +295,38 @@ constraint Div { ``` // Binary `%`. -interface ModWith(U:! type) { - default let Result:! type = Self; - fn Op[self: Self](other: U) -> Result; +interface ModWithPrimitive + [implicit_into Self:! NoRefForm] + (implicit_into U:! NoRefForm) { + default let implicit_from ResultForm:! NoRefForm + = form(var Self.type); + fn Op[self:? Self](other:? U) + ->? ResultForm; +} +constraint ModWith(U:! type) { + let Result:! type; + extend require form(val Self) impls + ModWithPrimitive + where .ResultForm = form(var Result); } constraint Mod { extend ModWith(Self) where .Result = Self; } ``` -Given `x: T` and `y: U`: +These interfaces are used to rewrite uses of arithmetic operators: -- The expression `-x` is rewritten to `x.(Negate.Op)()`. -- The expression `x + y` is rewritten to `x.(AddWith(U).Op)(y)`. -- The expression `x - y` is rewritten to `x.(SubWith(U).Op)(y)`. -- The expression `x * y` is rewritten to `x.(MulWith(U).Op)(y)`. -- The expression `x / y` is rewritten to `x.(DivWith(U).Op)(y)`. -- The expression `x % y` is rewritten to `x.(ModWith(U).Op)(y)`. +- The expression `-x` is rewritten to `x.(NegatePrimitive.Op)()`. +- The expression `x + y` is rewritten to + `x.(AddWithPrimitive(formof(y)).Op)(y)`. +- The expression `x - y` is rewritten to + `x.(SubWithPrimitive(formof(y)).Op)(y)`. +- The expression `x * y` is rewritten to + `x.(MulWithPrimitive(formof(y)).Op)(y)`. +- The expression `x / y` is rewritten to + `x.(DivWithPrimitive(formof(y)).Op)(y)`. +- The expression `x % y` is rewritten to + `x.(ModWithPrimitive(formof(y)).Op)(y)`. Implementations of these interfaces are provided for built-in types as necessary to give the semantics described above. @@ -289,3 +355,5 @@ to give the semantics described above. [#1083: Arithmetic](https://github.com/carbon-language/carbon-lang/pull/1083) - Proposal [#1178: Rework operator interfaces](https://github.com/carbon-language/carbon-lang/pull/1178) +- Proposal + [#5389: Generic across forms](https://github.com/carbon-language/carbon-lang/pull/5389) diff --git a/docs/design/expressions/as_expressions.md b/docs/design/expressions/as_expressions.md index 432a95ca477c3..f0695fb94ec4d 100644 --- a/docs/design/expressions/as_expressions.md +++ b/docs/design/expressions/as_expressions.md @@ -154,6 +154,20 @@ The following conversion is supported by `as`: - `T` -> `U` if `T` is [compatible](../generics/terminology.md#compatible-types) with `U`. +This conversion preserves category. In this example, + +```carbon +class C {} +class A { + adapt C; +} + +var x: C = {}; +``` + +since `x` is a reference expression of type `C` and `A` is an adapter for `C`, +`x as A` is a reference expression as well. + **Future work:** We may need a mechanism to restrict which conversions between adapters are permitted and which code can perform them. Some of the conversions permitted by this rule may only be allowed in certain contexts. @@ -161,15 +175,32 @@ permitted by this rule may only be allowed in certain contexts. ## Extensibility Explicit casts can be defined for user-defined types such as -[classes](../classes.md) by implementing the `As` interface: - -``` -interface As(Dest:! type) { - fn Convert[self: Self]() -> Dest; +[classes](../classes.md) by implementing the `AsPrimitive` form interface or +`As` named constraint: + +```carbon +package Core; + +interface AsPrimitive[implicit_into Self:! Form] + (Dest:! type) { + // FIXME: Need to get the unqualified version + // of `Dest` without `const`/`partial` here. + let implicit_from ResultForm:! Form where .type = Dest; + fn Convert[bound self:? Self]() + ->? ResultForm; +} +constraint As(Dest:! type) { + extend require form(val Self) as + AsPrimitive(Dest) + where .ResultForm = form(var Dest); } ``` -The expression `x as U` is rewritten to `x.(As(U).Convert)()`. +The expression `x as U` is rewritten to `x.(AsPrimitive(U).Convert)()`. Observe +that the destination type is specified as an input parameter, but the resulting +form is specified as an associated constant by the `impl` (though it is required +to have a matching type). This allows +[conversion between compatible types](#compatible-types) to preserve category. **Note:** This rewrite causes the expression `U` to be implicitly converted to type `type`. The program is invalid if this conversion is not possible. @@ -187,3 +218,5 @@ type `type`. The program is invalid if this conversion is not possible. - [Implicit conversions in C++](https://en.cppreference.com/w/cpp/language/implicit_conversion) - Proposal [#845: `as` expressions](https://github.com/carbon-language/carbon-lang/pull/845). +- Proposal + [#5389: Generic across forms](https://github.com/carbon-language/carbon-lang/pull/5389) diff --git a/docs/design/expressions/bitwise.md b/docs/design/expressions/bitwise.md index 3fe19cf509dfc..4893581b84488 100644 --- a/docs/design/expressions/bitwise.md +++ b/docs/design/expressions/bitwise.md @@ -195,18 +195,38 @@ Bitwise and shift operators can be provided for user-defined types by implementing the following family of interfaces: ``` +package Core; + // Unary `^`. -interface BitComplement { - default let Result:! type = Self; +interface BitComplementPrimitive + [implicit_into anchor Self:! NoRefForm] { + default let implicit_from ResultForm:! NoRefForm + = form(var Self.type); fn Op[self: Self]() -> Result; } +constraint BitComplement { + let Result:! type; + extend require form(val Self) impls + BitComplementPrimitive + where .ResultForm = form(var Result); +} ``` ``` // Binary `&`. -interface BitAndWith(U:! type) { - default let Result:! type = Self; - fn Op[self: Self](other: U) -> Result; +interface BitAndWithPrimitive + [implicit_into Self:! NoRefForm] + (implicit_into U:! NoRefForm) { + default let implicit_from ResultForm:! NoRefForm + = form(var Self.type); + fn Op[self:? Self](other:? U) + ->? ResultForm; +} +constraint BitAndWith(U:! type) { + let Result:! type; + extend require form(val Self) impls + BitAndWithPrimitive + where .ResultForm = form(var Result); } constraint BitAnd { extend BitAndWith(Self) where .Result = Self; @@ -215,9 +235,19 @@ constraint BitAnd { ``` // Binary `|`. -interface BitOrWith(U:! type) { - default let Result:! type = Self; - fn Op[self: Self](other: U) -> Result; +interface BitOrWithPrimitive + [implicit_into Self:! NoRefForm] + (implicit_into U:! NoRefForm) { + default let implicit_from ResultForm:! NoRefForm + = form(var Self.type); + fn Op[self:? Self](other:? U) + ->? ResultForm; +} +constraint BitOrWith(U:! type) { + let Result:! type; + extend require form(val Self) impls + BitOrWithPrimitive + where .ResultForm = form(var Result); } constraint BitOr { extend BitOrWith(Self) where .Result = Self; @@ -226,20 +256,42 @@ constraint BitOr { ``` // Binary `^`. -interface BitXorWith(U:! type) { - default let Result:! type = Self; - fn Op[self: Self](other: U) -> Result; +interface BitXorWithPrimitive + [implicit_into Self:! NoRefForm] + (implicit_into U:! NoRefForm) { + default let implicit_from ResultForm:! NoRefForm + = form(var Self.type); + fn Op[self:? Self](other:? U) + ->? ResultForm; +} +constraint BitXorWith(U:! type) { + let Result:! type; + extend require form(val Self) impls + BitXorWithPrimitive + where .ResultForm = form(var Result); } constraint BitXor { extend BitXorWith(Self) where .Result = Self; } ``` +Note that the shift operators anchor on the type of the left argument. + ``` // Binary `<<`. -interface LeftShiftWith(U:! type) { - default let Result:! type = Self; - fn Op[self: Self](other: U) -> Result; +interface LeftShiftWithPrimitive + [implicit_into anchor Self:! NoRefForm] + (implicit_into U:! NoRefForm) { + default let implicit_from ResultForm:! NoRefForm + = form(var Self.type); + fn Op[self:? Self](other:? U) + ->? ResultForm; +} +constraint LeftShiftWith(U:! type) { + let Result:! type; + extend require form(val Self) impls + LeftShiftWithPrimitive + where .ResultForm = form(var Result); } constraint LeftShift { extend LeftShiftWith(Self) where .Result = Self; @@ -248,23 +300,38 @@ constraint LeftShift { ``` // Binary `>>`. -interface RightShiftWith(U:! type) { - default let Result:! type = Self; - fn Op[self: Self](other: U) -> Result; +interface RightShiftWithPrimitive + [implicit_into anchor Self:! NoRefForm] + (implicit_into U:! NoRefForm) { + default let implicit_from ResultForm:! NoRefForm + = form(var Self.type); + fn Op[self:? Self](other:? U) + ->? ResultForm; +} +constraint RightShiftWith(U:! type) { + let Result:! type; + extend require form(val Self) impls + RightShiftWithPrimitive + where .ResultForm = form(var Result); } constraint RightShift { extend RightShiftWith(Self) where .Result = Self; } ``` -Given `x: T` and `y: U`: +These interfaces are used to rewrite uses of the bitwise and shift operators: - The expression `^x` is rewritten to `x.(BitComplement.Op)()`. -- The expression `x & y` is rewritten to `x.(BitAndWith(U).Op)(y)`. -- The expression `x | y` is rewritten to `x.(BitOrWith(U).Op)(y)`. -- The expression `x ^ y` is rewritten to `x.(BitXorWith(U).Op)(y)`. -- The expression `x << y` is rewritten to `x.(LeftShiftWith(U).Op)(y)`. -- The expression `x >> y` is rewritten to `x.(RightShiftWith(U).Op)(y)`. +- The expression `x & y` is rewritten to + `x.(BitAndWithPrimitive(formof(y)).Op)(y)`. +- The expression `x | y` is rewritten to + `x.(BitOrWithPrimitive(formof(y)).Op)(y)`. +- The expression `x ^ y` is rewritten to + `x.(BitXorWithPrimitive(formof(y)).Op)(y)`. +- The expression `x << y` is rewritten to + `x.(LeftShiftWithPrimitive(formof(y)).Op)(y)`. +- The expression `x >> y` is rewritten to + `x.(RightShiftWithPrimitive(formof(y)).Op)(y)`. Implementations of these interfaces are provided for built-in types as necessary to give the semantics described above. @@ -281,3 +348,5 @@ to give the semantics described above. - Proposal [#1191: bitwise and shift operators](https://github.com/carbon-language/carbon-lang/pull/1191). +- Proposal + [#5389: Generic across forms](https://github.com/carbon-language/carbon-lang/pull/5389) diff --git a/docs/design/expressions/comparison_operators.md b/docs/design/expressions/comparison_operators.md index 262264ad5e2fa..9d2cc5cc60230 100644 --- a/docs/design/expressions/comparison_operators.md +++ b/docs/design/expressions/comparison_operators.md @@ -247,27 +247,35 @@ resulting in unexpected behavior if they are violated. #### Equality Comparison operators can be provided for user-defined types by implementing the -`EqWith` and `OrderedWith` interfaces. +`EqWithPrimitive` and `OrderedWithPrimitive` interfaces, or the higher-level +`EqWith` and `OrderedWith` constraints. -The `EqWith` interface is used to define the semantics of the `==` and `!=` -operators for a given pair of types: +The `EqWithPrimitive` interface is used to define the semantics of the `==` and +`!=` operators for a given pair of types: ``` -interface EqWith(U:! type) { - fn Equal[self: Self](u: U) -> bool; - default fn NotEqual[self: Self](u: U) -> bool { +interface EqWithPrimitive + [implicit_into Self:! Core.NoRefForm] + (implicit_into U:! Core.NoRefForm) { + fn Equal[self:? Self](u:? U) -> bool; + default fn NotEqual[self:? Self](u:? U) -> bool { return not (self == u); } } +constraint EqWith(U:! type) { + extend require impls + LetSelf(EqWithPrimitive(form(val U))); +} +# FIXME: anchor constraint Eq { extend EqWith(Self); } ``` -Given `x: T` and `y: U`: +The `==` and `!=` operators are rewritten as follows: -- The expression `x == y` calls `x.(EqWith(U).Equal)(y)`. -- The expression `x != y` calls `x.(EqWith(U).NotEqual)(y)`. +- The expression `x == y` calls `x.(EqWithPrimitive(formof(y)).Equal)(y)`. +- The expression `x != y` calls `x.(EqWithPrimitive(formof(y)).NotEqual)(y)`. ``` class Path { @@ -284,6 +292,10 @@ class Path { } ``` +TODO: The following needs to be updated to reflect +[proposal #5389](https://github.com/carbon-language/carbon-lang/pull/5389), to +use `anchor` instead of `like`. + The `EqWith` overload is selected without considering possible implicit conversions. To permit implicit conversions in the operands of an `==` overload, the @@ -353,23 +365,34 @@ choice Ordering { Greater, Incomparable } -interface OrderedWith(U:! type) { - fn Compare[self: Self](u: U) -> Ordering; - default fn Less[self: Self](u: U) -> bool { +interface OrderedWithPrimitive + [implicit_into Self:! Core.Form] + (implicit_into U:! Core.Form) { + fn Compare[self:? Self](u:? U) -> Ordering; + default fn Less[self? Self](u? U) -> bool { return self.Compare(u) == Ordering.Less; } - default fn LessOrEquivalent[self: Self](u: U) -> bool { + default fn LessOrEquivalent + [self:? Self](u:? U) -> bool { let c: Ordering = self.Compare(u); - return c == Ordering.Less or c == Ordering.Equivalent; + return c == Ordering.Less + or c == Ordering.Equivalent; } - default fn Greater[self: Self](u: U) -> bool { + default fn Greater[self:? Self](u:? U) -> bool { return self.Compare(u) == Ordering.Greater; } - default fn GreaterOrEquivalent[self: Self](u: U) -> bool { + default fn GreaterOrEquivalent + [self:? Self](u:? U) -> bool { let c: Ordering = self.Compare(u); - return c == Ordering.Greater or c == Ordering.Equivalent; + return c == Ordering.Greater + or c == Ordering.Equivalent; } } +constraint OrderedWith(U:! type) { + extend require impls + LetSelf(OrderedWithPrimitive(form(val U))); +} +// FIXME: anchor constraint Ordered { extend OrderedWith(Self); } @@ -381,12 +404,15 @@ impl Ordering as Ordered; **TODO:** Revise the above when we have a concrete design for enumerated types. -Given `x: T` and `y: U`: +The comparison operators are rewritten as follows: -- The expression `x < y` calls `x.(OrderedWith(U).Less)(y)`. -- The expression `x <= y` calls `x.(OrderedWith(U).LessOrEquivalent)(y)`. -- The expression `x > y` calls `x.(OrderedWith(U).Greater)(y)`. -- The expression `x >= y` calls `x.(OrderedWith(U).GreaterOrEquivalent)(y)`. +- The expression `x < y` calls `x.(OrderedWithPrimitive(formof(y)).Less)(y)`. +- The expression `x <= y` calls + `x.(OrderedWithPrimitive(formof(y)).LessOrEquivalent)(y)`. +- The expression `x > y` calls + `x.(OrderedWithPrimitive(formof(y)).Greater)(y)`. +- The expression `x >= y` calls + `x.(OrderedWithPrimitive(formof(y)).GreaterOrEquivalent)(y)`. For example: @@ -526,3 +552,5 @@ in general. That decision is left to a future proposal. [#1178: Rework operator interfaces](https://github.com/carbon-language/carbon-lang/pull/1178) - Issue [#710: Default comparison for data classes](https://github.com/carbon-language/carbon-lang/issues/710) +- Proposal + [#5389: Generic across forms](https://github.com/carbon-language/carbon-lang/pull/5389) diff --git a/docs/design/expressions/implicit_conversions.md b/docs/design/expressions/implicit_conversions.md index ec8e1fdeed0f6..49819ee63464b 100644 --- a/docs/design/expressions/implicit_conversions.md +++ b/docs/design/expressions/implicit_conversions.md @@ -202,15 +202,29 @@ conversion. ## Extensibility Implicit conversions can be defined for user-defined types such as -[classes](../classes.md) by implementing the `ImplicitAs` interface, which -extends -[the `As` interface used to implement `as` expressions](as_expressions.md#extensibility): +[classes](../classes.md) by implementing the `ImplicitAsPrimitive` interface, +which extends +[the `AsPrimitive` interface used to implement `as` expressions](as_expressions.md#extensibility), +or the `ImplicitAs` named constraint: ``` -interface ImplicitAs(Dest:! type) { - extend As(Dest); - // Inherited from As(Dest): - // fn Convert[self: Self]() -> Dest; +package Core; + +// FIXME: `implicit_into` is concerning here, since we +// generally only want to perform a single implicit +// type conversion. Perhaps it should have `anchor`? +interface ImplicitAsPrimitive + [implicit_into Self:! Form](Dest:! type) { + final extend impl as AsPrimitive(Dest); + // Inherited from AsPrimitive(Dest): + // let implicit_from ResultForm:! Form where .type = Dest; + // fn Convert[bound self:? Self]() + // ->? ResultForm; +} +constraint ImplicitAs(Dest:! type) { + extend require form(val Self) as + ImplicitAsPrimitive(Dest) + where .ResultForm = form(var Dest); } ``` @@ -239,3 +253,5 @@ types. [#820: Implicit conversions](https://github.com/carbon-language/carbon-lang/pull/820). - Proposal [#866: Allow ties in floating literals](https://github.com/carbon-language/carbon-lang/pull/866). +- Proposal + [#5389: Generic across forms](https://github.com/carbon-language/carbon-lang/pull/5389) diff --git a/docs/design/expressions/indexing.md b/docs/design/expressions/indexing.md index 1fb95b7c1ef2b..1a5efc7b6a2f8 100644 --- a/docs/design/expressions/indexing.md +++ b/docs/design/expressions/indexing.md @@ -21,27 +21,33 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception ## Overview Carbon supports indexing using the conventional `a[i]` subscript syntax. When -`a` is a -[durable reference expression](/docs/design/values.md#durable-reference-expressions), -the result of subscripting is also a durable reference expression, but when `a` -is a [value expression](/docs/design/values.md#value-expressions), the result -can be a durable reference expression or a value expression, depending on which -interface the type implements: +`a` is a [value expression](/docs/design/values.md#value-expressions), the +result can be a durable reference expression or a value expression, depending on +which constraints the type implements: - If subscripting a value expression produces a value expression, as with an - array, the type should implement `IndexWith`. + array, the type should implement `IndexValWith` and `IndexRefWith`. Types + that implement both satisfy the `IndexWith` constraint. - If subscripting a value expression produces a durable reference expression, as with C++'s `std::span`, the type should implement `IndirectIndexWith`. -`IndirectIndexWith` is a subtype of `IndexWith`, and subscript expressions are -rewritten to method calls on `IndirectIndexWith` if the type is known to -implement that interface, or to method calls on `IndexWith` otherwise. +When `a` is a +[durable reference expression](/docs/design/values.md#durable-reference-expressions), +the result of subscripting is also a durable reference expression in either +case. + +Any type that implements `IndirectIndexWith` automatically also implements +`IndexWith`. + +Other behaviors can be accomplished by implementing the underlying interface +`IndexWithPrimitive`. -`IndirectIndexWith` provides a final blanket `impl` of `IndexWith`, so a type -can implement at most one of those two interfaces. +`IndirectIndexWith` overlaps and conflicts with `IndexValWith`, so a type can +implement at most one of those two constraints. -The `Ref` methods of these interfaces, which are used to form durable reference -expressions on indexing, must return by `ref`. +The `Ref` methods of `IndexRefWith` and `IndirectIndexWith`, which are used to +form durable reference expressions on indexing, return by `ref`. The +`IndexValWith` interface has an `At` method that returns by value. ## Details @@ -49,52 +55,91 @@ A subscript expression has the form "_lhs_ `[` _index_ `]`". As in C++, this syntax has the same precedence as `.`, `->`, and function calls, and associates left-to-right with all of them. -Its semantics are defined in terms of the following interfaces: +Its semantics are defined in terms of the following form interface: -``` -interface IndexWith(SubscriptType:! type) { - let ElementType:! type; - fn At[bound self: Self](subscript: SubscriptType) -> val ElementType; - fn Ref[bound ref self: Self](subscript: SubscriptType) -> ref ElementType; -} +```carbon +package Core; -interface IndirectIndexWith(SubscriptType:! type) { - require Self impls IndexWith(SubscriptType); - fn Ref[bound self: Self](subscript: SubscriptType) -> ref ElementType; +interface IndexWithPrimitive + [implicit_into anchor Self:! Form] + (implicit_into Subscript:! Form) { + let implicit_from ResultForm:! Form; + fn Op[bound self:? Self](subscript:? Subscript) + ->? ResultForm; } ``` -A subscript expression where _lhs_ has type `T` and _index_ has type `I` is -rewritten based on the expression category of _lhs_ and whether `T` is known to -implement `IndirectIndexWith(I)`: +The expression "_lhs_ `[` _index_ `]`" is rewritten to "_lhs_ +`.(IndexWithPrimitive(formof(` _index_ `)).Op)(` _index_ `)`". -- If `T` implements `IndirectIndexWith(I)`, the expression is rewritten to - "`(` _lhs_ `).(IndirectIndexWith(I).Ref)(` _index_ `)`". -- Otherwise, if _lhs_ is a - [_durable reference expression_](/docs/design/values.md#durable-reference-expressions), - the expression is rewritten to "`(` _lhs_ `).(IndexWith(I).Ref)(` _index_ - `)`". -- Otherwise, the expression is rewritten to "`(` _lhs_ `).(IndexWith(I).At)(` - _index_ `)`". +The named constraint `IndexWith` covers the case of indexing into an object that +owns the storage for its elements, like an array or C++'s `std::vector`: -`IndirectIndexWith` provides a blanket `final impl` for `IndexWith`: +```carbon +// `lhs[index]` is a value expression when `lhs` +// is a value expression. +constraint IndexValWith(SubscriptType:! type) { + let ElementType:! type; -``` -final impl forall - [SubscriptType:! type, T:! IndirectIndexWith(SubscriptType)] - T as IndexWith(SubscriptType) { - where ElementType = T.(IndirectIndexWith(SubscriptType).ElementType); - fn At[bound self: Self](subscript: SubscriptType) -> val ElementType { - return self.(IndirectIndexWith(SubscriptType).Ref)(index); - } - fn Ref[bound ref self: Self](subscript: SubscriptType) -> ref ElementType { - return self.(IndirectIndexWith(SubscriptType).Ref)(index); + require form(val Self) impls + IndexWithPrimitive(form(val SubscriptType)) + where .ResultForm = form(val ElementType); + alias At = LetSelf(IndexWithPrimitive( + form(val SubscriptType))).Op; +} + +// `lhs[index]` is a ref expression when `lhs` +// is a ref expression. +constraint IndexRefWith(SubscriptType:! type) { + let ElementType:! type; + + require form(ref Self) impls + IndexWithPrimitive(form(val SubscriptType)) + where .ResultForm = form(ref ElementType); + alias Ref = RefSelf(IndexWithPrimitive( + form(val SubscriptType))).Op; +} + +// `lhs[index]` is a reference expression or value +// depending on the category of `lhs`. +constraint IndexWith + [Self:! NoVarForm](SubscriptType:! type) { + let ElementType:! type; + match_first { + extend require impls IndexRefWith(SubscriptType) + where .ElementType = ElementType; + extend require impls IndexValWith(SubscriptType) + where .ElementType = ElementType; } } ``` -Thus, a type that implements `IndirectIndexWith` need not, and cannot, provide -its own definitions of `IndexWith.At` and `IndexWith.Ref`. +Note that `IndexWith` may be used as parameter's constraint, but can't be +directly implemented, since Carbon doesn't support implementing multiple +interfaces together (see +[leads issue #4566: Implementing multiple interfaces with a single `impl` definition](https://github.com/carbon-language/carbon-lang/issues/4566) +and +[proposal #5168: Forward `impl` declaration of an incomplete interface](https://github.com/carbon-language/carbon-lang/pull/5168)). + +```carbon +// `lhs[index]` is always reference expression, even +// when `lhs` is a value. +constraint IndirectIndexWith(SubscriptType:! type) { + let ElementType:! type; + + require form(val Self) impls + IndexWithPrimitive(form(val SubscriptType)) + where .ResultForm = form(ref ElementType); + alias Ref = LetSelf(IndexWithPrimitive( + form(val SubscriptType))).Op; +} +``` + +Note that both `IndexValWith` and `IndexIndirectWith` require +`form(val Self) as IndexWithPrimitive(form(val SubscriptType))`, with different +result forms, and so conflict. However, a type that defines an `impl` of +`IndirectIndexWith` will also satisfy the `IndexValWith`, `IndexRefWith`, and +`IndexWith` constraints due to implicit conversions. ### Examples @@ -102,9 +147,12 @@ An array type could implement subscripting like so: ``` class Array(template T:! type) { - impl as IndexWith(like i64) { - let ElementType:! type = T; + impl as IndexValWith(i64) { + where ElementType = T; fn At[bound self: Self](subscript: i64) -> val T; + } + impl as IndexRefWith(i64) { + where ElementType = T; fn Ref[bound ref self: Self](subscript: i64) -> ref T; } } @@ -114,9 +162,9 @@ And a type such as `std::span` could look like this: ``` class Span(T:! type) { - impl as IndirectIndexWith(like i64) { - let ElementType:! type = T; - fn Ref[bound ref self: Self](subscript: i64) -> ref T; + impl as IndirectIndexWith(i64) { + where ElementType = T; + fn Ref[bound self: Self](subscript: i64) -> ref T; } } ``` @@ -135,3 +183,5 @@ class Span(T:! type) { [#2274: Subscript syntax and semantics](https://github.com/carbon-language/carbon-lang/pull/2274) - Proposal [#2006: Values, variables, and pointers](https://github.com/carbon-language/carbon-lang/pull/2006) +- Proposal + [#5389: Generic across forms](https://github.com/carbon-language/carbon-lang/pull/5389) diff --git a/docs/design/generics/details.md b/docs/design/generics/details.md index 64c2a977903fa..6b55bda350eee 100644 --- a/docs/design/generics/details.md +++ b/docs/design/generics/details.md @@ -4504,7 +4504,9 @@ of type structures, which is resolved using this rule: > prioritization block are required to have the same type structure, at a > cost in expressivity. This option was not chosen since it wouldn't support > the different type structures created by the -> [`like` operator](#like-operator-for-implicit-conversions). +> [`like` operator](#like-operator-for-implicit-conversions). TODO: Update +> to reflect +> [proposal #5389](https://github.com/carbon-language/carbon-lang/pull/5389). > > To see the difference from the first option, consider two libraries with type > structures as follows: @@ -6000,6 +6002,9 @@ if (positive > even) { ... } ### `like` operator for implicit conversions +> **TODO:** Update to reflect +> [proposal #5389](https://github.com/carbon-language/carbon-lang/pull/5389). + Because the type of the operands is directly used to select the operator interface implementation, there are no automatic implicit conversions, unlike with function or method calls. Given both a method and an interface diff --git a/proposals/p5389.md b/proposals/p5389.md new file mode 100644 index 0000000000000..d4039322136fb --- /dev/null +++ b/proposals/p5389.md @@ -0,0 +1,3495 @@ +# Generic across forms + + + +[Pull request](https://github.com/carbon-language/carbon-lang/pull/5389) + + + +## Table of contents + +- [Abstract](#abstract) +- [Problem](#problem) +- [Background](#background) +- [Summary](#summary) +- [Proposal](#proposal) + - [Form type and values](#form-type-and-values) + - [Primitive form value literals](#primitive-form-value-literals) + - [`formof`](#formof) + - [Compound form values](#compound-form-values) + - [`type` property of form values](#type-property-of-form-values) + - [Form facet types](#form-facet-types) + - [Specifying the form of a binding](#specifying-the-form-of-a-binding) + - [Specifying the form of a return](#specifying-the-form-of-a-return) + - [Form interfaces](#form-interfaces) + - [Forms in `impl`s](#forms-in-impls) + - [`where`...`impls`](#whereimpls) + - [`extend`](#extend) + - [Converting from a form facet type to a type facet type](#converting-from-a-form-facet-type-to-a-type-facet-type) + - [Any form with this type](#any-form-with-this-type) + - [`Core.ConvertsInto`](#coreconvertsinto) + - [`implicit_into` interface parameter variance](#implicit_into-interface-parameter-variance) + - [Implied constraints](#implied-constraints) + - [Modifiers for coherence](#modifiers-for-coherence) + - [Facets create adapters](#facets-create-adapters) + - [`implicit_from` variance](#implicit_from-variance) + - [`Core.ConvertsFrom`](#coreconvertsfrom) + - [Covariant](#covariant) + - [Primitive call interface](#primitive-call-interface) + - [`call`](#call) + - [Named constraints](#named-constraints) + - [Named form constraints](#named-form-constraints) + - [Associated constants in named constraints](#associated-constants-in-named-constraints) + - [`match_first` in named constraints](#match_first-in-named-constraints) + - [`Core.Call` named constraint](#corecall-named-constraint) + - [Interaction between `anchor`, `exact`, and named constraints](#interaction-between-anchor-exact-and-named-constraints) + - [Primitive indexing interface](#primitive-indexing-interface) + - [Primitive member binding interface](#primitive-member-binding-interface) + - [Primitive conversion interfaces](#primitive-conversion-interfaces) + - [with `partial`](#with-partial) + - [with `const`](#with-const) + - [Primitive versions of other operator interfaces](#primitive-versions-of-other-operator-interfaces) + - [`auto` form](#auto-form) + - [`auto` form bindings](#auto-form-bindings) + - [Positional parameters](#positional-parameters) + - [`alias`](#alias) + - [namespace aliases](#namespace-aliases) + - [`using`](#using) + - [`auto` form returns](#auto-form-returns) + - [Implicit conversions of `self`](#implicit-conversions-of-self) +- [Details](#details) + - [Coherence modifier examples](#coherence-modifier-examples) + - [Examples using `call`](#examples-using-call) + - [`impl` lookup for an interface with variant parameters](#impl-lookup-for-an-interface-with-variant-parameters) + - [Conversions when calling a function argument](#conversions-when-calling-a-function-argument) + - [Deducing a form value](#deducing-a-form-value) + - [Compile-time parameter equal to a specified value](#compile-time-parameter-equal-to-a-specified-value) + - [Parameter requires exact type match](#parameter-requires-exact-type-match) + - [Representing deduced parameters](#representing-deduced-parameters) + - [Representing explicit compile-time parameters](#representing-explicit-compile-time-parameters) + - [Callables that may or may not mutate](#callables-that-may-or-may-not-mutate) + - [Forwarding](#forwarding) + - [Forwarding tuple parameters](#forwarding-tuple-parameters) +- [Future work](#future-work) + - [Compile-time calls](#compile-time-calls) + - [Impl prioritization](#impl-prioritization) + - [Parameterized aliases](#parameterized-aliases) + - [`ref?`](#ref) + - [Allow more variance](#allow-more-variance) +- [Rationale](#rationale) +- [Alternatives considered](#alternatives-considered) + - [Decoupling type from the rest of the form](#decoupling-type-from-the-rest-of-the-form) + - [Other ways to write "any form with a specified type"](#other-ways-to-write-any-form-with-a-specified-type) + - [Don't have types that represent all binding information](#dont-have-types-that-represent-all-binding-information) + - [Represent all form information in ordinary types](#represent-all-form-information-in-ordinary-types) + - [Different form types for parameters and returns](#different-form-types-for-parameters-and-returns) + - [Implicit conversion from `type` to `Core.Form`](#implicit-conversion-from-type-to-coreform) + - [Other ways to determine variance in interfaces](#other-ways-to-determine-variance-in-interfaces) + - [Support implicit conversions in impls](#support-implicit-conversions-in-impls) + - [Infer `anchor` in `impl` declarations](#infer-anchor-in-impl-declarations) + - [Different form literal syntax](#different-form-literal-syntax) + - [`ref` on an argument controls its category](#ref-on-an-argument-controls-its-category) + - [Replace `require` for interface-interface requirements](#replace-require-for-interface-interface-requirements) + + + +## Abstract + +We propose: + +- Special type `Core.Form` whose values describe the form (category, phase, + and so on) of parameters or returns in the signature of functions. +- A `form(`...`)` literal syntax for writing values of these form types. +- Form facet types for expressing constraints on form types, which may be + composed using `&`. +- `:?` binding and `->?` return syntax parameterized by a form value. +- Form versions of interfaces, facets, and facet types. +- Use these new form facet types to create new "primitive" versions of the + operator interfaces, like `Core.CallPrimitive`, that allow control over the + form of the parameters and return. +- A `call(`...`)` syntax for concisely and naturally writing facet types of + the `Core.CallPrimitive` interface. +- Impl lookup will allow some conversions between `Core.Form` values in + interface arguments and associated constants, when specified by the + interface, replacing the existing mechanism where `impl`s use `like` to + allow implicit conversions in arguments. +- A number of increased capabilities for named constraints. + +Together these changes will allow: + +- the operator interfaces to support Carbon's full range of function + semantics, particularly in the `Core.CallPrimitive` form interface; +- replacing our existing operator interfaces like `Core.Call` and + `Core.AddWidth` with named constraints that use types instead of forms; +- a new, more capable definition of `alias`, along with a shorthand `using`; +- full-fidelity forwarding of function parameters; and +- a syntax for a compile-time parameter that is equal to a specified value. + +## Problem + +The `Core.Call` interface defined in +[proposal #2875](https://github.com/carbon-language/carbon-lang/pull/2875) does +not support all of the features of function calls: + +- `var` and `ref` parameters; +- `bound` parameters; +- mutation of the callable object using `ref self`; +- compile-time parameters, as designated by `:!` or `template`...`:!`; and +- compile-time parameters that are mentioned elsewhere in the signature. + +In addition, we want to be able to express these aspects of parameters in other +contexts: + +- Some interfaces, such as operators, should support `impl`s specifying these + aspects for the parameters of the interface's member functions. For example, + a type should be able to implement `Core.AddWith` in a way that uses `var` + or compile-time parameters, but not `ref`. +- We would like there to be a way to forward arguments passed to one function + to another function it calls, preserving those aspects. For example, there + should be a way to write + [`Apply`](https://en.wikipedia.org/wiki/Function_application) that takes a + function and arguments to call it with and performs the call (so + `Apply(F, x)` returns `F(x)`). + +Ideally, our call operator interface would support: + +- **Uniformity**: ("consistent and universal") Ordinary functions, lambdas, + and bound methods are all values of types that implement the call operator + interface with the relevant signature. This is to enable a single constraint + on a parameter to accept any of these. This also implies that implementing + the call operator interface is sufficient to express the full range of + function signatures, including `var` and `ref` parameters. +- **Functors**: Types may implement the interface to be callable using the + normal function-calling syntax, like implementing `operator()` in C++. A + closure is syntactic sugar for declaring and creating a value of such a + type. +- **Overloading**: There is a relatively convenient way to define a function + value whose type has multiple implementations of the "call operator" + interface. +- **Dispatch**: There is a method of matching actual call invocations to + implementations of the "call operator." It should be as similar as possible + to other cases of `impl` selection, including supporting the same + `match_first` `impl` prioritization system (or whatever we replace that + with). However, it also needs to be able to support the expected implicit + conversions from the arguments values to the parameter types. +- **Subsumption**: An overload set containing two functions, one accepting a + `bool` and one accepting an `i32`, should be able to be passed as an + argument to a function requiring a callable accepting a `bool`. This same + mechanism should allow a generic function with signature that could accept a + `bool`, such as `fn F[T:! type](x: T)`, to be passed to the function + requiring a callable accepting a `bool`, using the instantiation with + `T == bool`. +- **Closed**: There is a way to say "just these implementations and no + others." This should be the default when defining ordinary functions and + function overloads. + +However, fully addressing the last four of these properties is out of scope of +this proposal, since it won't address declaring overloaded functions and `impl` +prioritization. We still would like the decisions in this proposal to be +consistent with a future solution that achieves those properties. + +In addition, there are a number of outstanding problems in Carbon that arise +from a construct requiring some specification of aspects in a binding when it +should instead to a + +[Leads issue #5028: More powerful aliasing feature](https://github.com/carbon-language/carbon-lang/issues/5028) +documents our desires to improve the shortcomings of our current definition of +the `alias` construct. Leads issues +[#996: Generic let with auto?](https://github.com/carbon-language/carbon-lang/issues/996) +and +[#1371: Is let referentially transparent?](https://github.com/carbon-language/carbon-lang/issues/1371) +considered whether `let` could be combined with `auto` to make something +[referentially transparent](https://en.wikipedia.org/wiki/Referential_transparency), +as you would want from an `alias` construct, and concluded the answer was no. A +solution to the above problems about capturing information beyond type might +also allow us to define semantics for a referentially transparent `alias` +feature without its current shortcomings. + +## Background + +This proposal builds upon these prior issues and proposals: + +- [Leads issue #578: Value patterns as function parameters](https://github.com/carbon-language/carbon-lang/issues/578) + decided that we would not have refutable patterns in function signatures, + and discusses workarounds where this is helpful to work around ordering + constraints on compile-time parameters. +- [Proposal #2875: Functions, function types, and function calls](https://github.com/carbon-language/carbon-lang/pull/2875) + defines the `Call` interface, with its current restriction to value + parameters and initializing returns. +- [Proposal #5434: `ref` parameters, arguments, returns and `val` returns](https://github.com/carbon-language/carbon-lang/pull/5434) + expands the set of categories for parameters and returns, increasing the + need for a way to represent them. +- [Proposal #5545: Expression form basics](https://github.com/carbon-language/carbon-lang/pull/5545) + introduces forms as capturing aspects of bindings and returns beyond their + type. + +Some of the thinking that led to this proposal: + +- [Function overloading document](https://docs.google.com/document/d/1rTsDJ_ZNENH0mhi5E64MGjKJ29OYiI_dzBRz2GzYySU/edit?resourcekey=0-z6_xQ9xuJ5CZ6qJqiuSxuw&tab=t.0) + with the initial ideas on how to support function overloading in Carbon, and + links to early discussions on this topic. +- [Suggestion on leads issue #5261 to support parameterizing bindings with categories](https://github.com/carbon-language/carbon-lang/issues/5261#issuecomment-2790947831). +- [Idea in open discussion on 2025-05-07 to allow parameterizing interfaces by forms](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.4zbo49wg5rmk). + +## Summary + +In short, this proposal introduces: + +- a type `Core.Form` of form values, which describe the type and non-type + aspects of bindings and returns. Values of this type can be created as + generic parameters of type `Core.Form`, or using: + - Primitive form value literal syntax `form(val T)`, `form(ref T)`, and + `form(var T)` for value, reference, and initializing forms respectively. + - `formof(`_expression_`)` gives the form of the _expression_ without any + runtime evaluation. + - `(`_form1_`, ` _form2_`, ` _form3_`) as Core.Form` creates a compound + tuple form value. + - `{.a = `_form1_`, .b = ` _form2_`} as Core.Form` creates a compound + struct form value. +- that form values have a `.type` property that gives the unqualified (without + `partial` or `const` modifiers) version of the type associated with the + form. +- form facet types that are restricted versions of `Core.Form`, such as + `Core.NoValForm`. +- a binding _name_`:?`_form value_, where the form of the binding is + determined by the _form value_. +- a return syntax `->? `_form value_, where the form of the return is + determined by the _form value_. +- form interfaces, where the `Self` is of type `Core.Form` or a form facet + type instead of `type`. +- that an `impl` of a form interface, or an interface with form parameters, + uses the `.type` property of form arguments to determine the type to use for + the orphan rule. +- some uses of `extend` that previously assumed `Self` and didn't allow it to + be specified, now allow `Self` or a form using `Self` to be specified. +- `Core.ValSelf`, `Core.RefSelf`, and `Core.VarSelf` functions that take a + `Core.Form` facet type and return an ordinary `type` facet type with the + specified category used for `Self`. +- `Core.Form where .type = T` which gives a form facet type that matches any + form with unqualified type `T`. Similarly, `Core.Form where .type impls C` + gives a form facet type that matches any form whose type implements `C`. +- `Core.ConvertsInto(PF:! Form)` which is a `Core.Form` constraint that + matches all expression forms that can be converted to a parameter with form + `PF`. +- `implicit_into` which may be used to mark `Core.Form` interface parameters, + including the `Self` parameter of a form interface. Those parameters are + called "variant", specifically "contravariant." The arguments to a query in + that position may be converted, as described by the `Core.ConvertsInto` + constraint. + - An `impl` of such an interface can have multiple type structures, + depending on whether the types in the query match or need to be + converted. + - An `impl` may use `anchor` or `exact` to limit the conversions allowed, + which can be needed to satisfy the orphan rule. + - Implied constraints are not added for variant parameters. + - When normally we would for a facets of an interface, if that interface + has variant parameters, we create an adapter that also implements that + interface. This adapter performs the conversion between the argument and + parameter forms, and allows the implementations of the interface to + differ from the original type without introducing coherence concerns. +- `implicit_from` which similarly may be used to mark an interface parameter + or associated constant. These parameters are also "variant," specifically + "covariant." These allow conversions in the opposite direction as + `implicit_into`, as described by the `Core.ConvertsFrom` constraint. +- updates to named constraints to support forms. + - We add support for associated constants in named constraints. Their + values must be deducible from an `impl` of an interface required by the + named constraint. + - A named constraint can contain a `match_first` block to prioritize + between requirements that overlap. +- a change to the ...`(`...`)` function call operator. It now uses the + `Core.CallPrimitive` form interface, instead of the `Core.Call` interface. + - A `call` sugar syntax makes it easier to specify a specific + `Core.CallPrimitive` with a syntax similar to a function declaration + instead of using form literals. + - The `Core.Call` interface is changed to a named constraint that uses + types to specify the call instead of forms. +- a change to the ...`[`...`]` indexing operator. It now uses the + `Core.IndexWithPrimitive` form interface instead of a combination of + `Core.IndexWith` and `Core.IndirectIndexWith` type interface. + - `Core.IndirectIndexWith` becomes a named constraint that requires + `Core.IndexWithPrimitive`. + - `Core.IndexWith` becomes a named constraint that requires both + `Core.IndexValWith` and `Core.IndexRefWith`. `Core.IndexWith` can't be + implemented directly, implement `Core.IndexValWith` and + `Core.IndexRefWith` separately instead. +- a change to the interfaces used for member binding introduced in + [proposal #3720](https://github.com/carbon-language/carbon-lang/pull/3720). + Those type interfaces are replaced with named constraints that + `extend require` `MemberBind`, a single form interface that is used for all + cases. +- form interfaces `Core.AsPrimitive` and `Core.ImplicitAsPrimitive` that + replace type interfaces `Core.As` and `Core.ImplicitAs`. This gives `impl`s + the ability to control the resulting category. `Core.As` and + `Core.ImplicitAs` become named constraints requiring the corresponding + primitive form interfaces. + - With this greater control, we define how the conversions with `partial`- + and `const`-qualified types interact with expression category. +- new `Primitive` form interfaces for other other operators that allow control + over form, not just type. The previous interface names are replaced with + named constraints that allow you to continue to use types. +- `auto` may now be used to deduce a form in a `:?` form binding or `->?` form + return. + - This is used implicitly for positional parameters. + - This is used to give a new definition of the `alias` construct. + - This new `alias` construct doesn't apply to namespaces, so a new + namespace aliasing facility is introduced. + +## Proposal + +### Form type and values + +First, we introduce the new special type `Core.Form` that describe the form of +bindings (such as function parameters or in a `let` declaration), returns, or +expressions. + +- The new `:?` syntax takes a form value to + [specify the form of a binding](#specifying-the-form-of-a-binding). +- The new `->?` syntax takes a form value to + [specify the form of a return](#specifying-the-form-of-a-return). + +Values of `Core.Form` are compile-time only, like types. Form values can be +compound forms or primitive forms. A compound form is either a tuple form or +struct form. + +A primitive `Core.Form` has: + +- a type +- a category, which can be `val`/value, `ref`/reference, or `var`/initializing +- for parameter bindings, whether it is marked with `bound` +- the phase, which can be "compile time" or "run time" (meaning "when the + function is run") +- for compile time phase, a specific compile-time value + +#### Primitive form value literals + +A primitive `Core.Form` value with "run time" phase can be written `form(`_cat_ +_type_`)`, where _cat_ is an optional category modifier, and _type_ is a type +expression: + +| `form` syntax | category | +| :------------ | :----------------- | +| `form(val T)` | `val`/value | +| `form(ref T)` | `ref`/reference | +| `form(var T)` | `var`/initializing | + +This was +[discussed on 2025-06-04](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.stp5dpvithkz). +We use `val` for the value category in alignment with the using `val` for value +category in returns in the resolution of +[leads issue #5522](https://github.com/carbon-language/carbon-lang/issues/5522). + +#### `formof` + +You may also write `formof(`_expression_`)` to get the form of the expression +argument. If the expression has "compile time" phase, then this will result in a +form with that phase and also the value. If the argument to `formof` is a call +expression, the result will be the form of that function's return. However, only +compile-time evaluation will be performed on the argument to `formof`, the +argument is never runtime evaluated. + +Examples: + +``` +let template c: i32 = 1; +// formof(c) == formof(1 as i32) + +let v: i32 = 2; +// formof(v) == form(val i32) + +var r: i32 = 3; +// formof(r) == form(ref i32) + +fn Prints() -> i32 { + Core.Print("This isn't printed"); + return 4; +} +// formof(Prints()) == form(var i32) +``` + +This was +[discussed on 2025-06-04](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.stp5dpvithkz). + +#### Compound form values + +To get a compound tuple form value, take a tuple of form values and cast it to +`Core.Form`, as in: + +```carbon +(form(val T), form(var U), formof(7)) + as Core.Form +``` + +Similarly, a compound struct form value can be constructed from a struct of form +values cast to `Core.Form`: + +```carbon +{.a = form(val T), + .b = form(var U), + .c = formof(7) +} as Core.Form +``` + +These may be nested, as in + +```carbon +// Struct form containing a tuple form +{.a = (form(val T), form(var U)), + .b = form(ref V) +} as Core.Form + +// Tuple form containing a struct form +({.a = form(val T), .b = form(var U)}, + form(ref V) +) as Core.Form +``` + +Note that `:?` and `->?` cast their right argument to `Core.Form`, much like `:` +and `->` cast their right argument to `type`, so the `as Core.Form` can be left +off in those positions. + +This was +[discussed on 2025-06-04](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.stp5dpvithkz). + +#### `type` property of form values + +Every form value has a `type` property, giving its _unqualified type_, accessed +by writing _\_`.type`, following these rules: + +- `form(val T).type`, `form(var T).type`, and `form(ref T).type` are all `T` +- `((X, Y) as Core.Form).type` is `(X.type, Y.type) as type` +- `({.a = X, .b = Y} as Core.Form).type` is `{.a: X.type, .b: Y.type}` + +This definition of the type part of a form is consistent with +[proposal #5545: "Expression form basics"](https://github.com/carbon-language/carbon-lang/pull/5545). +We additionally remove any `const` or `partial` qualifiers to get the +_unqualified_ type. For example: + +- `form(val const T).type` is `T` +- `({.a = form(ref const T), .b = form(var partial U)} as Core.Form).type` is + `{.a: T, .b: U}` + +We want the unqualfied type here, since `.type` will be +[used for the orphan rule](#forms-in-impls), where we don't want to distinguish +types with the `const` or `partial` modifiers. See +[discussion on 2025-06-24](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.d985djkv6qti). + +### Form facet types + +_Form facet types_ are our way of expressing a form type with some additional +restrictions. The values of form facet type are _form facets_, which are values +that are implicitly convertible to the corresponding form type. For example, the +operator interfaces for many operators, such as `+`, don't want to allow `ref` +parameters, and so could use `Core.NoRefForm` to get a `Core.Form` facet type +with that restriction. A value of `Core.NoRefForm`, like +`form(val i32) as Core.NoRefForm`, is implicitly convertible to `Core.Form`, +resulting in `form(val i32)`. Here are some form facet types with different +restrictions: + +- `Core.NoValForm` +- `Core.NoRefForm` +- `Core.NoVarForm` +- `Core.NoCompileTimeForm` +- `Core.NoRunTimeForm` +- `Core.NoBoundForm` + +When converting a form value to a different form facet type, the conversion +fails if the form is not allowed by the destination type. For example, +converting `form(var i32)` to `Core.NoVarForm` or `formof(7)` to +`Core.NoCompileTimeForm` are both invalid. + +Use `&` to combine form facet types to get one that requires its values to +satisfy the constraints from both, as in +`Core.NoRefForm & Core.NoCompileTimeForm` to say a form that doesn't use `ref` +or compile-time forms. + +### Specifying the form of a binding + +The `n :? B` binding syntax creates a binding to the name `n` with form given by +`B`. Note that `B` will be implicitly converted to `Core.Form`, much like a `:` +binding will implicitly convert its right-hand argument to `type`. Example: + +```carbon +fn VarFn(x:? form(var i32)); +// is equivalent to: +fn VarFn(var x: i32); + +fn RefFn(x:? form(ref i32)); +// is equivalent to: +fn RefFn(ref x: i32); +``` + +While this is valid, this is not how this feature is expected to be used. +Instead, the form value will typically be a generic parameter. + +```carbon +fn Explicit(PF:! Core.Form, arg:? PF); + +// ✅ Valid since `5` can be passed to a +// `var _: i32` parameter. +Explicit(form(var i32), 5); + +// ❌ Invalid, `5` is not a reference +// expression. +Explicit(form(ref i32), 5); + +// ❌ Invalid, `true` can't be cast to `f32`. +Explicit(form(val f32), true); +``` + +A `Core.Form` parameter is deducible from an argument expression, see +[the "Deducing a form value" section](#deducing-a-form-value). In fact, the form +of a binding is _about_ the expressions it binds to. In contrast, the result of +a `var` and `ref` binding is a reference expression in both cases. + +A `:?` binding with a keyword modifier, like `ref` or `bound`, forces that +binding to have that property, overwriting whatever is in the form value to the +right of the `:?`. This allows specifying `bound`, which is helpful since it +can't be deduced. + +### Specifying the form of a return + +The `->? R` return syntax specifies a return with form `R`. The `R` will be +implicitly converted to `Core.Form`, much like the expression to the right of +`->` will be implicitly converted to `type`. + +```carbon +// Equivalent to: `fn Init() -> i32;` +fn Init() ->? form(var i32); + +// Equivalent to: `fn Val() -> val i32;` +fn Val() ->? form(val i32); + +// Equivalent to: `fn Ref() -> ref i32;` +fn Ref() ->? form(val i32); + +// Deterimines the return form from the +// argument. `Param(form(ref i32))` +// returns an `i32` ref. +fn Param(RF:! Core.Form) ->? RF; +``` + +### Form interfaces + +Previously, interfaces had an implicit `Self` type parameter, set to the type +that is implementing the interface. We add the capability to explicitly declare +the `Self` parameter with a form facet type as an implicit parameter in square +brackets `[`...`]`, similar to the `self` parameter of methods: + +```carbon +interface Callback[Self:! Core.Form] { + // Uses `Self` as the form of a + // parameter using `:?`. + fn Go[self:? Self](); +} + +interface DefaultConstructible + [Self:! Core.Form] { + // Uses `Self` as the form of the + // return using `->?`. + fn MakeDefault() ->? Self; +} +``` + +`Callback` and `DefaultConstructible` are _form interfaces_, specifically +`Core.Form` interfaces in this case. A value of a form interface is a _form +facet_. These work the same way as ordinary "type" interfaces except they use +the matching kind of form values instead of type values. An ordinary "type" +interface acts as if `Self` is declared `[Self:! type]` instead of with a form +type. + +Let's break down what happens with an ordinary "type" interface: + +```carbon +// Equivalent to: interface I[Self:! type] +interface I { + fn F[self: Self](); +} + +// Since `I` is effectively declared `I[Self:! type]`, that means +// `T` is a facet of a type, which means a type that is known to +// implement `I`. Since `T` is a facet of a type, it has an implicit +// conversion to `type`, so it can be used to the right of a `:` +// to give a type to `x`. +fn A[T:! I](x: T) { + x.F(): + // - Looks in the type of `x` for a `F` + // - Type of `x` is `T`, which is symbolic, so look in its type instead + // - Type of `T` is `I`, has a member `F`, namely `I.F` + // - Now evaluate `x.(I.F)` + // - `I.F` has signature `I[Self:! type].fn F[self: Self]()` + // - Requires that the type of `x` implements `I` + // - Satisfied by the bindings `x: T` and `T:! I` +} +``` + +Now look at how this works analogously with the `Core.Form` interface +`Callback`: + +```carbon +// Since `Callback` is declared `Callback[Self:! Core.Form]`, that means +// `CF` is a facet of a `Core.Form`, which means a `Core.Form` that is +// known to implement `Callback`. Since `CF` is a facet of a `Core.Form`, +// it has an implicit conversion to `Core.Form`, so it can be used to the +// right of a `:?` to give a form to `c`. +fn InvokeCallback[CF:! Callback](c:? CF) { + c.Go(); + // - Looks in the type part of the form of `c` for `Go` + // - If the form is a paren form, allow `.0`, `.1` access + // - If the form is a curly brace form, allow `.x`, `.c` access + // - If the form is primitive, look in its type (as above) + // - Since the form `CF` is symbolic, instead we look at `CF`'s type. + // - Type of `CF` is `Callback`, has a member `Go`, namely `Callback.Go` + // - Now evaluate `c.(Callback.Go)` + // - `Callback.Go` has signature + // `Callback[Self:! Core.Form].fn Go[self:? Self]()` + // - Requires the *form* of `c` to implement `Callback` + // - Satisfied by the bindings `c:? CF` and `CF:! Callback`. +} +``` + +Other operations such as implementing a form interface also work analogously, +using form values instead of type values. + +```carbon +class V {} +// `Core.Form` values implement `Callback`, instead of type +// values, since `Callback` is a `Core.Form` interface (and +// a `Core.Form` facet type). +impl form(val V) as Callback { + // Notice the form of the `self` parameter is + // `form(val V)`, the value of `Self`. This is the + // same as `fn Go[self:? Self]()`... + fn Go[self: V]() { + Core.Print("Printed!"); + } +} + +let v: V = {}; +// The form of the expression `v` is `form(val V)`. +// This `Core.Form` value implements `Callback` so this +// call typechecks with `CF` deduced to be +// `form(val V) as Callback`. +// +// The `c.Go()` call in `InvokeCallback` prints "Printed!". +InvokeCallback(v); +``` + +With a form interface, we can change other aspects of the form beyond the type. +Here we show a similar example except with a `ref` `Core.Form`: + +```carbon +class R { + var m: i32; +} +impl form(ref R) as Callback { + // Notice the form of the `self` parameter is + // `form(ref R)`, the value of `Self`. + fn Go[ref self: R]() { + self.m += 2; + } +} +var r: R = {.m = 3}; +// This time `r` is a reference expression so `CF` is +// deduced to be `form(ref R) as Callback`. +InvokeCallback(ref r); +Assert(r.m == 5); +``` + +Finally, here is an example using `DefaultConstructible` instead of `Callback`: + +```carbon +// Initializing form +impl form(var R) as DefaultConstructible { + fn MakeDefault() -> R { + return {.m = 7}; + } +} +r = (form(var R) as DefaultConstructible) + .MakeDefault(); +Assert(r.m == 7); + +var global: R = {.m = 6}; +// `ref` form +impl form(ref R) as DefaultConstructible { + fn MakeDefault() -> ref R { + return global; + } +} +(form(ref R) as DefaultConstructible) + .MakeDefault().m += 3; +Assert(global.m == 9); +``` + +### Forms in `impl`s + +Interfaces can also use form types as the types of its parameters or associated +constants. + +```carbon +interface OneArg(P:! Core.Form) { + let Result:! Core.Form; + fn Fun[self: Self](a:? P) -> Result; +} + +impl MyType as OneArg(form(val i32)) { + where Result = form(var bool); + fn Fun[self: Self](a: i32) -> bool; +} +``` + +To satisfy coherence by +[the orphan rule](/docs/design/generics/details.md#orphan-rule), forms are +converted to types in the type structure using the +[`.type` property](#type-property-of-form-values) (as +[discussed on 2025-06-11](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.rebuyhkgncpq)). +The form value itself is used, though, when prioritizing during `impl` lookup. + +### `where`...`impls` + +A `where` constraint may now contain a requirement `A impls B` where `A` is a +form or facet of a form, and `B` is a form facet type. For example, +`T:! type where form(val .Self) impls Callback` will bind to types `T` such that +there is an implementation of `Callback` for `form(val T)`. + +### `extend` + +Prior to this proposal, the `extend` modifier on some declarations means that +some type argument must be omitted, and is presumed to be `Self`, although +there's a syntactic position available for it: + +- In an interface or named constraint, `extend require`, as defined in + [proposal #5337](https://github.com/carbon-language/carbon-lang/pull/5337), + must be followed by `impls` instead of allowing a type to be specified. +- In a class, `extend impl` and `extend final impl` must be followed by `as` + instead of allowing a type to be specified. +- Similarly, in an interface, `extend impl` and `extend final impl`, as + defined in + [proposal #5337](https://github.com/carbon-language/carbon-lang/pull/5337), + must be followed by `as` instead of allowing a type to be specified. + +In all of these cases, we drop that restriction, and allow a type or a form to +be specified in the expected position. These will generally only be useful if +the `Self` type or form can implicitly convert to what is placed in that +position, though we allow anything in the spirit of supporting extension method +approach of +[leads issue #1345](https://github.com/carbon-language/carbon-lang/issues/1345) +and +[deferred proposal #1122](https://github.com/carbon-language/carbon-lang/pull/1122). +This doesn't override the need for `Self` to appear in a deducible position for +an `impl` in a generic `class` scope, as described in +[leads issue #5251](https://github.com/carbon-language/carbon-lang/issues/5251#issuecomment-2779776355). + +### Converting from a form facet type to a type facet type + +Given a form facet type, we can construct an ordinary `type` facet type in a few +different ways. One is to construct a named constraint. The `Self` values of the +named constraint are types, but the requirements of the constraint can be on +form values using the `Self` type. + +```carbon +// Equivalent to `constraint ValCallback[Self:! type]` +constraint ValCallback { + extend require form(val Self) impls Callback; +} + +constraint RefCallback { + extend require form(ref Self) impls Callback; +} + +constraint VarCallback { + extend require form(var Self) impls Callback; +} +``` + +Another way is with [a `where`...`impls` expression](#whereimpls): + +- `type where form(val .Self) impls Callback` +- `type where form(ref .Self) impls Callback` +- `type where form(var .Self) impls Callback` + +This however doesn't give a way to have name lookup into the facet type find +names in `Callback`, like the named constraints accomplish with +[`extend`](#extend). For that, we introduce functions that take a `Core.Form` +facet type and return an ordinary `type` facet type: `Core.ValSelf`, +`Core.RefSelf`, and `Core.VarSelf`. They are used like: + +```carbon +fn InvokeValCallback + [T:! Core.ValSelf(Callback)](c: T) { + // Name lookup into `T` finds names from + // `Callback`. `T.Go` has signature + // `fn Go[self: T]()`. + c.Go(); +} + +fn InvokeRefCallback + [T:! Core.RefSelf(Callback)](ref c: T) { + // Name lookup into `T` finds names from + // `Callback`. `T.Go` has signature + // `fn Go[ref self: T]()`. + c.Go(); +} + +fn InvokeVarCallback + [T:! Core.VarSelf(Callback) & Core.Move] + (var c: T) { + // Name lookup into `T` finds names from + // `Callback`. `T.Go` has signature + // `fn Go[var self: T]()`. + // The upcoming move proposal will define + // how this works, but is expected to make + // `~c` an initializing expression in this + // case. + (~c).Go(); +} + +fn InvokeWithResultOfFunctionCall + [T:! Core.Call() where + .Result impls VarSelf(Callback)] + (f: T) { + // Not `f().Go()` since `.Result impls` + // doesn't give `.Result` names. + f().(VarSelf(Callback).Go)(); +} +``` + +In addition, there are variations on these functions that also mark the `self` +parameter as `bound`: `Core.BoundValSelf`, `Core.BoundRefSelf`, and +`Core.BoundVarSelf`. + +This was discussed on +[2025-05-08](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.vdognq1upsf5). + +### Any form with this type + +To create a [form facet type](#form-facet-types) expressing "any form with +unqualified type `T`", we use the +[`type` property](#type-property-of-form-values) in a `where` clause, as in +`Core.Form where .type = T`. + +This approach can also be used to express "any form with an unqualified type +satisfying facet type `C`" as in `Core.Form where .type impls C`. This gives the +conversion in the other direction from +[the previous section](#converting-from-a-form-facet-type-to-a-type-facet-type). + +In both cases, the `Core.Form` part can be replaced by another +[form facet type](#form-facet-types), in order to compose form constraints. + +Since +[forms in an `impl` use `.type` to get the types for the orphan rule](#forms-in-impls), +we end up with a situation where the type to satisfy the orphan rule can come +from the `forall` clause. In this example: + +```carbon +impl [PF:! Core.Form where .type = MyClass] PF as I; +``` + +The type structure for the orphan rule is `PF.type as I` which, after applying +the rewrite from `PF`'s constraint, becomes `MyClass as I`. + +This approach also allows deduction of a type through a form, as in: + +```carbon +fn F[T:! I](PF:! Core.Form where + .type = Vector(T)) + -> T.Iterator; +``` + +since the `T` value is uniquely determined by `PF`. + +This was +[discussed on 2025-06-11](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.rebuyhkgncpq), +along with alternative ways we could specify this constraint. + +### `Core.ConvertsInto` + +The `Core` package defines the `Form` facet type `ConvertsInto(PF:! Form)`, +which says which `Form`s describe a binding that would be allowed to convert to +the binding described by `PF`. So `form(val i32)` is a value of +`ConvertsInto(form(val i64))` since there is an implicit conversion from `i32` +to `i64`. More precisely, if we create a function `F` with `PF` as the form of +its parameter, and `y` a binding with form `SRC` (also a `Form` value), as in + +```carbon +fn F(x:? PF); +fn G(y:? SRC) { + F(~y); +} +``` + +then `SRC` is a value of `ConvertsInto(PF)` if and only if the call `F(~y)` is +legal. + +Note that this depends on the meaning of the planned move operator `~`. In this +case, we need: + +- `~v` when `v` is a value parameter gives you the value of `v` before the + expression; +- `~r` when `r` is a `ref` parameter gives you a reference expression that + references whatever `r` did before the expression; +- `~i` when `i` is a `var` parameter gives you an initializing expression that + initializes an object to the state that `i` was in before the expression. + +As an example, `ConvertsInto(form(var i64))` includes the facets of +`form(val i32)`, `form(ref i16)`, and `formof(3)`, since this code is legal: + +```carbon +fn F(var x: i64); + +fn G1(y1: i32) { + F(~y1); +} + +fn G2(ref y2: i16) { + F(~y2); +} + +fn G3(y3:? formof(3)) { + F(~y3); +} +``` + +Also, the facet of `form(var i64)` is also a member of +`ConvertsInto(form(var i64))`. In fact `PF` is a member of `ConvertsInto(PF)` +for all `PF`. + +Note that this is different from the +[form facet type conversions](#form-facet-types), which are about converting +between one form facet type to another. This is about what conversions would be +allowed to a binding described by a particular value of the `Form` type. + +This is also different from [`ImplicitAs`](#primitive-conversion-interfaces): + +- With `ImplicitAs`, the parameter specifies the destination type, not the + destination form, and the `impl` determines the resulting form. + `ConvertsInto` uses `ImplicitAs` to determine if types convert, but in + combination with other interfaces, such as `Copy` and `Move`, which + determine if other aspects of the form such as category convert. For + example, a reference to an object of a derived class implicit converts to a + reference to its base class. It additionally `ConvertsInto` a _value_ of the + base class, since we can follow that type conversion with a + [value binding](/docs/design/values.md#value-binding). +- You can't implement `ConvertsInto`, it may only be used as a constraint. + +### `implicit_into` interface parameter variance + +A form interface parameter (including `Self` for a form interface) may be marked +with the `implicit_into` keyword binding modifier, as in this example: + +```carbon +interface I[implicit_into Self:! Core.Form] + (implicit_into P:! Core.Form) { + fn F[self:? Self](a:? P); +} + +impl form(ref u64) as I(form(var i64)) { + fn F[ref self: u64](var a: i64) { + self += a; + } +} +``` + +This means `impl` lookup for queries involving `I` will consider `impl` +declarations that don't match exactly, unless the corresponding form values in +the `impl` declarations have +[a mark that requires them to match, such as `exact`](#modifiers-for-coherence). +In particular, in those positions a query `X` will match `Y` if `X` is a value +of type `ConvertsInto(Y)`. For example, the `impl` defined above acts as if it +was replaced by a collection of `impl`s for purposes of `impl` lookup: + +```carbon +// `ForwardTo` is the `F` member of the `impl` +// above. It is equivalent to: +// fn [ref self: u64](var a: i64) { +// self += a; +// } +alias ForwardTo = + (form(ref u64) as I(form(var i64))).F; + +impl forall [PF1:! ConvertsInto(form(ref u64)), + PF2:! ConvertsInto(form(var i64))] + PF1 as I(PF2) { + fn F[self:? PF1](a:? PF2) { + // This is allowed, by the definition of + // `ConvertsInto` and that the form of `self` + // of `ForwardTo` is `ref _: u64` and + // the form of its argument is `var _: i64`. + (~self).(ForwardTo)(~a); + } +} + +impl forall [PF1:! ConvertsInto(form(ref u64))] + PF1 as I(exact form(var i64)) { ... } + +impl forall [PF2:! ConvertsInto(form(var i64))] + exact form(ref u64) as I(PF2) { ... } + +impl exact form(ref u64) + as I(exact form(var i64)) { + fn F[ref self: u64](var a: i64) = ForwardTo; +} +``` + +Note that these `impl` definitions are not created, but `impl` lookup acts as if +they exist. This replaces the `like` mechanism introduced in +[proposal #1144](https://github.com/carbon-language/carbon-lang/pull/1144), that +would add this parameterization to the `impl` itself, rather than making it part +of the `interface`. + +Consequences: + +- The type structure of the match for purposes of prioritization counts + `implicit_into` parameters as a pair of a type and the complete form, and + changes depending on how well the query matches the `impl`. + - If the type of the `impl` doesn't match the type in the query, then both + parts of the pair are considered to be `?`. + - If the type matches but rest of the form doesn't, the type structure is + considered to be `(T, ?)`. + - If the whole form matches, ignoring `bound` which is not an aspect of + forms that can be inferred, the type structure is considered to have a + concrete match for both parts of the pair. + - This allows a type to implement the same form interface twice, once with + a value form and once with a reference form, and the one with the + category matching the query will be chosen. (If the query is for an + initializing or constant expression, only the one with the value form + will apply and so will be chosen.) +- As a result, a single `impl` written in the source can correspond to + multiple type structures. If any of the type structures of two different + `impl`s are the same, they must be put together in a `match_first` block. +- These additional `impl`s can only cover cases where we can reliably forward + a source form parameter as an argument to the original function. The job of + the `ConvertTo` constraints is to restrict to those cases. +- The number of notional `impl`s generated tripled for every variant parameter + (minus one for every variant parameter that is marked + [`anchor`](#modifiers-for-coherence)). +- An `implicit_into` parameter may only be used in a + [contravariant position]() + within the interface definition, as either: + + - the + [form of an associated function parameter, after `:?`](#specifying-the-form-of-a-binding), + or + - the argument to + [an `implicit_from` interface parameter](#implicit_from-variance) that + is used as the type of a parameter. + + Note that parameters of a class are always _invariant_, even if that type is + used as the type of a parameter. + +Now consider a generic call to invoke `I.F`: + +```carbon +fn CallF[T:! Core.RefSelf(I(form(val i16)))] + (ref x: T) { + x.F(3); +} + +var y: u64 = 2; +CallF(y); +``` + +A few things to note here: + +- The constraint on `T` requires `form(ref T)` to implement + `I(form(val i16))`. The `impl` defined above is for + `form(ref u64) as I(form(var i64))`, which doesn't match in the parameter + form. However since that parameter is variant, it acts as if there is an + impl that does satisfy that constraint: + + ```carbon + impl forall [PF2:! ConvertTo(form(var i64))] + exact form(ref u64) as I(PF2) { + + fn F[ref self: u64](a:? PF2) { + // Performs an implicit conversion of `a` + // to call the original implementation that + // has one `var _: i64` parameter. + } + } + ``` + +- We could not pass in a reference to a `u32` object here, since although a + `u32` value will implicitly convert to `u64`, a `u32 ref` won't convert to a + `u64 ref`. +- Inside of `CallF`, `x.F` takes a `val i16` parameter. The literal `3` gets + implicitly converted to `i16` to make that call, and then get converted + again to `i64` to call the original implementation of `I`. See + [the "Conversions when calling a function argument" section](#conversions-when-calling-a-function-argument). + +#### Implied constraints + +Consider a class that uses the interface with a variant parameter from before as +a parameter constraint: + +```carbon +interface I[implicit_into Self:! Core.Form] + (implicit_into P:! Core.Form) { + fn F[self:? Self](a:? P); +} + +class C(P:! I(form(val i16))) { ... } + +fn G[P:! I(form(val i32))](c: C(P)); +``` + +Unlike with interfaces with invariant parameters, multiple different `impl`s +could satisfy that constraint. In this case, the `C(P)` parameter type in `G` +would be legal with the existing constraint of `I(form(val i32))` on `P`, but +implied constraints would normally add another constraint that +`P impls I(form(val i16))`. When +[we considered this on 2025-05-29](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.dj0nqhfqo67w), +we decided we didn't want implied constraints adding constraints when there was +a choice of how to do it, so implied constraint don't apply to interfaces with +variant parameters. + +#### Modifiers for coherence + +Note that, unless modified by the `impl`, parameters marked `implicit_into` +can't be used to satisfy the orphan rule for coherence. As such we allow these +modifiers on those parameters, which can be used to ensure that there is a local +type in the `impl`'s type structure: + +- `exact`: the type and category must match between the query and `impl`, + restricting the effect of `implicit_into` to other aspects of form for this + parameter in this `impl` +- `anchor`: at least one of the parameters marked `anchor` must have a + matching type between the query and `impl`. + +See [examples in the "Details" section](#coherence-modifier-examples). + +We also allow using `anchor` to modify `implicit_into` on the _interface_ +parameters to only allow conversions of form that don't change the type. This +can be useful since otherwise an interface that uses `implicit_into` on all its +parameters always has to use `anchor` when defining `impl`s. + +> FIXME: **QUESTION:** Is it `anchor implicit_into` or `implicit_into anchor`? + +Either use of `anchor` in effect adds a +[`where .type = T` constraint](#any-form-with-this-type) on the +`ConvertTo(`...`)` form facet type used to allow conversions to use that `impl`. + +Note that the presence or absence of `anchor`, `exact`, `implicit_into`, or +`implicit_from` is not included in `Core.Form` values. + +> **Alternative considered:** We considered having `exact` mean exact form +> match, but this had some concerns such as: +> +> - We want to allow evolution of what is included in a form. For example we +> might want to include the source location of the argument expression in +> the form. +> - Additional knowledge of the compile-time value in the query should not +> prevent matching. + +#### Facets create adapters + +The facets of an interface without variant parameters preserve the original +type. When forming a facet of an interface with variant parameters, however, we +instead get an adapter type that also implements the interface. In this case, +the implementation of the interface for the adapter type performs the `i16` to +`i64` conversion and then delegates to the original implementation. This change +in type occurs anytime the compiler can't prove it can use the original type +with its original `impl` unchanged, and gives the freedom to have differences +from the original `impl` without violating coherence. A few differences can +occur: + +- Using the original type may mean different implicit conversions occur. In + our example, the original type's `impl` would have directly converted `3` to + `i64`, without going through `i16`. +- As a result of using different implicit conversions, they may accept + different input types. The original version could be called with `i32`, but + the version inside `CallF` could be called with a type that converts to + `i16` but not to `i64`. +- The original type might have another `impl` of the same interface that could + apply. The adapted type only has the ones specified by the constraint. Only + the `impl` used to satisfy the constraint will be used by the adapted type. +- Use of `anchor` or `exact` on the original `impl` will be ignored, only + aspects of the `impl` that are explicitly in the constraint are preserved by + the adapter. + +For `template` parameters, if the call can be resolved at definition time using +the adapter type, then when the template is instantiated the call must be +resolved the same way. This follows the general consistency required of template +parameters with their constraints, see for example in +[member access](/docs/design/expressions/member_access.md#lookup-ambiguity). + +This was discussed on +[2025-05-29](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.dj0nqhfqo67w). + +### `implicit_from` variance + +Form associated constants and interface parameters of an interface may be marked +`implicit_from`. This allows variance as part of `impl` lookup, but in the +opposite direction from +[`implicit_into` parameters](#implicit_into-interface-parameter-variance). This +example shows an `implicit_from` associated constant: + +```carbon +interface Factory { + let implicit_from Result: Core.Form; + fn Create[self: Self]() ->? Result; +} + +fn UseFactory + [T:! Factory where .Result = form(var i64)] + (x: T) -> i64 { + return x.Create(); +} + +class HasFactory { + impl as Factory { + where Result = form(val i32); + fn Create[self: Self]() -> val i32 { + return 1; + } + } +} + +let f: HasFactory = {}; +UseFactory(f); +``` + +Like for `implicit_into` parameters, `implicit_from` associated constants mean +that creating a facet for a type may +[create an adapter type](#facets-create-adapters). In this case though, the +adapter converts between the return forms. In our example, it is as if the +`UseFactory(f);` call was replaced by: + +```carbon +class __HasFactory_adapter { + adapt HasFactory; + impl as Factory { + where Result = form(var i64); + fn Create[self: Self]() -> i64 { + // Does implicit conversion i32 -> i64. + return (self as HasFactory).Create(); + } + } +} + +UseFactory(f as __HasFactory_adapter); +``` + +This example shows an `implicit_from` interface parameter, using +[the `Core.CallPrimitive` interface](#primitive-call-interface): + +```carbon +interface Registry(implicit_from P:! Core.Form) { + fn Register[ref self: Self, + FN:! Core.CallPrimitive(P)](f: FN); + fn DefaultArg() ->? P; +} +``` + +#### `Core.ConvertsFrom` + +The mismatch between the form value in the constraint and `impl` is allowed when +this transformation is valid. In particular, there is a `Core.ConvertsFrom` +constraint that is the mirror of [`Core.ConvertsInto`](#coreconvertsinto). If we +create a function `F` with `RF` as the form of its return, and `G()` a function +returning form `DEST` (also a `Form` value), as in + +```carbon +fn F() ->? RF; +fn G() ->? DEST { + return F(); +} +``` + +then `DEST` is a value of `ConvertsFrom(RF)` if and only if `return F();` is +legal. + +For example, an `impl` of `Registry`: + +```carbon +class R {} +impl R as Registry(form(val i32)) { + fn Register + [ref self: Self, + FN:! Core.CallPrimitive(form(val i32))] + (f: FN) { + f(R.DefaultArg()); + } + fn DefaultArg() -> val i32 { + return 7; + } +} +``` + +is as if it was written: + +```carbon +class R {} +impl forall [RF:! Core.ConvertsFrom(form(val i32))] + R as Registry(RF) { ... } +``` + +This means that since `i32` implicitly converts to `i64`, +`R impls Registry(form(val i64))` as well, and the following use is allowed: + +```carbon +fn TakesI64(x: i64); + +// In the `DoRegister(r)` call below, `T` +// is an adapter for `R` that adds the +// `i32` -> `i64` conversion. +fn DoRegister[T:! Registry(form(val i64))] + (ref r: T) { + // Calls `TakesI64` with `7 as i32` + // which gets converted to an `i64`. + r.Register(TakesI64); +} + +var r: R; +DoRegister(r); +``` + +#### Covariant + +An `implicit_from` interface parameter or associated constant may only be used +in a +[covariant position]() +within an interface definition, either: + +- [the form of an associated function return, after a `->?`](#specifying-the-form-of-a-return), + as in `Factory.Create` and `Registry.DefaultArg` + [earlier](#implicit_from-variance), or +- the argument to + [an `implicit_into` interface parameter](#implicit_into-interface-parameter-variance) + that is used as the type of a parameter, as in `Registry.Register` + [earlier](#implicit_from-variance). + +### Primitive call interface + +Combining forms with variadics allows us to represent a more general version of +the `Call` interface that allows specifying forms: + +```carbon +package Core; + +interface CallPrimitive[implicit_into anchor Self:! Form]( + ... implicit_into each Param:! Form) { + let implicit_from ResultForm:! Form; + fn Op[self:? Self] + (... each args:? each Param) + ->? ResultForm; +} +``` + +Note that the `Self` is variant, since we want to allow a `val T` `impl` to be +used for a `ref T` object. The variance is using +[`anchor` modifier on `implicit_into`](#modifiers-for-coherence) so the _type_ +of `Self` is not variant (though see +[the "Implicit conversions of `self`" section](#implicit-conversions-of-self)), +just the other aspects of the form. + +#### `call` + +It can be cumbersome to write out form values for the arguments to this +interface, though, and we expect this to be the most common use case that would +otherwise require writing form values. So we introduce a `call(`...`)` +convenience syntax for writing a facet type of the `Core.CallPrimitive` +interface. + +| `call` syntax | `Core.Form` facet type value | +| :---------------------- | :-------------------------------------------------- | +| `call()` | `CallPrimitive()` | +| `call(_: i32)` | `CallPrimitive(form(val i32))` | +| `call(_: i32, _: bool)` | `CallPrimitive(form(val i32), form(val bool))` | +| `call(var _: bool)` | `CallPrimitive(form(var bool))` | +| `call(bound _: i32*)` | `CallPrimitive(form(bound val i32*))` | +| `call(_:? X)` | `CallPrimitive(X)` | +| `call(... _: each T)` | `CallPrimitive(... form(val each T))` | +| `call() -> i32` | `CallPrimitive() where .ResultForm = form(var i32)` | +| `call() -> val i32` | `CallPrimitive() where .ResultForm = form(val i32)` | +| `call() -> ()` | `CallPrimitive() where .ResultForm = form(var ())` | + +Note: If "`->` _\_" is not included at the end, the return type is +unconstrained. Use `-> ()` to mean "returns nothing." + +Observe that `CallPrimitive` is `Core.Form` interface, so the above expressions +represent `Core.Form` facet types. Alternatively you may specify the non-type +aspects of the form of `self` by writing `[`...`]` between `call` and the `(` of +the parameter list, as in: + +| `call` syntax | facet type value | +| :------------------ | :------------------------------ | +| `call[val]()` | `ValSelf(CallPrimitive())` | +| `call[ref]()` | `RefSelf(CallPrimitive())` | +| `call[var]()` | `VarSelf(CallPrimitive())` | +| `call[bound ref]()` | `BoundRefSelf(CallPrimitive())` | + +These can be combined, so `call[ref](var _: bool, bound _: i32*) -> ref i32` +gives the facet type: + +```carbon +RefSelf( + CallPrimitive(form(var bool), + form(bound val i32*)) + where .ResultForm = form(ref i32)) +``` + +See [examples in the "details" section](#examples-using-call). + +This was discussed on +[2025-05-08](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.vdognq1upsf5). + +### Named constraints + +We want named constraints to provide +[progressive disclosure](/docs/project/principles/progressive_disclosure.md) for +forms, providing alternative ways of accessing functionality that uses forms at +the lowest level, but can use a named constraint with types instead in common +scenarios. This is similar to how we use named constraints in other +circumstances to hide complexity, such as providing `Add` as an easier +alternative to `AddWith` when you don't need the additional flexibility. + +#### Named form constraints + +We allow the optional `[Self:!`...`]` declaration on named constraints to create +a named form constraint, parallel to [form interfaces](#form-interfaces). This +overrides the default of `[Self:! type]`. A `require impls` or +`require Self impls` in a constraint is allowed when the type of `Self` matches +the type of the `Self` of the interface or constraint being required. + +```carbon +constraint DefaultConstructibleCallback + [Self:! Core.Form] { + // `Self` is `Core.Form`, matches the `Self` + // of `Callback` and `DefaultConstructible`. + extend require impls Callback; + extend require impls DefaultConstructible; +} +``` + +#### Associated constants in named constraints + +We add support for associated constant declarations in named constraints, using +the same `let`...`:!`...`;` syntax as in interfaces. Such associated constants +must be used in such a way as to be deducible from the `impl`s of interfaces +required by the constraint. Deducible here means following the same rules as a +deduced parameter in a function signature. When seeing if a facet satisfies a +constraint, the associated constants are deduced. + +```carbon +constraint Invalid { + // ❌ Invalid: `Key` not deducible. + let Key:! type; + extend require impls Map(Key); +} +``` + +When implementing the named constraint directly, every associated constant of +the extended interface must be given a value, as before. This can now be done by +given a value to an associated constant in the named constraint, which will give +values to any derived associated constants in the interface being implemented. + +Example: + +```carbon +constraint MultiMap(Key:! type) { + // Shadows `Value` from `Map`. + let Value:! type; + extend require impls Map(Key) + where .Value = Vector(Value); +} +// This is legal since a function like +// fn F[Value:! type] +// (T:! Map(Key) where .Value = Vector(Value)); +// is valid, since `Value` is deducible from `T`. + +class S2I { ... } + +impl S2I as Map(String) + where .Value = Vector(i32) { ... } + +fn MultiGet[T:! MultiMap(String)](x: T) + -> T.Value; +fn MapGet[T:! Map(String)](x: T) + -> T.Value; +fn Restricted( + V:! type, + T:! MultiMap(String) where .Value = V); + +var s2i: S2I = {...} +// `(S2I as Map(String)).Value` is +// `Vector(i32)`, so +// `(S2I as MultiMap(String)).Value` +// is `i32`. +let r1: i32 = MultiGet(s2i); +let r2: Vector(i32) = MapGet(s2i); +// ✅ Allowed +Restricted(i32, S2I); +// ❌ Invalid: +// `(S2I as MultiMap(String)).Value` +// is `i32` not `bool` +Restricted(bool, S2I); + +class S2B { ... } + +// `(S2B as MultiMap(String)).Value` +// is `bool`, so +// `(S2B as Map(String)).Value` is +// `Vector(bool)`. +impl S2B as MultiMap(String) + where .Value = bool { ... } + +var s2b: S2B = {...} +let r3: bool = MultiGet(s2b); +let r4: Vector(bool) = MapGet(s2b); +// ❌ Invalid: +// `(S2B as MultiMap(String)).Value` +// is `bool` not `i32` +Restricted(i32, S2B); +// ✅ Allowed +Restricted(bool, S2B); +``` + +Whenever a named constraint is implemented, the resulting `impl` is checked to +verify that its satisfies the named constraint, including giving a single +consistent value to any associated constants it might have. + +```carbon +interface X { + let T:! type; + let U:! type; +} + +constraint N { + let V:! type; + extend require impls X + where .T = Vector(V) + and .U = Map(V); +} + +class Invalid1 {} + +impl Invalid1 as N { + where T = Vector(bool); + // ❌ Inconsistent, `V` can't be both + // `bool` and `i32`. + where U = Map(i32); +} + +class Invalid2 {} + +impl Invalid2 as N { + // ❌ Inconsistent, `T` has to be a + // `Vector` so there is some legal + // value for `V`. + where T = i32; + where U = Map(i32); +} +``` + +This feature can be used to convert a form associated constant in the extended +interface into a type associated constant in the named constraint, as in +[`Core.Call`](#corecall-named-constraint) and +[other](#primitive-versions-of-other-operator-interfaces) named constraints. + +The `final` modifier is allowed on associated constants in named constraints. In +this case, it is given a value directly instead of being deduced from the +`impl`s of required interfaces. Examples: + +```carbon +constraint VectorI(T:! type) { + // Can be used to give a name to an + // an expression. + final let Elt:! type = Vector(T); + + require impls I where .Elt = Elt; + + // Can be used to create an alias to + // a member of a required interface. + final let template Iter:! auto + = I.Iter; +} +``` + +Allowing the `default` modifier here is future work, which we expect to support +once we have an algorithm for resolving when there are multiple applicable +defaults (likely using the defaults from the outermost constraint first). Until +then, note that the interface can still have a default that can be applicable to +a named constraint default, as in: + +```carbon +interface DefaultResult { + default let ResultForm:! Core.Form + = form(var Self); + fn F() ->? ResultForm; +} +constraint C { + let Result:! type; + extend require impls DefaultResult + where .ResultForm = form(var Result); +} +``` + +Here an `impl` of `C` that doesn't specify `Result` will use the default +`DefaultResult.ResultForm` of `form(var Self)`, which will deduce a value of +`Self` for `C.Result`. + +We considered similar constructs (`forunique` or `forsome`) in the context of +template constraints in +[discussion on 2023-01-23](https://docs.google.com/document/d/1gnJBTfY81fZYvI_QXjwKk1uQHYBNHGqRLI2BS_cYYNQ/edit?resourcekey=0-ql1Q1WvTcDvhycf8LbA9DQ&tab=t.0#heading=h.klm1hw3hfm1n) +and +[as part of the design of supporting `for` loops with C++ interop](https://docs.google.com/document/d/157k0s1e6qgTKUtads4x7BRtLHq8Xesh6DUHtbQ01gjY/edit?tab=t.0#heading=h.bs060kxctkgo). + +#### `match_first` in named constraints + +Consider a situation where an interface with variant parameters is used twice in +the constraint of a generic parameter, as in this example: + +```carbon +fn H[T:! call(_: i32) & call(_: i64)] + (g:? T, x: i16) { + // ❌ Ambiguous whether it uses + // `call(_: i32)` or `call(_:i64)`. + g(x); +} +``` + +Due to the allowed implicit conversions, it can be ambiguous which +implementation to use. In this example, the different implementations of `call` +could have different return types. Without a way to choose between them, the +compiler is forced to issue a diagnostic that the call is ambiguous. + +To resolve this ambiguity, we need additional information from the developer in +the constraint. Due to the difficulty of expressing this inline in a constraint +and a desire to avoid a second syntax for expressing the prioritization between +`impl`s, we've decided to express this out-of-line in a named constraint using +the same `match_first` syntax used to prioritize `impl`s outside this context. + +```carbon +constraint X[Self:! ParamForm] { + match_first { + require Self impls call(_: i32); + require Self impls call(_: i64); + } +} + +fn J[T:! X](g:? T, x: i16) { + // ✅ Uses `call(_: i32)`. + g(x); +} +``` + +This was discussed on +[2025-05-29](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?pli=1&tab=t.0#heading=h.dj0nqhfqo67w). + +#### `Core.Call` named constraint + +We can use these new features to define `Core.Call` as a named constraint that +acts like the interface before this proposal, for use cases where the extra +control over forms is not needed. + +```carbon +package Core; + +constraint Call(... each Param:! type) { + let Result:! type; + extend require impls + call[val](... _: each Param) -> Result; + // Equivalent to: + extend require impls + ValSelf( + CallPrimitive(... each form(val Param))) + where .ResultForm = form(var Result); +} +``` + +> FIXME: **QUESTION:** Is this redundant with providing `call`? Should instead +> this be dropped and `CallPrimitive` be renamed `Call`? Or do we want a +> non-primitive version to parallel other operator interfaces? + +### Interaction between `anchor`, `exact`, and named constraints + +Without named constraints, we would only use `anchor` and `exact` in impls and +only in the position of a variant parameter to the interface. With named +constraints, we could want to use them in two other cases: + +- A type parameter in a named constraint may end up being a variant form + argument to the underlying interface. For example, this would happen with + the named constraint `AddWith`, which delegates to `AddWithPrimitive`. To + support this, we might need to allow types to be marked with `anchor`. + Further, Carbon would have to propagate whether an expression uses `anchor` + as extra-type information that isn't used by type checking except if the + expression ends up being the variant argument to an interface. We might also + want to diagnose using `anchor` on a type in a way that doesn't end up being + used as a variant argument, but that seems hard to determine. +- If you have a constraint like `Add` which takes only the `Self` parameter + and uses it to set all of the variant interface parameters, it is better to + put `anchor` in `Add` than in all impls of `Add`. We could support this by + allowing `anchor` or `exact` before interface arguments in + `extend require impls` declarations in a named constraint. This would be + ignored when using it as a constraint, but are used in an `impl` of the + named constraint. + +> FIXME: **QUESTION:** Is there a way to avoid some of this complexity? + +This was discussed on +[2025-06-13](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.52ru7ner80b4). + +### Primitive indexing interface + +Proposal +[#2274: Subscript syntax and semantics](https://github.com/carbon-language/carbon-lang/pull/2274) +introduced the `IndexWith` and `IndirectIndexWith` interfaces. The rewrites from +a `lhs[index]` expression into invoking methods of interfaces depended on both +the category of the `lhs` part of the expression, and which interfaces were +implemented. This was complex due to lacking the tools for dispatching on +category provided by this proposal, and resulted in undesirable dependence on +the information that a particular interface was not implemented. Which meant +that the rewrite could change if another constraint was added. We compensated +with a `final impl` to make the two rewrites have type consistency. With the +tools of this proposal, however, we can take a simpler approach of having a +single interface, `IndexWithPrimitive`, that uses forms, and two different use +cases expressed using named constraints: + +- The `IndirectIndexWith` constraint has a single requirement: given a value + `Self` the indexing operator produces a reference result. +- The `IndexWith` constraint requires that both the `IndexValWith` and + `IndexRefWith` constraints be implemented. The `IndexValWith` constraint + provides a value result from indexing given a value `Self`, and the + `IndexRefWith` constraint provides a reference result given a reference + `Self`. In effect, using two implementations to provide + [`ref?` semantics](#ref). `IndexValWith` and `IndexRefWith` use + [`alias`es](#alias) to give different names (`At` and `Ref`) to the `Op` + functions of `IndexWithPrimitive` with different parameters. During `impl` + lookup, the `IndexRefWith` version will be preferred for reference + expression due to the rules for + [`implicit_into` interface parameter variance](#implicit_into-interface-parameter-variance). + Note that `IndexWith` may be used as parameter's constraint, but can't be + directly implemented, since we don't support implementing multiple + interfaces together (see + [leads issue #4566: Implementing multiple interfaces with a single `impl` definition](https://github.com/carbon-language/carbon-lang/issues/4566) + and + [proposal #5168: Forward `impl` declaration of an incomplete interface](https://github.com/carbon-language/carbon-lang/pull/5168)). + This gap in the design affects this operator, but will need to be addressed + separately as future work, possibly by either changing the rules for + implementing multiple interfaces or by using mixins to address this use + case. This was + [discussed on 2025-06-13](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.52ru7ner80b4). + +Observe that a type that defines an `impl` of `IndirectIndexWith` will also +satisfy the `IndexWith` constraint: + +- The "value `Self` returning a value" requirement can be satisfied due to the + [`implicit_from` associated constant variance](#implicit_from-variance) + allowing the reference return to be converted to a value return. +- The "reference `Self` returning a reference" requirement takes advantage of + [variance](#implicit_into-interface-parameter-variance) to support + converting the reference `Self` to the value expected by the `impl`. + +To support coherence, `IndexWithPrimitive` uses `implicit_into anchor` on the +`Self` parameter, since that is the parameter expected to be used to find the +`impl`. To support returning results that reference the `self` parameter, it is +marked `bound`. + +See [Indexing](/docs/design/expressions/indexing.md) for details. + +Switching the indexing interface to forms was +[discussed on 2025-06-10](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.stp5dpvithkz). + +### Primitive member binding interface + +Proposal +[#3720: Member binding operators](https://github.com/carbon-language/carbon-lang/pull/3720) +also introduced multiple interfaces in order to handle different expression +categories. We can now redefine them as named constraints, in terms of a general +`MemberBind` interface: + +```carbon +interface MemberBind(implicit_into LHS:! Core.Form) { + let implicit_from ResultForm:! Core.Form; + fn Op[self: Self](lhs:? LHS) ->? ResultForm; +} + +// Formerly BindToValue +constraint BindToVal(T:! type) { + let Result:! type; + extend requires impls + MemberBind(form(bound val T)) + where .ResultForm = form(val Result); +} + +constraint BindToRef(T:! type) { + let Result:! type; + extend requires impls + MemberBind(form(bound ref T)) + where .ResultForm = form(ref Result); +} + +constraint BindToType(T:! type) { + let Result:! type; + extend requires impls + MemberBind(formof(T)) + where .ResultForm = form(val Result); +} +``` + +Observe that this replicates the semantics of `BindToValue`, `BindToRef`, and +`BindToType` from #3720, including: + +- `BindToType` uses the value of the left argument, not the type. +- The [`implicit_into` variance](#implicit_into-interface-parameter-variance) + of the `LHS` parameter supports + [implicit conversions](p3720.md#inheritance-and-other-implicit-conversions). + +However, there are a few differences: + +- There is no longer a `Bind` interface used guarantee that the result type of + `BindToVal` and `BindToRef` would be the same. In fact the result type can + vary for a type when using `BindToType`. +- `BindToVal` will be used for reference expressions if `BindToRef` is not + implemented, avoiding the need to routinely implement both. + +In the future, `MemberBind` could be made into a form interface, but currently +there is no motivation to use anything other than the type of `Self` for `impl` +selection. Also the `ResultForm` used in `BindToType` should be marked +compile-time [once that is supported](#compile-time-calls). + +### Primitive conversion interfaces + +We also replace the conversion interfaces, `As` and `ImplicitAs` with form +interfaces `AsPrimitive` and `ImplicitAsPrimitive`. These continue to each have +a parameter that specifies destination _type_, but an associated constant (set +by the `impl`) determines the destination _form_. The destination form is +constrained to [have type matching](#any-form-with-this-type) the parameter. We +also define named constraints `As` and `ImplicitAs` that operate on types, as +before, for +[progressive disclosure](/docs/project/principles/progressive_disclosure.md). +See [`as` expressions](/docs/design/expressions/as_expressions.md#extensibility) +and +[implicit conversions](/docs/design/expressions/implicit_conversions.md#extensibility). + +These new capabilities allow us to support conversions that preserve category, +without workarounds unavailable to libraries, supporting our principle that +["All APIs are library APIs"](/docs/project/principles/library_apis_only.md). + +- Adapter types automatically implement `AsPrimitive`, which allows those + conversions to preserve category. +- Derived-to-base implicit conversions use `ImplicitAsPrimitive` to preserve + category. + +This was +[discussed on 2025-06-11](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.rebuyhkgncpq). + +#### with `partial` + +Using category allows both preserving category and limiting to those cases that +are safe when casting between a `partial` class type, and the whole class type: + +- Implicit conversion `C` \-\> `partial C` is allowed for any category, and + preserves category, so `form(val C)`, `form(ref C)`, and `form(var C)` all + implement `ImplicitAs(partial C)`, with a corresponding `.ResultForm`: + - For `form(val C)`, `.ResultForm = form(val partial C)`. + - For `form(ref C)`, `.ResultForm = form(ref partial C)`. + - For `form(var C)`, `.ResultForm = form(var partial C)`. +- Implicit conversion `partial C` \-\> `C` is only allowed only when the + source is an initializing expression. A `partial C` initializing expression + always has dynamic type `C`. With other expression categories, it could be a + derived type. + + - `form(var partial C)` `impls` + `ImplicitAs(C) where .ResultForm = form(var C)` + + ``` + fn F() -> partial C; + fn G(c: C); + // ✅ Allowed + G(F()); + ``` + +Other result categories are possible by doing a category conversion after the +implicit type conversion. + +This was discussed on +[2025-06-24](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.d985djkv6qti). + +#### with `const` + +Similarly with `const`, we can capture the fact that value expressions are +immutable, and therefore imply `const`. + +- Conversion `C` \-\> `const C` is allowed for any category and preserves + category. This is since we are using a meaning of `const` like C++ `const` + which means "not changed through this reference" rather than "reference to + something immutable." +- Conversion `const C` \-\> `C` is allowed for values. + - `form(val const C)` `impls` + `ImplicitAs(C) where .ResultForm = form(val C)` + - A value with `form(ref const C)` will be able to use that conversion due + to + [`implicit_into` variance](#implicit_into-interface-parameter-variance), + requiring a [value binding](/docs/design/values.md#value-binding). + +This was discussed on +[2025-06-24](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.d985djkv6qti). + +### Primitive versions of other operator interfaces + +In general, operator interfaces from before this proposal are replaced with a +named constraint to a new interface with a `Primitive` suffix. The new interface +uses `Core.Form` or [form facet types](#form-facet-types), often +`Core.NoRefForm`, where appropriate for parameters and associated constants +describing returns. Operators are rewritten to these new "Primitive" interfaces +instead. + +For example, the expression `a + b` used to be rewritten to +`a.(AddWith(typeof(b)).Op)(b)`, calling a member of the `AddWith` interface. It +is now rewritten to `a.(AddWithPrimitive(formof(b)).Op)(b)`, where +`AddWithPrimitive` is defined like so: + +```carbon +package Core; + +interface AddWithPrimitive[implicit_into Self:! NoRefForm] + (implicit_into P:! NoRefForm) { + let implicit_from ResultForm:! NoRefForm; + fn Op[self:? Self](rhs:? P) ->? ResultForm; +} +``` + +This "Primitive" interface has some changes: + +- Uses `Core.NoRefForm` instead of `type`. +- The parameters are marked + [`implicit_into`](#implicit_into-interface-parameter-variance). In some + cases the left parameter will also be marked + [`anchor`](#modifiers-for-coherence). +- The associated constant controlling the return is marked + [`implicit_from`](#implicit_from-variance). +- Uses [`:?`](#specifying-the-form-of-a-binding) and + [`->?`](#specifying-the-form-of-a-return) instead of `:` and `->`. + +For +[progressive disclosure](/docs/project/principles/progressive_disclosure.md), we +continue to provide `Core.AddWith` that uses types instead of forms, but it is +now a named constraint: + +```carbon +constraint AddWith(T:! type) { + let Result:! type; + + extend require impls ValSelf( + AddWithPrimitive(form(val T)) + where .ResultForm = form(var Result)); +} +``` + +The following interfaces are updated, with the changes applied to +[`/docs/design/`](/docs/design/): + +- In [Arithmetic](/docs/design/expressions/arithmetic.md#extensibility): + `Negate`, `AddWith`, `SubWith`, `MulWith`, `DivWith`, `ModWith`. +- In [Assignment](/docs/design/assignment.md#extensibility): `AssignWith`, + `AddAssignWith`, `SubAssignWith`, `MulAssignWith`, `DivAssignWith`, + `ModAssignWith`, `BitAndAssignWith`, `BitOrAssignWith`, `BitXorAssignWith`, + `LeftShiftAssignWith`, `RightShiftAssignWith`. These use `bound ref` for the + left argument, the form does not vary. `Inc` and `Dec` are unchanged. +- In + [Bitwise and shift operators](/docs/design/expressions/bitwise.md#extensibility): + `BitComplement`, `BitAndWith`, `BitOrWith`, `BitXorWith`, `LeftShiftWith`, + `RightShiftWith`. +- In + [Comparison operators](/docs/design/expressions/comparison_operators.md#extensibility): + `EqWith`, `OrderedWith`. + +Note that the common type interfaces are unchanged. + +### `auto` form + +If `auto` is used in a position where a `Core.Form` is expected, such as in a +`:?` binding or `->?` return, the whole form is deduced, not just the type. + +For `:? auto` parameters, specifically, the deduced form will not be `ref` +(using `val` instead) unless the argument expression is marked `ref`. See +[the "Deducing a form value" section](#deducing-a-form-value). + +#### `auto` form bindings + +This allows us to create a binding to another value without changing its phase +or category. + +```carbon +let x:? auto = y; +// Equivalent to (if it was allowed): +let [P:! Core.Form] x:? P = y; + +// In contrast, +let a: auto = b; +// only allows the type to vary +// and forces `a` to have value +// category and runtime phase. +``` + +This allows us to address the use case of creating a binding that is +[referentially transparent](https://en.wikipedia.org/wiki/Referential_transparency), +as considered in leads issues +[#996](https://github.com/carbon-language/carbon-lang/issues/996) and +[#1371](https://github.com/carbon-language/carbon-lang/issues/1371). For +example, if the `y` in the example is a reference expression, `x` will be a +reference binding to it. If `y` is a compile-time value, `x` will be the same +value, with the same phase. + +This was discussed on +[2025-05-07](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.4zbo49wg5rmk). + +#### Positional parameters + +[Positional parameters](/docs/design/lambdas.md#positional-parameters), +introduced in [proposal #3848](/proposals/p3848.md#positional-parameters), +previously had type `auto`. This proposal changes them to have `auto` form. So +`fn F {`...`}` acts as if it had signature `fn F(... _:? auto)`. This means that +an argument that is a reference expression that is modified by the function body +must be marked `ref`, as in: + +``` +var x: i32 = 1; +let IncBy: auto = fn { $0 += $1; }; +IncBy(ref x, 2); +Assert(x == 3); + +let Add: auto = fn => $0 + $1; +// Will deduce a value form since +// not marked `ref`: +Assert(Add(x, 3) == 6); +``` + +#### `alias` + +Prior to this proposal, `alias` is a construct we have been assuming would +operate purely in the domain of names, but has only been specified in a few +contexts. This approach has limitations that we need to address, as described in +[leads issue #502: "More powerful aliasing feature"](https://github.com/carbon-language/carbon-lang/issues/5028). +The highest priority here is being able to give a name to a member of a +specific. For example, we've frequently assumed that declarations like +`alias String = BasicString(u8);`, `alias T = i32;` (equivalent to +`alias T = Core.Int(32);`), and `alias X = C(i32).X;` would somehow be allowed. +So we give `alias` with a definition in terms of `let` bindings instead of +operating on names: + +> `alias A = B;` means `let A:? auto = B;` + +An `alias` declaration is allowed in these contexts: + +- at file scope or in the body of a function; +- in the body of a `class`, but only to define a compile-time constant; +- in the body of an `impl` in order to specify that an associated function is + to be implemented by an existing function; and +- in the body of an interface or named constraint, where the rewrite to `let` + is additionally given the `final` modifier. + +An `alias` declaration is not allowed when the right-hand side (`B`) is a +runtime expression, unless it is a reference expression with address known at +compile-time (such as the name of a variable). For example, + +```carbon +var v: i32 = 7; +// ✅ Allowed, reference expression with +// known address. +alias va = v; + +var arr: array(i32, 64); +// ❌ Invalid, reference expression with +// address unknown at compile time. +alias aa = arr[v]; + +// ❌ Invalid, non-reference runtime +// expression. +alias pa = v + 2; +``` + +We could support more runtime expressions if there is a demonstrated need as +future work, perhaps by capturing the right-hand side as a lambda. + +An `alias` may have an access modifier such as `private`, when allowed in that +scope. + +This was discussed on +[2025-06-03](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.hdj6hk4bwd2z). +This approach has the benefit of defining `alias` in terms of other Carbon +features, reducing the need to specify its semantics separately and removing a +situation where there was two ways to do something that were slightly different. + +Support for parameterized aliases is [future work](#parameterized-aliases). + +#### namespace aliases + +However, this definition of `alias` only works with first-class values. The good +news here is that almost everything we want to alias is first class, +particularly with +[proposal #3720](https://github.com/carbon-language/carbon-lang/pull/3720) which +made more entities like class and interface members first class. The main +exception is that we have no intention of making namespaces first class, because +the set of members is incoherent (different between libraries depending on what +they import) and in fact changes as new entities are declared in the namespace. +The solution is to, like C++, use another mechanism to alias namespaces. To this +end, we say that a `namespace` declaration may now optionally declare a +namespace alias by using a `=`: + +```carbon +// Previous syntax: declare a namespace +// `A.B`: +namespace A.B; + +// New syntax: declare `C` as an alias +// for namespace `A.B`: +namespace C = A.B; + +// New syntax: declare `D` as a private +// namespace alias: +private namespace D = A.B; +``` + +Aliases of namespaces that belong to other packages are restricted being +declared `private` or in an impl file. + +Support for parameterized aliases is [future work](#parameterized-aliases). + +#### `using` + +We define `using A.B.C;` to be a shorthand for `alias C = A.B.C;`. Note that the +argument is not required to have an periods, so `using D;` is the same as +`alias D = D;`, which creates an alias to a `D` found in a containing scope. +However, the expression must either be _something_`.`_word_ or a word by itself, +so that the resulting name is clear. + +Example: + +```carbon +class C { + class D {} +} + +class E(T:! type) { + // Equivalent to `alias D = C.D;`: + using C.D; + + // Equivalent to `alias C = package.C;`: + using C; + + // Afterward `E(X).T == X`. + using T; +} +``` + +#### `auto` form returns + +Using `->? auto` as the return of a function causes the return form, not just +type, to be determined by the form of the return expression. For example, +returning a reference expression will result in a `ref` return, as in: + +```carbon +// Equivalent to ...`-> ref i32`: +fn Id(bound ref x: i32) ->? auto { + return x; +} +``` + +Note that the `=>` return syntax introduced in +[proposal #3848](https://github.com/carbon-language/carbon-lang/pull/3848) is +not changed to deduce form, as decided in +[proposal #5434](/proposals/p5434.md#-infers-form-not-just-type). This still may +be revisited once the memory safety story is more developed. + +### Implicit conversions of `self` + +Consider a class with an alias to a method in another class, with an implicit +conversion between the two classes: + +```carbon +class Dog { + // Equivalent to: + // fn Bark[self: Dog](); + fn Bark[self: Self]() { + DoBark(); + } +} + +class Poodle { + impl as ImplicitAs(Dog) { + fn Convert[self: Self]() -> Dog { + return {}; + } + } + // Equivalent to + // `alias Bark = Dog.Bark;` + using Dog.Bark; +} + +var poodle: Poodle = {}; +// Equivalent to: +// ((poodle as Dog).(Dog.Bark))() +poodle.Bark(); +``` + +The implicit conversion of `poodle` to type `Dog` does not happen because of the +[`Core.CallPrimitive` interface](#primitive-call-interface). That interface +declares its `Self` parameter as `implicit_into anchor`, which means it won't +look for different types as part of `impl` lookup, which is important for +coherence. Instead, that implicit conversion happens as a result of the binding +of `poodle` to `Dog.Bark`, as part of the process described by +[proposal #3720: "Member binding operators"](https://github.com/carbon-language/carbon-lang/pull/3720) +when calling the `Op` method of the +[member binding interface](#primitive-member-binding-interface). In fact, there +is another conversion after that, to an adapter of `Dog` that implements +`Core.CallPrimitive` with the body of the `Dog.Bark` method. + +```carbon +class __TypeOf_Dog_Bark {} +let __Dog_Bark:! __TypeOf_Dog_Bark = {}; + +class __Binding_Dog_Bark { + adapt C; + impl as call[val]() -> () { + fn Op[self: Self]() { + DoBark(); + } + } +} + +impl __TypeOf_Dog_Bark as BindToRef(Dog) { + where Result = __Binding_Dog_Bark; + fn Op[self: Self](bound ref r: Dog) + -> ref __Binding_Dog_Bark { + return r as __Binding_Dog_Bark; + } +} + +impl __TypeOf_Dog_Bark as BindToVal(Dog) { + where Result = __Binding_Dog_Bark; + fn Op[self: Self](bound x: Dog) + -> val __Binding_Dog_Bark { + return x as __Binding_Dog_Bark; + } +} +``` + +Only after binding is complete and the `poodle` has been converted to a `Dog` is +the `CallPrimitive` implementation looked up as part of resolving the `()` +operation. That lookup will only find calls where the type of `Self` is `Dog`. + +This works with +[our approach of allowing implicit conversions with the `self` parameter](p3720.md#inheritance-and-other-implicit-conversions). +See extension methods +[leads issue #1345: "How is the type of me restricted, and where can methods be declared?"](https://github.com/carbon-language/carbon-lang/issues/1345) +and +[deferred proposal #1122](https://github.com/carbon-language/carbon-lang/pull/1122). + +## Details + +### Coherence modifier examples + +Given this package: + +```carbon +package P; + +interface J + (implicit_into P1:! Core.Form, + implicit_into P2:! Core.Form, + P3: Core.Form) { } + +class C {} + +// ✅ Allowed since `J` is local, even +// though `i32` is not. +impl i32 as + J(form(val i32), form(val i32), form(val i32)) {} +// As if 4 impls with type structure: +// - i32 as J(i32, i32, i32) +// - i32 as J(?, i32, i32) +// - i32 as J(i32, ?, i32) +// - i32 as J(?, ?, i32) +``` + +A library using the interface from that package needs to ensure all of the +notional `impl`s implied by these `impl` declarations reference a local type. +This means that there needs to be a reference to a local type: + +- in a parameter that is not in a `implicit_into` parameter of the interface, +- in a parameter that is an `exact` parameter of the `impl`, or +- in every parameter that is an `anchor` parameter of the `impl`. + +Note that the `Self` parameter before the `as` counts as a parameter for these +purposes, but local types in a `forall` clause do not. + +```carbon +import P; + +// ❌ Invalid since nothing is local. +impl bool as P.J(form(val P.C), + form(val P.C), + form(val P.C)) {} + +class D {} + +// ❌ Invalid since only local type is +// `D`, which is in `implicit_into` parameters. +impl i16 as P.J(form(val D), + form(val D), + form(val P.C)) {} +// As if 4 impls with type structure: +// - i16 as J(D, D, P.C) +// - i16 as J(?, D, P.C) +// - i16 as J(D, ?, P.C) +// - i16 as J(?, ?, P.C) <- problem + + +// ✅ Allowed: `D` is local and in a +// non-`implicit_into` parameter. +impl i8 as P.J(form(val P.C), + form(val P.C), + form(val D)) {} +// As if 4 impls with type structure: +// - i8 as J(P.C, P.C, D) +// - i8 as J(?, P.C, D) +// - i8 as J(P.C, ?, D) +// - i8 as J(?, ?, D) <- okay, has D + +// ✅ Allowed: `D` is local and in an +// `exact` parameter. +impl i64 as P.J(exact form(val D), + form(val P.C), + form(val P.C)) {} +// As if 2 impls with type structure: +// - i64 as J(D, P.C, P.C) +// - i64 as J(D, ?, P.C) <- okay, has D + +class E {} + +// ✅ Allowed: every `anchor` parameter +// has a local type. +impl u16 as P.J(anchor form(val D), + anchor form(val E), + form(val P.C)) {} +// As if 3 impls with type structure: +// - u16 as J(D, E, P.C) +// - u16 as J(?, E, P.C) <- okay, has E +// - u16 as J(D, ?, P.C) <- okay, has D +// No J(?, ?, P.C) due to `anchor` + +// ❌ Invalid since only one `anchor` is +// required to have type matching the +// query, and if it is the second +// `anchor`, then this declaration has +// no local type. +impl u32 as P.J(anchor form(val D), + anchor form(val P.C), + form(val P.C)) {} +// - u32 as J(D, P.C, P.C) +// - u32 as J(?, P.C, P.C) <- problem +// - u32 as J(D, ?, P.C) +// No J(?, ?, P.C) due to `anchor` +``` + +### Examples using `call` + +The `call` syntax may be used as the facet type in an `impl` to define the call +operator for a type, as in: + +```carbon +class OverloadedCallable { + var x: i32; +} + +// First impl: as a type facet type. +impl OverloadedCallable as + call[ref](_: i32) -> () { + fn Op[ref self: Self](d: i32) -> () { + self.x += d; + } +} + +// Second impl: as a `Core.Form` facet type. +// Equivalent to: +// impl form(val OverloadedCallable) as +// CallPrimitive() +// where .ResultForm = form(var i32) +impl form(val OverloadedCallable) as + call() -> i32 { + // `Self` is a `Core.Form` value equal to + // `form(val OverloadedCallable)` so + // `self:? Self` is the same as + // `self: OverloadedCallbale`. + fn Op[self:? Self]() -> i32 { + return self.x; + } +} + +var c: OverloadedCallable = {.x = 1}; + +// Uses first impl. +Assert(c() == 1); +// Uses second impl. +c(2); +// Uses first impl. +Assert(c() == 3); +``` + +These facet types may also be used as a constraint for a generic parameter: + +```carbon +// `call` followed by `[ref]` creates an +// ordinary type facet type +fn InvokeRef[T:! call[ref](_: i32) -> ()] + (ref f: T, arg: i32) { + f(arg); +} + +// `call` without `[`...`]` creates a +// `Core.Form` facet type. Category of `f` +// will be deduced from the argument. +fn InvokeForm[PF:! call() -> i32] + (f:? PF) -> i32 { + return f(); +} + +// Uses second impl. +InvokeRef(ref c, 4); +// Uses first impl. Must be `ref` to +// match the category of `c`, which is +// used to determine the `InvokeForm` +// parameter. +Assert(InvokeForm(ref c) == 7); +``` + +Note that the `ref` marker on arguments follows whether the category of the +parameter was eventually determined to be `ref`. `InvokeForm(c)` would be an +error instead of using value category. See +[alternative considered: "`ref` on an argument controls its category"](#ref-on-an-argument-controls-its-category). + +A `call` expression generates a constraint that matches the corresponding lambda +expression with `fn` instead of `call` and names for parameters instead of `_`: + +```carbon +var i: i32 = 0; +var lambda1: auto = + fn (x: i32) -> () { i += x }; +InvokeRef(ref lambda, 1); +let lambda2: auto = + fn () -> i32 { return i; }; +InvokeForm(lambda2) +``` + +### `impl` lookup for an interface with variant parameters + +There are a few changes needed to +[the current `impl` selection algorithm from proposal #5337](/proposals/p5337.md#impl-selection-algorithm): + +- The initial filter for `impl`s that have a compatible type structure for the + query is changed to allow differences in the type structure in the + [variant parameters](#implicit_into-interface-parameter-variance) to the + interface. +- If the interface or `impl` has [`anchor`](#modifiers-for-coherence) + parameters, at least one must have a type match with the query. +- If an `impl` passes those tests, its type structure must be determined so + the `impl` may be prioritized against other candidates. This is done + following the rules + [described in the proposal](#implicit_into-interface-parameter-variance). + +Note that the only observable semantics of `impl` lookup are the sequence of +`impl`s that are considered (including their order), and the `impl` that is +eventually matched. This allows the compiler to avoid work on other `impl`s if +it can prove they won't affect what's observable. + +### Conversions when calling a function argument + +One advantage of the approach of +[marking the variance on the interface parameter](#implicit_into-interface-parameter-variance) +instead of the approach prior to this proposal where the `impl` would be +parameterized to allow implicit conversions, is we can get implicit conversions +even when we can't have parameterized `impl`s. This comes up with function +parameters, and this proposal allows them to work similarly to ordinary function +calls: + +```carbon +fn IntArg(x: i32); + +fn ConcreteCall() { + // ✅ Performs implicit conversion from + // `Core.IntLiteral` to `i32`. + IntArg(7); +} + +fn GenericCall[FNT:! call[val](_: i32)](f: FNT) { + // Good to get the same conversion here, even + // though we don't (and can't) have a blanket + // `impl` that `f` accepts anything that + // implicitly converts to `i32`. + f(7); +} + +GenericCall(IntArg); +``` + +### Deducing a form value + +A `Core.Form` parameter is deducible from an argument expression, allowing it to +capture the argument's expression category, phase, and compile-time value (but +not whether it is `bound`). + +- A compile-time argument will deduce a constant `formof(N)`, including for + symbolic constants. +- An initializing expression argument will deduce a `var` form. +- A reference expression argument will deduce a `ref` form. + +```carbon +fn Deduced[PF:! Core.Form](arg:? PF); + +let l: bool = true; +// Deduces PF = form(val bool). +Deduced(l); + +var v: i32 = 4; +// Deduces PF = form(ref i32). +Deduced(v); + +// A call to `Make()` is an initializing expression. +fn Make() -> i32; + +// Deduces PF = form(var i32). +Deduced(Make()); + +// Deduces PF = formof(7). +Deduced(7); + +fn SymbolicN(N:! i32) { + // Deduces PF = formof(N). + F(N); +} +``` + +In contrast to [form facet type conversion](#form-facet-types), when a form +facet parameter is deduced, the compiler is willing to change categories to get +a legal value of the form facet type. + +- When deducing a `Core.NoValForm`, use category `var`/initializing instead of + `val`/value. +- When deducing a `Core.NoRefForm`, use category `val`/value instead of + `ref`/reference. +- When deducing a `Core.NoVarForm`, use category `val`/value instead of + `var`/initializing. + +```carbon +fn NoVar[P:! Core.NoVarForm](x:? P); + +// Deduces P = form(val i32) +NoVar(Make()); +``` + +If there is only one allowed destination category, that will be the category of +the result (as in `var`/initializing for `Core.NoValForm & Core.NoRefForm`). +However, this case would generally be better supported by a +[type facet type](#converting-from-a-form-facet-type-to-a-type-facet-type). + +An argument expression will only deduce a `ref` form if it is marked `ref`. +Otherwise, it is as if the parameter has a `& Core.NoRefForm` restriction. This +was discussed +[in #pointers-and-references on Discord on 2025-06-18](https://discord.com/channels/655572317891461132/753021843459538996/1385028689904926763). + +### Compile-time parameter equal to a specified value + +The [`:?` binding syntax](#specifying-the-form-of-a-binding) and +[`formof` operator for computing a form value](#formof) may be combined to write +a parameter binding that will only match a single specified value, as in: + +```carbon +// Argument must be a compile-time value equal to `i32` +fn F(_:? formof(i32)); + +// ✅ Allowed +F(i32); + +// ❌ not something with type `i32` +F(7 as i32); + +// ❌ not a different type +F(i16); + +fn G(T:! type) { + // ❌ not known to be `i32` + F(T); +} + +fn H(template T:! type) { + F(T); +} + +// ✅ Allowed +H(i32); + +// ❌ error substituting in `i16` for `T` +H(i16); +``` + +This was discussed on +[2025-05-13](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.bdznj2d0by2g). +It provides a resolution of +[Leads issue #578](https://github.com/carbon-language/carbon-lang/issues/578), +giving a method to work around ordering constraints on parameters: + +```carbon +fn DoACast[U:! type, T:! ImplicitAs(U)] + (x: T, _:? formof(U)) -> U { + return x as U; +} + +DoACast(7, i32); +``` + +This feature is also needed by this proposal to model +[explicit compile-time parameters](#representing-explicit-compile-time-parameters), +so they can be used in other parts of the signature. + +### Parameter requires exact type match + +We can also prevent implicit type conversions for a parameter. Recall that using +a deduced type means that the compiler won't consider types that implicitly +convert to that type, relying on deduction to match instead. If the deduced type +parameter is constrained to have a specific compile-time value using the +technique from +[the previous section](#compile-time-parameter-equal-to-a-specified-value), then +only that type will be permitted. + +For example: + +```carbon +// This function can only be passed values of type +// `bool`. `T` will be deduced from the argument +// type, but can only have the value `bool`. +fn ExactlyBool[T:? formof(bool)](x: T); + +// ✅ Allowed +ExactlyBool(true); +ExactlyBool(false); + +class Truthy { + impl as ImplicitAs(bool) { + fn Op[self: Self]() -> bool { return true; } + } +} +let truthy: Truthy = {}; + +// ❌ Invalid +ExactlyBool(truthy); +``` + +Note that this mechanism can be defeated. Of course wrapping the function will +do it: + +```carbon +fn BoolConversionFirst(x: bool) { + ExactlyBool(x); +} + +// ✅ Allowed +BoolConversionFirst(truthy); +``` + +More surprising is that passing `ExactlyBool` as a function parameter will also +lose the exact type match property. This is because it will use an +[adapter](#facets-create-adapters) with the signature declared in the type +parameter instead of what was declared for `ExactlyBool`: + +``` +fn ErasedByGeneric + [T:! call(_: bool) -> (), + U:! ImplicitAs(bool)](f:? T, x: U) { + // The deduction of parameters to `f` + // is done by this point, so nothing to + // prevent conversion of `x` to `bool`. + f(x); +} + +// `ExactlyBool`'s type does implement +// `call(_: bool) -> ()`. +ErasedByGeneric(ExactlyBool, t); +``` + +### Representing deduced parameters + +Observe that deduced parameters do not show up in the +[`Core.CallPrimitive` interface](#primitive-call-interface). They are not +modeled as part of the interface, but using parameterized `impl`s of that +interface. For example: + +```carbon +fn Ident[T:! type](x: T) -> T; +``` + +can be modeled as + +```carbon +class __Ident_Type {} +let Ident:! __Ident_Type = {}; +impl forall [T:! type] + form(val __Ident_Type) + as CallPrimitive(form(val T)) + where .ResultForm = form(var T); +``` + +or equivalently: + +```carbon +class __Ident_Type {} +let F:! __Ident_Type = {}; +impl forall [T:! type] __Ident_Type + as call[val](_: T) -> T; +``` + +This partially addresses the ["subsumption" problem](#problem), since this +`Ident` could be passed to this function: + +```carbon +fn GenericCall[FNT:! call[val](_: i32)](f: FNT); +``` + +This will succeed since when it looks to see if `__Ident_Type` implements +`call[val](_: i32)`, it will find that the parameterized `impl` does provide +that when `T` is `i32`. + +### Representing explicit compile-time parameters + +Explicit compile-time parameters are modeled the same way as deduced parameters, +except they also are included in the list of parameter forms passed to +`CallPrimitive`, using [`formof`](#formof). + +For example: + +```carbon +fn F(T:! type, x: T) -> T; +``` + +can be modeled as: + +```carbon +class __F_Type {} +let F:! __F_Type = {}; +impl forall [T:! type] form(val __F_Type) + as CallPrimitive(formof(T), + form(val T)) + where .ResultForm = form(var T); +``` + +or equivalently: + +```carbon +class __F_Type {} +let F:! __F_Type = {}; +impl forall [T:! type] __F_Type as + call[val](_:? formof(T), _: T) -> T; +``` + +### Callables that may or may not mutate + +In many cases, a function accepting a callable object will not care about +whether the call mutates the object. + +Consider an example of two callables, one that has no mutation, and one that +does: + +```carbon +fn CallbackNoMutation() -> i32 { + // https://xkcd.com/221/ + return 4; +} + +class Counter { + var count: i32; + impl as call[ref]() -> i32 { + fn Op[ref self: Self]() -> i32 { + self.count += 1; + return self.count; + } + } +} +var counter: Counter = {.count = 0}; +``` + +There are two approaches to accommodating this that are supported by the current +design. The function taking the callable object can be generic on its aspect in +the caller, as in: + +```carbon +fn GenericCaller[PF:! call() -> i32] + (f:? PF) -> i32 { + return f(); +} + +Assert(GenericCaller(CallbackNoMutation) == 4); +Assert(GenericCaller(counter) == 1); +``` + +Alternatively, we can have the function takes its argument by value, and make a +wrapper that holds a pointer to make the call: + +```carbon +// Only has to be defined once +class CalledThroughPointer(T:! type) { + var p: T*; +} + +fn CallThroughPointer[T:! type](p: T*) + -> CalledThroughPointer(T) { + return {.p = p}; +} + +impl forall + [... each P:! Core.Form, + // Or: `T:! call[ref](... _:? each P)` + T:! Core.RefSelf(Core.CallPrimitive(... each P))] + form(val CalledThroughPointer(T)) as + Core.CallPrimitive(... each P) { + where ResultForm = T.ResultForm; + fn [self: Self](... each param:? each P) ->? ResultForm { + return (*self.p)(... ~each param); + } +} + +// Or: `FNT:! Core.Call() where .Result = i32` +fn ValueCaller[FNT:! call[val]() -> i32](f: FNT) -> i32 { + return f(); +} + +Assert(ValueCaller(CallbackNoMutation) == 4); +Assert(ValueCaller(CallThroughPointer(&counter)) == 2); +``` + +NOTE: The `~` is there in anticipation of using moves to support forwarding, see +[the "Forwarding" section](#forwarding). + +The first, generic approach is a bit more convenient but means using forms. The +second approach only uses types once `CallThroughPointer` has been defined, but +is less convenient. Some may prefer the second approach since it makes it +explicit when the callable object may be mutated. + +### Forwarding + +Forwarding is where an argument is passed along generically, including aspects +of its form like category and phase. Input-to-input forwarding is where the +arguments passed to one function become the arguments passed to another. For +example, this `Apply` function takes a callable object and argument expressions +to call it with and performs the call: + +```carbon +fn Apply[... each ArgT:! Core.Form, + FNT:! call(... _:? each ArgT)] + (bound f:? FNT, + bound ... each arg:? each ArgT) + ->? FNT.ResultForm { + return (~f)(... ~each arg); +} +``` + +> **Note:** Forwarding of a `var` parameter will be supported by performing a +> destructive move when passing it as an argument, once that is supported. This +> is marked with `~` in the example. + +> **Note:** An expression with generic form need not specify `ref` when used as +> an argument. + +This works with `Apply` calling `f` once. To support multiple calls, we drop +support for using `var` parameters with initializing argument expressions: + +```carbon +fn Apply2[... each ArgT:! Core.NoVarForm, + FNT:! call(... _:? each ArgT) & + Core.NoVarForm] + (f:? FNT, ... each arg:? each ArgT) { + f(... each arg); + f(... each arg); +} +``` + +With this change, following the [rules of deduction](#deducing-a-form-value), +initializing expressions will be converted to values. + +Input-to-output forwarding is where argument forms are returned from a function, +as in: + +```carbon +fn Id[F:! Core.NoVarForm](bound x:? F) ->? F { + return x; +} +``` + +This requires `Core.NoVarForm`, since the calling convention for an initializing +return requires the ability to construct the return value at an address provided +by the caller for some types, different from the address the argument is passed +in. + +> **Future work:** Once supported, a requirement that the type be movable would +> allow preserving category, including for initializing expressions. Perhaps +> something like: +> +> ```carbon +> fn Moves +> [F:! Core.Form where .type impls Core.Move] +> (bound x:? F) ->? F { +> return ~x; +> } +> ``` + +This was discussed in open discussion: + +- [2025-05-07](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.4zbo49wg5rmk): + definition of `Apply` using the proposed form types +- [2025-05-08](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.vdognq1upsf5): + using `bound` to support non-initializing returns in `Apply` +- [2025-05-12](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.1mjh6unumnwu): + calling conventions limit forwarding for `var` forms + +#### Forwarding tuple parameters + +A tuple expression can have elements with different categories and other +different forms, not just different types. This proposal uses +[compound form values](#compound-form-values) to properly capture the form of +each element, so a tuple expression can be faithfully forwarded. Alternatives +where the type of an expression was kept separate from the other form aspects +struggled to capture this, see the +[discussion on 2025-05-07](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.4zbo49wg5rmk). + +The approach from this proposal allows functions that pass variable-length +argument lists using tuple patterns, such as this definition of `ApplySum` + +```carbon +// Multiple variadic parameters have to be passed as tuples. +fn ApplySum[... each ArgF:! Core.NoVarForm, + Fn:! call(... _:? each ArgF) -> i32 & Core.NoVarForm] + (f: Fn, + (... each a:? each ArgF), + (... each b:? each Argf)) -> i32 { + return f(... each a) + f(... each b); +} +``` + +to compose with the `Apply` function from +[the "forwarding" section](#forwarding), as in: + +```carbon +// Preserves the categories of the argument +// tuple expressions. +Apply(ApplySum, (...), (...)) +``` + +This works since the form deduced for the arguments of `Apply` can be a +composite form value that captures the form of each element of each tuple +argument. + +## Future work + +### Compile-time calls + +A function executed at compile time has a return value that will be determined +at compile time. This is a statement about the form of the function's return. +Ideally Carbon will support functions that can be executed either at compile or +run time (like C++'s +[`constexpr`](https://en.cppreference.com/w/cpp/language/constexpr.html)), and +compile-time functions (like C++'s +[`consteval`](https://en.cppreference.com/w/cpp/language/consteval.html)) that +aren't instantiated for every distinct compile-time input argument. + +This was +[discussed on 2025-06-03](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.hdj6hk4bwd2z). +In short, we expect: + +- To introduce another phase that represents a values that are constant, in + the sense of have a value determined at compile time, but where the value is + unavailable for typechecking. +- We will rename "runtime" to "execute time," to include the values of + functions whether they are executed at compile time or runtime. + +### Impl prioritization + +We still need to have a mechanism for picking an `impl` to use when there are +multiple with the most preferred type structure. This issue is now more acute +with forms, since there is more non-type information that can now appear in an +`impl` signature. Resolving this question will allow us to support +prioritization across the `CallPrimitive` implementations for a type, which is +how we expect to support selecting an overload from a function overload set. + +### Parameterized aliases + +Just like +[C++ supports parameterized type aliases](https://en.cppreference.com/w/cpp/language/type_alias.html), +it would be useful for Carbon to support parameterized aliases. These would act +a bit like functions, except that the arguments to the alias may be deduced. For +example, this generic `Double` alias: + +```carbon +alias Double(T:! type) = (T, T) as type; +``` + +would allow you to define a function that accepted any pair of two values of the +same type: + +```carbon +// `T` is deduced from the argument type. +fn SumPair[T:! Add](p: Double(T)) -> T { + return p.0 + p.1; +} + +let three: i32 = 3; +Assert(SumPair((three, three)) == 6); +``` + +A parameterized alias was mentioned in +[proposal #2875](p2875.md#function-pointers) as a way to define a parameterized +`FunctionPtr` type. + +### `ref?` + +We would like to support being generic across `val` and `ref` for accessor +functions -- where the `self` and the return are both `val` or both `ref`. One +issue is we can do input-to-input, output-to-output, and output-to-input +forwarding of all three categories, but accessors want to do input-to-output +forwarding, which we can't do for initializing expressions. One possibility +would be to define a special syntax for just this case like `ref?`, as in: + +```carbon +class C { + private var x: D; + fn AccessX[ref? self: Self]() -> ref? D { + return self.x; + } +} +``` + +This would be equivalent to an overload of the two versions of the function. +`ref?` would have to be used on at least one explicit or `self` parameter, and +the `ref` version would be used if all of those arguments were reference +expressions (we might require explicit argument to be marked with `ref`). An +initializing expression counts as a `val` expression for those purposes, since +`ref` would mean enabling mutation of a temporary. + +On +[2025-09-04](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.ruyknn9cg56v), +we discussed that this feature would also be useful in an `impl` to implement +the same form interface twice. + +Is it a flaw in the design that `ref?` looks to be a useful form genericity, but +is not well supported without a separate feature? We see this use case coming up +with indexing, where indexing into an array gives you a reference if you started +with a reference to the array, and a value if you started with a value. + +One possible approach would be to have something like: + +```carbon +fn AccessX[PF:! ValOrRef(Self), self:? PF]() ->? FormWithCategory(PF, D); +``` + +`ValOrRef(Self)` (passed a type and returns a form facet type) is equivalent to +`Core.NoVarForm where .type = Self`. However, we are missing `FormWithCategory` +(passed a `Form` and a type, returns a form value), and the machinery to +definition check this generically. This option was considered in +[discussion on 2025-05-13](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.bdznj2d0by2g). + +A C++-like approach would be to have conditional versions of our existing `var`, +`ref`, `template`, `bound` keywords, perhaps with a trailing `_`: + +```carbon +fn AccessX[IsRef:! bool, + ref_(IsRef) self: Self]() + -> ref_(IsRef) D; +``` + +This last option was discussed on +[2025-06-09](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.xktpa55flu0z). + +### Allow more variance + +If motivated by use cases, we could add support for `implicit_into` variance on +associated constants, or variance on types, not just forms. This would be above +and beyond types that are eventually used to construct a form, as considered in +[the "Interaction between `anchor`, `exact`, and named constraints" section](#interaction-between-anchor-exact-and-named-constraints). + +## Rationale + +This advances [Carbon's goals](/docs/project/goals.md): + +- [Code that is easy to read, understand, and write](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write): + This proposal allows some programs and APIs to be written that couldn't + otherwise be expressed in Carbon. +- [Practical safety and testing mechanisms](/docs/project/goals.md#practical-safety-and-testing-mechanisms): + The increased expressivity of forms allows us to prevent some bugs. For + example, limiting conversion of `partial` types to initializing expressions + avoids misuses of those values. + +It does this while adhering to [Carbon's principles](/docs/project/principles): + +- [Principle: All APIs are library APIs](/docs/project/principles/library_apis_only.md): + This machinery allows many more constructs to be expressed within the + language as opposed to being special capabilities only available to + built-ins. This includes abilities like how conversion to an adapter type + can preserve category. +- [Principle: Progressive disclosure](/docs/project/principles/progressive_disclosure.md): + Developers don't need to be aware of this machinery unless they are engaged + in code that needs these advanced features. + +## Alternatives considered + +### Decoupling type from the rest of the form + +The goal of this approach was to avoid introducing form interfaces. Instead, the +non-type parts of the form could passed in as a separate parameter to supplement +the `Self` type. This ran into a few problems though: + +- It didn't support compound forms well, and as a result had trouble + supporting some forwarding use cases. +- For the compile-time value form `formof(N)`, the additional information + beyond the type includes a value of that type. As a result, the additional + information was parameterized by the type, which was complex and introduced + dependency cycles in some cases. + +There are cases where we still would like to separately specify type from the +rest of the form, but we do that without a representation for the rest of the +form. See [the "any form with this type" section](#any-form-with-this-type). + +This was discussed on +[2025-05-07](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.4zbo49wg5rmk) +and +[2025-06-11](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.rebuyhkgncpq). + +### Other ways to write "any form with a specified type" + +We +[considered on 2025-06-11](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.rebuyhkgncpq) +other ways of specifying any form with a specified type than +[the `Core.Form where .type` approach we settled on](#any-form-with-this-type). + +One approach was to have a constraint `FormWithType(``)`. However, the +approach we settled on more naturally supported +[getting the type from the form using `.type`](#forms-in-impls), which +[we wanted to work with other rewrite constraints](https://discord.com/channels/655572317891461132/941071822756143115/1381487716776022107). + +The other approach we considered was decomposing forms into types and and +non-type information, which ran into the problem that +[the non-type information depended on the type](#decoupling-type-from-the-rest-of-the-form). + +### Don't have types that represent all binding information + +We could have aspects of bindings without reflecting them into the type system. +For example, Swift has reference bindings, but does not represent references in +its type system. This means no way to do perfect forwarding. More significantly +to Carbon, it would mean we wouldn't have a way to represent calls using an +interface. This was +[discussed on 2025-05-28](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.9pvtvm7atpo5). + +### Represent all form information in ordinary types + +We could represent the additional information present in forms in types. This +would avoid splitting constructs, such as different kinds of interfaces for +types and forms. The concern is that there are cases where we want to consider +type separate from the other aspects of form. Further, we want the rules for +forms to be different than types. For example, category and phase are +independent, not ordered like type composition. Also, different categories are +mutually exclusive. + +Additionally, having forms separate from types means we can hide some complexity +from people learning the language under +[progressive disclosure](/docs/project/principles/progressive_disclosure.md). + +This was +[discussed on 2025-05-28](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.9pvtvm7atpo5). + +### Different form types for parameters and returns + +We originally considered using different types for the forms used in parameters +and returns. This allowed some modelling of the differences, for example between +`var` parameters and initializing returns, see the discussions on +[2025-05-14](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.52tb7l2he343) +and +[2025-05-13](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.bdznj2d0by2g). +Ultimately this led to a proliferation of different form types, increasing +complexity in area that is already quite complex. Merging has some downsides, +for example that memory safety and compile-time value information is only +currently used for parameter, but in +[a discussion on 2025-06-03](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.hdj6hk4bwd2z) +we determined that is expected to change once we support +[functions executed at compile-time](#compile-time-calls). + +The additional type information couldn't be used to determine the variance of a +form parameter, since forms after `:?` can appear in positions with different +variance, as +[discussed on 2025-06-24](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.dqgfbeb33txh). + +Example: + +```carbon +interface CallbackRegistry(PF:! Core.Form) { + fn Register[T:! CallPrimitive(PF)](f:? T); +} + +class CR { } +impl CR as CallbackRegistry(form(val i32)) { + fn Register[T:! call(_: i32)](f:? T) { + let i: i32 = 999999; + f(i); + } +} + +fn F(x: i16); + +fn G(U:! CallbackRegistry(_: i16)) { + U.Register(F); +} + +// Type error: calling `F` with an `i32` value. +G(CR); +``` + +In this next example, `PF` needs to be invariant, since it is used in both +covariant and contravariant positions: + +```carbon +interface J(PF:! Core.Form) { + fn F(c: C(PF)); + fn G() -> C(PF); +} +``` + +### Implicit conversion from `type` to `Core.Form` + +We originally defined an implicit conversion from type to form, for example in +[discussion on 2025-05-08](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.vdognq1upsf5). +Originally this would result in a value form, which would allow briefer +specification of the parameters or return for `CallPrimitive`. However, in +[discussion on 2025-05-14](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.52tb7l2he343) +we decided against having any implicit conversion, for a few reasons: + +- The natural default for parameter forms (value) is a different from return + forms (initializing). Picking one would lead to confusion when using the + other. Making it different somehow using contextual information would lead + to inconsistencies that were also expected to be confusing. +- It did not allow you to deal only in types instead of using forms in any use + case we foresaw. +- Forms are an advanced feature that is expected to be used rarely. As a + result, brevity is not as valuable, and readers are less likely to be + familiar with which default would be used. The `CallPrimitive` use case is + already well supported by using [`call` sugar](#call) instead. +- Using the implicit conversion for specifying arguments to `CallPrimitive` + could lead to ambiguity. For example `CallPrimitive((T, U))` could be + equivalent to `call((_: T, _: U))` or `call(_: (T, U))`. + +### Other ways to determine variance in interfaces + +We first considered `in` and `out` (such as in discussions on +[2025-05-28](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.9pvtvm7atpo5) +and +[2025-05-29](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?pli=1&tab=t.0#heading=h.dj0nqhfqo67w)) +to mark the different kinds of variance instead of +[`implicit_into`](#implicit_into-interface-parameter-variance) and +[`implicit_from`](#implicit_from-variance), following other languages such as +Scala, Kotlin, Typescript, and C#. We +[decided to switch 2025-06-24](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.dqgfbeb33txh) +that `in` and `out` were particularly expensive words to reserve, and which +corresponded to each kind of variance was hard to remember. The chosen keywords +are intended to emphasize what implicit conversion will be used. + +We also considered making the variance keyword part of the parameter name, much +like `each` on variadic parameters. This seemed unnecessary verbosity given +that: + +- the compiler would enforce that the variance was consistent with usage, + there was no choice about what variance to use in a given position; and +- the `impl` you write is actual `impl` you get, there is just there's another + layer around it. + +We considered inferring variance, or just marking that there was variance and +inferring only the direction of variance. This had some downsides: + +- Variance comes with significantly different semantics, causing + [facets to create adapters](#facets-create-adapters), so better if it is opt + in. +- Don't always want variance, for example since it requires extra annotations + on impls to avoid coherence problems. +- It goes against our + ["signature is the contract" (proposed) Carbon principle](https://github.com/carbon-language/carbon-lang/pull/5990). + FIXME: update link when merged. This is our general policy of not + determining properties of parameters based on how they are used in the body + of the definition: + - This allows forward declarations to have the information needed to be + used. + - Avoids action at a distance. For example, having to look at the body of + the interface and referenced interfaces. + - Makes the contract visible and explicit. + - Avoids potentially expensive reasoning when there are recursive + references to the containing type. + +### Support implicit conversions in impls + +The support for implicit conversions prior to this proposal was provided by +parameterizing an `impl` so that it also applied to types that could be +implicitly converted from. This had the downside that the following code is an +error: + +```carbon +fn F[T:! call[val](_: i32)->bool](f: T) -> bool { + // Error: `T` supports `i32` arguments, not + // `Core.IntLiteral`. + return f(7); +} +``` + +Given Carbon's reliance on implicit conversions in various contexts, this was +considered important to address. We did not see a path to addressing this by +adding `forall` requirements that the impls providing the implicit conversions +exist. The issue is that those would be very hard to satisfy in the presence of +specialization. In addition, `forall` constraint would preclude being called +with an overload set with overlap in arities. In general, the concern is that +there is nothing preventing the creation of a new library with a new type that +implicitly converts to the parameter types of both members of the overload set. +This would be an evolution hazard. + +This was +[discussed on 2025-05-28](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.9pvtvm7atpo5). + +### Infer `anchor` in `impl` declarations + +The `anchor` annotation could be inferred instead of marked explicitly by which +types mentioned in the `impl` declaration are local to that file. That has some +downsides: + +- It causes the `impl` declaration to be sensitive to declarations that can be + anywhere earlier in the same file. This causes readers of the code to need + to scan the rest of the file to understand the which arguments need a type + match, and makes the impact of changes less local. This is against the + ["low context-sensitivity" principle](/docs/project/principles/low_context_sensitivity.md). +- This would cause semantic changes when concatenating files, for example to + make a bug report. In particular, more types could then be used as anchors + for satisfying the orphan rule. This is against the + ["file concatenation should preserve meaning" (proposed) principle](https://github.com/carbon-language/carbon-lang/pull/6031). + FIXME: update link when merged. + +This was +[discussed on 2025-05-28](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.9pvtvm7atpo5). + +### Different form literal syntax + +In a +[discussion on 2025-06-04](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.stp5dpvithkz), +we considered other ways to write the form of a specific compile-time value, +like `7 as i32`. We considered using the `form(`...`)` with an introducer before +an expression that evaluates to the value: + +- `form(== 7 as i32)` +- `form(=> 7 as i32)` +- `form(is 7 as i32)` + +Of these, `form(=> 7 as i32)` was the most promising, since it matched the +syntax for returning an expression from a function or `case`. The `is` keyword +was considered too expensive to introduce just for this use. + +We also considered using no introducer inside `form(`...`)`, as in +`form(7 as i32)`, but it had some downsides: + +- Required lookahead when parsing. +- We didn't want `form(i32)` to be legal and mean something other than + `form(val i32)`, which is more likely what the code author intended. + +Ultimately we didn't think that this was a common case that needed to be short. + +We settled on [the `formof` approach](#formof). We expect that `formof(`...`)` +will be a valuable construct that we want outside of for compile-time value +forms. + +For compound forms, we first tried to represent them using parens `(`...`)` and +curly braces `{`...`}` inside the `form(`...`)`. There was some concern about +ambiguity between the `()` value and the empty tuple form, similarly for `{}`, +but that was addressed by switching to `formof` for compile-time constant +values. However, the switch to `formof` meant that we needed a way to combine +`form(`...`)` and `formof(`...`)` expressions to create a compound form value. +The [compound form approach we settled on](#compound-form-values) had the +advantage of supporting all the composition we wanted without needing any +dedicated syntax. It is a bit verbose, but that is perhaps acceptable given that +this isn't a commonly used construct. It mirrored our approach for tuple types, +but not for struct types. + +In a +[discussion on 2025-06-05](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.itqt68gnfeob) +we considered `form(-> T)` instead of `form(var T)`, but we wanted to be +consistent about using keyword introducers for the different categories. We also +considered `form(init T)`, which was better for returns but worse for +parameters, but was not worth making `init` into a keyword. + +In that discussion, we also considered `form(T)` instead of `form(val T)`, but +it seemed like it would lead to mistakes for returns where `val` was not the +default. + +### `ref` on an argument controls its category + +We considered an approach where `ref` on an argument would control whether a +reference expression was converted to a value expression before overload +resolution. Consider this example (using the overloading syntax proposed in +[discussion on 2025-03-28](https://docs.google.com/document/d/1Iut5f2TQBrtBNIduF4vJYOKfw7MbS8xH_J01_Q4e6Rk/edit?resourcekey=0-mc_vh5UzrzXfU4kO-3tOjA&tab=t.0#heading=h.t6l733mu79i7)): + +```carbon +overload F { + // Overload R + fn (ref r: i32) -> i32; + // Overload V + fn (v: i32) -> bool; +} + +var a: i32 = 1; +F(a); +``` + +With this approach, the call to `F` would convert the reference expression `a` +into a value before overload resolution and select "Overload V." + +We instead decided that `ref` on an argument only affects deduction. In this +model, the call to `F` would instead select "Overload R" and then give an error +because the call site does not mark the argument with the `ref` keyword. This +means an overload set with different parameter categories behaves differently +than a function that allows the category to vary using form generics. The +benefits of this decision are that this approach: + +- makes `ref` more like a readability annotation than a category cast; +- makes `ref` argument marking easier to remove as part of language evolution; +- makes pattern matching of argument to function parameters more consistent + with other pattern matching contexts; and +- didn't introduce concerns about converting to a value interfering with + converting the argument to the parameter's type. + +This was discussed on +[2025-05-28](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.9pvtvm7atpo5) +and in +[the #pointers-and-references Discord channel](https://discord.com/channels/655572317891461132/753021843459538996/1377506479355203635). + +### Replace `require` for interface-interface requirements + +In some cases, a `require` declaration in an interface to add a constraint that +another interface must be implemented, as in: + +```carbon +interface J {} + +interface I { + require impls J; +} +``` + +is equivalent to an interface with a constraint on `Self`: + +```carbon +interface I[Self:! J] {} +``` + +This however had concerns which encouraged us to keep using `require`: + +- It raised questions about how qualified name lookup into `Self` would work. +- We preferred these requirements to be expressed in the body of the interface + definition, not declaration, from a reading perspective. +- Having the requirements in the declaration added restrictions on `I`'s + declaration. + +This was discussed on +[2025-05-08](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.vdognq1upsf5).