Skip to content

Commit 574a8ba

Browse files
authored
Rollup merge of rust-lang#132214 - fmease:mv-impl-trait-val-paths, r=compiler-errors
Cleanup: Move an impl-Trait check from AST validation to AST lowering Namely the one that rejects `impl Trait` in qself types and non-final path segments. There's no good reason to perform this during AST validation. We have better infrastructure in place in the AST lowerer (`ImplTraitContext`). This shaves off a lot of code. We now lower `impl Trait` in bad positions to `{type error}` which allows us to remove a special case from HIR ty lowering. Coincidentally fixes rust-lang#126725. Well, it only *masks* it by passing `{type error}` to HIR analysis instead of a "bad" opaque. I was able to find a new reproducer for it. See the issue.
2 parents 60beb59 + 442f395 commit 574a8ba

File tree

13 files changed

+78
-153
lines changed

13 files changed

+78
-153
lines changed

compiler/rustc_ast_lowering/src/path.rs

+16-3
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
3434
modifiers: Option<ast::TraitBoundModifiers>,
3535
) -> hir::QPath<'hir> {
3636
let qself_position = qself.as_ref().map(|q| q.position);
37-
let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
37+
let qself = qself
38+
.as_ref()
39+
// Reject cases like `<impl Trait>::Assoc` and `<impl Trait as Trait>::Assoc`.
40+
.map(|q| self.lower_ty(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path)));
3841

3942
let partial_res =
4043
self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
@@ -75,6 +78,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
7578
None
7679
};
7780

81+
// Only permit `impl Trait` in the final segment. E.g., we permit `Option<impl Trait>`,
82+
// `option::Option<T>::Xyz<impl Trait>` and reject `option::Option<impl Trait>::Xyz`.
83+
let itctx = |i| {
84+
if i + 1 == p.segments.len() {
85+
itctx
86+
} else {
87+
ImplTraitContext::Disallowed(ImplTraitPosition::Path)
88+
}
89+
};
90+
7891
let path_span_lo = p.span.shrink_to_lo();
7992
let proj_start = p.segments.len() - unresolved_segments;
8093
let path = self.arena.alloc(hir::Path {
@@ -121,7 +134,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
121134
segment,
122135
param_mode,
123136
generic_args_mode,
124-
itctx,
137+
itctx(i),
125138
bound_modifier_allowed_features.clone(),
126139
)
127140
},
@@ -185,7 +198,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
185198
segment,
186199
param_mode,
187200
generic_args_mode,
188-
itctx,
201+
itctx(i),
189202
None,
190203
));
191204
let qpath = hir::QPath::TypeRelative(ty, hir_segment);

compiler/rustc_ast_passes/messages.ftl

-2
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,6 @@ ast_passes_generic_before_constraints = generic arguments must come before the f
146146
147147
ast_passes_generic_default_trailing = generic parameters with a default must be trailing
148148
149-
ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters
150-
151149
ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
152150
.help = remove one of these features
153151

compiler/rustc_ast_passes/src/ast_validation.rs

-46
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,6 @@ struct AstValidator<'a> {
8080

8181
disallow_tilde_const: Option<TildeConstReason>,
8282

83-
/// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
84-
/// or `Foo::Bar<impl Trait>`
85-
is_impl_trait_banned: bool,
86-
8783
/// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe.
8884
extern_mod_safety: Option<Safety>,
8985

@@ -123,12 +119,6 @@ impl<'a> AstValidator<'a> {
123119
self.extern_mod_safety = old;
124120
}
125121

