introduce infcx.at(..).normalize(..)
operation [VIC]
It is backed by the new `normalize_projection_ty` query, which uses canonicalization.
This commit is contained in:
parent
8c024fdafb
commit
3a50b41da4
23 changed files with 637 additions and 10 deletions
14
src/Cargo.lock
generated
14
src/Cargo.lock
generated
|
@ -1884,6 +1884,7 @@ dependencies = [
|
|||
"rustc_privacy 0.0.0",
|
||||
"rustc_resolve 0.0.0",
|
||||
"rustc_save_analysis 0.0.0",
|
||||
"rustc_traits 0.0.0",
|
||||
"rustc_trans_utils 0.0.0",
|
||||
"rustc_typeck 0.0.0",
|
||||
"serialize 0.0.0",
|
||||
|
@ -2068,6 +2069,19 @@ dependencies = [
|
|||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_traits"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"graphviz 0.0.0",
|
||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_trans"
|
||||
version = "0.0.0"
|
||||
|
|
|
@ -67,11 +67,12 @@ use hir::{HirId, ItemLocalId};
|
|||
|
||||
use ich::{Fingerprint, StableHashingContext};
|
||||
use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
|
||||
use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty};
|
||||
use ty::subst::Substs;
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
use syntax_pos::symbol::InternedString;
|
||||
use traits::query::CanonicalProjectionGoal;
|
||||
use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty};
|
||||
use ty::subst::Substs;
|
||||
|
||||
// erase!() just makes tokens go away. It's used to specify which macro argument
|
||||
// is repeated (i.e. which sub-expression of the macro we are in) but don't need
|
||||
|
@ -635,6 +636,7 @@ define_dep_nodes!( <'tcx>
|
|||
[] CompileCodegenUnit(InternedString),
|
||||
[input] OutputFilenames,
|
||||
[anon] NormalizeTy,
|
||||
[] NormalizeProjectionTy(CanonicalProjectionGoal<'tcx>),
|
||||
|
||||
[] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) },
|
||||
|
||||
|
|
|
@ -40,9 +40,9 @@ use super::*;
|
|||
use ty::relate::{Relate, TypeRelation};
|
||||
|
||||
pub struct At<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
||||
cause: &'a ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
||||
pub cause: &'a ObligationCause<'tcx>,
|
||||
pub param_env: ty::ParamEnv<'tcx>,
|
||||
}
|
||||
|
||||
pub struct Trace<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||
|
|
|
@ -69,6 +69,7 @@ pub mod type_variable;
|
|||
pub mod unify_key;
|
||||
|
||||
#[must_use]
|
||||
#[derive(Debug)]
|
||||
pub struct InferOk<'tcx, T> {
|
||||
pub value: T,
|
||||
pub obligations: PredicateObligations<'tcx>,
|
||||
|
@ -1224,6 +1225,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
self.borrow_region_constraints().take_and_reset_data()
|
||||
}
|
||||
|
||||
/// Gives temporary access to the region constraint data.
|
||||
#[allow(non_camel_case_types)] // bug with impl trait
|
||||
pub fn with_region_constraints<R>(
|
||||
&self,
|
||||
op: impl FnOnce(&RegionConstraintData<'tcx>) -> R,
|
||||
) -> R {
|
||||
let region_constraints = self.borrow_region_constraints();
|
||||
op(region_constraints.data())
|
||||
}
|
||||
|
||||
/// Takes ownership of the list of variable regions. This implies
|
||||
/// that all the region constriants have already been taken, and
|
||||
/// hence that `resolve_regions_and_report_errors` can never be
|
||||
|
|
|
@ -99,6 +99,16 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
|||
.push((body_id, obligation));
|
||||
}
|
||||
|
||||
/// Trait queries just want to pass back type obligations "as is"
|
||||
pub fn take_registered_region_obligations(
|
||||
&self,
|
||||
) -> Vec<(ast::NodeId, RegionObligation<'tcx>)> {
|
||||
::std::mem::replace(
|
||||
&mut *self.region_obligations.borrow_mut(),
|
||||
vec![],
|
||||
)
|
||||
}
|
||||
|
||||
/// Process the region obligations that must be proven (during
|
||||
/// `regionck`) for the given `body_id`, given information about
|
||||
/// the region bounds in scope and so forth. This function must be
|
||||
|
|
|
@ -350,6 +350,10 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
|||
mem::replace(data, RegionConstraintData::default())
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &RegionConstraintData<'tcx> {
|
||||
&self.data
|
||||
}
|
||||
|
||||
fn in_snapshot(&self) -> bool {
|
||||
!self.undo_log.is_empty()
|
||||
}
|
||||
|
|
|
@ -175,6 +175,11 @@ pub struct PerfStats {
|
|||
pub decode_def_path_tables_time: Cell<Duration>,
|
||||
/// Total number of values canonicalized queries constructed.
|
||||
pub queries_canonicalized: Cell<usize>,
|
||||
/// Number of times we canonicalized a value and found that the
|
||||
/// result had already been canonicalized.
|
||||
pub canonicalized_values_allocated: Cell<usize>,
|
||||
/// Number of times this query is invoked.
|
||||
pub normalize_projection_ty: Cell<usize>,
|
||||
}
|
||||
|
||||
/// Enum to support dispatch of one-time diagnostics (in Session.diag_once)
|
||||
|
@ -862,6 +867,10 @@ impl Session {
|
|||
);
|
||||
println!("Total queries canonicalized: {}",
|
||||
self.perf_stats.queries_canonicalized.get());
|
||||
println!("Total canonical values interned: {}",
|
||||
self.perf_stats.canonicalized_values_allocated.get());
|
||||
println!("normalize_projection_ty: {}",
|
||||
self.perf_stats.normalize_projection_ty.get());
|
||||
}
|
||||
|
||||
/// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n.
|
||||
|
@ -1149,6 +1158,8 @@ pub fn build_session_(
|
|||
symbol_hash_time: Cell::new(Duration::from_secs(0)),
|
||||
decode_def_path_tables_time: Cell::new(Duration::from_secs(0)),
|
||||
queries_canonicalized: Cell::new(0),
|
||||
canonicalized_values_allocated: Cell::new(0),
|
||||
normalize_projection_ty: Cell::new(0),
|
||||
},
|
||||
code_stats: RefCell::new(CodeStats::new()),
|
||||
optimization_fuel_crate,
|
||||
|
|
|
@ -63,6 +63,8 @@ mod structural_impls;
|
|||
pub mod trans;
|
||||
mod util;
|
||||
|
||||
pub mod query;
|
||||
|
||||
// Whether to enable bug compatibility with issue #43355
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum IntercrateMode {
|
||||
|
|
31
src/librustc/traits/query/mod.rs
Normal file
31
src/librustc/traits/query/mod.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
// 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.
|
||||
|
||||
//! Experimental types for the trait query interface. The methods
|
||||
//! defined in this module are all based on **canonicalization**,
|
||||
//! which makes a canonical query by replacing unbound inference
|
||||
//! variables and regions, so that results can be reused more broadly.
|
||||
//! The providers for the queries defined here can be found in
|
||||
//! `librustc_traits`.
|
||||
|
||||
use infer::canonical::Canonical;
|
||||
use ty;
|
||||
|
||||
pub mod normalize;
|
||||
|
||||
pub type CanonicalProjectionGoal<'tcx> =
|
||||
Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::ProjectionTy<'tcx>>>;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct NoSolution;
|
||||
|
||||
pub type Fallible<T> = Result<T, NoSolution>;
|
||||
|
||||
impl_stable_hash_for!(struct NoSolution { });
|
268
src/librustc/traits/query/normalize.rs
Normal file
268
src/librustc/traits/query/normalize.rs
Normal file
|
@ -0,0 +1,268 @@
|
|||
// 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.
|
||||
|
||||
//! Code for the 'normalization' query. This consists of a wrapper
|
||||
//! which folds deeply, invoking the underlying
|
||||
//! `normalize_projection_ty` query when it encounters projections.
|
||||
|
||||
use infer::{InferCtxt, InferOk};
|
||||
use infer::at::At;
|
||||
use infer::canonical::{Canonical, Canonicalize, QueryResult};
|
||||
use middle::const_val::ConstVal;
|
||||
use mir::interpret::GlobalId;
|
||||
use std::rc::Rc;
|
||||
use traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
|
||||
use traits::query::CanonicalProjectionGoal;
|
||||
use traits::project::Normalized;
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::fold::{TypeFoldable, TypeFolder};
|
||||
use ty::subst::{Subst, Substs};
|
||||
|
||||
use super::NoSolution;
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> At<'cx, 'gcx, 'tcx> {
|
||||
/// Normalize `value` in the context of the inference context,
|
||||
/// yielding a resulting type, or an error if `value` cannot be
|
||||
/// normalized. If you don't care about regions, you should prefer
|
||||
/// `normalize_erasing_regions`, which is more efficient.
|
||||
///
|
||||
/// If the normalization succeeds and is unambigious, returns back
|
||||
/// the normalized value along with various outlives relations (in
|
||||
/// the form of obligations that must be discharged).
|
||||
///
|
||||
/// NB. This will *eventually* be the main means of
|
||||
/// normalizing, but for now should be used only when we actually
|
||||
/// know that normalization will succeed, since error reporting
|
||||
/// and other details are still "under development".
|
||||
pub fn normalize<T>(&self, value: &T) -> Result<Normalized<'tcx, T>, NoSolution>
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
let mut normalizer = QueryNormalizer {
|
||||
infcx: self.infcx,
|
||||
cause: self.cause,
|
||||
param_env: self.param_env,
|
||||
obligations: vec![],
|
||||
error: false,
|
||||
anon_depth: 0,
|
||||
};
|
||||
if !value.has_projections() {
|
||||
return Ok(Normalized {
|
||||
value: value.clone(),
|
||||
obligations: vec![],
|
||||
});
|
||||
}
|
||||
|
||||
let value1 = value.fold_with(&mut normalizer);
|
||||
if normalizer.error {
|
||||
Err(NoSolution)
|
||||
} else {
|
||||
Ok(Normalized {
|
||||
value: value1,
|
||||
obligations: normalizer.obligations,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Result from the `normalize_projection_ty` query.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NormalizationResult<'tcx> {
|
||||
/// Result of normalization.
|
||||
pub normalized_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
struct QueryNormalizer<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
|
||||
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
|
||||
cause: &'cx ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
obligations: Vec<PredicateObligation<'tcx>>,
|
||||
error: bool,
|
||||
anon_depth: usize,
|
||||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx> {
|
||||
fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
let ty = ty.super_fold_with(self);
|
||||
match ty.sty {
|
||||
ty::TyAnon(def_id, substs) if !substs.has_escaping_regions() => {
|
||||
// (*)
|
||||
// Only normalize `impl Trait` after type-checking, usually in trans.
|
||||
match self.param_env.reveal {
|
||||
Reveal::UserFacing => ty,
|
||||
|
||||
Reveal::All => {
|
||||
let recursion_limit = self.tcx().sess.recursion_limit.get();
|
||||
if self.anon_depth >= recursion_limit {
|
||||
let obligation = Obligation::with_depth(
|
||||
self.cause.clone(),
|
||||
recursion_limit,
|
||||
self.param_env,
|
||||
ty,
|
||||
);
|
||||
self.infcx.report_overflow_error(&obligation, true);
|
||||
}
|
||||
|
||||
let generic_ty = self.tcx().type_of(def_id);
|
||||
let concrete_ty = generic_ty.subst(self.tcx(), substs);
|
||||
self.anon_depth += 1;
|
||||
let folded_ty = self.fold_ty(concrete_ty);
|
||||
self.anon_depth -= 1;
|
||||
folded_ty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty::TyProjection(ref data) if !data.has_escaping_regions() => {
|
||||
// (*)
|
||||
// (*) This is kind of hacky -- we need to be able to
|
||||
// handle normalization within binders because
|
||||
// otherwise we wind up a need to normalize when doing
|
||||
// trait matching (since you can have a trait
|
||||
// obligation like `for<'a> T::B : Fn(&'a int)`), but
|
||||
// we can't normalize with bound regions in scope. So
|
||||
// far now we just ignore binders but only normalize
|
||||
// if all bound regions are gone (and then we still
|
||||
// have to renormalize whenever we instantiate a
|
||||
// binder). It would be better to normalize in a
|
||||
// binding-aware fashion.
|
||||
|
||||
let gcx = self.infcx.tcx.global_tcx();
|
||||
|
||||
let (c_data, orig_values) =
|
||||
self.infcx.canonicalize_query(&self.param_env.and(*data));
|
||||
debug!("QueryNormalizer: c_data = {:#?}", c_data);
|
||||
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
|
||||
match gcx.normalize_projection_ty(c_data) {
|
||||
Ok(result) => {
|
||||
// We don't expect ambiguity.
|
||||
if result.is_ambiguous() {
|
||||
self.error = true;
|
||||
return ty;
|
||||
}
|
||||
|
||||
match self.infcx.instantiate_query_result(
|
||||
self.cause,
|
||||
self.param_env,
|
||||
&orig_values,
|
||||
&result,
|
||||
) {
|
||||
Ok(InferOk {
|
||||
value: result,
|
||||
obligations,
|
||||
}) => {
|
||||
debug!("QueryNormalizer: result = {:#?}", result);
|
||||
debug!("QueryNormalizer: obligations = {:#?}", obligations);
|
||||
self.obligations.extend(obligations);
|
||||
return result.normalized_ty;
|
||||
}
|
||||
|
||||
Err(_) => {
|
||||
self.error = true;
|
||||
return ty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(NoSolution) => {
|
||||
self.error = true;
|
||||
ty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => ty,
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
|
||||
if let ConstVal::Unevaluated(def_id, substs) = constant.val {
|
||||
let tcx = self.infcx.tcx.global_tcx();
|
||||
if let Some(param_env) = self.tcx().lift_to_global(&self.param_env) {
|
||||
if substs.needs_infer() {
|
||||
let identity_substs = Substs::identity_for_item(tcx, def_id);
|
||||
let instance = ty::Instance::resolve(tcx, param_env, def_id, identity_substs);
|
||||
if let Some(instance) = instance {
|
||||
let cid = GlobalId {
|
||||
instance,
|
||||
promoted: None,
|
||||
};
|
||||
match tcx.const_eval(param_env.and(cid)) {
|
||||
Ok(evaluated) => {
|
||||
let evaluated = evaluated.subst(self.tcx(), substs);
|
||||
return self.fold_const(evaluated);
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let Some(substs) = self.tcx().lift_to_global(&substs) {
|
||||
let instance = ty::Instance::resolve(tcx, param_env, def_id, substs);
|
||||
if let Some(instance) = instance {
|
||||
let cid = GlobalId {
|
||||
instance,
|
||||
promoted: None,
|
||||
};
|
||||
match tcx.const_eval(param_env.and(cid)) {
|
||||
Ok(evaluated) => return self.fold_const(evaluated),
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
constant
|
||||
}
|
||||
}
|
||||
|
||||
BraceStructTypeFoldableImpl! {
|
||||
impl<'tcx> TypeFoldable<'tcx> for NormalizationResult<'tcx> {
|
||||
normalized_ty
|
||||
}
|
||||
}
|
||||
|
||||
BraceStructLiftImpl! {
|
||||
impl<'a, 'tcx> Lift<'tcx> for NormalizationResult<'a> {
|
||||
type Lifted = NormalizationResult<'tcx>;
|
||||
normalized_ty
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for ty::ParamEnvAnd<'tcx, ty::ProjectionTy<'tcx>> {
|
||||
type Canonicalized = CanonicalProjectionGoal<'gcx>;
|
||||
|
||||
fn intern(
|
||||
_gcx: TyCtxt<'_, 'gcx, 'gcx>,
|
||||
value: Canonical<'gcx, Self::Lifted>,
|
||||
) -> Self::Canonicalized {
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for QueryResult<'tcx, NormalizationResult<'tcx>> {
|
||||
// we ought to intern this, but I'm too lazy just now
|
||||
type Canonicalized = Rc<Canonical<'gcx, QueryResult<'gcx, NormalizationResult<'gcx>>>>;
|
||||
|
||||
fn intern(
|
||||
_gcx: TyCtxt<'_, 'gcx, 'gcx>,
|
||||
value: Canonical<'gcx, Self::Lifted>,
|
||||
) -> Self::Canonicalized {
|
||||
Rc::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(struct NormalizationResult<'tcx> {
|
||||
normalized_ty
|
||||
});
|
|
@ -106,6 +106,7 @@ pub struct GlobalArenas<'tcx> {
|
|||
tables: TypedArena<ty::TypeckTables<'tcx>>,
|
||||
/// miri allocations
|
||||
const_allocs: TypedArena<interpret::Allocation>,
|
||||
|
||||
}
|
||||
|
||||
impl<'tcx> GlobalArenas<'tcx> {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
use dep_graph::SerializedDepNodeIndex;
|
||||
use hir::def_id::{CrateNum, DefId, DefIndex};
|
||||
use mir::interpret::{GlobalId};
|
||||
use traits::query::CanonicalProjectionGoal;
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::subst::Substs;
|
||||
use ty::maps::queries;
|
||||
|
@ -51,6 +52,15 @@ impl<'tcx, M: QueryConfig<Key=DefId>> QueryDescription<'tcx> for M {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> QueryDescription<'tcx> for queries::normalize_projection_ty<'tcx> {
|
||||
fn describe(
|
||||
_tcx: TyCtxt,
|
||||
goal: CanonicalProjectionGoal<'tcx>,
|
||||
) -> String {
|
||||
format!("normalizing `{:?}`", goal)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> QueryDescription<'tcx> for queries::is_copy_raw<'tcx> {
|
||||
fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String {
|
||||
format!("computing whether `{}` is `Copy`", env.value)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
//! Defines the set of legal keys that can be used in queries.
|
||||
|
||||
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex};
|
||||
use traits::query::CanonicalProjectionGoal;
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::subst::Substs;
|
||||
use ty::fast_reject::SimplifiedType;
|
||||
|
@ -170,3 +171,13 @@ impl Key for InternedString {
|
|||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for CanonicalProjectionGoal<'tcx> {
|
||||
fn map_crate(&self) -> CrateNum {
|
||||
LOCAL_CRATE
|
||||
}
|
||||
|
||||
fn default_span(&self, _tcx: TyCtxt) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ use hir::def_id::{CrateNum, DefId, DefIndex};
|
|||
use hir::def::{Def, Export};
|
||||
use hir::{self, TraitCandidate, ItemLocalId, TransFnAttrs};
|
||||
use hir::svh::Svh;
|
||||
use infer::canonical::{Canonical, QueryResult};
|
||||
use lint;
|
||||
use middle::borrowck::BorrowCheckResult;
|
||||
use middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary,
|
||||
|
@ -33,6 +34,8 @@ use mir::interpret::{GlobalId};
|
|||
use session::{CompileResult, CrateDisambiguator};
|
||||
use session::config::OutputFilenames;
|
||||
use traits::Vtable;
|
||||
use traits::query::{CanonicalProjectionGoal, NoSolution};
|
||||
use traits::query::normalize::NormalizationResult;
|
||||
use traits::specialization_graph;
|
||||
use ty::{self, CrateInherentImpls, Ty, TyCtxt};
|
||||
use ty::steal::Steal;
|
||||
|
@ -380,6 +383,14 @@ define_maps! { <'tcx>
|
|||
[] fn erase_regions_ty: erase_regions_ty(Ty<'tcx>) -> Ty<'tcx>,
|
||||
[] fn fully_normalize_monormophic_ty: normalize_ty_node(Ty<'tcx>) -> Ty<'tcx>,
|
||||
|
||||
/// Do not call this query directly: invoke `normalize` instead.
|
||||
[] fn normalize_projection_ty: NormalizeProjectionTy(
|
||||
CanonicalProjectionGoal<'tcx>
|
||||
) -> Result<
|
||||
Lrc<Canonical<'tcx, QueryResult<'tcx, NormalizationResult<'tcx>>>>,
|
||||
NoSolution,
|
||||
>,
|
||||
|
||||
[] fn substitute_normalize_and_test_predicates:
|
||||
substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool,
|
||||
|
||||
|
@ -537,6 +548,7 @@ fn output_filenames_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
|
|||
fn vtable_methods_node<'tcx>(trait_ref: ty::PolyTraitRef<'tcx>) -> DepConstructor<'tcx> {
|
||||
DepConstructor::VtableMethods{ trait_ref }
|
||||
}
|
||||
|
||||
fn normalize_ty_node<'tcx>(_: Ty<'tcx>) -> DepConstructor<'tcx> {
|
||||
DepConstructor::NormalizeTy
|
||||
}
|
||||
|
|
|
@ -773,6 +773,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
|
|||
DepKind::VtableMethods |
|
||||
DepKind::EraseRegionsTy |
|
||||
DepKind::NormalizeTy |
|
||||
DepKind::NormalizeProjectionTy |
|
||||
DepKind::SubstituteNormalizeAndTestPredicates |
|
||||
DepKind::InstanceDefSizeEstimate |
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ rustc_plugin = { path = "../librustc_plugin" }
|
|||
rustc_privacy = { path = "../librustc_privacy" }
|
||||
rustc_resolve = { path = "../librustc_resolve" }
|
||||
rustc_save_analysis = { path = "../librustc_save_analysis" }
|
||||
rustc_traits = { path = "../librustc_traits" }
|
||||
rustc_trans_utils = { path = "../librustc_trans_utils" }
|
||||
rustc_typeck = { path = "../librustc_typeck" }
|
||||
serialize = { path = "../libserialize" }
|
||||
|
|
|
@ -31,6 +31,7 @@ use rustc_incremental;
|
|||
use rustc_resolve::{MakeGlobMap, Resolver, ResolverArenas};
|
||||
use rustc_metadata::creader::CrateLoader;
|
||||
use rustc_metadata::cstore::{self, CStore};
|
||||
use rustc_traits;
|
||||
use rustc_trans_utils::trans_crate::TransCrate;
|
||||
use rustc_typeck as typeck;
|
||||
use rustc_privacy;
|
||||
|
@ -942,6 +943,7 @@ pub fn default_provide(providers: &mut ty::maps::Providers) {
|
|||
traits::provide(providers);
|
||||
reachable::provide(providers);
|
||||
rustc_passes::provide(providers);
|
||||
rustc_traits::provide(providers);
|
||||
middle::region::provide(providers);
|
||||
cstore::provide(providers);
|
||||
lint::provide(providers);
|
||||
|
|
|
@ -46,6 +46,7 @@ extern crate rustc_metadata;
|
|||
extern crate rustc_mir;
|
||||
extern crate rustc_resolve;
|
||||
extern crate rustc_save_analysis;
|
||||
extern crate rustc_traits;
|
||||
extern crate rustc_trans_utils;
|
||||
extern crate rustc_typeck;
|
||||
extern crate serialize;
|
||||
|
|
|
@ -20,7 +20,8 @@ use dataflow::move_paths::MoveData;
|
|||
use rustc::hir::def_id::DefId;
|
||||
use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult};
|
||||
use rustc::infer::region_constraints::{GenericKind, RegionConstraintData};
|
||||
use rustc::traits::{self, FulfillmentContext};
|
||||
use rustc::traits::{self, Normalized, FulfillmentContext};
|
||||
use rustc::traits::query::NoSolution;
|
||||
use rustc::ty::error::TypeError;
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants};
|
||||
|
@ -1553,10 +1554,17 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
{
|
||||
debug!("normalize(value={:?}, location={:?})", value, location);
|
||||
self.fully_perform_op(location.at_self(), |this| {
|
||||
let mut selcx = traits::SelectionContext::new(this.infcx);
|
||||
let cause = this.misc(this.last_span);
|
||||
let traits::Normalized { value, obligations } =
|
||||
traits::normalize(&mut selcx, this.param_env, cause, value);
|
||||
let Normalized { value, obligations } = this.infcx
|
||||
.at(&this.misc(this.last_span), this.param_env)
|
||||
.normalize(value)
|
||||
.unwrap_or_else(|NoSolution| {
|
||||
span_bug!(
|
||||
this.last_span,
|
||||
"normalization of `{:?}` failed at {:?}",
|
||||
value,
|
||||
location,
|
||||
);
|
||||
});
|
||||
Ok(InferOk { value, obligations })
|
||||
}).unwrap()
|
||||
}
|
||||
|
|
18
src/librustc_traits/Cargo.toml
Normal file
18
src/librustc_traits/Cargo.toml
Normal file
|
@ -0,0 +1,18 @@
|
|||
[package]
|
||||
authors = ["The Rust Project Developers"]
|
||||
name = "rustc_traits"
|
||||
version = "0.0.0"
|
||||
|
||||
[lib]
|
||||
name = "rustc_traits"
|
||||
path = "lib.rs"
|
||||
crate-type = ["dylib"]
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
graphviz = { path = "../libgraphviz" }
|
||||
log = { version = "0.4" }
|
||||
rustc = { path = "../librustc" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
syntax = { path = "../libsyntax" }
|
||||
syntax_pos = { path = "../libsyntax_pos" }
|
37
src/librustc_traits/lib.rs
Normal file
37
src/librustc_traits/lib.rs
Normal file
|
@ -0,0 +1,37 @@
|
|||
// 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.
|
||||
|
||||
//! New recursive solver modeled on Chalk's recursive solver. Most of
|
||||
//! the guts are broken up into modules; see the comments in those modules.
|
||||
|
||||
#![deny(warnings)]
|
||||
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(match_default_bindings)]
|
||||
#![feature(underscore_lifetimes)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate rustc;
|
||||
extern crate rustc_data_structures;
|
||||
extern crate syntax;
|
||||
extern crate syntax_pos;
|
||||
|
||||
mod normalize_projection_ty;
|
||||
mod util;
|
||||
|
||||
use rustc::ty::maps::Providers;
|
||||
|
||||
pub fn provide(p: &mut Providers) {
|
||||
*p = Providers {
|
||||
normalize_projection_ty: normalize_projection_ty::normalize_projection_ty,
|
||||
..*p
|
||||
};
|
||||
}
|
55
src/librustc_traits/normalize_projection_ty.rs
Normal file
55
src/librustc_traits/normalize_projection_ty.rs
Normal file
|
@ -0,0 +1,55 @@
|
|||
// 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::canonical::{Canonical, QueryResult};
|
||||
use rustc::traits::{self, FulfillmentContext, Normalized, ObligationCause,
|
||||
SelectionContext};
|
||||
use rustc::traits::query::{CanonicalProjectionGoal, NoSolution, normalize::NormalizationResult};
|
||||
use rustc::ty::{ParamEnvAnd, TyCtxt};
|
||||
use rustc::util::common::CellUsizeExt;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast::DUMMY_NODE_ID;
|
||||
use syntax_pos::DUMMY_SP;
|
||||
use util;
|
||||
|
||||
crate fn normalize_projection_ty<'tcx>(
|
||||
tcx: TyCtxt<'_, 'tcx, 'tcx>,
|
||||
goal: CanonicalProjectionGoal<'tcx>,
|
||||
) -> Result<Rc<Canonical<'tcx, QueryResult<'tcx, NormalizationResult<'tcx>>>>, NoSolution> {
|
||||
debug!("normalize_provider(goal={:#?})", goal);
|
||||
|
||||
tcx.sess.perf_stats.normalize_projection_ty.increment();
|
||||
tcx.infer_ctxt().enter(|ref infcx| {
|
||||
let (
|
||||
ParamEnvAnd {
|
||||
param_env,
|
||||
value: goal,
|
||||
},
|
||||
canonical_inference_vars,
|
||||
) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &goal);
|
||||
let fulfill_cx = &mut FulfillmentContext::new();
|
||||
let selcx = &mut SelectionContext::new(infcx);
|
||||
let cause = ObligationCause::misc(DUMMY_SP, DUMMY_NODE_ID);
|
||||
let Normalized {
|
||||
value: answer,
|
||||
obligations,
|
||||
} = traits::normalize_projection_type(selcx, param_env, goal, cause, 0);
|
||||
fulfill_cx.register_predicate_obligations(infcx, obligations);
|
||||
|
||||
// Now that we have fulfilled as much as we can, create a solution
|
||||
// from what we've learned.
|
||||
util::make_query_response(
|
||||
infcx,
|
||||
canonical_inference_vars,
|
||||
NormalizationResult { normalized_ty: answer },
|
||||
fulfill_cx,
|
||||
)
|
||||
})
|
||||
}
|
117
src/librustc_traits/util.rs
Normal file
117
src/librustc_traits/util.rs
Normal file
|
@ -0,0 +1,117 @@
|
|||
// 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, QueryRegionConstraints,
|
||||
QueryResult};
|
||||
use rustc::infer::region_constraints::{Constraint, RegionConstraintData};
|
||||
use rustc::traits::FulfillmentContext;
|
||||
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_outlives, ty_outlives) = infcx.with_region_constraints(|region_constraints| {
|
||||
let RegionConstraintData {
|
||||
constraints,
|
||||
verifys,
|
||||
givens,
|
||||
} = region_constraints;
|
||||
|
||||
assert!(verifys.is_empty());
|
||||
assert!(givens.is_empty());
|
||||
|
||||
let region_outlives: Vec<_> = constraints
|
||||
.into_iter()
|
||||
.map(|(k, _)| match *k {
|
||||
Constraint::VarSubVar(v1, v2) => {
|
||||
(tcx.mk_region(ty::ReVar(v1)), tcx.mk_region(ty::ReVar(v2)))
|
||||
}
|
||||
Constraint::VarSubReg(v1, r2) => (tcx.mk_region(ty::ReVar(v1)), r2),
|
||||
Constraint::RegSubVar(r1, v2) => (r1, tcx.mk_region(ty::ReVar(v2))),
|
||||
Constraint::RegSubReg(r1, r2) => (r1, r2),
|
||||
})
|
||||
.collect();
|
||||
|
||||
let ty_outlives: Vec<_> = region_obligations
|
||||
.into_iter()
|
||||
.map(|(_, r_o)| (r_o.sup_type, r_o.sub_region))
|
||||
.collect();
|
||||
|
||||
(region_outlives, ty_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: QueryRegionConstraints {
|
||||
region_outlives,
|
||||
ty_outlives,
|
||||
},
|
||||
certainty,
|
||||
value: answer,
|
||||
});
|
||||
|
||||
debug!(
|
||||
"make_query_response: canonical_result = {:#?}",
|
||||
canonical_result
|
||||
);
|
||||
|
||||
Ok(canonical_result)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue