move make_query_response into method on infcx

This commit is contained in:
Niko Matsakis 2018-06-08 09:29:41 -04:00
parent a1811cef76
commit dfd33f5932
5 changed files with 148 additions and 138 deletions

View File

@ -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

View File

@ -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>>()?;

View File

@ -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;

View File

@ -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,

View File

@ -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)
}