From 2e0a80c8c0e4fb2fdbdcecfa21df22ad20521fd1 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 12 Jan 2022 23:13:52 +0100 Subject: [PATCH] Err about fn traits in a single place. --- compiler/rustc_typeck/src/astconv/errors.rs | 134 +++++++++++------- compiler/rustc_typeck/src/astconv/mod.rs | 19 ++- compiler/rustc_typeck/src/coherence/mod.rs | 22 --- ...-gate-unboxed-closures-manual-impls.stderr | 58 ++++---- .../feature-gate-unboxed-closures.stderr | 6 +- 5 files changed, 130 insertions(+), 109 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, ) { - let trait_def = self.tcx().trait_def(trait_def_id); + if self.tcx().features().unboxed_closures { + return; + } - if !self.tcx().features().unboxed_closures - && trait_segment.args().parenthesized != trait_def.paren_sugar - { - let sess = &self.tcx().sess.parse_sess; + 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(); + } + + 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::, _>>() - .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::, _>>() + .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( 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 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 for more information = 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:6 + | +LL | impl FnMut<()> for Bar { + | ^^^^^^^^^ manual implementations of `FnMut` are experimental + | + = 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 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 - | -LL | impl FnMut<()> for Bar { - | ^^^^^^^^^^^^^^^^^^^^^^ 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 - | -LL | impl FnOnce() for Foo1 { - | ^^^^^^^^^^^^^^^^^^^^^^ manual implementations of `FnOnce` 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: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 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