Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 17ab9c0

Browse files
committed
extract Rust 2021 prelude logic to its own module
1 parent 8d42f3d commit 17ab9c0

File tree

2 files changed

+178
-124
lines changed

2 files changed

+178
-124
lines changed

compiler/rustc_typeck/src/check/method/mod.rs

Lines changed: 11 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,15 @@
33
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/method-lookup.html
44
55
mod confirm;
6+
mod prelude2021;
67
pub mod probe;
78
mod suggest;
89

910
pub use self::suggest::{SelfSource, TraitInfo};
1011
pub use self::CandidateSource::*;
1112
pub use self::MethodError::*;
1213

13-
use crate::check::method::probe::PickKind;
1414
use crate::check::FnCtxt;
15-
use rustc_ast::ast::Mutability;
1615
use rustc_data_structures::sync::Lrc;
1716
use rustc_errors::{Applicability, DiagnosticBuilder};
1817
use rustc_hir as hir;
@@ -23,9 +22,7 @@ use rustc_middle::ty::subst::Subst;
2322
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
2423
use rustc_middle::ty::GenericParamDefKind;
2524
use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TypeFoldable, WithConstness};
26-
use rustc_session::lint::builtin::FUTURE_PRELUDE_COLLISION;
27-
use rustc_span::edition::Edition;
28-
use rustc_span::symbol::{sym, Ident};
25+
use rustc_span::symbol::Ident;
2926
use rustc_span::Span;
3027
use rustc_trait_selection::traits;
3128
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
@@ -202,71 +199,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
202199
let pick =
203200
self.lookup_probe(span, segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?;
204201

205-
if span.edition() < Edition::Edition2021 {
206-
if let sym::try_into = segment.ident.name {
207-
if !matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
208-
self.tcx.struct_span_lint_hir(
209-
FUTURE_PRELUDE_COLLISION,
210-
call_expr.hir_id,
211-
call_expr.span,
212-
|lint| {
213-
let sp = call_expr.span;
214-
let trait_name = self.tcx.def_path_str(pick.item.container.id());
215-
216-
let mut lint = lint.build(&format!(
217-
"trait method `{}` will become ambiguous in Rust 2021",
218-
segment.ident.name
219-
));
220-
221-
if let Ok(self_expr) =
222-
self.sess().source_map().span_to_snippet(self_expr.span)
223-
{
224-
let derefs = "*".repeat(pick.autoderefs);
225-
226-
let autoref = match pick.autoref_or_ptr_adjustment {
227-
Some(probe::AutorefOrPtrAdjustment::Autoref {
228-
mutbl: Mutability::Mut,
229-
..
230-
}) => "&mut ",
231-
Some(probe::AutorefOrPtrAdjustment::Autoref {
232-
mutbl: Mutability::Not,
233-
..
234-
}) => "&",
235-
Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
236-
};
237-
let self_adjusted =
238-
if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
239-
pick.autoref_or_ptr_adjustment
240-
{
241-
format!("{}{} as *const _", derefs, self_expr)
242-
} else {
243-
format!("{}{}{}", autoref, derefs, self_expr)
244-
};
245-
lint.span_suggestion(
246-
sp,
247-
"disambiguate the associated function",
248-
format!(
249-
"{}::{}({})",
250-
trait_name, segment.ident.name, self_adjusted,
251-
),
252-
Applicability::MachineApplicable,
253-
);
254-
} else {
255-
lint.span_help(
256-
sp,
257-
&format!(
258-
"disambiguate the associated function with `{}::{}(...)`",
259-
trait_name, segment.ident,
260-
),
261-
);
262-
}
263-
264-
lint.emit();
265-
},
266-
);
267-
}
268-
}
269-
}
202+
self.lint_dot_call_from_2018(self_ty, segment, span, call_expr, self_expr, &pick);
270203

271204
for import_id in &pick.import_ids {
272205
debug!("used_trait_import: {:?}", import_id);
@@ -551,60 +484,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
551484
ProbeScope::TraitsInScope,
552485
)?;
553486