126-
fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
127-
let old = mem::replace(&mut self.is_impl_trait_banned, true);
128-
f(self);
129-
self.is_impl_trait_banned = old;
130-
}
131-
132122
fn with_tilde_const(
133123
&mut self,
134124
disallowed: Option<TildeConstReason>,
@@ -213,37 +203,6 @@ impl<'a> AstValidator<'a> {
213203
.with_tilde_const(Some(TildeConstReason::TraitObject), |this| {
214204
visit::walk_ty(this, t)
215205
}),
216-
TyKind::Path(qself, path) => {
217-
// We allow these:
218-
// - `Option<impl Trait>`
219-
// - `option::Option<impl Trait>`
220-
// - `option::Option<T>::Foo<impl Trait>`
221-
//
222-
// But not these:
223-
// - `<impl Trait>::Foo`
224-
// - `option::Option<impl Trait>::Foo`.
225-
//
226-
// To implement this, we disallow `impl Trait` from `qself`
227-
// (for cases like `<impl Trait>::Foo>`)
228-
// but we allow `impl Trait` in `GenericArgs`
229-
// iff there are no more PathSegments.
230-
if let Some(qself) = qself {
231-
// `impl Trait` in `qself` is always illegal
232-
self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
233-
}
234-
235-
// Note that there should be a call to visit_path here,
236-
// so if any logic is added to process `Path`s a call to it should be
237-
// added both in visit_path and here. This code mirrors visit::walk_path.
238-
for (i, segment) in path.segments.iter().enumerate() {
239-
// Allow `impl Trait` iff we're on the final path segment
240-
if i == path.segments.len() - 1 {
241-
self.visit_path_segment(segment);
242-
} else {
243-
self.with_banned_impl_trait(|this| this.visit_path_segment(segment));
244-
}
245-
}
246-
}
247206
_ => visit::walk_ty(self, t),
248207
}
249208
}
@@ -737,10 +696,6 @@ impl<'a> AstValidator<'a> {
737696
}
738697
}
739698
TyKind::ImplTrait(_, bounds) => {
740-
if self.is_impl_trait_banned {
741-
self.dcx().emit_err(errors::ImplTraitPath { span: ty.span });
742-
}
743-
744699
if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
745700
self.dcx().emit_err(errors::NestedImplTrait {
746701
span: ty.span,
@@ -1729,7 +1684,6 @@ pub fn check_crate(
17291684
has_proc_macro_decls: false,
17301685
outer_impl_trait: None,
17311686
disallow_tilde_const: Some(TildeConstReason::Item),
1732-
is_impl_trait_banned: false,
17331687
extern_mod_safety: None,
17341688
lint_buffer: lints,
17351689
};

compiler/rustc_ast_passes/src/errors.rs

-7
Original file line numberDiff line numberDiff line change
@@ -418,13 +418,6 @@ pub(crate) struct TraitObjectBound {
418418
pub span: Span,
419419
}
420420

421-
#[derive(Diagnostic)]
422-
#[diag(ast_passes_impl_trait_path, code = E0667)]
423-
pub(crate) struct ImplTraitPath {
424-
#[primary_span]
425-
pub span: Span,
426-
}
427-
428421
#[derive(Diagnostic)]
429422
#[diag(ast_passes_nested_impl_trait, code = E0666)]
430423
pub(crate) struct NestedImplTrait {

compiler/rustc_error_codes/src/error_codes/E0667.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
#### Note: this error code is no longer emitted by the compiler.
2+
13
`impl Trait` is not allowed in path parameters.
24

35
Erroneous code example:
46

5-
```compile_fail,E0667
7+
```ignore (removed error code)
68
fn some_fn(mut x: impl Iterator) -> <impl Iterator>::Item { // error!
79
x.next().unwrap()
810
}
@@ -11,7 +13,7 @@ fn some_fn(mut x: impl Iterator) -> <impl Iterator>::Item { // error!
1113
You cannot use `impl Trait` in path parameters. If you want something
1214
equivalent, you can do this instead:
1315

14-
```
16+
```ignore (removed error code)
1517
fn some_fn<T: Iterator>(mut x: T) -> T::Item { // ok!
1618
x.next().unwrap()
1719
}

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

-9
Original file line numberDiff line numberDiff line change
@@ -1203,15 +1203,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
12031203
err.emit()
12041204
} else if let Err(reported) = qself_ty.error_reported() {
12051205
reported
1206-
} else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() {
1207-
// `<impl Trait as OtherTrait>::Assoc` makes no sense.
1208-
struct_span_code_err!(
1209-
self.dcx(),
1210-
tcx.def_span(alias_ty.def_id),
1211-
E0667,
1212-
"`impl Trait` is not allowed in path parameters"
1213-
)
1214-
.emit() // Already reported in an earlier stage.
12151206
} else {
12161207
self.maybe_report_similar_assoc_fn(span, qself_ty, qself)?;
12171208

tests/crashes/126725.rs

-20
This file was deleted.

tests/ui/impl-trait/impl_trait_projections.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,27 @@ fn path_parametrized_type_is_allowed() -> option::Option<impl Debug> {
1010
}
1111

1212
fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
13-
//~^ ERROR `impl Trait` is not allowed in path parameters
14-
//~| ERROR `impl Trait` is not allowed in path parameters
13+
//~^ ERROR `impl Trait` is not allowed in paths
1514
x.next().unwrap()
1615
}
1716

1817
fn projection_with_named_trait_is_disallowed(mut x: impl Iterator)
1918
-> <impl Iterator as Iterator>::Item
20-
//~^ ERROR `impl Trait` is not allowed in path parameters
19+
//~^ ERROR `impl Trait` is not allowed in paths
2120
{
2221
x.next().unwrap()
2322
}
2423

2524
fn projection_with_named_trait_inside_path_is_disallowed()
2625
-> <::std::ops::Range<impl Debug> as Iterator>::Item
27-
//~^ ERROR `impl Trait` is not allowed in path parameters
28-
//~| ERROR `impl Debug: Step` is not satisfied
26+
//~^ ERROR `impl Trait` is not allowed in paths
2927
{
30-
//~^ ERROR `impl Debug: Step` is not satisfied
3128
(1i32..100).next().unwrap()
3229
}
3330

3431
fn projection_from_impl_trait_inside_dyn_trait_is_disallowed()
3532
-> <dyn Iterator<Item = impl Debug> as Iterator>::Item
36-
//~^ ERROR `impl Trait` is not allowed in path parameters
33+
//~^ ERROR `impl Trait` is not allowed in paths
3734
{
3835
panic!()
3936
}
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,35 @@
1-
error[E0667]: `impl Trait` is not allowed in path parameters
1+
error[E0562]: `impl Trait` is not allowed in paths
22
--> $DIR/impl_trait_projections.rs:12:51
33
|
44
LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
55
| ^^^^^^^^^^^^^
6+
|
7+
= note: `impl Trait` is only allowed in arguments and return types of functions and methods
68

7-
error[E0667]: `impl Trait` is not allowed in path parameters
8-
--> $DIR/impl_trait_projections.rs:19:9
9+
error[E0562]: `impl Trait` is not allowed in paths
10+
--> $DIR/impl_trait_projections.rs:18:9
911
|
1012
LL | -> <impl Iterator as Iterator>::Item
1113
| ^^^^^^^^^^^^^
14+
|
15+
= note: `impl Trait` is only allowed in arguments and return types of functions and methods
1216

13-
error[E0667]: `impl Trait` is not allowed in path parameters
14-
--> $DIR/impl_trait_projections.rs:26:27
17+
error[E0562]: `impl Trait` is not allowed in paths
18+
--> $DIR/impl_trait_projections.rs:25:27
1519
|
1620
LL | -> <::std::ops::Range<impl Debug> as Iterator>::Item
1721
| ^^^^^^^^^^
22+
|
23+
= note: `impl Trait` is only allowed in arguments and return types of functions and methods
1824

19-
error[E0667]: `impl Trait` is not allowed in path parameters
20-
--> $DIR/impl_trait_projections.rs:35:29
25+
error[E0562]: `impl Trait` is not allowed in paths
26+
--> $DIR/impl_trait_projections.rs:32:29
2127
|
2228
LL | -> <dyn Iterator<Item = impl Debug> as Iterator>::Item
2329
| ^^^^^^^^^^
24-
25-
error[E0667]: `impl Trait` is not allowed in path parameters
26-
--> $DIR/impl_trait_projections.rs:12:51
27-
|
28-
LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
29-
| ^^^^^^^^^^^^^
30-
31-
error[E0277]: the trait bound `impl Debug: Step` is not satisfied
32-
--> $DIR/impl_trait_projections.rs:26:8
33-
|
34-
LL | -> <::std::ops::Range<impl Debug> as Iterator>::Item
35-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Step` is not implemented for `impl Debug`, which is required by `std::ops::Range<impl Debug>: Iterator`
36-
|
37-
= help: the following other types implement trait `Step`:
38-
Char
39-
Ipv4Addr
40-
Ipv6Addr
41-
char
42-
i128
43-
i16
44-
i32
45-
i64
46-
and 8 others
47-
= note: required for `std::ops::Range<impl Debug>` to implement `Iterator`
48-
49-
error[E0277]: the trait bound `impl Debug: Step` is not satisfied
50-
--> $DIR/impl_trait_projections.rs:29:1
51-
|
52-
LL | / {
53-
LL | |
54-
LL | | (1i32..100).next().unwrap()
55-
LL | | }
56-
| |_^ the trait `Step` is not implemented for `impl Debug`, which is required by `std::ops::Range<impl Debug>: Iterator`
5730
|
58-
= help: the following other types implement trait `Step`:
59-
Char
60-
Ipv4Addr
61-
Ipv6Addr
62-
char
63-
i128
64-
i16
65-
i32
66-
i64
67-
and 8 others
68-
= note: required for `std::ops::Range<impl Debug>` to implement `Iterator`
31+
= note: `impl Trait` is only allowed in arguments and return types of functions and methods
6932

70-
error: aborting due to 7 previous errors
33+
error: aborting due to 4 previous errors
7134

72-
Some errors have detailed explanations: E0277, E0667.
73-
For more information about an error, try `rustc --explain E0277`.
35+
For more information about this error, try `rustc --explain E0562`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// issue: rust-lang/rust#126725
2+
3+
trait Foo {
4+
fn foo<'a>() -> <&'a impl Sized as Bar>::Output;
5+
//~^ ERROR `impl Trait` is not allowed in paths
6+
}
7+
8+
trait Bar {
9+
type Output;
10+
}
11+
12+
impl<'a> Bar for &'a () {
13+
type Output = &'a i32;
14+
}
15+
16+
impl Foo for () {
17+
fn foo<'a>() -> <&'a Self as Bar>::Output {
18+
&0
19+
}
20+
}
21+
22+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0562]: `impl Trait` is not allowed in paths
2+
--> $DIR/bad-projection-from-opaque.rs:4:26
3+
|
4+
LL | fn foo<'a>() -> <&'a impl Sized as Bar>::Output;
5+
| ^^^^^^^^^^
6+
|
7+
= note: `impl Trait` is only allowed in arguments and return types of functions and methods
8+
9+
error: aborting due to 1 previous error
10+
11+
For more information about this error, try `rustc --explain E0562`.

tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
pub trait Bar { }
77
pub trait Quux<T> { type Assoc; }
88
pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { }
9-
//~^ ERROR `impl Trait` is not allowed in path parameters
9+
//~^ ERROR `impl Trait` is not allowed in paths
1010
impl<T> Quux<T> for () { type Assoc = u32; }
1111

1212
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
error[E0667]: `impl Trait` is not allowed in path parameters
1+
error[E0562]: `impl Trait` is not allowed in paths
22
--> $DIR/issue-57979-impl-trait-in-path.rs:8:48
33
|
44
LL | pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { }
55
| ^^^^^^^^
6+
|
7+
= note: `impl Trait` is only allowed in arguments and return types of functions and methods
68

79
error: aborting due to 1 previous error
810

9-
For more information about this error, try `rustc --explain E0667`.
11+
For more information about this error, try `rustc --explain E0562`.

0 commit comments

Comments
 (0)