Skip to content

Commit ef27e43

Browse files
authored
Rollup merge of #108063 - compiler-errors:associated-type-bounds-in-bad-position, r=cjgillot
Ban associated type bounds in bad positions We should not try to lower associated type bounds into TAITs in positions where `impl Trait` is not allowed (except for in `where` clauses, like `where T: Trait<Assoc: Bound>`). This is achieved by using the same `rustc_ast_lowering` machinery as impl-trait does to characterize positions as universal/existential/disallowed. Fixes #106077 Split out the first commit into #108066, since it's not really related.
2 parents 0978711 + b14eb0c commit ef27e43

33 files changed

+221
-276
lines changed

compiler/rustc_ast_lowering/locales/en-US.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ ast_lowering_remove_parentheses = remove these parentheses
1919
ast_lowering_misplaced_impl_trait =
2020
`impl Trait` only allowed in function and inherent method return types, not in {$position}
2121
22+
ast_lowering_misplaced_assoc_ty_binding =
23+
associated type bounds are only allowed in where clauses and function signatures, not in {$position}
24+
2225
ast_lowering_rustc_box_attribute_error =
2326
#[rustc_box] requires precisely one argument and no other attributes are allowed
2427

compiler/rustc_ast_lowering/src/errors.rs

+8
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,14 @@ pub struct MisplacedImplTrait<'a> {
7979
pub position: DiagnosticArgFromDisplay<'a>,
8080
}
8181

