Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove extra call to upvar_tys #78725

Merged
merged 2 commits into from
Dec 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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`.