address review comments
This commit is contained in:
parent
6fc19ada6b
commit
05f1a057b6
@ -1750,105 +1750,6 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> {
|
||||
}
|
||||
|
||||
impl<'tcx> AdtDefData<'tcx, 'tcx> {
|
||||
fn sized_constraint_for_tys<TYS>(
|
||||
&'tcx self,
|
||||
tcx: &ty::TyCtxt<'tcx>,
|
||||
stack: &mut Vec<AdtDefMaster<'tcx>>,
|
||||
tys: TYS
|
||||
) -> Ty<'tcx>
|
||||
where TYS: IntoIterator<Item=Ty<'tcx>>
|
||||
{
|
||||
let tys : Vec<_> = tys.into_iter()
|
||||
.map(|ty| self.sized_constraint_for_ty(tcx, stack, ty))
|
||||
.flat_map(|ty| match ty.sty {
|
||||
ty::TyTuple(ref tys) => tys.last().cloned(),
|
||||
_ => Some(ty)
|
||||
})
|
||||
.filter(|ty| *ty != tcx.types.bool)
|
||||
.collect();
|
||||
|
||||
match tys.len() {
|
||||
_ if tys.references_error() => tcx.types.err,
|
||||
0 => tcx.types.bool,
|
||||
1 => tys[0],
|
||||
_ => tcx.mk_tup(tys)
|
||||
}
|
||||
}
|
||||
|
||||
fn sized_constraint_for_ty(
|
||||
&'tcx self,
|
||||
tcx: &ty::TyCtxt<'tcx>,
|
||||
stack: &mut Vec<AdtDefMaster<'tcx>>,
|
||||
ty: Ty<'tcx>
|
||||
) -> Ty<'tcx> {
|
||||
let result = match ty.sty {
|
||||
TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
|
||||
TyBox(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) |
|
||||
TyArray(..) | TyClosure(..) => {
|
||||
// these are always sized - return a primitive
|
||||
tcx.types.bool
|
||||
}
|
||||
|
||||
TyStr | TyTrait(..) | TySlice(_) | TyError => {
|
||||
// these are never sized - return the target type
|
||||
ty
|
||||
}
|
||||
|
||||
TyTuple(ref tys) => {
|
||||
self.sized_constraint_for_tys(tcx, stack, tys.iter().cloned())
|
||||
}
|
||||
|
||||
TyEnum(adt, substs) | TyStruct(adt, substs) => {
|
||||
// recursive case
|
||||
let adt = tcx.lookup_adt_def_master(adt.did);
|
||||
adt.calculate_sized_constraint_inner(tcx, stack);
|
||||
let adt_ty =
|
||||
adt.sized_constraint
|
||||
.unwrap(DepNode::SizedConstraint(adt.did))
|
||||
.subst(tcx, substs);
|
||||
debug!("sized_constraint_for_ty({:?}) intermediate = {:?}",
|
||||
ty, adt_ty);
|
||||
self.sized_constraint_for_ty(tcx, stack, adt_ty)
|
||||
}
|
||||
|
||||
TyProjection(..) => {
|
||||
// must calculate explicitly.
|
||||
// FIXME: consider special-casing always-Sized projections
|
||||
ty
|
||||
}
|
||||
|
||||
TyParam(..) => {
|
||||
// perf hack: if there is a `T: Sized` bound, then
|
||||
// we know that `T` is Sized and do not need to check
|
||||
// it on the impl.
|
||||
|
||||
let sized_trait = match tcx.lang_items.sized_trait() {
|
||||
Some(x) => x,
|
||||
_ => return ty
|
||||
};
|
||||
let sized_predicate = Binder(TraitRef {
|
||||
def_id: sized_trait,
|
||||
substs: tcx.mk_substs(Substs::new_trait(
|
||||
vec![], vec![], ty
|
||||
))
|
||||
}).to_predicate();
|
||||
let predicates = tcx.lookup_predicates(self.did).predicates;
|
||||
if predicates.into_iter().any(|p| p == sized_predicate) {
|
||||
tcx.types.bool
|
||||
} else {
|
||||
ty
|
||||
}
|
||||
}
|
||||
|
||||
TyInfer(..) => {
|
||||
bug!("unexpected type `{:?}` in sized_constraint_for_ty",
|
||||
ty)
|
||||
}
|
||||
};
|
||||
debug!("sized_constraint_for_ty({:?}) = {:?}", ty, result);
|
||||
result
|
||||
}
|
||||
|
||||
/// Calculates the Sized-constraint.
|
||||
///
|
||||
/// As the Sized-constraint of enums can be a *set* of types,
|
||||
@ -1876,21 +1777,33 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> {
|
||||
|
||||
if stack.contains(&self) {
|
||||
debug!("calculate_sized_constraint: {:?} is recursive", self);
|
||||
// This should be reported as an error by `check_representable`.
|
||||
//
|
||||
// Consider the type as Sized in the meanwhile to avoid
|
||||
// further errors.
|
||||
self.sized_constraint.fulfill(dep_node, tcx.types.err);
|
||||
return;
|
||||
}
|
||||
|
||||
stack.push(self);
|
||||
let ty = self.sized_constraint_for_tys(
|
||||
tcx, stack,
|
||||
|
||||
let tys : Vec<_> =
|
||||
self.variants.iter().flat_map(|v| {
|
||||
v.fields.last()
|
||||
}).map(|f| f.unsubst_ty())
|
||||
);
|
||||
}).flat_map(|f| {
|
||||
self.sized_constraint_for_ty(tcx, stack, f.unsubst_ty())
|
||||
}).collect();
|
||||
|
||||
let self_ = stack.pop().unwrap();
|
||||
assert_eq!(self_, self);
|
||||
|
||||
let ty = match tys.len() {
|
||||
_ if tys.references_error() => tcx.types.err,
|
||||
0 => tcx.types.bool,
|
||||
1 => tys[0],
|
||||
_ => tcx.mk_tup(tys)
|
||||
};
|
||||
|
||||
match self.sized_constraint.get(dep_node) {
|
||||
Some(old_ty) => {
|
||||
debug!("calculate_sized_constraint: {:?} recurred", self);
|
||||
@ -1902,6 +1815,87 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sized_constraint_for_ty(
|
||||
&'tcx self,
|
||||
tcx: &ty::TyCtxt<'tcx>,
|
||||
stack: &mut Vec<AdtDefMaster<'tcx>>,
|
||||
ty: Ty<'tcx>
|
||||
) -> Vec<Ty<'tcx>> {
|
||||
let result = match ty.sty {
|
||||
TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
|
||||
TyBox(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) |
|
||||
TyArray(..) | TyClosure(..) => {
|
||||
vec![]
|
||||
}
|
||||
|
||||
TyStr | TyTrait(..) | TySlice(_) | TyError => {
|
||||
// these are never sized - return the target type
|
||||
vec![ty]
|
||||
}
|
||||
|
||||
TyTuple(ref tys) => {
|
||||
tys.last().into_iter().flat_map(|ty| {
|
||||
self.sized_constraint_for_ty(tcx, stack, ty)
|
||||
}).collect()
|
||||
}
|
||||
|
||||
TyEnum(adt, substs) | TyStruct(adt, substs) => {
|
||||
// recursive case
|
||||
let adt = tcx.lookup_adt_def_master(adt.did);
|
||||
adt.calculate_sized_constraint_inner(tcx, stack);
|
||||
let adt_ty =
|
||||
adt.sized_constraint
|
||||
.unwrap(DepNode::SizedConstraint(adt.did))
|
||||
.subst(tcx, substs);
|
||||
debug!("sized_constraint_for_ty({:?}) intermediate = {:?}",
|
||||
ty, adt_ty);
|
||||
if let ty::TyTuple(ref tys) = adt_ty.sty {
|
||||
tys.iter().flat_map(|ty| {
|
||||
self.sized_constraint_for_ty(tcx, stack, ty)
|
||||
}).collect()
|
||||
} else {
|
||||
self.sized_constraint_for_ty(tcx, stack, adt_ty)
|
||||
}
|
||||
}
|
||||
|
||||
TyProjection(..) => {
|
||||
// must calculate explicitly.
|
||||
// FIXME: consider special-casing always-Sized projections
|
||||
vec![ty]
|
||||
}
|
||||
|
||||
TyParam(..) => {
|
||||
// perf hack: if there is a `T: Sized` bound, then
|
||||
// we know that `T` is Sized and do not need to check
|
||||
// it on the impl.
|
||||
|
||||
let sized_trait = match tcx.lang_items.sized_trait() {
|
||||
Some(x) => x,
|
||||
_ => return vec![ty]
|
||||
};
|
||||
let sized_predicate = Binder(TraitRef {
|
||||
def_id: sized_trait,
|
||||
substs: tcx.mk_substs(Substs::new_trait(
|
||||
vec![], vec![], ty
|
||||
))
|
||||
}).to_predicate();
|
||||
let predicates = tcx.lookup_predicates(self.did).predicates;
|
||||
if predicates.into_iter().any(|p| p == sized_predicate) {
|
||||
vec![]
|
||||
} else {
|
||||
vec![ty]
|
||||
}
|
||||
}
|
||||
|
||||
TyInfer(..) => {
|
||||
bug!("unexpected type `{:?}` in sized_constraint_for_ty",
|
||||
ty)
|
||||
}
|
||||
};
|
||||
debug!("sized_constraint_for_ty({:?}) = {:?}", ty, result);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, 'container> VariantDefData<'tcx, 'container> {
|
||||
|
@ -12,12 +12,19 @@
|
||||
// because of eager normalization:
|
||||
//
|
||||
// proving `M: Sized` requires
|
||||
// - proving `PtrBack<Vec<M>>: Sized` requis
|
||||
// - proving `PtrBack<Vec<M>>: Sized` requires
|
||||
// - normalizing `Vec<<Vec<M> as Front>::Back>>: Sized` requires
|
||||
// - proving `Vec<M>: Front` requires
|
||||
// - `M: Sized` <-- cycle!
|
||||
//
|
||||
// If we skip the normalization step, though, everything goes fine.
|
||||
//
|
||||
// This could be fixed by implementing lazy normalization everywhere.
|
||||
//
|
||||
// However, we want this to work before then. For that, when checking
|
||||
// whether a type is Sized we only check that the tails are Sized. As
|
||||
// PtrBack does not have a tail, we don't need to normalize anything
|
||||
// and this compiles
|
||||
|
||||
trait Front {
|
||||
type Back;
|
||||
|
Loading…
Reference in New Issue
Block a user