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

Generic parameters #258

Merged
merged 4 commits into from
May 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
- [Traits](items/traits.md)
- [Implementations](items/implementations.md)
- [External blocks](items/external-blocks.md)
- [Type and lifetime parameters](items/generics.md)
- [Associated Items](items/associated-items.md)
- [Visibility and Privacy](visibility-and-privacy.md)
- [Attributes](attributes.md)
Expand Down Expand Up @@ -66,6 +67,7 @@
- [Type layout](type-layout.md)
- [Interior mutability](interior-mutability.md)
- [Subtyping and Variance](subtyping.md)
- [Trait and lifetime bounds](trait-bounds.md)
- [Type coercions](type-coercions.md)
- [Destructors](destructors.md)
- [Lifetime elision](lifetime-elision.md)
Expand Down
19 changes: 0 additions & 19 deletions src/items.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,3 @@ as if the item was declared outside the scope — it is still a static item
qualified by the name of the enclosing item, or is private to the enclosing
item (in the case of functions). The grammar specifies the exact locations in
which sub-item declarations may appear.

## Type Parameters

Functions, type aliases, structs, enumerations, unions, traits and
implementations may be *parameterized* by type. Type parameters are given as a
comma-separated list of identifiers enclosed in angle brackets (`<...>`), after
the name of the item (except for implementations, where they come directly
after `impl`) and before its definition.

The type parameters of an item are considered "part of the name", not part of
the type of the item. A referencing [path] must (in principle) provide type
arguments as a list of comma-separated types enclosed within angle brackets, in
order to refer to the type-parameterized item. In practice, the type-inference
system can usually infer such argument types from context. There are no general
type-parametric types, only type-parametric items. That is, Rust has no notion
of type abstraction: there are no higher-ranked (or "forall") types abstracted
over other types, though higher-ranked types do exist for lifetimes.

