Values, variables, pointers, and references (#2006)

Introduce a concrete design for how Carbon values, objects, storage,
variables,
and pointers will work. This includes fleshing out the design for:

- The expression categories used in Carbon to represent values and
objects,
how they interact, and terminology that anchors on their expression
nature.
-   An expression category model for readonly, abstract values that can
    efficiently support function inputs.
- A customization system for value expression representations,
especially as
    seen on function boundaries in the calling convention.
- An expression category model for references instead of a type system
model.
-   How patterns match different expression categories.
-   How initialization works in conjunction with function returns.
- Specific pointer syntax, semantics, and library customization
mechanisms.
- A `const` type qualifier for use when the value expression category
system
    is too abstracted from the underlying objects in storage.

---------

Co-authored-by: Geoff Romer <gromer@google.com>
Co-authored-by: josh11b <josh11b@users.noreply.github.com>
Co-authored-by: Adrien Leravat <Pixep@users.noreply.github.com>
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This commit is contained in:
Chandler Carruth
2023-08-08 07:27:44 +00:00
committed by GitHub
co-authored by Geoff Romer josh11b Adrien Leravat Jon Ross-Perkins Richard Smith
parent 049fbc1ee4
commit 0d1e6bd84d
12 changed files with 2446 additions and 198 deletions
+134 -74
View File
@@ -27,7 +27,9 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- [Floating-point literals](#floating-point-literals)
- [String types](#string-types)
- [String literals](#string-literals)
- [Value categories and value phases](#value-categories-and-value-phases)
- [Values, objects, and expressions](#values-objects-and-expressions)
- [Expression categories](#expression-categories)
- [Value phases](#value-phases)
- [Composite types](#composite-types)
- [Tuples](#tuples)
- [Struct types](#struct-types)
@@ -43,6 +45,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- [Constant `let` declarations](#constant-let-declarations)
- [Variable `var` declarations](#variable-var-declarations)
- [`auto`](#auto)
- [Global constants and variables](#global-constants-and-variables)
- [Functions](#functions)
- [Parameters](#parameters)
- [`auto` return type](#auto-return-type)
@@ -396,10 +399,10 @@ Some values, such as `()` and `{}`, may even be used as types, but only act like
types when they are in a type position, like after a `:` in a variable
declaration or the return type after a `->` in a function declaration. Any
expression in a type position must be
[a constants or symbolic value](#value-categories-and-value-phases) so the
compiler can resolve whether the value can be used as a type. This also puts
limits on how much operators can do different things for types. This is good for
consistency, but is a significant restriction on Carbon's design.
[a constant or symbolic value](#value-phases) so the compiler can resolve
whether the value can be used as a type. This also puts limits on how much
operators can do different things for types. This is good for consistency, but
is a significant restriction on Carbon's design.
## Primitive types
@@ -637,21 +640,57 @@ are available for representing strings with `\`s and `"`s.
> - Proposal
> [#199: String literals](https://github.com/carbon-language/carbon-lang/pull/199)
## Value categories and value phases
## Values, objects, and expressions
Every expression has a
[value category](<https://en.wikipedia.org/wiki/Value_(computer_science)#lrvalue>),
similar to [C++](https://en.cppreference.com/w/cpp/language/value_category),
that is either _l-value_ or _r-value_. Carbon will automatically convert an
l-value to an r-value, but not in the other direction.
Carbon has both abstract _values_ and concrete _objects_. Carbon _values_ are
things like `42`, `true`, and `i32` (a type value). Carbon _objects_ have
_storage_ where values can be read and written. Storage also allows taking the
address of an object in memory in Carbon.
L-value expressions refer to values that have storage and a stable address. They
may be modified, assuming their type is not [`const`](#const).
> References:
>
> - [Values, variables, and pointers](values.md)
> - Proposal
> [#2006: Values, variables, pointers, and references](https://github.com/carbon-language/carbon-lang/pull/2006)
R-value expressions evaluate to values that may not have dedicated storage. This
means they cannot be modified and their address generally cannot be taken. The
values of r-value expressions are broken down into three kinds, called _value
phases_:
### Expression categories
A Carbon expression produces a value, references an object, or initializes an
object. Every expression has a
[category](<https://en.wikipedia.org/wiki/Value_(computer_science)#lrvalue>),
similar to [C++](https://en.cppreference.com/w/cpp/language/value_category):
- [_Value expressions_](values.md#value-expressions) produce abstract,
read-only _values_ that cannot be modified or have their address taken.
- [_Reference expressions_](values.md#reference-expressions) refer to
_objects_ with _storage_ where a value may be read or written and the
object's address can be taken.
- [_Initializing expressions_](values.md#initializing-expressions) which
require storage to be provided implicitly when evaluating the expression.
The expression then initializes an object in that storage. These are used to
model function returns, which can construct the returned value directly in
the caller's storage.
Expressions in one category can be converted to any other category when needed.
The primitive conversion steps used are:
- _Value binding_ converts a reference expression into a value expression.
- _Direct initialization_ converts a value expression into an initializing
expression.
- _Copy initialization_ converts a reference expression into an initializing
expression.
- _Temporary materialization_ converts an initializing expression into a
reference expression.
> References:
>
> - [Expression categories](values.md#expression-categories)
> - Proposal
> [#2006: Values, variables, pointers, and references](https://github.com/carbon-language/carbon-lang/pull/2006)
### Value phases
Value expressions are also broken down into three _value phases_:
- A _constant_ has a value known at compile time, and that value is available
during type checking, for example to use as the size of an array. These
@@ -674,7 +713,7 @@ to a runtime value:
```mermaid
graph TD;
A(constant)-->B(symbolic value)-->C(runtime value);
D(l-value)-->C;
D(reference expression)-->C;
```
Constants convert to symbolic values and to runtime values. Symbolic values will
@@ -682,9 +721,7 @@ generally convert into runtime values if an operation that inspects the value is
performed on them. Runtime values will convert into constants or to symbolic
values if constant evaluation of the runtime expression succeeds.
> **Note:** Conversion of runtime values to other phases is provisional, as are
> the semantics of r-values. See pending proposal
> [#2006: Values, variables, pointers, and references](https://github.com/carbon-language/carbon-lang/pull/2006).
> **Note:** Conversion of runtime values to other phases is provisional.
## Composite types
@@ -762,30 +799,25 @@ not support
[pointer arithmetic](<https://en.wikipedia.org/wiki/Pointer_(computer_programming)>);
the only pointer [operations](#expressions) are:
- Dereference: given a pointer `p`, `*p` gives the value `p` points to as an
[l-value](#value-categories-and-value-phases). `p->m` is syntactic sugar for
`(*p).m`.
- Address-of: given an [l-value](#value-categories-and-value-phases) `x`, `&x`
- Dereference: given a pointer `p`, `*p` gives the value `p` points to as a
[reference expression](#expression-categories). `p->m` is syntactic sugar
for `(*p).m`.
- Address-of: given a [reference expression](#expression-categories) `x`, `&x`
returns a pointer to `x`.
There are no [null pointers](https://en.wikipedia.org/wiki/Null_pointer) in
Carbon. To represent a pointer that may not refer to a valid object, use the
type `Optional(T*)`.
**TODO:** Perhaps Carbon will have
**Future work:** Perhaps Carbon will have
[stricter pointer provenance](https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html)
or restrictions on casts between pointers and integers.
> **Note:** While the syntax for pointers has been decided, the semantics of
> pointers are provisional, as is the syntax for optionals. See pending proposal
> [#2006: Values, variables, pointers, and references](https://github.com/carbon-language/carbon-lang/pull/2006).
> References:
>
> - Question-for-leads issue
> [#520: should we use whitespace-sensitive operator fixity?](https://github.com/carbon-language/carbon-lang/issues/520)
> - Question-for-leads issue
> [#523: what syntax should we use for pointer types?](https://github.com/carbon-language/carbon-lang/issues/523)
> - [Pointers](values.md#pointers)
> - Proposal
> [#2006: Values, variables, pointers, and references](https://github.com/carbon-language/carbon-lang/pull/2006)
### Arrays and slices
@@ -846,7 +878,7 @@ Some common expressions in Carbon include:
`not e`
- [Indexing](#arrays-and-slices): `a[3]`
- [Function](#functions) call: `f(4)`
- [Pointer](#pointer-types): `*p`, `p->m`, `&x`
- [Pointer](expressions/pointer_operators.md): `*p`, `p->m`, `&x`
- [Move](#move): `~x`
- [Conditionals](expressions/if.md): `if c then t else f`
@@ -875,6 +907,8 @@ are applied to convert the expression to the target type.
> [#911: Conditional expressions](https://github.com/carbon-language/carbon-lang/pull/911)
> - Proposal
> [#1083: Arithmetic expressions](https://github.com/carbon-language/carbon-lang/pull/1083)
> - Proposal
> [#2006: Values, variables, pointers, and references](https://github.com/carbon-language/carbon-lang/pull/2006)
## Declarations, Definitions, and Scopes
@@ -954,14 +988,15 @@ binding any name to it.
Binding patterns default to _`let` bindings_. The `var` keyword is used to make
it a _`var` binding_.
- The result of a `let` binding is the name is bound to an
[r-value](#value-categories-and-value-phases). This means the value cannot
be modified, and its address generally cannot be taken.
- A `var` binding has dedicated storage, and so the name is an
[l-value](#value-categories-and-value-phases) which can be modified and has
a stable address.
- A `let` binding binds a name to a value, so the name can be used as a
[value expression](#expression-categories). This means the value cannot be
modified, and its address generally cannot be taken.
- A `var` binding creates an object with dedicated storage, and so the name
can be used as a [reference expression](#expression-categories) which can be
modified and has a stable address.
A `let`-binding may be implemented as an alias for the original value (like a
A `let`-binding may be [implemented](values.md#value-expressions) as an alias
for the original value (like a
[`const` reference in C++](<https://en.wikipedia.org/wiki/Reference_(C%2B%2B)>)),
or it may be copied from the original value (if it is copyable), or it may be
moved from the original value (if it was a temporary). The Carbon
@@ -971,9 +1006,8 @@ the program's correctness must not depend on which option the Carbon
implementation chooses.
A [generic binding](#checked-and-template-parameters) uses `:!` instead of a
colon (`:`) and can only match
[constant or symbolic values](#value-categories-and-value-phases), not run-time
values.
colon (`:`) and can only match [constant or symbolic values](#value-phases), not
run-time values.
The keyword `auto` may be used in place of the type in a binding pattern, as
long as the type can be deduced from the type of a value in the same
@@ -1049,14 +1083,17 @@ Here `x: i64` is the pattern, which is followed by an equal sign (`=`) and the
value to match, `42`. The names from [binding patterns](#binding-patterns) are
introduced into the enclosing [scope](#declarations-definitions-and-scopes).
> **Note:** `let` declarations are provisional. See pending proposal
> [#2006: Values, variables, pointers, and references](https://github.com/carbon-language/carbon-lang/pull/2006).
> References:
>
> - [Binding patterns and local variables with `let` and `var`](values.md#binding-patterns-and-local-variables-with-let-and-var)
> - Proposal
> [#2006: Values, variables, pointers, and references](https://github.com/carbon-language/carbon-lang/pull/2006)
### Variable `var` declarations
A `var` declaration is similar, except with `var` bindings, so `x` here is an
[l-value](#value-categories-and-value-phases) with storage and an address, and
so may be modified:
A `var` declaration is similar, except with `var` bindings, so `x` here is a
[reference expression](#expression-categories) for an object with storage and an
address, and so may be modified:
```carbon
var x: i64 = 42;
@@ -1069,7 +1106,7 @@ they are used.
> References:
>
> - [Variables](variables.md)
> - [Binding patterns and local variables with `let` and `var`](values.md#binding-patterns-and-local-variables-with-let-and-var)
> - Proposal
> [#162: Basic Syntax](https://github.com/carbon-language/carbon-lang/pull/162)
> - Proposal
@@ -1078,6 +1115,8 @@ they are used.
> [#339: Add `var <type> <identifier> [ = <value> ];` syntax for variables](https://github.com/carbon-language/carbon-lang/pull/339)
> - Proposal
> [#618: var ordering](https://github.com/carbon-language/carbon-lang/pull/618)
> - Proposal
> [#2006: Values, variables, pointers, and references](https://github.com/carbon-language/carbon-lang/pull/2006)
### `auto`
@@ -1098,6 +1137,21 @@ var z: auto = (y > 1);
> - Proposal
> [#851: auto keyword for vars](https://github.com/carbon-language/carbon-lang/pull/851)
### Global constants and variables
[Constant `let` declarations](#constant-let-declarations) may occur at a global
scope as well as local and member scopes. However, there are currently no global
variables.
> **Note**: The semantics of global constant declarations and absence of global
> variable declarations is currently provisional.
>
> We are exploring several different ideas for how to design less bug-prone
> patterns to replace the important use cases programmers still have for global
> variables. We may be unable to fully address them, at least for migrated code,
> and be forced to add some limited form of global variables back. We may also
> discover that their convenience outweighs any improvements afforded.
## Functions
Functions are the core unit of behavior. For example, this is a
@@ -1149,7 +1203,7 @@ declaration. The parameter names in a forward declaration may be omitted using
The bindings in the parameter list default to
[`let` bindings](#binding-patterns), and so the parameter names are treated as
[r-values](#value-categories-and-value-phases). This is appropriate for input
[value expressions](#expression-categories). This is appropriate for input
parameters. This binding will be implemented using a pointer, unless it is legal
to copy and copying is cheaper.
@@ -1167,9 +1221,11 @@ the caller, and dereferencing using `*` in the callee.
Outputs of a function should prefer to be returned. Multiple values may be
returned using a [tuple](#tuples) or [struct](#struct-types) type.
> **Note:** The semantics of parameter passing are provisional. See pending
> proposal
> [#2006: Values, variables, pointers, and references](https://github.com/carbon-language/carbon-lang/pull/2006).
> References:
>
> - [Binding patterns and local variables with `let` and `var`](values.md#binding-patterns-and-local-variables-with-let-and-var)
> - Proposal
> [#2006: Values, variables, pointers, and references](https://github.com/carbon-language/carbon-lang/pull/2006)
### `auto` return type
@@ -1689,8 +1745,8 @@ two methods `Distance` and `Offset`:
declaration.
- `origin.Offset(`...`)` does modify the value of `origin`. This is signified
using `[addr self: Self*]` in the method declaration. Since calling this
method requires taking the address of `origin`, it may only be called on
[non-`const`](#const) [l-values](#value-categories-and-value-phases).
method requires taking the [non-`const`](#const) address of `origin`, it may
only be called on [reference expressions](#expression-categories).
- Methods may be declared lexically inline like `Distance`, or lexically out
of line like `Offset`.
@@ -1883,20 +1939,19 @@ type, use `UnsafeDelete`.
#### `const`
> **Note:** This is provisional, no design for `const` has been through the
> proposal process yet.
For every type `MyClass`, there is the type `const MyClass` such that:
- The data representation is the same, so a `MyClass*` value may be implicitly
converted to a `(const MyClass)*`.
- A `const MyClass` [l-value](#value-categories-and-value-phases) may
automatically convert to a `MyClass` r-value, the same way that a `MyClass`
l-value can.
- A `const MyClass` [reference expression](#expression-categories) may
automatically convert to a `MyClass` value expression, the same way that a
`MyClass` reference expression can.
- If member `x` of `MyClass` has type `T`, then member `x` of `const MyClass`
has type `const T`.
- The API of a `const MyClass` is a subset of `MyClass`, excluding all methods
taking `[addr self: Self*]`.
- While all of the member names in `MyClass` are also member names in
`const MyClass`, the effective API of a `const MyClass` reference expression
is a subset of `MyClass`, because only `addr` methods accepting a
`const Self*` will be valid.
Note that `const` binds more tightly than postfix-`*` for forming a pointer
type, so `const MyClass*` is equal to `(const MyClass)*`.
@@ -1911,8 +1966,8 @@ var origin: Point = {.x = 0, .y = 0};
// `const Point*`:
let p: const Point* = &origin;
// ✅ Allowed conversion of `const Point` l-value
// to `Point` r-value.
// ✅ Allowed conversion of `const Point` reference expression
// to `Point` value expression.
let five: f32 = p->Distance(3, 4);
// ❌ Error: mutating method `Offset` excluded
@@ -1924,6 +1979,12 @@ p->Offset(3, 4);
p->x += 2;
```
> References:
>
> - [`const`-qualified types](values.md#const-qualified-types)
> - Proposal
> [#2006: Values, variables, pointers, and references](https://github.com/carbon-language/carbon-lang/pull/2006)
#### Unformed state
Types indicate that they support unformed states by
@@ -1967,8 +2028,6 @@ value.
> **Note:** This is provisional. The move operator was discussed but not
> proposed in accepted proposal
> [#257: Initialization of memory and variables](https://github.com/carbon-language/carbon-lang/pull/257).
> See pending proposal
> [#2006: Values, variables, pointers, and references](https://github.com/carbon-language/carbon-lang/pull/2006).
#### Mixins
@@ -2664,8 +2723,8 @@ templates. Constraints can then be added incrementally, with the compiler
verifying that the semantics stay the same. Once all constraints have been
added, removing the word `template` to switch to a checked parameter is safe.
The [value phase](#value-categories-and-value-phases) of a checked parameter is
a symbolic value whereas the value phase of a template parameter is constant.
The [value phase](#value-phases) of a checked parameter is a symbolic value
whereas the value phase of a template parameter is constant.
Although checked generics are generally preferred, templates enable translation
of code between C++ and Carbon, and address some cases where the type checking
@@ -3111,9 +3170,10 @@ The interfaces that correspond to each operator are given by:
The
[logical operators can not be overloaded](expressions/logical_operators.md#overloading).
Operators that result in [l-values](#value-categories-and-value-phases), such as
dereferencing `*p` and indexing `a[3]`, have interfaces that return the address
of the value. Carbon automatically dereferences the pointer to get the l-value.
Operators that result in [reference expressions](#expression-categories), such
as dereferencing `*p` and indexing `a[3]`, have interfaces that return the
address of the value. Carbon automatically dereferences the pointer to form the
reference expression.
Operators that can take multiple arguments, such as function calling operator
`f(4)`, have a [variadic](generics/details.md#variadic-arguments) parameter
+2 -2
View File
@@ -80,8 +80,8 @@ fn MaybeDraw(should_draw: bool) -> () {
### `returned var`
[Variables](../variables.md) may be declared with a `returned` statement. Its
syntax is:
[Local variables](../values.md#binding-patterns-and-local-variables-with-let-and-var)
may be declared with a `returned` statement. Its syntax is:
> `returned` _var statement_
+70 -33
View File
@@ -61,10 +61,27 @@ graph BT
unqualifiedName["x"]
click unqualifiedName "https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/expressions/README.md#unqualified-names"
top((" "))
memberAccess>"x.y<br>
x.(...)"]
x.(...)<br>
x->y<br>
x->(...)"]
click memberAccess "https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/expressions/member_access.md"
constType["const T"]
click pointer-type "https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/expressions/type_operators.md"
pointerType>"T*"]
click pointer-type "https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/expressions/type_operators.md"
%% FIXME: Need to switch unary operators from a left/right associativity to
%% a "repeated" marker, as we only have one direction for associativity and
%% that is wrong in this specific case.
pointer>"*x<br>
&x<br>"]
click pointer "https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/expressions/pointer.md"
negation["-x"]
click negation "https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/expressions/arithmetic.md"
@@ -124,15 +141,22 @@ graph BT
expressionEnd["x;"]
memberAccess --> parens & braces & unqualifiedName
negation --> memberAccess
complement --> memberAccess
top --> parens & braces & unqualifiedName
constType --> top
pointerType --> constType
as --> pointerType
memberAccess --> top
pointer --> memberAccess
negation --> pointer
complement --> pointer
unary --> negation & complement
%% Use a longer arrow here to put `not` next to `and` and `or`.
not -----> memberAccess
multiplication & modulo & as & bitwise_and & bitwise_or & bitwise_xor & shift --> unary
not -------> memberAccess
as & multiplication & modulo & bitwise_and & bitwise_or & bitwise_xor & shift --> unary
addition --> multiplication
comparison --> modulo & addition & as & bitwise_and & bitwise_or & bitwise_xor & shift
comparison --> as & addition & modulo & bitwise_and & bitwise_or & bitwise_xor & shift
logicalOperand --> comparison & not
and & or --> logicalOperand
logicalExpression --> and & or
@@ -179,12 +203,14 @@ keyword and is not preceded by a period (`.`).
### Qualified names and member access
A _qualified name_ is a word that appears immediately after a period. Qualified
names appear in the following contexts:
A _qualified name_ is a word that appears immediately after a period or
rightward arrow. Qualified names appear in the following contexts:
- [Designators](/docs/design/classes.md#literals): `.` _word_
- [Simple member access expressions](member_access.md): _expression_ `.`
_word_
- [Simple pointer member access expressions](member_access.md): _expression_
`->` _word_
```
var x: auto = {.hello = 1, .world = 2};
@@ -194,6 +220,10 @@ var x: auto = {.hello = 1, .world = 2};
x.hello = x.world;
^^^^^ ^^^^^ qualified name
^^^^^^^ ^^^^^^^ member access expression
x.hello = (&x)->world;
^^^^^ qualified name
^^^^^^^^^^^ pointer member access expression
```
Qualified names refer to members of an entity determined by the context in which
@@ -231,6 +261,7 @@ complex than a single _word_, a compound member access expression can be used,
with parentheses around the member name:
- _expression_ `.` `(` _expression_ `)`
- _expression_ `->` `(` _expression_ `)`
```
interface I { fn F[self: Self](); }
@@ -241,34 +272,40 @@ impl X as I { fn F[self: Self]() {} }
fn Q(x: X) { x.(I.F)(); }
```
Either simple or compound member access can be part of a _pointer_ member access
expression when an `->` is used instead of a `.`, where _expression_ `->` _..._
is syntactic sugar for `(` `*` _expression_ `)` `.` _..._.
## Operators
Most expressions are modeled as operators:
| Category | Operator | Syntax | Function |
| ---------- | ------------------------------- | --------- | --------------------------------------------------------------------- |
| Arithmetic | [`-`](arithmetic.md) (unary) | `-x` | The negation of `x`. |
| Bitwise | [`^`](bitwise.md) (unary) | `^x` | The bitwise complement of `x`. |
| Arithmetic | [`+`](arithmetic.md) | `x + y` | The sum of `x` and `y`. |
| Arithmetic | [`-`](arithmetic.md) (binary) | `x - y` | The difference of `x` and `y`. |
| Arithmetic | [`*`](arithmetic.md) | `x * y` | The product of `x` and `y`. |
| Arithmetic | [`/`](arithmetic.md) | `x / y` | `x` divided by `y`, or the quotient thereof. |
| Arithmetic | [`%`](arithmetic.md) | `x % y` | `x` modulo `y`. |
| Bitwise | [`&`](bitwise.md) | `x & y` | The bitwise AND of `x` and `y`. |
| Bitwise | [`\|`](bitwise.md) | `x \| y` | The bitwise OR of `x` and `y`. |
| Bitwise | [`^`](bitwise.md) (binary) | `x ^ y` | The bitwise XOR of `x` and `y`. |
| Bitwise | [`<<`](bitwise.md) | `x << y` | `x` bit-shifted left `y` places. |
| Bitwise | [`>>`](bitwise.md) | `x >> y` | `x` bit-shifted right `y` places. |
| Conversion | [`as`](as_expressions.md) | `x as T` | Converts the value `x` to the type `T`. |
| Comparison | [`==`](comparison_operators.md) | `x == y` | Equality: `true` if `x` is equal to `y`. |
| Comparison | [`!=`](comparison_operators.md) | `x != y` | Inequality: `true` if `x` is not equal to `y`. |
| Comparison | [`<`](comparison_operators.md) | `x < y` | Less than: `true` if `x` is less than `y`. |
| Comparison | [`<=`](comparison_operators.md) | `x <= y` | Less than or equal: `true` if `x` is less than or equal to `y`. |
| Comparison | [`>`](comparison_operators.md) | `x > y` | Greater than: `true` if `x` is greater than to `y`. |
| Comparison | [`>=`](comparison_operators.md) | `x >= y` | Greater than or equal: `true` if `x` is greater than or equal to `y`. |
| Logical | [`and`](logical_operators.md) | `x and y` | A short-circuiting logical AND: `true` if both operands are `true`. |
| Logical | [`or`](logical_operators.md) | `x or y` | A short-circuiting logical OR: `true` if either operand is `true`. |
| Logical | [`not`](logical_operators.md) | `not x` | Logical NOT: `true` if the operand is `false`. |
| Category | Operator | Syntax | Function |
| ---------- | ----------------------------------- | --------- | --------------------------------------------------------------------- |
| Pointer | [`*`](pointer_operators.md) (unary) | `*x` | Pointer dereference: the object pointed to by `x`. |
| Pointer | [`&`](pointer_operators.md) (unary) | `&x` | Address-of: a pointer to the object `x`. |
| Arithmetic | [`-`](arithmetic.md) (unary) | `-x` | The negation of `x`. |
| Bitwise | [`^`](bitwise.md) (unary) | `^x` | The bitwise complement of `x`. |
| Arithmetic | [`+`](arithmetic.md) | `x + y` | The sum of `x` and `y`. |
| Arithmetic | [`-`](arithmetic.md) (binary) | `x - y` | The difference of `x` and `y`. |
| Arithmetic | [`*`](arithmetic.md) | `x * y` | The product of `x` and `y`. |
| Arithmetic | [`/`](arithmetic.md) | `x / y` | `x` divided by `y`, or the quotient thereof. |
| Arithmetic | [`%`](arithmetic.md) | `x % y` | `x` modulo `y`. |
| Bitwise | [`&`](bitwise.md) | `x & y` | The bitwise AND of `x` and `y`. |
| Bitwise | [`\|`](bitwise.md) | `x \| y` | The bitwise OR of `x` and `y`. |
| Bitwise | [`^`](bitwise.md) (binary) | `x ^ y` | The bitwise XOR of `x` and `y`. |
| Bitwise | [`<<`](bitwise.md) | `x << y` | `x` bit-shifted left `y` places. |
| Bitwise | [`>>`](bitwise.md) | `x >> y` | `x` bit-shifted right `y` places. |
| Conversion | [`as`](as_expressions.md) | `x as T` | Converts the value `x` to the type `T`. |
| Comparison | [`==`](comparison_operators.md) | `x == y` | Equality: `true` if `x` is equal to `y`. |
| Comparison | [`!=`](comparison_operators.md) | `x != y` | Inequality: `true` if `x` is not equal to `y`. |
| Comparison | [`<`](comparison_operators.md) | `x < y` | Less than: `true` if `x` is less than `y`. |
| Comparison | [`<=`](comparison_operators.md) | `x <= y` | Less than or equal: `true` if `x` is less than or equal to `y`. |
| Comparison | [`>`](comparison_operators.md) | `x > y` | Greater than: `true` if `x` is greater than to `y`. |
| Comparison | [`>=`](comparison_operators.md) | `x >= y` | Greater than or equal: `true` if `x` is greater than or equal to `y`. |
| Logical | [`and`](logical_operators.md) | `x and y` | A short-circuiting logical AND: `true` if both operands are `true`. |
| Logical | [`or`](logical_operators.md) | `x or y` | A short-circuiting logical OR: `true` if either operand is `true`. |
| Logical | [`not`](logical_operators.md) | `not x` | Logical NOT: `true` if the operand is `false`. |
The binary arithmetic and bitwise operators also have
[compound assignment](/docs/design/assignment.md) forms. These are statements
+29 -9
View File
@@ -23,14 +23,17 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
## Overview
Carbon supports indexing using the conventional `a[i]` subscript syntax. When
`a` is an l-value, the result of subscripting is always an l-value, but when `a`
is an r-value, the result can be an l-value or an r-value, depending on which
`a` is a
[durable reference expression](/docs/design/values.md#durable-reference-expressions),
the result of subscripting is also a durable reference expression, but when `a`
is a [value expression](/docs/design/values.md#value-expressions), the result
can be a durable reference expression or a value expression, depending on which
interface the type implements:
- If subscripting an r-value produces an r-value result, as with an array, the
type should implement `IndexWith`.
- If subscripting an r-value produces an l-value result, as with C++'s
`std::span`, the type should implement `IndirectIndexWith`.
- If subscripting a value expression produces a value expression, as with an
array, the type should implement `IndexWith`.
- If subscripting a value expression produces a durable reference expression,
as with C++'s `std::span`, the type should implement `IndirectIndexWith`.
`IndirectIndexWith` is a subtype of `IndexWith`, and subscript expressions are
rewritten to method calls on `IndirectIndexWith` if the type is known to
@@ -39,6 +42,19 @@ implement that interface, or to method calls on `IndexWith` otherwise.
`IndirectIndexWith` provides a final blanket `impl` of `IndexWith`, so a type
can implement at most one of those two interfaces.
The `Addr` methods of these interfaces, which are used to form durable reference
expressions on indexing, must return a pointer and work similarly to the
[pointer dereference customization interface](/docs/design/values.md#dereferencing-customization).
The returned pointer is then dereferenced by the language to form the reference
expression referring to the pointed-to object. These methods must return a raw
pointer, and do not automatically chain with customized dereference interfaces.
**Open question:** It's not clear that the lack of chaining is necessary, and it
might be more expressive for the pointer type returned by the `Addr` methods to
be an associated type with a default to allow types to produce custom
pointer-like types on their indexing boundary and have them still be
automatically dereferenced.
## Details
A subscript expression has the form "_lhs_ `[` _index_ `]`". As in C++, this
@@ -61,13 +77,15 @@ interface IndirectIndexWith(SubscriptType:! type) {
```
A subscript expression where _lhs_ has type `T` and _index_ has type `I` is
rewritten based on the value category of _lhs_ and whether `T` is known to
rewritten based on the expression category of _lhs_ and whether `T` is known to
implement `IndirectIndexWith(I)`:
- If `T` implements `IndirectIndexWith(I)`, the expression is rewritten to
"`*((` _lhs_ `).(IndirectIndexWith(I).Addr)(` _index_ `))`".
- Otherwise, if _lhs_ is an l-value, the expression is rewritten to "`*((`
_lhs_ `).(IndexWith(I).Addr)(` _index_ `))`".
- Otherwise, if _lhs_ is a
[_durable reference expression_](/docs/design/values.md#durable-reference-expressions),
the expression is rewritten to "`*((` _lhs_ `).(IndexWith(I).Addr)(` _index_
`))`".
- Otherwise, the expression is rewritten to "`(` _lhs_ `).(IndexWith(I).At)(`
_index_ `)`".
@@ -136,3 +154,5 @@ Carbon API.
- Proposal
[#2274: Subscript syntax and semantics](https://github.com/carbon-language/carbon-lang/pull/2274)
- Proposal
[#2006: Values, variables, and pointers](https://github.com/carbon-language/carbon-lang/pull/2006)
+18 -1
View File
@@ -29,9 +29,12 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
## Overview
A _qualified name_ is a [word](../lexical_conventions/words.md) that is preceded
by a period. The name is found within a contextually determined entity:
by a period or a rightward arrow. The name is found within a contextually
determined entity:
- In a member access expression, this is the entity preceding the period.
- In a pointer member access expression, this is the entity pointed to by the
pointer preceding the rightward arrow.
- For a designator in a struct literal, the name is introduced as a member of
the struct type.
@@ -43,10 +46,12 @@ A member access expression is either a _simple_ member access expression of the
form:
- _member-access-expression_ ::= _expression_ `.` _word_
- _member-access-expression_ ::= _expression_ `->` _word_
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.
@@ -66,14 +71,26 @@ class Cog {
fn GrowSomeCogs() {
var cog1: Cog = Cog.Make(1);
var cog2: Cog = cog1.Make(2);
var cog_pointer: Cog* = &cog2;
let cog1_size: i32 = cog1.size;
cog1.Grow(1.5);
cog2.(Cog.Grow)(cog1_size as f64);
cog1.(Widget.Grow)(1.1);
cog2.(Widgets.Cog.(Widgets.Widget.Grow))(1.9);
cog_pointer->Grow(0.75);
cog_pointer->(Widget.Grow)(1.2);
}
```
Pointer member access expressions are those using a `->` instead of a `.` and
their semantics are exactly what would result from first dereferencing the
expression preceding the `->` and then forming a member access expression using
a `.`. For example, a simple pointer member access expression _expression_ `->`
_word_ becomes `(` `*` _expression_ `)` `.` _word_. More details on this syntax
and semantics can be found in the [pointers](/docs/design/values.md#pointers)
design. The rest of this document describes the semantics using `.` alone for
simplicity.
A member access expression is processed using the following steps:
- First, the word or parenthesized expression to the right of the `.` is
@@ -0,0 +1,57 @@
# Pointer operators
<!--
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
-->
<!-- toc -->
## Table of contents
- [Overview](#overview)
- [Details](#details)
- [Precedence](#precedence)
- [Alternatives considered](#alternatives-considered)
- [References](#references)
<!-- tocstop -->
## Overview
Carbon provides the following operators related to pointers:
- `&` as a prefix unary operator takes the address of an object, forming a
pointer to it.
- `*` as a prefix unary operator dereferences a pointer.
Note that [member access expressions](member_access.md) include an `->` form
that implicitly performs a dereference in the same way as the `*` operator.
## Details
The semantic details of pointer operators are collected in the main
[pointers](/docs/design/values.md#pointers) design. The syntax and precedence
details are covered here.
The syntax tries to remain as similar as possible to C++ pointer types as they
are commonly written in code and are expected to be extremely common and a key
anchor of syntactic similarity between the languages.
### Precedence
These operators have high precedence. Only [member access](member_access.md)
expressions can be used as an unparenthesized operand to them.
The two prefix operators `&` and `*` are generally above the other unary and
binary operators and can appear inside them as unparenthesized operands. For the
full details, see the [precedence graph](README.md#precedence).
## Alternatives considered
- [Alternative pointer syntaxes](/proposals/p2006.md#alternative-pointer-syntaxes)
## References
- [Proposal #2006: Values, variables, and pointers](/proposals/p2006.md)
+67
View File
@@ -0,0 +1,67 @@
# Type operators
<!--
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
-->
<!-- toc -->
## Table of contents
- [Overview](#overview)
- [Details](#details)
- [Precedence](#precedence)
- [Alternatives considered](#alternatives-considered)
- [References](#references)
<!-- tocstop -->
## Overview
Carbon provides the following operators to transform types:
- `const` as a prefix unary operator produces a `const`-qualified type.
- `*` as a postfix unary operator produces a pointer _type_ to some other
type.
The pointer type operator is also covered as one of the
[pointer operators](pointer_operators.md).
## Details
The semantic details of both `const`-qualified types and pointer types are
provided as part of the [values](/docs/design/values.md) design:
- [`const`-qualified types](/docs/design/values.md#const-qualified-types)
- [Pointers](/docs/design/values.md#pointers)
The syntax of these operators tries to mimic the most common appearance of
`const` types and pointer types in C++.
### Precedence
Because these are type operators, they don't have many precedence relationship
with non-type operators.
- `const` binds more tightly than `*` and can appear unparenthesized in an
operand, despite being both a unary operator and having whitespace
separating it.
- This allows the syntax of a pointer to a `const i32` to be `const i32*`,
which is intended to be familiar to C++ developers.
- Forming a `const` pointer type requires parentheses: `const (i32*)`.
- All type operators bind more tightly than `as` so they can be used in its
type operand.
- This also allows a desirable transitive precedence with `if`:
`if condition then T* else U*`.
## Alternatives considered
- [Alternative pointer syntaxes](/proposals/p2006.md#alternative-pointer-syntaxes)
- [Alternative syntaxes for locals](/proposals/p2006.md#alternative-syntaxes-for-locals)
- [Make `const` a postfix rather than prefix operator](/proposals/p2006.md#make-const-a-postfix-rather-than-prefix-operator)
## References
- [Proposal #2006: Values, variables, and pointers](/proposals/p2006.md)
+1 -1
View File
@@ -287,7 +287,7 @@ _Binding patterns_ associate a name with a type and a value. This is used to
declare function parameters, in `let` and `var` declarations, as well as to
declare [generic parameters](#generic-means-compile-time-parameterized). There
are three kinds of binding patterns, corresponding to
[the three value phases](/docs/design/README.md#value-categories-and-value-phases):
[the three value phases](/docs/design/README.md#value-phases):
- A _runtime binding pattern_ binds to a dynamic value at runtime, and is
written using a `:`, as in `x: i32`.
+4 -2
View File
@@ -22,7 +22,8 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
[Type inference](https://en.wikipedia.org/wiki/Type_inference) occurs in Carbon
when the `auto` keyword is used. This may occur in
[variable declarations](variables.md) or [function declarations](functions.md).
[variable declarations](values.md#binding-patterns-and-local-variables-with-let-and-var)
or [function declarations](functions.md).
At present, type inference is very simple: given the expression which generates
the value to be used for type inference, the inferred type is the precise type
@@ -30,7 +31,8 @@ of that expression. For example, the inferred type for `auto` in
`fn Foo(x: i64) -> auto { return x; }` is `i64`.
Type inference is currently supported for [function return types](functions.md)
and [declared variable types](variables.md).
and
[declared variable types](values.md#binding-patterns-and-local-variables-with-let-and-var).
## Open questions
File diff suppressed because it is too large Load Diff
-76
View File
@@ -1,76 +0,0 @@
# Variables
<!--
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
-->
<!-- toc -->
## Table of contents
- [Overview](#overview)
- [Notes](#notes)
- [Global variables](#global-variables)
- [Alternatives considered](#alternatives-considered)
- [References](#references)
<!-- tocstop -->
## Overview
Carbon's local variable syntax is:
- `var` _identifier_`:` _< expression |_ `auto` _> [_ `=` _value ]_`;`
Blocks introduce nested scopes and can contain local variable declarations that
work similarly to function parameters.
For example:
```
fn Foo() {
var x: i32 = 42;
}
```
This introduces a local variable named `x` into the block's scope. It has the
type `Int` and is initialized with the value `42`. These variable declarations
(and function declarations) have a lot more power than what we're covering just
yet, but this gives you the basic idea.
If `auto` is used in place of the type, [type inference](type_inference.md) is
used to automatically determine the variable's type.
While there can be global constants, there are no global variables.
## Notes
> TODO: Constant syntax is an ongoing discussion.
### Global variables
We are exploring several different ideas for how to design less bug-prone
patterns to replace the important use cases programmers still have for global
variables. We may be unable to fully address them, at least for migrated code,
and be forced to add some limited form of global variables back. We may also
discover that their convenience outweighs any improvements afforded.
## Alternatives considered
- [No `var` introducer keyword](/proposals/p0339.md#no-var-introducer-keyword)
- [Name of the `var` statement introducer](/proposals/p0339.md#name-of-the-var-statement-introducer)
- [Colon between type and identifier](/proposals/p0339.md#colon-between-type-and-identifier)
- [Type elision](/proposals/p0339.md#type-elision)
- [Type ordering](/proposals/p0618.md#type-ordering)
- [Elide the type instead of using `auto`](/proposals/p0851.md#elide-the-type-instead-of-using-auto)
## References
- Proposal
[#339: `var` statement](https://github.com/carbon-language/carbon-lang/pull/339)
- Proposal
[#618: `var` ordering](https://github.com/carbon-language/carbon-lang/pull/618)
- Proposal
[#851: auto keyword for vars](https://github.com/carbon-language/carbon-lang/pull/851)
+1020
View File
File diff suppressed because it is too large Load Diff