about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-01-15 14:43:45 +0000
committerbors <bors@rust-lang.org>2022-01-15 14:43:45 +0000
commitec4bcaac450279b029f3480b8b8f1b82ab36a5eb (patch)
tree7868ce973b848dee601867b72239114eb6225c22 /compiler
parentb13a5bf3c4d66ce375f5978c2c2233f9714b721e (diff)
parent441c1a6c50cab4b010d03ceb9a7b616487720b1f (diff)
downloadrust-ec4bcaac450279b029f3480b8b8f1b82ab36a5eb.tar.gz
rust-ec4bcaac450279b029f3480b8b8f1b82ab36a5eb.zip
Auto merge of #92441 - cjgillot:resolve-trait-impl-item, r=matthewjasper
Link impl items to corresponding trait items in late resolver.

Hygienically linking trait impl items to declarations in the trait can be done directly by the late resolver. In fact, it is already done to diagnose unknown items.

This PR uses this resolution work and stores the `DefId` of the trait item in the HIR. This avoids having to do this resolution manually later.

r? `@matthewjasper`
Related to #90639. The added `trait_item_id` field can be moved to `ImplItemRef` to be used directly by your PR.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast_lowering/src/index.rs3
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs1
-rw-r--r--compiler/rustc_hir/src/hir.rs2
-rw-r--r--compiler/rustc_hir/src/intravisit.rs3
-rw-r--r--compiler/rustc_middle/src/ty/assoc.rs15
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs19
-rw-r--r--compiler/rustc_resolve/src/late.rs85
-rw-r--r--compiler/rustc_resolve/src/lib.rs8
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs106
-rw-r--r--compiler/rustc_typeck/src/astconv/errors.rs132
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs19
-rw-r--r--compiler/rustc_typeck/src/check/method/mod.rs11
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs2
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs46
-rw-r--r--compiler/rustc_typeck/src/coherence/mod.rs22
15 files changed, 214 insertions, 260 deletions
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index 8a9dad2cdd7..39a8cd405de 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -335,7 +335,8 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     fn visit_impl_item_ref(&mut self, ii: &'hir ImplItemRef) {
         // Do not visit the duplicate information in ImplItemRef. We want to
         // map the actual nodes, not the duplicate ones in the *Ref.
-        let ImplItemRef { id, ident: _, kind: _, span: _, defaultness: _ } = *ii;
+        let ImplItemRef { id, ident: _, kind: _, span: _, defaultness: _, trait_item_def_id: _ } =
+            *ii;
 
         self.visit_nested_impl_item(id);
     }
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 92cae4da89a..ed3abbd5b4d 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -925,6 +925,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 }
                 AssocItemKind::MacCall(..) => unimplemented!(),
             },
+            trait_item_def_id: self.resolver.get_partial_res(i.id).map(|r| r.base_res().def_id()),
         }
     }
 
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 76f4df6ec2d..76d94fe7dbc 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2881,6 +2881,8 @@ pub struct ImplItemRef {
     pub kind: AssocItemKind,
     pub span: Span,
     pub defaultness: Defaultness,
+    /// When we are in a trait impl, link to the trait-item's id.
+    pub trait_item_def_id: Option<DefId>,
 }
 
 #[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index d0eee422202..7c77930193c 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -1088,7 +1088,8 @@ pub fn walk_foreign_item_ref<'v, V: Visitor<'v>>(
 
 pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'v ImplItemRef) {
     // N.B., deliberately force a compilation error if/when new fields are added.
-    let ImplItemRef { id, ident, ref kind, span: _, ref defaultness } = *impl_item_ref;
+    let ImplItemRef { id, ident, ref kind, span: _, ref defaultness, trait_item_def_id: _ } =
+        *impl_item_ref;
     visitor.visit_nested_impl_item(id);
     visitor.visit_ident(ident);
     visitor.visit_associated_item_kind(kind);
diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs
index 5af4eef40d4..8563bac0bbf 100644
--- a/compiler/rustc_middle/src/ty/assoc.rs
+++ b/compiler/rustc_middle/src/ty/assoc.rs
@@ -139,21 +139,6 @@ impl<'tcx> AssocItems<'tcx> {
         self.items.get_by_key(name).copied()
     }
 
