Просмотр исходного кода

Clarify some points in Member Access design (#3177)

Follow-on to #3160. Incorporates decision about template specialization
from #2200.
josh11b 2 лет назад
Родитель
Сommit
dc394b6d95
1 измененных файлов с 47 добавлено и 25 удалено
  1. 47 25
      docs/design/expressions/member_access.md

+ 47 - 25
docs/design/expressions/member_access.md

@@ -17,7 +17,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
     -   [Values](#values)
     -   [Facet binding](#facet-binding)
         -   [Compile-time bindings](#compile-time-bindings)
-            -   [Lookup ambiguity](#lookup-ambiguity)
+        -   [Lookup ambiguity](#lookup-ambiguity)
 -   [`impl` lookup](#impl-lookup)
     -   [`impl` lookup for simple member access](#impl-lookup-for-simple-member-access)
     -   [`impl` lookup for compound member access](#impl-lookup-for-compound-member-access)
@@ -254,10 +254,9 @@ fn PrintPointTwice() {
 
 ### Facet binding
 
-If any of the above lookups would search for members of a
-[facet binding](/docs/design/generics/terminology.md#facet-binding) `T:! C`, it
-searches the facet `T as C` instead, treating the facet binding as an
-[archetype](/docs/design/generics/terminology.md#archetype).
+A search for members of a facet binding `T:! C` treats the facet binding as an
+[archetype](/docs/design/generics/terminology.md#archetype), and finds members
+of the facet `T` of facet type `C`.
 
 For example:
 
@@ -301,7 +300,8 @@ interface Renderable {
   fn Draw[self: Self]();
 }
 fn DrawChecked[T:! Renderable](c: T) {
-  // `Draw` resolves to `Renderable.Draw`.
+  // `Draw` resolves to `(T as Renderable).Draw` or
+  // `T.(Renderable.Draw)`.
   c.Draw();
 }
 
@@ -336,29 +336,51 @@ fn CallsDrawTemplate(c: Cowboy) {
 }
 ```
 
-> **TODO:** The behavior of this code depends on whether we decide to allow
-> class templates to be specialized:
->
-> ```carbon
-> class TemplateWrapper(template T:! type) {
->   var field: T;
-> }
-> fn G[template T:! type](x: TemplateWrapper(T)) -> T {
->   // 🤷 Not yet decided.
->   return x.field;
-> }
-> ```
->
-> If class specialization is allowed, then we cannot know the members of
-> `TemplateWrapper(T)` without knowing `T`, so this first lookup will find
-> nothing. In any case, the lookup will be performed again when `T` is known.
+Since we have decided to forbid specialization of class templates, see
+[proposal #2200: Template generics](https://github.com/carbon-language/carbon-lang/pull/2200),
+the compiler can assume the body of a templated class will be the same for all
+argument values:
+
+```carbon
+class TemplateWrapper(template T:! type) {
+  var field: T;
+}
+fn G[template T:! type](x: TemplateWrapper(T)) -> T {
+  // ✅ Allowed, finds `TemplateWrapper(T).field`.
+  return x.field;
+}
+```
+
+In addition, the lookup will be performed again when `T` is known. This allows
+cases where the lookup only succeeds for specific values of `T`:
+
+```carbon
+class HasField {
+  var field: i32;
+}
+class DerivingWrapper(template T:! type) {
+  extend base: T;
+}
+fn H[template T:! type](x: DerivingWrapper(T)) -> i32 {
+  // ✅ Allowed, but no name `field` found in template
+  // definition of `DerivingWrapper`.
+  return x.field;
+}
+fn CallH(a: DerivingWrapper(HasField),
+         b: DerivingWrapper(i32)) {
+  // ✅ Member `field` in base class found in instantiation.
+  var x: i32 = H(a);
+  // ❌ Error, no member `field` in type of `b`.
+  var y: i32 = H(b);
+}
+```
 
 **Note:** All lookups are done from a context where the values of any symbolic
 bindings that are in scope are unknown. Unlike for a template binding, the
 actual value of a symbolic binding never affects the result of member
 resolution.
 
-##### Lookup ambiguity
+#### Lookup ambiguity
 
 Multiple lookups can be performed when resolving a member access expression with
 a [template binding](#compile-time-bindings). We resolve this the same way as
@@ -378,8 +400,8 @@ interface Renderable {
 }
 
 fn DrawTemplate2[template T:! Renderable](c: T) {
-  // Member lookup finds `Renderable.Draw` and the `Draw`
-  // member of the actual deduced value of `T`, if any.
+  // Member lookup finds `(T as Renderable).Draw` and the
+  // `Draw` member of the actual deduced value of `T`, if any.
   c.Draw();
 }