mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Assisted-by: Gemini via Antigravity Co-authored-by: Josh L <josh11b@users.noreply.github.com>
This commit is contained in:
+19
-2
@@ -799,13 +799,17 @@ class GraphNode {
|
||||
// `GraphNode` is first complete here.
|
||||
```
|
||||
|
||||
**Open question:** What is specifically allowed and forbidden with an incomplete
|
||||
type has not yet been decided.
|
||||
An incomplete type cannot be used as the target of an `extend` declaration (such
|
||||
as `extend base: T` or `extend adapt T`), as the target type must be complete to
|
||||
allow name lookup into it.
|
||||
|
||||
> **TODO:** Document that qualified names can be looked up in an incomplete
|
||||
> type, as adopted in
|
||||
> [#5087: Qualified lookup into types being defined](/proposals/p005087-qualified-lookup-into-types-being-defined.md).
|
||||
|
||||
**Open question:** What else is specifically allowed and forbidden with an
|
||||
incomplete type has not yet been decided.
|
||||
|
||||
### `Self`
|
||||
|
||||
A `class` definition may provisionally include references to its own name in
|
||||
@@ -1230,6 +1234,19 @@ class FinalDerived {
|
||||
// may not extend `FinalDerived` since not declared `base` or `abstract`.
|
||||
```
|
||||
|
||||
An `extend base` declaration requires the specified base class to be complete at
|
||||
the point where the declaration is written, to allow name lookup to search into
|
||||
the base class.
|
||||
|
||||
```
|
||||
base class Incomplete;
|
||||
|
||||
class InvalidDerived {
|
||||
// ❌ Forbidden: `Incomplete` is not complete.
|
||||
extend base: Incomplete;
|
||||
}
|
||||
```
|
||||
|
||||
An _[abstract class](https://en.wikipedia.org/wiki/Abstract_type)_ or _abstract
|
||||
base class_ is a base class that may not be instantiated.
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
- [Member resolution](#member-resolution)
|
||||
- [Package and namespace members](#package-and-namespace-members)
|
||||
- [Types, forms, and facets](#types-forms-and-facets)
|
||||
- [`extend`](#extend)
|
||||
- [Tuple indexing](#tuple-indexing)
|
||||
- [Values](#values)
|
||||
- [Facet binding](#facet-binding)
|
||||
@@ -238,6 +239,85 @@ implementation for `Avatar`, ignoring `Renderable.Draw`.
|
||||
Similarly, a form has members, specifically the members of the form's type
|
||||
component.
|
||||
|
||||
#### `extend`
|
||||
|
||||
An `extend` declaration declares that the enclosing scope extends the scope
|
||||
associated with any target entity named in the declaration. That is to say name
|
||||
lookups into the enclosing scope will also look into the scopes which are
|
||||
nominated by the `extend` declaration. The `extend` declaration requires that
|
||||
the target scopes named in an `extend` declaration are complete, or if the
|
||||
target is a generic parameter, requires the type of the parameter to be
|
||||
complete.
|
||||
|
||||
To `extend` an entity `Y` with another `Z` means that name lookups into `Y` will
|
||||
also look into `Z`. Immediately after the `extend` operation, members of `Z`
|
||||
should also be found when doing name lookup into `Y`, both from outside and from
|
||||
inside the definition of `Y`. In order to be able to perform lookups into `Z`,
|
||||
we require that `extend` operations only target scopes that are complete.
|
||||
|
||||
This requirement functions recursively. Given an interface `B` that extends
|
||||
another interface `A`: By naming `A` in an extend declaration, we require `A` is
|
||||
complete. This provides that its entire definition is known, and thus its
|
||||
`extend` relationship to `B`. The `extend` relationship there also provides that
|
||||
`B` is complete.
|
||||
|
||||
If the target scope of an `extend` declaration is a generic parameter, its type
|
||||
must be complete where the `extend` declaration is written, as name lookups into
|
||||
the extended scope will look into the type of the generic parameter.
|
||||
|
||||
```carbon
|
||||
interface I {
|
||||
fn F();
|
||||
}
|
||||
|
||||
class C(T:! I) {
|
||||
extend base: T;
|
||||
// `F` names `T.F` here, found in `I`.
|
||||
fn G() { F(); }
|
||||
}
|
||||
```
|
||||
|
||||
As any generic parameter in the enclosing scope is replaced by a more specific
|
||||
value, extended scopes that depend on a generic parameter must remain complete.
|
||||
This includes forming a specific for the extended scope involving the parameter
|
||||
in order to surface any monomorphization errors in the resulting specific.
|
||||
|
||||
In the next example, the `extend` declaration in interface `A(N)` names a
|
||||
symbolic facet type which can produce monomorphization errors when a negative
|
||||
value is provided for `N`. When a more specific value for the target `B(N)` is
|
||||
provided, we require the specific value to be complete as well by forming the
|
||||
specific. A diagnostic error would be produced while checking `C(-1)` for
|
||||
completeness, as it requires `A(-1)` to be complete, which requires
|
||||
`B(array(i32, -1))` to be complete, and that contains an invalid type.
|
||||
|
||||
```carbon
|
||||
interface B(T:! type) {}
|
||||
|
||||
interface A(N:! i32) {
|
||||
// Requires `B(N)` to be complete.
|
||||
extend require impls B(array(i32, N)) {}
|
||||
}
|
||||
|
||||
class C(N! i32) {
|
||||
// Requires `A(N)` to be complete, which requires `B(N)` to be complete.
|
||||
extend impl as A(N);
|
||||
}
|
||||
|
||||
fn F() {
|
||||
// Requires `C(-1)` to be complete, which requires `A(-1)` to be complete, which requires `B(array(i32, -1))` to be complete.
|
||||
var c: C(-1);
|
||||
}
|
||||
```
|
||||
|
||||
These rules prohibit an `extend` declaration from naming its enclosing scope,
|
||||
since by being part of the definition of that scope, it is implied that the
|
||||
enclosing scope is not complete. This seems reasonable as all names available
|
||||
inside the enclosing interface or named constraint are already available or
|
||||
would conflict with the ones that are.
|
||||
|
||||
> **Alternative considered:** >
|
||||
> [Not requiring the target scope to be complete immediately](/proposals/p006395-type-completeness-in-extend.md#alternatives-considered).
|
||||
|
||||
### Tuple indexing
|
||||
|
||||
Tuple types have member names that are *integer-literal*s, not *word*s.
|
||||
@@ -959,3 +1039,5 @@ var n: i32 = 1 + X.Y;
|
||||
[#2360: Types are values of type `type`](https://github.com/carbon-language/carbon-lang/pull/2360)
|
||||
- Proposal
|
||||
[#2550: Simplified package declaration for the `Main` package](https://github.com/carbon-language/carbon-lang/pull/2550)
|
||||
- Proposal
|
||||
[#6395: Type completeness in extend](https://github.com/carbon-language/carbon-lang/pull/6395)
|
||||
|
||||
@@ -310,6 +310,9 @@ Assert(p1.Scale(2.0) == p2);
|
||||
Assert(p1.Add(p1) == p2);
|
||||
```
|
||||
|
||||
For more on how `extend` affects member access, see
|
||||
[member access](../expressions/member_access.md#extend).
|
||||
|
||||
Without `extend`, those methods may only be accessed with
|
||||
[qualified member names and compound member access](#qualified-member-names-and-compound-member-access):
|
||||
|
||||
@@ -506,6 +509,9 @@ class Player {
|
||||
|
||||
### Avoiding name collisions
|
||||
|
||||
> **TODO:** This has changed. Now you can always extend, but conflicting names
|
||||
> may only be found by qualified name lookup.
|
||||
|
||||
To avoid name collisions, you can't extend implementations of two interfaces
|
||||
that have a name in common:
|
||||
|
||||
@@ -1041,6 +1047,8 @@ var s: String = "string";
|
||||
var p_s: String = Identity(&s);
|
||||
```
|
||||
|
||||
The facet type `type` is associated with an empty scope and is complete.
|
||||
|
||||
In general, the declarations in `constraint` definition match a subset of the
|
||||
declarations in an `interface`. These named constraints can be used with checked
|
||||
generics, as opposed to templates, and only include required interfaces and
|
||||
@@ -1251,6 +1259,10 @@ Note that the expressions `A & B` and `A where .Self impls B` have the same
|
||||
requirements, and so you would be able to switch a function declaration between
|
||||
them without affecting callers.
|
||||
|
||||
The scope of a facet type formed by a `&` operator extends the scopes of both of
|
||||
its operands. The scope of the resulting facet type is complete if every scope
|
||||
it extends is complete.
|
||||
|
||||
**Alternatives considered:** See
|
||||
[Carbon: Access to interface methods](https://docs.google.com/document/d/17IXDdu384x1t9RimQ01bhx4-nWzs4ZEeke4eO6ImQNc/edit?resourcekey=0-Fe44R-0DhQBlw0gs2ujNJA).
|
||||
|
||||
@@ -1347,6 +1359,8 @@ fn DoHashAndEquals[T:! Hashable](x: T) {
|
||||
> **TODO:** Update this section as needed to reflect the fact that an impl of an
|
||||
> interface doesn't impl the interfaces it extends, as adopted in
|
||||
> [#5168: Forward `impl` declaration of an incomplete interface](/proposals/p005168-forward-impl-declaration-of-an-incomplete-interface.md).
|
||||
> Should link to
|
||||
> [`extend` in member access](../expressions/member_access.md#extend).
|
||||
|
||||
When implementing an interface, we allow implementing the aliased names as well.
|
||||
In the case of `Hashable` above, this includes all the members of `Equatable`,
|
||||
@@ -1864,7 +1878,9 @@ Frequently we expect that the adapter type will want to preserve most or all of
|
||||
the API of the original type. The two most common cases expected are adding and
|
||||
replacing an interface implementation. Users would indicate that an adapter
|
||||
starts from the original type's existing API by using the `extend` keyword
|
||||
before `adapt`:
|
||||
before `adapt`, which
|
||||
[extends member access to lookup names in the adapted class](../expressions/member_access.md#extend)
|
||||
along with `impl` lookup:
|
||||
|
||||
```carbon
|
||||
class Song {
|
||||
@@ -1898,8 +1914,10 @@ functions can be cast to the corresponding type with `SongByArtist` substituted
|
||||
in for `Song`.
|
||||
|
||||
Unlike the similar `class B { extend base: A; }` notation,
|
||||
`class B { extend adapt A; }` is permitted even if `A` is a final class. Also,
|
||||
there is no implicit conversion from `B` to `A`, matching `adapt` without
|
||||
`class B { extend adapt A; }` is permitted even if `A` is a final class. Like
|
||||
other `extend` declarations, it requires the target `A` to be complete, or if
|
||||
`A` is a generic parameter, requires the type of the parameter to be complete.
|
||||
Also, there is no implicit conversion from `B` to `A`, matching `adapt` without
|
||||
`extend` but unlike class extension.
|
||||
|
||||
To avoid or resolve name conflicts between interfaces, an `impl` may be declared
|
||||
@@ -2651,6 +2669,11 @@ between different type variables, such as that a member of one is equal to a
|
||||
member of another. The `where` operator is not associative, so a type expression
|
||||
using multiple must use round parens `(`...`)` to specify grouping.
|
||||
|
||||
The scope of a facet type formed by a `where` declaration
|
||||
[extends](../expressions/member_access.md#extend) the scope of its first
|
||||
operand, and the resulting facet type is complete if that scope it extends is
|
||||
complete.
|
||||
|
||||
> **Comparison with other languages:** Both Swift and Rust use `where` clauses
|
||||
> on declarations instead of in the expression syntax. These happen after the
|
||||
> type that is being constrained has been given a name and use that name to
|
||||
@@ -5379,32 +5402,15 @@ An incomplete `C` cannot be used in the following contexts:
|
||||
- ❌ `T:! C` ... `T.X`
|
||||
- ❌ `T:! C where `...
|
||||
- ❌ `class `...` { extend impl as C; }`
|
||||
- The names of `C` are added to the class, and so those names need to be
|
||||
known.
|
||||
- ❌ `interface `...` { extend require impls C; }` or
|
||||
`constraint `...` { extend require impls C; }`
|
||||
- An `extend` declaration requires the target scope to be complete. See
|
||||
[`extend` in member access](../expressions/member_access.md#extend).
|
||||
- ❌ `T:! C` ... `T impls A` where `A` is an interface or named constraint
|
||||
different from `C`
|
||||
- Need to see the definition of `C` to see if it implies `A`.
|
||||
- ❌ `impl` ... `as C {` ... `}`
|
||||
|
||||
> **Future work:** It is currently undecided whether an interface needs to be
|
||||
> complete to be extended, as in:
|
||||
>
|
||||
> ```carbon
|
||||
> interface I { extend C; }
|
||||
> ```
|
||||
>
|
||||
> There are three different approaches being considered:
|
||||
>
|
||||
> - If we detect name collisions between the members of the interface `I` and
|
||||
> `C` when the interface `I` is defined, then we need `C` to be complete.
|
||||
> - If we instead only generate errors on ambiguous use of members with the
|
||||
> same name, as we do with `A & B`, then we don't need to require `C` to be
|
||||
> complete.
|
||||
> - Another option, being discussed in
|
||||
> [#2745](https://github.com/carbon-language/carbon-lang/issues/2745), is
|
||||
> that names in interface `I` shadow the names in any interface being
|
||||
> extended, then `C` would not be required to be complete.
|
||||
|
||||
### Declaring implementations
|
||||
|
||||
> **TODO:** Update this section to reflect the new rules adopted in
|
||||
|
||||
@@ -464,6 +464,8 @@ A type that _extends_ the implementation of an interface has all the named
|
||||
members of the interface as named members of the type. This means that the
|
||||
members of the interface are available by way of both
|
||||
[simple member access and qualified member access expressions](#member-access).
|
||||
See
|
||||
[how `extend` affects member access](../expressions/member_access.md#extend).
|
||||
|
||||
If a type implements an interface without extending, the members of the
|
||||
interface may only be accessed using
|
||||
@@ -648,7 +650,8 @@ also has the member names of its constraint. Effectively it is considered to
|
||||
An interface can be extended by defining an interface that includes the full API
|
||||
of another interface, plus some additional API. Types implementing the extended
|
||||
interface should automatically be considered to have implemented the narrower
|
||||
interface.
|
||||
interface. See
|
||||
[how `extend` affects member access](../expressions/member_access.md#extend).
|
||||
|
||||
## Dynamic-dispatch witness table
|
||||
|
||||
|
||||
Reference in New Issue
Block a user