Skip to content

Commit

Permalink
address review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
arielb1 committed May 3, 2016
1 parent 6fc19ad commit 05f1a05
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 82 deletions.
156 changes: 75 additions & 81 deletions src/librustc/ty/mod.rs
Expand Up @@ -1750,28 +1750,69 @@ 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>>
/// Calculates the Sized-constraint.
///
/// As the Sized-constraint of enums can be a *set* of types,
/// the Sized-constraint may need to be a set also. Because introducing
/// a new type of IVar is currently a complex affair, the Sized-constraint
/// may be a tuple.
///
/// In fact, there are only a few options for the constraint:
/// - `bool`, if the type is always Sized
/// - an obviously-unsized type
/// - a type parameter or projection whose Sizedness can't be known
/// - a tuple of type parameters or projections, if there are multiple
/// such.
/// - a TyError, if a type contained itself. The representability
/// check should catch this case.
fn calculate_sized_constraint_inner(&'tcx self, tcx: &ty::TyCtxt<'tcx>,
stack: &mut Vec<AdtDefMaster<'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() {

let dep_node = DepNode::SizedConstraint(self.did);

if self.sized_constraint.get(dep_node).is_some() {
return;
}

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 tys : Vec<_> =
self.variants.iter().flat_map(|v| {
v.fields.last()
}).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);
assert_eq!(old_ty, tcx.types.err)
}
None => {
debug!("calculate_sized_constraint: {:?} => {:?}", self, ty);
self.sized_constraint.fulfill(dep_node, ty)
}
}
}

Expand All @@ -1780,22 +1821,23 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> {
tcx: &ty::TyCtxt<'tcx>,
stack: &mut Vec<AdtDefMaster<'tcx>>,
ty: Ty<'tcx>
) -> Ty<'tcx> {
) -> Vec<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
vec![]
}

TyStr | TyTrait(..) | TySlice(_) | TyError => {
// these are never sized - return the target type
ty
vec![ty]
}

TyTuple(ref tys) => {
self.sized_constraint_for_tys(tcx, stack, tys.iter().cloned())
tys.last().into_iter().flat_map(|ty| {
self.sized_constraint_for_ty(tcx, stack, ty)
}).collect()
}

TyEnum(adt, substs) | TyStruct(adt, substs) => {
Expand All @@ -1808,13 +1850,19 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> {
.subst(tcx, substs);
debug!("sized_constraint_for_ty({:?}) intermediate = {:?}",
ty, adt_ty);
self.sized_constraint_for_ty(tcx, stack, 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
ty
vec![ty]
}

TyParam(..) => {
Expand All @@ -1824,7 +1872,7 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> {

let sized_trait = match tcx.lang_items.sized_trait() {
Some(x) => x,
_ => return ty
_ => return vec![ty]
};
let sized_predicate = Binder(TraitRef {
def_id: sized_trait,
Expand All @@ -1834,9 +1882,9 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> {
}).to_predicate();
let predicates = tcx.lookup_predicates(self.did).predicates;
if predicates.into_iter().any(|p| p == sized_predicate) {
tcx.types.bool
vec![]
} else {
ty
vec![ty]
}
}

Expand All @@ -1848,60 +1896,6 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> {
debug!("sized_constraint_for_ty({:?}) = {:?}", ty, result);
result
}

/// Calculates the Sized-constraint.
///
/// As the Sized-constraint of enums can be a *set* of types,
/// the Sized-constraint may need to be a set also. Because introducing
/// a new type of IVar is currently a complex affair, the Sized-constraint
/// may be a tuple.
///
/// In fact, there are only a few options for the constraint:
/// - `bool`, if the type is always Sized
/// - an obviously-unsized type
/// - a type parameter or projection whose Sizedness can't be known
/// - a tuple of type parameters or projections, if there are multiple
/// such.
/// - a TyError, if a type contained itself. The representability
/// check should catch this case.
fn calculate_sized_constraint_inner(&'tcx self, tcx: &ty::TyCtxt<'tcx>,
stack: &mut Vec<AdtDefMaster<'tcx>>)
{

let dep_node = DepNode::SizedConstraint(self.did);

if self.sized_constraint.get(dep_node).is_some() {
return;
}

if stack.contains(&self) {
debug!("calculate_sized_constraint: {:?} is recursive", self);
self.sized_constraint.fulfill(dep_node, tcx.types.err);
return;
}

stack.push(self);
let ty = self.sized_constraint_for_tys(
tcx, stack,
self.variants.iter().flat_map(|v| {
v.fields.last()
}).map(|f| f.unsubst_ty())
);

let self_ = stack.pop().unwrap();
assert_eq!(self_, self);

match self.sized_constraint.get(dep_node) {
Some(old_ty) => {
debug!("calculate_sized_constraint: {:?} recurred", self);
assert_eq!(old_ty, tcx.types.err)
}
None => {
debug!("calculate_sized_constraint: {:?} => {:?}", self, ty);
self.sized_constraint.fulfill(dep_node, ty)
}
}
}
}

impl<'tcx, 'container> VariantDefData<'tcx, 'container> {
Expand Down
9 changes: 8 additions & 1 deletion src/test/run-pass/issue-31299.rs
Expand Up @@ -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;
Expand Down

0 comments on commit 05f1a05

Please sign in to comment.