diff options
| author | Alexander Regueiro <alexreg@me.com> | 2019-03-21 17:55:09 +0000 |
|---|---|---|
| committer | Alexander Regueiro <alexreg@me.com> | 2019-06-05 21:09:26 +0100 |
| commit | 01f49f0bb2461ebe1987a40c6afea5b1dd30e881 (patch) | |
| tree | 472caf3acf29691bbde6a32e17cf83e0676ce56d | |
| parent | aaa53ec8531565e2f5721548b5a38c0062aa0e51 (diff) | |
| download | rust-01f49f0bb2461ebe1987a40c6afea5b1dd30e881.tar.gz rust-01f49f0bb2461ebe1987a40c6afea5b1dd30e881.zip | |
Use both existential-type desugaring and where-clause (predicate) desugaring depending on context.
| -rw-r--r-- | src/librustc/hir/lowering.rs | 182 | ||||
| -rw-r--r-- | src/librustc_passes/ast_validation.rs | 46 | ||||
| -rw-r--r-- | src/librustc_typeck/astconv.rs | 24 | ||||
| -rw-r--r-- | src/librustc_typeck/collect.rs | 8 |
4 files changed, 173 insertions, 87 deletions
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 2c2cd6a2f6f..165723bcfa2 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -106,6 +106,7 @@ pub struct LoweringContext<'a> { 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 @@ -195,12 +196,6 @@ enum ImplTraitContext<'a> { /// (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), } @@ -208,7 +203,10 @@ enum ImplTraitContext<'a> { /// 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, } @@ -223,7 +221,6 @@ impl<'a> ImplTraitContext<'a> { match self { Universal(params) => Universal(params), Existential(fn_def_id) => Existential(*fn_def_id), - AssociatedTy => AssociatedTy, Disallowed(pos) => Disallowed(*pos), } } @@ -256,6 +253,8 @@ pub fn lower_crate( 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, @@ -265,7 +264,6 @@ pub fn lower_crate( 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(), @@ -1230,6 +1228,20 @@ impl<'a> LoweringContext<'a> { 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, @@ -1353,24 +1365,58 @@ impl<'a> LoweringContext<'a> { 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, + }) + } } }; @@ -1477,23 +1523,26 @@ impl<'a> LoweringContext<'a> { } 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); } @@ -1544,16 +1593,6 @@ impl<'a> LoweringContext<'a> { }), )) } - 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 { @@ -2407,7 +2446,8 @@ impl<'a> LoweringContext<'a> { 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())) @@ -2770,7 +2810,7 @@ impl<'a> LoweringContext<'a> { 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)) @@ -3275,39 +3315,43 @@ impl<'a> LoweringContext<'a> { 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( @@ -3675,9 +3719,9 @@ impl<'a> LoweringContext<'a> { (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())), diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 2d602a7f1b4..532cec2af15 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -63,6 +63,10 @@ struct AstValidator<'a> { /// 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 @@ -87,6 +91,12 @@ impl<'a> AstValidator<'a> { 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); @@ -94,12 +104,21 @@ impl<'a> AstValidator<'a> { } 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); @@ -726,7 +745,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { // 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) => { @@ -819,6 +839,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> { 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 @@ -842,6 +873,7 @@ pub fn check_crate(session: &Session, krate: &Crate) -> (bool, bool) { 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, }; diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 6123ee2af6e..5ddb2c974ac 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -930,13 +930,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { .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], @@ -944,7 +942,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { 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) @@ -954,6 +955,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } else { None }; + bounds } @@ -993,7 +995,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { // 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); @@ -1074,8 +1077,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { }), 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, ); @@ -2050,6 +2056,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } }; + debug!("ast_ty_to_ty: result_ty={:?}", result_ty); + self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span); result_ty } @@ -2135,7 +2143,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } } }); - 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); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 92d0e37cb9b..90ab596363b 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -703,7 +703,8 @@ fn super_predicates_of<'a, 'tcx>( // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`. let self_param_ty = tcx.mk_self_type(); - let superbounds1 = AstConv::compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No, item.span); + let superbounds1 = AstConv::compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No, + item.span); let superbounds1 = superbounds1.predicates(tcx, self_param_ty); @@ -1988,15 +1989,16 @@ fn explicit_predicates_of<'a, 'tcx>( tcx.def_span(def_id), ); + let bounds_predicates = bounds.predicates(tcx, opaque_ty); if impl_trait_fn.is_some() { // opaque types return tcx.arena.alloc(ty::GenericPredicates { parent: None, - predicates: bounds.predicates(tcx, opaque_ty), + predicates: bounds_predicates, }); } else { // named existential types - predicates.extend(bounds.predicates(tcx, opaque_ty)); + predicates.extend(bounds_predicates); generics } } |
