loop_scopes: Vec<NodeId>,
is_in_loop_condition: bool,
is_in_trait_impl: bool,
+ is_in_dyn_type: bool,
/// What to do when we encounter either an "anonymous lifetime
/// reference". The term "anonymous" is meant to encompass both
/// (e.g., for consts and statics).
Existential(Option<DefId> /* fn def-ID */),
- /// Treat `impl Trait` as a bound on the associated type applied to the trait.
- /// Example: `trait Foo { type Bar: Iterator<Item = impl Debug>; }` is conceptually
- /// equivalent to `trait Foo where <Self::Bar as Iterator>::Item: Debug
- /// { type Bar: Iterator; }`.
- AssociatedTy,
-
/// `impl Trait` is not accepted in this position.
Disallowed(ImplTraitPosition),
}
/// Position in which `impl Trait` is disallowed. Used for error reporting.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum ImplTraitPosition {
+ /// Disallowed in `let` / `const` / `static` bindings.
Binding,
+
+ /// All other posiitons.
Other,
}
match self {
Universal(params) => Universal(params),
Existential(fn_def_id) => Existential(*fn_def_id),
- AssociatedTy => AssociatedTy,
Disallowed(pos) => Disallowed(*pos),
}
}
catch_scopes: Vec::new(),
loop_scopes: Vec::new(),
is_in_loop_condition: false,
+ is_in_trait_impl: false,
+ is_in_dyn_type: false,
anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
type_def_lifetime_params: Default::default(),
current_module: CRATE_NODE_ID,
is_generator: false,
is_async_body: false,
current_item: None,
- is_in_trait_impl: false,
lifetimes_to_define: Vec::new(),
is_collecting_in_band_lifetimes: false,
in_scope_lifetimes: Vec::new(),
result
}
+ fn with_dyn_type_scope<T, F>(&mut self, in_scope: bool, f: F) -> T
+ where
+ F: FnOnce(&mut LoweringContext<'_>) -> T,
+ {
+ let was_in_dyn_type = self.is_in_dyn_type;
+ self.is_in_dyn_type = in_scope;
+
+ let result = f(self);
+
+ self.is_in_dyn_type = was_in_dyn_type;
+
+ result
+ }
+
fn with_new_scopes<T, F>(&mut self, f: F) -> T
where
F: FnOnce(&mut LoweringContext<'_>) -> T,
c: &AssocTyConstraint,
itctx: ImplTraitContext<'_>)
-> hir::TypeBinding {
+ debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", c, itctx);
+
let ty = match c.kind {
AssocTyConstraintKind::Equality { ref ty } => self.lower_ty(ty, itctx),
AssocTyConstraintKind::Bound { ref bounds } => {
- // Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`.
- let impl_ty_node_id = self.sess.next_node_id();
- let parent_def_index = self.current_hir_id_owner.last().unwrap().0;
- self.resolver.definitions().create_def_with_parent(
- parent_def_index,
- impl_ty_node_id,
- DefPathData::Misc,
- DefIndexAddressSpace::High,
- Mark::root(),
- DUMMY_SP);
- self.lower_ty(&Ty {
- id: self.sess.next_node_id(),
- node: TyKind::ImplTrait(impl_ty_node_id, bounds.clone()),
- span: DUMMY_SP,
- }, itctx)
+ let (existential_desugaring, itctx) = match itctx {
+ ImplTraitContext::Existential(_) => (true, itctx),
+ ImplTraitContext::Universal(_) if self.is_in_dyn_type => (true, itctx),
+ // FIXME: this is only needed until `impl Trait` is allowed in type aliases.
+ ImplTraitContext::Disallowed(_) if self.is_in_dyn_type =>
+ (true, ImplTraitContext::Existential(None)),
+ _ => (false, itctx),
+ };
+
+ if existential_desugaring {
+ // Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`.
+
+ let impl_ty_node_id = self.sess.next_node_id();
+ let parent_def_index = self.current_hir_id_owner.last().unwrap().0;
+ self.resolver.definitions().create_def_with_parent(
+ parent_def_index,
+ impl_ty_node_id,
+ DefPathData::Misc,
+ DefIndexAddressSpace::High,
+ Mark::root(),
+ DUMMY_SP
+ );
+
+ self.with_dyn_type_scope(false, |this| {
+ this.lower_ty(
+ &Ty {
+ id: this.sess.next_node_id(),
+ node: TyKind::ImplTrait(impl_ty_node_id, bounds.clone()),
+ span: DUMMY_SP,
+ },
+ itctx,
+ )
+ })
+ } else {
+ // Desugar `AssocTy: Bounds` into `AssocTy = ∃ T (T: Bounds)`, where the
+ // "false existential" later desugars into a trait predicate.
+
+ let bounds = self.lower_param_bounds(bounds, itctx);
+
+ let id = self.sess.next_node_id();
+ let LoweredNodeId { node_id: _, hir_id } = self.lower_node_id(id);
+ P(hir::Ty {
+ hir_id,
+ node: hir::TyKind::AssocTyExistential(bounds),
+ span: DUMMY_SP,
+ })
+ }
}
};
}
TyKind::TraitObject(ref bounds, kind) => {
let mut lifetime_bound = None;
- let bounds = bounds
- .iter()
- .filter_map(|bound| match *bound {
- GenericBound::Trait(ref ty, TraitBoundModifier::None) => {
- Some(self.lower_poly_trait_ref(ty, itctx.reborrow()))
- }
- GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
- GenericBound::Outlives(ref lifetime) => {
- if lifetime_bound.is_none() {
- lifetime_bound = Some(self.lower_lifetime(lifetime));
+ let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
+ let bounds = bounds
+ .iter()
+ .filter_map(|bound| match *bound {
+ GenericBound::Trait(ref ty, TraitBoundModifier::None) => {
+ Some(this.lower_poly_trait_ref(ty, itctx.reborrow()))
}
- None
- }
- })
- .collect();
- let lifetime_bound =
- lifetime_bound.unwrap_or_else(|| self.elided_dyn_bound(t.span));
+ GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
+ GenericBound::Outlives(ref lifetime) => {
+ if lifetime_bound.is_none() {
+ lifetime_bound = Some(this.lower_lifetime(lifetime));
+ }
+ None
+ }
+ })
+ .collect();
+ let lifetime_bound =
+ lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span));
+ (bounds, lifetime_bound)
+ });
if kind != TraitObjectSyntax::Dyn {
self.maybe_lint_bare_trait(t.span, t.id, false);
}
}),
))
}
- ImplTraitContext::AssociatedTy => {
- let hir_bounds = self.lower_param_bounds(
- bounds,
- ImplTraitContext::AssociatedTy,
- );
-
- hir::TyKind::AssocTyExistential(
- hir_bounds,
- )
- }
ImplTraitContext::Disallowed(pos) => {
let allowed_in = if self.sess.features_untracked()
.impl_trait_in_bindings {
FunctionRetTy::Ty(ref ty) => match in_band_ty_params {
Some((def_id, _)) if impl_trait_return_allow => {
hir::Return(self.lower_ty(ty,
- ImplTraitContext::Existential(Some(def_id))))
+ ImplTraitContext::Existential(Some(def_id))
+ ))
}
_ => {
hir::Return(self.lower_ty(ty, ImplTraitContext::disallowed()))
let kind = hir::GenericParamKind::Type {
default: default.as_ref().map(|x| {
- self.lower_ty(x, ImplTraitContext::disallowed())
+ self.lower_ty(x, ImplTraitContext::Existential(None))
}),
synthetic: param.attrs.iter()
.filter(|attr| attr.check_name(sym::rustc_synthetic))
ItemKind::ForeignMod(ref nm) => hir::ItemKind::ForeignMod(self.lower_foreign_mod(nm)),
ItemKind::GlobalAsm(ref ga) => hir::ItemKind::GlobalAsm(self.lower_global_asm(ga)),
ItemKind::Ty(ref t, ref generics) => hir::ItemKind::Ty(
- self.lower_ty(t, ImplTraitContext::AssociatedTy),
- self.lower_generics(generics, ImplTraitContext::AssociatedTy),
+ self.lower_ty(t, ImplTraitContext::disallowed()),
+ self.lower_generics(generics, ImplTraitContext::disallowed()),
),
ItemKind::Existential(ref b, ref generics) => hir::ItemKind::Existential(
hir::ExistTy {
- generics: self.lower_generics(generics, ImplTraitContext::AssociatedTy),
- bounds: self.lower_param_bounds(b, ImplTraitContext::AssociatedTy),
+ generics: self.lower_generics(generics,
+ ImplTraitContext::Existential(None)),
+ bounds: self.lower_param_bounds(b,
+ ImplTraitContext::Existential(None)),
impl_trait_fn: None,
origin: hir::ExistTyOrigin::ExistentialType,
},
),
- ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum(
- hir::EnumDef {
- variants: enum_definition
- .variants
- .iter()
- .map(|x| self.lower_variant(x))
- .collect(),
- },
- self.lower_generics(generics, ImplTraitContext::AssociatedTy),
- ),
+ ItemKind::Enum(ref enum_definition, ref generics) => {
+ hir::ItemKind::Enum(
+ hir::EnumDef {
+ variants: enum_definition
+ .variants
+ .iter()
+ .map(|x| self.lower_variant(x))
+ .collect(),
+ },
+ self.lower_generics(generics, ImplTraitContext::disallowed()),
+ )
+ },
ItemKind::Struct(ref struct_def, ref generics) => {
let struct_def = self.lower_variant_data(struct_def);
hir::ItemKind::Struct(
struct_def,
- self.lower_generics(generics, ImplTraitContext::AssociatedTy),
+ self.lower_generics(generics, ImplTraitContext::disallowed()),
)
}
ItemKind::Union(ref vdata, ref generics) => {
let vdata = self.lower_variant_data(vdata);
hir::ItemKind::Union(
vdata,
- self.lower_generics(generics, ImplTraitContext::AssociatedTy),
+ self.lower_generics(generics, ImplTraitContext::disallowed()),
)
}
ItemKind::Impl(
(generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Provided(body_id)))
}
TraitItemKind::Type(ref bounds, ref default) => {
- let generics = self.lower_generics(&i.generics, ImplTraitContext::AssociatedTy);
+ let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed());
let node = hir::TraitItemKind::Type(
- self.lower_param_bounds(bounds, ImplTraitContext::AssociatedTy),
+ self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
default
.as_ref()
.map(|x| self.lower_ty(x, ImplTraitContext::disallowed())),
/// or `Foo::Bar<impl Trait>`
is_impl_trait_banned: bool,
+ /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
+ /// certain positions.
+ is_assoc_ty_bound_banned: bool,
+
/// rust-lang/rust#57979: the ban of nested `impl Trait` was buggy
/// until PRs #57730 and #57981 landed: it would jump directly to
/// walk_ty rather than visit_ty (or skip recurring entirely for
self.is_impl_trait_banned = old;
}
+ fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
+ let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
+ f(self);
+ self.is_assoc_ty_bound_banned = old;
+ }
+
fn with_impl_trait(&mut self, outer: Option<OuterImplTrait>, f: impl FnOnce(&mut Self)) {
let old = mem::replace(&mut self.outer_impl_trait, outer);
f(self);
}
fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
- if let AssocTyConstraintKind::Equality { ref ty } = constraint.kind {
- // rust-lang/rust#57979: bug in old `visit_generic_args` called
- // `walk_ty` rather than `visit_ty`, skipping outer `impl Trait`
- // if it happened to occur at `ty`.
- if let TyKind::ImplTrait(..) = ty.node {
- self.warning_period_57979_didnt_record_next_impl_trait = true;
+ match constraint.kind {
+ AssocTyConstraintKind::Equality { ref ty } => {
+ // rust-lang/rust#57979: bug in old `visit_generic_args` called
+ // `walk_ty` rather than `visit_ty`, skipping outer `impl Trait`
+ // if it happened to occur at `ty`.
+ if let TyKind::ImplTrait(..) = ty.node {
+ self.warning_period_57979_didnt_record_next_impl_trait = true;
+ }
+ }
+ AssocTyConstraintKind::Bound { .. } => {
+ if self.is_assoc_ty_bound_banned {
+ self.err_handler().span_err(constraint.span,
+ "associated type bounds are not allowed within structs, enums, or unions"
+ );
+ }
}
}
self.visit_assoc_ty_constraint(constraint);
// Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
// are allowed to contain nested `impl Trait`.
self.with_impl_trait(None, |this| {
- walk_list!(this, visit_assoc_ty_constraint_from_generic_args, &data.constraints);
+ walk_list!(this, visit_assoc_ty_constraint_from_generic_args,
+ &data.constraints);
});
}
GenericArgs::Parenthesized(ref data) => {
visit::walk_poly_trait_ref(self, t, m);
}
+ fn visit_variant_data(&mut self, s: &'a VariantData, _: Ident,
+ _: &'a Generics, _: NodeId, _: Span) {
+ self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
+ }
+
+ fn visit_enum_def(&mut self, enum_definition: &'a EnumDef,
+ generics: &'a Generics, item_id: NodeId, _: Span) {
+ self.with_banned_assoc_ty_bound(
+ |this| visit::walk_enum_def(this, enum_definition, generics, item_id))
+ }
+
fn visit_mac(&mut self, mac: &Spanned<Mac_>) {
// when a new macro kind is added but the author forgets to set it up for expansion
// because that's the only part that won't cause a compiler error
has_global_allocator: false,
outer_impl_trait: None,
is_impl_trait_banned: false,
+ is_assoc_ty_bound_banned: false,
warning_period_57979_didnt_record_next_impl_trait: false,
warning_period_57979_impl_trait_in_proj: false,
};
.into_iter()
.map(|r| (self.ast_region_to_region(r, None), r.span))
);
-
- bounds.trait_bounds.sort_by_key(|(t, _)| t.def_id());
}
- /// Translates the AST's notion of ty param bounds (which are an enum consisting of a newtyped `Ty`
- /// or a region) to ty's notion of ty param bounds, which can either be user-defined traits or the
- /// built-in trait `Send`.
+ /// Translates the AST's notion of ty param bounds (which are an enum consisting of a newtyped
+ /// `Ty` or a region) to ty's notion of ty param bounds, which can either be user-defined traits
+ /// or the built-in trait `Send`.
pub fn compute_bounds(&self,
param_ty: Ty<'tcx>,
ast_bounds: &[hir::GenericBound],
span: Span,
) -> Bounds<'tcx> {
let mut bounds = Bounds::default();
+
self.add_bounds(param_ty, ast_bounds, &mut bounds);
+ bounds.trait_bounds.sort_by_key(|(t, _)| t.def_id());
+
bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default {
if !self.is_unsized(ast_bounds, span) {
Some(span)
} else {
None
};
+
bounds
}
// for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
// for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
if let ConvertedBindingKind::Equality(ty) = binding.kind {
- let late_bound_in_trait_ref = tcx.collect_constrained_late_bound_regions(&trait_ref);
+ let late_bound_in_trait_ref =
+ tcx.collect_constrained_late_bound_regions(&trait_ref);
let late_bound_in_ty =
tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty));
debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
}), binding.span));
}
ConvertedBindingKind::Constraint(ref ast_bounds) => {
+ // Calling `skip_binder` is okay, because the predicates are re-bound later by
+ // `instantiate_poly_trait_ref`.
+ let param_ty = tcx.mk_projection(assoc_ty.def_id, candidate.skip_binder().substs);
self.add_bounds(
- trait_ref.self_ty(),
+ param_ty,
ast_bounds,
bounds,
);
}
};
+ debug!("ast_ty_to_ty: result_ty={:?}", result_ty);
+
self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span);
result_ty
}
}
}
});
- debug!("impl_trait_ty_to_ty: final substs = {:?}", substs);
+ debug!("impl_trait_ty_to_ty: substs={:?}", substs);
let ty = tcx.mk_opaque(def_id, substs);
debug!("impl_trait_ty_to_ty: {}", ty);