Skip to content

Commit 2e0a80c

Browse files
committed
Err about fn traits in a single place.
1 parent 7b28592 commit 2e0a80c

File tree

5 files changed

+127
-106
lines changed

5 files changed

+127
-106
lines changed

compiler/rustc_typeck/src/astconv/errors.rs

+83-49
Original file line numberDiff line numberDiff line change
@@ -93,62 +93,96 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
9393
span: Span,
9494
trait_def_id: DefId,
9595
trait_segment: &'_ hir::PathSegment<'_>,
96+
is_impl: bool,
9697
) {
98+
if self.tcx().features().unboxed_closures {
99+
return;
100+
}
101+
97102
let trait_def = self.tcx().trait_def(trait_def_id);
103+
if !trait_def.paren_sugar {
104+
if trait_segment.args().parenthesized {
105+
// For now, require that parenthetical notation be used only with `Fn()` etc.
106+
let mut err = feature_err(
107+
&self.tcx().sess.parse_sess,
108+
sym::unboxed_closures,
109+
span,
110+
"parenthetical notation is only stable when used with `Fn`-family traits",
111+
);
112+
err.emit();
113+
}
98114

99-
if !self.tcx().features().unboxed_closures
100-
&& trait_segment.args().parenthesized != trait_def.paren_sugar
101-
{
102-
let sess = &self.tcx().sess.parse_sess;
115+
return;
116+
}
117+
118+
let sess = self.tcx().sess;
119+
120+
if !trait_segment.args().parenthesized {
103121
// For now, require that parenthetical notation be used only with `Fn()` etc.
104-
let (msg, sugg) = if trait_def.paren_sugar {
105-
(
106-
"the precise format of `Fn`-family traits' type parameters is subject to \
107-
change",
108-
Some(format!(
109-
"{}{} -> {}",
110-
trait_segment.ident,
111-
trait_segment
112-
.args
113-
.as_ref()
114-
.and_then(|args| args.args.get(0))
115-
.and_then(|arg| match arg {
116-
hir::GenericArg::Type(ty) => match ty.kind {
117-
hir::TyKind::Tup(t) => t
118-
.iter()
119-
.map(|e| sess.source_map().span_to_snippet(e.span))
120-
.collect::<Result<Vec<_>, _>>()
121-
.map(|a| a.join(", ")),
122-
_ => sess.source_map().span_to_snippet(ty.span),
123-
}
124-
.map(|s| format!("({})", s))
125-
.ok(),
126-
_ => None,
127-
})
128-
.unwrap_or_else(|| "()".to_string()),
129-
trait_segment
130-
.args()
131-
.bindings
132-
.iter()
133-
.find_map(|b| match (b.ident.name == sym::Output, &b.kind) {
134-
(true, hir::TypeBindingKind::Equality { ty }) => {
135-
sess.source_map().span_to_snippet(ty.span).ok()
136-
}
137-
_ => None,
138-
})
139-
.unwrap_or_else(|| "()".to_string()),
140-
)),
141-
)
142-
} else {
143-
("parenthetical notation is only stable when used with `Fn`-family traits", None)
144-
};
145-
let mut err = feature_err(sess, sym::unboxed_closures, span, msg);
146-
if let Some(sugg) = sugg {
147-
let msg = "use parenthetical notation instead";
148-
err.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect);
122+
let mut err = feature_err(
123+
&sess.parse_sess,
124+
sym::unboxed_closures,
125+
span,
126+
"the precise format of `Fn`-family traits' type parameters is subject to change",
127+
);
128+
// Do not suggest the other syntax if we are in trait impl:
129+
// the desugaring would contain an associated type constrait.
130+
if !is_impl {
131+
let args = trait_segment
132+
.args
133+
.as_ref()
134+
.and_then(|args| args.args.get(0))
135+
.and_then(|arg| match arg {
136+
hir::GenericArg::Type(ty) => match ty.kind {
137+
hir::TyKind::Tup(t) => t
138+
.iter()
139+
.map(|e| sess.source_map().span_to_snippet(e.span))
140+
.collect::<Result<Vec<_>, _>>()
141+
.map(|a| a.join(", ")),
142+
_ => sess.source_map().span_to_snippet(ty.span),
143+
}
144+
.map(|s| format!("({})", s))
145+
.ok(),
146+
_ => None,
147+
})
148+
.unwrap_or_else(|| "()".to_string());
149+
let ret = trait_segment
150+
.args()
151+
.bindings
152+
.iter()
153+
.find_map(|b| match (b.ident.name == sym::Output, &b.kind) {
154+
(true, hir::TypeBindingKind::Equality { ty }) => {
155+
sess.source_map().span_to_snippet(ty.span).ok()
156+
}
157+
_ => None,
158+
})
159+
.unwrap_or_else(|| "()".to_string());
160+
err.span_suggestion(
161+
span,
162+
"use parenthetical notation instead",
163+
format!("{}{} -> {}", trait_segment.ident, args, ret),
164+
Applicability::MaybeIncorrect,
165+
);
149166
}
150167
err.emit();
151168
}
169+
170+
if is_impl {
171+
let trait_name = self.tcx().def_path_str(trait_def_id);
172+
struct_span_err!(
173+
self.tcx().sess,
174+
span,
175+
E0183,
176+
"manual implementations of `{}` are experimental",
177+
trait_name,
178+
)
179+
.span_label(
180+
span,
181+
format!("manual implementations of `{}` are experimental", trait_name),
182+
)
183+
.help("add `#![feature(unboxed_closures)]` to the crate attributes to enable")
184+
.emit();
185+
}
152186
}
153187

154188
pub(crate) fn complain_about_assoc_type_not_found<I>(

compiler/rustc_typeck/src/astconv/mod.rs

+14-5
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
669669
trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()),
670670
self_ty,
671671
trait_ref.path.segments.last().unwrap(),
672+
true,
672673
)
673674
}
674675