82+
#[derive(Diagnostic)]
83+
#[diag(ast_lowering_misplaced_assoc_ty_binding)]
84+
pub struct MisplacedAssocTyBinding<'a> {
85+
#[primary_span]
86+
pub span: Span,
87+
pub position: DiagnosticArgFromDisplay<'a>,
88+
}
89+
8290
#[derive(Diagnostic, Clone, Copy)]
8391
#[diag(ast_lowering_rustc_box_attribute_error)]
8492
pub struct RustcBoxAttributeError {

compiler/rustc_ast_lowering/src/lib.rs

+73-62
Original file line numberDiff line numberDiff line change
@@ -288,31 +288,31 @@ enum ImplTraitPosition {
288288
impl std::fmt::Display for ImplTraitPosition {
289289
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
290290
let name = match self {
291-
ImplTraitPosition::Path => "path",
292-
ImplTraitPosition::Variable => "variable binding",
293-
ImplTraitPosition::Trait => "trait",
294-
ImplTraitPosition::AsyncBlock => "async block",
295-
ImplTraitPosition::Bound => "bound",
296-
ImplTraitPosition::Generic => "generic",
297-
ImplTraitPosition::ExternFnParam => "`extern fn` param",
298-
ImplTraitPosition::ClosureParam => "closure param",
299-
ImplTraitPosition::PointerParam => "`fn` pointer param",
300-
ImplTraitPosition::FnTraitParam => "`Fn` trait param",
301-
ImplTraitPosition::TraitParam => "trait method param",
302-
ImplTraitPosition::ImplParam => "`impl` method param",
303-
ImplTraitPosition::ExternFnReturn => "`extern fn` return",
304-
ImplTraitPosition::ClosureReturn => "closure return",
305-
ImplTraitPosition::PointerReturn => "`fn` pointer return",
306-
ImplTraitPosition::FnTraitReturn => "`Fn` trait return",
307-
ImplTraitPosition::TraitReturn => "trait method return",
308-
ImplTraitPosition::ImplReturn => "`impl` method return",
309-
ImplTraitPosition::GenericDefault => "generic parameter default",
310-
ImplTraitPosition::ConstTy => "const type",
311-
ImplTraitPosition::StaticTy => "static type",
312-
ImplTraitPosition::AssocTy => "associated type",
313-
ImplTraitPosition::FieldTy => "field type",
314-
ImplTraitPosition::Cast => "cast type",
315-
ImplTraitPosition::ImplSelf => "impl header",
291+
ImplTraitPosition::Path => "paths",
292+
ImplTraitPosition::Variable => "variable bindings",
293+
ImplTraitPosition::Trait => "traits",
294+
ImplTraitPosition::AsyncBlock => "async blocks",
295+
ImplTraitPosition::Bound => "bounds",
296+
ImplTraitPosition::Generic => "generics",
297+
ImplTraitPosition::ExternFnParam => "`extern fn` params",
298+
ImplTraitPosition::ClosureParam => "closure params",
299+
ImplTraitPosition::PointerParam => "`fn` pointer params",
300+
ImplTraitPosition::FnTraitParam => "`Fn` trait params",
301+
ImplTraitPosition::TraitParam => "trait method params",
302+
ImplTraitPosition::ImplParam => "`impl` method params",
303+
ImplTraitPosition::ExternFnReturn => "`extern fn` return types",
304+
ImplTraitPosition::ClosureReturn => "closure return types",
305+
ImplTraitPosition::PointerReturn => "`fn` pointer return types",
306+
ImplTraitPosition::FnTraitReturn => "`Fn` trait return types",
307+
ImplTraitPosition::TraitReturn => "trait method return types",
308+
ImplTraitPosition::ImplReturn => "`impl` method return types",
309+
ImplTraitPosition::GenericDefault => "generic parameter defaults",
310+
ImplTraitPosition::ConstTy => "const types",
311+
ImplTraitPosition::StaticTy => "static types",
312+
ImplTraitPosition::AssocTy => "associated types",
313+
ImplTraitPosition::FieldTy => "field types",
314+
ImplTraitPosition::Cast => "cast types",
315+
ImplTraitPosition::ImplSelf => "impl headers",
316316
};
317317

318318
write!(f, "{name}")
@@ -1002,8 +1002,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
10021002
} else {
10031003
self.arena.alloc(hir::GenericArgs::none())
10041004
};
1005-
let itctx_tait = &ImplTraitContext::TypeAliasesOpaqueTy;
1006-
10071005
let kind = match &constraint.kind {
10081006
AssocConstraintKind::Equality { term } => {
10091007
let term = match term {
@@ -1013,8 +1011,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
10131011
hir::TypeBindingKind::Equality { term }
10141012
}
10151013
AssocConstraintKind::Bound { bounds } => {
1014+
enum DesugarKind<'a> {
1015+
ImplTrait,
1016+
Error(&'a ImplTraitPosition),
1017+
Bound,
1018+
}
1019+
10161020
// Piggy-back on the `impl Trait` context to figure out the correct behavior.
1017-
let (desugar_to_impl_trait, itctx) = match itctx {
1021+
let desugar_kind = match itctx {
10181022
// We are in the return position:
10191023
//
10201024
// fn foo() -> impl Iterator<Item: Debug>
@@ -1023,7 +1027,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
10231027
//
10241028
// fn foo() -> impl Iterator<Item = impl Debug>
10251029
ImplTraitContext::ReturnPositionOpaqueTy { .. }
1026-
| ImplTraitContext::TypeAliasesOpaqueTy { .. } => (true, itctx),
1030+
| ImplTraitContext::TypeAliasesOpaqueTy { .. } => DesugarKind::ImplTrait,
10271031

10281032
// We are in the argument position, but within a dyn type:
10291033
//
@@ -1032,15 +1036,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
10321036
// so desugar to
10331037
//
10341038
// fn foo(x: dyn Iterator<Item = impl Debug>)
1035-
ImplTraitContext::Universal if self.is_in_dyn_type => (true, itctx),
1039+
ImplTraitContext::Universal if self.is_in_dyn_type => DesugarKind::ImplTrait,
10361040

1037-
// In `type Foo = dyn Iterator<Item: Debug>` we desugar to
1038-
// `type Foo = dyn Iterator<Item = impl Debug>` but we have to override the
1039-
// "impl trait context" to permit `impl Debug` in this position (it desugars
1040-
// then to an opaque type).
1041-
//
1042-
// FIXME: this is only needed until `impl Trait` is allowed in type aliases.
1043-
ImplTraitContext::Disallowed(_) if self.is_in_dyn_type => (true, itctx_tait),
1041+
ImplTraitContext::Disallowed(position) if self.is_in_dyn_type => {
1042+
DesugarKind::Error(position)
1043+
}
10441044

10451045
// We are in the parameter position, but not within a dyn type:
10461046
//
@@ -1049,35 +1049,46 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
10491049
// so we leave it as is and this gets expanded in astconv to a bound like
10501050
// `<T as Iterator>::Item: Debug` where `T` is the type parameter for the
10511051
// `impl Iterator`.
1052-
_ => (false, itctx),
1052+
_ => DesugarKind::Bound,
10531053
};
10541054

1055-
if desugar_to_impl_trait {
1056-
// Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`. We do this by
1057-
// constructing the HIR for `impl bounds...` and then lowering that.
1058-
1059-
let impl_trait_node_id = self.next_node_id();
1060-
1061-
self.with_dyn_type_scope(false, |this| {
1062-
let node_id = this.next_node_id();
1063-
let ty = this.lower_ty(
1064-
&Ty {
1065-
id: node_id,
1066-
kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
1067-
span: this.lower_span(constraint.span),
1068-
tokens: None,
1069-
},
1070-
itctx,
1071-
);
1055+
match desugar_kind {
1056+
DesugarKind::ImplTrait => {
1057+
// Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`. We do this by
1058+
// constructing the HIR for `impl bounds...` and then lowering that.
10721059

1073-
hir::TypeBindingKind::Equality { term: ty.into() }
1074-
})
1075-
} else {
1076-
// Desugar `AssocTy: Bounds` into a type binding where the
1077-
// later desugars into a trait predicate.
1078-
let bounds = self.lower_param_bounds(bounds, itctx);
1060+
let impl_trait_node_id = self.next_node_id();
10791061

1080-
hir::TypeBindingKind::Constraint { bounds }
1062+
self.with_dyn_type_scope(false, |this| {
1063+
let node_id = this.next_node_id();
1064+
let ty = this.lower_ty(
1065+
&Ty {
1066+
id: node_id,
1067+
kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
1068+
span: this.lower_span(constraint.span),
1069+
tokens: None,
1070+
},
1071+
itctx,
1072+
);
1073+
1074+
hir::TypeBindingKind::Equality { term: ty.into() }
1075+
})
1076+
}
1077+
DesugarKind::Bound => {
1078+
// Desugar `AssocTy: Bounds` into a type binding where the
1079+
// later desugars into a trait predicate.
1080+
let bounds = self.lower_param_bounds(bounds, itctx);
1081+
1082+
hir::TypeBindingKind::Constraint { bounds }
1083+
}
1084+
DesugarKind::Error(position) => {
1085+
self.tcx.sess.emit_err(errors::MisplacedAssocTyBinding {
1086+
span: constraint.span,
1087+
position: DiagnosticArgFromDisplay(position),
1088+
});
1089+
let err_ty = &*self.arena.alloc(self.ty(constraint.span, hir::TyKind::Err));
1090+
hir::TypeBindingKind::Equality { term: err_ty.into() }
1091+
}
10811092
}
10821093
}
10831094
};

compiler/rustc_ast_passes/locales/en-US.ftl

-3
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ ast_passes_forbidden_let_stable =
1111
ast_passes_deprecated_where_clause_location =
1212
where clause not allowed here
1313
14-
ast_passes_forbidden_assoc_constraint =
15-
associated type bounds are not allowed within structs, enums, or unions
16-
1714
ast_passes_keyword_lifetime =
1815
lifetimes cannot use keyword names
1916

compiler/rustc_ast_passes/src/ast_validation.rs

+1-32
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,6 @@ struct AstValidator<'a> {
7171
/// or `Foo::Bar<impl Trait>`
7272
is_impl_trait_banned: bool,
7373

74-
/// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
75-
/// certain positions.
76-
is_assoc_ty_bound_banned: bool,
77-
7874
/// See [ForbiddenLetReason]
7975
forbidden_let_reason: Option<ForbiddenLetReason>,
8076

@@ -180,30 +176,12 @@ impl<'a> AstValidator<'a> {
180176
}
181177
}
182178

183-
fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
184-
let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
185-
f(self);
186-
self.is_assoc_ty_bound_banned = old;
187-
}
188-
189179
fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
190180
let old = mem::replace(&mut self.outer_impl_trait, outer);
191181
f(self);
192182
self.outer_impl_trait = old;
193183
}
194184

195-
fn visit_assoc_constraint_from_generic_args(&mut self, constraint: &'a AssocConstraint) {
196-
match constraint.kind {
197-
AssocConstraintKind::Equality { .. } => {}
198-
AssocConstraintKind::Bound { .. } => {
199-
if self.is_assoc_ty_bound_banned {
200-
self.session.emit_err(ForbiddenAssocConstraint { span: constraint.span });
201-
}
202-
}
203-
}
204-
self.visit_assoc_constraint(constraint);
205-
}
206-
207185
// Mirrors `visit::walk_ty`, but tracks relevant state.
208186
fn walk_ty(&mut self, t: &'a Ty) {
209187
match &t.kind {
@@ -1248,7 +1226,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
12481226
// are allowed to contain nested `impl Trait`.
12491227
AngleBracketedArg::Constraint(constraint) => {
12501228
self.with_impl_trait(None, |this| {
1251-
this.visit_assoc_constraint_from_generic_args(constraint);
1229+
this.visit_assoc_constraint(constraint);
12521230
});
12531231
}
12541232
}
@@ -1373,14 +1351,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
13731351
visit::walk_param_bound(self, bound)
13741352
}
13751353

1376-
fn visit_variant_data(&mut self, s: &'a VariantData) {
1377-
self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1378-
}
1379-
1380-
fn visit_enum_def(&mut self, enum_definition: &'a EnumDef) {
1381-
self.with_banned_assoc_ty_bound(|this| visit::walk_enum_def(this, enum_definition))
1382-
}
1383-
13841354
fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
13851355
// Only associated `fn`s can have `self` parameters.
13861356
let self_semantic = match fk.ctxt() {
@@ -1709,7 +1679,6 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) ->
17091679
outer_impl_trait: None,
17101680
disallow_tilde_const: None,
17111681
is_impl_trait_banned: false,
1712-
is_assoc_ty_bound_banned: false,
17131682
forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
17141683
lint_buffer: lints,
17151684
};

compiler/rustc_ast_passes/src/errors.rs

-7
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,6 @@ pub struct ForbiddenLetStable {
2323
pub span: Span,
2424
}
2525

26-
#[derive(Diagnostic)]
27-
#[diag(ast_passes_forbidden_assoc_constraint)]
28-
pub struct ForbiddenAssocConstraint {
29-
#[primary_span]
30-
pub span: Span,
31-
}
32-
3326
#[derive(Diagnostic)]
3427
#[diag(ast_passes_keyword_lifetime)]
3528
pub struct KeywordLifetime {

tests/ui/associated-consts/issue-105330.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ LL | fn main<A: TraitWAssocConst<A=32>>() {
3333
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
3434
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
3535

36-
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in impl header
36+
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in impl headers
3737
--> $DIR/issue-105330.rs:6:27
3838
|
3939
LL | impl TraitWAssocConst for impl Demo {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#![feature(associated_type_bounds)]
2+
3+
trait B {
4+
type AssocType;
5+
}
6+
7+
fn f()
8+
where
9+
dyn for<'j> B<AssocType: 'j>:,
10+
//~^ ERROR associated type bounds are only allowed in where clauses and function signatures
11+
{
12+
}
13+
14+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: associated type bounds are only allowed in where clauses and function signatures, not in bounds
2+
--> $DIR/bad-universal-in-dyn-in-where-clause.rs:9:19
3+
|
4+
LL | dyn for<'j> B<AssocType: 'j>:,
5+
| ^^^^^^^^^^^^^
6+
7+
error: aborting due to previous error
8+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#![feature(associated_type_bounds)]
2+
3+
trait Trait {
4+
type Item;
5+
}
6+
7+
trait Trait2 {}
8+
9+
// It's not possible to insert a universal `impl Trait` here!
10+
impl dyn Trait<Item: Trait2> {}
11+
//~^ ERROR associated type bounds are only allowed in where clauses and function signatures
12+
13+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: associated type bounds are only allowed in where clauses and function signatures, not in impl headers
2+
--> $DIR/bad-universal-in-impl-sig.rs:10:16
3+
|
4+
LL | impl dyn Trait<Item: Trait2> {}
5+
| ^^^^^^^^^^^^
6+
7+
error: aborting due to previous error
8+

tests/ui/associated-type-bounds/inside-adt.rs

+9-13
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,24 @@
33
use std::mem::ManuallyDrop;
44

55
struct S1 { f: dyn Iterator<Item: Copy> }
6-
//~^ ERROR associated type bounds are not allowed within structs, enums, or unions
6+
//~^ ERROR associated type bounds are only allowed in where clauses and function signatures
77
struct S2 { f: Box<dyn Iterator<Item: Copy>> }
8-
//~^ ERROR associated type bounds are not allowed within structs, enums, or unions
8+
//~^ ERROR associated type bounds are only allowed in where clauses and function signatures
99
struct S3 { f: dyn Iterator<Item: 'static> }
10-
//~^ ERROR associated type bounds are not allowed within structs, enums, or unions
10+
//~^ ERROR associated type bounds are only allowed in where clauses and function signatures
1111

1212
enum E1 { V(dyn Iterator<Item: Copy>) }
13-
//~^ ERROR associated type bounds are not allowed within structs, enums, or unions
14-
//~| ERROR the size for values of type `(dyn Iterator<Item = impl Copy> + 'static)`
13+
//~^ ERROR associated type bounds are only allowed in where clauses and function signatures
1514
enum E2 { V(Box<dyn Iterator<Item: Copy>>) }
16-
//~^ ERROR associated type bounds are not allowed within structs, enums, or unions
15+
//~^ ERROR associated type bounds are only allowed in where clauses and function signatures
1716
enum E3 { V(dyn Iterator<Item: 'static>) }
18-
//~^ ERROR associated type bounds are not allowed within structs, enums, or unions
19-
//~| ERROR the size for values of type `(dyn Iterator<Item = impl Sized + 'static> + 'static)`
17+
//~^ ERROR associated type bounds are only allowed in where clauses and function signatures
2018

2119
union U1 { f: ManuallyDrop<dyn Iterator<Item: Copy>> }
22-
//~^ ERROR associated type bounds are not allowed within structs, enums, or unions
23-
//~| ERROR the size for values of type `(dyn Iterator<Item = impl Copy> + 'static)`
20+
//~^ ERROR associated type bounds are only allowed in where clauses and function signatures
2421
union U2 { f: ManuallyDrop<Box<dyn Iterator<Item: Copy>>> }
25-
//~^ ERROR associated type bounds are not allowed within structs, enums, or unions
22+
//~^ ERROR associated type bounds are only allowed in where clauses and function signatures
2623
union U3 { f: ManuallyDrop<dyn Iterator<Item: 'static>> }
27-
//~^ ERROR associated type bounds are not allowed within structs, enums, or unions
28-
//~| ERROR the size for values of type `(dyn Iterator<Item = impl Sized + 'static> + 'static)`
24+
//~^ ERROR associated type bounds are only allowed in where clauses and function signatures
2925

3026
fn main() {}

0 commit comments

Comments
 (0)