mirror of
https://github.com/rust-lang/rust.git
synced 2026-06-01 22:18:23 +03:00
try harder to preserve regions when doing inference
This is not complete yet, but it is enough to make unsized-tuple-impls work.
This commit is contained in:
@@ -531,9 +531,12 @@ pub(crate) fn suspend_write_lock(&mut self, ptr: MemoryPointer, len: u64,
|
||||
trace!("Releasing {:?} at {:?}", lock.active, lock_lft);
|
||||
// Disable the lock
|
||||
lock.active = NoLock;
|
||||
} else {
|
||||
trace!("Not touching {:?} at {:?} as its not our lock", lock.active, lock_lft);
|
||||
}
|
||||
match suspend {
|
||||
Some(suspend_region) => {
|
||||
trace!("Adding suspension to {:?} at {:?}", lock.active, lock_lft);
|
||||
// We just released this lock, so add a new suspension.
|
||||
// FIXME: Really, if there ever already is a suspension when is_our_lock, or if there is no suspension when !is_our_lock, something is amiss.
|
||||
// But this model is not good enough yet to prevent that.
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use rustc::hir::Mutability;
|
||||
use rustc::hir::Mutability::*;
|
||||
use rustc::mir::{self, ValidationOp, ValidationOperand};
|
||||
use rustc::ty::{self, Ty, TypeFoldable};
|
||||
use rustc::ty::subst::Subst;
|
||||
use rustc::ty::{self, Ty, TypeFoldable, TyCtxt};
|
||||
use rustc::ty::subst::{Substs, Subst};
|
||||
use rustc::traits;
|
||||
use rustc::infer::InferCtxt;
|
||||
use rustc::traits::Reveal;
|
||||
use rustc::infer::TransNormalize;
|
||||
use rustc::middle::region::CodeExtent;
|
||||
|
||||
use super::{
|
||||
@@ -110,6 +111,116 @@ pub(crate) fn end_region(&mut self, ce: CodeExtent) -> EvalResult<'tcx> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn normalize_type_unerased(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
return normalize_associated_type(self.tcx, &ty);
|
||||
|
||||
use syntax::codemap::{Span, DUMMY_SP};
|
||||
|
||||
// We copy a bunch of stuff from rustc/infer/mod.rs to be able to tweak its behavior
|
||||
fn normalize_projections_in<'a, 'gcx, 'tcx, T>(
|
||||
self_: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
value: &T)
|
||||
-> T::Lifted
|
||||
where T: TypeFoldable<'tcx> + ty::Lift<'gcx>
|
||||
{
|
||||
let mut selcx = traits::SelectionContext::new(self_);
|
||||
let cause = traits::ObligationCause::dummy();
|
||||
let traits::Normalized { value: result, obligations } =
|
||||
traits::normalize(&mut selcx, param_env, cause, value);
|
||||
|
||||
debug!("normalize_projections_in: result={:?} obligations={:?}",
|
||||
result, obligations);
|
||||
|
||||
let mut fulfill_cx = traits::FulfillmentContext::new();
|
||||
|
||||
for obligation in obligations {
|
||||
fulfill_cx.register_predicate_obligation(self_, obligation);
|
||||
}
|
||||
|
||||
drain_fulfillment_cx_or_panic(self_, DUMMY_SP, &mut fulfill_cx, &result)
|
||||
}
|
||||
|
||||
fn drain_fulfillment_cx_or_panic<'a, 'gcx, 'tcx, T>(
|
||||
self_: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
span: Span,
|
||||
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
|
||||
result: &T)
|
||||
-> T::Lifted
|
||||
where T: TypeFoldable<'tcx> + ty::Lift<'gcx>
|
||||
{
|
||||
debug!("drain_fulfillment_cx_or_panic()");
|
||||
|
||||
// In principle, we only need to do this so long as `result`
|
||||
// contains unbound type parameters. It could be a slight
|
||||
// optimization to stop iterating early.
|
||||
match fulfill_cx.select_all_or_error(self_) {
|
||||
Ok(()) => { }
|
||||
Err(errors) => {
|
||||
span_bug!(span, "Encountered errors `{:?}` resolving bounds after type-checking",
|
||||
errors);
|
||||
}
|
||||
}
|
||||
|
||||
let result = self_.resolve_type_vars_if_possible(result);
|
||||
let result = self_.tcx.fold_regions(&result, &mut false, |r, _| match *r { ty::ReVar(_) => self_.tcx.types.re_erased, _ => r });
|
||||
|
||||
match self_.tcx.lift_to_global(&result) {
|
||||
Some(result) => result,
|
||||
None => {
|
||||
span_bug!(span, "Uninferred types/regions in `{:?}`", result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait MyTransNormalize<'gcx>: TypeFoldable<'gcx> {
|
||||
fn my_trans_normalize<'a, 'tcx>(&self,
|
||||
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>)
|
||||
-> Self;
|
||||
}
|
||||
|
||||
macro_rules! items { ($($item:item)+) => ($($item)+) }
|
||||
macro_rules! impl_trans_normalize {
|
||||
($lt_gcx:tt, $($ty:ty),+) => {
|
||||
items!($(impl<$lt_gcx> MyTransNormalize<$lt_gcx> for $ty {
|
||||
fn my_trans_normalize<'a, 'tcx>(&self,
|
||||
infcx: &InferCtxt<'a, $lt_gcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>)
|
||||
-> Self {
|
||||
normalize_projections_in(infcx, param_env, self)
|
||||
}
|
||||
})+);
|
||||
}
|
||||
}
|
||||
|
||||
impl_trans_normalize!('gcx,
|
||||
Ty<'gcx>,
|
||||
&'gcx Substs<'gcx>,
|
||||
ty::FnSig<'gcx>,
|
||||
ty::PolyFnSig<'gcx>,
|
||||
ty::ClosureSubsts<'gcx>,
|
||||
ty::PolyTraitRef<'gcx>,
|
||||
ty::ExistentialTraitRef<'gcx>
|
||||
);
|
||||
|
||||
fn normalize_associated_type<'a, 'tcx, T>(self_: TyCtxt<'a, 'tcx, 'tcx>, value: &T) -> T
|
||||
where T: MyTransNormalize<'tcx>
|
||||
{
|
||||
debug!("normalize_associated_type(t={:?})", value);
|
||||
|
||||
let param_env = ty::ParamEnv::empty(Reveal::All);
|
||||
|
||||
if !value.has_projection_types() {
|
||||
return value.clone();
|
||||
}
|
||||
|
||||
self_.infer_ctxt().enter(|infcx| {
|
||||
value.my_trans_normalize(&infcx, param_env)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_variant(
|
||||
&mut self,
|
||||
query: ValidationQuery<'tcx>,
|
||||
@@ -189,14 +300,7 @@ fn try_validate(&mut self, mut query: ValidationQuery<'tcx>, mode: ValidationMod
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// This is essentially a copy of normalize_associated_type, but without erasure
|
||||
if query.ty.has_projection_types() {
|
||||
let param_env = ty::ParamEnv::empty(Reveal::All);
|
||||
let old_ty = query.ty;
|
||||
query.ty = self.tcx.infer_ctxt().enter(move |infcx| {
|
||||
old_ty.trans_normalize(&infcx, param_env)
|
||||
})
|
||||
}
|
||||
query.ty = self.normalize_type_unerased(&query.ty);
|
||||
trace!("{:?} on {:?}", mode, query);
|
||||
|
||||
// Decide whether this type *owns* the memory it covers (like integers), or whether it
|
||||
@@ -215,7 +319,7 @@ fn try_validate(&mut self, mut query: ValidationQuery<'tcx>, mode: ValidationMod
|
||||
// Tracking the same state for locals not backed by memory would just duplicate too
|
||||
// much machinery.
|
||||
// FIXME: We ignore alignment.
|
||||
let (ptr, extra, _aligned) = self.force_allocation(query.lval)?.to_ptr_extra_aligned();
|
||||
let (ptr, extra) = self.force_allocation(query.lval)?.to_ptr_extra_aligned();
|
||||
// Determine the size
|
||||
// FIXME: Can we reuse size_and_align_of_dst for Lvalues?
|
||||
let len = match self.type_size(query.ty)? {
|
||||
|
||||
Reference in New Issue
Block a user