Skip to content

Commit

Permalink
trans: deanonymize TyAnon types to obtain concrete types.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Aug 3, 2015
1 parent d5cc1d8 commit 608ab6b
Show file tree
Hide file tree
Showing 10 changed files with 69 additions and 56 deletions.
36 changes: 25 additions & 11 deletions src/librustc/middle/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ pub struct InferCtxt<'a, 'tcx: 'a> {
// directly.
normalize: bool,

/// Whether to resolve anonymized types to their concrete values.
/// This can cause inconsistent results or ICEs if used before
/// type-checking finishes processing all the functions.
deanonymize: bool,

err_count_on_creation: usize,
}

Expand Down Expand Up @@ -350,15 +355,17 @@ pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>,
parameter_environment: param_env.unwrap_or(tcx.empty_parameter_environment()),
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new(errors_will_be_reported)),
normalize: false,
deanonymize: false,
err_count_on_creation: tcx.sess.err_count()
}
}

pub fn normalizing_infer_ctxt<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>,
tables: &'a RefCell<ty::Tables<'tcx>>)
-> InferCtxt<'a, 'tcx> {
pub fn normalizing_deanynonymizing_infer_ctxt<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>,
tables: &'a RefCell<ty::Tables<'tcx>>)
-> InferCtxt<'a, 'tcx> {
let mut infcx = new_infer_ctxt(tcx, tables, None, false);
infcx.normalize = true;
infcx.deanonymize = true;
infcx
}

Expand Down Expand Up @@ -473,19 +480,19 @@ pub struct CombinedSnapshot {
region_vars_snapshot: RegionSnapshot,
}

pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
pub fn normalize_associated_type<'a, 'tcx, T>(infcx: &InferCtxt<'a,'tcx>, value: &T) -> T
where T : TypeFoldable<'tcx> + HasTypeFlags
{
debug!("normalize_associated_type(t={:?})", value);

let value = erase_regions(tcx, value);
let value = erase_regions(infcx.tcx, value);

if !value.has_projection_types() {
if !value.has_projection_types() &&
!(infcx.deanonymize && value.has_anonymized_types()) {
return value;
}

let infcx = new_infer_ctxt(tcx, &tcx.tables, None, true);
let mut selcx = traits::SelectionContext::new(&infcx);
let mut selcx = traits::SelectionContext::new(infcx);
let cause = traits::ObligationCause::dummy();
let traits::Normalized { value: result, obligations } =
traits::normalize(&mut selcx, cause, &value);
Expand All @@ -497,10 +504,10 @@ pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
let mut fulfill_cx = infcx.fulfillment_cx.borrow_mut();

for obligation in obligations {
fulfill_cx.register_predicate_obligation(&infcx, obligation);
fulfill_cx.register_predicate_obligation(infcx, obligation);
}

let result = drain_fulfillment_cx_or_panic(DUMMY_SP, &infcx, &mut fulfill_cx, &result);
let result = drain_fulfillment_cx_or_panic(DUMMY_SP, infcx, &mut fulfill_cx, &result);

result
}
Expand Down Expand Up @@ -617,6 +624,10 @@ pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T
}

impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn deanonymize(&self) -> bool {
self.deanonymize
}

pub fn freshen<T:TypeFoldable<'tcx>>(&self, t: T) -> T {
t.fold_with(&mut self.freshener())
}
Expand Down Expand Up @@ -1504,7 +1515,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
.subst(self.tcx, &substs.func_substs);

if self.normalize {
normalize_associated_type(&self.tcx, &closure_ty)
let mut infcx = new_infer_ctxt(self.tcx, self.tables, None, true);
infcx.normalize = true;
infcx.deanonymize = self.deanonymize;
normalize_associated_type(&infcx, &closure_ty)
} else {
closure_ty
}
Expand Down
20 changes: 16 additions & 4 deletions src/librustc/middle/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,10 +240,11 @@ impl<'a,'b,'tcx> AssociatedTypeNormalizer<'a,'b,'tcx> {
fn fold<T:TypeFoldable<'tcx> + HasTypeFlags>(&mut self, value: &T) -> T {
let value = self.selcx.infcx().resolve_type_vars_if_possible(value);

if !value.has_projection_types() {
value.clone()
} else {
if value.has_projection_types() ||
self.selcx.infcx().deanonymize() && value.has_anonymized_types() {
value.fold_with(self)
} else {
value.clone()
}
}
}
Expand Down Expand Up @@ -290,6 +291,16 @@ impl<'a,'b,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'b,'tcx> {
ty
}

ty::TyAnon(def_id, substs, ref data) => {
if self.selcx.infcx().deanonymize() && !data.principal.has_escaping_regions() {
let generic_ty = self.tcx().lookup_item_type(def_id).ty;
let concrete_ty = generic_ty.subst(self.tcx(), substs);
self.fold_ty(concrete_ty)
} else {
ty
}
}

_ => {
ty
}
Expand Down Expand Up @@ -373,7 +384,8 @@ fn opt_normalize_projection_type<'a,'b,'tcx>(
depth,
obligations);

if projected_ty.has_projection_types() {
if projected_ty.has_projection_types() ||
selcx.infcx().deanonymize() && projected_ty.has_anonymized_types() {
let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth);
let normalized_ty = normalizer.fold(&projected_ty);

Expand Down
9 changes: 8 additions & 1 deletion src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1247,10 +1247,11 @@ bitflags! {
const HAS_TY_ERR = 1 << 6,
const HAS_PROJECTION = 1 << 7,
const HAS_TY_CLOSURE = 1 << 8,
const HAS_ANONYMIZED = 1 << 9,

// true if there are "names" of types and regions and so forth
// that are local to a particular fn
const HAS_LOCAL_NAMES = 1 << 9,
const HAS_LOCAL_NAMES = 1 << 10,

const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
TypeFlags::HAS_SELF.bits |
Expand All @@ -1268,6 +1269,7 @@ bitflags! {
TypeFlags::HAS_TY_ERR.bits |
TypeFlags::HAS_PROJECTION.bits |
TypeFlags::HAS_TY_CLOSURE.bits |
TypeFlags::HAS_ANONYMIZED.bits |
TypeFlags::HAS_LOCAL_NAMES.bits,

// Caches for type_is_sized, type_moves_by_default
Expand Down Expand Up @@ -3381,6 +3383,8 @@ impl FlagComputation {
}

&TyAnon(_, substs, box TraitTy { ref principal, ref bounds }) => {
self.add_flags(TypeFlags::HAS_ANONYMIZED);

self.add_substs(substs);

let mut computation = FlagComputation::new();
Expand Down Expand Up @@ -7068,6 +7072,9 @@ pub trait HasTypeFlags {
fn has_projection_types(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_PROJECTION)
}
fn has_anonymized_types(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_ANONYMIZED)
}
fn references_error(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_TY_ERR)
}
Expand Down
14 changes: 10 additions & 4 deletions src/librustc_lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,14 +435,20 @@ fn is_repr_nullable_ptr<'tcx>(variants: &Vec<Rc<ty::VariantInfo<'tcx>>>) -> bool
false
}

fn normalize_associated_type<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>)
-> Ty<'tcx> {
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, true);
infer::normalize_associated_type(&infcx, &ty)
}

fn ast_ty_to_normalized<'tcx>(tcx: &ty::ctxt<'tcx>,
id: ast::NodeId)
-> Ty<'tcx> {
let tty = match tcx.ast_ty_to_ty_cache.borrow().get(&id) {
Some(&t) => t,
None => panic!("ast_ty_to_ty_cache was incomplete after typeck!")
};
infer::normalize_associated_type(tcx, &tty)
normalize_associated_type(tcx, tty)
}

impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
Expand Down Expand Up @@ -484,7 +490,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
}

for field in fields {
let field_ty = infer::normalize_associated_type(cx, &field.mt.ty);
let field_ty = normalize_associated_type(cx, field.mt.ty);
let r = self.check_type_for_ffi(cache, field_ty);
match r {
FfiSafe => {}
Expand Down Expand Up @@ -539,8 +545,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {

// Check the contained variants.
for variant in variants {
for arg in &variant.args {
let arg = infer::normalize_associated_type(cx, arg);
for &arg in &variant.args {
let arg = normalize_associated_type(cx, arg);
let r = self.check_type_for_ffi(cache, arg);
match r {
FfiSafe => {}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1454,7 +1454,7 @@ fn is_discr_reassigned(bcx: Block, discr: &ast::Expr, body: &ast::Expr) -> bool
reassigned: false
};
{
let infcx = infer::normalizing_infer_ctxt(bcx.tcx(), &bcx.tcx().tables);
let infcx = infer::normalizing_deanynonymizing_infer_ctxt(bcx.tcx(), &bcx.tcx().tables);
let mut visitor = euv::ExprUseVisitor::new(&mut rc, &infcx);
visitor.walk_expr(body);
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx
let (fn_sig, abi, env_ty) = match fn_type.sty {
ty::TyBareFn(_, ref f) => (&f.sig, f.abi, None),
ty::TyClosure(closure_did, ref substs) => {
let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables);
let infcx = infer::normalizing_deanynonymizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables);
function_type = infcx.closure_type(closure_did, substs);
let self_type = base::self_type_for_closure(ccx, closure_did, fn_type);
(&function_type.sig, abi::RustCall, Some(self_type))
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_trans/trans/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
// this function (`trans_closure`) is invoked at the point
// of the closure expression.

let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables);
let infcx = infer::normalizing_deanynonymizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables);
let function_type = infcx.closure_type(closure_id, closure_substs);

let freevars: Vec<ty::Freevar> =
Expand Down Expand Up @@ -334,7 +334,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
ccx.tn().val_to_string(llreffn));

let tcx = ccx.tcx();
let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables);
let infcx = infer::normalizing_deanynonymizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables);

// Find a version of the closure type. Substitute static for the
// region since it doesn't really matter.
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_trans/trans/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -949,7 +949,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,

// Do the initial selection for the obligation. This yields the
// shallow result we are looking for -- that is, what specific impl.
let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables);
let infcx = infer::normalizing_deanynonymizing_infer_ctxt(tcx, &tcx.tables);
let mut selcx = traits::SelectionContext::new(&infcx);

let obligation =
Expand Down Expand Up @@ -1010,7 +1010,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
predicates);

let tcx = ccx.tcx();
let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables);
let infcx = infer::normalizing_deanynonymizing_infer_ctxt(tcx, &tcx.tables);
let mut selcx = traits::SelectionContext::new(&infcx);
let mut fulfill_cx = infcx.fulfillment_cx.borrow_mut();
let cause = traits::ObligationCause::dummy();
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_trans/trans/declare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ pub fn declare_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
(&f.sig, f.abi, None)
}
ty::TyClosure(closure_did, ref substs) => {
let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables);
let tcx = ccx.tcx();
let infcx = infer::normalizing_deanynonymizing_infer_ctxt(tcx, &tcx.tables);
function_type = infcx.closure_type(closure_did, substs);
let self_type = base::self_type_for_closure(ccx, closure_did, fn_type);
let llenvironment_type = type_of::type_of_explicit_arg(ccx, self_type);
Expand Down
31 changes: 2 additions & 29 deletions src/librustc_trans/trans/monomorphize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ use llvm;
use middle::infer;
use middle::subst;
use middle::subst::{Subst, Substs};
use middle::traits;
use middle::ty_fold::{TypeFolder, TypeFoldable};
use rustc::ast_map;
use trans::attributes;
Expand All @@ -31,7 +30,6 @@ use syntax::abi;
use syntax::ast;
use syntax::ast_util::local_def;
use syntax::attr;
use syntax::codemap::DUMMY_SP;
use std::hash::{Hasher, Hash, SipHasher};

pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
Expand Down Expand Up @@ -310,31 +308,6 @@ pub fn apply_param_substs<'tcx,T>(tcx: &ty::ctxt<'tcx>,
pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
where T : TypeFoldable<'tcx> + HasTypeFlags
{
debug!("normalize_associated_type(t={:?})", value);

let value = erase_regions(tcx, value);

if !value.has_projection_types() {
return value;
}

// FIXME(#20304) -- cache
let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables);
let mut selcx = traits::SelectionContext::new(&infcx);
let cause = traits::ObligationCause::dummy();
let traits::Normalized { value: result, obligations } =
traits::normalize(&mut selcx, cause, &value);

debug!("normalize_associated_type: result={:?} obligations={:?}",
result,
obligations);

let mut fulfill_cx = infcx.fulfillment_cx.borrow_mut();

for obligation in obligations {
fulfill_cx.register_predicate_obligation(&infcx, obligation);
}
let result = drain_fulfillment_cx_or_panic(DUMMY_SP, &infcx, &mut fulfill_cx, &result);

result
let infcx = infer::normalizing_deanynonymizing_infer_ctxt(tcx, &tcx.tables);
infer::normalize_associated_type(&infcx, value)
}

0 comments on commit 608ab6b

Please sign in to comment.