Skip to content

Commit 6d50db0

Browse files
committed
Add "argument ordering and matching"
This adds a whole section describing how generic arguments are matched with their parameters.
1 parent 345774c commit 6d50db0

1 file changed

Lines changed: 127 additions & 3 deletions

File tree

src/types/generics/index.md

Lines changed: 127 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,133 @@ GenericArgsBounds ->
9999
IDENTIFIER GenericArgs? `:` Bounds
100100
```
101101
102-
r[generics.arguments.argument-order]
103-
The order of generic arguments is restricted to lifetime arguments, then type arguments, then const arguments, then equality constraints.
102+
### Argument ordering and matching
103+
104+
r[generics.arguments.lifetime-order]
105+
Lifetime arguments must appear before all other argument kinds.
106+
107+
> [!EXAMPLE]
108+
> ```rust,compile_fail
109+
> struct Foo<'a, T> {
110+
> data: &'a T,
111+
> }
112+
>
113+
> // ERROR: lifetime argument `'static` must come before type argument `i32`
114+
> let _: Foo<i32, 'static>;
115+
> ```
116+
117+
r[generics.arguments.positional-matching]
118+
Generic arguments are matched to generic parameters positionally:
119+
120+
- The i<sub>th</sub> lifetime argument corresponds to the i<sub>th</sub> lifetime parameter.
121+
- The i<sub>th</sub> type or const argument corresponds to the i<sub>th</sub> type or const parameter (counted together in declaration order).
122+
123+
r[generics.arguments.constraint-order]
124+
Associated item constraints must be listed after all other argument kinds, and may be listed in any order.
125+
126+
> [!EXAMPLE]
127+
> ```rust
128+
> use std::fmt::Display;
129+
>
130+
> trait Container {
131+
> type Item;
132+
> type Error;
133+
> }
134+
>
135+
> // Associated item constraints may be listed in any order relative to each other.
136+
> fn process<C: Container<Error = String, Item = i32>>(_: C) {}
137+
> ```
138+
139+
> [!EXAMPLE]
140+
> ```rust,compile_fail
141+
> struct Foo<'a, T> {
142+
> data: &'a T,
143+
> }
144+
>
145+
> trait MyTrait {
146+
> type Assoc;
147+
> }
148+
>
149+
> // ERROR: associated item constraints must come after all other argument kinds.
150+
> fn bad<T: MyTrait>(_: &dyn MyTrait<Assoc = i32>) where T: 'static {}
151+
> let _: std::collections::HashMap<Item = i32, String, String>;
152+
> ```
153+
154+
r[generics.arguments.lifetime-elision]
155+
Lifetime arguments may be omitted in the following cases:
156+
157+
- When [lifetime elision] rules apply.
158+
- In [turbofish] expressions (`::<...>`) where all lifetimes can be inferred.
159+
160+
> [!EXAMPLE]
161+
> ```rust
162+
> struct Foo<'a, T> {
163+
> data: &'a T,
164+
> }
165+
>
166+
> fn make_foo<'a, T>(data: &'a T) -> Foo<'a, T> {
167+
> Foo { data }
168+
> }
169+
>
170+
> // Turbofish: lifetime arguments omitted because they can be inferred.
171+
> let x = 42i32;
172+
> let foo = make_foo::<i32>(&x); // `'_` lifetime argument elided in turbofish
173+
>
174+
> // Lifetime arguments omitted in a type annotation.
175+
> let foo: Foo<i32> = Foo { data: &x };
176+
> ```
177+
178+
r[generics.arguments.all-lifetimes]
179+
If any lifetime argument is provided, then all lifetime parameters must be specified.
180+
181+
> [!EXAMPLE]
182+
> ```rust,compile_fail
183+
> struct Foo<'a, 'b, T> {
184+
> x: &'a T,
185+
> y: &'b T,
186+
> }
187+
>
188+
> fn make_foo<'a, 'b, T>(x: &'a T, y: &'b T) -> Foo<'a, 'b, T> {
189+
> Foo { x, y }
190+
> }
191+
>
192+
> let a = 1i32;
193+
> let b = 2i32;
194+
>
195+
> // OK: no lifetime arguments supplied (elided).
196+
> let _: Foo<i32> = Foo { x: &a, y: &b };
197+
> // OK: all lifetime arguments supplied.
198+
> let _: Foo<'static, 'static, i32> = Foo { x: &1, y: &2 };
199+
> // ERROR: only one of two lifetime arguments provided.
200+
> let _: Foo<'static, i32> = Foo { x: &1, y: &b };
201+
> ```
202+
203+
r[generics.arguments.defaults]
204+
Type and const parameters with default values need not be supplied. A parameter without a default cannot follow one with a default.
205+
206+
When fewer arguments are supplied than parameters exist, the missing trailing arguments use their defaults if available, or are inferred if inference is enabled for that context.
207+
208+
r[generics.arguments.self-param]
209+
The `Self` parameter (when present, e.g., in [trait definitions][items.traits.self-param]) is implicit and cannot be explicitly specified.
104210
105211
r[generics.arguments.impl-trait-params]
106-
The synthetic type parameters corresponding to `impl Trait` types are implicit, and these cannot be explicitly specified.
212+
Synthetic type parameters corresponding to `impl Trait` types are implicit and cannot be explicitly specified.
213+
214+
r[generics.arguments.late-bound-lifetimes]
215+
It is an error to provide explicit lifetime arguments when late-bound lifetimes are present.
216+
217+
> [!EXAMPLE]
218+
> ```rust,compile_fail
219+
> fn foo<'a>(x: &'a str) -> &'a str { x }
220+
>
221+
> // ERROR: cannot specify late-bound lifetime arguments explicitly
222+
> foo::<'static>("hello");
223+
> ```
224+
225+
<!--
226+
FCW exists for non-value (function) position, see
227+
https://doc.rust-lang.org/nightly/rustc/lints/listing/warn-by-default.html#late-bound-lifetime-arguments
228+
-->
107229
108230
r[generics.const]
109231
## Const generics
@@ -333,6 +455,7 @@ struct Foo<#[my_flexible_clone(unbounded)] H> {
333455
[inferred const]: generics.const.inferred
334456
[item declarations]: statement.item
335457
[item]: items
458+
[lifetime elision]: lifetime-elision
336459
[literal]: expr.literal
337460
[path expression]: expr.path
338461
[path]: paths
@@ -345,6 +468,7 @@ struct Foo<#[my_flexible_clone(unbounded)] H> {
345468
[trait object]: type.trait-object
346469
[traits]: items.traits
347470
[tuples]: type.tuple
471+
[turbofish]: paths.expr.turbofish
348472
[type aliases]: items.type
349473
[unions]: items.union
350474
[value namespace]: names.namespaces

0 commit comments

Comments
 (0)