about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-12-01 07:00:41 +0000
committerbors <bors@rust-lang.org>2020-12-01 07:00:41 +0000
commitc4926d01ada661d4fbffb0e5b1708ae5463d47b3 (patch)
treededda250178e25359830d9b113a4e67526df24ca
parent29c4358c189fbb3bd3fd7ac3d7a95fac7b97814c (diff)
parente35e46c1139d292ca0b352416d01b38bcf96fd69 (diff)
downloadrust-c4926d01ada661d4fbffb0e5b1708ae5463d47b3.tar.gz
rust-c4926d01ada661d4fbffb0e5b1708ae5463d47b3.zip
Auto merge of #78725 - sexxi-goose:fix-78720, r=nikomatsakis
Remove extra call to upvar_tys

We already visit the tuple of upvar_tys, we don't need to visit each individual type.

Fixes #78720

r? `@ghost`
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs228
-rw-r--r--compiler/rustc_trait_selection/src/opaque_types.rs10
-rw-r--r--compiler/rustc_ty_utils/src/needs_drop.rs8
-rw-r--r--src/test/ui/issues/issue-78720.rs19
-rw-r--r--src/test/ui/issues/issue-78720.stderr55
5 files changed, 205 insertions, 115 deletions
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 8bdc7efa0bb..00fea91fdfc 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -2105,118 +2105,148 @@ where
     }
 
     fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout {
-        let tcx = cx.tcx();
-        let tag_layout = |tag: &Scalar| -> C::TyAndLayout {
-            let layout = Layout::scalar(cx, tag.clone());
-            MaybeResult::from(Ok(TyAndLayout {
-                layout: tcx.intern_layout(layout),
-                ty: tag.value.to_ty(tcx),
-            }))
-        };
+        enum TyMaybeWithLayout<C: LayoutOf> {
+            Ty(C::Ty),
+            TyAndLayout(C::TyAndLayout),
+        }
 
-        cx.layout_of(match *this.ty.kind() {
-            ty::Bool
-            | ty::Char
-            | ty::Int(_)
-            | ty::Uint(_)
-            | ty::Float(_)
-            | ty::FnPtr(_)
-            | ty::Never
-            | ty::FnDef(..)
-            | ty::GeneratorWitness(..)
-            | ty::Foreign(..)
-            | ty::Dynamic(..) => bug!("TyAndLayout::field_type({:?}): not applicable", this),
-
-            // Potentially-fat pointers.
-            ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
-                assert!(i < this.fields.count());
-
-                // Reuse the fat `*T` type as its own thin pointer data field.
-                // This provides information about, e.g., DST struct pointees
-                // (which may have no non-DST form), and will work as long
-                // as the `Abi` or `FieldsShape` is checked by users.
-                if i == 0 {
-                    let nil = tcx.mk_unit();
-                    let ptr_ty = if this.ty.is_unsafe_ptr() {
-                        tcx.mk_mut_ptr(nil)
-                    } else {
-                        tcx.mk_mut_ref(tcx.lifetimes.re_static, nil)
-                    };
-                    return MaybeResult::from(cx.layout_of(ptr_ty).to_result().map(
-                        |mut ptr_layout| {
-                            ptr_layout.ty = this.ty;
-                            ptr_layout
-                        },
-                    ));
-                }
+        fn ty_and_layout_kind<
+            C: LayoutOf<Ty = Ty<'tcx>, TyAndLayout: MaybeResult<TyAndLayout<'tcx>>>
+                + HasTyCtxt<'tcx>
+                + HasParamEnv<'tcx>,
+        >(
+            this: TyAndLayout<'tcx>,
+            cx: &C,
+            i: usize,
+            ty: C::Ty,
+        ) -> TyMaybeWithLayout<C> {
+            let tcx = cx.tcx();
+            let tag_layout = |tag: &Scalar| -> C::TyAndLayout {
+                let layout = Layout::scalar(cx, tag.clone());
+                MaybeResult::from(Ok(TyAndLayout {
+                    layout: tcx.intern_layout(layout),
+                    ty: tag.value.to_ty(tcx),
+                }))
+            };
 
-                match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() {
-                    ty::Slice(_) | ty::Str => tcx.types.usize,
-                    ty::Dynamic(_, _) => {
-                        tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.usize, 3))
-                        /* FIXME: use actual fn pointers
-                        Warning: naively computing the number of entries in the
-                        vtable by counting the methods on the trait + methods on
-                        all parent traits does not work, because some methods can
-                        be not object safe and thus excluded from the vtable.
-                        Increase this counter if you tried to implement this but
-                        failed to do it without duplicating a lot of code from
-                        other places in the compiler: 2
-                        tcx.mk_tup(&[
-                            tcx.mk_array(tcx.types.usize, 3),
-                            tcx.mk_array(Option<fn()>),
-                        ])
-                        */
+            match *ty.kind() {
+                ty::Bool
+                | ty::Char
+                | ty::Int(_)
+                | ty::Uint(_)
+                | ty::Float(_)
+                | ty::FnPtr(_)
+                | ty::Never
+                | ty::FnDef(..)
+                | ty::GeneratorWitness(..)
+                | ty::Foreign(..)
+                | ty::Dynamic(..) => bug!("TyAndLayout::field_type({:?}): not applicable", this),
+
+                // Potentially-fat pointers.
+                ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
+                    assert!(i < this.fields.count());
+
+                    // Reuse the fat `*T` type as its own thin pointer data field.
+                    // This provides information about, e.g., DST struct pointees
+                    // (which may have no non-DST form), and will work as long
+                    // as the `Abi` or `FieldsShape` is checked by users.
+                    if i == 0 {
+                        let nil = tcx.mk_unit();
+                        let ptr_ty = if ty.is_unsafe_ptr() {
+                            tcx.mk_mut_ptr(nil)
+                        } else {
+                            tcx.mk_mut_ref(tcx.lifetimes.re_static, nil)
+                        };
+                        return TyMaybeWithLayout::TyAndLayout(MaybeResult::from(
+                            cx.layout_of(ptr_ty).to_result().map(|mut ptr_layout| {
+                                ptr_layout.ty = ty;
+                                ptr_layout
+                            }),
+                        ));
                     }
-                    _ => bug!("TyAndLayout::field_type({:?}): not applicable", this),
-                }
-            }
 
-            // Arrays and slices.
-            ty::Array(element, _) | ty::Slice(element) => element,
-            ty::Str => tcx.types.u8,
-
-            // Tuples, generators and closures.
-            ty::Closure(_, ref substs) => substs.as_closure().upvar_tys().nth(i).unwrap(),
-
-            ty::Generator(def_id, ref substs, _) => match this.variants {
-                Variants::Single { index } => substs
-                    .as_generator()
-                    .state_tys(def_id, tcx)
-                    .nth(index.as_usize())
-                    .unwrap()
-                    .nth(i)
-                    .unwrap(),
-                Variants::Multiple { ref tag, tag_field, .. } => {
-                    if i == tag_field {
-                        return tag_layout(tag);
+                    match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() {
+                        ty::Slice(_) | ty::Str => TyMaybeWithLayout::Ty(tcx.types.usize),
+                        ty::Dynamic(_, _) => {
+                            TyMaybeWithLayout::Ty(tcx.mk_imm_ref(
+                                tcx.lifetimes.re_static,
+                                tcx.mk_array(tcx.types.usize, 3),
+                            ))
+                            /* FIXME: use actual fn pointers
+                            Warning: naively computing the number of entries in the
+                            vtable by counting the methods on the trait + methods on
+                            all parent traits does not work, because some methods can
+                            be not object safe and thus excluded from the vtable.
+                            Increase this counter if you tried to implement this but
+                            failed to do it without duplicating a lot of code from
+                            other places in the compiler: 2
+                            tcx.mk_tup(&[
+                                tcx.mk_array(tcx.types.usize, 3),
+                                tcx.mk_array(Option<fn()>),
+                            ])
+                            */
+                        }
+                        _ => bug!("TyAndLayout::field_type({:?}): not applicable", this),
                     }
-                    substs.as_generator().prefix_tys().nth(i).unwrap()
                 }
-            },
 
-            ty::Tuple(tys) => tys[i].expect_ty(),
+                // Arrays and slices.
+                ty::Array(element, _) | ty::Slice(element) => TyMaybeWithLayout::Ty(element),
+                ty::Str => TyMaybeWithLayout::Ty(tcx.types.u8),
 
-            // ADTs.
-            ty::Adt(def, substs) => {
-                match this.variants {
-                    Variants::Single { index } => def.variants[index].fields[i].ty(tcx, substs),
+                // Tuples, generators and closures.
+                ty::Closure(_, ref substs) => {
+                    ty_and_layout_kind(this, cx, i, substs.as_closure().tupled_upvars_ty())
+                }
+
+                ty::Generator(def_id, ref substs, _) => match this.variants {
+                    Variants::Single { index } => TyMaybeWithLayout::Ty(
+                        substs
+                            .as_generator()
+                            .state_tys(def_id, tcx)
+                            .nth(index.as_usize())
+                            .unwrap()
+                            .nth(i)
+                            .unwrap(),
+                    ),
+                    Variants::Multiple { ref tag, tag_field, .. } => {
+                        if i == tag_field {
+                            return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
+                        }
+                        TyMaybeWithLayout::Ty(substs.as_generator().prefix_tys().nth(i).unwrap())
+                    }
+                },
+
+                ty::Tuple(tys) => TyMaybeWithLayout::Ty(tys[i].expect_ty()),
+
+                // ADTs.
+                ty::Adt(def, substs) => {
+                    match this.variants {
+                        Variants::Single { index } => {
+                            TyMaybeWithLayout::Ty(def.variants[index].fields[i].ty(tcx, substs))
+                        }
 
-                    // Discriminant field for enums (where applicable).
-                    Variants::Multiple { ref tag, .. } => {
-                        assert_eq!(i, 0);
-                        return tag_layout(tag);
+                        // Discriminant field for enums (where applicable).
+                        Variants::Multiple { ref tag, .. } => {
+                            assert_eq!(i, 0);
+                            return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
+                        }
                     }
                 }
+
+                ty::Projection(_)
+                | ty::Bound(..)
+                | ty::Placeholder(..)
+                | ty::Opaque(..)
+                | ty::Param(_)
+                | ty::Infer(_)
+                | ty::Error(_) => bug!("TyAndLayout::field_type: unexpected type `{}`", this.ty),
             }
+        }
 
-            ty::Projection(_)
-            | ty::Bound(..)
-            | ty::Placeholder(..)
-            | ty::Opaque(..)
-            | ty::Param(_)
-            | ty::Infer(_)
-            | ty::Error(_) => bug!("TyAndLayout::field_type: unexpected type `{}`", this.ty),
+        cx.layout_of(match ty_and_layout_kind(this, cx, i, this.ty) {
+            TyMaybeWithLayout::Ty(result) => result,
+            TyMaybeWithLayout::TyAndLayout(result) => return result,
         })
     }
 
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index ca547bf88b5..f5bc90e6f96 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -722,11 +722,6 @@ where
                 // Skip lifetime parameters of the enclosing item(s)
 
                 substs.as_closure().tupled_upvars_ty().visit_with(self);
-
-                for upvar_ty in substs.as_closure().upvar_tys() {
-                    upvar_ty.visit_with(self);
-                }
-
                 substs.as_closure().sig_as_fn_ptr_ty().visit_with(self);
             }
 
@@ -735,11 +730,6 @@ where
                 // Also skip the witness type, because that has no free regions.
 
                 substs.as_generator().tupled_upvars_ty().visit_with(self);
-
-                for upvar_ty in substs.as_generator().upvar_tys() {
-                    upvar_ty.visit_with(self);
-                }
-
                 substs.as_generator().return_ty().visit_with(self);
                 substs.as_generator().yield_ty().visit_with(self);
                 substs.as_generator().resume_ty().visit_with(self);
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index d62fc764c76..64f82817d39 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -94,16 +94,12 @@ where
                     _ if component.is_copy_modulo_regions(tcx.at(DUMMY_SP), self.param_env) => (),
 
                     ty::Closure(_, substs) => {
-                        for upvar_ty in substs.as_closure().upvar_tys() {
-                            queue_type(self, upvar_ty);
-                        }
+                        queue_type(self, substs.as_closure().tupled_upvars_ty());
                     }
 
                     ty::Generator(def_id, substs, _) => {
                         let substs = substs.as_generator();
-                        for upvar_ty in substs.upvar_tys() {
-                            queue_type(self, upvar_ty);
-                        }
+                        queue_type(self, substs.tupled_upvars_ty());
 
                         let witness = substs.witness();
                         let interior_tys = match witness.kind() {
diff --git a/src/test/ui/issues/issue-78720.rs b/src/test/ui/issues/issue-78720.rs
new file mode 100644
index 00000000000..57615d1a207
--- /dev/null
+++ b/src/test/ui/issues/issue-78720.rs
@@ -0,0 +1,19 @@
+fn server() -> impl {
+//~^ ERROR at least one trait must be specified
+    ().map2(|| "")
+}
+
+trait FilterBase2 {
+    fn map2<F>(self, F) -> Map2<F> {}
+    //~^ ERROR mismatched types
+    //~^^ ERROR the size for values of type `Self` cannot be known at compilation time
+}
+
+struct Map2<Segment2> {
+    _func: F,
+    //~^ ERROR cannot find type `F` in this scope
+}
+
+impl<F> FilterBase2 for F {}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-78720.stderr b/src/test/ui/issues/issue-78720.stderr
new file mode 100644
index 00000000000..a3a14e34acb
--- /dev/null
+++ b/src/test/ui/issues/issue-78720.stderr
@@ -0,0 +1,55 @@
+error: at least one trait must be specified
+  --> $DIR/issue-78720.rs:1:16
+   |
+LL | fn server() -> impl {
+   |                ^^^^
+
+error[E0412]: cannot find type `F` in this scope
+  --> $DIR/issue-78720.rs:13:12
+   |
+LL |     _func: F,
+   |            ^
+   | 
+  ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
+   |
+LL | pub trait Fn<Args>: FnMut<Args> {
+   | ------------------------------- similarly named trait `Fn` defined here
+   |
+help: a trait with a similar name exists
+   |
+LL |     _func: Fn,
+   |            ^^
+help: you might be missing a type parameter
+   |
+LL | struct Map2<Segment2, F> {
+   |                     ^^^
+
+error[E0308]: mismatched types
+  --> $DIR/issue-78720.rs:7:36
+   |
+LL |     fn map2<F>(self, F) -> Map2<F> {}
+   |                                    ^^ expected struct `Map2`, found `()`
+   |
+   = note: expected struct `Map2<F>`
+           found unit type `()`
+
+error[E0277]: the size for values of type `Self` cannot be known at compilation time
+  --> $DIR/issue-78720.rs:7:16
+   |
+LL |     fn map2<F>(self, F) -> Map2<F> {}
+   |                ^^^^ doesn't have a size known at compile-time
+   |
+   = help: unsized fn params are gated as an unstable feature
+help: consider further restricting `Self`
+   |
+LL |     fn map2<F>(self, F) -> Map2<F> where Self: Sized {}
+   |                                    ^^^^^^^^^^^^^^^^^
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL |     fn map2<F>(&self, F) -> Map2<F> {}
+   |                ^
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0277, E0308, E0412.
+For more information about an error, try `rustc --explain E0277`.