Skip to content

Commit 01f49f0

Browse files
author
Alexander Regueiro
committed
Use both existential-type desugaring and where-clause (predicate) desugaring depending on context.
1 parent aaa53ec commit 01f49f0

File tree

4 files changed

+173
-87
lines changed

4 files changed

+173
-87
lines changed

src/librustc/hir/lowering.rs

Lines changed: 113 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ pub struct LoweringContext<'a> {
106106
loop_scopes: Vec<NodeId>,
107107
is_in_loop_condition: bool,
108108
is_in_trait_impl: bool,
109+
is_in_dyn_type: bool,
109110

110111
/// What to do when we encounter either an "anonymous lifetime
111112
/// reference". The term "anonymous" is meant to encompass both
@@ -195,20 +196,17 @@ enum ImplTraitContext<'a> {
195196
/// (e.g., for consts and statics).
196197
Existential(Option<DefId> /* fn def-ID */),
197198

198-
/// Treat `impl Trait` as a bound on the associated type applied to the trait.
199-
/// Example: `trait Foo { type Bar: Iterator<Item = impl Debug>; }` is conceptually
200-
/// equivalent to `trait Foo where <Self::Bar as Iterator>::Item: Debug
201-
/// { type Bar: Iterator; }`.
202-
AssociatedTy,
203-
204199
/// `impl Trait` is not accepted in this position.
205200
Disallowed(ImplTraitPosition),
206201
}
207202

208203
/// Position in which `impl Trait` is disallowed. Used for error reporting.
209204
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
210205
enum ImplTraitPosition {
206+
/// Disallowed in `let` / `const` / `static` bindings.
211207
Binding,
208+
209+
/// All other posiitons.
212210
Other,
213211
}
214212

