Skip to content

Commit

Permalink
Auto merge of #78725 - sexxi-goose:fix-78720, r=nikomatsakis
Browse files Browse the repository at this point in the history
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`
  • Loading branch information
bors committed Dec 1, 2020
2 parents 29c4358 + e35e46c commit c4926d0
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 115 deletions.
228 changes: 129 additions & 99 deletions compiler/rustc_middle/src/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
})
}

Expand Down
10 changes: 0 additions & 10 deletions compiler/rustc_trait_selection/src/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand All @@ -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);
Expand Down
8 changes: 2 additions & 6 deletions compiler/rustc_ty_utils/src/needs_drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
19 changes: 19 additions & 0 deletions src/test/ui/issues/issue-78720.rs
Original file line number Diff line number Diff line change
@@ -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() {}
55 changes: 55 additions & 0 deletions src/test/ui/issues/issue-78720.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit c4926d0

Please sign in to comment.