Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document const functions #440

Merged
merged 13 commits into from
Oct 13, 2018
2 changes: 2 additions & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@
- [Behavior considered undefined](behavior-considered-undefined.md)
- [Behavior not considered unsafe](behavior-not-considered-unsafe.md)

- [Constant Evalutation](const_eval.md)

[Appendix: Influences](influences.md)

[Appendix: As-yet-undocumented Features](undocumented.md)
Expand Down
82 changes: 82 additions & 0 deletions src/const_eval.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Constant evaluation

Constant evaluation is the process of computing the result of
[expressions] during compilation. Only a subset of all expressions
can be evaluated at compile-time.

## Constant expressions

Certain types of expressions can be evaluated at compile time. These are called
_constant expressions_ and are required in const contexts. In
other places, such as in [`let` statements](statements.html#let-statements),
constant expressions may be evaluated at compile time. If errors, such as out
of bounds [array indexing] or [overflow] occurs,
then it is a compiler error if the value must be evaluated at compile time,
otherwise it is just a warning, but the code will most likely panic when run.

The following expressions are constant expressions, so long as any operands are
also constant expressions and do not cause any [`Drop::drop`][destructors] calls
to be ran.

* [Literals].
* [Paths] to [functions](items/functions.html) and constants.
Recursively defining constants is not allowed.
* [Tuple expressions].
* [Array expressions].
* [Struct] expressions.
* [Enum variant] expressions.
* [Block expressions], including `unsafe` blocks, which only contain items and
possibly a constant tail expression.
* [Field] expressions.
* Index expressions, [array indexing] or [slice] with a `usize`.
* [Range expressions].
* [Closure expressions] which don't capture variables from the environment.
* Built in [negation], [arithmetic, logical], [comparison] or [lazy boolean]
operators used on integer and floating point types, `bool` and `char`.
* Shared [borrow]s, except if applied to a type with [interior mutability].
* The [dereference operator].
* [Grouped] expressions.
* [Cast] expressions, except pointer to address and
function pointer to address casts.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing a bullet point for calling const fns.

* calls of const functions and const methods

## Const context

A _const context_ is one of the following:

* [array type length expressions]
* repeat expression length expessions
* the initializer of
* [constants]
* [statics]
* [enum discriminants]

[array type length expressions]: types.html#array-and-slice-types
[enum discriminants]: items/enumerations.html#custom-discriminant-values-for-field-less-enumerations
[constants]: items/constant-items.html
[statics]: items/static-items.html
[expressions]: expressions.html
[array indexing]: expressions/array-expr.html#array-and-slice-indexing-expressions
[overflow]: expressions/operator-expr.html#overflow
[destructors]: destructors.html
[literals]: expressions/literal-expr.html
[paths]: expressions/path-expr.html
[tuple expressions]: expressions/tuple-expr.html
[array expressions]: expressions/array-expr.html
[struct]: expressions/struct-expr.html
[enum variant]: expressions/enum-variant-expr.html
[block expressions]: expressions/block-expr.html
[field]: expressions/field-expr.html
[array indexing]: expressions/array-expr.html#array-and-slice-indexing-expressions
[slice]: types.html#array-and-slice-types
[range expressions]: expressions/range-expr.html
[closure expressions]: expressions/closure-expr.html
[negation]: expressions/operator-expr.html#negation-operators
[arithmetic, logical]: expressions/operator-expr.html#arithmetic-and-logical-binary-operators
[comparison]: expressions/operator-expr.html#comparison-operators
[lazy boolean]: expressions/operator-expr.html#lazy-boolean-operators
[borrow]: expressions/operator-expr.html#borrow-operators
[interior mutability]: interior-mutability.html
[dereference operator]: expressions/operator-expr.html#the-dereference-operator
[grouped]: expressions/grouped-expr.html
[cast]: expressions/operator-expr.html#type-cast-expressions
38 changes: 1 addition & 37 deletions src/expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,43 +229,6 @@ Implicit borrows may be taken in the following expressions:
* Operands of [comparison].
* Left operands of the [compound assignment].

## Constant expressions

Certain types of expressions can be evaluated at compile time. These are called
_constant expressions_. Certain places, such as in
[constants](items/constant-items.html) and [statics](items/static-items.html),
require a constant expression, and are always evaluated at compile time. In
other places, such as in [`let` statements](statements.html#let-statements),
constant expressions may be evaluated at compile time. If errors, such as out
of bounds [array indexing] or [overflow] occurs,
then it is a compiler error if the value must be evaluated at compile time,
otherwise it is just a warning, but the code will most likely panic when run.

The following expressions are constant expressions, so long as any operands are
also constant expressions and do not cause any [`Drop::drop`][destructors] calls
to be ran.

* [Literals].
* [Paths] to [functions](items/functions.html) and constants.
Recursively defining constants is not allowed.
* [Tuple expressions].
* [Array expressions].
* [Struct] expressions.
* [Enum variant] expressions.
* [Block expressions], including `unsafe` blocks, which only contain items and
possibly a constant tail expression.
* [Field] expressions.
* Index expressions, [array indexing] or [slice] with a `usize`.
* [Range expressions].
* [Closure expressions] which don't capture variables from the environment.
* Built in [negation], [arithmetic, logical], [comparison] or [lazy boolean]
operators used on integer and floating point types, `bool` and `char`.
* Shared [borrow]s, except if applied to a type with [interior mutability].
* The [dereference operator].
* [Grouped] expressions.
* [Cast] expressions, except pointer to address and
function pointer to address casts.

## Overloading Traits

Many of the following operators and expressions can also be overloaded for
Expand Down Expand Up @@ -313,6 +276,7 @@ exist in `core::ops` and `core::cmp` with the same names.
[let]: statements.html#let-statements
[let statement]: statements.html#let-statements
[Mutable `static` items]: items/static-items.html#mutable-statics
[const contexts]: const_eval.html
[slice]: types.html#array-and-slice-types
[static variables]: items/static-items.html
[Temporary values]: #temporary-lifetimes
Expand Down
58 changes: 57 additions & 1 deletion src/items/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
>       [_BlockExpression_]
>
> _FunctionFront_ :\
> &nbsp;&nbsp; `unsafe`<sup>?</sup> (`extern` _Abi_<sup>?</sup>)<sup>?</sup>
> &nbsp;&nbsp; `const`<sup>?</sup> `unsafe`<sup>?</sup> (`extern` _Abi_<sup>?</sup>)<sup>?</sup>
>
> _Abi_ :\
> &nbsp;&nbsp; [STRING_LITERAL] | [RAW_STRING_LITERAL]
Expand Down Expand Up @@ -160,6 +160,59 @@ attributes], [`must_use`], [the procedural macro attributes], [the testing
attributes], and [the optimization hint
attributes].

## Const functions

Functions can be `const`, meaning they can be called from within
Copy link
Contributor

@Centril Centril Oct 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would somehow explain here that this applies so long as provided arguments (expressions) to the functions explicit formal parameters (e.g. those within (...) but not those within <...> which are rather implicit formal parameters) are also valid in const contexts.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't do that for operators. I don't see how add(x, y) differs from x + y in the "explain constness"-aspect

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say we should do that for operators in that case. This is the reference, so better be as unambiguous as we can be.

[const contexts]. When called from a const context, the function is interpreted
by the compiler at compile time. The interpretation happens in the environment
of the compilation target and not the host. So `usize` is `32` bits if you are
compiling against a `32` bit system, irrelevant of whether you are building on
a `64` bit or a `32` bit system.

If a const function is called outside a "const context", it is indistinguishable
from any other function. You can freely do anything with a const function that
you can do with a regular function.

const functions have various restrictions to makes sure that you cannot define a
const function that can't be evaluated at compile-time. It is, for example, not
possible to write a random number generator as a const function. Calling a
const function at compile-time will always yield the same result as calling it at
runtime, even when called multiple times. There's one exception to this rule:
if you are doing complex floating point operations in extreme situations,
then you might get (very slightly) different results.
It is adviseable to not make array lengths and enum discriminants depend
on floating point computations.

Exhaustive list of permitted structures in const functions:

> **Note**: this list is more restrictive than what you can write in
> regular constants

* type parameters where the parameters only have any [trait bounds]
of the following kind:
* lifetimes
* `Sized` or [`?Sized`]

This means that `<T: 'a + ?Sized>`, `<T: 'b + Sized>` and `<T>`
are all permitted.

This rule also applies to type parameters of impl blocks that
contain const methods

* arithmetic and comparison operators on integers
* all boolean operators except for `&&` and `||` which are banned since
they are short-circuiting.
* any kind of aggregate constructor (array, `struct`, `enum`, tuple, ...)
* calls to other *safe* const functions (whether by function call or method call)
* index expressions on arrays and slices
* field accesses on structs and tuples
* reading from constants (but not statics, not even taking a reference to a static)
* `&` and `*` (only dereferencing of references, not raw pointers)
* casts except for raw pointer to integer casts
* `const unsafe fn` is allowed, but the body must consist of safe operations
only and you won't be able to call the `const unsafe fn` from within another
const function even if you use `unsafe`

[IDENTIFIER]: identifiers.html
[RAW_STRING_LITERAL]: tokens.html#raw-string-literals
[STRING_LITERAL]: tokens.html#string-literals
Expand All @@ -170,6 +223,7 @@ attributes].
[_Statement_]: statements.html
[_Type_]: types.html
[_WhereClause_]: items/generics.html#where-clauses
[const contexts]: const_eval.html
[external blocks]: items/external-blocks.html
[path]: paths.html
[block]: expressions/block-expr.html
Expand All @@ -187,3 +241,5 @@ attributes].
[`doc`]: attributes.html#documentation
[`must_use`]: attributes.html#must_use
[patterns]: patterns.html
[`?Sized`]: trait-bounds.html#sized
[trait bounds]: trait-bounds.html