-    /// Returns an iterator over all associated items with the given name.
-    ///
-    /// Multiple items may have the same name if they are in different `Namespace`s. For example,
-    /// an associated type can have the same name as a method. Use one of the `find_by_name_and_*`
-    /// methods below if you know which item you are looking for.
-    pub fn filter_by_name<'a>(
-        &'a self,
-        tcx: TyCtxt<'a>,
-        ident: Ident,
-        parent_def_id: DefId,
-    ) -> impl 'a + Iterator<Item = &'a ty::AssocItem> {
-        self.filter_by_name_unhygienic(ident.name)
-            .filter(move |item| tcx.hygienic_eq(ident, item.ident, parent_def_id))
-    }
-
     /// Returns the associated item with the given name and `AssocKind`, if one exists.
     pub fn find_by_name_and_kind(
         &self,
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 4feeae5cab1..941c2a70d11 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -602,6 +602,25 @@ impl<'a> Resolver<'a> {
 
                 err
             }
+            ResolutionError::TraitImplMismatch {
+                name,
+                kind,
+                code,
+                trait_item_span,
+                trait_path,
+            } => {
+                let mut err = self.session.struct_span_err_with_code(
+                    span,
+                    &format!(
+                        "item `{}` is an associated {}, which doesn't match its trait `{}`",
+                        name, kind, trait_path,
+                    ),
+                    code,
+                );
+                err.span_label(span, "does not match trait");
+                err.span_label(trait_item_span, "item in trait");
+                err
+            }
         }
     }
 
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 1b02511fd7c..ccaaa2eaf46 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1247,15 +1247,14 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             );
             let res = res.base_res();
             if res != Res::Err {
-                new_id = Some(res.def_id());
-                let span = trait_ref.path.span;
                 if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.resolve_path(
                     &path,
                     Some(TypeNS),
-                    false,
-                    span,
+                    true,
+                    trait_ref.path.span,
                     CrateLint::SimplePath(trait_ref.ref_id),
                 ) {
+                    new_id = Some(res.def_id());
                     new_val = Some((module, trait_ref.clone()));
                 }
             }