@@ -223,7 +221,6 @@ impl<'a> ImplTraitContext<'a> {
223221
match self {
224222
Universal(params) => Universal(params),
225223
Existential(fn_def_id) => Existential(*fn_def_id),
226-
AssociatedTy => AssociatedTy,
227224
Disallowed(pos) => Disallowed(*pos),
228225
}
229226
}
@@ -256,6 +253,8 @@ pub fn lower_crate(
256253
catch_scopes: Vec::new(),
257254
loop_scopes: Vec::new(),
258255
is_in_loop_condition: false,
256+
is_in_trait_impl: false,
257+
is_in_dyn_type: false,
259258
anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
260259
type_def_lifetime_params: Default::default(),
261260
current_module: CRATE_NODE_ID,
@@ -265,7 +264,6 @@ pub fn lower_crate(
265264
is_generator: false,
266265
is_async_body: false,
267266
current_item: None,
268-
is_in_trait_impl: false,
269267
lifetimes_to_define: Vec::new(),
270268
is_collecting_in_band_lifetimes: false,
271269
in_scope_lifetimes: Vec::new(),
@@ -1230,6 +1228,20 @@ impl<'a> LoweringContext<'a> {
12301228
result
12311229
}
12321230

1231+
fn with_dyn_type_scope<T, F>(&mut self, in_scope: bool, f: F) -> T
1232+
where
1233+
F: FnOnce(&mut LoweringContext<'_>) -> T,
1234+
{
1235+
let was_in_dyn_type = self.is_in_dyn_type;
1236+
self.is_in_dyn_type = in_scope;
1237+
1238+
let result = f(self);
1239+
1240+
self.is_in_dyn_type = was_in_dyn_type;
1241+
1242+
result
1243+
}
1244+
12331245
fn with_new_scopes<T, F>(&mut self, f: F) -> T
12341246
where
12351247
F: FnOnce(&mut LoweringContext<'_>) -> T,
@@ -1353,24 +1365,58 @@ impl<'a> LoweringContext<'a> {
13531365
c: &AssocTyConstraint,
13541366
itctx: ImplTraitContext<'_>)
13551367
-> hir::TypeBinding {
1368+
debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", c, itctx);
1369+
13561370
let ty = match c.kind {
13571371
AssocTyConstraintKind::Equality { ref ty } => self.lower_ty(ty, itctx),
13581372
AssocTyConstraintKind::Bound { ref bounds } => {
1359-
// Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`.
1360-
let impl_ty_node_id = self.sess.next_node_id();
1361-
let parent_def_index = self.current_hir_id_owner.last().unwrap().0;
1362-
self.resolver.definitions().create_def_with_parent(
1363-
parent_def_index,
1364-
impl_ty_node_id,
1365-
DefPathData::Misc,
1366-
DefIndexAddressSpace::High,
1367-
Mark::root(),
1368-
DUMMY_SP);
1369-
self.lower_ty(&Ty {
1370-
id: self.sess.next_node_id(),
1371-
node: TyKind::ImplTrait(impl_ty_node_id, bounds.clone()),
1372-
span: DUMMY_SP,
1373-
}, itctx)
1373+
let (existential_desugaring, itctx) = match itctx {
1374+
ImplTraitContext::Existential(_) => (true, itctx),
1375+
ImplTraitContext::Universal(_) if self.is_in_dyn_type => (true, itctx),
1376+
// FIXME: this is only needed until `impl Trait` is allowed in type aliases.
1377+
ImplTraitContext::Disallowed(_) if self.is_in_dyn_type =>
1378+
(true, ImplTraitContext::Existential(None)),
1379+
_ => (false, itctx),
1380+
};
1381+
1382+
if existential_desugaring {
1383+
// Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`.
1384+
1385+
let impl_ty_node_id = self.sess.next_node_id();
1386+
let parent_def_index = self.current_hir_id_owner.last().unwrap().0;
1387+
self.resolver.definitions().create_def_with_parent(
1388+
parent_def_index,
1389+
impl_ty_node_id,
1390+
DefPathData::Misc,
1391+
DefIndexAddressSpace::High,
1392+
Mark::root(),
1393+
DUMMY_SP
1394+
);
1395+
1396+
self.with_dyn_type_scope(false, |this| {
1397+
this.lower_ty(
1398+
&Ty {
1399+
id: this.sess.next_node_id(),
1400+
node: TyKind::ImplTrait(impl_ty_node_id, bounds.clone()),
1401+
span: DUMMY_SP,
1402+
},
1403+
itctx,
1404+
)
1405+
})
1406+
} else {
1407+
// Desugar `AssocTy: Bounds` into `AssocTy = ∃ T (T: Bounds)`, where the
1408+
// "false existential" later desugars into a trait predicate.
1409+
1410+
let bounds = self.lower_param_bounds(bounds, itctx);
1411+
1412+
let id = self.sess.next_node_id();
1413+
let LoweredNodeId { node_id: _, hir_id } = self.lower_node_id(id);
1414+
P(hir::Ty {
1415+
hir_id,
1416+
node: hir::TyKind::AssocTyExistential(bounds),
1417+
span: DUMMY_SP,
1418+
})
1419+
}
13741420
}
13751421
};
13761422

@@ -1477,23 +1523,26 @@ impl<'a> LoweringContext<'a> {
14771523
}
14781524
TyKind::TraitObject(ref bounds, kind) => {
14791525
let mut lifetime_bound = None;
1480-
let bounds = bounds
1481-
.iter()
1482-
.filter_map(|bound| match *bound {
1483-
GenericBound::Trait(ref ty, TraitBoundModifier::None) => {
1484-
Some(self.lower_poly_trait_ref(ty, itctx.reborrow()))
1485-
}
1486-
GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
1487-
GenericBound::Outlives(ref lifetime) => {
1488-
if lifetime_bound.is_none() {
1489-
lifetime_bound = Some(self.lower_lifetime(lifetime));
1526+
let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
1527+
let bounds = bounds
1528+
.iter()
1529+
.filter_map(|bound| match *bound {
1530+
GenericBound::Trait(ref ty, TraitBoundModifier::None) => {
1531+
Some(this.lower_poly_trait_ref(ty, itctx.reborrow()))
14901532
}
1491-
None
1492-
}
1493-
})
1494-
.collect();
1495-
let lifetime_bound =
1496-
lifetime_bound.unwrap_or_else(|| self.elided_dyn_bound(t.span));
1533+
GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
1534+
GenericBound::Outlives(ref lifetime) => {
1535+
if lifetime_bound.is_none() {
1536+
lifetime_bound = Some(this.lower_lifetime(lifetime));
1537+
}
1538+
None
1539+
}
1540+
})
1541+
.collect();
1542+
let lifetime_bound =
1543+
lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span));
1544+
(bounds, lifetime_bound)
1545+
});
14971546
if kind != TraitObjectSyntax::Dyn {
14981547
self.maybe_lint_bare_trait(t.span, t.id, false);
14991548
}
@@ -1544,16 +1593,6 @@ impl<'a> LoweringContext<'a> {
15441593
}),
15451594
))
15461595
}
1547-
ImplTraitContext::AssociatedTy => {
1548-
let hir_bounds = self.lower_param_bounds(
1549-
bounds,
1550-
ImplTraitContext::AssociatedTy,
1551-
);
1552-
1553-
hir::TyKind::AssocTyExistential(
1554-
hir_bounds,
1555-
)
1556-
}
15571596
ImplTraitContext::Disallowed(pos) => {
15581597
let allowed_in = if self.sess.features_untracked()
15591598
.impl_trait_in_bindings {
@@ -2407,7 +2446,8 @@ impl<'a> LoweringContext<'a> {
24072446
FunctionRetTy::Ty(ref ty) => match in_band_ty_params {
24082447
Some((def_id, _)) if impl_trait_return_allow => {
24092448
hir::Return(self.lower_ty(ty,
2410-
ImplTraitContext::Existential(Some(def_id))))
2449+
ImplTraitContext::Existential(Some(def_id))
2450+
))
24112451
}
24122452
_ => {
24132453
hir::Return(self.lower_ty(ty, ImplTraitContext::disallowed()))
@@ -2770,7 +2810,7 @@ impl<'a> LoweringContext<'a> {
27702810

27712811
let kind = hir::GenericParamKind::Type {
27722812
default: default.as_ref().map(|x| {
2773-
self.lower_ty(x, ImplTraitContext::disallowed())
2813+
self.lower_ty(x, ImplTraitContext::Existential(None))
27742814
}),
27752815
synthetic: param.attrs.iter()
27762816
.filter(|attr| attr.check_name(sym::rustc_synthetic))
@@ -3275,39 +3315,43 @@ impl<'a> LoweringContext<'a> {
32753315
ItemKind::ForeignMod(ref nm) => hir::ItemKind::ForeignMod(self.lower_foreign_mod(nm)),
32763316
ItemKind::GlobalAsm(ref ga) => hir::ItemKind::GlobalAsm(self.lower_global_asm(ga)),
32773317
ItemKind::Ty(ref t, ref generics) => hir::ItemKind::Ty(
3278-
self.lower_ty(t, ImplTraitContext::AssociatedTy),
3279-
self.lower_generics(generics, ImplTraitContext::AssociatedTy),
3318+
self.lower_ty(t, ImplTraitContext::disallowed()),
3319+
self.lower_generics(generics, ImplTraitContext::disallowed()),
32803320
),
32813321
ItemKind::Existential(ref b, ref generics) => hir::ItemKind::Existential(
32823322
hir::ExistTy {
3283-
generics: self.lower_generics(generics, ImplTraitContext::AssociatedTy),
3284-
bounds: self.lower_param_bounds(b, ImplTraitContext::AssociatedTy),
3323+
generics: self.lower_generics(generics,
3324+
ImplTraitContext::Existential(None)),
3325+
bounds: self.lower_param_bounds(b,
3326+
ImplTraitContext::Existential(None)),
32853327
impl_trait_fn: None,
32863328
origin: hir::ExistTyOrigin::ExistentialType,
32873329
},
32883330
),
3289-
ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum(
3290-
hir::EnumDef {
3291-
variants: enum_definition
3292-
.variants
3293-
.iter()
3294-
.map(|x| self.lower_variant(x))
3295-
.collect(),
3296-
},
3297-
self.lower_generics(generics, ImplTraitContext::AssociatedTy),
3298-
),
3331+
ItemKind::Enum(ref enum_definition, ref generics) => {
3332+
hir::ItemKind::Enum(
3333+
hir::EnumDef {
3334+
variants: enum_definition
3335+
.variants
3336+
.iter()
3337+
.map(|x| self.lower_variant(x))
3338+
.collect(),
3339+
},
3340+
self.lower_generics(generics, ImplTraitContext::disallowed()),
3341+
)
3342+
},
32993343
ItemKind::Struct(ref struct_def, ref generics) => {
33003344
let struct_def = self.lower_variant_data(struct_def);
33013345
hir::ItemKind::Struct(
33023346
struct_def,
3303-
self.lower_generics(generics, ImplTraitContext::AssociatedTy),
3347+
self.lower_generics(generics, ImplTraitContext::disallowed()),
33043348
)
33053349
}
33063350
ItemKind::Union(ref vdata, ref generics) => {
33073351
let vdata = self.lower_variant_data(vdata);
33083352
hir::ItemKind::Union(
33093353
vdata,
3310-
self.lower_generics(generics, ImplTraitContext::AssociatedTy),
3354+
self.lower_generics(generics, ImplTraitContext::disallowed()),
33113355
)
33123356
}
33133357
ItemKind::Impl(
@@ -3675,9 +3719,9 @@ impl<'a> LoweringContext<'a> {
36753719
(generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Provided(body_id)))
36763720
}
36773721
TraitItemKind::Type(ref bounds, ref default) => {
3678-
let generics = self.lower_generics(&i.generics, ImplTraitContext::AssociatedTy);
3722+
let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed());
36793723
let node = hir::TraitItemKind::Type(
3680-
self.lower_param_bounds(bounds, ImplTraitContext::AssociatedTy),
3724+
self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
36813725
default
36823726
.as_ref()
36833727
.map(|x| self.lower_ty(x, ImplTraitContext::disallowed())),

src/librustc_passes/ast_validation.rs

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ struct AstValidator<'a> {
6363
/// or `Foo::Bar<impl Trait>`
6464
is_impl_trait_banned: bool,
6565

66+
/// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
67+
/// certain positions.
68+
is_assoc_ty_bound_banned: bool,
69+
6670
/// rust-lang/rust#57979: the ban of nested `impl Trait` was buggy
6771
/// until PRs #57730 and #57981 landed: it would jump directly to
6872
/// walk_ty rather than visit_ty (or skip recurring entirely for
@@ -87,19 +91,34 @@ impl<'a> AstValidator<'a> {
8791
self.is_impl_trait_banned = old;
8892
}
8993

94+
fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
95+
let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
96+
f(self);
97+
self.is_assoc_ty_bound_banned = old;
98+
}
99+
90100
fn with_impl_trait(&mut self, outer: Option<OuterImplTrait>, f: impl FnOnce(&mut Self)) {
91101
let old = mem::replace(&mut self.outer_impl_trait, outer);
92102
f(self);
93103
self.outer_impl_trait = old;
94104
}
95105

96106
fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
97-
if let AssocTyConstraintKind::Equality { ref ty } = constraint.kind {
98-
// rust-lang/rust#57979: bug in old `visit_generic_args` called
99-
// `walk_ty` rather than `visit_ty`, skipping outer `impl Trait`
100-
// if it happened to occur at `ty`.
101-
if let TyKind::ImplTrait(..) = ty.node {
102-
self.warning_period_57979_didnt_record_next_impl_trait = true;
107+
match constraint.kind {
108+
AssocTyConstraintKind::Equality { ref ty } => {
109+
// rust-lang/rust#57979: bug in old `visit_generic_args` called
110+
// `walk_ty` rather than `visit_ty`, skipping outer `impl Trait`
111+
// if it happened to occur at `ty`.
112+
if let TyKind::ImplTrait(..) = ty.node {
113+
self.warning_period_57979_didnt_record_next_impl_trait = true;
114+
}
115+
}
116+
AssocTyConstraintKind::Bound { .. } => {
117+
if self.is_assoc_ty_bound_banned {
118+
self.err_handler().span_err(constraint.span,
119+
"associated type bounds are not allowed within structs, enums, or unions"
120+
);
121+
}
103122
}
104123
}
105124
self.visit_assoc_ty_constraint(constraint);
@@ -726,7 +745,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
726745
// Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
727746
// are allowed to contain nested `impl Trait`.
728747
self.with_impl_trait(None, |this| {
729-
walk_list!(this, visit_assoc_ty_constraint_from_generic_args, &data.constraints);
748+
walk_list!(this, visit_assoc_ty_constraint_from_generic_args,
749+
&data.constraints);
730750
});
731751
}
732752
GenericArgs::Parenthesized(ref data) => {
@@ -819,6 +839,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
819839
visit::walk_poly_trait_ref(self, t, m);
820840
}
821841

842+
fn visit_variant_data(&mut self, s: &'a VariantData, _: Ident,
843+
_: &'a Generics, _: NodeId, _: Span) {
844+
self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
845+
}
846+
847+
fn visit_enum_def(&mut self, enum_definition: &'a EnumDef,
848+
generics: &'a Generics, item_id: NodeId, _: Span) {
849+
self.with_banned_assoc_ty_bound(
850+
|this| visit::walk_enum_def(this, enum_definition, generics, item_id))
851+
}
852+
822853
fn visit_mac(&mut self, mac: &Spanned<Mac_>) {
823854
// when a new macro kind is added but the author forgets to set it up for expansion
824855
// because that's the only part that won't cause a compiler error
@@ -842,6 +873,7 @@ pub fn check_crate(session: &Session, krate: &Crate) -> (bool, bool) {
842873
has_global_allocator: false,
843874
outer_impl_trait: None,
844875
is_impl_trait_banned: false,
876+
is_assoc_ty_bound_banned: false,
845877
warning_period_57979_didnt_record_next_impl_trait: false,
846878
warning_period_57979_impl_trait_in_proj: false,
847879
};

0 commit comments

Comments
 (0)