Skip to content

Commit 5e9d9ae

Browse files
committed
fill-proposal
1 parent cc3058d commit 5e9d9ae

File tree

2 files changed

+381
-27
lines changed

2 files changed

+381
-27
lines changed

proposals/p6395.md

Lines changed: 118 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Type completeness in extend require
1+
# Type completeness in extend
22

33
<!--
44
Part of the Carbon Language project, under the Apache License v2.0 with LLVM
@@ -24,47 +24,138 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2424

2525
## Abstract
2626

27-
TODO: Describe, in a succinct paragraph, the gist of this document. This
28-
paragraph should be reproduced verbatim in the PR summary.
27+
Require the facet type in `extend require impls` and `extend impl as`
28+
declarations to be complete, since `extend` changes the scopes which are looked
29+
in for name lookup.
2930

3031
## Problem
3132

32-
TODO: What problem are you trying to solve? How important is that problem? Who
33-
is impacted by it?
33+
Proposal
34+
[#5168](https://github.com/carbon-language/carbon-lang/blob/trunk/proposals/p5168.md)
35+
laid out rules for when a facet type needs to be identified or complete. When
36+
`require impls Z` is written, then `Z` must be identified. However it does not
37+
specify any rule for `extend require impls Z`. or `extend impl as Z`.
38+
39+
If an interface `Y` uses `extend` for another interface `Z`, then a facet type
40+
for `Y` will also allow name lookup into `Z`. Similarly if a class `Y` uses
41+
`extend` for an interface `Z`, then an object of type `Y` will also allow name
42+
lookup into `Z`. In both cases, when the definition of `Y` is complete, we
43+
should also require `Z` to be complete, as its name scope becomes conceptually a
44+
part of `Y`.
45+
46+
Additionally, after an `extend ... Z` declaration inside the definition of `Y`,
47+
the names of `Z` should be immediately available inside the `Y` definition,
48+
including inside the nested definition of `extend impl as Z { ... }`.
3449

3550
## Background
3651

37-
TODO: Is there any background that readers should consider to fully understand
38-
this problem and your approach to solving it?
52+
- Proposal
53+
[#5168](https://github.com/carbon-language/carbon-lang/blob/trunk/proposals/p5168.md):
54+
Forward impl declaration of an incomplete interface
55+
- Proposal
56+
[#2760](https://github.com/carbon-language/carbon-lang/blob/trunk/proposals/p2760.md):
57+
Consistent class and interface syntax
3958

4059
## Proposal
4160

42-
TODO: Briefly and at a high level, how do you propose to solve the problem? Why
43-
will that in fact solve it?
61+
Require that `extend require impls Z` requires `Z` to be complete where the
62+
declaration is written. Similarly, require that `extend impl as Z` requires `Z`
63+
to be complete where the declaration is written. In both cases, this ensures
64+
that `Z` is complete by the time the definition of the enclosing class,
65+
interface, or named constraint is complete. And it ensures that we can perform
66+
name lookup into `Z` from within the enclosing scope of the `extend` declaration
67+
thereafter.
68+
69+
We call an `extend require` declaration _extend-reachable_ from a facet type if
70+
it's enclosing interface or named constraint is part of that facet type, or if
71+
its enclosing interface or named constraint is named by another
72+
_extend-reachable_ declaration. That is, we can find a path from the facet type
73+
to the `extend require` declaration through other `extend require` declarations.
74+
75+
We say that a facet type is complete if:
76+
77+
- All its _extend-reachable_ `extend require` declarations are complete. This
78+
follows from the enclosing interface or named constraint being complete.
79+
- We are able to form a specific for each interface and named constraint
80+
extended by the facet type.
81+
- We are able to form a specific for each _extend-reachable_ `extend require`
82+
declaration in the context of the specific facet type being completed.
4483

4584
## Details
4685

47-
TODO: Fully explain the details of the proposed solution.
86+
To `extend` an entity `Y` with another `Z` means that name lookups into `Y` will
87+
also look into `Z`. At the end of the definition of `Y`, we expect to be able to
88+
perform name lookup into `Y`, as it is complete. To maintain this property
89+
through `extend`, we require that `extend require` declarations only name other
90+
interfaces or named constraints that are themselves complete.
4891

49-
## Rationale
50-
51-
TODO: How does this proposal effectively advance Carbon's goals? Rather than
52-
re-stating the full motivation, this should connect that motivation back to
53-
Carbon's stated goals and principles. This may evolve during review. Use links
54-
to appropriate sections of [`/docs/project/goals.md`](/docs/project/goals.md),
55-
and/or to documents in [`/docs/project/principles`](/docs/project/principles).
92+
This functions recursively: Since each interface or named constraint is
93+
complete, we already know the `extend require` declarations inside are complete.
94+
However it is possible to uncover monomorphization errors once a specific is
95+
applied to the facet type in an `extend require` or `extend impls` declaration.
5696
For example:
5797

58-
- [Community and culture](/docs/project/goals.md#community-and-culture)
59-
- [Language tools and ecosystem](/docs/project/goals.md#language-tools-and-ecosystem)
60-
- [Performance-critical software](/docs/project/goals.md#performance-critical-software)
61-
- [Software and language evolution](/docs/project/goals.md#software-and-language-evolution)
62-
- [Code that is easy to read, understand, and write](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write)
63-
- [Practical safety and testing mechanisms](/docs/project/goals.md#practical-safety-and-testing-mechanisms)
64-
- [Fast and scalable development](/docs/project/goals.md#fast-and-scalable-development)
65-
- [Modern OS platforms, hardware architectures, and environments](/docs/project/goals.md#modern-os-platforms-hardware-architectures-and-environments)
66-
- [Interoperability with and migration from existing C++ code](/docs/project/goals.md#interoperability-with-and-migration-from-existing-c-code)
98+
```carbon
99+
interface Z(T:! type) {}
100+
101+
class C(N! i32) {
102+
extend impls Z(array(i32, N)) {}
103+
}
104+
```
105+
106+
Here the facet yype `Z(array(i32, N))` is complete at the point where it is
107+
written, so `C(N)` is complete. However checking `C(-1)` for completeness must
108+
form a specific for the `extend impls` declaration that will generate an error
109+
(as -1 is not valid for an array size), failing type completeness.
110+
111+
The same is true for any `extend require` declaration which is
112+
_extend-reachable_ from the facet type in the `extend` declaration. So we
113+
require type completeness to form a specific for each extended interface or
114+
named constraint in the facet type, as well as for each extended interface or
115+
named constraint in the facet type of a `extend require` declaration that is
116+
_extend-reachable_ from them. This implies forming a specific for any interface
117+
or named constraint along the path to an _extend-reachable_ `extend require`
118+
declaration.
119+
120+
## Rationale
121+
122+
This is based on the principle of
123+
[Code that is easy to read, understand, and write](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write).
124+
For code to be easy to write, the rules need to be consistent. Once an `extend`
125+
declaration has been written, the names inside should become available through
126+
the enclosing scope immediately. If we allow an interface named in an
127+
_extend-reachable_ `extend require` declaration to be incomplete, then name
128+
lookup will fail ambiguously. Those same names may be valid later once the
129+
interface is defined.
67130

68131
## Alternatives considered
69132

70-
TODO: What alternative solutions have you considered?
133+
We considered not requiring that the facet type in an `extend` be complete where
134+
it is written, but only when the enclosing class, interface, or named constraint
135+
is required to be complete. However this does not allow the use of names from
136+
the facet type in the `extend` to be used within the enclosing definition scope.
137+
They would not become available until the enclosing definition scope was closed
138+
and complete.
139+
140+
In particular, we want this to work:
141+
142+
```carbon
143+
interface Z {
144+
let X:! type;
145+
fn F() -> X;
146+
}
147+
class C {
148+
extend impl as Z where .X = () {
149+
// Names `X` directly.
150+
fn F() -> X;
151+
}
152+
153+
// Names `X` and `F` directly.
154+
fn G() -> X { return F(); }
155+
}
156+
157+
// Now `C` is complete, `C.X` and `C.F` are also available.
158+
fn H() -> C.X {
159+
return C.F();
160+
}
161+
```

0 commit comments

Comments
 (0)