554-
if span.edition() < Edition::Edition2021 {
555-
if let sym::try_into | sym::try_from | sym::from_iter = method_name.name {
556-
// No need to warn if either:
557-
//
558-
// * The method comes from std/core, since ten it's the built-in trait.
559-
// * This is an inherent method called on a specific type, like `Vec::foo(...)`,
560-
// since such methods take precedence over trait methods.
561-
if !matches!(tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core)
562-
&& !matches!(pick.kind, PickKind::InherentImplPick)
563-
{
564-
tcx.struct_span_lint_hir(FUTURE_PRELUDE_COLLISION, expr_id, span, |lint| {
565-
// "type" refers to either a type or, more likely, a trait from which
566-
// the associated function or method is from.
567-
let type_name = tcx.def_path_str(pick.item.container.id());
568-
let type_generics = tcx.generics_of(pick.item.container.id());
569-
570-
let parameter_count =
571-
type_generics.count() - (type_generics.has_self as usize);
572-
let trait_name = if parameter_count == 0 {
573-
type_name
574-
} else {
575-
format!(
576-
"{}<{}>",
577-
type_name,
578-
std::iter::repeat("_")
579-
.take(parameter_count)
580-
.collect::<Vec<_>>()
581-
.join(", ")
582-
)
583-
};
584-
585-
let mut lint = lint.build(&format!(
586-
"trait-associated function `{}` will become ambiguous in Rust 2021",
587-
method_name.name
588-
));
589-
590-
let self_ty = self
591-
.sess()
592-
.source_map()
593-
.span_to_snippet(self_ty_span)
594-
.unwrap_or_else(|_| self_ty.to_string());
595-
596-
lint.span_suggestion(
597-
span,
598-
"disambiguate the associated function",
599-
format!("<{} as {}>::{}", self_ty, trait_name, method_name.name,),
600-
Applicability::MachineApplicable,
601-
);
602-
603-
lint.emit();
604-
});
605-
}
606-
}
607-
}
487+
self.lint_fully_qualified_call_from_2018(
488+
span,
489+
method_name,
490+
self_ty,
491+
self_ty_span,
492+
expr_id,
493+
&pick,
494+
);
608495

