about summary refs log tree commit diff
diff options
context:
space:
mode:
-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/coherence/mod.rs22
-rw-r--r--src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr54
-rw-r--r--src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr6
5 files changed, 127 insertions, 106 deletions
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 8226ffbccc4..ba40f3c7db2 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/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
diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr b/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr
index e0e0acadb37..f647380ef9b 100644
--- a/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr
+++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr
@@ -38,11 +38,27 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje
   --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:9:6
    |
 LL | impl Fn<()> for Foo {
-   |      ^^^^^^ help: use parenthetical notation instead: `Fn() -> ()`
+   |      ^^^^^^
    |
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
+error[E0183]: manual implementations of `Fn` are experimental
+  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:9:6
+   |
+LL | impl Fn<()> for Foo {
+   |      ^^^^^^ manual implementations of `Fn` are experimental
+   |
+   = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
+
+error[E0183]: manual implementations of `FnOnce` are experimental
+  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:16:6
+   |
+LL | impl FnOnce() for Foo1 {
+   |      ^^^^^^^^ manual implementations of `FnOnce` are experimental
+   |
+   = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
+
 error[E0229]: associated type bindings are not allowed here
   --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:16:6
    |
@@ -53,49 +69,33 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje
   --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:23:6
    |
 LL | impl FnMut<()> for Bar {
-   |      ^^^^^^^^^ help: use parenthetical notation instead: `FnMut() -> ()`
-   |
-   = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
-   = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
-
-error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change
-  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:30:6
-   |
-LL | impl FnOnce<()> for Baz {
-   |      ^^^^^^^^^^ help: use parenthetical notation instead: `FnOnce() -> ()`
+   |      ^^^^^^^^^
    |
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
-error[E0183]: manual implementations of `Fn` are experimental
-  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:9:1
-   |
-LL | impl Fn<()> for Foo {
-   | ^^^^^^^^^^^^^^^^^^^ manual implementations of `Fn` are experimental
-   |
-   = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
-
 error[E0183]: manual implementations of `FnMut` are experimental
-  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:23:1
+  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:23:6
    |
 LL | impl FnMut<()> for Bar {
-   | ^^^^^^^^^^^^^^^^^^^^^^ manual implementations of `FnMut` are experimental
+   |      ^^^^^^^^^ manual implementations of `FnMut` are experimental
    |
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
-error[E0183]: manual implementations of `FnOnce` are experimental
-  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:16:1
+error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change
+  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:30:6
    |
-LL | impl FnOnce() for Foo1 {
-   | ^^^^^^^^^^^^^^^^^^^^^^ manual implementations of `FnOnce` are experimental
+LL | impl FnOnce<()> for Baz {
+   |      ^^^^^^^^^^
    |
+   = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0183]: manual implementations of `FnOnce` are experimental
-  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:30:1
+  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:30:6
    |
 LL | impl FnOnce<()> for Baz {
-   | ^^^^^^^^^^^^^^^^^^^^^^^ manual implementations of `FnOnce` are experimental
+   |      ^^^^^^^^^^ manual implementations of `FnOnce` are experimental
    |
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr b/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr
index 8c5f8796456..a763c28de60 100644
--- a/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr
+++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr
@@ -11,16 +11,16 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje
   --> $DIR/feature-gate-unboxed-closures.rs:5:6
    |
 LL | impl FnOnce<(u32, u32)> for Test {
-   |      ^^^^^^^^^^^^^^^^^^ help: use parenthetical notation instead: `FnOnce(u32, u32) -> ()`
+   |      ^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0183]: manual implementations of `FnOnce` are experimental
-  --> $DIR/feature-gate-unboxed-closures.rs:5:1
+  --> $DIR/feature-gate-unboxed-closures.rs:5:6
    |
 LL | impl FnOnce<(u32, u32)> for Test {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ manual implementations of `FnOnce` are experimental
+   |      ^^^^^^^^^^^^^^^^^^ manual implementations of `FnOnce` are experimental
    |
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable