From 608ab6bb6a8618c02a6493b60059acaaf014077a Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 10 Jun 2015 04:38:07 +0300 Subject: [PATCH] trans: deanonymize TyAnon types to obtain concrete types. --- src/librustc/middle/infer/mod.rs | 36 ++++++++++++++++-------- src/librustc/middle/traits/project.rs | 20 ++++++++++--- src/librustc/middle/ty.rs | 9 +++++- src/librustc_lint/builtin.rs | 14 ++++++--- src/librustc_trans/trans/_match.rs | 2 +- src/librustc_trans/trans/attributes.rs | 2 +- src/librustc_trans/trans/closure.rs | 4 +-- src/librustc_trans/trans/common.rs | 4 +-- src/librustc_trans/trans/declare.rs | 3 +- src/librustc_trans/trans/monomorphize.rs | 31 ++------------------ 10 files changed, 69 insertions(+), 56 deletions(-) diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index f63154af72426..b752e045f4340 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -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, } @@ -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>) - -> InferCtxt<'a, 'tcx> { +pub fn normalizing_deanynonymizing_infer_ctxt<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>, + tables: &'a RefCell>) + -> InferCtxt<'a, 'tcx> { let mut infcx = new_infer_ctxt(tcx, tables, None, false); infcx.normalize = true; + infcx.deanonymize = true; infcx } @@ -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); @@ -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 } @@ -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>(&self, t: T) -> T { t.fold_with(&mut self.freshener()) } @@ -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 } diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index bd39224df9ee7..3ab433235356a 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -240,10 +240,11 @@ impl<'a,'b,'tcx> AssociatedTypeNormalizer<'a,'b,'tcx> { fn fold + 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() } } } @@ -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 } @@ -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); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index e6f8cfc13d628..f7d709c67b9dc 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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 | @@ -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 @@ -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(); @@ -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) } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index c2d8a5d70bc88..f676ed39be573 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -435,6 +435,12 @@ fn is_repr_nullable_ptr<'tcx>(variants: &Vec>>) -> 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> { @@ -442,7 +448,7 @@ fn ast_ty_to_normalized<'tcx>(tcx: &ty::ctxt<'tcx>, 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> { @@ -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 => {} @@ -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 => {} diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 7d7fd111fe94c..e57b0ee691775 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -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); } diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs index 62b03c9fb0f1f..4210c5b1e8665 100644 --- a/src/librustc_trans/trans/attributes.rs +++ b/src/librustc_trans/trans/attributes.rs @@ -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)) diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index d97872310966b..a62ac095579d8 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -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 = @@ -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. diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 9f65050097ded..19488b0f60705 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -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 = @@ -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(); diff --git a/src/librustc_trans/trans/declare.rs b/src/librustc_trans/trans/declare.rs index 0c77e74be38aa..c462d72efdd53 100644 --- a/src/librustc_trans/trans/declare.rs +++ b/src/librustc_trans/trans/declare.rs @@ -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); diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 13bccf761b4ca..e9f67c16f70d0 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -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; @@ -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>, @@ -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) }