@@ -5,9 +5,9 @@ use rustc_ast::Mutability;
5
5
use rustc_errors:: Applicability ;
6
6
use rustc_hir as hir;
7
7
use rustc_middle:: ty:: subst:: InternalSubsts ;
8
- use rustc_middle:: ty:: { Adt , Ref , Ty } ;
8
+ use rustc_middle:: ty:: { Adt , Array , Ref , Ty } ;
9
9
use rustc_session:: lint:: builtin:: RUST_2021_PRELUDE_COLLISIONS ;
10
- use rustc_span:: symbol:: kw:: Underscore ;
10
+ use rustc_span:: symbol:: kw:: { Empty , Underscore } ;
11
11
use rustc_span:: symbol:: { sym, Ident } ;
12
12
use rustc_span:: Span ;
13
13
use rustc_trait_selection:: infer:: InferCtxtExt ;
@@ -38,10 +38,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
38
38
return ;
39
39
}
40
40
41
- // These are the method names that were added to prelude in Rust 2021
42
- if !matches ! ( segment. ident. name, sym:: try_into) {
43
- return ;
44
- }
41
+ let prelude_or_array_lint = match segment. ident . name {
42
+ // `try_into` was added to the prelude in Rust 2021.
43
+ sym:: try_into => RUST_2021_PRELUDE_COLLISIONS ,
44
+ // `into_iter` wasn't added to the prelude,
45
+ // but `[T; N].into_iter()` doesn't resolve to IntoIterator::into_iter
46
+ // before Rust 2021, which results in the same problem.
47
+ // It is only a problem for arrays.
48
+ sym:: into_iter if let Array ( ..) = self_ty. kind ( ) => {
49
+ // In this case, it wasn't really a prelude addition that was the problem.
50
+ // Instead, the problem is that the array-into_iter hack will no longer apply in Rust 2021.
51
+ rustc_lint:: ARRAY_INTO_ITER
52
+ }
53
+ _ => return ,
54
+ } ;
45
55
46
56
// No need to lint if method came from std/core, as that will now be in the prelude
47
57
if matches ! ( self . tcx. crate_name( pick. item. def_id. krate) , sym:: std | sym:: core) {
@@ -69,7 +79,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
69
79
// Inherent impls only require not relying on autoref and autoderef in order to
70
80
// ensure that the trait implementation won't be used
71
81
self . tcx . struct_span_lint_hir (
72
- RUST_2021_PRELUDE_COLLISIONS ,
82
+ prelude_or_array_lint ,
73
83
self_expr. hir_id ,
74
84
self_expr. span ,
75
85
|lint| {
@@ -130,7 +140,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
130
140
// trait implementations require full disambiguation to not clash with the new prelude
131
141
// additions (i.e. convert from dot-call to fully-qualified call)
132
142
self . tcx . struct_span_lint_hir (
133
- RUST_2021_PRELUDE_COLLISIONS ,
143
+ prelude_or_array_lint ,
134
144
call_expr. hir_id ,
135
145
call_expr. span ,
136
146
|lint| {
@@ -239,47 +249,58 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
239
249
let trait_path = self . trait_path_or_bare_name ( span, expr_id, pick. item . container . id ( ) ) ;
240
250
let trait_generics = self . tcx . generics_of ( pick. item . container . id ( ) ) ;
241
251
242
- let parameter_count = trait_generics. count ( ) - ( trait_generics. has_self as usize ) ;
243
- let trait_name = if parameter_count == 0 {
244
- trait_path
245
- } else {
246
- format ! (
247
- "{}<{}>" ,
248
- trait_path,
249
- std:: iter:: repeat( "_" ) . take( parameter_count) . collect:: <Vec <_>>( ) . join( ", " )
250
- )
251
- } ;
252
+ let trait_name =
253
+ if trait_generics. params . len ( ) <= trait_generics. has_self as usize {
254
+ trait_path
255
+ } else {
256
+ let counts = trait_generics. own_counts ( ) ;
257
+ format ! (
258
+ "{}<{}>" ,
259
+ trait_path,
260
+ std:: iter:: repeat( "'_" )
261
+ . take( counts. lifetimes)
262
+ . chain( std:: iter:: repeat( "_" ) . take(
263
+ counts. types + counts. consts - trait_generics. has_self as usize
264
+ ) )
265
+ . collect:: <Vec <_>>( )
266
+ . join( ", " )
267
+ )
268
+ } ;
252
269
253
270
let mut lint = lint. build ( & format ! (
254
271
"trait-associated function `{}` will become ambiguous in Rust 2021" ,
255
272
method_name. name
256
273
) ) ;
257
274
258
- let self_ty_name = self
275
+ let mut self_ty_name = self
259
276
. sess ( )
260
277
. source_map ( )
261
278
. span_to_snippet ( self_ty_span)
262
279
. unwrap_or_else ( |_| self_ty. to_string ( ) ) ;
263
280
264
- let self_ty_generics_count = match self_ty. kind ( ) {
265
- // Get the number of generics the self type has (if an Adt) unless we can determine that
266
- // the user has written the self type with generics already which we (naively) do by looking
267
- // for a "<" in `self_ty_name`.
268
- Adt ( def, _) if !self_ty_name. contains ( '<' ) => self . tcx . generics_of ( def. did ) . count ( ) ,
269
- _ => 0 ,
270
- } ;
271
- let self_ty_generics = if self_ty_generics_count > 0 {
272
- format ! ( "<{}>" , vec![ "_" ; self_ty_generics_count] . join( ", " ) )
273
- } else {
274
- String :: new ( )
275
- } ;
281
+ // Get the number of generics the self type has (if an Adt) unless we can determine that
282
+ // the user has written the self type with generics already which we (naively) do by looking
283
+ // for a "<" in `self_ty_name`.
284
+ if !self_ty_name. contains ( '<' ) {
285
+ if let Adt ( def, _) = self_ty. kind ( ) {
286
+ let generics = self . tcx . generics_of ( def. did ) ;
287
+ if !generics. params . is_empty ( ) {
288
+ let counts = generics. own_counts ( ) ;
289
+ self_ty_name += & format ! (
290
+ "<{}>" ,
291
+ std:: iter:: repeat( "'_" )
292
+ . take( counts. lifetimes)
293
+ . chain( std:: iter:: repeat( "_" ) . take( counts. types + counts. consts) )
294
+ . collect:: <Vec <_>>( )
295
+ . join( ", " )
296
+ ) ;
297
+ }
298
+ }
299
+ }
276
300
lint. span_suggestion (
277
301
span,
278
302
"disambiguate the associated function" ,
279
- format ! (
280
- "<{}{} as {}>::{}" ,
281
- self_ty_name, self_ty_generics, trait_name, method_name. name,
282
- ) ,
303
+ format ! ( "<{} as {}>::{}" , self_ty_name, trait_name, method_name. name, ) ,
283
304
Applicability :: MachineApplicable ,
284
305
) ;
285
306
@@ -322,7 +343,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
322
343
. filter_map ( |item| if item. ident . name != Underscore { Some ( item. ident ) } else { None } )
323
344
. next ( ) ;
324
345
if let Some ( any_id) = any_id {
325
- return Some ( format ! ( "{}" , any_id) ) ;
346
+ if any_id. name == Empty {
347
+ // Glob import, so just use its name.
348
+ return None ;
349
+ } else {
350
+ return Some ( format ! ( "{}" , any_id) ) ;
351
+ }
326
352
}
327
353
328
354
// All that is left is `_`! We need to use the full path. It doesn't matter which one we pick,
0 commit comments