@@ -765,7 +766,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
765766
let infer_args = trait_segment.infer_args;
766767

767768
self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1);
768-
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment);
769+
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
769770

770771
self.instantiate_poly_trait_ref_inner(
771772
hir_id,
@@ -822,9 +823,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
822823
trait_def_id: DefId,
823824
self_ty: Ty<'tcx>,
824825
trait_segment: &hir::PathSegment<'_>,
826+
is_impl: bool,
825827
) -> ty::TraitRef<'tcx> {
826-
let (substs, _) =
827-
self.create_substs_for_ast_trait_ref(span, trait_def_id, self_ty, trait_segment);
828+
let (substs, _) = self.create_substs_for_ast_trait_ref(
829+
span,
830+
trait_def_id,
831+
self_ty,
832+
trait_segment,
833+
is_impl,
834+
);
828835
let assoc_bindings = self.create_assoc_bindings_for_generic_args(trait_segment.args());
829836
if let Some(b) = assoc_bindings.first() {
830837
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
@@ -839,8 +846,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
839846
trait_def_id: DefId,
840847
self_ty: Ty<'tcx>,
841848
trait_segment: &'a hir::PathSegment<'a>,
849+
is_impl: bool,
842850
) -> (SubstsRef<'tcx>, GenericArgCountResult) {
843-
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment);
851+
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
844852

845853
self.create_substs_for_ast_path(
846854
span,
@@ -1932,7 +1940,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
19321940

19331941
debug!("qpath_to_ty: self_type={:?}", self_ty);
19341942

1935-
let trait_ref = self.ast_path_to_mono_trait_ref(span, trait_def_id, self_ty, trait_segment);
1943+
let trait_ref =
1944+
self.ast_path_to_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false);
19361945

19371946
let item_substs = self.create_substs_for_associated_item(
19381947
tcx,

compiler/rustc_typeck/src/coherence/mod.rs

-22
Original file line numberDiff line numberDiff line change
@@ -121,28 +121,6 @@ fn enforce_trait_manually_implementable(
121121
return;
122122
}
123123
}
124-
125-
let trait_name = if did == li.fn_trait() {
126-
"Fn"
127-
} else if did == li.fn_mut_trait() {
128-
"FnMut"
129-
} else if did == li.fn_once_trait() {
130-
"FnOnce"
131-
} else {
132-
return; // everything OK
133-
};
134-
135-
let span = impl_header_span(tcx, impl_def_id);
136-
struct_span_err!(
137-
tcx.sess,
138-
span,
139-
E0183,
140-
"manual implementations of `{}` are experimental",
141-
trait_name
142-
)
143-
.span_label(span, format!("manual implementations of `{}` are experimental", trait_name))
144-
.help("add `#![feature(unboxed_closures)]` to the crate attributes to enable")
145-
.emit();
146124
}
147125

148126
/// We allow impls of marker traits to overlap, so they can't override impls

src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr

