From 1e3214ba330c81f93b69ac5f4e3cfee73271e4c4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 1 Jan 2015 17:58:57 -0500 Subject: [PATCH] Normalize the associated types in closure and closure upvar types. --- src/librustc/middle/traits/select.rs | 5 ++ src/librustc/middle/ty.rs | 40 +++++++++++++++- src/librustc/middle/ty_fold.rs | 10 ++++ src/librustc_trans/trans/base.rs | 34 +++++++------- src/librustc_trans/trans/closure.rs | 21 +++++---- src/librustc_trans/trans/common.rs | 60 ++++++++++++++++++++---- src/librustc_trans/trans/debuginfo.rs | 16 +++---- src/librustc_trans/trans/monomorphize.rs | 3 +- 8 files changed, 145 insertions(+), 44 deletions(-) diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index c5ad8c3b230..f9dced088f8 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1781,6 +1781,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { substs.repr(self.tcx())); let closure_type = self.closure_typer.unboxed_closure_type(closure_def_id, substs); + + debug!("confirm_unboxed_closure_candidate: closure_def_id={} closure_type={}", + closure_def_id.repr(self.tcx()), + closure_type.repr(self.tcx())); + let closure_sig = &closure_type.sig; let arguments_tuple = closure_sig.0.inputs[0]; let trait_substs = diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index cea98ff20cd..a83f03c2c16 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -5665,7 +5665,7 @@ pub fn tup_fields<'tcx>(v: &[Ty<'tcx>]) -> Vec> { }).collect() } -#[deriving(Copy)] +#[deriving(Copy, Clone)] pub struct UnboxedClosureUpvar<'tcx> { pub def: def::Def, pub span: Span, @@ -7099,12 +7099,30 @@ pub trait HasProjectionTypes { fn has_projection_types(&self) -> bool; } +impl<'tcx,T:HasProjectionTypes> HasProjectionTypes for Vec { + fn has_projection_types(&self) -> bool { + self.iter().any(|p| p.has_projection_types()) + } +} + impl<'tcx,T:HasProjectionTypes> HasProjectionTypes for VecPerParamSpace { fn has_projection_types(&self) -> bool { self.iter().any(|p| p.has_projection_types()) } } +impl<'tcx> HasProjectionTypes for ClosureTy<'tcx> { + fn has_projection_types(&self) -> bool { + self.sig.has_projection_types() + } +} + +impl<'tcx> HasProjectionTypes for UnboxedClosureUpvar<'tcx> { + fn has_projection_types(&self) -> bool { + self.ty.has_projection_types() + } +} + impl<'tcx> HasProjectionTypes for ty::GenericBounds<'tcx> { fn has_projection_types(&self) -> bool { self.predicates.has_projection_types() @@ -7304,3 +7322,23 @@ impl ReferencesError for Region false } } + +impl<'tcx> Repr<'tcx> for ClosureTy<'tcx> { + fn repr(&self, tcx: &ctxt<'tcx>) -> String { + format!("ClosureTy({},{},{},{},{},{})", + self.unsafety, + self.onceness, + self.store, + self.bounds.repr(tcx), + self.sig.repr(tcx), + self.abi) + } +} + +impl<'tcx> Repr<'tcx> for UnboxedClosureUpvar<'tcx> { + fn repr(&self, tcx: &ctxt<'tcx>) -> String { + format!("UnboxedClosureUpvar({},{})", + self.def.repr(tcx), + self.ty.repr(tcx)) + } +} diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 1e7605c0f17..83d2f6fb0e6 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -532,6 +532,16 @@ impl<'tcx,T,U> TypeFoldable<'tcx> for ty::OutlivesPredicate } } +impl<'tcx> TypeFoldable<'tcx> for ty::UnboxedClosureUpvar<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::UnboxedClosureUpvar<'tcx> { + ty::UnboxedClosureUpvar { + def: self.def, + span: self.span, + ty: self.ty.fold_with(folder), + } + } +} + /////////////////////////////////////////////////////////////////////////// // "super" routines: these are the default implementations for TypeFolder. // diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index b4dac456536..18155d75680 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -43,7 +43,7 @@ use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}; use middle::subst; use middle::weak_lang_items; use middle::subst::{Subst, Substs}; -use middle::ty::{mod, Ty}; +use middle::ty::{mod, Ty, UnboxedClosureTyper}; use session::config::{mod, NoDebugInfo, FullDebugInfo}; use session::Session; use trans::_match; @@ -257,12 +257,12 @@ fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>, } pub fn self_type_for_unboxed_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - closure_id: ast::DefId, - fn_ty: Ty<'tcx>) - -> Ty<'tcx> { - let unboxed_closures = ccx.tcx().unboxed_closures.borrow(); - let unboxed_closure = &(*unboxed_closures)[closure_id]; - match unboxed_closure.kind { + closure_id: ast::DefId, + fn_ty: Ty<'tcx>) + -> Ty<'tcx> +{ + let unboxed_closure_kind = ccx.tcx().unboxed_closure_kind(closure_id); + match unboxed_closure_kind { ty::FnUnboxedClosureKind => { ty::mk_imm_rptr(ccx.tcx(), ccx.tcx().mk_region(ty::ReStatic), fn_ty) } @@ -291,13 +291,15 @@ pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, (f.sig.0.inputs.clone(), f.sig.0.output, f.abi, Some(Type::i8p(ccx))) } ty::ty_unboxed_closure(closure_did, _, substs) => { - let unboxed_closures = ccx.tcx().unboxed_closures.borrow(); - let unboxed_closure = &(*unboxed_closures)[closure_did]; - let function_type = unboxed_closure.closure_type.clone(); + let typer = common::NormalizingUnboxedClosureTyper::new(ccx.tcx()); + let function_type = typer.unboxed_closure_type(closure_did, substs); let self_type = self_type_for_unboxed_closure(ccx, closure_did, fn_ty); let llenvironment_type = type_of_explicit_arg(ccx, self_type); - (function_type.sig.0.inputs.iter().map(|t| t.subst(ccx.tcx(), substs)).collect(), - function_type.sig.0.output.subst(ccx.tcx(), substs), + debug!("decl_rust_fn: function_type={} self_type={}", + function_type.repr(ccx.tcx()), + self_type.repr(ccx.tcx())); + (function_type.sig.0.inputs, + function_type.sig.0.output, RustCall, Some(llenvironment_type)) } @@ -2436,11 +2438,9 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty< ty::ty_closure(ref f) => (f.sig.clone(), f.abi, true), ty::ty_bare_fn(_, ref f) => (f.sig.clone(), f.abi, false), ty::ty_unboxed_closure(closure_did, _, substs) => { - let unboxed_closures = ccx.tcx().unboxed_closures.borrow(); - let ref function_type = (*unboxed_closures)[closure_did] - .closure_type; - - (function_type.sig.subst(ccx.tcx(), substs), RustCall, true) + let typer = common::NormalizingUnboxedClosureTyper::new(ccx.tcx()); + let function_type = typer.unboxed_closure_type(closure_did, substs); + (function_type.sig, RustCall, true) } _ => ccx.sess().bug("expected closure or function.") }; diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index 3723ad07a36..93a5b54fde3 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -22,11 +22,11 @@ use trans::common::*; use trans::datum::{Datum, DatumBlock, Expr, Lvalue, rvalue_scratch_datum}; use trans::debuginfo; use trans::expr; -use trans::monomorphize::MonoId; +use trans::monomorphize::{mod, MonoId}; use trans::type_of::*; use trans::type_::Type; -use middle::ty::{mod, Ty}; -use middle::subst::{Subst, Substs}; +use middle::ty::{mod, Ty, UnboxedClosureTyper}; +use middle::subst::{Substs}; use session::config::FullDebugInfo; use util::ppaux::Repr; use util::ppaux::ty_to_string; @@ -464,7 +464,7 @@ pub fn get_or_create_declaration_if_unboxed_closure<'blk, 'tcx>(bcx: Block<'blk, } let function_type = ty::node_id_to_type(bcx.tcx(), closure_id.node); - let function_type = function_type.subst(bcx.tcx(), substs); + let function_type = monomorphize::apply_param_substs(bcx.tcx(), substs, &function_type); // Normalize type so differences in regions and typedefs don't cause // duplicate declarations @@ -511,7 +511,8 @@ pub fn trans_unboxed_closure<'blk, 'tcx>( body: &ast::Block, id: ast::NodeId, dest: expr::Dest) - -> Block<'blk, 'tcx> { + -> Block<'blk, 'tcx> +{ let _icx = push_ctxt("closure::trans_unboxed_closure"); debug!("trans_unboxed_closure()"); @@ -522,9 +523,13 @@ pub fn trans_unboxed_closure<'blk, 'tcx>( closure_id, bcx.fcx.param_substs).unwrap(); - let function_type = (*bcx.tcx().unboxed_closures.borrow())[closure_id] - .closure_type - .clone(); + // Get the type of this closure. Use the current `param_substs` as + // the closure substitutions. This makes sense because the closure + // takes the same set of type arguments as the enclosing fn, and + // this function (`trans_unboxed_closure`) is invoked at the point + // of the closure expression. + let typer = NormalizingUnboxedClosureTyper::new(bcx.tcx()); + let function_type = typer.unboxed_closure_type(closure_id, bcx.fcx.param_substs); let function_type = ty::mk_closure(bcx.tcx(), function_type); let freevars: Vec = diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 8d1322da635..aa882240880 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -632,7 +632,8 @@ impl<'blk, 'tcx> ty::UnboxedClosureTyper<'tcx> for BlockS<'blk, 'tcx> { def_id: ast::DefId) -> ty::UnboxedClosureKind { - self.tcx().unboxed_closure_kind(def_id) + let typer = NormalizingUnboxedClosureTyper::new(self.tcx()); + typer.unboxed_closure_kind(def_id) } fn unboxed_closure_type(&self, @@ -640,9 +641,8 @@ impl<'blk, 'tcx> ty::UnboxedClosureTyper<'tcx> for BlockS<'blk, 'tcx> { substs: &subst::Substs<'tcx>) -> ty::ClosureTy<'tcx> { - // the substitutions in `substs` are already monomorphized, so we can - // ignore `param_substs` - self.tcx().unboxed_closure_type(def_id, substs) + let typer = NormalizingUnboxedClosureTyper::new(self.tcx()); + typer.unboxed_closure_type(def_id, substs) } fn unboxed_closure_upvars(&self, @@ -650,9 +650,8 @@ impl<'blk, 'tcx> ty::UnboxedClosureTyper<'tcx> for BlockS<'blk, 'tcx> { substs: &Substs<'tcx>) -> Option>> { - // the substitutions in `substs` are already monomorphized, so we can - // ignore `param_substs` - ty::unboxed_closure_upvars(self.tcx(), def_id, substs) + let typer = NormalizingUnboxedClosureTyper::new(self.tcx()); + typer.unboxed_closure_upvars(def_id, substs) } } @@ -948,7 +947,8 @@ 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 mut selcx = traits::SelectionContext::new(&infcx, ¶m_env, tcx); + let typer = NormalizingUnboxedClosureTyper::new(infcx.tcx); + let mut selcx = traits::SelectionContext::new(&infcx, ¶m_env, &typer); let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), trait_ref.to_poly_trait_predicate()); let selection = match selcx.select(&obligation) { @@ -992,6 +992,47 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, vtable } +pub struct NormalizingUnboxedClosureTyper<'a,'tcx:'a> { + tcx: &'a ty::ctxt<'tcx> +} + +impl<'a,'tcx> NormalizingUnboxedClosureTyper<'a,'tcx> { + pub fn new(tcx: &'a ty::ctxt<'tcx>) -> NormalizingUnboxedClosureTyper<'a,'tcx> { + NormalizingUnboxedClosureTyper { tcx: tcx } + } +} + +impl<'a,'tcx> ty::UnboxedClosureTyper<'tcx> for NormalizingUnboxedClosureTyper<'a,'tcx> { + fn unboxed_closure_kind(&self, + def_id: ast::DefId) + -> ty::UnboxedClosureKind + { + self.tcx.unboxed_closure_kind(def_id) + } + + fn unboxed_closure_type(&self, + def_id: ast::DefId, + substs: &subst::Substs<'tcx>) + -> ty::ClosureTy<'tcx> + { + // the substitutions in `substs` are already monomorphized, + // but we still must normalize associated types + let closure_ty = self.tcx.unboxed_closure_type(def_id, substs); + monomorphize::normalize_associated_type(self.tcx, &closure_ty) + } + + fn unboxed_closure_upvars(&self, + def_id: ast::DefId, + substs: &Substs<'tcx>) + -> Option>> + { + // the substitutions in `substs` are already monomorphized, + // but we still must normalize associated types + let result = ty::unboxed_closure_upvars(self.tcx, def_id, substs); + monomorphize::normalize_associated_type(self.tcx, &result) + } +} + pub fn drain_fulfillment_cx<'a,'tcx,T>(span: Span, infcx: &infer::InferCtxt<'a,'tcx>, param_env: &ty::ParameterEnvironment<'tcx>, @@ -1006,7 +1047,8 @@ pub fn drain_fulfillment_cx<'a,'tcx,T>(span: Span, // 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(infcx, param_env, infcx.tcx) { + let typer = NormalizingUnboxedClosureTyper::new(infcx.tcx); + match fulfill_cx.select_all_or_error(infcx, param_env, &typer) { Ok(()) => { } Err(errors) => { if errors.iter().all(|e| e.is_overflow()) { diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index bce446b7412..c651255226b 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -194,13 +194,13 @@ use llvm; use llvm::{ModuleRef, ContextRef, ValueRef}; use llvm::debuginfo::*; use metadata::csearch; -use middle::subst::{mod, Subst, Substs}; +use middle::subst::{mod, Substs}; use trans::{mod, adt, machine, type_of}; use trans::common::*; use trans::_match::{BindingInfo, TrByCopy, TrByMove, TrByRef}; use trans::monomorphize; use trans::type_::Type; -use middle::ty::{mod, Ty}; +use middle::ty::{mod, Ty, UnboxedClosureTyper}; use middle::pat_util; use session::config::{mod, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}; use util::nodemap::{DefIdMap, NodeMap, FnvHashMap, FnvHashSet}; @@ -470,9 +470,9 @@ impl<'tcx> TypeMap<'tcx> { closure_ty.clone(), &mut unique_type_id); }, - ty::ty_unboxed_closure(ref def_id, _, substs) => { - let closure_ty = cx.tcx().unboxed_closures.borrow() - .get(def_id).unwrap().closure_type.subst(cx.tcx(), substs); + ty::ty_unboxed_closure(def_id, _, substs) => { + let typer = NormalizingUnboxedClosureTyper::new(cx.tcx()); + let closure_ty = typer.unboxed_closure_type(def_id, substs); self.get_unique_type_id_of_closure_type(cx, closure_ty, &mut unique_type_id); @@ -3020,9 +3020,9 @@ fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::ty_closure(ref closurety) => { subroutine_type_metadata(cx, unique_type_id, &closurety.sig, usage_site_span) } - ty::ty_unboxed_closure(ref def_id, _, substs) => { - let sig = cx.tcx().unboxed_closures.borrow() - .get(def_id).unwrap().closure_type.sig.subst(cx.tcx(), substs); + ty::ty_unboxed_closure(def_id, _, substs) => { + let typer = NormalizingUnboxedClosureTyper::new(cx.tcx()); + let sig = typer.unboxed_closure_type(def_id, substs).sig; subroutine_type_metadata(cx, unique_type_id, &sig, usage_site_span) } ty::ty_struct(def_id, substs) => { diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 7646aa086eb..7c8ba08d987 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -323,7 +323,8 @@ pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T let infcx = infer::new_infer_ctxt(tcx); let param_env = ty::empty_parameter_environment(); - let mut selcx = traits::SelectionContext::new(&infcx, ¶m_env, tcx); + let typer = NormalizingUnboxedClosureTyper::new(infcx.tcx); + let mut selcx = traits::SelectionContext::new(&infcx, ¶m_env, &typer); let cause = traits::ObligationCause::dummy(); let traits::Normalized { value: result, obligations } = traits::normalize(&mut selcx, cause, value);