Преглед изворни кода

What can be done with an incomplete interface (#2347)

Clarify what can and cannot be done with a incomplete interface or named constraint.

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
josh11b пре 3 година
родитељ
комит
e29e4cfa29
2 измењених фајлова са 173 додато и 0 уклоњено
  1. 51 0
      docs/design/generics/details.md
  2. 122 0
      proposals/p2347.md

+ 51 - 0
docs/design/generics/details.md

@@ -4383,6 +4383,56 @@ An interface or named constraint may be forward declared subject to these rules:
     interface using `MyInterface.MemberName` or constrain a member using a
     `where` clause.
 
+If `C` is the name of an incomplete interface or named constraint, then it can
+be used in the following contexts:
+
+-   ✅ `T:! C`
+-   ✅ `C & D`
+    -   There may be conflicts between `C` and `D` making this invalid that will
+        only be discovered once they are both complete.
+-   ✅ `interface `...` { impl` ... `as C; }` or `constraint `...` { impl` ...
+    `as C; }`
+    -   Nothing implied by implementing `C` will be visible until `C` is
+        complete.
+-   ✅ `T:! C` ... `T is C`
+-   ✅ `T:! A & C` ... `T is C`
+    -   This includes constructs requiring `T is C` such as `T as C` or
+        `U:! C = T`.
+-   ✅ `external impl `...` as C;`
+    -   Checking that all associated constants of `C` are correctly assigned
+        values will be delayed until `C` is complete.
+
+An incomplete `C` cannot be used in the following contexts:
+
+-   ❌ `T:! C` ... `T.X`
+-   ❌ `T:! C where `...
+-   ❌ `class `...` { impl as C; }`
+    -   The names of `C` are added to the class, and so those names need to be
+        known.
+-   ❌ `T:! C` ... `T is 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`.
+-   ❌ `external impl` ... `as C {` ... `}`
+
+**Future work:** It is currently undecided whether an interface needs to be
+complete to be extended, as in:
+
+```
+interface I { extends 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
+    [#2355](https://github.com/carbon-language/carbon-lang/issues/2355), 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
 
 The declaration of an interface implementation consists of:
@@ -5689,3 +5739,4 @@ parameter, as opposed to an associated type, as in `N:! u32 where ___ >= 2`.
 -   [#1146: Generic details 12: parameterized types](https://github.com/carbon-language/carbon-lang/pull/1146)
 -   [#1327: Generics: `impl forall`](https://github.com/carbon-language/carbon-lang/pull/1327)
 -   [#2107: Clarify rules around `Self` and `.Self`](https://github.com/carbon-language/carbon-lang/pull/2107)
+-   [#2347: What can be done with an incomplete interface](https://github.com/carbon-language/carbon-lang/pull/2347)

+ 122 - 0
proposals/p2347.md

@@ -0,0 +1,122 @@
+# What can be done with an incomplete interface
+
+<!--
+Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+Exceptions. See /LICENSE for license information.
+SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+-->
+
+[Pull request](https://github.com/carbon-language/carbon-lang/pull/2347)
+
+<!-- toc -->
+
+## Table of contents
+
+-   [Abstract](#abstract)
+-   [Problem](#problem)
+-   [Background](#background)
+-   [Proposal](#proposal)
+-   [Rationale](#rationale)
+-   [Alternatives considered](#alternatives-considered)
+    -   [Allow declaration and definition in different files](#allow-declaration-and-definition-in-different-files)
+    -   [No specific restriction on `where` clauses on incomplete constraints](#no-specific-restriction-on-where-clauses-on-incomplete-constraints)
+    -   [Don't allow combinations of incomplete constraints as in `C & D`](#dont-allow-combinations-of-incomplete-constraints-as-in-c--d)
+
+<!-- tocstop -->
+
+## Abstract
+
+Clarify what can and cannot be done with a incomplete interface or named
+constraint.
+
+## Problem
+
+For purposes of this proposal, the term _constraints_ refers to interfaces and
+named constraints. Interfaces do not require any different treatment from named
+constraints, and treating them the same is good for simplicity and uniformity.
+
+We want to support forward declaring constraints so that they may be used before
+they are allowed to be defined, due to recursion or a reference cycle. Some uses
+require the definition of the constraint to be visible to be checked, however.
+In some cases, those checks may be delayed at the cost of complexity in the
+implementation of the compiler. This proposal aims to specify what uses are
+allowed, particularly those cases that were not covered by
+[the previous proposal on forward declarations](https://github.com/carbon-language/carbon-lang/pull/1084).
+
+## Background
+
+Proposal
+[#1084: Generics details 9: forward declarations](https://github.com/carbon-language/carbon-lang/pull/1084)
+originally laid out the rules for incomplete constraints. Since then, the
+[discussion on 2022-10-12](https://docs.google.com/document/d/1tEt4iM6vfcY0O0DG0uOEMIbaXcZXlNREc2ChNiEtn_w/edit#heading=h.q7afaawbc5k)
+considered how we needed to update and fill in those rules, as part of an effort
+to implement those rules in the Carbon Explorer.
+
+## Proposal
+
+The new rule details have been added by this proposal PR to the
+[Forward declarations and cyclic references: declaring interfaces and named constraints](/docs/design/generics/details.md#declaring-interfaces-and-named-constraints)
+section of
+[Generics: details design document](/docs/design/generics/details.md).
+
+## Rationale
+
+This proposal is balancing the expressivity needed to make code easier to write
+with implementation simplicity, both concerns of Carbon's
+["code that is easy to read, understand, and write"](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write)
+goal.
+
+## Alternatives considered
+
+### Allow declaration and definition in different files
+
+In particular, we considered allowing the declaration of an interface or named
+constraint in an API file and the definition in the impl file of the same
+library. We considered some use cases that might benefit from this in
+[#931](p0931.md#private-interfaces-in-public-api-files) and
+[#971](https://github.com/carbon-language/carbon-lang/issues/971). In
+[#generics-and-templates on 2022-10-24](https://discord.com/channels/655572317891461132/941071822756143115/1034207895392358431),
+we decided those use cases would be okay including the definition of the private
+interface in the API file. So to support checking for invalid uses of an
+incomplete interfaces with information local to that file, we reaffirmed the
+decision in #971 and implemented in proposal
+[#1084](https://github.com/carbon-language/carbon-lang/pull/1084) to require the
+definition to be in the same file as the declaration.
+
+### No specific restriction on `where` clauses on incomplete constraints
+
+We considered not having a specific rule preventing any `where` clause on an
+incomplete constraint. The idea is that the problematic cases, such as those
+that access members of the constraint like `where .X = T`, are already
+forbidden. By removing this rule, we would allow constructions like
+`C where Vector(.Self) is Hashable` for incomplete `C`. We decided to wait until
+we had a motivating use case to allow this, and start with the more restrictive
+rule.
+
+### Don't allow combinations of incomplete constraints as in `C & D`
+
+We considered forbidding the combination of incomplete constraints with the `&`
+operator, because otherwise we would not be able to diagnose conflicts between
+the two constraints. For example,
+
+```carbon
+constraint C;
+constraint D;
+
+// Can't tell if there is a conflict between `C` and `D`.
+fn F[T:! C & D](x: T);
+
+// These definitions of `C` and `D` conflict.
+constraint C {
+  extends I where .X = i32;
+}
+constraint D {
+  extends I where .X = bool;
+}
+```
+
+Since our existing examples of using forward declarations to define a graph with
+cyclic references between the edge and node interfaces needed this feature, we
+decided to support it. This motivated the requirement that
+[the definition be in the same file as the declaration](#allow-declaration-and-definition-in-different-files),
+so the error could be detected once the compiler reached the definitions.