[path]: paths.html
4 changes: 2 additions & 2 deletions src/items/enumerations.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ enum ZeroVariants {}
```

[IDENTIFIER]: identifiers.html
[_Generics_]: items.html#type-parameters
[_WhereClause_]: items.html#type-parameters
[_Generics_]: items/generics.html
[_WhereClause_]: items/generics.html#where-clauses
[_Expression_]: expressions.html
[_TupleFields_]: items/structs.html
[_StructFields_]: items/structs.html
Expand Down
106 changes: 106 additions & 0 deletions src/items/generics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Type and Lifetime Parameters
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a reason this is named items/generics.md and not types_and_lifetime_parameters.md?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Name length. Maybe to avoid issues once constant parameters are stabilized.


> **<sup>Syntax</sup>**
> _Generics_ :
> &nbsp;&nbsp; `<` _GenericParams_ `>`
>
> _GenericParams_ :
> &nbsp;&nbsp; &nbsp;&nbsp; _LifetimeParams_
> &nbsp;&nbsp; | ( _LifetimeParam_ `,` )<sup>\*</sup> _TypeParams_
>
> _LifetimeParams_ :
> &nbsp;&nbsp; ( _LifetimeParam_ `,` )<sup>\*</sup> _LifetimeParam_<sup>?</sup>
>
> _LifetimeParam_ :
> &nbsp;&nbsp; [LIFETIME_OR_LABEL] `:` [_LifetimeBounds_]<sup>?</sup>
>
> _TypeParams_:
> &nbsp;&nbsp; ( _TypeParam_ `,` )<sup>\*</sup> _TypeParam_ <sup>?</sup>
>
> _TypeParam_ :
> &nbsp;&nbsp; [IDENTIFIER] ( `:` [_TypeParamBounds_] )<sup>?</sup> ( `=` [_Type_] )<sup>?</sup>

Functions, type aliases, structs, enumerations, unions, traits and
implementations may be *parameterized* by types and lifetimes. These parameters
are listed in angle <span class="parenthetical">brackets (`<...>`)</span>,
usually immediately after and before its definition the name of the item. For
implementations, which don't have a name, they come directly after `impl`.
Lifetime parameters must be declared before type parameters. Some examples of
items with type and lifetime parameters:

```rust
fn foo<'a, T>() {}
trait A<U> {}
struct Ref<'a, T> where T: 'a { r: &'a T }
```

[References], [raw pointers], [arrays], [slices][arrays], [tuples] and
[function pointers] have lifetime or type parameters as well, but are not
referred to with path syntax.

## Where clauses

> **<sup>Syntax</sup>**
> _WhereClause_ :
> &nbsp;&nbsp; `where` ( _WhereClauseItem_ `,` )<sup>\*</sup> _WhereClauseItem_ <sup>?</sup>
>
> _WhereClauseItem_ :
> &nbsp;&nbsp; &nbsp;&nbsp; _LifetimeWhereClauseItem_
> &nbsp;&nbsp; | _TypeBoundWhereClauseItem_
>
> _LifetimeWhereClauseItem_ :
> &nbsp;&nbsp; [_Lifetime_] `:` [_LifetimeBounds_]
>
> _TypeBoundWhereClauseItem_ :
> &nbsp;&nbsp; _ForLifetimes_<sup>?</sup> [_Type_] `:` [_TypeParamBounds_]<sup>?</sup>
>
> _ForLifetimes_ :
> &nbsp;&nbsp; `for` `<` [_LifetimeParams_](#type-and-lifetime-parameters) `>`

*Where clauses* provide an another way to specify bounds on type and lifetime
parameters as well as a way to specify bounds on types that aren't type
parameters.

Bounds that don't use the item's parameters or higher-ranked lifetimes are
checked when the item is defined. It is an error for such a bound to be false.

[`Copy`], [`Clone`] and [`Sized`] bounds are also checked for certain generic
types when defining the item. It is an error to have `Copy` or `Clone`as a
bound on a mutable reference, [trait object] or [slice][arrays] or `Sized` as a
bound on a trait object or slice.

```rust,ignore
struct A<T>
where
T: Iterator, // Could use A<T: Iterator> instead
T::Item: Copy,
String: PartialEq<T>,
i32: Default, // Allowed, but not useful
i32: Iterator, // Error: the trait bound is not satisfied
[T]: Copy, // Error: the trait bound is not satisfied
{
f: T,
}
```

[IDENTIFIER]: identifiers.html
[LIFETIME_OR_LABEL]: tokens.html#lifetimes-and-loop-labels

[_LifetimeBounds_]: trait-bounds.html
[_Lifetime_]: trait-bounds.html
[_Type_]: types.html
[_TypeParamBounds_]: trait-bounds.html

[arrays]: types.html#array-and-slice-types
[function pointers]: types.html#function-pointer-types
[references]: types.html#shared-references-
[raw pointers]: types.html#raw-pointers-const-and-mut
[`Clone`]: special-types-and-traits.html#clone
[`Copy`]: special-types-and-traits.html#copy
[`Sized`]: special-types-and-traits.html#sized
[tuples]: types.html#tuple-types
[trait object]: types.html#trait-objects

[path]: ../paths.html
[Trait]: traits.html#trait-bounds
[_TypePath_]: paths.html
4 changes: 2 additions & 2 deletions src/items/structs.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ particular layout using the [`repr` attribute].

[_OuterAttribute_]: attributes.html
[IDENTIFIER]: identifiers.html
[_Generics_]: items.html#type-parameters
[_WhereClause_]: items.html#type-parameters
[_Generics_]: items/generics.html
[_WhereClause_]: items/generics.html#where-clauses
[_Visibility_]: visibility-and-privacy.html
[_Type_]: types.html
32 changes: 2 additions & 30 deletions src/items/traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,7 @@ any implementation must provide a definition.

## Trait bounds

Generic functions may use traits as _bounds_ on their type parameters. This
will have three effects:

- Only types that have the trait may instantiate the parameter.
- Within the generic function, the functions of the trait can be called on
values that have the parameter's type. Associated types can be used in the
function's signature, and associated constants can be used in expressions
within the function body.
- Generic functions and types with the same or weaker bounds can use the
generic type in the function body or signature.

For example:

```rust
# type Surface = i32;
# trait Shape { fn draw(&self, Surface); }
struct Figure<S: Shape>(S, S);
fn draw_twice<T: Shape>(surface: Surface, sh: T) {
sh.draw(surface);
sh.draw(surface);
}
fn draw_figure<U: Shape>(surface: Surface, Figure(sh1, sh2): Figure<U>) {
sh1.draw(surface);
draw_twice(surface, sh2); // Can call this since U: Shape
}
```
Generic items may use traits as [bounds] on their type parameters.
Copy link
Contributor

Choose a reason for hiding this comment

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

If you're going to gut this section, then fold this into another section somehow.


## Generic Traits

Expand Down Expand Up @@ -140,10 +115,7 @@ let mycircle = Box::new(mycircle) as Box<Circle>;
let nonsense = mycircle.radius() * mycircle.area();
```

[`Send`]: ../std/marker/trait.Send.html
[`Send`]: ../std/marker/trait.Sync.html
[`UnwindSafe`]: ../std/panic/trait.UnwindSafe.html
[`RefUnwindSafe`]: ../std/panic/trait.RefUnwindSafe.html
[bounds]: trait-bounds.html
[trait object]: types.html#trait-objects
[explicit]: expressions/operator-expr.html#type-cast-expressions
[RFC 255]: https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md
Expand Down
4 changes: 2 additions & 2 deletions src/items/type-aliases.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ let _: F = E::A; // OK
```

[IDENTIFIER]: identifiers.html
[_Generics_]: items.html#type-parameters
[_WhereClause_]: items.html#type-parameters
[_Generics_]: items/generics.html
[_WhereClause_]: items/generics.html#where-clauses
[_Type_]: types.html
4 changes: 2 additions & 2 deletions src/items/unions.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,6 @@ More detailed specification for unions, including unstable bits, can be found
in [RFC 1897 "Unions v1.2"](https://github.com/rust-lang/rfcs/pull/1897).

[IDENTIFIER]: identifiers.html
[_Generics_]: items.html#type-parameters
[_WhereClause_]: items.html#type-parameters
[_Generics_]: items/generics.html
[_WhereClause_]: items/generics.html#where-clauses
[_StructFields_]: items/structs.html
148 changes: 148 additions & 0 deletions src/trait-bounds.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# Trait and lifetime bounds

> **<sup>Syntax</sup>**
> _TypeParamBounds_ :
> &nbsp;&nbsp; _TypeParamBound_ ( `+` _TypeParamBound_ )<sup>\*</sup> `+`<sup>?</sup>
Copy link
Contributor

Choose a reason for hiding this comment

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

Not actionable, but I wish we had syntax for this pattern that pops up everywhere in our grammar.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Some of the Rust parsers that people have written define something for this (example), but I'm not sure how far we want to stray from common ways of defining syntax.

>
> _TypeParamBound_ :
> &nbsp;&nbsp; &nbsp;&nbsp; _Lifetime_ | _TraitBound_
>
> _TraitBound_ :
> &nbsp;&nbsp; &nbsp;&nbsp; `?`<sup>?</sup>
> [_ForLifetimes_](#higher-ranked-trait-bounds)<sup>?</sup> [_TraitPath_]
> &nbsp;&nbsp; | `(` `?`<sup>?</sup>
> [_ForLifetimes_](#higher-ranked-trait-bounds)<sup>?</sup> [_TraitPath_] `)`
>
> _LifetimeBounds_ :
> &nbsp;&nbsp; ( _Lifetime_ `+` )<sup>\*</sup> _Lifetime_<sup>?</sup>
>
> _Lifetime_ :
> &nbsp;&nbsp; &nbsp;&nbsp; [LIFETIME_OR_LABEL]
> &nbsp;&nbsp; | `'static`

[Trait] and lifetime bounds provide a way for [generic items][generic] to
restrict which types and lifetimes are used as their parameters. Bounds can be
provided on any type in a [where clause]. There are also shorter forms for
certain common cases:

* Bounds written after declaring a [generic parameter][generic]:
`fn f<A: Copy>() {}` is the same as `fn f<A> where A: Copy () {}`.
* In trait declarations as [supertraits]: `trait Circle : Shape {}` is
equivalent to `trait Circle where Self : Shape {}`.
* In trait declarations as bounds on [associated types]:
`trait A { type B: Copy; }` is equivalent to
`trait A where Self::B: Copy { type B; }`.

Bounds on an item must be satisfied when using the item. When type checking and
borrow checking a generic item, the bounds can be used to determine that a
trait is implemented for a type. For example, given `Ty: Trait`

* In the body of a generic function, methods from `Trait` can be called on `Ty`
values. Likewise associated constants on the `Trait` can be used.
* Associated types from `Trait` can be used.
* Generic functions and types with a `T: Trait` bounds can be used with `Ty`
being used for `T`.

```rust
# type Surface = i32;
trait Shape {
fn draw(&self, Surface);
fn name() -> &'static str;
}

fn draw_twice<T: Shape>(surface: Surface, sh: T) {
sh.draw(surface); // Can call method because T: Shape
sh.draw(surface);
}

fn copy_and_draw_twice<T: Copy>(surface: Surface, sh: T) where T: Shape {
let shape_copy = sh; // doesn't move sh because T: Copy
draw_twice(surface, sh); // Can use generic function because T: Shape
}

struct Figure<S: Shape>(S, S);

fn name_figure<U: Shape>(
figure: Figure<U>, // Type Figure<U> is well-formed because U: Shape
) {
println!(
"Figure of two {}",
U::name(), // Can use associated function
);
}
```

Trait and lifetime bounds are also used to name [trait objects].

## `?Sized`

`?` is only used to declare that the [`Sized`] trait may not be
implemented for a type parameter or associated type. `?Sized` may
not be used as a bound for other types.

## Lifetime bounds

Lifetime bounds can be applied to types or other lifetimes. The bound `'a: 'b`
is usually read as `'a` *outlives* `'b`. `'a: 'b` means that `'a` lasts longer
than `'b`, so a reference `&'a ()` is valid whenever `&'b ()` is valid.

```rust
fn f<'a, 'b>(x: &'a i32, mut y: &'b i32) where 'a: 'b {
y = x; // &'a i32 is a subtype of &'b i32 because 'a: 'b
let r: &'b &'a i32 = &&0; // &'b &'a i32 is well formed because 'a: 'b
}
```

`T: 'a` means that all lifetime parameters of `T` outlive `'a`. For example if
`'a` is an unconstrained lifetime parameter then `i32: 'static` and
`&'static str: 'a` are satisfied but `Vec<&'a ()>: 'static` is not.

## Higher-ranked trait bounds

Type bounds may be *higher ranked* over lifetimes. These bounds specify a bound
is true *for all* lifetimes. For example, a bound such as `for<'a> &'a T:
PartialEq<i32>` would require an implementation like

```rust,ignore
impl<'a> PartialEq<i32> for &'a T {
// ...
}
```

and could then be used to compare a `&'a T` with any lifetime to an `i32`.

Only a higher-ranked bound can be used here as the lifetime of the reference is
shorter than a lifetime parameter on the function:

```rust
fn call_on_ref_zero<F>(f: F) where for<'a> F: Fn(&'a i32) {
let zero = 0;
f(&zero);
}
```

Higher-ranked lifetimes may also be specified just before the trait, the only
end of the following trait instead of the whole bound. This function is
difference is the scope of the lifetime parameter, which extends only to the
equivalent to the last one.

```rust
fn call_on_ref_zero<F>(f: F) where F: for<'a> Fn(&'a i32) {
let zero = 0;
f(&zero);
}
```

> Warning: lifetime bounds are allowed on lifetimes in a `for` binder, but have
> no effect: `for<'a, 'b: 'a>` is no different to `for<'a, 'b>`.

[LIFETIME_OR_LABEL]: tokens.html#lifetimes-and-loop-labels
[_TraitPath_]: paths.html
[`Sized`]: special-types-and-traits.html#sized

[associated types]: items/associated-items.html#associated-types
[supertraits]: items/traits.html#supertraits
[generic]: items/generics.html
[Trait]: traits.html#trait-bounds
[trait objects]: types.html#trait-objects
[where clause]: items/where-clauses.html
9 changes: 3 additions & 6 deletions src/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -537,12 +537,9 @@ Because captures are often by reference, the following general rules arise:

## Trait objects

> **<sup>Syntax</sup>**
> _TraitObjectType_ :
> &nbsp;&nbsp; `dyn`<sup>?</sup> _LifetimeOrPath_ ( `+` _LifetimeOrPath_ )<sup>\*</sup> `+`<sup>?</sup>
>
> _LifetimeOrPath_ :
> &nbsp;&nbsp; [_Path_] | `(` [_Path_] `)` | [_LIFETIME_OR_LABEL_]
> **<sup>Syntax</sup>**
> _TraitObjectType_ :
> &nbsp;&nbsp; `dyn`<sup>?</sup> _TypeParamBounds_

A *trait object* is an opaque value of another type that implements a set of
traits. The set of traits is made up of an [object safe] *base trait* plus any
Expand Down