609496
debug!("resolve_fully_qualified_call: pick={:?}", pick);
610497
{
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
use rustc_ast::Mutability;
2+
use rustc_errors::Applicability;
3+
use rustc_hir as hir;
4+
use rustc_middle::ty::Ty;
5+
use rustc_session::lint::builtin::FUTURE_PRELUDE_COLLISION;
6+
use rustc_span::symbol::{sym, Ident};
7+
use rustc_span::Span;
8+
9+
use crate::check::{
10+
method::probe::{self, Pick},
11+
FnCtxt,
12+
};
13+
14+
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15+
pub(super) fn lint_dot_call_from_2018(
16+
&self,
17+
self_ty: Ty<'tcx>,
18+
segment: &hir::PathSegment<'_>,
19+
span: Span,
20+
call_expr: &'tcx hir::Expr<'tcx>,
21+
self_expr: &'tcx hir::Expr<'tcx>,
22+
pick: &Pick<'tcx>,
23+
) {
24+
debug!(
25+
"lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
26+
segment.ident, self_ty, call_expr, self_expr
27+
);
28+
29+
// Rust 2021 and later is already using the new prelude
30+
if span.rust_2021() {
31+
return;
32+
}
33+
34+
// These are the method names that were added to prelude in Rust 2021
35+
if !matches!(segment.ident.name, sym::try_into) {
36+
return;
37+
}
38+
39+
// No need to lint if method came from std/core, as that will now be in the prelude
40+
if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
41+
return;
42+
}
43+
44+
self.tcx.struct_span_lint_hir(
45+
FUTURE_PRELUDE_COLLISION,
46+
call_expr.hir_id,
47+
call_expr.span,
48+
|lint| {
49+
let sp = call_expr.span;
50+
let trait_name = self.tcx.def_path_str(pick.item.container.id());
51+
52+
let mut lint = lint.build(&format!(
53+
"trait method `{}` will become ambiguous in Rust 2021",
54+
segment.ident.name
55+
));
56+
57+
if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span) {
58+
let derefs = "*".repeat(pick.autoderefs);
59+
60+
let autoref = match pick.autoref_or_ptr_adjustment {
61+
Some(probe::AutorefOrPtrAdjustment::Autoref {
62+
mutbl: Mutability::Mut,
63+
..
64+
}) => "&mut ",
65+
Some(probe::AutorefOrPtrAdjustment::Autoref {
66+
mutbl: Mutability::Not,
67+
..
68+
}) => "&",
69+
Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
70+
};
71+
let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
72+
pick.autoref_or_ptr_adjustment
73+
{
74+
format!("{}{} as *const _", derefs, self_expr)
75+
} else {
76+
format!("{}{}{}", autoref, derefs, self_expr)
77+
};
78+
lint.span_suggestion(
79+
sp,
80+
"disambiguate the associated function",
81+
format!("{}::{}({})", trait_name, segment.ident.name, self_adjusted,),
82+
Applicability::MachineApplicable,
83+
);
84+
} else {
85+
lint.span_help(
86+
sp,
87+
&format!(
88+
"disambiguate the associated function with `{}::{}(...)`",
89+
trait_name, segment.ident,
90+
),
91+
);
92+
}
93+
94+
lint.emit();
95+
},
96+
);
97+
}
98+
99+
pub(super) fn lint_fully_qualified_call_from_2018(
100+
&self,
101+
span: Span,
102+
method_name: Ident,
103+
self_ty: Ty<'tcx>,
104+
self_ty_span: Span,
105+
expr_id: hir::HirId,
106+
pick: &Pick<'tcx>,
107+
) {
108+
// Rust 2021 and later is already using the new prelude
109+
if span.rust_2021() {
110+
return;
111+
}
112+
113+
// These are the fully qualified methods added to prelude in Rust 2021
114+
if !matches!(method_name.name, sym::try_into | sym::try_from | sym::from_iter) {
115+
return;
116+
}
117+
118+
// No need to lint if method came from std/core, as that will now be in the prelude
119+
if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
120+
return;
121+
}
122+
123+
// No need to lint if this is an inherent method called on a specific type, like `Vec::foo(...)`,
124+
// since such methods take precedence over trait methods.
125+
if matches!(pick.kind, probe::PickKind::InherentImplPick) {
126+
return;
127+
}
128+
129+
self.tcx.struct_span_lint_hir(FUTURE_PRELUDE_COLLISION, expr_id, span, |lint| {
130+
// "type" refers to either a type or, more likely, a trait from which
131+
// the associated function or method is from.
132+
let type_name = self.tcx.def_path_str(pick.item.container.id());
133+
let type_generics = self.tcx.generics_of(pick.item.container.id());
134+
135+
let parameter_count = type_generics.count() - (type_generics.has_self as usize);
136+
let trait_name = if parameter_count == 0 {
137+
type_name
138+
} else {
139+
format!(
140+
"{}<{}>",
141+
type_name,
142+
std::iter::repeat("_").take(parameter_count).collect::<Vec<_>>().join(", ")
143+
)
144+
};
145+
146+
let mut lint = lint.build(&format!(
147+
"trait-associated function `{}` will become ambiguous in Rust 2021",
148+
method_name.name
149+
));
150+
151+
let self_ty = self
152+
.sess()
153+
.source_map()
154+
.span_to_snippet(self_ty_span)
155+
.unwrap_or_else(|_| self_ty.to_string());
156+
157+
lint.span_suggestion(
158+
span,
159+
"disambiguate the associated function",
160+
format!("<{} as {}>::{}", self_ty, trait_name, method_name.name,),
161+
Applicability::MachineApplicable,
162+
);
163+
164+
lint.emit();
165+
});
166+
}
167+
}

0 commit comments

Comments
 (0)