From 2a0b3d6224768119f1d2e9850488c3d184362c1c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 11 Jun 2018 11:56:06 -0400 Subject: [PATCH] introduce `Normalizable` trait for things directly normalizable --- src/librustc/dep_graph/dep_node.rs | 9 +- src/librustc/traits/query/mod.rs | 3 + src/librustc/traits/query/type_op/eq.rs | 8 +- src/librustc/traits/query/type_op/mod.rs | 33 ++-- .../traits/query/type_op/normalize.rs | 151 +++++++++++++++--- .../traits/query/type_op/prove_predicate.rs | 18 ++- src/librustc/traits/query/type_op/subtype.rs | 8 +- src/librustc/ty/query/config.rs | 32 +++- src/librustc/ty/query/mod.rs | 40 ++++- src/librustc/ty/query/plumbing.rs | 4 + .../borrow_check/nll/type_check/mod.rs | 40 +++-- src/librustc_traits/lib.rs | 5 + src/librustc_traits/type_op_normalize.rs | 68 ++++++++ 13 files changed, 362 insertions(+), 57 deletions(-) create mode 100644 src/librustc_traits/type_op_normalize.rs diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 94c79c17f05..33322993b1d 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -72,9 +72,10 @@ use syntax_pos::symbol::InternedString; use traits::query::{ CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, - CanonicalPredicateGoal, CanonicalTypeOpProvePredicateGoal, + CanonicalPredicateGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal, }; -use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty}; +use ty::{TyCtxt, FnSig, Instance, InstanceDef, + ParamEnv, ParamEnvAnd, Predicate, PolyFnSig, PolyTraitRef, Ty}; use ty::subst::Substs; // erase!() just makes tokens go away. It's used to specify which macro argument @@ -652,6 +653,10 @@ pub fn fingerprint_needed_for_crate_hash(self) -> bool { [] TypeOpEq(CanonicalTypeOpEqGoal<'tcx>), [] TypeOpSubtype(CanonicalTypeOpSubtypeGoal<'tcx>), [] TypeOpProvePredicate(CanonicalTypeOpProvePredicateGoal<'tcx>), + [] TypeOpNormalizeTy(CanonicalTypeOpNormalizeGoal<'tcx, Ty<'tcx>>), + [] TypeOpNormalizePredicate(CanonicalTypeOpNormalizeGoal<'tcx, Predicate<'tcx>>), + [] TypeOpNormalizePolyFnSig(CanonicalTypeOpNormalizeGoal<'tcx, PolyFnSig<'tcx>>), + [] TypeOpNormalizeFnSig(CanonicalTypeOpNormalizeGoal<'tcx, FnSig<'tcx>>), [] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) }, diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs index aa0b524af06..dddd05db668 100644 --- a/src/librustc/traits/query/mod.rs +++ b/src/librustc/traits/query/mod.rs @@ -41,6 +41,9 @@ pub type CanonicalTypeOpProvePredicateGoal<'tcx> = Canonical<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>; +pub type CanonicalTypeOpNormalizeGoal<'tcx, T> = + Canonical<'tcx, type_op::normalize::Normalize<'tcx, T>>; + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct NoSolution; diff --git a/src/librustc/traits/query/type_op/eq.rs b/src/librustc/traits/query/type_op/eq.rs index 8925fa12f03..348283d1af3 100644 --- a/src/librustc/traits/query/type_op/eq.rs +++ b/src/librustc/traits/query/type_op/eq.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use infer::canonical::{Canonical, CanonicalizedQueryResult}; +use infer::canonical::{Canonical, CanonicalizedQueryResult, QueryResult}; use ty::{self, ParamEnv, Ty, TyCtxt}; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] @@ -45,6 +45,12 @@ fn perform_query( ) -> CanonicalizedQueryResult<'gcx, ()> { tcx.type_op_eq(canonicalized).unwrap() } + + fn upcast_result( + v: &'a CanonicalizedQueryResult<'gcx, ()>, + ) -> &'a Canonical<'tcx, QueryResult<'tcx, ()>> { + v + } } BraceStructTypeFoldableImpl! { diff --git a/src/librustc/traits/query/type_op/mod.rs b/src/librustc/traits/query/type_op/mod.rs index 6cda9ea1518..cddb648f04f 100644 --- a/src/librustc/traits/query/type_op/mod.rs +++ b/src/librustc/traits/query/type_op/mod.rs @@ -9,15 +9,17 @@ // except according to those terms. use infer::canonical::query_result; -use infer::canonical::{Canonicalized, CanonicalizedQueryResult, QueryRegionConstraint}; +use infer::canonical::{ + Canonical, Canonicalized, CanonicalizedQueryResult, QueryRegionConstraint, QueryResult, +}; use infer::{InferCtxt, InferOk, InferResult}; +use std::fmt; +use std::rc::Rc; +use syntax::codemap::DUMMY_SP; use traits::{ObligationCause, TraitEngine}; use ty::error::TypeError; use ty::fold::TypeFoldable; use ty::{Lift, ParamEnv, TyCtxt}; -use std::fmt; -use std::rc::Rc; -use syntax::codemap::DUMMY_SP; pub mod custom; pub mod eq; @@ -98,17 +100,12 @@ fn fully_perform_nontrivial( } } -type Lifted<'gcx, T> = >::Lifted; - pub trait QueryTypeOp<'gcx: 'tcx, 'tcx>: TypeFoldable<'tcx> + Lift<'gcx> { type QueryResult: TypeFoldable<'tcx> + Lift<'gcx>; /// Micro-optimization: returns `Ok(x)` if we can trivially /// produce the output, else returns `Err(self)` back. - fn trivial_noop( - self, - tcx: TyCtxt<'_, 'gcx, 'tcx>, - ) -> Result, Self>; + fn trivial_noop(self, tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result; fn param_env(&self) -> ParamEnv<'tcx>; @@ -116,14 +113,24 @@ fn perform_query( tcx: TyCtxt<'_, 'gcx, 'tcx>, canonicalized: Canonicalized<'gcx, Self>, ) -> CanonicalizedQueryResult<'gcx, Self::QueryResult>; + + /// "Upcasts" a lifted query result (which is in the gcx lifetime) + /// into the tcx lifetime. This is always just an identity cast, + /// but the generic code does't realize it, so we have to push the + /// operation into the impls that know more specifically what + /// `QueryResult` is. This operation would (maybe) be nicer with + /// something like HKTs or GATs, since then we could make + /// `QueryResult` parametric and `'gcx` and `'tcx` etc. + fn upcast_result( + lifted_query_result: &'a CanonicalizedQueryResult<'gcx, Self::QueryResult>, + ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self::QueryResult>>; } impl<'gcx: 'tcx, 'tcx, Q> TypeOp<'gcx, 'tcx> for Q where Q: QueryTypeOp<'gcx, 'tcx>, - Lifted<'gcx, Q::QueryResult>: TypeFoldable<'tcx>, { - type Output = Lifted<'gcx, Q::QueryResult>; + type Output = Q::QueryResult; fn trivial_noop(self, tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result { QueryTypeOp::trivial_noop(self, tcx) @@ -152,7 +159,7 @@ fn perform(self, infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, Self::O &ObligationCause::dummy(), param_env, &canonical_var_values, - &canonical_result, + Q::upcast_result(&canonical_result), ) } } diff --git a/src/librustc/traits/query/type_op/normalize.rs b/src/librustc/traits/query/type_op/normalize.rs index a363f6f213c..d63997fe40c 100644 --- a/src/librustc/traits/query/type_op/normalize.rs +++ b/src/librustc/traits/query/type_op/normalize.rs @@ -8,17 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use infer::{InferCtxt, InferOk, InferResult}; -use traits::query::NoSolution; -use traits::{Normalized, ObligationCause}; -use ty::fold::TypeFoldable; -use ty::{ParamEnv, TyCtxt}; +use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryResult}; use std::fmt; +use ty::fold::TypeFoldable; +use ty::{self, Lift, ParamEnv, Ty, TyCtxt}; -#[derive(Debug)] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct Normalize<'tcx, T> { - param_env: ParamEnv<'tcx>, - value: T, + pub param_env: ParamEnv<'tcx>, + pub value: T, } impl<'tcx, T> Normalize<'tcx, T> @@ -30,13 +28,13 @@ pub fn new(param_env: ParamEnv<'tcx>, value: T) -> Self { } } -impl<'gcx, 'tcx, T> super::TypeOp<'gcx, 'tcx> for Normalize<'tcx, T> +impl<'gcx: 'tcx, 'tcx, T> super::QueryTypeOp<'gcx, 'tcx> for Normalize<'tcx, T> where - T: fmt::Debug + TypeFoldable<'tcx>, + T: Normalizable<'gcx, 'tcx>, { - type Output = T; + type QueryResult = T; - fn trivial_noop(self, _tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result { + fn trivial_noop(self, _tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result { if !self.value.has_projections() { Ok(self.value) } else { @@ -44,13 +42,126 @@ fn trivial_noop(self, _tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result) -> InferResult<'tcx, Self::Output> { - let Normalized { value, obligations } = infcx - .at(&ObligationCause::dummy(), self.param_env) - .normalize(&self.value) - .unwrap_or_else(|NoSolution| { - bug!("normalization of `{:?}` failed", self.value,); - }); - Ok(InferOk { value, obligations }) + fn param_env(&self) -> ParamEnv<'tcx> { + self.param_env + } + + fn perform_query( + tcx: TyCtxt<'_, 'gcx, 'tcx>, + canonicalized: Canonicalized<'gcx, Self>, + ) -> CanonicalizedQueryResult<'gcx, Self::QueryResult> { + T::type_op_method(tcx, canonicalized) + } + + fn upcast_result( + v: &'a CanonicalizedQueryResult<'gcx, T>, + ) -> &'a Canonical<'tcx, QueryResult<'tcx, T>> { + T::upcast_result(v) + } +} + +pub trait Normalizable<'gcx, 'tcx>: fmt::Debug + TypeFoldable<'tcx> + Lift<'gcx> { + fn type_op_method( + tcx: TyCtxt<'_, 'gcx, 'tcx>, + canonicalized: Canonicalized<'gcx, Normalize<'gcx, Self>>, + ) -> CanonicalizedQueryResult<'gcx, Self>; + + /// Convert from the `'gcx` (lifted) form of `Self` into the `tcx` + /// form of `Self`. + fn upcast_result( + v: &'a CanonicalizedQueryResult<'gcx, Self>, + ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>>; +} + +impl Normalizable<'gcx, 'tcx> for Ty<'tcx> +where + 'gcx: 'tcx, +{ + fn type_op_method( + tcx: TyCtxt<'_, 'gcx, 'tcx>, + canonicalized: Canonicalized<'gcx, Normalize<'gcx, Self>>, + ) -> CanonicalizedQueryResult<'gcx, Self> { + tcx.type_op_normalize_ty(canonicalized).unwrap() + } + + fn upcast_result( + v: &'a CanonicalizedQueryResult<'gcx, Self>, + ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>> { + v + } +} + +impl Normalizable<'gcx, 'tcx> for ty::Predicate<'tcx> +where + 'gcx: 'tcx, +{ + fn type_op_method( + tcx: TyCtxt<'_, 'gcx, 'tcx>, + canonicalized: Canonicalized<'gcx, Normalize<'gcx, Self>>, + ) -> CanonicalizedQueryResult<'gcx, Self> { + tcx.type_op_normalize_predicate(canonicalized).unwrap() + } + + fn upcast_result( + v: &'a CanonicalizedQueryResult<'gcx, Self>, + ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>> { + v + } +} + +impl Normalizable<'gcx, 'tcx> for ty::PolyFnSig<'tcx> +where + 'gcx: 'tcx, +{ + fn type_op_method( + tcx: TyCtxt<'_, 'gcx, 'tcx>, + canonicalized: Canonicalized<'gcx, Normalize<'gcx, Self>>, + ) -> CanonicalizedQueryResult<'gcx, Self> { + tcx.type_op_normalize_poly_fn_sig(canonicalized).unwrap() + } + + fn upcast_result( + v: &'a CanonicalizedQueryResult<'gcx, Self>, + ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>> { + v + } +} + +impl Normalizable<'gcx, 'tcx> for ty::FnSig<'tcx> +where + 'gcx: 'tcx, +{ + fn type_op_method( + tcx: TyCtxt<'_, 'gcx, 'tcx>, + canonicalized: Canonicalized<'gcx, Normalize<'gcx, Self>>, + ) -> CanonicalizedQueryResult<'gcx, Self> { + tcx.type_op_normalize_fn_sig(canonicalized).unwrap() + } + + fn upcast_result( + v: &'a CanonicalizedQueryResult<'gcx, Self>, + ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>> { + v + } +} + +BraceStructTypeFoldableImpl! { + impl<'tcx, T> TypeFoldable<'tcx> for Normalize<'tcx, T> { + param_env, + value, + } where T: TypeFoldable<'tcx>, +} + +BraceStructLiftImpl! { + impl<'a, 'tcx, T> Lift<'tcx> for Normalize<'a, T> { + type Lifted = Normalize<'tcx, T::Lifted>; + param_env, + value, + } where T: Lift<'tcx>, +} + +impl_stable_hash_for! { + impl<'tcx, T> for struct Normalize<'tcx, T> { + param_env, value } } diff --git a/src/librustc/traits/query/type_op/prove_predicate.rs b/src/librustc/traits/query/type_op/prove_predicate.rs index 193dd1c7c84..866ebd0cc12 100644 --- a/src/librustc/traits/query/type_op/prove_predicate.rs +++ b/src/librustc/traits/query/type_op/prove_predicate.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use infer::canonical::{Canonical, CanonicalizedQueryResult}; +use infer::canonical::{Canonical, CanonicalizedQueryResult, QueryResult}; use ty::{ParamEnv, Predicate, TyCtxt}; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] @@ -18,11 +18,11 @@ pub struct ProvePredicate<'tcx> { } impl<'tcx> ProvePredicate<'tcx> { - pub fn new( - param_env: ParamEnv<'tcx>, - predicate: Predicate<'tcx>, - ) -> Self { - ProvePredicate { param_env, predicate } + pub fn new(param_env: ParamEnv<'tcx>, predicate: Predicate<'tcx>) -> Self { + ProvePredicate { + param_env, + predicate, + } } } @@ -43,6 +43,12 @@ fn perform_query( ) -> CanonicalizedQueryResult<'gcx, ()> { tcx.type_op_prove_predicate(canonicalized).unwrap() } + + fn upcast_result( + v: &'a CanonicalizedQueryResult<'gcx, ()>, + ) -> &'a Canonical<'tcx, QueryResult<'tcx, ()>> { + v + } } BraceStructTypeFoldableImpl! { diff --git a/src/librustc/traits/query/type_op/subtype.rs b/src/librustc/traits/query/type_op/subtype.rs index 01f9386bec4..a0fb2c2763d 100644 --- a/src/librustc/traits/query/type_op/subtype.rs +++ b/src/librustc/traits/query/type_op/subtype.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use infer::canonical::{Canonical, CanonicalizedQueryResult}; +use infer::canonical::{Canonical, CanonicalizedQueryResult, QueryResult}; use ty::{ParamEnv, Ty, TyCtxt}; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] @@ -49,6 +49,12 @@ fn perform_query( ) -> CanonicalizedQueryResult<'gcx, ()> { tcx.type_op_subtype(canonicalized).unwrap() } + + fn upcast_result( + v: &'a CanonicalizedQueryResult<'gcx, ()>, + ) -> &'a Canonical<'tcx, QueryResult<'tcx, ()>> { + v + } } BraceStructTypeFoldableImpl! { diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs index 930826dad62..8a48abd093d 100644 --- a/src/librustc/ty/query/config.rs +++ b/src/librustc/ty/query/config.rs @@ -14,7 +14,7 @@ use mir::interpret::{GlobalId, ConstValue}; use traits::query::{ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpEqGoal, - CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, + CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, }; use ty::{self, ParamEnvAnd, Ty, TyCtxt}; use ty::subst::Substs; @@ -123,6 +123,36 @@ fn describe(_tcx: TyCtxt, goal: CanonicalTypeOpProvePredicateGoal<'tcx>) -> Stri } } +impl<'tcx> QueryDescription<'tcx> for queries::type_op_normalize_ty<'tcx> { + fn describe(_tcx: TyCtxt, goal: CanonicalTypeOpNormalizeGoal<'tcx, Ty<'tcx>>) -> String { + format!("normalizing `{:?}`", goal) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::type_op_normalize_predicate<'tcx> { + fn describe( + _tcx: TyCtxt, + goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::Predicate<'tcx>>, + ) -> String { + format!("normalizing `{:?}`", goal) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::type_op_normalize_poly_fn_sig<'tcx> { + fn describe( + _tcx: TyCtxt, + goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::PolyFnSig<'tcx>>, + ) -> String { + format!("normalizing `{:?}`", goal) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::type_op_normalize_fn_sig<'tcx> { + fn describe(_tcx: TyCtxt, goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::FnSig<'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) diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index dfc54cb1425..178ee7cf8e9 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -35,7 +35,7 @@ use traits::{self, Vtable}; use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, - CanonicalTypeOpProvePredicateGoal, NoSolution}; + CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal, NoSolution}; use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult}; use traits::query::normalize::NormalizationResult; use traits::specialization_graph; @@ -447,7 +447,7 @@ CanonicalPredicateGoal<'tcx> ) -> Result, - /// Do not call this query directly: invoke `infcx.eq()` instead. + /// Do not call this query directly: part of the `Eq` type-op [] fn type_op_eq: TypeOpEq( CanonicalTypeOpEqGoal<'tcx> ) -> Result< @@ -455,7 +455,7 @@ NoSolution, >, - /// Do not call this query directly: invoke `infcx.at().subtype()` instead. + /// Do not call this query directly: part of the `Subtype` type-op [] fn type_op_subtype: TypeOpSubtype( CanonicalTypeOpSubtypeGoal<'tcx> ) -> Result< @@ -463,7 +463,7 @@ NoSolution, >, - /// Do not call this query directly: invoke `infcx.at().prove_predicates()` instead. + /// Do not call this query directly: part of the `ProvePredicate` type-op [] fn type_op_prove_predicate: TypeOpProvePredicate( CanonicalTypeOpProvePredicateGoal<'tcx> ) -> Result< @@ -471,6 +471,38 @@ NoSolution, >, + /// Do not call this query directly: part of the `Normalize` type-op + [] fn type_op_normalize_ty: TypeOpNormalizeTy( + CanonicalTypeOpNormalizeGoal<'tcx, Ty<'tcx>> + ) -> Result< + Lrc>>>, + NoSolution, + >, + + /// Do not call this query directly: part of the `Normalize` type-op + [] fn type_op_normalize_predicate: TypeOpNormalizePredicate( + CanonicalTypeOpNormalizeGoal<'tcx, ty::Predicate<'tcx>> + ) -> Result< + Lrc>>>, + NoSolution, + >, + + /// Do not call this query directly: part of the `Normalize` type-op + [] fn type_op_normalize_poly_fn_sig: TypeOpNormalizePolyFnSig( + CanonicalTypeOpNormalizeGoal<'tcx, ty::PolyFnSig<'tcx>> + ) -> Result< + Lrc>>>, + NoSolution, + >, + + /// Do not call this query directly: part of the `Normalize` type-op + [] fn type_op_normalize_fn_sig: TypeOpNormalizeFnSig( + CanonicalTypeOpNormalizeGoal<'tcx, ty::FnSig<'tcx>> + ) -> Result< + Lrc>>>, + NoSolution, + >, + [] fn substitute_normalize_and_test_predicates: substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool, diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 57568f60b86..e17c6fba74c 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -1031,6 +1031,10 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::TypeOpEq | DepKind::TypeOpSubtype | DepKind::TypeOpProvePredicate | + DepKind::TypeOpNormalizeTy | + DepKind::TypeOpNormalizePredicate | + DepKind::TypeOpNormalizePolyFnSig | + DepKind::TypeOpNormalizeFnSig | DepKind::SubstituteNormalizeAndTestPredicates | DepKind::InstanceDefSizeEstimate | DepKind::ProgramClausesForEnv | diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 1f45a8ba173..d8818b704bb 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -286,9 +286,10 @@ fn sanitize_constant(&mut self, constant: &Constant<'tcx>, location: Location) { let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); - let predicates = - type_checker.normalize(instantiated_predicates.predicates, location); - type_checker.prove_predicates(predicates, location); + type_checker.normalize_and_prove_instantiated_predicates( + instantiated_predicates, + location, + ); } value.ty @@ -1526,9 +1527,7 @@ fn prove_aggregate_predicates( AggregateKind::Array(_) | AggregateKind::Tuple => ty::InstantiatedPredicates::empty(), }; - let predicates = self.normalize(instantiated_predicates.predicates, location); - debug!("prove_aggregate_predicates: predicates={:?}", predicates); - self.prove_predicates(predicates, location); + self.normalize_and_prove_instantiated_predicates(instantiated_predicates, location); } fn prove_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>, location: Location) { @@ -1540,12 +1539,22 @@ fn prove_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>, location: Location) ); } - fn prove_predicates( + fn normalize_and_prove_instantiated_predicates( &mut self, - predicates: impl IntoIterator> + Clone, + instantiated_predicates: ty::InstantiatedPredicates<'tcx>, location: Location, ) { + for predicate in instantiated_predicates.predicates { + let predicate = self.normalize(predicate, location); + self.prove_predicate(predicate, location); + } + } + fn prove_predicates( + &mut self, + predicates: impl IntoIterator>, + location: Location, + ) { for predicate in predicates { debug!( "prove_predicates(predicate={:?}, location={:?})", @@ -1560,6 +1569,19 @@ fn prove_predicates( } } + fn prove_predicate(&mut self, predicate: ty::Predicate<'tcx>, location: Location) { + debug!( + "prove_predicate(predicate={:?}, location={:?})", + predicate, location, + ); + + let param_env = self.param_env; + self.fully_perform_op( + location.at_self(), + type_op::prove_predicate::ProvePredicate::new(param_env, predicate), + ).unwrap() + } + fn typeck_mir(&mut self, mir: &Mir<'tcx>) { self.last_span = mir.span; debug!("run_on_mir: {:?}", mir.span); @@ -1588,7 +1610,7 @@ fn typeck_mir(&mut self, mir: &Mir<'tcx>) { fn normalize(&mut self, value: T, location: impl ToLocations) -> T where - T: fmt::Debug + TypeFoldable<'tcx>, + T: type_op::normalize::Normalizable<'gcx, 'tcx>, { debug!("normalize(value={:?}, location={:?})", value, location); let param_env = self.param_env; diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs index 261d6b2fbfa..f81b6a2d906 100644 --- a/src/librustc_traits/lib.rs +++ b/src/librustc_traits/lib.rs @@ -35,6 +35,7 @@ mod normalize_erasing_regions; pub mod lowering; mod type_op_eq; +mod type_op_normalize; mod type_op_prove_predicate; mod type_op_subtype; @@ -53,6 +54,10 @@ pub fn provide(p: &mut Providers) { type_op_eq: type_op_eq::type_op_eq, type_op_prove_predicate: type_op_prove_predicate::type_op_prove_predicate, type_op_subtype: type_op_subtype::type_op_subtype, + type_op_normalize_ty: type_op_normalize::type_op_normalize_ty, + type_op_normalize_predicate: type_op_normalize::type_op_normalize_predicate, + type_op_normalize_fn_sig: type_op_normalize::type_op_normalize_fn_sig, + type_op_normalize_poly_fn_sig: type_op_normalize::type_op_normalize_poly_fn_sig, ..*p }; } diff --git a/src/librustc_traits/type_op_normalize.rs b/src/librustc_traits/type_op_normalize.rs new file mode 100644 index 00000000000..edfe627b15a --- /dev/null +++ b/src/librustc_traits/type_op_normalize.rs @@ -0,0 +1,68 @@ +// 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::canonical::{Canonical, QueryResult}; +use rustc::infer::InferCtxt; +use rustc::traits::query::type_op::normalize::Normalize; +use rustc::traits::query::NoSolution; +use rustc::traits::{FulfillmentContext, Normalized, ObligationCause}; +use rustc::ty::{FnSig, Lift, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable}; +use rustc_data_structures::sync::Lrc; +use std::fmt; +use syntax::codemap::DUMMY_SP; + +fn type_op_normalize<'gcx, 'tcx, T>( + infcx: &InferCtxt<'_, 'gcx, 'tcx>, + canonicalized: Canonical<'tcx, Normalize<'tcx, T>>, +) -> Result>::Lifted>>>, NoSolution> +where + T: fmt::Debug + TypeFoldable<'tcx> + Lift<'gcx>, +{ + let (Normalize { param_env, value }, canonical_inference_vars) = + infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonicalized); + let fulfill_cx = &mut FulfillmentContext::new(); + let Normalized { value, obligations } = infcx + .at(&ObligationCause::dummy(), param_env) + .normalize(&value)?; + fulfill_cx.register_predicate_obligations(infcx, obligations); + infcx.make_canonicalized_query_result(canonical_inference_vars, value, fulfill_cx) +} + +crate fn type_op_normalize_ty<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + canonicalized: Canonical<'tcx, Normalize<'tcx, Ty<'tcx>>>, +) -> Result>>>, NoSolution> { + tcx.infer_ctxt() + .enter(|ref infcx| type_op_normalize(infcx, canonicalized)) +} + +crate fn type_op_normalize_predicate<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + canonicalized: Canonical<'tcx, Normalize<'tcx, Predicate<'tcx>>>, +) -> Result>>>, NoSolution> { + tcx.infer_ctxt() + .enter(|ref infcx| type_op_normalize(infcx, canonicalized)) +} + +crate fn type_op_normalize_fn_sig<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + canonicalized: Canonical<'tcx, Normalize<'tcx, FnSig<'tcx>>>, +) -> Result>>>, NoSolution> { + tcx.infer_ctxt() + .enter(|ref infcx| type_op_normalize(infcx, canonicalized)) +} + +crate fn type_op_normalize_poly_fn_sig<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + canonicalized: Canonical<'tcx, Normalize<'tcx, PolyFnSig<'tcx>>>, +) -> Result>>>, NoSolution> { + tcx.infer_ctxt() + .enter(|ref infcx| type_op_normalize(infcx, canonicalized)) +} -- GitLab