From dfd33f593218aa47030e3d9abc12bf19c3c7525d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 8 Jun 2018 09:29:41 -0400 Subject: [PATCH] move `make_query_response` into method on infcx --- src/librustc/infer/canonical/query_result.rs | 131 +++++++++++++++++- src/librustc_traits/dropck_outlives.rs | 27 ++-- src/librustc_traits/lib.rs | 1 - .../normalize_projection_ty.rs | 4 +- src/librustc_traits/util.rs | 123 ---------------- 5 files changed, 148 insertions(+), 138 deletions(-) delete mode 100644 src/librustc_traits/util.rs diff --git a/src/librustc/infer/canonical/query_result.rs b/src/librustc/infer/canonical/query_result.rs index b1eed05c2a2f..aff9136bad07 100644 --- a/src/librustc/infer/canonical/query_result.rs +++ b/src/librustc/infer/canonical/query_result.rs @@ -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> = + 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( + &self, + inference_vars: CanonicalVarValues<'tcx>, + answer: T, + fulfill_cx: &mut FulfillmentContext<'tcx>, + ) -> Result, 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 diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs index 219c6b9aefba..cd49aa2241b3 100644 --- a/src/librustc_traits/dropck_outlives.rs +++ b/src/librustc_traits/dropck_outlives.rs @@ -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::>()?; diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs index c3135439204e..830aa93c3c3d 100644 --- a/src/librustc_traits/lib.rs +++ b/src/librustc_traits/lib.rs @@ -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; diff --git a/src/librustc_traits/normalize_projection_ty.rs b/src/librustc_traits/normalize_projection_ty.rs index a9ac53972e47..a9c4fef9f7dc 100644 --- a/src/librustc_traits/normalize_projection_ty.rs +++ b/src/librustc_traits/normalize_projection_ty.rs @@ -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, diff --git a/src/librustc_traits/util.rs b/src/librustc_traits/util.rs deleted file mode 100644 index cdf20bdafadc..000000000000 --- a/src/librustc_traits/util.rs +++ /dev/null @@ -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 or the MIT license -// , 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> = - 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, 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) -}