rustc: provide adt_sized_constraint as an on-demand query.
This commit is contained in:
parent
5f13a3b540
commit
2a17b84cbc
|
@ -1695,85 +1695,21 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||||
/// Due to normalization being eager, this applies even if
|
/// Due to normalization being eager, this applies even if
|
||||||
/// the associated type is behind a pointer, e.g. issue #31299.
|
/// the associated type is behind a pointer, e.g. issue #31299.
|
||||||
pub fn sized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
|
pub fn sized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
|
||||||
self.calculate_sized_constraint_inner(tcx.global_tcx(), &mut Vec::new())
|
match queries::adt_sized_constraint::try_get(tcx, DUMMY_SP, self.did) {
|
||||||
}
|
Ok(ty) => ty,
|
||||||
|
Err(_) => {
|
||||||
/// Calculates the Sized-constraint.
|
debug!("adt_sized_constraint: {:?} is recursive", self);
|
||||||
///
|
// This should be reported as an error by `check_representable`.
|
||||||
/// As the Sized-constraint of enums can be a *set* of types,
|
//
|
||||||
/// the Sized-constraint may need to be a set also. Because introducing
|
// Consider the type as Sized in the meanwhile to avoid
|
||||||
/// a new type of IVar is currently a complex affair, the Sized-constraint
|
// further errors.
|
||||||
/// may be a tuple.
|
tcx.types.err
|
||||||
///
|
|
||||||
/// 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(&self,
|
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|
||||||
stack: &mut Vec<DefId>)
|
|
||||||
-> Ty<'tcx>
|
|
||||||
{
|
|
||||||
if let Some(ty) = tcx.maps.adt_sized_constraint.borrow().get(&self.did) {
|
|
||||||
return ty;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Follow the memoization pattern: push the computation of
|
|
||||||
// DepNode::SizedConstraint as our current task.
|
|
||||||
let _task = tcx.dep_graph.in_task(DepNode::SizedConstraint(self.did));
|
|
||||||
|
|
||||||
if stack.contains(&self.did) {
|
|
||||||
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.
|
|
||||||
tcx.maps.adt_sized_constraint.borrow_mut().insert(self.did, tcx.types.err);
|
|
||||||
return tcx.types.err;
|
|
||||||
}
|
|
||||||
|
|
||||||
stack.push(self.did);
|
|
||||||
|
|
||||||
let tys : Vec<_> =
|
|
||||||
self.variants.iter().flat_map(|v| {
|
|
||||||
v.fields.last()
|
|
||||||
}).flat_map(|f| {
|
|
||||||
let ty = tcx.item_type(f.did);
|
|
||||||
self.sized_constraint_for_ty(tcx, stack, ty)
|
|
||||||
}).collect();
|
|
||||||
|
|
||||||
let self_ = stack.pop().unwrap();
|
|
||||||
assert_eq!(self_, self.did);
|
|
||||||
|
|
||||||
let ty = match tys.len() {
|
|
||||||
_ if tys.references_error() => tcx.types.err,
|
|
||||||
0 => tcx.types.bool,
|
|
||||||
1 => tys[0],
|
|
||||||
_ => tcx.intern_tup(&tys[..], false)
|
|
||||||
};
|
|
||||||
|
|
||||||
let old = tcx.maps.adt_sized_constraint.borrow().get(&self.did).cloned();
|
|
||||||
match old {
|
|
||||||
Some(old_ty) => {
|
|
||||||
debug!("calculate_sized_constraint: {:?} recurred", self);
|
|
||||||
assert_eq!(old_ty, tcx.types.err);
|
|
||||||
old_ty
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
debug!("calculate_sized_constraint: {:?} => {:?}", self, ty);
|
|
||||||
tcx.maps.adt_sized_constraint.borrow_mut().insert(self.did, ty);
|
|
||||||
ty
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sized_constraint_for_ty(&self,
|
fn sized_constraint_for_ty(&self,
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
stack: &mut Vec<DefId>,
|
|
||||||
ty: Ty<'tcx>)
|
ty: Ty<'tcx>)
|
||||||
-> Vec<Ty<'tcx>> {
|
-> Vec<Ty<'tcx>> {
|
||||||
let result = match ty.sty {
|
let result = match ty.sty {
|
||||||
|
@ -1791,23 +1727,23 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||||
TyTuple(ref tys, _) => {
|
TyTuple(ref tys, _) => {
|
||||||
match tys.last() {
|
match tys.last() {
|
||||||
None => vec![],
|
None => vec![],
|
||||||
Some(ty) => self.sized_constraint_for_ty(tcx, stack, ty)
|
Some(ty) => self.sized_constraint_for_ty(tcx, ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TyAdt(adt, substs) => {
|
TyAdt(adt, substs) => {
|
||||||
// recursive case
|
// recursive case
|
||||||
let adt_ty =
|
let adt_ty =
|
||||||
adt.calculate_sized_constraint_inner(tcx, stack)
|
adt.sized_constraint(tcx)
|
||||||
.subst(tcx, substs);
|
.subst(tcx, substs);
|
||||||
debug!("sized_constraint_for_ty({:?}) intermediate = {:?}",
|
debug!("sized_constraint_for_ty({:?}) intermediate = {:?}",
|
||||||
ty, adt_ty);
|
ty, adt_ty);
|
||||||
if let ty::TyTuple(ref tys, _) = adt_ty.sty {
|
if let ty::TyTuple(ref tys, _) = adt_ty.sty {
|
||||||
tys.iter().flat_map(|ty| {
|
tys.iter().flat_map(|ty| {
|
||||||
self.sized_constraint_for_ty(tcx, stack, ty)
|
self.sized_constraint_for_ty(tcx, ty)
|
||||||
}).collect()
|
}).collect()
|
||||||
} else {
|
} else {
|
||||||
self.sized_constraint_for_ty(tcx, stack, adt_ty)
|
self.sized_constraint_for_ty(tcx, adt_ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2703,9 +2639,56 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
|
||||||
panic!("associated item not found for def_id: {:?}", def_id);
|
panic!("associated item not found for def_id: {:?}", def_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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 adt_sized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
def_id: DefId)
|
||||||
|
-> Ty<'tcx> {
|
||||||
|
let def = tcx.lookup_adt_def(def_id);
|
||||||
|
|
||||||
|
let tys: Vec<_> = def.variants.iter().flat_map(|v| {
|
||||||
|
v.fields.last()
|
||||||
|
}).flat_map(|f| {
|
||||||
|
let ty = tcx.item_type(f.did);
|
||||||
|
def.sized_constraint_for_ty(tcx, ty)
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
let ty = match tys.len() {
|
||||||
|
_ if tys.references_error() => tcx.types.err,
|
||||||
|
0 => tcx.types.bool,
|
||||||
|
1 => tys[0],
|
||||||
|
_ => tcx.intern_tup(&tys[..], false)
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("adt_sized_constraint: {:?} => {:?}", def, ty);
|
||||||
|
|
||||||
|
ty
|
||||||
|
}
|
||||||
|
|
||||||
pub fn provide(providers: &mut ty::maps::Providers) {
|
pub fn provide(providers: &mut ty::maps::Providers) {
|
||||||
*providers = ty::maps::Providers {
|
*providers = ty::maps::Providers {
|
||||||
associated_item,
|
associated_item,
|
||||||
|
adt_sized_constraint,
|
||||||
|
..*providers
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn provide_extern(providers: &mut ty::maps::Providers) {
|
||||||
|
*providers = ty::maps::Providers {
|
||||||
|
adt_sized_constraint,
|
||||||
..*providers
|
..*providers
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -898,6 +898,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
|
||||||
|
|
||||||
let mut extern_providers = ty::maps::Providers::default();
|
let mut extern_providers = ty::maps::Providers::default();
|
||||||
cstore::provide(&mut extern_providers);
|
cstore::provide(&mut extern_providers);
|
||||||
|
ty::provide_extern(&mut extern_providers);
|
||||||
|
|
||||||
TyCtxt::create_and_enter(sess,
|
TyCtxt::create_and_enter(sess,
|
||||||
local_providers,
|
local_providers,
|
||||||
|
|
Loading…
Reference in New Issue