@@ -1324,6 +1323,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                                             // If this is a trait impl, ensure the const
                                             // exists in trait
                                             this.check_trait_item(
+                                                item.id,
                                                 item.ident,
                                                 &item.kind,
                                                 ValueNS,
@@ -1359,6 +1359,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                                                     // If this is a trait impl, ensure the method
                                                     // exists in trait
                                                     this.check_trait_item(
+                                                        item.id,
                                                         item.ident,
                                                         &item.kind,
                                                         ValueNS,
@@ -1386,6 +1387,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                                                     // If this is a trait impl, ensure the type
                                                     // exists in trait
                                                     this.check_trait_item(
+                                                        item.id,
                                                         item.ident,
                                                         &item.kind,
                                                         TypeNS,
@@ -1416,7 +1418,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
 
     fn check_trait_item<F>(
         &mut self,
-        ident: Ident,
+        id: NodeId,
+        mut ident: Ident,
         kind: &AssocItemKind,
         ns: Namespace,
         span: Span,
@@ -1424,26 +1427,62 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
     ) where
         F: FnOnce(Ident, &str, Option<Symbol>) -> ResolutionError<'_>,
     {
-        // If there is a TraitRef in scope for an impl, then the method must be in the
-        // trait.
-        if let Some((module, _)) = self.current_trait_ref {
-            if self
-                .r
-                .resolve_ident_in_module(
-                    ModuleOrUniformRoot::Module(module),
-                    ident,
-                    ns,
-                    &self.parent_scope,
-                    false,
-                    span,
-                )
-                .is_err()
-            {
-                let candidate = self.find_similarly_named_assoc_item(ident.name, kind);
-                let path = &self.current_trait_ref.as_ref().unwrap().1.path;
-                self.report_error(span, err(ident, &path_names_to_string(path), candidate));
+        // If there is a TraitRef in scope for an impl, then the method must be in the trait.
+        let Some((module, _)) = &self.current_trait_ref else { return; };
+        ident.span.normalize_to_macros_2_0_and_adjust(module.expansion);
+        let key = self.r.new_key(ident, ns);
+        let mut binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding);
+        debug!(?binding);
+        if binding.is_none() {
+            // We could not find the trait item in the correct namespace.
+            // Check the other namespace to report an error.
+            let ns = match ns {
+                ValueNS => TypeNS,
+                TypeNS => ValueNS,
+                _ => ns,
+            };
+            let key = self.r.new_key(ident, ns);
+            binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding);
+            debug!(?binding);
+        }
+        let Some(binding) = binding else {
+            // We could not find the method: report an error.
+            let candidate = self.find_similarly_named_assoc_item(ident.name, kind);
+            let path = &self.current_trait_ref.as_ref().unwrap().1.path;
+            self.report_error(span, err(ident, &path_names_to_string(path), candidate));
+            return;
+        };
+
+        let res = binding.res();
+        let Res::Def(def_kind, _) = res else { bug!() };
+        match (def_kind, kind) {
+            (DefKind::AssocTy, AssocItemKind::TyAlias(..))
+            | (DefKind::AssocFn, AssocItemKind::Fn(..))
+            | (DefKind::AssocConst, AssocItemKind::Const(..)) => {
+                self.r.record_partial_res(id, PartialRes::new(res));
+                return;
             }
+            _ => {}
         }
+
+        // The method kind does not correspond to what appeared in the trait, report.
+        let path = &self.current_trait_ref.as_ref().unwrap().1.path;
+        let (code, kind) = match kind {
+            AssocItemKind::Const(..) => (rustc_errors::error_code!(E0323), "const"),
+            AssocItemKind::Fn(..) => (rustc_errors::error_code!(E0324), "method"),
+            AssocItemKind::TyAlias(..) => (rustc_errors::error_code!(E0325), "type"),
+            AssocItemKind::MacCall(..) => span_bug!(span, "unexpanded macro"),
+        };
+        self.report_error(
+            span,
+            ResolutionError::TraitImplMismatch {
+                name: ident.name,
+                kind,
+                code,
+                trait_path: path_names_to_string(path),
+                trait_item_span: binding.span,
+            },
+        );
     }
 
     fn resolve_params(&mut self, params: &'ast [Param]) {
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 28437742758..25137c6eda7 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -262,6 +262,14 @@ enum ResolutionError<'a> {
     SelfInGenericParamDefault,
     /// Error E0767: use of unreachable label
     UnreachableLabel { name: Symbol, definition_span: Span, suggestion: Option<LabelSuggestion> },
+    /// Error E0323, E0324, E0325: mismatch between trait item and impl item.
+    TraitImplMismatch {
+        name: Symbol,
+        kind: &'static str,
+        trait_path: String,
+        trait_item_span: Span,
+        code: rustc_errors::DiagnosticId,
+    },
 }
 
 enum VisResolutionError<'a> {
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index b1d47f6c29a..6e2ef27f108 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -1,8 +1,7 @@
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, TyCtxt};
 
 pub fn provide(providers: &mut ty::query::Providers) {
     *providers = ty::query::Providers {
@@ -125,115 +124,14 @@ fn associated_item_from_impl_item_ref(
         hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
     };
 
-    let trait_item_def_id = impl_item_base_id(tcx, parent_def_id, impl_item_ref);
-
     ty::AssocItem {
         ident: impl_item_ref.ident,
         kind,
         vis: tcx.visibility(def_id),
         defaultness: impl_item_ref.defaultness,
         def_id: def_id.to_def_id(),
-        trait_item_def_id,
+        trait_item_def_id: impl_item_ref.trait_item_def_id,
         container: ty::ImplContainer(parent_def_id.to_def_id()),
         fn_has_self_parameter: has_self,
     }
 }
-
-fn impl_item_base_id<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    parent_def_id: LocalDefId,
-    impl_item: &hir::ImplItemRef,
-) -> Option<DefId> {
-    let impl_trait_ref = tcx.impl_trait_ref(parent_def_id)?;
-
-    // If the trait reference itself is erroneous (so the compilation is going
-    // to fail), skip checking the items here -- the `impl_item` table in `tcx`
-    // isn't populated for such impls.
-    if impl_trait_ref.references_error() {
-        return None;
-    }
-
-    // Locate trait items
-    let associated_items = tcx.associated_items(impl_trait_ref.def_id);
-
-    // Match item against trait
-    let mut items = associated_items.filter_by_name(tcx, impl_item.ident, impl_trait_ref.def_id);
-
-    let mut trait_item = items.next()?;
-
-    let is_compatible = |ty: &&ty::AssocItem| match (ty.kind, &impl_item.kind) {
-        (ty::AssocKind::Const, hir::AssocItemKind::Const) => true,
-        (ty::AssocKind::Fn, hir::AssocItemKind::Fn { .. }) => true,
-        (ty::AssocKind::Type, hir::AssocItemKind::Type) => true,
-        _ => false,
-    };
-
-    // If we don't have a compatible item, we'll use the first one whose name matches
-    // to report an error.
-    let mut compatible_kind = is_compatible(&trait_item);
-
-    if !compatible_kind {
-        if let Some(ty_trait_item) = items.find(is_compatible) {
-            compatible_kind = true;
-            trait_item = ty_trait_item;
-        }
-    }
-
-    if compatible_kind {
-        Some(trait_item.def_id)
-    } else {
-        report_mismatch_error(tcx, trait_item.def_id, impl_trait_ref, impl_item);
-        None
-    }
-}
-
-#[inline(never)]
-#[cold]
-fn report_mismatch_error<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    trait_item_def_id: DefId,
-    impl_trait_ref: ty::TraitRef<'tcx>,
-    impl_item: &hir::ImplItemRef,
-) {
-    let mut err = match impl_item.kind {
-        hir::AssocItemKind::Const => {
-            // Find associated const definition.
-            struct_span_err!(
-                tcx.sess,
-                impl_item.span,
-                E0323,
-                "item `{}` is an associated const, which doesn't match its trait `{}`",
-                impl_item.ident,
-                impl_trait_ref.print_only_trait_path()
-            )
-        }
-
-        hir::AssocItemKind::Fn { .. } => {
-            struct_span_err!(
-                tcx.sess,
-                impl_item.span,
-                E0324,
-                "item `{}` is an associated method, which doesn't match its trait `{}`",
-                impl_item.ident,
-                impl_trait_ref.print_only_trait_path()
-            )
-        }
-
-        hir::AssocItemKind::Type => {
-            struct_span_err!(
-                tcx.sess,
-                impl_item.span,
-                E0325,
-                "item `{}` is an associated type, which doesn't match its trait `{}`",
-                impl_item.ident,
-                impl_trait_ref.print_only_trait_path()
-            )
-        }
-    };
-
-    err.span_label(impl_item.span, "does not match trait");
-    if let Some(trait_span) = tcx.hir().span_if_local(trait_item_def_id) {
-        err.span_label(trait_span, "item in trait");
-    }
-    err.emit();
-}
diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs
index ea54b85b2f2..1f99a9b0536 100644
--- a/compiler/rustc_typeck/src/astconv/errors.rs
+++ b/compiler/rustc_typeck/src/astconv/errors.rs
@@ -93,62 +93,96 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         span: Span,
         trait_def_id: DefId,
         trait_segment: &'_ hir::PathSegment<'_>,
+        is_impl: bool,
     ) {
+        if self.tcx().features().unboxed_closures {
+            return;
+        }
+
         let trait_def = self.tcx().trait_def(trait_def_id);
+        if !trait_def.paren_sugar {
+            if trait_segment.args().parenthesized {
+                // For now, require that parenthetical notation be used only with `Fn()` etc.
+                let mut err = feature_err(
+                    &self.tcx().sess.parse_sess,
+                    sym::unboxed_closures,
+                    span,
+                    "parenthetical notation is only stable when used with `Fn`-family traits",
+                );
+                err.emit();
+            }
 
-        if !self.tcx().features().unboxed_closures
-            && trait_segment.args().parenthesized != trait_def.paren_sugar
-        {
-            let sess = &self.tcx().sess.parse_sess;
+            return;
+        }
+
+        let sess = self.tcx().sess;
+
+        if !trait_segment.args().parenthesized {
             // For now, require that parenthetical notation be used only with `Fn()` etc.
-            let (msg, sugg) = if trait_def.paren_sugar {
-                (
-                    "the precise format of `Fn`-family traits' type parameters is subject to \
-                     change",
-                    Some(format!(
-                        "{}{} -> {}",
-                        trait_segment.ident,
-                        trait_segment
-                            .args
-                            .as_ref()
-                            .and_then(|args| args.args.get(0))
-                            .and_then(|arg| match arg {
-                                hir::GenericArg::Type(ty) => match ty.kind {
-                                    hir::TyKind::Tup(t) => t
-                                        .iter()
-                                        .map(|e| sess.source_map().span_to_snippet(e.span))
-                                        .collect::<Result<Vec<_>, _>>()
-                                        .map(|a| a.join(", ")),
-                                    _ => sess.source_map().span_to_snippet(ty.span),
-                                }
-                                .map(|s| format!("({})", s))
-                                .ok(),
-                                _ => None,
-                            })
-                            .unwrap_or_else(|| "()".to_string()),
-                        trait_segment
-                            .args()
-                            .bindings
-                            .iter()
-                            .find_map(|b| match (b.ident.name == sym::Output, &b.kind) {
-                                (true, hir::TypeBindingKind::Equality { ty }) => {
-                                    sess.source_map().span_to_snippet(ty.span).ok()
-                                }
-                                _ => None,
-                            })
-                            .unwrap_or_else(|| "()".to_string()),
-                    )),
-                )
-            } else {
-                ("parenthetical notation is only stable when used with `Fn`-family traits", None)
-            };
-            let mut err = feature_err(sess, sym::unboxed_closures, span, msg);
-            if let Some(sugg) = sugg {
-                let msg = "use parenthetical notation instead";
-                err.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect);
+            let mut err = feature_err(
+                &sess.parse_sess,
+                sym::unboxed_closures,
+                span,
+                "the precise format of `Fn`-family traits' type parameters is subject to change",
+            );
+            // Do not suggest the other syntax if we are in trait impl:
+            // the desugaring would contain an associated type constrait.
+            if !is_impl {
+                let args = trait_segment
+                    .args
+                    .as_ref()
+                    .and_then(|args| args.args.get(0))
+                    .and_then(|arg| match arg {
+                        hir::GenericArg::Type(ty) => match ty.kind {
+                            hir::TyKind::Tup(t) => t
+                                .iter()
+                                .map(|e| sess.source_map().span_to_snippet(e.span))
+                                .collect::<Result<Vec<_>, _>>()
+                                .map(|a| a.join(", ")),
+                            _ => sess.source_map().span_to_snippet(ty.span),
+                        }
+                        .map(|s| format!("({})", s))
+                        .ok(),
+                        _ => None,
+                    })
+                    .unwrap_or_else(|| "()".to_string());
+                let ret = trait_segment
+                    .args()
+                    .bindings
+                    .iter()
+                    .find_map(|b| match (b.ident.name == sym::Output, &b.kind) {
+                        (true, hir::TypeBindingKind::Equality { ty }) => {
+                            sess.source_map().span_to_snippet(ty.span).ok()
+                        }
+                        _ => None,
+                    })
+                    .unwrap_or_else(|| "()".to_string());
+                err.span_suggestion(
+                    span,
+                    "use parenthetical notation instead",
+                    format!("{}{} -> {}", trait_segment.ident, args, ret),
+                    Applicability::MaybeIncorrect,
+                );
             }
             err.emit();
         }
+
+        if is_impl {
+            let trait_name = self.tcx().def_path_str(trait_def_id);
+            struct_span_err!(
+                self.tcx().sess,
+                span,
+                E0183,
+                "manual implementations of `{}` are experimental",
+                trait_name,
+            )
+            .span_label(
+                span,
+                format!("manual implementations of `{}` are experimental", trait_name),
+            )
+            .help("add `#![feature(unboxed_closures)]` to the crate attributes to enable")
+            .emit();
+        }
     }
 
     pub(crate) fn complain_about_assoc_type_not_found<I>(
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 34f93a517ce..63d69d32c19 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -669,6 +669,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()),
             self_ty,
             trait_ref.path.segments.last().unwrap(),
+            true,
         )
     }
 
