From 9dc57958dce77c7d48351a7f248f0eb4f206d0a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sun, 17 Mar 2024 20:22:00 +0100 Subject: [PATCH 1/4] Move validation of `impl Trait` in qpaths from ASTValidator to AST lowering --- compiler/rustc_ast_lowering/src/path.rs | 21 ++++-- compiler/rustc_ast_passes/messages.ftl | 2 - .../rustc_ast_passes/src/ast_validation.rs | 46 ------------ compiler/rustc_ast_passes/src/errors.rs | 7 -- tests/rustdoc/rrustdoc/auxiliary/dep.rs | 2 + tests/rustdoc/rrustdoc/crazy.rs | 9 +++ tests/rustdoc/rrustdoc/dep.rs | 1 + tests/ui/impl-trait/impl_trait_projections.rs | 11 ++- .../impl-trait/impl_trait_projections.stderr | 70 +++++-------------- .../issues/issue-57979-impl-trait-in-path.rs | 4 +- 10 files changed, 49 insertions(+), 124 deletions(-) create mode 100644 tests/rustdoc/rrustdoc/auxiliary/dep.rs create mode 100644 tests/rustdoc/rrustdoc/crazy.rs create mode 100644 tests/rustdoc/rrustdoc/dep.rs diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index aeeb4bf9e763a..cfb7279ed2aea 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -32,7 +32,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { modifiers: Option, ) -> hir::QPath<'hir> { let qself_position = qself.as_ref().map(|q| q.position); - let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx)); + let qself = qself + .as_ref() + .map(|q| self.lower_ty(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path))); let partial_res = self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err)); @@ -71,14 +73,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { res, segments: self.arena.alloc_from_iter(p.segments[..proj_start].iter().enumerate().map( |(i, segment)| { - let param_mode = match (qself_position, param_mode) { + let (param_mode, itctx) = match (qself_position, param_mode) { (Some(j), ParamMode::Optional) if i < j => { - // This segment is part of the trait path in a - // qualified path - one of `a`, `b` or `Trait` - // in `::T::U::method`. - ParamMode::Explicit + // This segment is part of the trait path in a qualified path: + // One of `a`, `b` or `Trait` in `::T::U::method`. + // `impl Trait` is unconditionally disallowed here. + ( + ParamMode::Explicit, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + ) } - _ => param_mode, + _ => (param_mode, itctx), }; let parenthesized_generic_args = match base_res { @@ -162,6 +167,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { segment, param_mode, ParenthesizedGenericArgs::Err, + // Whether `impl Trait` is allowed here depends on the context contrary to + // the self type and trait segment paths in qualified paths (see above). itctx, None, None, diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 28a13d275a559..b76a31519687a 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -149,8 +149,6 @@ ast_passes_generic_before_constraints = generic arguments must come before the f ast_passes_generic_default_trailing = generic parameters with a default must be trailing -ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters - ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed .help = remove one of these features diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 80c62d3fecf49..ec1e2f706fbae 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -83,10 +83,6 @@ struct AstValidator<'a> { disallow_tilde_const: Option>, - /// Used to ban `impl Trait` in path projections like `::Item` - /// or `Foo::Bar` - is_impl_trait_banned: bool, - lint_buffer: &'a mut LintBuffer, } @@ -117,12 +113,6 @@ impl<'a> AstValidator<'a> { self.outer_trait_or_trait_impl = old; } - fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) { - let old = mem::replace(&mut self.is_impl_trait_banned, true); - f(self); - self.is_impl_trait_banned = old; - } - fn with_tilde_const( &mut self, disallowed: Option>, @@ -191,37 +181,6 @@ impl<'a> AstValidator<'a> { .with_tilde_const(Some(DisallowTildeConstContext::TraitObject), |this| { visit::walk_ty(this, t) }), - TyKind::Path(qself, path) => { - // We allow these: - // - `Option` - // - `option::Option` - // - `option::Option::Foo` - // - // But not these: - // - `::Foo` - // - `option::Option::Foo`. - // - // To implement this, we disallow `impl Trait` from `qself` - // (for cases like `::Foo>`) - // but we allow `impl Trait` in `GenericArgs` - // iff there are no more PathSegments. - if let Some(qself) = qself { - // `impl Trait` in `qself` is always illegal - self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty)); - } - - // Note that there should be a call to visit_path here, - // so if any logic is added to process `Path`s a call to it should be - // added both in visit_path and here. This code mirrors visit::walk_path. - for (i, segment) in path.segments.iter().enumerate() { - // Allow `impl Trait` iff we're on the final path segment - if i == path.segments.len() - 1 { - self.visit_path_segment(segment); - } else { - self.with_banned_impl_trait(|this| this.visit_path_segment(segment)); - } - } - } TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => { walk_list!(self, visit_struct_field_def, fields) } @@ -715,10 +674,6 @@ impl<'a> AstValidator<'a> { } } TyKind::ImplTrait(_, bounds) => { - if self.is_impl_trait_banned { - self.dcx().emit_err(errors::ImplTraitPath { span: ty.span }); - } - if let Some(outer_impl_trait_sp) = self.outer_impl_trait { self.dcx().emit_err(errors::NestedImplTrait { span: ty.span, @@ -1718,7 +1673,6 @@ pub fn check_crate( has_proc_macro_decls: false, outer_impl_trait: None, disallow_tilde_const: Some(DisallowTildeConstContext::Item), - is_impl_trait_banned: false, lint_buffer: lints, }; visit::walk_crate(&mut validator, krate); diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 9e8c1d7f5fd19..b2b837c4c50d8 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -397,13 +397,6 @@ pub struct TraitObjectBound { pub span: Span, } -#[derive(Diagnostic)] -#[diag(ast_passes_impl_trait_path, code = E0667)] -pub struct ImplTraitPath { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(ast_passes_nested_impl_trait, code = E0666)] pub struct NestedImplTrait { diff --git a/tests/rustdoc/rrustdoc/auxiliary/dep.rs b/tests/rustdoc/rrustdoc/auxiliary/dep.rs new file mode 100644 index 0000000000000..ddd7ee5579374 --- /dev/null +++ b/tests/rustdoc/rrustdoc/auxiliary/dep.rs @@ -0,0 +1,2 @@ +pub struct X; + diff --git a/tests/rustdoc/rrustdoc/crazy.rs b/tests/rustdoc/rrustdoc/crazy.rs new file mode 100644 index 0000000000000..4f6662026a14d --- /dev/null +++ b/tests/rustdoc/rrustdoc/crazy.rs @@ -0,0 +1,9 @@ +//(@) aux-crate:dep=dep.rs +//@ aux-crate:dep +//(@) aux-build:../dep.rs + +extern crate dep; + +use dep::X; + + diff --git a/tests/rustdoc/rrustdoc/dep.rs b/tests/rustdoc/rrustdoc/dep.rs new file mode 100644 index 0000000000000..10ff0bd960d06 --- /dev/null +++ b/tests/rustdoc/rrustdoc/dep.rs @@ -0,0 +1 @@ +pub struct X; diff --git a/tests/ui/impl-trait/impl_trait_projections.rs b/tests/ui/impl-trait/impl_trait_projections.rs index 365ac85e2f665..2c277aee06dad 100644 --- a/tests/ui/impl-trait/impl_trait_projections.rs +++ b/tests/ui/impl-trait/impl_trait_projections.rs @@ -10,30 +10,27 @@ fn path_parametrized_type_is_allowed() -> option::Option { } fn projection_is_disallowed(x: impl Iterator) -> ::Item { -//~^ ERROR `impl Trait` is not allowed in path parameters -//~| ERROR `impl Trait` is not allowed in path parameters +//~^ ERROR `impl Trait` is not allowed in paths x.next().unwrap() } fn projection_with_named_trait_is_disallowed(mut x: impl Iterator) -> ::Item -//~^ ERROR `impl Trait` is not allowed in path parameters +//~^ ERROR `impl Trait` is not allowed in paths { x.next().unwrap() } fn projection_with_named_trait_inside_path_is_disallowed() -> <::std::ops::Range as Iterator>::Item -//~^ ERROR `impl Trait` is not allowed in path parameters -//~| ERROR `impl Debug: Step` is not satisfied +//~^ ERROR `impl Trait` is not allowed in paths { - //~^ ERROR `impl Debug: Step` is not satisfied (1i32..100).next().unwrap() } fn projection_from_impl_trait_inside_dyn_trait_is_disallowed() -> as Iterator>::Item -//~^ ERROR `impl Trait` is not allowed in path parameters +//~^ ERROR `impl Trait` is not allowed in paths { panic!() } diff --git a/tests/ui/impl-trait/impl_trait_projections.stderr b/tests/ui/impl-trait/impl_trait_projections.stderr index d62e3ac4183f5..5e0b80fcd5922 100644 --- a/tests/ui/impl-trait/impl_trait_projections.stderr +++ b/tests/ui/impl-trait/impl_trait_projections.stderr @@ -1,73 +1,35 @@ -error[E0667]: `impl Trait` is not allowed in path parameters +error[E0562]: `impl Trait` is not allowed in paths --> $DIR/impl_trait_projections.rs:12:51 | LL | fn projection_is_disallowed(x: impl Iterator) -> ::Item { | ^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0667]: `impl Trait` is not allowed in path parameters - --> $DIR/impl_trait_projections.rs:19:9 +error[E0562]: `impl Trait` is not allowed in paths + --> $DIR/impl_trait_projections.rs:18:9 | LL | -> ::Item | ^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0667]: `impl Trait` is not allowed in path parameters - --> $DIR/impl_trait_projections.rs:26:27 +error[E0562]: `impl Trait` is not allowed in paths + --> $DIR/impl_trait_projections.rs:25:27 | LL | -> <::std::ops::Range as Iterator>::Item | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0667]: `impl Trait` is not allowed in path parameters - --> $DIR/impl_trait_projections.rs:35:29 +error[E0562]: `impl Trait` is not allowed in paths + --> $DIR/impl_trait_projections.rs:32:29 | LL | -> as Iterator>::Item | ^^^^^^^^^^ - -error[E0667]: `impl Trait` is not allowed in path parameters - --> $DIR/impl_trait_projections.rs:12:51 - | -LL | fn projection_is_disallowed(x: impl Iterator) -> ::Item { - | ^^^^^^^^^^^^^ - -error[E0277]: the trait bound `impl Debug: Step` is not satisfied - --> $DIR/impl_trait_projections.rs:26:8 - | -LL | -> <::std::ops::Range as Iterator>::Item - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Step` is not implemented for `impl Debug`, which is required by `std::ops::Range: Iterator` - | - = help: the following other types implement trait `Step`: - Char - Ipv4Addr - Ipv6Addr - char - i128 - i16 - i32 - i64 - and 8 others - = note: required for `std::ops::Range` to implement `Iterator` - -error[E0277]: the trait bound `impl Debug: Step` is not satisfied - --> $DIR/impl_trait_projections.rs:29:1 - | -LL | / { -LL | | -LL | | (1i32..100).next().unwrap() -LL | | } - | |_^ the trait `Step` is not implemented for `impl Debug`, which is required by `std::ops::Range: Iterator` | - = help: the following other types implement trait `Step`: - Char - Ipv4Addr - Ipv6Addr - char - i128 - i16 - i32 - i64 - and 8 others - = note: required for `std::ops::Range` to implement `Iterator` + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error: aborting due to 7 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0277, E0667. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs index c5ecd1caae1f9..718830589af6a 100644 --- a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs +++ b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs @@ -3,10 +3,12 @@ // Here we test behavior of occurrences of `impl Trait` within a path // component in that context. +// FIXME(fmease): this is now check-pass :( + pub trait Bar { } pub trait Quux { type Assoc; } pub fn demo(_: impl Quux<(), Assoc=<() as Quux>::Assoc>) { } -//~^ ERROR `impl Trait` is not allowed in path parameters +//~^ ERROR `impl Trait` is not allowed in paths impl Quux for () { type Assoc = u32; } fn main() { } From 218e9d355599d89ac02dff2f5d10fa461e8b7095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 18 Mar 2024 02:14:50 +0100 Subject: [PATCH 2/4] [WIP] Move detection of nested `impl Trait` from ASTValidator to AST lowering --- compiler/rustc_ast_lowering/src/item.rs | 6 +-- compiler/rustc_ast_lowering/src/lib.rs | 51 +++++++++++-------- compiler/rustc_ast_lowering/src/path.rs | 24 ++++++--- compiler/rustc_ast_passes/messages.ftl | 4 -- .../rustc_ast_passes/src/ast_validation.rs | 35 ++----------- compiler/rustc_ast_passes/src/errors.rs | 11 ---- 6 files changed, 52 insertions(+), 79 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index c9786328565ba..63ef821279397 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -470,7 +470,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ty: &Ty, span: Span, body: Option<&Expr>, - impl_trait_position: ImplTraitPosition, + impl_trait_position: ImplTraitPosition<'_>, ) -> (&'hir hir::Ty<'hir>, hir::BodyId) { let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(impl_trait_position)); (ty, self.lower_const_body(span, body)) @@ -1418,7 +1418,7 @@ impl<'hir> LoweringContext<'_, 'hir> { generics: &Generics, constness: Const, parent_node_id: NodeId, - itctx: ImplTraitContext, + itctx: ImplTraitContext<'_>, f: impl FnOnce(&mut Self) -> T, ) -> (&'hir hir::Generics<'hir>, T) { debug_assert!(self.impl_trait_defs.is_empty()); @@ -1624,7 +1624,7 @@ impl<'hir> LoweringContext<'_, 'hir> { bounds: &[GenericBound], colon_span: Option, parent_span: Span, - itctx: ImplTraitContext, + itctx: ImplTraitContext<'_>, origin: PredicateOrigin, ) -> Option> { // Do not create a clause if we do not have anything inside it. diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 833b0e9b5679e..9e5f669630891 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -255,7 +255,7 @@ impl ResolverAstLowering { /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree, /// and if so, what meaning it has. #[derive(Debug, Copy, Clone, PartialEq, Eq)] -enum ImplTraitContext { +enum ImplTraitContext<'a> { /// Treat `impl Trait` as shorthand for a new universal generic parameter. /// Example: `fn foo(x: impl Debug)`, where `impl Debug` is conceptually /// equivalent to a fresh universal parameter like `fn foo(x: T)`. @@ -274,14 +274,14 @@ enum ImplTraitContext { fn_kind: Option, }, /// `impl Trait` is unstably accepted in this position. - FeatureGated(ImplTraitPosition, Symbol), + FeatureGated(ImplTraitPosition<'a>, Symbol), /// `impl Trait` is not accepted in this position. - Disallowed(ImplTraitPosition), + Disallowed(ImplTraitPosition<'a>), } /// Position in which `impl Trait` is disallowed. #[derive(Debug, Copy, Clone, PartialEq, Eq)] -enum ImplTraitPosition { +enum ImplTraitPosition<'a> { Path, Variable, Trait, @@ -303,9 +303,10 @@ enum ImplTraitPosition { Cast, ImplSelf, OffsetOf, + ImplTrait { outer: &'a ImplTraitContext<'a> }, } -impl std::fmt::Display for ImplTraitPosition { +impl std::fmt::Display for ImplTraitPosition<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let name = match self { ImplTraitPosition::Path => "paths", @@ -329,6 +330,7 @@ impl std::fmt::Display for ImplTraitPosition { ImplTraitPosition::Cast => "cast expression types", ImplTraitPosition::ImplSelf => "impl headers", ImplTraitPosition::OffsetOf => "`offset_of!` parameters", + ImplTraitPosition::ImplTrait { .. } => "`impl Trait`", }; write!(f, "{name}") @@ -979,7 +981,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_assoc_ty_constraint( &mut self, constraint: &AssocConstraint, - itctx: ImplTraitContext, + itctx: ImplTraitContext<'_>, ) -> hir::TypeBinding<'hir> { debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx); // lower generic arguments of identifier in constraint @@ -1129,7 +1131,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_generic_arg( &mut self, arg: &ast::GenericArg, - itctx: ImplTraitContext, + itctx: ImplTraitContext<'_>, ) -> hir::GenericArg<'hir> { match arg { ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(lt)), @@ -1208,7 +1210,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } #[instrument(level = "debug", skip(self))] - fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> { + fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext<'_>) -> &'hir hir::Ty<'hir> { self.arena.alloc(self.lower_ty_direct(t, itctx)) } @@ -1218,7 +1220,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself: &Option>, path: &Path, param_mode: ParamMode, - itctx: ImplTraitContext, + itctx: ImplTraitContext<'_>, ) -> hir::Ty<'hir> { // Check whether we should interpret this as a bare trait object. // This check mirrors the one in late resolution. We only introduce this special case in @@ -1260,7 +1262,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.ty(span, hir::TyKind::Tup(tys)) } - fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> { + fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext<'_>) -> hir::Ty<'hir> { let kind = match &t.kind { TyKind::Infer => hir::TyKind::Infer, TyKind::Err(guar) => hir::TyKind::Err(*guar), @@ -1407,7 +1409,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { *def_node_id, bounds, fn_kind, - itctx, + ImplTraitContext::Disallowed(ImplTraitPosition::ImplTrait { + outer: &itctx, + }), ), ImplTraitContext::Universal => { let span = t.span; @@ -1516,7 +1520,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { opaque_ty_node_id: NodeId, bounds: &GenericBounds, fn_kind: Option, - itctx: ImplTraitContext, + itctx: ImplTraitContext<'_>, ) -> hir::TyKind<'hir> { // Make sure we know that some funky desugaring has been going on here. // This is a first: there is code in other places like for loop @@ -1924,7 +1928,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { output: &FnRetTy, coro: CoroutineKind, opaque_ty_span: Span, - itctx: ImplTraitContext, + itctx: ImplTraitContext<'_>, ) -> hir::GenericBound<'hir> { // Compute the `T` in `Future` from the return type. let output_ty = match output { @@ -1972,7 +1976,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_param_bound( &mut self, tpb: &GenericBound, - itctx: ImplTraitContext, + itctx: ImplTraitContext<'_>, ) -> hir::GenericBound<'hir> { match tpb { GenericBound::Trait(p, modifiers) => hir::GenericBound::Trait( @@ -2151,7 +2155,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, modifiers: ast::TraitBoundModifiers, p: &TraitRef, - itctx: ImplTraitContext, + itctx: ImplTraitContext<'_>, ) -> hir::TraitRef<'hir> { let path = match self.lower_qpath( p.ref_id, @@ -2171,7 +2175,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_poly_trait_ref( &mut self, p: &PolyTraitRef, - itctx: ImplTraitContext, + itctx: ImplTraitContext<'_>, modifiers: ast::TraitBoundModifiers, ) -> hir::PolyTraitRef<'hir> { let bound_generic_params = @@ -2180,7 +2184,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) } } - fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> { + fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext<'_>) -> hir::MutTy<'hir> { hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl } } @@ -2188,16 +2192,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_param_bounds( &mut self, bounds: &[GenericBound], - itctx: ImplTraitContext, + itctx: ImplTraitContext<'_>, ) -> hir::GenericBounds<'hir> { self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, itctx)) } - fn lower_param_bounds_mut<'s>( + fn lower_param_bounds_mut<'s, 'c>( &'s mut self, bounds: &'s [GenericBound], - itctx: ImplTraitContext, - ) -> impl Iterator> + Captures<'s> + Captures<'a> { + itctx: ImplTraitContext<'c>, + ) -> impl Iterator> + Captures<'s> + Captures<'c> + Captures<'a> + { bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx)) } @@ -2232,7 +2237,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { bounds, /* colon_span */ None, span, - ImplTraitContext::Universal, + ImplTraitContext::Disallowed(ImplTraitPosition::ImplTrait { + outer: &ImplTraitContext::Universal, + }), hir::PredicateOrigin::ImplTrait, ); diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index cfb7279ed2aea..d22e88be1e4e2 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -27,7 +27,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself: &Option>, p: &Path, param_mode: ParamMode, - itctx: ImplTraitContext, + itctx: ImplTraitContext<'_>, // modifiers of the impl/bound if this is a trait path modifiers: Option, ) -> hir::QPath<'hir> { @@ -227,7 +227,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { segment: &PathSegment, param_mode: ParamMode, parenthesized_generic_args: ParenthesizedGenericArgs, - itctx: ImplTraitContext, + itctx: ImplTraitContext<'_>, constness: Option, // Additional features ungated with a bound modifier like `async`. // This is passed down to the implicit associated type binding in @@ -381,7 +381,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, data: &AngleBracketedArgs, param_mode: ParamMode, - itctx: ImplTraitContext, + itctx: ImplTraitContext<'_>, ) -> (GenericArgsCtor<'hir>, bool) { let has_non_lt_args = data.args.iter().any(|arg| match arg { AngleBracketedArg::Arg(ast::GenericArg::Lifetime(_)) @@ -396,10 +396,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { AngleBracketedArg::Constraint(_) => None, }) .collect(); - let bindings = self.arena.alloc_from_iter(data.args.iter().filter_map(|arg| match arg { - AngleBracketedArg::Constraint(c) => Some(self.lower_assoc_ty_constraint(c, itctx)), - AngleBracketedArg::Arg(_) => None, - })); + let bindings = { + // FIXME(fmease): explainer + let itctx = match itctx { + ImplTraitContext::Disallowed(ImplTraitPosition::ImplTrait { outer }) => *outer, + itctx => itctx, + }; + + self.arena.alloc_from_iter(data.args.iter().filter_map(|arg| match arg { + AngleBracketedArg::Constraint(c) => Some(self.lower_assoc_ty_constraint(c, itctx)), + AngleBracketedArg::Arg(_) => None, + })) + }; let ctor = GenericArgsCtor { args, bindings, @@ -412,7 +420,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_parenthesized_parameter_data( &mut self, data: &ParenthesizedArgs, - itctx: ImplTraitContext, + itctx: ImplTraitContext<'_>, bound_modifier_allowed_features: Option>, ) -> (GenericArgsCtor<'hir>, bool) { // Switch to `PassThrough` mode for anonymous lifetimes; this diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index b76a31519687a..a6a0d80e45895 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -189,10 +189,6 @@ ast_passes_negative_bound_not_supported = ast_passes_negative_bound_with_parenthetical_notation = parenthetical notation may not be used for negative bounds -ast_passes_nested_impl_trait = nested `impl Trait` is not allowed - .outer = outer `impl Trait` - .inner = nested `impl Trait` here - ast_passes_nested_lifetimes = nested quantification of lifetimes ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index ec1e2f706fbae..7c91b664c9c92 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -76,11 +76,6 @@ struct AstValidator<'a> { has_proc_macro_decls: bool, - /// Used to ban nested `impl Trait`, e.g., `impl Into`. - /// Nested `impl Trait` _is_ allowed in associated type position, - /// e.g., `impl Iterator`. - outer_impl_trait: Option, - disallow_tilde_const: Option>, lint_buffer: &'a mut LintBuffer, @@ -165,18 +160,9 @@ impl<'a> AstValidator<'a> { Err(errors::WhereClauseBeforeTypeAlias { span, sugg }) } - fn with_impl_trait(&mut self, outer: Option, f: impl FnOnce(&mut Self)) { - let old = mem::replace(&mut self.outer_impl_trait, outer); - f(self); - self.outer_impl_trait = old; - } - // Mirrors `visit::walk_ty`, but tracks relevant state. fn walk_ty(&mut self, t: &'a Ty) { match &t.kind { - TyKind::ImplTrait(..) => { - self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t)) - } TyKind::TraitObject(..) => self .with_tilde_const(Some(DisallowTildeConstContext::TraitObject), |this| { visit::walk_ty(this, t) @@ -674,14 +660,6 @@ impl<'a> AstValidator<'a> { } } TyKind::ImplTrait(_, bounds) => { - if let Some(outer_impl_trait_sp) = self.outer_impl_trait { - self.dcx().emit_err(errors::NestedImplTrait { - span: ty.span, - outer: outer_impl_trait_sp, - inner: ty.span, - }); - } - if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) { self.dcx().emit_err(errors::AtLeastOneTrait { span: ty.span }); } @@ -1133,25 +1111,21 @@ impl<'a> Visitor<'a> for AstValidator<'a> { GenericArgs::AngleBracketed(data) => { self.check_generic_args_before_constraints(data); + // FIXME: use walk method if available for arg in &data.args { match arg { AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg), - // Type bindings such as `Item = impl Debug` in `Iterator` - // are allowed to contain nested `impl Trait`. AngleBracketedArg::Constraint(constraint) => { - self.with_impl_trait(None, |this| { - this.visit_assoc_constraint(constraint); - }); + self.visit_assoc_constraint(constraint); } } } } + // FIXME: use walk method if available GenericArgs::Parenthesized(data) => { walk_list!(self, visit_ty, &data.inputs); if let FnRetTy::Ty(ty) = &data.output { - // `-> Foo` syntax is essentially an associated type binding, - // so it is also allowed to contain nested `impl Trait`. - self.with_impl_trait(None, |this| this.visit_ty(ty)); + self.visit_ty(ty); } } } @@ -1671,7 +1645,6 @@ pub fn check_crate( extern_mod: None, outer_trait_or_trait_impl: None, has_proc_macro_decls: false, - outer_impl_trait: None, disallow_tilde_const: Some(DisallowTildeConstContext::Item), lint_buffer: lints, }; diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index b2b837c4c50d8..2cb5162853640 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -397,17 +397,6 @@ pub struct TraitObjectBound { pub span: Span, } -#[derive(Diagnostic)] -#[diag(ast_passes_nested_impl_trait, code = E0666)] -pub struct NestedImplTrait { - #[primary_span] - pub span: Span, - #[label(ast_passes_outer)] - pub outer: Span, - #[label(ast_passes_inner)] - pub inner: Span, -} - #[derive(Diagnostic)] #[diag(ast_passes_at_least_one_trait)] pub struct AtLeastOneTrait { From 2dc206fb71044ac92e8dc4e0d2539b2ddf229626 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sat, 6 Apr 2024 02:57:07 +0200 Subject: [PATCH 3/4] wip --- compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 8886a78c6ecdc..08ddd2bb0502b 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1212,7 +1212,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { err.emit() } else if let Err(reported) = qself_ty.error_reported() { reported - } else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() { + } else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() { // FIXME: bug! // `::Assoc` makes no sense. struct_span_code_err!( tcx.dcx(), From fe49d0af269860e4a9cf20a5d43fc584a19140df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sat, 6 Apr 2024 03:28:30 +0200 Subject: [PATCH 4/4] tests --- ...-deeply-nested-impl-trait-in-assoc-proj.rs | 2 +- ...ply-nested-impl-trait-in-assoc-proj.stderr | 11 ++- ...e-57979-nested-impl-trait-in-assoc-proj.rs | 2 +- ...979-nested-impl-trait-in-assoc-proj.stderr | 11 ++- tests/ui/impl-trait/nested_impl_trait.rs | 8 +-- tests/ui/impl-trait/nested_impl_trait.stderr | 67 ++++++------------- tests/ui/impl-trait/where-allowed.rs | 4 +- tests/ui/impl-trait/where-allowed.stderr | 30 +++------ 8 files changed, 50 insertions(+), 85 deletions(-) diff --git a/tests/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs b/tests/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs index 0daec3305c0ae..dd8f7453aa127 100644 --- a/tests/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs +++ b/tests/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs @@ -12,6 +12,6 @@ pub trait Foo { } pub trait Bar { } pub trait Quux { type Assoc; } pub fn demo(_: impl Quux>>) { } -//~^ ERROR nested `impl Trait` is not allowed +//~^ ERROR `impl Trait` is not allowed in `impl Trait` fn main() { } diff --git a/tests/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.stderr b/tests/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.stderr index 83d0d77657247..8145d4ab5e3de 100644 --- a/tests/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.stderr +++ b/tests/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.stderr @@ -1,12 +1,11 @@ -error[E0666]: nested `impl Trait` is not allowed +error[E0562]: `impl Trait` is not allowed in `impl Trait` --> $DIR/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs:14:48 | LL | pub fn demo(_: impl Quux>>) { } - | ---------^^^^^^^^- - | | | - | | nested `impl Trait` here - | outer `impl Trait` + | ^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0666`. +For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.rs b/tests/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.rs index 5a444d3dfddfa..0c1ef2088963d 100644 --- a/tests/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.rs +++ b/tests/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.rs @@ -7,6 +7,6 @@ pub trait Foo { } pub trait Bar { } pub trait Quux { type Assoc; } pub fn demo(_: impl Quux>) { } -//~^ ERROR nested `impl Trait` is not allowed +//~^ ERROR `impl Trait` is not allowed in `impl Trait` fn main() { } diff --git a/tests/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.stderr b/tests/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.stderr index 0e105817b18af..f03bc62608341 100644 --- a/tests/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.stderr +++ b/tests/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.stderr @@ -1,12 +1,11 @@ -error[E0666]: nested `impl Trait` is not allowed +error[E0562]: `impl Trait` is not allowed in `impl Trait` --> $DIR/issue-57979-nested-impl-trait-in-assoc-proj.rs:9:41 | LL | pub fn demo(_: impl Quux>) { } - | ---------^^^^^^^^- - | | | - | | nested `impl Trait` here - | outer `impl Trait` + | ^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0666`. +For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/impl-trait/nested_impl_trait.rs b/tests/ui/impl-trait/nested_impl_trait.rs index 760102794c34e..610159d0b4773 100644 --- a/tests/ui/impl-trait/nested_impl_trait.rs +++ b/tests/ui/impl-trait/nested_impl_trait.rs @@ -4,20 +4,20 @@ use std::fmt::Debug; fn fine(x: impl Into) -> impl Into { x } fn bad_in_ret_position(x: impl Into) -> impl Into { x } -//~^ ERROR nested `impl Trait` is not allowed +//~^ ERROR `impl Trait` is not allowed in `impl Trait` //~| ERROR the trait bound `impl Debug: From>` is not satisfied fn bad_in_fn_syntax(x: fn() -> impl Into) {} -//~^ ERROR nested `impl Trait` is not allowed +//~^ ERROR `impl Trait` is not allowed in `impl Trait` //~| `impl Trait` is not allowed in `fn` pointer fn bad_in_arg_position(_: impl Into) { } -//~^ ERROR nested `impl Trait` is not allowed +//~^ ERROR `impl Trait` is not allowed in `impl Trait` struct X; impl X { fn bad(x: impl Into) -> impl Into { x } - //~^ ERROR nested `impl Trait` is not allowed + //~^ ERROR `impl Trait` is not allowed in `impl Trait` //~| ERROR the trait bound `impl Debug: From>` is not satisfied } diff --git a/tests/ui/impl-trait/nested_impl_trait.stderr b/tests/ui/impl-trait/nested_impl_trait.stderr index 83d1347aff431..b2c66dd5f3981 100644 --- a/tests/ui/impl-trait/nested_impl_trait.stderr +++ b/tests/ui/impl-trait/nested_impl_trait.stderr @@ -1,38 +1,10 @@ -error[E0666]: nested `impl Trait` is not allowed +error[E0562]: `impl Trait` is not allowed in `impl Trait` --> $DIR/nested_impl_trait.rs:6:56 | LL | fn bad_in_ret_position(x: impl Into) -> impl Into { x } - | ----------^^^^^^^^^^- - | | | - | | nested `impl Trait` here - | outer `impl Trait` - -error[E0666]: nested `impl Trait` is not allowed - --> $DIR/nested_impl_trait.rs:10:42 - | -LL | fn bad_in_fn_syntax(x: fn() -> impl Into) {} - | ----------^^^^^^^^^^- - | | | - | | nested `impl Trait` here - | outer `impl Trait` - -error[E0666]: nested `impl Trait` is not allowed - --> $DIR/nested_impl_trait.rs:14:37 + | ^^^^^^^^^^ | -LL | fn bad_in_arg_position(_: impl Into) { } - | ----------^^^^^^^^^^- - | | | - | | nested `impl Trait` here - | outer `impl Trait` - -error[E0666]: nested `impl Trait` is not allowed - --> $DIR/nested_impl_trait.rs:19:44 - | -LL | fn bad(x: impl Into) -> impl Into { x } - | ----------^^^^^^^^^^- - | | | - | | nested `impl Trait` here - | outer `impl Trait` + = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in `fn` pointer return types --> $DIR/nested_impl_trait.rs:10:32 @@ -42,25 +14,30 @@ LL | fn bad_in_fn_syntax(x: fn() -> impl Into) {} | = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0277]: the trait bound `impl Debug: From>` is not satisfied - --> $DIR/nested_impl_trait.rs:6:46 +error[E0562]: `impl Trait` is not allowed in `impl Trait` + --> $DIR/nested_impl_trait.rs:14:37 | -LL | fn bad_in_ret_position(x: impl Into) -> impl Into { x } - | ^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `impl Debug`, which is required by `impl Into: Into` +LL | fn bad_in_arg_position(_: impl Into) { } + | ^^^^^^^^^^ | - = help: the trait `Into` is implemented for `T` - = note: required for `impl Into` to implement `Into` + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0277]: the trait bound `impl Debug: From>` is not satisfied - --> $DIR/nested_impl_trait.rs:19:34 +error[E0562]: `impl Trait` is not allowed in `impl Trait` + --> $DIR/nested_impl_trait.rs:19:44 | LL | fn bad(x: impl Into) -> impl Into { x } - | ^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `impl Debug`, which is required by `impl Into: Into` + | ^^^^^^^^^^ | - = help: the trait `Into` is implemented for `T` - = note: required for `impl Into` to implement `Into` + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + +error[E0562]: `impl Trait` is not allowed in the return type of `Fn` trait bounds + --> $DIR/nested_impl_trait.rs:28:42 + | +LL | fn allowed_in_ret_type() -> impl Fn() -> impl Into { + | ^^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0277, E0562, E0666. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/impl-trait/where-allowed.rs b/tests/ui/impl-trait/where-allowed.rs index 72ce617693e40..60fa3e5f95183 100644 --- a/tests/ui/impl-trait/where-allowed.rs +++ b/tests/ui/impl-trait/where-allowed.rs @@ -49,7 +49,7 @@ fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic!() } // Disallowed fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } //~^ ERROR `impl Trait` is not allowed in the parameters of `Fn` trait bounds -//~^^ ERROR nested `impl Trait` is not allowed +//~| ERROR `impl Trait` is not allowed in `impl Trait` // Disallowed fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } @@ -58,7 +58,7 @@ fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } // Disallowed fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } //~^ ERROR `impl Trait` is not allowed in the parameters of `Fn` trait bounds -//~| ERROR nested `impl Trait` is not allowed +//~| ERROR `impl Trait` is not allowed in `impl Trait` // Allowed fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr index bffe0447f8bb4..ec7898a1d11bf 100644 --- a/tests/ui/impl-trait/where-allowed.stderr +++ b/tests/ui/impl-trait/where-allowed.stderr @@ -1,21 +1,3 @@ -error[E0666]: nested `impl Trait` is not allowed - --> $DIR/where-allowed.rs:50:51 - | -LL | fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } - | --------^^^^^^^^^^- - | | | - | | nested `impl Trait` here - | outer `impl Trait` - -error[E0666]: nested `impl Trait` is not allowed - --> $DIR/where-allowed.rs:59:57 - | -LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } - | --------^^^^^^^^^^- - | | | - | | nested `impl Trait` here - | outer `impl Trait` - error[E0658]: `impl Trait` in associated types is unstable --> $DIR/where-allowed.rs:122:16 | @@ -126,6 +108,14 @@ LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic | = note: `impl Trait` is only allowed in arguments and return types of functions and methods +error[E0562]: `impl Trait` is not allowed in the return type of `Fn` trait bounds + --> $DIR/where-allowed.rs:64:59 + | +LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } + | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + error[E0562]: `impl Trait` is not allowed in the parameters of `Fn` trait bounds --> $DIR/where-allowed.rs:68:38 | @@ -428,7 +418,7 @@ LL | fn in_method_generic_param_default(_: T) {} = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #36887 -error: aborting due to 50 previous errors +error: aborting due to 49 previous errors -Some errors have detailed explanations: E0053, E0118, E0283, E0562, E0599, E0658, E0666. +Some errors have detailed explanations: E0053, E0118, E0283, E0562, E0599, E0658. For more information about an error, try `rustc --explain E0053`.