mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 19:10:14 +01:00
Integrate description of tuple indexing into member access better. (#3679)
Improve the exposition of the design changes from #3646 to integrate better into the overall description of member access design. This fixes the incorrect description of the rules for `->` by instead relying on the general rule that `->` is rewritten to use `*` and `.` before any other processing is done, and generally makes *integer-literal* names be less of a special case.
This commit is contained in:
@@ -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 and facets](#types-and-facets)
|
||||
- [Tuple indexing](#tuple-indexing)
|
||||
- [Values](#values)
|
||||
- [Facet binding](#facet-binding)
|
||||
- [Compile-time bindings](#compile-time-bindings)
|
||||
@@ -24,7 +25,6 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
- [Instance binding](#instance-binding)
|
||||
- [Non-instance members](#non-instance-members)
|
||||
- [Non-vacuous member access restriction](#non-vacuous-member-access-restriction)
|
||||
- [Tuple indexing](#tuple-indexing)
|
||||
- [Precedence and associativity](#precedence-and-associativity)
|
||||
- [Alternatives considered](#alternatives-considered)
|
||||
- [References](#references)
|
||||
@@ -52,13 +52,17 @@ form:
|
||||
|
||||
- _member-access-expression_ ::= _expression_ `.` _word_
|
||||
- _member-access-expression_ ::= _expression_ `->` _word_
|
||||
- _member-access-expression_ ::= _expression_ `.` _integer-literal_
|
||||
- _member-access-expression_ ::= _expression_ `->` _integer-literal_
|
||||
|
||||
or a _compound_ member access of the form:
|
||||
|
||||
- _member-access-expression_ ::= _expression_ `.` `(` _expression_ `)`
|
||||
- _member-access-expression_ ::= _expression_ `->` `(` _expression_ `)`
|
||||
|
||||
Compound member accesses allow specifying a qualified member name.
|
||||
The _member name_ is the _word_, _integer-literal_, or the constant value of the
|
||||
parenthesized _expression_ in the member access expression. Compound member
|
||||
accesses allow specifying a qualified member name.
|
||||
|
||||
For example:
|
||||
|
||||
@@ -100,7 +104,7 @@ simplicity.
|
||||
|
||||
A member access expression is processed using the following steps:
|
||||
|
||||
- First, the word or parenthesized expression to the right of the `.` is
|
||||
- First, the member name to the right of the `.` is
|
||||
[resolved](#member-resolution) to a specific member entity, called `M` in
|
||||
this document.
|
||||
- Then, if necessary, [`impl` lookup](#impl-lookup) is performed to map from a
|
||||
@@ -117,24 +121,26 @@ A member access expression is processed using the following steps:
|
||||
The process of _member resolution_ determines which member `M` a member access
|
||||
expression is referring to.
|
||||
|
||||
For a simple member access, the second operand is a word. If the first operand
|
||||
is a type, facet, package, or namespace, a search for the word is performed in
|
||||
the first operand. Otherwise, a search for the word is performed in the type of
|
||||
the first operand. In either case, the search must succeed. In the latter case,
|
||||
if the result is an instance member, then [instance binding](#instance-binding)
|
||||
is performed on the first operand.
|
||||
For a simple member access, if the first operand is a type, facet, package, or
|
||||
namespace, a search for the member name is performed in the first operand.
|
||||
Otherwise, a search for the member name is performed in the type of the first
|
||||
operand. In either case, the search must succeed. In the latter case, if the
|
||||
result is an instance member, then [instance binding](#instance-binding) is
|
||||
performed on the first operand.
|
||||
|
||||
For a compound member access, the second operand is evaluated as a compile-time
|
||||
constant to determine the member being accessed. The evaluation is required to
|
||||
succeed and to result in a member of a type, interface, or non-type facet. If
|
||||
the result is an instance member, then [instance binding](#instance-binding) is
|
||||
always performed on the first operand.
|
||||
succeed and to result in a member of a type, interface, or non-type facet, or a
|
||||
value of an integer or integer literal type. If the result is an instance
|
||||
member, then [instance binding](#instance-binding) is always performed on the
|
||||
first operand.
|
||||
|
||||
### Package and namespace members
|
||||
|
||||
If the first operand is a package or namespace name, the expression must be a
|
||||
simple member access expression. The _word_ must name a member of that package
|
||||
or namespace, and the result is the package or namespace member with that name.
|
||||
simple member access expression. The member name must be a _word_ that names a
|
||||
member of that package or namespace, and the result is the package or namespace
|
||||
member with that name.
|
||||
|
||||
An expression that names a package or namespace can only be used as the first
|
||||
operand of a member access or as the target of an `alias` declaration.
|
||||
@@ -216,9 +222,52 @@ class Avatar {
|
||||
Simple member access `(Avatar as Cowboy).Draw` finds the `Cowboy.Draw`
|
||||
implementation for `Avatar`, ignoring `Renderable.Draw`.
|
||||
|
||||
### Tuple indexing
|
||||
|
||||
Tuple types have member names that are *integer-literal*s, not *word*s.
|
||||
|
||||
Each positional element of a tuple is considered to have a name that is the
|
||||
corresponding decimal integer: `0`, `1`, and so on. The spelling of the
|
||||
_integer-literal_ is required to exactly match one of those names, and the
|
||||
result of member resolution is an instance member that refers to the
|
||||
corresponding element of the tuple.
|
||||
|
||||
```
|
||||
// ✅ `a == 42`.
|
||||
let a: i32 = (41, 42, 43).1;
|
||||
// ❌ Error: no tuple element named `0x1`.
|
||||
let b: i32 = (1, 2, 3).0x1;
|
||||
// ❌ Error: no tuple element named `2`.
|
||||
let c: i32 = (1, 2).2;
|
||||
|
||||
var t: (i32, i32, i32) = (1, 2, 3);
|
||||
let p: (i32, i32, i32)* = &t;
|
||||
// ✅ `m == 3`.
|
||||
let m: i32 = p->2;
|
||||
```
|
||||
|
||||
In a compound member access whose second operand is of integer or integer
|
||||
literal type, the first operand is required to be of tuple type or to extend a
|
||||
tuple type, otherwise member resolution fails. The second operand is required to
|
||||
be a non-negative template constant that is less than the number of tuple
|
||||
elements, and the result is an instance member that refers to the corresponding
|
||||
positional element of the tuple.
|
||||
|
||||
```
|
||||
// ✅ `d == 43`.
|
||||
let d: i32 = (41, 42, 43).(1 + 1);
|
||||
// ✅ `e == 2`.
|
||||
let template e:! i32 = (1, 2, 3).(0x1);
|
||||
// ❌ Error: no tuple element with index 4.
|
||||
let f: i32 = (1, 2).(2 * 2);
|
||||
|
||||
// ✅ `n == 3`.
|
||||
let n: i32 = p->(e);
|
||||
```
|
||||
|
||||
### Values
|
||||
|
||||
If the first operand is not a type, package, namespace, or facet it does not
|
||||
If the first operand is not a type, package, namespace, or facet, it does not
|
||||
have member names, and a search is performed into the type of the first operand
|
||||
instead.
|
||||
|
||||
@@ -842,56 +891,6 @@ alias X3 = (i32 as Factory).Make;
|
||||
alias X4 = i32.((i32 as Factory).Make);
|
||||
```
|
||||
|
||||
## Tuple indexing
|
||||
|
||||
A tuple indexing expression is of the form:
|
||||
|
||||
- _expression_ `.` _integer-literal_
|
||||
- _expression_ `->` _integer-literal_
|
||||
|
||||
The _expression_ is required to be of tuple type.
|
||||
|
||||
Each positional element of the tuple is considered to have a name that is the
|
||||
corresponding decimal integer: `0`, `1`, and so on. The spelling of the
|
||||
_integer-literal_ is required to exactly match one of those names, and the
|
||||
result is the corresponding element of the tuple.
|
||||
|
||||
```
|
||||
// ✅ `a == 42`.
|
||||
let a: i32 = (41, 42, 43).1;
|
||||
// ❌ Error: no tuple element named `0x1`.
|
||||
let b: i32 = (1, 2, 3).0x1;
|
||||
// ❌ Error: no tuple element named `2`.
|
||||
let c: i32 = (1, 2).2;
|
||||
|
||||
var t: (i32, i32, i32) = (1, 2, 3);
|
||||
let p: (i32, i32, i32)* = &t;
|
||||
// ✅ `m == 3`.
|
||||
let m: i32 = p->2;
|
||||
```
|
||||
|
||||
In a compound member access of the form:
|
||||
|
||||
- _expression_ `.` `(` _expression_ `)`
|
||||
- _expression_ `->` `(` _expression_ `)`
|
||||
|
||||
in which the first _expression_ is a tuple and the second _expression_ is of
|
||||
integer or integer literal type, the second _expression_ is required to be a
|
||||
non-negative template constant that is less than the number of tuple elements,
|
||||
and the result is the corresponding positional element of the tuple.
|
||||
|
||||
```
|
||||
// ✅ `d == 43`.
|
||||
let d: i32 = (41, 42, 43).(1 + 1);
|
||||
// ✅ `e == 2`.
|
||||
let template e:! i32 = (1, 2, 3).(0x1);
|
||||
// ❌ Error: no tuple element with index 4.
|
||||
let f: i32 = (1, 2).(2 * 2);
|
||||
|
||||
// ✅ `n == 3`.
|
||||
let n: i32 = p->(e);
|
||||
```
|
||||
|
||||
## Precedence and associativity
|
||||
|
||||
Member access expressions associate left-to-right:
|
||||
|
||||
Reference in New Issue
Block a user