@@ -765,7 +766,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let infer_args = trait_segment.infer_args;
 
         self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1);
-        self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment);
+        self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
 
         self.instantiate_poly_trait_ref_inner(
             hir_id,
@@ -822,9 +823,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         trait_def_id: DefId,
         self_ty: Ty<'tcx>,
         trait_segment: &hir::PathSegment<'_>,
+        is_impl: bool,
     ) -> ty::TraitRef<'tcx> {
-        let (substs, _) =
-            self.create_substs_for_ast_trait_ref(span, trait_def_id, self_ty, trait_segment);
+        let (substs, _) = self.create_substs_for_ast_trait_ref(
+            span,
+            trait_def_id,
+            self_ty,
+            trait_segment,
+            is_impl,
+        );
         let assoc_bindings = self.create_assoc_bindings_for_generic_args(trait_segment.args());
         if let Some(b) = assoc_bindings.first() {
             Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
@@ -839,8 +846,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         trait_def_id: DefId,
         self_ty: Ty<'tcx>,
         trait_segment: &'a hir::PathSegment<'a>,
+        is_impl: bool,
     ) -> (SubstsRef<'tcx>, GenericArgCountResult) {
-        self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment);
+        self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
 
         self.create_substs_for_ast_path(
             span,
@@ -1932,7 +1940,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         debug!("qpath_to_ty: self_type={:?}", self_ty);
 
-        let trait_ref = self.ast_path_to_mono_trait_ref(span, trait_def_id, self_ty, trait_segment);
+        let trait_ref =
+            self.ast_path_to_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false);
 
         let item_substs = self.create_substs_for_associated_item(
             tcx,
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs
index 5057be70c48..d2dc21d84f6 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -371,7 +371,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // Trait must have a method named `m_name` and it should not have
         // type parameters or early-bound regions.
         let tcx = self.tcx;
-        let method_item = match self.associated_item(trait_def_id, m_name, Namespace::ValueNS) {
+        let method_item = match self.associated_value(trait_def_id, m_name) {
             Some(method_item) => method_item,
             None => {
                 tcx.sess.delay_span_bug(
@@ -540,15 +540,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     /// Finds item with name `item_name` defined in impl/trait `def_id`
     /// and return it, or `None`, if no such item was defined there.
-    pub fn associated_item(
-        &self,
-        def_id: DefId,
-        item_name: Ident,
-        ns: Namespace,
-    ) -> Option<ty::AssocItem> {
+    pub fn associated_value(&self, def_id: DefId, item_name: Ident) -> Option<ty::AssocItem> {
         self.tcx
             .associated_items(def_id)
-            .find_by_name_and_namespace(self.tcx, item_name, ns, def_id)
+            .find_by_name_and_namespace(self.tcx, item_name, Namespace::ValueNS, def_id)
             .copied()
     }
 }
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index 5615a08369d..b704ff8c7cb 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -1915,7 +1915,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     .collect()
             } else {
                 self.fcx
-                    .associated_item(def_id, name, Namespace::ValueNS)
+                    .associated_value(def_id, name)
                     .map_or_else(SmallVec::new, |x| SmallVec::from_buf([x]))
             }
         } else {
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index de83e45329b..f2fe4403d55 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -5,7 +5,6 @@ use crate::check::FnCtxt;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
-use rustc_hir::def::Namespace;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ExprKind, Node, QPath};
@@ -99,16 +98,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     CandidateSource::ImplSource(impl_did) => {
                         // Provide the best span we can. Use the item, if local to crate, else
                         // the impl, if local to crate (item may be defaulted), else nothing.
-                        let item = match self
-                            .associated_item(impl_did, item_name, Namespace::ValueNS)
-                            .or_else(|| {
-                                let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
-                                self.associated_item(
-                                    impl_trait_ref.def_id,
-                                    item_name,
-                                    Namespace::ValueNS,
-                                )
-                            }) {
+                        let item = match self.associated_value(impl_did, item_name).or_else(|| {
+                            let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
+                            self.associated_value(impl_trait_ref.def_id, item_name)
+                        }) {
                             Some(item) => item,
                             None => continue,
                         };
@@ -187,11 +180,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         }
                     }
                     CandidateSource::TraitSource(trait_did) => {
-                        let item =
-                            match self.associated_item(trait_did, item_name, Namespace::ValueNS) {
-                                Some(item) => item,
-                                None => continue,
-                            };
+                        let item = match self.associated_value(trait_did, item_name) {
+                            Some(item) => item,
+                            None => continue,
+                        };
                         let item_span = self
                             .tcx
                             .sess
@@ -271,16 +263,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // Suggest clamping down the type if the method that is being attempted to
                     // be used exists at all, and the type is an ambiguous numeric type
                     // ({integer}/{float}).
-                    let mut candidates = all_traits(self.tcx).into_iter().filter_map(|info| {
-                        self.associated_item(info.def_id, item_name, Namespace::ValueNS)
-                    });
+                    let mut candidates = all_traits(self.tcx)
+                        .into_iter()
+                        .filter_map(|info| self.associated_value(info.def_id, item_name));
                     // There are methods that are defined on the primitive types and won't be
                     // found when exploring `all_traits`, but we also need them to be acurate on
                     // our suggestions (#47759).
                     let fund_assoc = |opt_def_id: Option<DefId>| {
-                        opt_def_id
-                            .and_then(|id| self.associated_item(id, item_name, Namespace::ValueNS))
-                            .is_some()
+                        opt_def_id.and_then(|id| self.associated_value(id, item_name)).is_some()
                     };
                     let lang_items = tcx.lang_items();
                     let found_candidate = candidates.next().is_some()
@@ -398,11 +388,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                             .inherent_impls(adt_deref.did)
                                             .iter()
                                             .filter_map(|def_id| {
-                                                self.associated_item(
-                                                    *def_id,
-                                                    item_name,
-                                                    Namespace::ValueNS,
-                                                )
+                                                self.associated_value(*def_id, item_name)
                                             })
                                             .count()
                                             >= 1
@@ -515,9 +501,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 .iter()
                                 .copied()
                                 .filter(|def_id| {
-                                    if let Some(assoc) =
-                                        self.associated_item(*def_id, item_name, Namespace::ValueNS)
-                                    {
+                                    if let Some(assoc) = self.associated_value(*def_id, item_name) {
                                         // Check for both mode is the same so we avoid suggesting
                                         // incorrect associated item.
                                         match (mode, assoc.fn_has_self_parameter, source) {
@@ -1587,7 +1571,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 }) && (type_is_local || info.def_id.is_local())
                     && self
-                        .associated_item(info.def_id, item_name, Namespace::ValueNS)
+                        .associated_value(info.def_id, item_name)
                         .filter(|item| {
                             if let ty::AssocKind::Fn = item.kind {
                                 let id = item
diff --git a/compiler/rustc_typeck/src/coherence/mod.rs b/compiler/rustc_typeck/src/coherence/mod.rs
index 377ebf1fe2a..055818f55f0 100644
--- a/compiler/rustc_typeck/src/coherence/mod.rs
+++ b/compiler/rustc_typeck/src/coherence/mod.rs
@@ -121,28 +121,6 @@ fn enforce_trait_manually_implementable(
             return;
         }
     }
-
-    let trait_name = if did == li.fn_trait() {
-        "Fn"
-    } else if did == li.fn_mut_trait() {
-        "FnMut"
-    } else if did == li.fn_once_trait() {
-        "FnOnce"
-    } else {
-        return; // everything OK
-    };
-
-    let span = impl_header_span(tcx, impl_def_id);
-    struct_span_err!(
-        tcx.sess,
-        span,
-        E0183,
-        "manual implementations of `{}` are experimental",
-        trait_name
-    )
-    .span_label(span, format!("manual implementations of `{}` are experimental", trait_name))
-    .help("add `#![feature(unboxed_closures)]` to the crate attributes to enable")
-    .emit();
 }
 
 /// We allow impls of marker traits to overlap, so they can't override impls