about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_typeck/src/check/method/mod.rs135
-rw-r--r--compiler/rustc_typeck/src/check/method/prelude2021.rs167
2 files changed, 178 insertions, 124 deletions
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs
index f321d62edf6..e956637dec1 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -3,6 +3,7 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/method-lookup.html
 
 mod confirm;
+mod prelude2021;
 pub mod probe;
 mod suggest;
 
@@ -10,9 +11,7 @@ pub use self::suggest::{SelfSource, TraitInfo};
 pub use self::CandidateSource::*;
 pub use self::MethodError::*;
 
-use crate::check::method::probe::PickKind;
 use crate::check::FnCtxt;
-use rustc_ast::ast::Mutability;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
@@ -23,9 +22,7 @@ use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
 use rustc_middle::ty::GenericParamDefKind;
 use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TypeFoldable, WithConstness};
-use rustc_session::lint::builtin::FUTURE_PRELUDE_COLLISION;
-use rustc_span::edition::Edition;
-use rustc_span::symbol::{sym, Ident};
+use rustc_span::symbol::Ident;
 use rustc_span::Span;
 use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
@@ -202,71 +199,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let pick =
             self.lookup_probe(span, segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?;
 
-        if span.edition() < Edition::Edition2021 {
-            if let sym::try_into = segment.ident.name {
-                if !matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
-                    self.tcx.struct_span_lint_hir(
-                        FUTURE_PRELUDE_COLLISION,
-                        call_expr.hir_id,
-                        call_expr.span,
-                        |lint| {
-                            let sp = call_expr.span;
-                            let trait_name = self.tcx.def_path_str(pick.item.container.id());
-
-                            let mut lint = lint.build(&format!(
-                                "trait method `{}` will become ambiguous in Rust 2021",
-                                segment.ident.name
-                            ));
-
-                            if let Ok(self_expr) =
-                                self.sess().source_map().span_to_snippet(self_expr.span)
-                            {
-                                let derefs = "*".repeat(pick.autoderefs);
-
-                                let autoref = match pick.autoref_or_ptr_adjustment {
-                                    Some(probe::AutorefOrPtrAdjustment::Autoref {
-                                        mutbl: Mutability::Mut,
-                                        ..
-                                    }) => "&mut ",
-                                    Some(probe::AutorefOrPtrAdjustment::Autoref {
-                                        mutbl: Mutability::Not,
-                                        ..
-                                    }) => "&",
-                                    Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
-                                };
-                                let self_adjusted =
-                                    if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
-                                        pick.autoref_or_ptr_adjustment
-                                    {
-                                        format!("{}{} as *const _", derefs, self_expr)
-                                    } else {
-                                        format!("{}{}{}", autoref, derefs, self_expr)
-                                    };
-                                lint.span_suggestion(
-                                    sp,
-                                    "disambiguate the associated function",
-                                    format!(
-                                        "{}::{}({})",
-                                        trait_name, segment.ident.name, self_adjusted,
-                                    ),
-                                    Applicability::MachineApplicable,
-                                );
-                            } else {
-                                lint.span_help(
-                                    sp,
-                                    &format!(
-                                        "disambiguate the associated function with `{}::{}(...)`",
-                                        trait_name, segment.ident,
-                                    ),
-                                );
-                            }
-
-                            lint.emit();
-                        },
-                    );
-                }
-            }
-        }
+        self.lint_dot_call_from_2018(self_ty, segment, span, call_expr, self_expr, &pick);
 
         for import_id in &pick.import_ids {
             debug!("used_trait_import: {:?}", import_id);
@@ -551,60 +484,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ProbeScope::TraitsInScope,
         )?;
 
