You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/rust-2021/prelude.md
+74-31Lines changed: 74 additions & 31 deletions
Original file line number
Diff line number
Diff line change
@@ -36,64 +36,107 @@ The tracking issue [can be found here](https://github.com/rust-lang/rust/issues/
36
36
37
37
As a part of the 2021 edition a migration lint, `rust_2021_prelude_collisions`, has been added in order to aid in automatic migration of Rust 2018 codebases to Rust 2021.
38
38
39
-
In order to have rustfix migrate your code to be Rust 2021 Edition compatible, run:
39
+
In order to have `rustfix` migrate your code to be Rust 2021 Edition compatible, run:
40
40
41
-
```ignore
41
+
```sh
42
42
cargo fix --edition
43
43
```
44
44
45
45
The lint detects cases where functions or methods are called that have the same name as the methods defined in one of the new prelude traits. In some cases, it may rewrite your calls in various ways to ensure that you continue to call the same function you did before.
46
46
47
-
### Fully qualified calls to inherent methods
47
+
If you'd like to migrate your code manually or better understand what `rustfix` is doing, below we've outlined the situations where a migration is needed along with a counter example of when it's not needed.
48
48
49
-
Many types define their own inherent methods with the name `from_iter` which shares the same name with `std::iter::FromIterator::from_iter`:
49
+
### Migration needed
50
+
51
+
#### Conflicting trait methods
52
+
53
+
When two traits that are in scope have the same method name, it is ambiguous which trait method should be used. For example:
50
54
51
55
```rust
52
-
structMyStruct {
53
-
data:Vec<u32>
56
+
traitMyTrait<A> {
57
+
// This name is the same as the `from_iter` method on the `FromIterator` trait from `std`.
58
+
fnfrom_iter(x:Option<A>);
54
59
}
55
60
56
-
implMyStruct {
57
-
// This has the same name as `std::iter::FromIterator::from_iter`
58
-
fnfrom_iter(x:implIterator<Item=u32>) ->Self {
59
-
Self {
60
-
data:x.collect()
61
-
}
62
-
}
61
+
impl<T> MyTrait<()> forVec<T> {
62
+
fnfrom_iter(_:Option<()>) {}
63
63
}
64
-
```
65
64
66
-
In case that already use a fully qualified inherent method syntax (e.g., calls like `MyStruct::from_iter`), there is not ambiguity with calls to trait methods (e.g., `<MyStruct as FromIter>::from_iter`), because inherent methods take precedence over trait methods. Therefore, no migration is needed.
65
+
fnmain() {
66
+
// Vec<T> implements both `std::iter::FromIterator` and `MyTrait`
67
+
// If both traits are in scope (as would be the case in Rust 2021),
68
+
// then it becomes ambiguous which `from_iter` method to call
69
+
<Vec<i32>>::from_iter(None);
70
+
}
71
+
```
67
72
68
-
A migration is necessary when using "dot method" syntax where the method name is the same as the trait method name for a trait which is now
69
-
in scope. For example, a call like `my_struct.into_iter()` where `into_iter()` used to refer to an inherent method on `MyStruct` but now conflicts with
70
-
the trait method from `IntoIter`. To make these calls unambiguous, fully qualified inherent method syntax must be used:
73
+
We can fix this by using fully qualified syntax:
71
74
72
75
```rust,ignore
73
-
// Before:
74
-
my_struct.into_iter();
75
-
// After:
76
-
MyStruct::into_iter(my_struct);
76
+
fn main() {
77
+
// Now it is clear which trait method we're referring to
78
+
<Vec<i32> as MyTrait<i32>>::from_iter(None);
79
+
}
77
80
```
78
81
79
-
Note: this only impacts methods which take `&self` and `&mut self` but not `self`.
80
-
81
-
### Inherent methods on `dyn Trait` objects
82
+
#### Inherent methods on `dyn Trait` objects
82
83
83
84
Some users invoke methods on a `dyn Trait` value where the method name overlaps with a new prelude trait:
84
85
85
86
```rust
86
-
traitMyTrait {
87
-
// This has the same name as `std::iter::IntoIterator::into_iter`
88
-
fninto_iter(&self);
87
+
modsubmodule {
88
+
traitMyTrait {
89
+
// This has the same name as `TryInto::try_into`
90
+
fntry_into(&self) ->Result<u32, ()>;
91
+
}
92
+
}
93
+
94
+
// `MyTrait` isn't in scope here and can only be referred to through the path `submodule::MyTrait`
95
+
fnbar(f:Box<dynsubmodule::MyTrait>) {
96
+
// If `std::convert::TryInto` is in scope (as would be the case in Rust 2021),
97
+
// then it becomes ambiguous which `try_into` method to call
98
+
f.try_into();
99
+
}
100
+
```
101
+
102
+
Unlike with static dispatch methods, calling a trait method on a trait object does not require that the trait be in scope. The code above works
103
+
as long as there is no trait in scope with a conflicting method name. When the `TryInto` trait is in scope (which is the case in Rust 2021),
104
+
this causes an ambiguity. Should the call be to `MyTrait::try_into` or `std::convert::TryInto::try_into`?
105
+
106
+
In these cases, we can fix this by adding an additional dereferences or otherwise clarify the type of the method receiver. This ensures that
107
+
the `dyn Trait` method is chosen, versus the methods from the prelude trait. For example, turning `f.try_into()` above into `(&*f).try_into()`
108
+
ensures that we're calling `try_into` on the `dyn MyTrait` which can only refer to the `MyTrait::try_into` method.
109
+
110
+
### No migration needed
111
+
112
+
#### Inherent methods
113
+
114
+
Many types define their own inherent methods with the same name as a trait method. For instance, below the struct `MyStruct` implements `from_iter` which shares the same name with the method from the trait `FromIterator` found in the standard library:
115
+
116
+
```rust
117
+
structMyStruct {
118
+
data:Vec<u32>
89
119
}
90
120
91
-
fnbar(f:&dynMyTrait) {
92
-
f.into_iter();
121
+
implMyStruct {
122
+
// This has the same name as `std::iter::FromIterator::from_iter`
In these cases, the lint will sometimes rewrite to introduce additional dereferences or otherwise clarify the type of the method receiver. This ensures that the `dyn Trait` method is chosen, versus the methods from the prelude trait. For example, `f.into_iter()` above would become `(*f).into_iter()`.
139
+
Inherent methods always take precedent over trait methods so there's no need for any migration.
0 commit comments