]> git.lizzy.rs Git - rust.git/commitdiff
Use both existential-type desugaring and where-clause (predicate) desugaring dependin...
authorAlexander Regueiro <alexreg@me.com>
Thu, 21 Mar 2019 17:55:09 +0000 (17:55 +0000)
committerAlexander Regueiro <alexreg@me.com>
Wed, 5 Jun 2019 20:09:26 +0000 (21:09 +0100)
src/librustc/hir/lowering.rs
src/librustc_passes/ast_validation.rs
src/librustc_typeck/astconv.rs
src/librustc_typeck/collect.rs

index 2c2cd6a2f6f53e49280a5cf63ff54503b42f4aa0..165723bcfa27811e24f55542d9a5e8493b19cfdc 100644 (file)
@@ -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 @@ fn reborrow(&'b mut self) -> ImplTraitContext<'b> {
         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 @@ fn with_loop_condition_scope<T, F>(&mut self, f: F) -> T
         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 @@ fn lower_assoc_ty_constraint(&mut self,
                                  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 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_>) -> hir::T
             }
             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 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_>) -> hir::T
                             }),
                         ))
                     }
-                    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 @@ fn lower_fn_decl(
                 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 @@ fn lower_generic_param(&mut self,
 
                 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 @@ fn lower_item_kind(
             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 @@ fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem {
                 (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())),
index 2d602a7f1b468d4d361d7814573ef7c951f6560f..532cec2af159ee8900cab4df34831b3b1a96a78e 100644 (file)
@@ -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 @@ fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
         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 @@ fn with_impl_trait(&mut self, outer: Option<OuterImplTrait>, f: impl FnOnce(&mut
     }
 
     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 @@ fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
                 // 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 @@ fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifie
         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,
     };
index 6123ee2af6e888cc6ee13ffe042ac942c0dc4f80..5ddb2c974ac02b828533e827260c706736cc480f 100644 (file)
@@ -930,13 +930,11 @@ pub fn add_bounds(&self,
             .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 @@ pub fn compute_bounds(&self,
         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 @@ pub fn compute_bounds(&self,
         } else {
             None
         };
+
         bounds
     }
 
@@ -993,7 +995,8 @@ fn add_predicates_for_ast_type_binding(
             //     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 @@ fn add_predicates_for_ast_type_binding(
                 }), 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 @@ pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
             }
         };
 
+        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 @@ pub fn impl_trait_ty_to_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);
index 92d0e37cb9bbdbbb8451cc7a9423103c693dcde7..90ab596363bffea05fb952a952f41f00e704e22d 100644 (file)
@@ -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 extend<I: IntoIterator<Item = (ty::Predicate<'tcx>, Span)>>(&mut self, iter:
                         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
                     }
                 }