-        if span.edition() < Edition::Edition2021 {
-            if let sym::try_into | sym::try_from | sym::from_iter = method_name.name {
-                // No need to warn if either:
-                //
-                // * The method comes from std/core, since ten it's the built-in trait.
-                // * This is an inherent method called on a specific type, like `Vec::foo(...)`,
-                //   since such methods take precedence over trait methods.
-                if !matches!(tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core)
-                    && !matches!(pick.kind, PickKind::InherentImplPick)
-                {
-                    tcx.struct_span_lint_hir(FUTURE_PRELUDE_COLLISION, expr_id, span, |lint| {
-                        // "type" refers to either a type or, more likely, a trait from which
-                        // the associated function or method is from.
-                        let type_name = tcx.def_path_str(pick.item.container.id());
-                        let type_generics = tcx.generics_of(pick.item.container.id());
-
-                        let parameter_count =
-                            type_generics.count() - (type_generics.has_self as usize);
-                        let trait_name = if parameter_count == 0 {
-                            type_name
-                        } else {
-                            format!(
-                                "{}<{}>",
-                                type_name,
-                                std::iter::repeat("_")
-                                    .take(parameter_count)
-                                    .collect::<Vec<_>>()
-                                    .join(", ")
-                            )
-                        };
-
-                        let mut lint = lint.build(&format!(
-                            "trait-associated function `{}` will become ambiguous in Rust 2021",
-                            method_name.name
-                        ));
-
-                        let self_ty = self
-                            .sess()
-                            .source_map()
-                            .span_to_snippet(self_ty_span)
-                            .unwrap_or_else(|_| self_ty.to_string());
-
-                        lint.span_suggestion(
-                            span,
-                            "disambiguate the associated function",
-                            format!("<{} as {}>::{}", self_ty, trait_name, method_name.name,),
-                            Applicability::MachineApplicable,
-                        );
-
-                        lint.emit();
-                    });
-                }
-            }
-        }
+        self.lint_fully_qualified_call_from_2018(
+            span,
+            method_name,
+            self_ty,
+            self_ty_span,
+            expr_id,
+            &pick,
+        );
 
         debug!("resolve_fully_qualified_call: pick={:?}", pick);
         {
diff --git a/compiler/rustc_typeck/src/check/method/prelude2021.rs b/compiler/rustc_typeck/src/check/method/prelude2021.rs
new file mode 100644
index 00000000000..b141a4f6f89
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/method/prelude2021.rs
@@ -0,0 +1,167 @@
+use rustc_ast::Mutability;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_middle::ty::Ty;
+use rustc_session::lint::builtin::FUTURE_PRELUDE_COLLISION;
+use rustc_span::symbol::{sym, Ident};
+use rustc_span::Span;
+
+use crate::check::{
+    method::probe::{self, Pick},
+    FnCtxt,
+};
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    pub(super) fn lint_dot_call_from_2018(
+        &self,
+        self_ty: Ty<'tcx>,
+        segment: &hir::PathSegment<'_>,
+        span: Span,
+        call_expr: &'tcx hir::Expr<'tcx>,
+        self_expr: &'tcx hir::Expr<'tcx>,
+        pick: &Pick<'tcx>,
+    ) {
+        debug!(
+            "lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
+            segment.ident, self_ty, call_expr, self_expr
+        );
+
+        // Rust 2021 and later is already using the new prelude
+        if span.rust_2021() {
+            return;
+        }
+
+        // These are the method names that were added to prelude in Rust 2021
+        if !matches!(segment.ident.name, sym::try_into) {
+            return;
+        }
+
+        // No need to lint if method came from std/core, as that will now be in the prelude
+        if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
+            return;
+        }
+
+        self.tcx.struct_span_lint_hir(
+            FUTURE_PRELUDE_COLLISION,
+            call_expr.hir_id,
+            call_expr.span,
+            |lint| {
+                let sp = call_expr.span;
+                let trait_name = self.tcx.def_path_str(pick.item.container.id());
+
+                let mut lint = lint.build(&format!(
+                    "trait method `{}` will become ambiguous in Rust 2021",
+                    segment.ident.name
+                ));
+
+                if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span) {
+                    let derefs = "*".repeat(pick.autoderefs);
+
+                    let autoref = match pick.autoref_or_ptr_adjustment {
+                        Some(probe::AutorefOrPtrAdjustment::Autoref {
+                            mutbl: Mutability::Mut,
+                            ..
+                        }) => "&mut ",
+                        Some(probe::AutorefOrPtrAdjustment::Autoref {
+                            mutbl: Mutability::Not,
+                            ..
+                        }) => "&",
+                        Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
+                    };
+                    let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
+                        pick.autoref_or_ptr_adjustment
+                    {
+                        format!("{}{} as *const _", derefs, self_expr)
+                    } else {
+                        format!("{}{}{}", autoref, derefs, self_expr)
+                    };
+                    lint.span_suggestion(
+                        sp,
+                        "disambiguate the associated function",
+                        format!("{}::{}({})", trait_name, segment.ident.name, self_adjusted,),
+                        Applicability::MachineApplicable,
+                    );
+                } else {
+                    lint.span_help(
+                        sp,
+                        &format!(
+                            "disambiguate the associated function with `{}::{}(...)`",
+                            trait_name, segment.ident,
+                        ),
+                    );
+                }
+
+                lint.emit();
+            },
+        );
+    }
+
+    pub(super) fn lint_fully_qualified_call_from_2018(
+        &self,
+        span: Span,
+        method_name: Ident,
+        self_ty: Ty<'tcx>,
+        self_ty_span: Span,
+        expr_id: hir::HirId,
+        pick: &Pick<'tcx>,
+    ) {
+        // Rust 2021 and later is already using the new prelude
+        if span.rust_2021() {
+            return;
+        }
+
+        // These are the fully qualified methods added to prelude in Rust 2021
+        if !matches!(method_name.name, sym::try_into | sym::try_from | sym::from_iter) {
+            return;
+        }
+
+        // No need to lint if method came from std/core, as that will now be in the prelude
+        if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
+            return;
+        }
+
+        // No need to lint if this is an inherent method called on a specific type, like `Vec::foo(...)`,
+        // since such methods take precedence over trait methods.
+        if matches!(pick.kind, probe::PickKind::InherentImplPick) {
+            return;
+        }
+
+        self.tcx.struct_span_lint_hir(FUTURE_PRELUDE_COLLISION, expr_id, span, |lint| {
+            // "type" refers to either a type or, more likely, a trait from which
+            // the associated function or method is from.
+            let type_name = self.tcx.def_path_str(pick.item.container.id());
+            let type_generics = self.tcx.generics_of(pick.item.container.id());
+
+            let parameter_count = type_generics.count() - (type_generics.has_self as usize);
+            let trait_name = if parameter_count == 0 {
+                type_name
+            } else {
+                format!(
+                    "{}<{}>",
+                    type_name,
+                    std::iter::repeat("_").take(parameter_count).collect::<Vec<_>>().join(", ")
+                )
+            };
+
+            let mut lint = lint.build(&format!(
+                "trait-associated function `{}` will become ambiguous in Rust 2021",
+                method_name.name
+            ));
+
+            let self_ty = self
+                .sess()
+                .source_map()
+                .span_to_snippet(self_ty_span)
+                .unwrap_or_else(|_| self_ty.to_string());
+
+            lint.span_suggestion(
+                span,
+                "disambiguate the associated function",
+                format!("<{} as {}>::{}", self_ty, trait_name, method_name.name,),
+                Applicability::MachineApplicable,
+            );
+
+            lint.emit();
+        });
+    }
+}