1- # Type completeness in extend require
1+ # Type completeness in extend
22
33<!--
44Part 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.
5696For 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