Address review comments

* Handle arrays with const-generic lengths
* Use closure for repeated code.
This commit is contained in:
Matthew Jasper 2020-01-31 22:22:30 +00:00
parent d1965216a3
commit d20646b2d8
2 changed files with 36 additions and 32 deletions

View File

@ -18,6 +18,7 @@
use rustc_hir::def_id::DefId;
use rustc_macros::HashStable;
use rustc_span::Span;
use rustc_target::abi::TargetDataLayout;
use smallvec::SmallVec;
use std::{cmp, fmt};
use syntax::ast;
@ -726,7 +727,7 @@ pub fn is_freeze(
#[inline]
pub fn needs_drop(&'tcx self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
// Avoid querying in simple cases.
match needs_drop_components(self) {
match needs_drop_components(self, &tcx.data_layout) {
Err(AlwaysRequiresDrop) => true,
Ok(components) => {
let query_ty = match *components {
@ -736,7 +737,7 @@ pub fn needs_drop(&'tcx self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>)
[component_ty] => component_ty,
_ => self,
};
// This doesn't depend on regions, so try to minimize distinct.
// This doesn't depend on regions, so try to minimize distinct
// query keys used.
let erased = tcx.normalize_erasing_regions(param_env, query_ty);
tcx.needs_drop_raw(param_env.and(erased))
@ -992,7 +993,10 @@ pub fn determine<P>(self_arg_ty: Ty<'tcx>, is_self_ty: P) -> ExplicitSelf<'tcx>
/// Returns a list of types such that the given type needs drop if and only if
/// *any* of the returned types need drop. Returns `Err(AlwaysRequiresDrop)` if
/// this type always needs drop.
pub fn needs_drop_components(ty: Ty<'tcx>) -> Result<SmallVec<[Ty<'tcx>; 4]>, AlwaysRequiresDrop> {
pub fn needs_drop_components(
ty: Ty<'tcx>,
target_layout: &TargetDataLayout,
) -> Result<SmallVec<[Ty<'tcx>; 2]>, AlwaysRequiresDrop> {
match ty.kind {
ty::Infer(ty::FreshIntTy(_))
| ty::Infer(ty::FreshFloatTy(_))
@ -1017,18 +1021,25 @@ pub fn determine<P>(self_arg_ty: Ty<'tcx>, is_self_ty: P) -> ExplicitSelf<'tcx>
// state transformation pass
ty::Generator(..) | ty::Dynamic(..) | ty::Error => Err(AlwaysRequiresDrop),
ty::Slice(ty) => needs_drop_components(ty),
ty::Array(elem_ty, ..) => {
match needs_drop_components(elem_ty) {
ty::Slice(ty) => needs_drop_components(ty, target_layout),
ty::Array(elem_ty, size) => {
match needs_drop_components(elem_ty, target_layout) {
Ok(v) if v.is_empty() => Ok(v),
// Arrays of size zero don't need drop, even if their element
// type does.
_ => Ok(smallvec![ty]),
res => match size.val.try_to_bits(target_layout.pointer_size) {
// Arrays of size zero don't need drop, even if their element
// type does.
Some(0) => Ok(SmallVec::new()),
Some(_) => res,
// We don't know which of the cases above we are in, so
// return the whole type and let the caller decide what to
// do.
None => Ok(smallvec![ty]),
},
}
}
// If any field needs drop, then the whole tuple does.
ty::Tuple(..) => ty.tuple_fields().try_fold(SmallVec::new(), |mut acc, elem| {
acc.extend(needs_drop_components(elem)?);
ty::Tuple(..) => ty.tuple_fields().try_fold(SmallVec::new(), move |mut acc, elem| {
acc.extend(needs_drop_components(elem, target_layout)?);
Ok(acc)
}),

View File

@ -76,30 +76,25 @@ fn next(&mut self) -> Option<NeedsDropResult<Ty<'tcx>>> {
return Some(Err(AlwaysRequiresDrop));
}
let components = match needs_drop_components(ty) {
let components = match needs_drop_components(ty, &tcx.data_layout) {
Err(e) => return Some(Err(e)),
Ok(components) => components,
};
debug!("needs_drop_components({:?}) = {:?}", ty, components);
let queue_type = move |this: &mut Self, component: Ty<'tcx>| {
if this.seen_tys.insert(component) {
this.unchecked_tys.push((component, level + 1));
}
};
for component in components {
match component.kind {
_ if component.is_copy_modulo_regions(tcx, self.param_env, DUMMY_SP) => (),
ty::Array(elem_ty, len) => {
// Zero-length arrays never contain anything to drop.
if len.try_eval_usize(tcx, self.param_env) != Some(0) {
if self.seen_tys.insert(elem_ty) {
self.unchecked_tys.push((elem_ty, level + 1));
}
}
}
ty::Closure(def_id, substs) => {
for upvar_ty in substs.as_closure().upvar_tys(def_id, tcx) {
if self.seen_tys.insert(upvar_ty) {
self.unchecked_tys.push((upvar_ty, level + 1));
}
queue_type(self, upvar_ty);
}
}
@ -116,21 +111,19 @@ fn next(&mut self) -> Option<NeedsDropResult<Ty<'tcx>>> {
self.param_env,
required_ty.subst(tcx, substs),
);
if self.seen_tys.insert(subst_ty) {
self.unchecked_tys.push((subst_ty, level + 1));
}
queue_type(self, subst_ty);
}
}
ty::Opaque(..) | ty::Projection(..) | ty::Param(_) => {
ty::Array(..) | ty::Opaque(..) | ty::Projection(..) | ty::Param(_) => {
if ty == component {
// Return the type to the caller so they can decide
// what to do with it.
// Return the type to the caller: they may be able
// to normalize further than we can.
return Some(Ok(component));
} else if self.seen_tys.insert(component) {
} else {
// Store the type for later. We can't return here
// because we would then lose any other components
// of the type.
self.unchecked_tys.push((component, level + 1));
queue_type(self, component);
}
}
_ => return Some(Err(AlwaysRequiresDrop)),