move make_query_response
into method on infcx
This commit is contained in:
parent
a1811cef76
commit
dfd33f5932
@ -17,11 +17,16 @@
|
||||
//!
|
||||
//! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html
|
||||
|
||||
use infer::canonical::{Canonical, CanonicalVarValues, QueryRegionConstraint, QueryResult};
|
||||
use infer::canonical::substitute::substitute_value;
|
||||
use infer::canonical::{
|
||||
Canonical, CanonicalVarValues, Canonicalize, Certainty, QueryRegionConstraint, QueryResult,
|
||||
};
|
||||
use infer::region_constraints::{Constraint, RegionConstraintData};
|
||||
use infer::{InferCtxt, InferOk, InferResult};
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use std::fmt::Debug;
|
||||
use traits::query::NoSolution;
|
||||
use traits::{FulfillmentContext, TraitEngine};
|
||||
use traits::{Obligation, ObligationCause, PredicateObligation};
|
||||
use ty::fold::TypeFoldable;
|
||||
use ty::subst::{Kind, UnpackedKind};
|
||||
@ -29,7 +34,131 @@ use ty::{self, CanonicalVar};
|
||||
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
|
||||
type CanonicalizedQueryResult<'gcx, 'tcx, T> =
|
||||
<QueryResult<'tcx, T> as Canonicalize<'gcx, 'tcx>>::Canonicalized;
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
||||
/// This method is meant to be invoked as the final step of a canonical query
|
||||
/// implementation. It is given:
|
||||
///
|
||||
/// - the instantiated variables `inference_vars` created from the query key
|
||||
/// - the result `answer` of the query
|
||||
/// - a fulfillment context `fulfill_cx` that may contain various obligations which
|
||||
/// have yet to be proven.
|
||||
///
|
||||
/// Given this, the function will process the obligations pending
|
||||
/// in `fulfill_cx`:
|
||||
///
|
||||
/// - If all the obligations can be proven successfully, it will
|
||||
/// package up any resulting region obligations (extracted from
|
||||
/// `infcx`) along with the fully resolved value `answer` into a
|
||||
/// query result (which is then itself canonicalized).
|
||||
/// - If some obligations can be neither proven nor disproven, then
|
||||
/// the same thing happens, but the resulting query is marked as ambiguous.
|
||||
/// - Finally, if any of the obligations result in a hard error,
|
||||
/// then `Err(NoSolution)` is returned.
|
||||
pub fn make_canonicalized_query_result<T>(
|
||||
&self,
|
||||
inference_vars: CanonicalVarValues<'tcx>,
|
||||
answer: T,
|
||||
fulfill_cx: &mut FulfillmentContext<'tcx>,
|
||||
) -> Result<CanonicalizedQueryResult<'gcx, 'tcx, T>, NoSolution>
|
||||
where
|
||||
T: Debug,
|
||||
QueryResult<'tcx, T>: Canonicalize<'gcx, 'tcx>,
|
||||
{
|
||||
let tcx = self.tcx;
|
||||
|
||||
debug!(
|
||||
"make_query_response(\
|
||||
inference_vars={:?}, \
|
||||
answer={:?})",
|
||||
inference_vars, answer,
|
||||
);
|
||||
|
||||
// Select everything, returning errors.
|
||||
let true_errors = match fulfill_cx.select_where_possible(self) {
|
||||
Ok(()) => vec![],
|
||||
Err(errors) => errors,
|
||||
};
|
||||
debug!("true_errors = {:#?}", true_errors);
|
||||
|
||||
if !true_errors.is_empty() {
|
||||
// FIXME -- we don't indicate *why* we failed to solve
|
||||
debug!("make_query_response: true_errors={:#?}", true_errors);
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
// Anything left unselected *now* must be an ambiguity.
|
||||
let ambig_errors = match fulfill_cx.select_all_or_error(self) {
|
||||
Ok(()) => vec![],
|
||||
Err(errors) => errors,
|
||||
};
|
||||
debug!("ambig_errors = {:#?}", ambig_errors);
|
||||
|
||||
let region_obligations = self.take_registered_region_obligations();
|
||||
|
||||
let region_constraints = self.with_region_constraints(|region_constraints| {
|
||||
let RegionConstraintData {
|
||||
constraints,
|
||||
verifys,
|
||||
givens,
|
||||
} = region_constraints;
|
||||
|
||||
assert!(verifys.is_empty());
|
||||
assert!(givens.is_empty());
|
||||
|
||||
let mut outlives: Vec<_> = constraints
|
||||
.into_iter()
|
||||
.map(|(k, _)| match *k {
|
||||
// Swap regions because we are going from sub (<=) to outlives
|
||||
// (>=).
|
||||
Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate(
|
||||
tcx.mk_region(ty::ReVar(v2)).into(),
|
||||
tcx.mk_region(ty::ReVar(v1)),
|
||||
),
|
||||
Constraint::VarSubReg(v1, r2) => {
|
||||
ty::OutlivesPredicate(r2.into(), tcx.mk_region(ty::ReVar(v1)))
|
||||
}
|
||||
Constraint::RegSubVar(r1, v2) => {
|
||||
ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1)
|
||||
}
|
||||
Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1),
|
||||
})
|
||||
.map(ty::Binder::dummy) // no bound regions in the code above
|
||||
.collect();
|
||||
|
||||
outlives.extend(
|
||||
region_obligations
|
||||
.into_iter()
|
||||
.map(|(_, r_o)| ty::OutlivesPredicate(r_o.sup_type.into(), r_o.sub_region))
|
||||
.map(ty::Binder::dummy), // no bound regions in the code above
|
||||
);
|
||||
|
||||
outlives
|
||||
});
|
||||
|
||||
let certainty = if ambig_errors.is_empty() {
|
||||
Certainty::Proven
|
||||
} else {
|
||||
Certainty::Ambiguous
|
||||
};
|
||||
|
||||
let (canonical_result, _) = self.canonicalize_response(&QueryResult {
|
||||
var_values: inference_vars,
|
||||
region_constraints,
|
||||
certainty,
|
||||
value: answer,
|
||||
});
|
||||
|
||||
debug!(
|
||||
"make_query_response: canonical_result = {:#?}",
|
||||
canonical_result
|
||||
);
|
||||
|
||||
Ok(canonical_result)
|
||||
}
|
||||
|
||||
/// Given the (canonicalized) result to a canonical query,
|
||||
/// instantiates the result so it can be used, plugging in the
|
||||
/// values from the canonical query. (Note that the result may
|
||||
|
@ -8,17 +8,16 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use rustc::infer::canonical::{Canonical, QueryResult};
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::traits::{FulfillmentContext, Normalized, ObligationCause};
|
||||
use rustc::infer::canonical::{Canonical, QueryResult};
|
||||
use rustc::traits::query::dropck_outlives::{DropckOutlivesResult, DtorckConstraint};
|
||||
use rustc::traits::query::{CanonicalTyGoal, NoSolution};
|
||||
use rustc::traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
|
||||
use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt};
|
||||
use rustc::traits::{FulfillmentContext, Normalized, ObligationCause};
|
||||
use rustc::ty::subst::{Subst, Substs};
|
||||
use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt};
|
||||
use rustc::util::nodemap::FxHashSet;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use syntax::codemap::{Span, DUMMY_SP};
|
||||
use util;
|
||||
|
||||
crate fn dropck_outlives<'tcx>(
|
||||
tcx: TyCtxt<'_, 'tcx, 'tcx>,
|
||||
@ -36,7 +35,10 @@ crate fn dropck_outlives<'tcx>(
|
||||
canonical_inference_vars,
|
||||
) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &goal);
|
||||
|
||||
let mut result = DropckOutlivesResult { kinds: vec![], overflows: vec![] };
|
||||
let mut result = DropckOutlivesResult {
|
||||
kinds: vec![],
|
||||
overflows: vec![],
|
||||
};
|
||||
|
||||
// A stack of types left to process. Each round, we pop
|
||||
// something from the stack and invoke
|
||||
@ -135,7 +137,7 @@ crate fn dropck_outlives<'tcx>(
|
||||
|
||||
debug!("dropck_outlives: result = {:#?}", result);
|
||||
|
||||
util::make_query_response(infcx, canonical_inference_vars, result, fulfill_cx)
|
||||
infcx.make_canonicalized_query_result(canonical_inference_vars, result, fulfill_cx)
|
||||
})
|
||||
}
|
||||
|
||||
@ -184,7 +186,8 @@ fn dtorck_constraint_for_ty<'a, 'gcx, 'tcx>(
|
||||
dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ety)
|
||||
}
|
||||
|
||||
ty::TyTuple(tys) => tys.iter()
|
||||
ty::TyTuple(tys) => tys
|
||||
.iter()
|
||||
.map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty))
|
||||
.collect(),
|
||||
|
||||
@ -222,7 +225,10 @@ fn dtorck_constraint_for_ty<'a, 'gcx, 'tcx>(
|
||||
dtorck_types: vec![],
|
||||
overflows: vec![],
|
||||
};
|
||||
debug!("dtorck_constraint: generator {:?} => {:?}", def_id, constraint);
|
||||
debug!(
|
||||
"dtorck_constraint: generator {:?} => {:?}",
|
||||
def_id, constraint
|
||||
);
|
||||
|
||||
Ok(constraint)
|
||||
}
|
||||
@ -291,7 +297,8 @@ crate fn adt_dtorck_constraint<'a, 'tcx>(
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
let mut result = def.all_fields()
|
||||
let mut result = def
|
||||
.all_fields()
|
||||
.map(|field| tcx.type_of(field.did))
|
||||
.map(|fty| dtorck_constraint_for_ty(tcx, span, fty, 0, fty))
|
||||
.collect::<Result<DtorckConstraint, NoSolution>>()?;
|
||||
|
@ -33,7 +33,6 @@ mod dropck_outlives;
|
||||
mod evaluate_obligation;
|
||||
mod normalize_projection_ty;
|
||||
mod normalize_erasing_regions;
|
||||
mod util;
|
||||
pub mod lowering;
|
||||
|
||||
use rustc::ty::query::Providers;
|
||||
|
@ -15,7 +15,6 @@ use rustc::ty::{ParamEnvAnd, TyCtxt};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use syntax::ast::DUMMY_NODE_ID;
|
||||
use syntax_pos::DUMMY_SP;
|
||||
use util;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
crate fn normalize_projection_ty<'tcx>(
|
||||
@ -43,8 +42,7 @@ crate fn normalize_projection_ty<'tcx>(
|
||||
|
||||
// Now that we have fulfilled as much as we can, create a solution
|
||||
// from what we've learned.
|
||||
util::make_query_response(
|
||||
infcx,
|
||||
infcx.make_canonicalized_query_result(
|
||||
canonical_inference_vars,
|
||||
NormalizationResult { normalized_ty: answer },
|
||||
fulfill_cx,
|
||||
|
@ -1,123 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use rustc::infer::InferCtxt;
|
||||
use rustc::infer::canonical::{CanonicalVarValues, Canonicalize, Certainty, QueryResult};
|
||||
use rustc::infer::region_constraints::{Constraint, RegionConstraintData};
|
||||
use rustc::traits::{FulfillmentContext, TraitEngine};
|
||||
use rustc::traits::query::NoSolution;
|
||||
use rustc::ty;
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// The canonicalization form of `QueryResult<'tcx, T>`.
|
||||
type CanonicalizedQueryResult<'gcx, 'tcx, T> =
|
||||
<QueryResult<'tcx, T> as Canonicalize<'gcx, 'tcx>>::Canonicalized;
|
||||
|
||||
crate fn make_query_response<'gcx, 'tcx, T>(
|
||||
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||
inference_vars: CanonicalVarValues<'tcx>,
|
||||
answer: T,
|
||||
fulfill_cx: &mut FulfillmentContext<'tcx>,
|
||||
) -> Result<CanonicalizedQueryResult<'gcx, 'tcx, T>, NoSolution>
|
||||
where
|
||||
T: Debug,
|
||||
QueryResult<'tcx, T>: Canonicalize<'gcx, 'tcx>,
|
||||
{
|
||||
let tcx = infcx.tcx;
|
||||
|
||||
debug!(
|
||||
"make_query_response(\
|
||||
inference_vars={:?}, \
|
||||
answer={:?})",
|
||||
inference_vars, answer,
|
||||
);
|
||||
|
||||
// Select everything, returning errors.
|
||||
let true_errors = match fulfill_cx.select_where_possible(infcx) {
|
||||
Ok(()) => vec![],
|
||||
Err(errors) => errors,
|
||||
};
|
||||
debug!("true_errors = {:#?}", true_errors);
|
||||
|
||||
if !true_errors.is_empty() {
|
||||
// FIXME -- we don't indicate *why* we failed to solve
|
||||
debug!("make_query_response: true_errors={:#?}", true_errors);
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
// Anything left unselected *now* must be an ambiguity.
|
||||
let ambig_errors = match fulfill_cx.select_all_or_error(infcx) {
|
||||
Ok(()) => vec![],
|
||||
Err(errors) => errors,
|
||||
};
|
||||
debug!("ambig_errors = {:#?}", ambig_errors);
|
||||
|
||||
let region_obligations = infcx.take_registered_region_obligations();
|
||||
|
||||
let region_constraints = infcx.with_region_constraints(|region_constraints| {
|
||||
let RegionConstraintData {
|
||||
constraints,
|
||||
verifys,
|
||||
givens,
|
||||
} = region_constraints;
|
||||
|
||||
assert!(verifys.is_empty());
|
||||
assert!(givens.is_empty());
|
||||
|
||||
let mut outlives: Vec<_> = constraints
|
||||
.into_iter()
|
||||
.map(|(k, _)| match *k {
|
||||
// Swap regions because we are going from sub (<=) to outlives
|
||||
// (>=).
|
||||
Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate(
|
||||
tcx.mk_region(ty::ReVar(v2)).into(),
|
||||
tcx.mk_region(ty::ReVar(v1)),
|
||||
),
|
||||
Constraint::VarSubReg(v1, r2) => {
|
||||
ty::OutlivesPredicate(r2.into(), tcx.mk_region(ty::ReVar(v1)))
|
||||
}
|
||||
Constraint::RegSubVar(r1, v2) => {
|
||||
ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1)
|
||||
}
|
||||
Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1),
|
||||
})
|
||||
.map(ty::Binder::dummy) // no bound regions in the code above
|
||||
.collect();
|
||||
|
||||
outlives.extend(
|
||||
region_obligations
|
||||
.into_iter()
|
||||
.map(|(_, r_o)| ty::OutlivesPredicate(r_o.sup_type.into(), r_o.sub_region))
|
||||
.map(ty::Binder::dummy) // no bound regions in the code above
|
||||
);
|
||||
|
||||
outlives
|
||||
});
|
||||
|
||||
let certainty = if ambig_errors.is_empty() {
|
||||
Certainty::Proven
|
||||
} else {
|
||||
Certainty::Ambiguous
|
||||
};
|
||||
|
||||
let (canonical_result, _) = infcx.canonicalize_response(&QueryResult {
|
||||
var_values: inference_vars,
|
||||
region_constraints,
|
||||
certainty,
|
||||
value: answer,
|
||||
});
|
||||
|
||||
debug!(
|
||||
"make_query_response: canonical_result = {:#?}",
|
||||
canonical_result
|
||||
);
|
||||
|
||||
Ok(canonical_result)
|
||||
}
|
Loading…
Reference in New Issue
Block a user