Auto merge of #26677 - jroesch:fulfillment-context-refactor, r=nrc
This patch implements the next chunk of flattening out the type checking context. In a series of patches I moved around the necessary state and logic in order to delete the `Typer` and `ClosureTyper` traits. My next goal is to clean the interfaces and start to move the normalization code behind them. r? @nrc I hope my PR is coherent, doing this too late at night ;)
This commit is contained in:
commit
560b1dab15
54 changed files with 483 additions and 610 deletions
|
|
@ -26,7 +26,6 @@ use metadata::tydecode::{RegionParameter, ClosureSource};
|
|||
use metadata::tyencode;
|
||||
use middle::cast;
|
||||
use middle::check_const::ConstQualif;
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::privacy::{AllPublic, LastMod};
|
||||
use middle::subst;
|
||||
use middle::subst::VecPerParamSpace;
|
||||
|
|
|
|||
|
|
@ -110,14 +110,16 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn with_euv<'b, F, R>(&'b mut self, item_id: Option<ast::NodeId>, f: F) -> R where
|
||||
F: for<'t> FnOnce(&mut euv::ExprUseVisitor<'b, 't, 'tcx,
|
||||
ty::ParameterEnvironment<'a, 'tcx>>) -> R,
|
||||
F: for<'t> FnOnce(&mut euv::ExprUseVisitor<'b, 't, 'b, 'tcx>) -> R,
|
||||
{
|
||||
let param_env = match item_id {
|
||||
Some(item_id) => ty::ParameterEnvironment::for_item(self.tcx, item_id),
|
||||
None => self.tcx.empty_parameter_environment()
|
||||
};
|
||||
f(&mut euv::ExprUseVisitor::new(self, ¶m_env))
|
||||
|
||||
let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, Some(param_env), false);
|
||||
|
||||
f(&mut euv::ExprUseVisitor::new(self, &infcx))
|
||||
}
|
||||
|
||||
fn global_expr(&mut self, mode: Mode, expr: &ast::Expr) -> ConstQualif {
|
||||
|
|
@ -283,11 +285,11 @@ 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, &self.tcx.tables, None);
|
||||
let mut fulfill_cx = traits::FulfillmentContext::new(false);
|
||||
let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None, false);
|
||||
let cause = traits::ObligationCause::new(e.span, e.id, traits::SharedStatic);
|
||||
let mut fulfill_cx = infcx.fulfillment_cx.borrow_mut();
|
||||
fulfill_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause);
|
||||
match fulfill_cx.select_all_or_error(&infcx, &infcx.parameter_environment) {
|
||||
match fulfill_cx.select_all_or_error(&infcx) {
|
||||
Ok(()) => { },
|
||||
Err(ref errors) => {
|
||||
traits::report_fulfillment_errors(&infcx, errors);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ use middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Init};
|
|||
use middle::expr_use_visitor::{JustWrite, LoanCause, MutateMode};
|
||||
use middle::expr_use_visitor::WriteAndRead;
|
||||
use middle::expr_use_visitor as euv;
|
||||
use middle::mem_categorization::{cmt, Typer};
|
||||
use middle::infer;
|
||||
use middle::mem_categorization::{cmt};
|
||||
use middle::pat_util::*;
|
||||
use middle::ty::*;
|
||||
use middle::ty;
|
||||
|
|
@ -1111,7 +1112,12 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
|
|||
match p.node {
|
||||
ast::PatIdent(ast::BindByValue(_), _, ref sub) => {
|
||||
let pat_ty = tcx.node_id_to_type(p.id);
|
||||
if cx.param_env.type_moves_by_default(pat_ty, pat.span) {
|
||||
//FIXME: (@jroesch) this code should be floated up as well
|
||||
let infcx = infer::new_infer_ctxt(cx.tcx,
|
||||
&cx.tcx.tables,
|
||||
Some(cx.param_env.clone()),
|
||||
false);
|
||||
if infcx.type_moves_by_default(pat_ty, pat.span) {
|
||||
check_move(p, sub.as_ref().map(|p| &**p));
|
||||
}
|
||||
}
|
||||
|
|
@ -1139,8 +1145,13 @@ fn check_for_mutation_in_guard<'a, 'tcx>(cx: &'a MatchCheckCtxt<'a, 'tcx>,
|
|||
let mut checker = MutationChecker {
|
||||
cx: cx,
|
||||
};
|
||||
let mut visitor = ExprUseVisitor::new(&mut checker,
|
||||
&checker.cx.param_env);
|
||||
|
||||
let infcx = infer::new_infer_ctxt(cx.tcx,
|
||||
&cx.tcx.tables,
|
||||
Some(checker.cx.param_env.clone()),
|
||||
false);
|
||||
|
||||
let mut visitor = ExprUseVisitor::new(&mut checker, &infcx);
|
||||
visitor.walk_expr(guard);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
// is the public starting point.
|
||||
|
||||
use middle::expr_use_visitor as euv;
|
||||
use middle::infer;
|
||||
use middle::mem_categorization as mc;
|
||||
use middle::ty::ParameterEnvironment;
|
||||
use middle::ty;
|
||||
|
|
@ -38,9 +39,14 @@ impl<'a, 'tcx, 'v> visit::Visitor<'v> for RvalueContext<'a, 'tcx> {
|
|||
s: Span,
|
||||
fn_id: ast::NodeId) {
|
||||
{
|
||||
// FIXME (@jroesch) change this to be an inference context
|
||||
let param_env = ParameterEnvironment::for_item(self.tcx, fn_id);
|
||||
let infcx = infer::new_infer_ctxt(self.tcx,
|
||||
&self.tcx.tables,
|
||||
Some(param_env.clone()),
|
||||
false);
|
||||
let mut delegate = RvalueContextDelegate { tcx: self.tcx, param_env: ¶m_env };
|
||||
let mut euv = euv::ExprUseVisitor::new(&mut delegate, ¶m_env);
|
||||
let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx);
|
||||
euv.walk_fn(fd, b);
|
||||
}
|
||||
visit::walk_fn(self, fk, fd, b, s)
|
||||
|
|
|
|||
|
|
@ -1031,9 +1031,9 @@ 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, &tcx.tables, None);
|
||||
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, false);
|
||||
|
||||
let mut selcx = traits::SelectionContext::new(&infcx, &infcx.parameter_environment);
|
||||
let mut selcx = traits::SelectionContext::new(&infcx);
|
||||
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
|
||||
trait_ref.to_poly_trait_predicate());
|
||||
let selection = match selcx.select(&obligation) {
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ use self::TrackMatchMode::*;
|
|||
use self::OverloadedCallType::*;
|
||||
|
||||
use middle::{def, region, pat_util};
|
||||
use middle::infer;
|
||||
use middle::mem_categorization as mc;
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::ty::{self};
|
||||
use middle::ty::{MethodCall, MethodObject, MethodTraitObject};
|
||||
use middle::ty::{MethodOrigin, MethodParam, MethodTypeParam};
|
||||
|
|
@ -291,9 +291,9 @@ impl OverloadedCallType {
|
|||
// supplies types from the tree. After type checking is complete, you
|
||||
// can just use the tcx as the typer.
|
||||
|
||||
pub struct ExprUseVisitor<'d,'t,'tcx:'t,TYPER:'t> {
|
||||
typer: &'t TYPER,
|
||||
mc: mc::MemCategorizationContext<'t,TYPER>,
|
||||
pub struct ExprUseVisitor<'d,'t,'a: 't, 'tcx:'a> {
|
||||
typer: &'t infer::InferCtxt<'a, 'tcx>,
|
||||
mc: mc::MemCategorizationContext<'t, 'a, 'tcx>,
|
||||
delegate: &'d mut (Delegate<'tcx>+'d),
|
||||
}
|
||||
|
||||
|
|
@ -319,10 +319,10 @@ enum PassArgs {
|
|||
ByRef,
|
||||
}
|
||||
|
||||
impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
||||
impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
|
||||
pub fn new(delegate: &'d mut Delegate<'tcx>,
|
||||
typer: &'t TYPER)
|
||||
-> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
||||
typer: &'t infer::InferCtxt<'a, 'tcx>)
|
||||
-> ExprUseVisitor<'d,'t,'a, 'tcx> {
|
||||
ExprUseVisitor {
|
||||
typer: typer,
|
||||
mc: mc::MemCategorizationContext::new(typer),
|
||||
|
|
@ -355,7 +355,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
}
|
||||
|
||||
fn tcx(&self) -> &'t ty::ctxt<'tcx> {
|
||||
self.typer.tcx()
|
||||
self.typer.tcx
|
||||
}
|
||||
|
||||
fn delegate_consume(&mut self,
|
||||
|
|
@ -690,7 +690,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
match local.init {
|
||||
None => {
|
||||
let delegate = &mut self.delegate;
|
||||
pat_util::pat_bindings(&self.typer.tcx().def_map, &*local.pat,
|
||||
pat_util::pat_bindings(&self.typer.tcx.def_map, &*local.pat,
|
||||
|_, id, span, _| {
|
||||
delegate.decl_without_init(id, span);
|
||||
})
|
||||
|
|
@ -1052,7 +1052,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
let delegate = &mut self.delegate;
|
||||
return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| {
|
||||
if pat_util::pat_is_binding(def_map, pat) {
|
||||
let tcx = typer.tcx();
|
||||
let tcx = typer.tcx;
|
||||
|
||||
debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}",
|
||||
cmt_pat,
|
||||
|
|
@ -1139,7 +1139,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
// the leaves of the pattern tree structure.
|
||||
return_if_err!(mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| {
|
||||
let def_map = def_map.borrow();
|
||||
let tcx = typer.tcx();
|
||||
let tcx = typer.tcx;
|
||||
|
||||
match pat.node {
|
||||
ast::PatEnum(_, _) | ast::PatQPath(..) |
|
||||
|
|
@ -1278,7 +1278,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
}
|
||||
}
|
||||
|
||||
fn copy_or_move<'tcx>(typer: &mc::Typer<'tcx>,
|
||||
fn copy_or_move<'a, 'tcx>(typer: &infer::InferCtxt<'a, 'tcx>,
|
||||
cmt: &mc::cmt<'tcx>,
|
||||
move_reason: MoveReason)
|
||||
-> ConsumeMode
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ pub enum Implication<'tcx> {
|
|||
|
||||
struct Implicator<'a, 'tcx: 'a> {
|
||||
infcx: &'a InferCtxt<'a,'tcx>,
|
||||
closure_typer: &'a (ty::ClosureTyper<'tcx>+'a),
|
||||
body_id: ast::NodeId,
|
||||
stack: Vec<(ty::Region, Option<Ty<'tcx>>)>,
|
||||
span: Span,
|
||||
|
|
@ -46,7 +45,6 @@ struct Implicator<'a, 'tcx: 'a> {
|
|||
/// appear in a context with lifetime `outer_region`
|
||||
pub fn implications<'a,'tcx>(
|
||||
infcx: &'a InferCtxt<'a,'tcx>,
|
||||
closure_typer: &ty::ClosureTyper<'tcx>,
|
||||
body_id: ast::NodeId,
|
||||
ty: Ty<'tcx>,
|
||||
outer_region: ty::Region,
|
||||
|
|
@ -60,8 +58,7 @@ pub fn implications<'a,'tcx>(
|
|||
|
||||
let mut stack = Vec::new();
|
||||
stack.push((outer_region, None));
|
||||
let mut wf = Implicator { closure_typer: closure_typer,
|
||||
infcx: infcx,
|
||||
let mut wf = Implicator { infcx: infcx,
|
||||
body_id: body_id,
|
||||
span: span,
|
||||
stack: stack,
|
||||
|
|
@ -404,7 +401,6 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
|
|||
{
|
||||
let value =
|
||||
traits::fully_normalize(self.infcx,
|
||||
self.closure_typer,
|
||||
traits::ObligationCause::misc(self.span, self.body_id),
|
||||
value);
|
||||
match value {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@ use middle::region::CodeExtent;
|
|||
use middle::subst;
|
||||
use middle::subst::Substs;
|
||||
use middle::subst::Subst;
|
||||
use middle::traits;
|
||||
use middle::traits::{self, FulfillmentContext, Normalized,
|
||||
SelectionContext, ObligationCause};
|
||||
use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, UnconstrainedNumeric};
|
||||
use middle::ty::{self, Ty, HasTypeFlags};
|
||||
use middle::ty_fold::{self, TypeFolder, TypeFoldable};
|
||||
|
|
@ -39,7 +40,7 @@ use std::cell::{RefCell, Ref};
|
|||
use std::fmt;
|
||||
use syntax::ast;
|
||||
use syntax::codemap;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::codemap::{Span, DUMMY_SP};
|
||||
use util::nodemap::{FnvHashMap, NodeMap};
|
||||
|
||||
use self::combine::CombineFields;
|
||||
|
|
@ -87,6 +88,8 @@ pub struct InferCtxt<'a, 'tcx: 'a> {
|
|||
|
||||
pub parameter_environment: ty::ParameterEnvironment<'a, 'tcx>,
|
||||
|
||||
pub fulfillment_cx: RefCell<traits::FulfillmentContext<'tcx>>,
|
||||
|
||||
// This is a temporary field used for toggling on normalization in the inference context,
|
||||
// as we move towards the approach described here:
|
||||
// https://internals.rust-lang.org/t/flattening-the-contexts-for-fun-and-profit/2293
|
||||
|
|
@ -327,9 +330,16 @@ pub fn fixup_err_to_string(f: fixup_err) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
/// errors_will_be_reported is required to proxy to the fulfillment context
|
||||
/// FIXME -- a better option would be to hold back on modifying
|
||||
/// the global cache until we know that all dependent obligations
|
||||
/// are also satisfied. In that case, we could actually remove
|
||||
/// this boolean flag, and we'd also avoid the problem of squelching
|
||||
/// duplicate errors that occur across fns.
|
||||
pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>,
|
||||
tables: &'a RefCell<ty::Tables<'tcx>>,
|
||||
param_env: Option<ty::ParameterEnvironment<'a, 'tcx>>)
|
||||
param_env: Option<ty::ParameterEnvironment<'a, 'tcx>>,
|
||||
errors_will_be_reported: bool)
|
||||
-> InferCtxt<'a, 'tcx> {
|
||||
InferCtxt {
|
||||
tcx: tcx,
|
||||
|
|
@ -339,11 +349,20 @@ pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>,
|
|||
float_unification_table: RefCell::new(UnificationTable::new()),
|
||||
region_vars: RegionVarBindings::new(tcx),
|
||||
parameter_environment: param_env.unwrap_or(tcx.empty_parameter_environment()),
|
||||
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new(errors_will_be_reported)),
|
||||
normalize: 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> {
|
||||
let mut infcx = new_infer_ctxt(tcx, tables, None, false);
|
||||
infcx.normalize = true;
|
||||
infcx
|
||||
}
|
||||
|
||||
/// Computes the least upper-bound of `a` and `b`. If this is not possible, reports an error and
|
||||
/// returns ty::err.
|
||||
pub fn common_supertype<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
|
||||
|
|
@ -455,123 +474,145 @@ 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<Ty<'tcx>> {
|
||||
let ty = self.node_ty(id);
|
||||
self.resolve_type_vars_or_error(&ty)
|
||||
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;
|
||||
}
|
||||
|
||||
fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>> {
|
||||
let ty = self.adjust_expr_ty(expr, self.tables.borrow().adjustments.get(&expr.id));
|
||||
self.resolve_type_vars_or_error(&ty)
|
||||
let infcx = new_infer_ctxt(tcx, &tcx.tables, None, true);
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
let result = drain_fulfillment_cx_or_panic(DUMMY_SP, &infcx, &mut fulfill_cx, &result);
|
||||
|
||||
fn node_method_ty(&self, method_call: ty::MethodCall)
|
||||
-> Option<Ty<'tcx>> {
|
||||
self.tables
|
||||
.borrow()
|
||||
.method_map
|
||||
.get(&method_call)
|
||||
.map(|method| method.ty)
|
||||
.map(|ty| self.resolve_type_vars_if_possible(&ty))
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn node_method_origin(&self, method_call: ty::MethodCall)
|
||||
-> Option<ty::MethodOrigin<'tcx>>
|
||||
{
|
||||
self.tables
|
||||
.borrow()
|
||||
.method_map
|
||||
.get(&method_call)
|
||||
.map(|method| method.origin.clone())
|
||||
}
|
||||
|
||||
fn adjustments(&self) -> Ref<NodeMap<ty::AutoAdjustment<'tcx>>> {
|
||||
fn project_adjustments<'a, 'tcx>(tables: &'a ty::Tables<'tcx>)
|
||||
-> &'a NodeMap<ty::AutoAdjustment<'tcx>> {
|
||||
&tables.adjustments
|
||||
pub fn drain_fulfillment_cx_or_panic<'a,'tcx,T>(span: Span,
|
||||
infcx: &InferCtxt<'a,'tcx>,
|
||||
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
|
||||
result: &T)
|
||||
-> T
|
||||
where T : TypeFoldable<'tcx>
|
||||
{
|
||||
match drain_fulfillment_cx(infcx, fulfill_cx, result) {
|
||||
Ok(v) => v,
|
||||
Err(errors) => {
|
||||
infcx.tcx.sess.span_bug(
|
||||
span,
|
||||
&format!("Encountered errors `{:?}` fulfilling during trans",
|
||||
errors));
|
||||
}
|
||||
|
||||
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<CodeExtent> {
|
||||
self.parameter_environment.temporary_scope(rvalue_id)
|
||||
}
|
||||
|
||||
fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
|
||||
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
|
||||
}
|
||||
/// Finishes processes any obligations that remain in the fulfillment
|
||||
/// context, and then "freshens" and returns `result`. This is
|
||||
/// primarily used during normalization and other cases where
|
||||
/// processing the obligations in `fulfill_cx` may cause type
|
||||
/// inference variables that appear in `result` to be unified, and
|
||||
/// hence we need to process those obligations to get the complete
|
||||
/// picture of the type.
|
||||
pub fn drain_fulfillment_cx<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
|
||||
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
|
||||
result: &T)
|
||||
-> Result<T,Vec<traits::FulfillmentError<'tcx>>>
|
||||
where T : TypeFoldable<'tcx>
|
||||
{
|
||||
debug!("drain_fulfillment_cx(result={:?})",
|
||||
result);
|
||||
|
||||
fn closure_kind(&self,
|
||||
def_id: ast::DefId)
|
||||
-> Option<ty::ClosureKind>
|
||||
{
|
||||
self.tables.borrow().closure_kinds.get(&def_id).cloned()
|
||||
}
|
||||
|
||||
fn closure_type(&self,
|
||||
def_id: ast::DefId,
|
||||
substs: &subst::Substs<'tcx>)
|
||||
-> ty::ClosureTy<'tcx>
|
||||
{
|
||||
|
||||
let closure_ty = self.tables
|
||||
.borrow()
|
||||
.closure_tys
|
||||
.get(&def_id)
|
||||
.unwrap()
|
||||
.subst(self.tcx, substs);
|
||||
|
||||
if self.normalize {
|
||||
// NOTE: this flag is currently *always* set to false, we are slowly folding
|
||||
// normalization into this trait and will come back to remove this in the near
|
||||
// future.
|
||||
|
||||
// code from NormalizingClosureTyper:
|
||||
// the substitutions in `substs` are already monomorphized,
|
||||
// but we still must normalize associated types
|
||||
// normalize_associated_type(self.param_env.tcx, &closure_ty)
|
||||
panic!("see issue 26597: fufillment context refactor must occur")
|
||||
} else {
|
||||
closure_ty
|
||||
// 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) {
|
||||
Ok(()) => { }
|
||||
Err(errors) => {
|
||||
return Err(errors);
|
||||
}
|
||||
}
|
||||
|
||||
fn closure_upvars(&self,
|
||||
def_id: ast::DefId,
|
||||
substs: &Substs<'tcx>)
|
||||
-> Option<Vec<ty::ClosureUpvar<'tcx>>>
|
||||
{
|
||||
let result = ty::ctxt::closure_upvars(self, def_id, substs);
|
||||
// Use freshen to simultaneously replace all type variables with
|
||||
// their bindings and replace all regions with 'static. This is
|
||||
// sort of overkill because we do not expect there to be any
|
||||
// unbound type variables, hence no `TyFresh` types should ever be
|
||||
// inserted.
|
||||
Ok(result.fold_with(&mut infcx.freshener()))
|
||||
}
|
||||
|
||||
if self.normalize {
|
||||
// NOTE: this flag is currently *always* set to false, we are slowly folding
|
||||
// normalization into this trait and will come back to remove this in the near
|
||||
// future.
|
||||
/// Returns an equivalent value with all free regions removed (note
|
||||
/// that late-bound regions remain, because they are important for
|
||||
/// subtyping, but they are anonymized and normalized as well). This
|
||||
/// is a stronger, caching version of `ty_fold::erase_regions`.
|
||||
pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T
|
||||
where T : TypeFoldable<'tcx>
|
||||
{
|
||||
let value1 = value.fold_with(&mut RegionEraser(cx));
|
||||
debug!("erase_regions({:?}) = {:?}",
|
||||
value, value1);
|
||||
return value1;
|
||||
|
||||
// code from NormalizingClosureTyper:
|
||||
// the substitutions in `substs` are already monomorphized,
|
||||
// but we still must normalize associated types
|
||||
// monomorphize::normalize_associated_type(self.param_env.tcx, &result)
|
||||
panic!("see issue 26597: fufillment context refactor must occur")
|
||||
} else {
|
||||
result
|
||||
struct RegionEraser<'a, 'tcx: 'a>(&'a ty::ctxt<'tcx>);
|
||||
|
||||
impl<'a, 'tcx> TypeFolder<'tcx> for RegionEraser<'a, 'tcx> {
|
||||
fn tcx(&self) -> &ty::ctxt<'tcx> { self.0 }
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match self.tcx().normalized_cache.borrow().get(&ty).cloned() {
|
||||
None => {}
|
||||
Some(u) => return u
|
||||
}
|
||||
|
||||
let t_norm = ty_fold::super_fold_ty(self, ty);
|
||||
self.tcx().normalized_cache.borrow_mut().insert(ty, t_norm);
|
||||
return t_norm;
|
||||
}
|
||||
|
||||
fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
|
||||
where T : TypeFoldable<'tcx>
|
||||
{
|
||||
let u = self.tcx().anonymize_late_bound_regions(t);
|
||||
ty_fold::super_fold_binder(self, &u)
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: ty::Region) -> ty::Region {
|
||||
// because late-bound regions affect subtyping, we can't
|
||||
// erase the bound/free distinction, but we can replace
|
||||
// all free regions with 'static.
|
||||
//
|
||||
// Note that we *CAN* replace early-bound regions -- the
|
||||
// type system never "sees" those, they get substituted
|
||||
// away. In trans, they will always be erased to 'static
|
||||
// whenever a substitution occurs.
|
||||
match r {
|
||||
ty::ReLateBound(..) => r,
|
||||
_ => ty::ReStatic
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_substs(&mut self,
|
||||
substs: &subst::Substs<'tcx>)
|
||||
-> subst::Substs<'tcx> {
|
||||
subst::Substs { regions: subst::ErasedRegions,
|
||||
types: substs.types.fold_with(self) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1017,7 +1058,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
.map(|method| resolve_ty(method.ty)))
|
||||
}
|
||||
|
||||
pub fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx> {
|
||||
pub fn node_type(&self, id: ast::NodeId) -> Ty<'tcx> {
|
||||
match self.tables.borrow().node_types.get(&id) {
|
||||
Some(&t) => t,
|
||||
// FIXME
|
||||
|
|
@ -1263,6 +1304,109 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
self.equate(true, trace).relate(a, b)
|
||||
}).map(|_| ())
|
||||
}
|
||||
|
||||
pub fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>> {
|
||||
let ty = self.node_type(id);
|
||||
self.resolve_type_vars_or_error(&ty)
|
||||
}
|
||||
|
||||
pub fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>> {
|
||||
let ty = self.adjust_expr_ty(expr, self.tables.borrow().adjustments.get(&expr.id));
|
||||
self.resolve_type_vars_or_error(&ty)
|
||||
}
|
||||
|
||||
pub 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, ty, ty::BoundCopy, span)
|
||||
// FIXME(@jroesch): should be able to use:
|
||||
// ty.moves_by_default(&self.parameter_environment, span)
|
||||
}
|
||||
|
||||
pub fn node_method_ty(&self, method_call: ty::MethodCall)
|
||||
-> Option<Ty<'tcx>> {
|
||||
self.tables
|
||||
.borrow()
|
||||
.method_map
|
||||
.get(&method_call)
|
||||
.map(|method| method.ty)
|
||||
.map(|ty| self.resolve_type_vars_if_possible(&ty))
|
||||
}
|
||||
|
||||
pub fn node_method_origin(&self, method_call: ty::MethodCall)
|
||||
-> Option<ty::MethodOrigin<'tcx>>
|
||||
{
|
||||
self.tables
|
||||
.borrow()
|
||||
.method_map
|
||||
.get(&method_call)
|
||||
.map(|method| method.origin.clone())
|
||||
}
|
||||
|
||||
pub fn adjustments(&self) -> Ref<NodeMap<ty::AutoAdjustment<'tcx>>> {
|
||||
fn project_adjustments<'a, 'tcx>(tables: &'a ty::Tables<'tcx>)
|
||||
-> &'a NodeMap<ty::AutoAdjustment<'tcx>> {
|
||||
&tables.adjustments
|
||||
}
|
||||
|
||||
Ref::map(self.tables.borrow(), project_adjustments)
|
||||
}
|
||||
|
||||
pub fn is_method_call(&self, id: ast::NodeId) -> bool {
|
||||
self.tables.borrow().method_map.contains_key(&ty::MethodCall::expr(id))
|
||||
}
|
||||
|
||||
pub fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<CodeExtent> {
|
||||
self.tcx.region_maps.temporary_scope(rvalue_id)
|
||||
}
|
||||
|
||||
pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
|
||||
self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned()
|
||||
}
|
||||
|
||||
pub fn param_env<'b>(&'b self) -> &'b ty::ParameterEnvironment<'b,'tcx> {
|
||||
&self.parameter_environment
|
||||
}
|
||||
|
||||
pub fn closure_kind(&self,
|
||||
def_id: ast::DefId)
|
||||
-> Option<ty::ClosureKind>
|
||||
{
|
||||
self.tables.borrow().closure_kinds.get(&def_id).cloned()
|
||||
}
|
||||
|
||||
pub fn closure_type(&self,
|
||||
def_id: ast::DefId,
|
||||
substs: &subst::Substs<'tcx>)
|
||||
-> ty::ClosureTy<'tcx>
|
||||
{
|
||||
|
||||
let closure_ty = self.tables
|
||||
.borrow()
|
||||
.closure_tys
|
||||
.get(&def_id)
|
||||
.unwrap()
|
||||
.subst(self.tcx, substs);
|
||||
|
||||
if self.normalize {
|
||||
normalize_associated_type(&self.tcx, &closure_ty)
|
||||
} else {
|
||||
closure_ty
|
||||
}
|
||||
}
|
||||
|
||||
pub fn closure_upvars(&self,
|
||||
def_id: ast::DefId,
|
||||
substs: &Substs<'tcx>)
|
||||
-> Option<Vec<ty::ClosureUpvar<'tcx>>>
|
||||
{
|
||||
let result = ty::ctxt::closure_upvars(self, def_id, substs);
|
||||
|
||||
if self.normalize {
|
||||
normalize_associated_type(&self.tcx, &result)
|
||||
} else {
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeTrace<'tcx> {
|
||||
|
|
|
|||
|
|
@ -110,11 +110,9 @@ use self::LiveNodeKind::*;
|
|||
use self::VarKind::*;
|
||||
|
||||
use middle::def::*;
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::pat_util;
|
||||
use middle::region;
|
||||
use middle::ty;
|
||||
use middle::ty::ClosureTyper;
|
||||
use lint;
|
||||
use util::nodemap::NodeMap;
|
||||
|
||||
|
|
|
|||
|
|
@ -73,17 +73,16 @@ pub use self::categorization::*;
|
|||
use self::Aliasability::*;
|
||||
|
||||
use ast_map;
|
||||
use middle::infer;
|
||||
use middle::check_const;
|
||||
use middle::def;
|
||||
use middle::region;
|
||||
use middle::ty::{self, Ty};
|
||||
use util::nodemap::NodeMap;
|
||||
|
||||
use syntax::ast::{MutImmutable, MutMutable};
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
use std::cell::Ref;
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -255,46 +254,13 @@ impl ast_node for ast::Pat {
|
|||
fn span(&self) -> Span { self.span }
|
||||
}
|
||||
|
||||
pub struct MemCategorizationContext<'t,TYPER:'t> {
|
||||
typer: &'t TYPER
|
||||
}
|
||||
|
||||
impl<'t,TYPER:'t> Copy for MemCategorizationContext<'t,TYPER> {}
|
||||
impl<'t,TYPER:'t> Clone for MemCategorizationContext<'t,TYPER> {
|
||||
fn clone(&self) -> MemCategorizationContext<'t,TYPER> { *self }
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct MemCategorizationContext<'t, 'a: 't, 'tcx : 'a> {
|
||||
pub typer: &'t infer::InferCtxt<'a, 'tcx>,
|
||||
}
|
||||
|
||||
pub type McResult<T> = Result<T, ()>;
|
||||
|
||||
/// The `Typer` trait provides the interface for the mem-categorization
|
||||
/// module to the results of the type check. It can be used to query
|
||||
/// the type assigned to an expression node, to inquire after adjustments,
|
||||
/// and so on.
|
||||
///
|
||||
/// This interface is needed because mem-categorization is used from
|
||||
/// two places: `regionck` and `borrowck`. `regionck` executes before
|
||||
/// type inference is complete, and hence derives types and so on from
|
||||
/// intermediate tables. This also implies that type errors can occur,
|
||||
/// and hence `node_ty()` and friends return a `Result` type -- any
|
||||
/// error will propagate back up through the mem-categorization
|
||||
/// routines.
|
||||
///
|
||||
/// In the borrow checker, in contrast, type checking is complete and we
|
||||
/// know that no errors have occurred, so we simply consult the tcx and we
|
||||
/// can be sure that only `Ok` results will occur.
|
||||
pub trait Typer<'tcx> : ty::ClosureTyper<'tcx> {
|
||||
fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>>;
|
||||
fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>>;
|
||||
fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool;
|
||||
fn node_method_ty(&self, method_call: ty::MethodCall) -> Option<Ty<'tcx>>;
|
||||
fn node_method_origin(&self, method_call: ty::MethodCall)
|
||||
-> Option<ty::MethodOrigin<'tcx>>;
|
||||
fn adjustments(&self) -> Ref<NodeMap<ty::AutoAdjustment<'tcx>>>;
|
||||
fn is_method_call(&self, id: ast::NodeId) -> bool;
|
||||
fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<region::CodeExtent>;
|
||||
fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture>;
|
||||
}
|
||||
|
||||
impl MutabilityCategory {
|
||||
pub fn from_mutbl(m: ast::Mutability) -> MutabilityCategory {
|
||||
let ret = match m {
|
||||
|
|
@ -391,13 +357,13 @@ impl MutabilityCategory {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
||||
pub fn new(typer: &'t TYPER) -> MemCategorizationContext<'t,TYPER> {
|
||||
impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> {
|
||||
pub fn new(typer: &'t infer::InferCtxt<'a, 'tcx>) -> MemCategorizationContext<'t, 'a, 'tcx> {
|
||||
MemCategorizationContext { typer: typer }
|
||||
}
|
||||
|
||||
fn tcx(&self) -> &'t ty::ctxt<'tcx> {
|
||||
self.typer.tcx()
|
||||
fn tcx(&self) -> &'a ty::ctxt<'tcx> {
|
||||
self.typer.tcx
|
||||
}
|
||||
|
||||
fn expr_ty(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>> {
|
||||
|
|
@ -1175,7 +1141,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
}
|
||||
|
||||
pub fn cat_pattern<F>(&self, cmt: cmt<'tcx>, pat: &ast::Pat, mut op: F) -> McResult<()>
|
||||
where F: FnMut(&MemCategorizationContext<'t, TYPER>, cmt<'tcx>, &ast::Pat),
|
||||
where F: FnMut(&MemCategorizationContext<'t, 'a, 'tcx>, cmt<'tcx>, &ast::Pat),
|
||||
{
|
||||
self.cat_pattern_(cmt, pat, &mut op)
|
||||
}
|
||||
|
|
@ -1183,7 +1149,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
// FIXME(#19596) This is a workaround, but there should be a better way to do this
|
||||
fn cat_pattern_<F>(&self, cmt: cmt<'tcx>, pat: &ast::Pat, op: &mut F)
|
||||
-> McResult<()>
|
||||
where F : FnMut(&MemCategorizationContext<'t, TYPER>, cmt<'tcx>, &ast::Pat),
|
||||
where F : FnMut(&MemCategorizationContext<'t, 'a, 'tcx>, cmt<'tcx>, &ast::Pat),
|
||||
{
|
||||
// Here, `cmt` is the categorization for the value being
|
||||
// matched and pat is the pattern it is being matched against.
|
||||
|
|
|
|||
|
|
@ -38,8 +38,7 @@ pub fn overlapping_impls(infcx: &InferCtxt,
|
|||
impl1_def_id,
|
||||
impl2_def_id);
|
||||
|
||||
let param_env = &infcx.tcx.empty_parameter_environment();
|
||||
let selcx = &mut SelectionContext::intercrate(infcx, param_env);
|
||||
let selcx = &mut SelectionContext::intercrate(infcx);
|
||||
infcx.probe(|_| {
|
||||
overlap(selcx, impl1_def_id, impl2_def_id) || overlap(selcx, impl2_def_id, impl1_def_id)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ pub struct FulfillmentContext<'tcx> {
|
|||
// particular node-id).
|
||||
region_obligations: NodeMap<Vec<RegionObligation<'tcx>>>,
|
||||
|
||||
errors_will_be_reported: bool,
|
||||
pub errors_will_be_reported: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -132,7 +132,6 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
|||
/// `projection_ty` again.
|
||||
pub fn normalize_projection_type<'a>(&mut self,
|
||||
infcx: &InferCtxt<'a,'tcx>,
|
||||
typer: &ty::ClosureTyper<'tcx>,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
cause: ObligationCause<'tcx>)
|
||||
-> Ty<'tcx>
|
||||
|
|
@ -144,7 +143,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
|||
|
||||
// FIXME(#20304) -- cache
|
||||
|
||||
let mut selcx = SelectionContext::new(infcx, typer);
|
||||
let mut selcx = SelectionContext::new(infcx);
|
||||
let normalized = project::normalize_projection_type(&mut selcx, projection_ty, cause, 0);
|
||||
|
||||
for obligation in normalized.obligations {
|
||||
|
|
@ -208,11 +207,10 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
|||
}
|
||||
|
||||
pub fn select_all_or_error<'a>(&mut self,
|
||||
infcx: &InferCtxt<'a,'tcx>,
|
||||
typer: &ty::ClosureTyper<'tcx>)
|
||||
infcx: &InferCtxt<'a,'tcx>)
|
||||
-> Result<(),Vec<FulfillmentError<'tcx>>>
|
||||
{
|
||||
try!(self.select_where_possible(infcx, typer));
|
||||
try!(self.select_where_possible(infcx));
|
||||
|
||||
// Anything left is ambiguous.
|
||||
let errors: Vec<FulfillmentError> =
|
||||
|
|
@ -233,20 +231,18 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
|||
/// gaining type information. It'd be equally valid to use `select_where_possible` but it
|
||||
/// results in `O(n^2)` performance (#18208).
|
||||
pub fn select_new_obligations<'a>(&mut self,
|
||||
infcx: &InferCtxt<'a,'tcx>,
|
||||
typer: &ty::ClosureTyper<'tcx>)
|
||||
infcx: &InferCtxt<'a,'tcx>)
|
||||
-> Result<(),Vec<FulfillmentError<'tcx>>>
|
||||
{
|
||||
let mut selcx = SelectionContext::new(infcx, typer);
|
||||
let mut selcx = SelectionContext::new(infcx);
|
||||
self.select(&mut selcx, true)
|
||||
}
|
||||
|
||||
pub fn select_where_possible<'a>(&mut self,
|
||||
infcx: &InferCtxt<'a,'tcx>,
|
||||
typer: &ty::ClosureTyper<'tcx>)
|
||||
infcx: &InferCtxt<'a,'tcx>)
|
||||
-> Result<(),Vec<FulfillmentError<'tcx>>>
|
||||
{
|
||||
let mut selcx = SelectionContext::new(infcx, typer);
|
||||
let mut selcx = SelectionContext::new(infcx);
|
||||
self.select(&mut selcx, false)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -312,7 +312,6 @@ pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>,
|
|||
/// conservative towards *no impl*, which is the opposite of the
|
||||
/// `evaluate` methods).
|
||||
pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
||||
typer: &ty::ClosureTyper<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
bound: ty::BuiltinBound,
|
||||
span: Span)
|
||||
|
|
@ -334,7 +333,7 @@ pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
|||
// Note: we only assume something is `Copy` if we can
|
||||
// *definitively* show that it implements `Copy`. Otherwise,
|
||||
// assume it is move; linear is always ok.
|
||||
match fulfill_cx.select_all_or_error(infcx, typer) {
|
||||
match fulfill_cx.select_all_or_error(infcx) {
|
||||
Ok(()) => {
|
||||
debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} success",
|
||||
ty,
|
||||
|
|
@ -397,8 +396,8 @@ 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, &tcx.tables, Some(elaborated_env));
|
||||
let predicates = match fully_normalize(&infcx, &infcx.parameter_environment, cause,
|
||||
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(elaborated_env), false);
|
||||
let predicates = match fully_normalize(&infcx, cause,
|
||||
&infcx.parameter_environment.caller_bounds) {
|
||||
Ok(predicates) => predicates,
|
||||
Err(errors) => {
|
||||
|
|
@ -429,7 +428,6 @@ pub fn normalize_param_env_or_error<'a,'tcx>(unnormalized_env: ty::ParameterEnvi
|
|||
}
|
||||
|
||||
pub fn fully_normalize<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
|
||||
closure_typer: &ty::ClosureTyper<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
value: &T)
|
||||
-> Result<T, Vec<FulfillmentError<'tcx>>>
|
||||
|
|
@ -437,8 +435,22 @@ pub fn fully_normalize<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
|
|||
{
|
||||
debug!("normalize_param_env(value={:?})", value);
|
||||
|
||||
let mut selcx = &mut SelectionContext::new(infcx, closure_typer);
|
||||
let mut selcx = &mut SelectionContext::new(infcx);
|
||||
// FIXME (@jroesch) ISSUE 26721
|
||||
// I'm not sure if this is a bug or not, needs further investigation.
|
||||
// It appears that by reusing the fulfillment_cx here we incur more
|
||||
// obligations and later trip an asssertion on regionck.rs line 337.
|
||||
//
|
||||
// The two possibilities I see is:
|
||||
// - normalization is not actually fully happening and we
|
||||
// have a bug else where
|
||||
// - we are adding a duplicate bound into the list causing
|
||||
// its size to change.
|
||||
//
|
||||
// I think we should probably land this refactor and then come
|
||||
// back to this is a follow-up patch.
|
||||
let mut fulfill_cx = FulfillmentContext::new(false);
|
||||
|
||||
let Normalized { value: normalized_value, obligations } =
|
||||
project::normalize(selcx, cause, value);
|
||||
debug!("normalize_param_env: normalized_value={:?} obligations={:?}",
|
||||
|
|
@ -447,7 +459,8 @@ pub fn fully_normalize<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
|
|||
for obligation in obligations {
|
||||
fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation);
|
||||
}
|
||||
try!(fulfill_cx.select_all_or_error(infcx, closure_typer));
|
||||
|
||||
try!(fulfill_cx.select_all_or_error(infcx));
|
||||
let resolved_value = infcx.resolve_type_vars_if_possible(&normalized_value);
|
||||
debug!("normalize_param_env: resolved_value={:?}", resolved_value);
|
||||
Ok(resolved_value)
|
||||
|
|
|
|||
|
|
@ -55,8 +55,6 @@ 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
|
||||
/// obligation stack. This ensures that all entries on the stack
|
||||
/// at one time will have the same set of skolemized entries,
|
||||
|
|
@ -244,23 +242,19 @@ enum EvaluationResult<'tcx> {
|
|||
}
|
||||
|
||||
impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>,
|
||||
closure_typer: &'cx ty::ClosureTyper<'tcx>)
|
||||
pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>)
|
||||
-> SelectionContext<'cx, 'tcx> {
|
||||
SelectionContext {
|
||||
infcx: infcx,
|
||||
closure_typer: closure_typer,
|
||||
freshener: infcx.freshener(),
|
||||
intercrate: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>,
|
||||
closure_typer: &'cx ty::ClosureTyper<'tcx>)
|
||||
pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>)
|
||||
-> SelectionContext<'cx, 'tcx> {
|
||||
SelectionContext {
|
||||
infcx: infcx,
|
||||
closure_typer: closure_typer,
|
||||
freshener: infcx.freshener(),
|
||||
intercrate: true,
|
||||
}
|
||||
|
|
@ -275,11 +269,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn param_env(&self) -> &'cx ty::ParameterEnvironment<'cx, 'tcx> {
|
||||
self.closure_typer.param_env()
|
||||
self.infcx.param_env()
|
||||
}
|
||||
|
||||
pub fn closure_typer(&self) -> &'cx (ty::ClosureTyper<'tcx>+'cx) {
|
||||
self.closure_typer
|
||||
pub fn closure_typer(&self) -> &'cx InferCtxt<'cx, 'tcx> {
|
||||
self.infcx
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -1163,7 +1157,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
kind,
|
||||
obligation);
|
||||
|
||||
match self.closure_typer.closure_kind(closure_def_id) {
|
||||
match self.infcx.closure_kind(closure_def_id) {
|
||||
Some(closure_kind) => {
|
||||
debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind);
|
||||
if closure_kind.extends(kind) {
|
||||
|
|
@ -1727,7 +1721,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
return ok_if(Vec::new());
|
||||
}
|
||||
|
||||
match self.closure_typer.closure_upvars(def_id, substs) {
|
||||
match self.infcx.closure_upvars(def_id, substs) {
|
||||
Some(upvars) => ok_if(upvars.iter().map(|c| c.ty).collect()),
|
||||
None => {
|
||||
debug!("assemble_builtin_bound_candidates: no upvar types available yet");
|
||||
|
|
@ -1865,7 +1859,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
ty::TyClosure(def_id, substs) => {
|
||||
assert_eq!(def_id.krate, ast::LOCAL_CRATE);
|
||||
|
||||
match self.closure_typer.closure_upvars(def_id, substs) {
|
||||
match self.infcx.closure_upvars(def_id, substs) {
|
||||
Some(upvars) => {
|
||||
Some(upvars.iter().map(|c| c.ty).collect())
|
||||
}
|
||||
|
|
@ -2844,7 +2838,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
substs: &Substs<'tcx>)
|
||||
-> ty::PolyTraitRef<'tcx>
|
||||
{
|
||||
let closure_type = self.closure_typer.closure_type(closure_def_id, substs);
|
||||
let closure_type = self.infcx.closure_type(closure_def_id, substs);
|
||||
let ty::Binder((trait_ref, _)) =
|
||||
util::closure_trait_ref_and_return_type(self.tcx(),
|
||||
obligation.predicate.def_id(),
|
||||
|
|
|
|||
|
|
@ -52,8 +52,6 @@ use middle::dependency_format;
|
|||
use middle::fast_reject;
|
||||
use middle::free_region::FreeRegionMap;
|
||||
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
|
||||
use middle::mem_categorization as mc;
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::region;
|
||||
use middle::resolve_lifetime;
|
||||
use middle::infer;
|
||||
|
|
@ -2919,11 +2917,14 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
|
|||
-> Result<(),CopyImplementationError> {
|
||||
let tcx = self.tcx;
|
||||
|
||||
// FIXME: (@jroesch) float this code up
|
||||
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(self.clone()), false);
|
||||
|
||||
let did = match self_type.sty {
|
||||
ty::TyStruct(struct_did, substs) => {
|
||||
let fields = tcx.struct_fields(struct_did, substs);
|
||||
for field in &fields {
|
||||
if self.type_moves_by_default(field.mt.ty, span) {
|
||||
if infcx.type_moves_by_default(field.mt.ty, span) {
|
||||
return Err(FieldDoesNotImplementCopy(field.name))
|
||||
}
|
||||
}
|
||||
|
|
@ -2935,7 +2936,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
|
|||
for variant_arg_type in &variant.args {
|
||||
let substd_arg_type =
|
||||
variant_arg_type.subst(tcx, substs);
|
||||
if self.type_moves_by_default(substd_arg_type, span) {
|
||||
if infcx.type_moves_by_default(substd_arg_type, span) {
|
||||
return Err(VariantDoesNotImplementCopy(variant.name))
|
||||
}
|
||||
}
|
||||
|
|
@ -3177,35 +3178,6 @@ impl ClosureKind {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait ClosureTyper<'tcx> {
|
||||
fn tcx(&self) -> &ctxt<'tcx> {
|
||||
self.param_env().tcx
|
||||
}
|
||||
|
||||
fn param_env<'a>(&'a self) -> &'a ty::ParameterEnvironment<'a, 'tcx>;
|
||||
|
||||
/// Is this a `Fn`, `FnMut` or `FnOnce` closure? During typeck,
|
||||
/// returns `None` if the kind of this closure has not yet been
|
||||
/// inferred.
|
||||
fn closure_kind(&self,
|
||||
def_id: ast::DefId)
|
||||
-> Option<ty::ClosureKind>;
|
||||
|
||||
/// Returns the argument/return types of this closure.
|
||||
fn closure_type(&self,
|
||||
def_id: ast::DefId,
|
||||
substs: &subst::Substs<'tcx>)
|
||||
-> ty::ClosureTy<'tcx>;
|
||||
|
||||
/// Returns the set of all upvars and their transformed
|
||||
/// types. During typeck, maybe return `None` if the upvar types
|
||||
/// have not yet been inferred.
|
||||
fn closure_upvars(&self,
|
||||
def_id: ast::DefId,
|
||||
substs: &Substs<'tcx>)
|
||||
-> Option<Vec<ClosureUpvar<'tcx>>>;
|
||||
}
|
||||
|
||||
impl<'tcx> CommonTypes<'tcx> {
|
||||
fn new(arena: &'tcx TypedArena<TyS<'tcx>>,
|
||||
interner: &mut FnvHashMap<InternedTy<'tcx>, Ty<'tcx>>)
|
||||
|
|
@ -4272,7 +4244,8 @@ impl<'tcx> TyS<'tcx> {
|
|||
TyClosure(did, substs) => {
|
||||
// FIXME(#14449): `borrowed_contents` below assumes `&mut` closure.
|
||||
let param_env = cx.empty_parameter_environment();
|
||||
let upvars = param_env.closure_upvars(did, substs).unwrap();
|
||||
let infcx = infer::new_infer_ctxt(cx, &cx.tables, Some(param_env), false);
|
||||
let upvars = infcx.closure_upvars(did, substs).unwrap();
|
||||
TypeContents::union(&upvars, |f| tc_ty(cx, &f.ty, cache))
|
||||
}
|
||||
|
||||
|
|
@ -4400,10 +4373,10 @@ impl<'tcx> TyS<'tcx> {
|
|||
span: Span)
|
||||
-> bool
|
||||
{
|
||||
let tcx = param_env.tcx();
|
||||
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env.clone()));
|
||||
let tcx = param_env.tcx;
|
||||
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env.clone()), false);
|
||||
|
||||
let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, param_env,
|
||||
let is_impld = traits::type_known_to_meet_builtin_bound(&infcx,
|
||||
self, bound, span);
|
||||
|
||||
debug!("Ty::impls_bound({:?}, {:?}) = {:?}",
|
||||
|
|
@ -4412,7 +4385,8 @@ impl<'tcx> TyS<'tcx> {
|
|||
is_impld
|
||||
}
|
||||
|
||||
fn moves_by_default<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>,
|
||||
// FIXME (@jroesch): I made this public to use it, not sure if should be private
|
||||
pub fn moves_by_default<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>,
|
||||
span: Span) -> bool {
|
||||
if self.flags.get().intersects(TypeFlags::MOVENESS_CACHED) {
|
||||
return self.flags.get().intersects(TypeFlags::MOVES_BY_DEFAULT);
|
||||
|
|
@ -6112,7 +6086,7 @@ impl<'tcx> ctxt<'tcx> {
|
|||
}
|
||||
|
||||
// Returns a list of `ClosureUpvar`s for each upvar.
|
||||
pub fn closure_upvars(typer: &Typer<'tcx>,
|
||||
pub fn closure_upvars<'a>(typer: &infer::InferCtxt<'a, 'tcx>,
|
||||
closure_id: ast::DefId,
|
||||
substs: &Substs<'tcx>)
|
||||
-> Option<Vec<ClosureUpvar<'tcx>>>
|
||||
|
|
@ -6123,7 +6097,7 @@ impl<'tcx> ctxt<'tcx> {
|
|||
// This may change if abstract return types of some sort are
|
||||
// implemented.
|
||||
assert!(closure_id.krate == ast::LOCAL_CRATE);
|
||||
let tcx = typer.tcx();
|
||||
let tcx = typer.tcx;
|
||||
match tcx.freevars.borrow().get(&closure_id.node) {
|
||||
None => Some(vec![]),
|
||||
Some(ref freevars) => {
|
||||
|
|
@ -6711,79 +6685,6 @@ impl<'tcx> ctxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a,'tcx> Typer<'tcx> for ParameterEnvironment<'a,'tcx> {
|
||||
fn node_ty(&self, id: ast::NodeId) -> mc::McResult<Ty<'tcx>> {
|
||||
Ok(self.tcx.node_id_to_type(id))
|
||||
}
|
||||
|
||||
fn expr_ty_adjusted(&self, expr: &ast::Expr) -> mc::McResult<Ty<'tcx>> {
|
||||
Ok(self.tcx.expr_ty_adjusted(expr))
|
||||
}
|
||||
|
||||
fn node_method_ty(&self, method_call: ty::MethodCall) -> Option<Ty<'tcx>> {
|
||||
self.tcx.tables.borrow().method_map.get(&method_call).map(|method| method.ty)
|
||||
}
|
||||
|
||||
fn node_method_origin(&self, method_call: ty::MethodCall)
|
||||
-> Option<ty::MethodOrigin<'tcx>>
|
||||
{
|
||||
self.tcx.tables.borrow().method_map.get(&method_call).map(|method| method.origin.clone())
|
||||
}
|
||||
|
||||
fn adjustments(&self) -> Ref<NodeMap<ty::AutoAdjustment<'tcx>>> {
|
||||
fn projection<'a, 'tcx>(tables: &'a Tables<'tcx>) -> &'a NodeMap<ty::AutoAdjustment<'tcx>> {
|
||||
&tables.adjustments
|
||||
}
|
||||
|
||||
Ref::map(self.tcx.tables.borrow(), projection)
|
||||
}
|
||||
|
||||
fn is_method_call(&self, id: ast::NodeId) -> bool {
|
||||
self.tcx.is_method_call(id)
|
||||
}
|
||||
|
||||
fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<region::CodeExtent> {
|
||||
self.tcx.region_maps.temporary_scope(rvalue_id)
|
||||
}
|
||||
|
||||
fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
|
||||
self.tcx.upvar_capture(upvar_id)
|
||||
}
|
||||
|
||||
fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool {
|
||||
ty.moves_by_default(self, span)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'tcx> ClosureTyper<'tcx> for ty::ParameterEnvironment<'a,'tcx> {
|
||||
fn param_env<'b>(&'b self) -> &'b ty::ParameterEnvironment<'b,'tcx> {
|
||||
self
|
||||
}
|
||||
|
||||
fn closure_kind(&self,
|
||||
def_id: ast::DefId)
|
||||
-> Option<ty::ClosureKind>
|
||||
{
|
||||
Some(self.tcx.closure_kind(def_id))
|
||||
}
|
||||
|
||||
fn closure_type(&self,
|
||||
def_id: ast::DefId,
|
||||
substs: &subst::Substs<'tcx>)
|
||||
-> ty::ClosureTy<'tcx>
|
||||
{
|
||||
self.tcx.closure_type(def_id, substs)
|
||||
}
|
||||
|
||||
fn closure_upvars(&self,
|
||||
def_id: ast::DefId,
|
||||
substs: &Substs<'tcx>)
|
||||
-> Option<Vec<ClosureUpvar<'tcx>>> {
|
||||
ctxt::closure_upvars(self, def_id, substs)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// The category of explicit self.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub enum ExplicitSelfCategory {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue