1 use hir::def_id::DefId;
3 use rustc_ast::Mutability;
4 use rustc_errors::Applicability;
6 use rustc_middle::ty::Ty;
7 use rustc_session::lint::builtin::FUTURE_PRELUDE_COLLISION;
8 use rustc_span::symbol::{sym, Ident};
12 method::probe::{self, Pick},
16 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17 pub(super) fn lint_dot_call_from_2018(
20 segment: &hir::PathSegment<'_>,
22 call_expr: &'tcx hir::Expr<'tcx>,
23 self_expr: &'tcx hir::Expr<'tcx>,
25 args: &'tcx [hir::Expr<'tcx>],
28 "lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
29 segment.ident, self_ty, call_expr, self_expr
32 // Rust 2021 and later is already using the new prelude
37 // These are the method names that were added to prelude in Rust 2021
38 if !matches!(segment.ident.name, sym::try_into) {
42 // No need to lint if method came from std/core, as that will now be in the prelude
43 if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
47 self.tcx.struct_span_lint_hir(
48 FUTURE_PRELUDE_COLLISION,
52 let sp = call_expr.span;
54 self.trait_path_or_bare_name(call_expr.hir_id, pick.item.container.id());
56 let mut lint = lint.build(&format!(
57 "trait method `{}` will become ambiguous in Rust 2021",
61 if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span) {
62 let derefs = "*".repeat(pick.autoderefs);
64 let autoref = match pick.autoref_or_ptr_adjustment {
65 Some(probe::AutorefOrPtrAdjustment::Autoref {
66 mutbl: Mutability::Mut,
69 Some(probe::AutorefOrPtrAdjustment::Autoref {
70 mutbl: Mutability::Not,
73 Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
75 let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
76 pick.autoref_or_ptr_adjustment
78 format!("{}{} as *const _", derefs, self_expr)
80 format!("{}{}{}", autoref, derefs, self_expr)
88 self.sess().source_map().span_to_snippet(arg.span).unwrap()
95 "disambiguate the associated function",
98 trait_name, segment.ident.name, self_adjusted, args
100 Applicability::MachineApplicable,
106 "disambiguate the associated function with `{}::{}(...)`",
107 trait_name, segment.ident,
117 pub(super) fn lint_fully_qualified_call_from_2018(
126 // Rust 2021 and later is already using the new prelude
127 if span.rust_2021() {
131 // These are the fully qualified methods added to prelude in Rust 2021
132 if !matches!(method_name.name, sym::try_into | sym::try_from | sym::from_iter) {
136 // No need to lint if method came from std/core, as that will now be in the prelude
137 if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
141 // No need to lint if this is an inherent method called on a specific type, like `Vec::foo(...)`,
142 // since such methods take precedence over trait methods.
143 if matches!(pick.kind, probe::PickKind::InherentImplPick) {
147 self.tcx.struct_span_lint_hir(FUTURE_PRELUDE_COLLISION, expr_id, span, |lint| {
148 // "type" refers to either a type or, more likely, a trait from which
149 // the associated function or method is from.
150 let trait_path = self.trait_path_or_bare_name(expr_id, pick.item.container.id());
151 let trait_generics = self.tcx.generics_of(pick.item.container.id());
153 let parameter_count = trait_generics.count() - (trait_generics.has_self as usize);
154 let trait_name = if parameter_count == 0 {
160 std::iter::repeat("_").take(parameter_count).collect::<Vec<_>>().join(", ")
164 let mut lint = lint.build(&format!(
165 "trait-associated function `{}` will become ambiguous in Rust 2021",
172 .span_to_snippet(self_ty_span)
173 .unwrap_or_else(|_| self_ty.to_string());
175 lint.span_suggestion(
177 "disambiguate the associated function",
178 format!("<{} as {}>::{}", self_ty, trait_name, method_name.name,),
179 Applicability::MachineApplicable,
186 fn trait_path_or_bare_name(&self, expr_hir_id: HirId, trait_def_id: DefId) -> String {
187 self.trait_path(expr_hir_id, trait_def_id).unwrap_or_else(|| {
188 let key = self.tcx.def_key(trait_def_id);
189 format!("{}", key.disambiguated_data.data)
193 fn trait_path(&self, expr_hir_id: HirId, trait_def_id: DefId) -> Option<String> {
194 let applicable_traits = self.tcx.in_scope_traits(expr_hir_id)?;
195 let applicable_trait = applicable_traits.iter().find(|t| t.def_id == trait_def_id)?;
196 if applicable_trait.import_ids.is_empty() {
197 // The trait was declared within the module, we only need to use its name.
201 for &import_id in &applicable_trait.import_ids {
202 let hir_id = self.tcx.hir().local_def_id_to_hir_id(import_id);
203 let item = self.tcx.hir().expect_item(hir_id);
204 debug!(?item, ?import_id, "import_id");