From 480cd8fe678ddd34c7dc626791deaed2b49a0bda Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Thu, 25 Jun 2015 13:08:10 -0700 Subject: [PATCH] Ground work for replacing the ClosureTyper trait --- src/librustc/middle/check_const.rs | 2 +- src/librustc/middle/const_eval.rs | 2 +- src/librustc/middle/infer/mod.rs | 154 +++++++++++++++++++- src/librustc/middle/traits/mod.rs | 2 +- src/librustc/middle/traits/select.rs | 2 + src/librustc/middle/ty.rs | 3 +- src/librustc_trans/trans/common.rs | 4 +- src/librustc_trans/trans/monomorphize.rs | 2 +- src/librustc_typeck/check/compare_method.rs | 4 +- src/librustc_typeck/check/dropck.rs | 4 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/coherence/mod.rs | 4 +- src/librustc_typeck/coherence/overlap.rs | 2 +- src/librustc_typeck/collect.rs | 2 +- src/librustc_typeck/lib.rs | 2 +- 15 files changed, 170 insertions(+), 21 deletions(-) diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index b156a2c087b..8bbb6ae757f 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -283,7 +283,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { fn check_static_type(&self, e: &ast::Expr) { let ty = self.tcx.node_id_to_type(e.id); - let infcx = infer::new_infer_ctxt(self.tcx, None); + let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None); let mut fulfill_cx = traits::FulfillmentContext::new(false); let cause = traits::ObligationCause::new(e.span, e.id, traits::SharedStatic); fulfill_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause); diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 8f19a6e9e15..a6b7d7f832a 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -1031,7 +1031,7 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, substs: trait_substs }); tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id()); - let infcx = infer::new_infer_ctxt(tcx, None); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None); let mut selcx = traits::SelectionContext::new(&infcx, &infcx.parameter_environment); let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 8e53747e899..7727f6a6470 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -23,19 +23,24 @@ pub use self::freshen::TypeFreshener; pub use self::region_inference::GenericKind; use middle::free_region::FreeRegionMap; +use middle::mem_categorization as mc; +use middle::mem_categorization::McResult; +use middle::region::{self, CodeExtent}; use middle::subst; use middle::subst::Substs; +use middle::subst::Subst; +use middle::traits; use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, UnconstrainedNumeric}; use middle::ty::{self, Ty, HasTypeFlags}; use middle::ty_fold::{self, TypeFolder, TypeFoldable}; use middle::ty_relate::{Relate, RelateResult, TypeRelation}; use rustc_data_structures::unify::{self, UnificationTable}; -use std::cell::{RefCell}; +use std::cell::{RefCell, Ref}; use std::fmt; use syntax::ast; use syntax::codemap; use syntax::codemap::Span; -use util::nodemap::FnvHashMap; +use util::nodemap::{DefIdMap, FnvHashMap, NodeMap}; use self::combine::CombineFields; use self::region_inference::{RegionVarBindings, RegionSnapshot}; @@ -64,6 +69,8 @@ pub type fres = Result; // "fixup result" pub struct InferCtxt<'a, 'tcx: 'a> { pub tcx: &'a ty::ctxt<'tcx>, + pub tables: &'a RefCell>, + // We instantiate UnificationTable with bounds because the // types that might instantiate a general type variable have an // order, represented by its upper and lower bounds. @@ -80,7 +87,9 @@ pub struct InferCtxt<'a, 'tcx: 'a> { pub parameter_environment: ty::ParameterEnvironment<'a, 'tcx>, - // pub tables: &'a RefCell> + normalize: bool, + + err_count_on_creation: usize, } /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized @@ -314,15 +323,19 @@ pub fn fixup_err_to_string(f: fixup_err) -> String { } pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>, + tables: &'a RefCell>, param_env: Option>) -> InferCtxt<'a, 'tcx> { InferCtxt { tcx: tcx, + tables: tables, type_variables: RefCell::new(type_variable::TypeVariableTable::new()), int_unification_table: RefCell::new(UnificationTable::new()), float_unification_table: RefCell::new(UnificationTable::new()), region_vars: RegionVarBindings::new(tcx), - parameter_environment: param_env.unwrap_or(tcx.empty_parameter_environment()) + parameter_environment: param_env.unwrap_or(tcx.empty_parameter_environment()), + normalize: true, + err_count_on_creation: tcx.sess.err_count() } } @@ -437,6 +450,92 @@ pub struct CombinedSnapshot { region_vars_snapshot: RegionSnapshot, } +impl<'a, 'tcx> mc::Typer<'tcx> for InferCtxt<'a, 'tcx> { + fn node_ty(&self, id: ast::NodeId) -> McResult> { + let ty = self.node_ty(id); + self.resolve_type_vars_or_error(&ty) + } + + fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult> { + let ty = self.adjust_expr_ty(expr, self.tables.borrow().adjustments.get(&expr.id)); + self.resolve_type_vars_or_error(&ty) + } + + fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool { + let ty = self.resolve_type_vars_if_possible(&ty); + !traits::type_known_to_meet_builtin_bound(self, self, ty, ty::BoundCopy, span) + } + + fn node_method_ty(&self, method_call: ty::MethodCall) + -> Option> { + self.tables + .borrow() + .method_map + .get(&method_call) + .map(|method| method.ty) + .map(|ty| self.resolve_type_vars_if_possible(&ty)) + } + + fn node_method_origin(&self, method_call: ty::MethodCall) + -> Option> + { + self.tables + .borrow() + .method_map + .get(&method_call) + .map(|method| method.origin.clone()) + } + + fn adjustments(&self) -> Ref>> { + fn project_adjustments<'a, 'tcx>(tables: &'a ty::Tables<'tcx>) -> &'a NodeMap> { + &tables.adjustments + } + + Ref::map(self.tables.borrow(), project_adjustments) + } + + fn is_method_call(&self, id: ast::NodeId) -> bool { + self.tables.borrow().method_map.contains_key(&ty::MethodCall::expr(id)) + } + + fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option { + self.parameter_environment.temporary_scope(rvalue_id) + } + + fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option { + self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned() + } +} + +impl<'a, 'tcx> ty::ClosureTyper<'tcx> for InferCtxt<'a, 'tcx> { + fn param_env<'b>(&'b self) -> &'b ty::ParameterEnvironment<'b,'tcx> { + &self.parameter_environment + } + + fn closure_kind(&self, + def_id: ast::DefId) + -> Option + { + self.tables.borrow().closure_kinds.get(&def_id).cloned() + } + + fn closure_type(&self, + def_id: ast::DefId, + substs: &subst::Substs<'tcx>) + -> ty::ClosureTy<'tcx> + { + self.tables.borrow().closure_tys.get(&def_id).unwrap().subst(self.tcx, substs) + } + + fn closure_upvars(&self, + def_id: ast::DefId, + substs: &Substs<'tcx>) + -> Option>> + { + ty::ctxt::closure_upvars(self, def_id, substs) + } +} + impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn freshen>(&self, t: T) -> T { t.fold_with(&mut self.freshener()) @@ -858,6 +957,48 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.region_vars.new_bound(debruijn) } + /// Apply `adjustment` to the type of `expr` + pub fn adjust_expr_ty(&self, + expr: &ast::Expr, + adjustment: Option<&ty::AutoAdjustment<'tcx>>) + -> Ty<'tcx> + { + let raw_ty = self.expr_ty(expr); + let raw_ty = self.shallow_resolve(raw_ty); + let resolve_ty = |ty: Ty<'tcx>| self.resolve_type_vars_if_possible(&ty); + raw_ty.adjust(self.tcx, + expr.span, + expr.id, + adjustment, + |method_call| self.tables + .borrow() + .method_map + .get(&method_call) + .map(|method| resolve_ty(method.ty))) + } + + pub fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx> { + match self.tables.borrow().node_types.get(&id) { + Some(&t) => t, + // FIXME + None if self.tcx.sess.err_count() - self.err_count_on_creation != 0 => self.tcx.types.err, + None => { + self.tcx.sess.bug( + &format!("no type for node {}: {} in fcx", + id, self.tcx.map.node_to_string(id))); + } + } + } + + pub fn expr_ty(&self, ex: &ast::Expr) -> Ty<'tcx> { + match self.tables.borrow().node_types.get(&ex.id) { + Some(&t) => t, + None => { + self.tcx.sess.bug(&format!("no type for expr in fcx")); + } + } + } + pub fn resolve_regions_and_report_errors(&self, free_regions: &FreeRegionMap, subject_node_id: ast::NodeId) { @@ -932,6 +1073,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { value.fold_with(&mut r) } + fn resolve_type_vars_or_error(&self, t: &Ty<'tcx>) -> mc::McResult> { + let ty = self.resolve_type_vars_if_possible(t); + if ty.has_infer_types() || ty.references_error() { Err(()) } else { Ok(ty) } + } + pub fn fully_resolve>(&self, value: &T) -> fres { /*! * Attempts to resolve all type/region variables in diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index eb839eade14..69b9762b7b9 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -397,7 +397,7 @@ pub fn normalize_param_env_or_error<'a,'tcx>(unnormalized_env: ty::ParameterEnvi let elaborated_env = unnormalized_env.with_caller_bounds(predicates); - let infcx = infer::new_infer_ctxt(tcx, Some(elaborated_env)); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(elaborated_env)); let predicates = match fully_normalize(&infcx, &infcx.parameter_environment, cause, &infcx.parameter_environment.caller_bounds) { Ok(predicates) => predicates, diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 01faa6b7cf7..ae15c8aa8e0 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -54,6 +54,7 @@ use util::nodemap::FnvHashMap; pub struct SelectionContext<'cx, 'tcx:'cx> { infcx: &'cx InferCtxt<'cx, 'tcx>, + closure_typer: &'cx (ty::ClosureTyper<'tcx>+'cx), /// Freshener used specifically for skolemizing entries on the @@ -77,6 +78,7 @@ pub struct SelectionContext<'cx, 'tcx:'cx> { /// other words, we consider `$0 : Bar` to be unimplemented if /// there is no type that the user could *actually name* that /// would satisfy it. This avoids crippling inference, basically. + intercrate: bool, } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index cdf7f6ef9b6..7616879d102 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4468,7 +4468,8 @@ impl<'tcx> TyS<'tcx> { span: Span) -> bool { - let infcx = infer::new_infer_ctxt(param_env.tcx(), Some(param_env.clone())); + let tcx = param_env.tcx(); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env.clone())); let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, param_env, self, bound, span); diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index dc8c9242961..c549d8cd22d 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -997,7 +997,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, trait_ref, trait_ref.def_id()); tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id()); - let infcx = infer::new_infer_ctxt(tcx, None); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None); // Do the initial selection for the obligation. This yields the // shallow result we are looking for -- that is, what specific impl. @@ -1059,7 +1059,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, predicates); let tcx = ccx.tcx(); - let infcx = infer::new_infer_ctxt(tcx, None); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None); let typer = NormalizingClosureTyper::new(tcx); let mut selcx = traits::SelectionContext::new(&infcx, &typer); let mut fulfill_cx = traits::FulfillmentContext::new(false); diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index fa992511cc1..67ccf64621a 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -324,7 +324,7 @@ pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T // FIXME(#20304) -- cache // NOTE: @jroesch // Here is of an example where we do not use a param_env but use a typer instead. - let infcx = infer::new_infer_ctxt(tcx, None); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None); let typer = NormalizingClosureTyper::new(tcx); let mut selcx = traits::SelectionContext::new(&infcx, &typer); let cause = traits::ObligationCause::dummy(); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index dc8ef46a7ba..85f4fdc8932 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -43,7 +43,7 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, debug!("compare_impl_method: impl_trait_ref (liberated) = {:?}", impl_trait_ref); - let mut infcx = infer::new_infer_ctxt(tcx, None); + let mut infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None); let mut fulfillment_cx = traits::FulfillmentContext::new(true); let trait_to_impl_substs = &impl_trait_ref.substs; @@ -418,7 +418,7 @@ pub fn compare_const_impl<'tcx>(tcx: &ty::ctxt<'tcx>, debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref); - let infcx = infer::new_infer_ctxt(tcx, None); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None); let mut fulfillment_cx = traits::FulfillmentContext::new(true); // The below is for the most part highly similar to the procedure diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 4abfd84d8ef..6f0fbfebf46 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -93,8 +93,8 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( ty: named_type } = tcx.lookup_item_type(self_type_did); - let infcx = infer::new_infer_ctxt(tcx, None); - + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None); + infcx.commit_if_ok(|snapshot| { let (named_type_to_skolem, skol_map) = infcx.construct_skolemized_subst(named_type_generics, snapshot); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 058cbe020b7..e91be5fa9df 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -382,7 +382,7 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> { -> Inherited<'a, 'tcx> { Inherited { - infcx: infer::new_infer_ctxt(tcx, Some(param_env)), + infcx: infer::new_infer_ctxt(tcx, tables, Some(param_env)), locals: RefCell::new(NodeMap()), tables: tables, fn_sig_map: RefCell::new(NodeMap()), diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 5441f0b6772..af2c3a32150 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -448,7 +448,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (free)", source, target); - let infcx = new_infer_ctxt(tcx, Some(param_env)); + let infcx = new_infer_ctxt(tcx, &tcx.tables, Some(param_env)); let check_mutbl = |mt_a: ty::mt<'tcx>, mt_b: ty::mt<'tcx>, mk_ptr: &Fn(Ty<'tcx>) -> Ty<'tcx>| { @@ -630,7 +630,7 @@ fn subst_receiver_types_in_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, pub fn check_coherence(crate_context: &CrateCtxt) { CoherenceChecker { crate_context: crate_context, - inference_context: new_infer_ctxt(crate_context.tcx, None), + inference_context: new_infer_ctxt(crate_context.tcx, &crate_context.tcx.tables, None), inherent_impls: RefCell::new(FnvHashMap()), }.check(crate_context.tcx.map.krate()); unsafety::check(crate_context.tcx); diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index a851bb93e3f..3495714fcc7 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -133,7 +133,7 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { impl1_def_id, impl2_def_id); - let infcx = infer::new_infer_ctxt(self.tcx, None); + let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None); if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) { self.report_overlap_error(trait_def_id, impl1_def_id, impl2_def_id); } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 3e2a88e1f79..ef9dcd56a57 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2204,7 +2204,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( base_type, base_type_free); - let infcx = infer::new_infer_ctxt(tcx, None); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None); drop(::require_same_types(tcx, Some(&infcx), false, diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 5d589d2ec78..48a64675c70 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -188,7 +188,7 @@ fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>, { let result = match maybe_infcx { None => { - let infcx = infer::new_infer_ctxt(tcx, None); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None); infer::mk_eqty(&infcx, t1_is_expected, infer::Misc(span), t1, t2) } Some(infcx) => {