+27-27
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,27 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje
3838
--> $DIR/feature-gate-unboxed-closures-manual-impls.rs:9:6
3939
|
4040
LL | impl Fn<()> for Foo {
41-
| ^^^^^^ help: use parenthetical notation instead: `Fn() -> ()`
41+
| ^^^^^^
4242
|
4343
= note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
4444
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
4545

46+
error[E0183]: manual implementations of `Fn` are experimental
47+
--> $DIR/feature-gate-unboxed-closures-manual-impls.rs:9:6
48+
|
49+
LL | impl Fn<()> for Foo {
50+
| ^^^^^^ manual implementations of `Fn` are experimental
51+
|
52+
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
53+
54+
error[E0183]: manual implementations of `FnOnce` are experimental
55+
--> $DIR/feature-gate-unboxed-closures-manual-impls.rs:16:6
56+
|
57+
LL | impl FnOnce() for Foo1 {
58+
| ^^^^^^^^ manual implementations of `FnOnce` are experimental
59+
|
60+
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
61+
4662
error[E0229]: associated type bindings are not allowed here
4763
--> $DIR/feature-gate-unboxed-closures-manual-impls.rs:16:6
4864
|
@@ -53,49 +69,33 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje
5369
--> $DIR/feature-gate-unboxed-closures-manual-impls.rs:23:6
5470
|
5571
LL | impl FnMut<()> for Bar {
56-
| ^^^^^^^^^ help: use parenthetical notation instead: `FnMut() -> ()`
57-
|
58-
= note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
59-
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
60-
61-
error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change
62-
--> $DIR/feature-gate-unboxed-closures-manual-impls.rs:30:6
63-
|
64-
LL | impl FnOnce<()> for Baz {
65-
| ^^^^^^^^^^ help: use parenthetical notation instead: `FnOnce() -> ()`
72+
| ^^^^^^^^^
6673
|
6774
= note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
6875
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
6976

70-
error[E0183]: manual implementations of `Fn` are experimental
71-
--> $DIR/feature-gate-unboxed-closures-manual-impls.rs:9:1
72-
|
73-
LL | impl Fn<()> for Foo {
74-
| ^^^^^^^^^^^^^^^^^^^ manual implementations of `Fn` are experimental
75-
|
76-
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
77-
7877
error[E0183]: manual implementations of `FnMut` are experimental
79-
--> $DIR/feature-gate-unboxed-closures-manual-impls.rs:23:1
78+
--> $DIR/feature-gate-unboxed-closures-manual-impls.rs:23:6
8079
|
8180
LL | impl FnMut<()> for Bar {
82-
| ^^^^^^^^^^^^^^^^^^^^^^ manual implementations of `FnMut` are experimental
81+
| ^^^^^^^^^ manual implementations of `FnMut` are experimental
8382
|
8483
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
8584

86-
error[E0183]: manual implementations of `FnOnce` are experimental
87-
--> $DIR/feature-gate-unboxed-closures-manual-impls.rs:16:1
85+
error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change
86+
--> $DIR/feature-gate-unboxed-closures-manual-impls.rs:30:6
8887
|
89-
LL | impl FnOnce() for Foo1 {
90-
| ^^^^^^^^^^^^^^^^^^^^^^ manual implementations of `FnOnce` are experimental
88+
LL | impl FnOnce<()> for Baz {
89+
| ^^^^^^^^^^
9190
|
91+
= note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
9292
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
9393

9494
error[E0183]: manual implementations of `FnOnce` are experimental
95-
--> $DIR/feature-gate-unboxed-closures-manual-impls.rs:30:1
95+
--> $DIR/feature-gate-unboxed-closures-manual-impls.rs:30:6
9696
|
9797
LL | impl FnOnce<()> for Baz {
98-
| ^^^^^^^^^^^^^^^^^^^^^^^ manual implementations of `FnOnce` are experimental
98+
| ^^^^^^^^^^ manual implementations of `FnOnce` are experimental
9999
|
100100
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
101101

src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,16 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje
1111
--> $DIR/feature-gate-unboxed-closures.rs:5:6
1212
|
1313
LL | impl FnOnce<(u32, u32)> for Test {
14-
| ^^^^^^^^^^^^^^^^^^ help: use parenthetical notation instead: `FnOnce(u32, u32) -> ()`
14+
| ^^^^^^^^^^^^^^^^^^
1515
|
1616
= note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
1717
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
1818

1919
error[E0183]: manual implementations of `FnOnce` are experimental
20-
--> $DIR/feature-gate-unboxed-closures.rs:5:1
20+
--> $DIR/feature-gate-unboxed-closures.rs:5:6
2121
|
2222
LL | impl FnOnce<(u32, u32)> for Test {
23-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ manual implementations of `FnOnce` are experimental
23+
| ^^^^^^^^^^^^^^^^^^ manual implementations of `FnOnce` are experimental
2424
|
2525
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
2626

0 commit comments

Comments
 (0)