From 056ea1e72d728ee05e902c8b6edf732269ae5c7d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 9 Feb 2018 10:34:23 -0500 Subject: [PATCH 01/22] move macros from `structural_impls` to `macros.rs` Also port a bunch of de rigeur impls to use them. --- src/librustc/macros.rs | 269 ++++++++++++ src/librustc/traits/structural_impls.rs | 337 ++++---------- src/librustc/ty/fold.rs | 3 + src/librustc/ty/structural_impls.rs | 559 ++++++------------------ 4 files changed, 485 insertions(+), 683 deletions(-) diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index f0285d6a93782..78a54c100e4e4 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -138,3 +138,272 @@ macro_rules! impl_stable_hash_for_spanned { ); } +/////////////////////////////////////////////////////////////////////////// +// Lift and TypeFoldable macros +// +// When possible, use one of these (relatively) convenient macros to write +// the impls for you. + +/// Used for types that are `Copy` and which **do not care arena +/// allocated data** (i.e., don't need to be folded). +#[macro_export] +macro_rules! CopyTypeFoldableImpls { + ($($ty:ty,)+) => { + $( + impl<'tcx> Lift<'tcx> for $ty { + type Lifted = Self; + fn lift_to_tcx<'a, 'gcx>(&self, _: TyCtxt<'a, 'gcx, 'tcx>) -> Option { + Some(*self) + } + } + + impl<'tcx> TypeFoldable<'tcx> for $ty { + fn super_fold_with<'gcx: 'tcx, F: $crate::ty::fold::TypeFolder<'gcx, 'tcx>>( + &self, + _: &mut F + ) -> $ty { + *self + } + + fn super_visit_with>( + &self, + _: &mut F) + -> bool + { + false + } + } + )+ + } +} + +#[macro_export] +macro_rules! BraceStructLiftImpl { + (impl<$($p:tt),*> Lift<$tcx:tt> for $s:path { + type Lifted = $lifted:ty; + $($field:ident),* $(,)* + } $(where $($wc:tt)*)*) => { + impl<$($p),*> $crate::ty::Lift<$tcx> for $s + $(where $($wc)*)* + { + type Lifted = $lifted; + + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<$lifted> { + $(let $field = tcx.lift(&self.$field)?;)* + Some(Self::Lifted { $($field),* }) + } + } + }; +} + +#[macro_export] +macro_rules! EnumLiftImpl { + (impl<$($p:tt),*> Lift<$tcx:tt> for $s:path { + type Lifted = $lifted:ty; + $( + ($variant:path) ( $( $variant_arg:ident),* ) + ),* + $(,)* + } $(where $($wc:tt)*)*) => { + impl<$($p),*> $crate::ty::Lift<$tcx> for $s + $(where $($wc)*)* + { + type Lifted = $lifted; + + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<$lifted> { + match self { + $($variant ( $($variant_arg),* ) => { + Some($variant ( $(tcx.lift($variant_arg)?),* )) + })* + } + } + } + }; +} + +#[macro_export] +macro_rules! BraceStructTypeFoldableImpl { + (impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path { + $($field:ident),* $(,)* + } $(where $($wc:tt)*)*) => { + impl<$($p),*> $crate::ty::fold::TypeFoldable<$tcx> for $s + $(where $($wc)*)* + { + fn super_fold_with<'gcx: $tcx, V: $crate::ty::fold::TypeFolder<'gcx, $tcx>>( + &self, + folder: &mut V, + ) -> Self { + let $s { $($field,)* } = self; + $s { $($field: $crate::ty::fold::TypeFoldable::fold_with($field, folder),)* } + } + + fn super_visit_with>( + &self, + visitor: &mut V, + ) -> bool { + let $s { $($field,)* } = self; + false $(|| $crate::ty::fold::TypeFoldable::visit_with($field, visitor))* + } + } + }; +} + +#[macro_export] +macro_rules! TupleStructTypeFoldableImpl { + (impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path { + $($field:ident),* $(,)* + } $(where $($wc:tt)*)*) => { + impl<$($p),*> $crate::ty::fold::TypeFoldable<$tcx> for $s + $(where $($wc)*)* + { + fn super_fold_with<'gcx: $tcx, V: $crate::ty::fold::TypeFolder<'gcx, $tcx>>( + &self, + folder: &mut V, + ) -> Self { + let $s($($field,)*)= self; + $s($($crate::ty::fold::TypeFoldable::fold_with($field, folder),)*) + } + + fn super_visit_with>( + &self, + visitor: &mut V, + ) -> bool { + let $s($($field,)*) = self; + false $(|| $crate::ty::fold::TypeFoldable::visit_with($field, visitor))* + } + } + }; +} + +#[macro_export] +macro_rules! EnumTypeFoldableImpl { + (impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path { + $($variants:tt)* + } $(where $($wc:tt)*)*) => { + impl<$($p),*> $crate::ty::fold::TypeFoldable<$tcx> for $s + $(where $($wc)*)* + { + fn super_fold_with<'gcx: $tcx, V: $crate::ty::fold::TypeFolder<'gcx, $tcx>>( + &self, + folder: &mut V, + ) -> Self { + EnumTypeFoldableImpl!(@FoldVariants(self, folder) input($($variants)*) output()) + } + + fn super_visit_with>( + &self, + visitor: &mut V, + ) -> bool { + EnumTypeFoldableImpl!(@VisitVariants(self, visitor) input($($variants)*) output()) + } + } + }; + + (@FoldVariants($this:expr, $folder:expr) input() output($($output:tt)*)) => { + match $this { + $($output)* + } + }; + + (@FoldVariants($this:expr, $folder:expr) + input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*) + output( $($output:tt)*) ) => { + EnumTypeFoldableImpl!( + @FoldVariants($this, $folder) + input($($input)*) + output( + $variant ( $($variant_arg),* ) => { + $variant ( + $($crate::ty::fold::TypeFoldable::fold_with($variant_arg, $folder)),* + ) + } + $($output)* + ) + ) + }; + + (@FoldVariants($this:expr, $folder:expr) + input( ($variant:path) { $($variant_arg:ident),* $(,)* } , $($input:tt)*) + output( $($output:tt)*) ) => { + EnumTypeFoldableImpl!( + @FoldVariants($this, $folder) + input($($input)*) + output( + $variant { $($variant_arg),* } => { + $variant { + $($variant_arg: $crate::ty::fold::TypeFoldable::fold_with( + $variant_arg, $folder + )),* } + } + $($output)* + ) + ) + }; + + (@FoldVariants($this:expr, $folder:expr) + input( ($variant:path), $($input:tt)*) + output( $($output:tt)*) ) => { + EnumTypeFoldableImpl!( + @FoldVariants($this, $folder) + input($($input)*) + output( + $variant => { $variant } + $($output)* + ) + ) + }; + + (@VisitVariants($this:expr, $visitor:expr) input() output($($output:tt)*)) => { + match $this { + $($output)* + } + }; + + (@VisitVariants($this:expr, $visitor:expr) + input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*) + output( $($output:tt)*) ) => { + EnumTypeFoldableImpl!( + @VisitVariants($this, $visitor) + input($($input)*) + output( + $variant ( $($variant_arg),* ) => { + false $(|| $crate::ty::fold::TypeFoldable::visit_with( + $variant_arg, $visitor + ))* + } + $($output)* + ) + ) + }; + + (@VisitVariants($this:expr, $visitor:expr) + input( ($variant:path) { $($variant_arg:ident),* $(,)* } , $($input:tt)*) + output( $($output:tt)*) ) => { + EnumTypeFoldableImpl!( + @VisitVariants($this, $visitor) + input($($input)*) + output( + $variant { $($variant_arg),* } => { + false $(|| $crate::ty::fold::TypeFoldable::visit_with( + $variant_arg, $visitor + ))* + } + $($output)* + ) + ) + }; + + (@VisitVariants($this:expr, $visitor:expr) + input( ($variant:path), $($input:tt)*) + output( $($output:tt)*) ) => { + EnumTypeFoldableImpl!( + @VisitVariants($this, $visitor) + input($($input)*) + output( + $variant => { false } + $($output)* + ) + ) + }; +} + diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 1eb14a222787d..a39589f5f7e68 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -11,7 +11,7 @@ use traits; use traits::project::Normalized; use ty::{self, Lift, TyCtxt}; -use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; +use ty::fold::{TypeFoldable}; use std::fmt; use std::rc::Rc; @@ -348,276 +348,121 @@ impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> { /////////////////////////////////////////////////////////////////////////// // TypeFoldable implementations. -impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> -{ - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - traits::Obligation { - cause: self.cause.clone(), - recursion_depth: self.recursion_depth, - predicate: self.predicate.fold_with(folder), - param_env: self.param_env.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.predicate.visit_with(visitor) - } +BraceStructTypeFoldableImpl! { + impl<'tcx, O> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> { + cause, recursion_depth, predicate, param_env + } where O: TypeFoldable<'tcx> } -impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableImplData<'tcx, N> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - traits::VtableImplData { - impl_def_id: self.impl_def_id, - substs: self.substs.fold_with(folder), - nested: self.nested.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.substs.visit_with(visitor) || self.nested.visit_with(visitor) - } +BraceStructTypeFoldableImpl! { + impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableImplData<'tcx, N> { + impl_def_id, substs, nested + } where N: TypeFoldable<'tcx> } -impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableGeneratorData<'tcx, N> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - traits::VtableGeneratorData { - closure_def_id: self.closure_def_id, - substs: self.substs.fold_with(folder), - nested: self.nested.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.substs.visit_with(visitor) || self.nested.visit_with(visitor) - } +BraceStructTypeFoldableImpl! { + impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableGeneratorData<'tcx, N> { + closure_def_id, substs, nested + } where N: TypeFoldable<'tcx> } -impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableClosureData<'tcx, N> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - traits::VtableClosureData { - closure_def_id: self.closure_def_id, - substs: self.substs.fold_with(folder), - nested: self.nested.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.substs.visit_with(visitor) || self.nested.visit_with(visitor) - } +BraceStructTypeFoldableImpl! { + impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableClosureData<'tcx, N> { + closure_def_id, substs, nested + } where N: TypeFoldable<'tcx> } -impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableAutoImplData { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - traits::VtableAutoImplData { - trait_def_id: self.trait_def_id, - nested: self.nested.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.nested.visit_with(visitor) - } +BraceStructTypeFoldableImpl! { + impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableAutoImplData { + trait_def_id, nested + } where N: TypeFoldable<'tcx> } -impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableBuiltinData { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - traits::VtableBuiltinData { - nested: self.nested.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.nested.visit_with(visitor) - } +BraceStructTypeFoldableImpl! { + impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableBuiltinData { + nested + } where N: TypeFoldable<'tcx> } -impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx, N> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - traits::VtableObjectData { - upcast_trait_ref: self.upcast_trait_ref.fold_with(folder), - vtable_base: self.vtable_base, - nested: self.nested.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.upcast_trait_ref.visit_with(visitor) || self.nested.visit_with(visitor) - } +BraceStructTypeFoldableImpl! { + impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx, N> { + upcast_trait_ref, vtable_base, nested + } where N: TypeFoldable<'tcx> } -impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableFnPointerData<'tcx, N> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - traits::VtableFnPointerData { - fn_ty: self.fn_ty.fold_with(folder), - nested: self.nested.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.fn_ty.visit_with(visitor) || self.nested.visit_with(visitor) - } +BraceStructTypeFoldableImpl! { + impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableFnPointerData<'tcx, N> { + fn_ty, + nested + } where N: TypeFoldable<'tcx> } -impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - match *self { - traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)), - traits::VtableAutoImpl(ref t) => traits::VtableAutoImpl(t.fold_with(folder)), - traits::VtableGenerator(ref d) => { - traits::VtableGenerator(d.fold_with(folder)) - } - traits::VtableClosure(ref d) => { - traits::VtableClosure(d.fold_with(folder)) - } - traits::VtableFnPointer(ref d) => { - traits::VtableFnPointer(d.fold_with(folder)) - } - traits::VtableParam(ref n) => traits::VtableParam(n.fold_with(folder)), - traits::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)), - traits::VtableObject(ref d) => traits::VtableObject(d.fold_with(folder)), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - match *self { - traits::VtableImpl(ref v) => v.visit_with(visitor), - traits::VtableAutoImpl(ref t) => t.visit_with(visitor), - traits::VtableGenerator(ref d) => d.visit_with(visitor), - traits::VtableClosure(ref d) => d.visit_with(visitor), - traits::VtableFnPointer(ref d) => d.visit_with(visitor), - traits::VtableParam(ref n) => n.visit_with(visitor), - traits::VtableBuiltin(ref d) => d.visit_with(visitor), - traits::VtableObject(ref d) => d.visit_with(visitor), - } - } +EnumTypeFoldableImpl! { + impl<'tcx, N> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> { + (traits::VtableImpl)(a), + (traits::VtableAutoImpl)(a), + (traits::VtableGenerator)(a), + (traits::VtableClosure)(a), + (traits::VtableFnPointer)(a), + (traits::VtableParam)(a), + (traits::VtableBuiltin)(a), + (traits::VtableObject)(a), + } where N: TypeFoldable<'tcx> } -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Normalized<'tcx, T> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - Normalized { - value: self.value.fold_with(folder), - obligations: self.obligations.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.value.visit_with(visitor) || self.obligations.visit_with(visitor) - } +BraceStructTypeFoldableImpl! { + impl<'tcx, T> TypeFoldable<'tcx> for Normalized<'tcx, T> { + value, + obligations + } where T: TypeFoldable<'tcx> } -impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - match *self { - super::ExprAssignable | - super::MatchExpressionArm { arm_span: _, source: _ } | - super::IfExpression | - super::IfExpressionWithNoElse | - super::EquatePredicate | - super::MainFunctionType | - super::StartFunctionType | - super::IntrinsicType | - super::MethodReceiver | - super::MiscObligation | - super::SliceOrArrayElem | - super::TupleElem | - super::ItemObligation(_) | - super::AssignmentLhsSized | - super::TupleInitializerSized | - super::StructInitializerSized | - super::VariableType(_) | - super::ReturnType(_) | - super::SizedReturnType | - super::SizedYieldType | - super::ReturnNoExpression | - super::RepeatVec | - super::FieldSized(_) | - super::ConstSized | - super::SharedStatic | - super::BlockTailExpression(_) | - super::CompareImplMethodObligation { .. } => self.clone(), - - super::ProjectionWf(proj) => super::ProjectionWf(proj.fold_with(folder)), - super::ReferenceOutlivesReferent(ty) => { - super::ReferenceOutlivesReferent(ty.fold_with(folder)) - } - super::ObjectTypeBound(ty, r) => { - super::ObjectTypeBound(ty.fold_with(folder), r.fold_with(folder)) - } - super::ObjectCastObligation(ty) => { - super::ObjectCastObligation(ty.fold_with(folder)) - } - super::BuiltinDerivedObligation(ref cause) => { - super::BuiltinDerivedObligation(cause.fold_with(folder)) - } - super::ImplDerivedObligation(ref cause) => { - super::ImplDerivedObligation(cause.fold_with(folder)) - } - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - match *self { - super::ExprAssignable | - super::MatchExpressionArm { arm_span: _, source: _ } | - super::IfExpression | - super::IfExpressionWithNoElse | - super::EquatePredicate | - super::MainFunctionType | - super::StartFunctionType | - super::IntrinsicType | - super::MethodReceiver | - super::MiscObligation | - super::SliceOrArrayElem | - super::TupleElem | - super::ItemObligation(_) | - super::AssignmentLhsSized | - super::TupleInitializerSized | - super::StructInitializerSized | - super::VariableType(_) | - super::ReturnType(_) | - super::SizedReturnType | - super::SizedYieldType | - super::ReturnNoExpression | - super::RepeatVec | - super::FieldSized(_) | - super::ConstSized | - super::SharedStatic | - super::BlockTailExpression(_) | - super::CompareImplMethodObligation { .. } => false, - - super::ProjectionWf(proj) => proj.visit_with(visitor), - super::ReferenceOutlivesReferent(ty) => ty.visit_with(visitor), - super::ObjectTypeBound(ty, r) => ty.visit_with(visitor) || r.visit_with(visitor), - super::ObjectCastObligation(ty) => ty.visit_with(visitor), - super::BuiltinDerivedObligation(ref cause) => cause.visit_with(visitor), - super::ImplDerivedObligation(ref cause) => cause.visit_with(visitor) - } +EnumTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { + (super::ExprAssignable), + (super::MatchExpressionArm) { arm_span, source }, + (super::IfExpression), + (super::IfExpressionWithNoElse), + (super::EquatePredicate), + (super::MainFunctionType), + (super::StartFunctionType), + (super::IntrinsicType), + (super::MethodReceiver), + (super::MiscObligation), + (super::SliceOrArrayElem), + (super::TupleElem), + (super::ItemObligation)(a), + (super::AssignmentLhsSized), + (super::TupleInitializerSized), + (super::StructInitializerSized), + (super::VariableType)(a), + (super::ReturnType)(a), + (super::SizedReturnType), + (super::SizedYieldType), + (super::ReturnNoExpression), + (super::RepeatVec), + (super::FieldSized)(a), + (super::ConstSized), + (super::SharedStatic), + (super::BlockTailExpression)(a), + (super::CompareImplMethodObligation) { item_name, impl_item_def_id, trait_item_def_id }, + (super::ProjectionWf)(proj), + (super::ReferenceOutlivesReferent)(ty), + (super::ObjectTypeBound)(ty, r), + (super::ObjectCastObligation)(ty), + (super::BuiltinDerivedObligation)(cause), + (super::ImplDerivedObligation)(cause), } } -impl<'tcx> TypeFoldable<'tcx> for traits::DerivedObligationCause<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - traits::DerivedObligationCause { - parent_trait_ref: self.parent_trait_ref.fold_with(folder), - parent_code: self.parent_code.fold_with(folder) - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.parent_trait_ref.visit_with(visitor) || self.parent_code.visit_with(visitor) +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for traits::DerivedObligationCause<'tcx> { + parent_trait_ref, parent_code } } -impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCause<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - traits::ObligationCause { - span: self.span, - body_id: self.body_id, - code: self.code.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.code.visit_with(visitor) +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCause<'tcx> { + span, body_id, code } } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index c5b82730e488c..b96e3847bfb23 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -49,6 +49,9 @@ use util::nodemap::FxHashSet; /// The TypeFoldable trait is implemented for every type that can be folded. /// Basically, every type that has a corresponding method in TypeFolder. +/// +/// To implement this conveniently, use the +/// `BraceStructTypeFoldableImpl` etc macros found in `macros.rs`. pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self; fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 0dc1338fff860..0bc6745e715e4 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -28,152 +28,34 @@ use std::rc::Rc; // For things that don't carry any arena-allocated data (and are // copy...), just add them to this list. -macro_rules! CopyImpls { - ($($ty:ty,)+) => { - $( - impl<'tcx> Lift<'tcx> for $ty { - type Lifted = Self; - fn lift_to_tcx<'a, 'gcx>(&self, _: TyCtxt<'a, 'gcx, 'tcx>) -> Option { - Some(*self) - } - } - - impl<'tcx> TypeFoldable<'tcx> for $ty { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> $ty { - *self - } - - fn super_visit_with>(&self, _: &mut F) -> bool { - false - } - } - )+ - } -} - -CopyImpls! { +CopyTypeFoldableImpls! { (), + bool, + usize, + u64, + ::syntax::ast::FloatTy, + ::syntax::ast::NodeId, + ::syntax_pos::symbol::Symbol, + ::hir::def::Def, + ::hir::def_id::DefId, + ::hir::MatchSource, + ::hir::Mutability, ::hir::Unsafety, ::syntax::abi::Abi, - ::hir::def_id::DefId, ::mir::Local, ::traits::Reveal, + ::ty::adjustment::AutoBorrowMutability, + ::ty::AdtKind, + // Including `BoundRegion` is a *bit* dubious, but direct + // references to bound region appear in `ty::Error`, and aren't + // really meant to be folded. In general, we can only fold a fully + // general `Region`. + ::ty::BoundRegion, + ::ty::ClosureKind, + ::ty::IntVarValue, ::syntax_pos::Span, } -/////////////////////////////////////////////////////////////////////////// -// Macros -// -// When possible, use one of these (relatively) convenient macros to write -// the impls for you. - -#[macro_export] -macro_rules! BraceStructLiftImpl { - (impl<$($p:tt),*> Lift<$tcx:tt> for $s:path { - type Lifted = $lifted:ty; - $($field:ident),* $(,)* - } $(where $($wc:tt)*)*) => { - impl<$($p),*> $crate::ty::Lift<$tcx> for $s - $(where $($wc)*)* - { - type Lifted = $lifted; - - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<$lifted> { - $(let $field = tcx.lift(&self.$field)?;)* - Some(Self::Lifted { $($field),* }) - } - } - }; -} - -#[macro_export] -macro_rules! EnumLiftImpl { - (impl<$($p:tt),*> Lift<$tcx:tt> for $s:path { - type Lifted = $lifted:ty; - $( - ($variant:path) ( $( $variant_arg:ident),* ) - ),* - $(,)* - } $(where $($wc:tt)*)*) => { - impl<$($p),*> $crate::ty::Lift<$tcx> for $s - $(where $($wc)*)* - { - type Lifted = $lifted; - - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<$lifted> { - match self { - $($variant ( $($variant_arg),* ) => { - Some($variant ( $(tcx.lift($variant_arg)?),* )) - })* - } - } - } - }; -} - -#[macro_export] -macro_rules! BraceStructTypeFoldableImpl { - (impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path { - $($field:ident),* $(,)* - } $(where $($wc:tt)*)*) => { - impl<$($p),*> $crate::ty::fold::TypeFoldable<$tcx> for $s - $(where $($wc)*)* - { - fn super_fold_with<'gcx: $tcx, V: $crate::ty::fold::TypeFolder<'gcx, $tcx>>( - &self, - folder: &mut V, - ) -> Self { - let $s { $($field,)* } = self; - $s { $($field: $field.fold_with(folder),)* } - } - - fn super_visit_with>( - &self, - visitor: &mut V, - ) -> bool { - let $s { $($field,)* } = self; - false $(|| $field.visit_with(visitor))* - } - } - }; -} - -#[macro_export] -macro_rules! EnumTypeFoldableImpl { - (impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path { - $( - ($variant:path) ( $( $variant_arg:ident),* ) - ),* - $(,)* - } $(where $($wc:tt)*)*) => { - impl<$($p),*> $crate::ty::fold::TypeFoldable<$tcx> for $s - $(where $($wc)*)* - { - fn super_fold_with<'gcx: $tcx, V: $crate::ty::fold::TypeFolder<'gcx, $tcx>>( - &self, - folder: &mut V, - ) -> Self { - match self { - $($variant ( $($variant_arg),* ) => { - $variant ( $($variant_arg.fold_with(folder)),* ) - })* - } - } - - fn super_visit_with>( - &self, - visitor: &mut V, - ) -> bool { - match self { - $($variant ( $($variant_arg),* ) => { - false $(|| $variant_arg.visit_with(visitor))* - })* - } - } - } - }; -} - /////////////////////////////////////////////////////////////////////////// // Lift implementations @@ -674,14 +556,11 @@ impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T } } -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Option { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - self.as_ref().map(|t| t.fold_with(folder)) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) - } +EnumTypeFoldableImpl! { + impl<'tcx, T> TypeFoldable<'tcx> for Option { + (Some)(a), + (None), + } where T: TypeFoldable<'tcx> } impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc { @@ -748,22 +627,11 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice } } -impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialPredicate<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - use ty::ExistentialPredicate::*; - match *self { - Trait(ref tr) => Trait(tr.fold_with(folder)), - Projection(ref p) => Projection(p.fold_with(folder)), - AutoTrait(did) => AutoTrait(did), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - match *self { - ty::ExistentialPredicate::Trait(ref tr) => tr.visit_with(visitor), - ty::ExistentialPredicate::Projection(ref p) => p.visit_with(visitor), - ty::ExistentialPredicate::AutoTrait(_) => false, - } +EnumTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialPredicate<'tcx> { + (ty::ExistentialPredicate::Trait)(a), + (ty::ExistentialPredicate::Projection)(a), + (ty::ExistentialPredicate::AutoTrait)(a), } } @@ -848,13 +716,9 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::TypeAndMut { ty: self.ty.fold_with(folder), mutbl: self.mutbl } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.ty.visit_with(visitor) +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> { + ty, mutbl } } @@ -864,20 +728,9 @@ BraceStructTypeFoldableImpl! { } } -impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - let inputs_and_output = self.inputs_and_output.fold_with(folder); - ty::FnSig { - inputs_and_output: folder.tcx().intern_type_list(&inputs_and_output), - variadic: self.variadic, - unsafety: self.unsafety, - abi: self.abi, - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.inputs().iter().any(|i| i.visit_with(visitor)) || - self.output().visit_with(visitor) +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> { + inputs_and_output, variadic, unsafety, abi } } @@ -916,28 +769,15 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::ClosureSubsts { - substs: self.substs.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.substs.visit_with(visitor) +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> { + substs, } } -impl<'tcx> TypeFoldable<'tcx> for ty::GeneratorInterior<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::GeneratorInterior { - witness: self.witness.fold_with(folder), - movable: self.movable, - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.witness.visit_with(visitor) +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for ty::GeneratorInterior<'tcx> { + witness, movable, } } @@ -948,74 +788,32 @@ BraceStructTypeFoldableImpl! { } } -impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjust<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - match *self { - ty::adjustment::Adjust::NeverToAny | - ty::adjustment::Adjust::ReifyFnPointer | - ty::adjustment::Adjust::UnsafeFnPointer | - ty::adjustment::Adjust::ClosureFnPointer | - ty::adjustment::Adjust::MutToConstPointer | - ty::adjustment::Adjust::Unsize => self.clone(), - ty::adjustment::Adjust::Deref(ref overloaded) => { - ty::adjustment::Adjust::Deref(overloaded.fold_with(folder)) - } - ty::adjustment::Adjust::Borrow(ref autoref) => { - ty::adjustment::Adjust::Borrow(autoref.fold_with(folder)) - } - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - match *self { - ty::adjustment::Adjust::NeverToAny | - ty::adjustment::Adjust::ReifyFnPointer | - ty::adjustment::Adjust::UnsafeFnPointer | - ty::adjustment::Adjust::ClosureFnPointer | - ty::adjustment::Adjust::MutToConstPointer | - ty::adjustment::Adjust::Unsize => false, - ty::adjustment::Adjust::Deref(ref overloaded) => { - overloaded.visit_with(visitor) - } - ty::adjustment::Adjust::Borrow(ref autoref) => { - autoref.visit_with(visitor) - } - } +EnumTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjust<'tcx> { + (ty::adjustment::Adjust::NeverToAny), + (ty::adjustment::Adjust::ReifyFnPointer), + (ty::adjustment::Adjust::UnsafeFnPointer), + (ty::adjustment::Adjust::ClosureFnPointer), + (ty::adjustment::Adjust::MutToConstPointer), + (ty::adjustment::Adjust::Unsize), + (ty::adjustment::Adjust::Deref)(a), + (ty::adjustment::Adjust::Borrow)(a), } } -impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::OverloadedDeref<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::adjustment::OverloadedDeref { - region: self.region.fold_with(folder), - mutbl: self.mutbl, - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.region.visit_with(visitor) +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::OverloadedDeref<'tcx> { + region, mutbl, } } -impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoBorrow<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - match *self { - ty::adjustment::AutoBorrow::Ref(ref r, m) => { - ty::adjustment::AutoBorrow::Ref(r.fold_with(folder), m) - } - ty::adjustment::AutoBorrow::RawPtr(m) => ty::adjustment::AutoBorrow::RawPtr(m) - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - match *self { - ty::adjustment::AutoBorrow::Ref(r, _m) => r.visit_with(visitor), - ty::adjustment::AutoBorrow::RawPtr(_m) => false, - } +EnumTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoBorrow<'tcx> { + (ty::adjustment::AutoBorrow::Ref)(a, b), + (ty::adjustment::AutoBorrow::RawPtr)(m), } } - BraceStructTypeFoldableImpl! { impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> { parent, predicates @@ -1033,46 +831,18 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - match *self { - ty::Predicate::Trait(ref a) => - ty::Predicate::Trait(a.fold_with(folder)), - ty::Predicate::Equate(ref binder) => - ty::Predicate::Equate(binder.fold_with(folder)), - ty::Predicate::Subtype(ref binder) => - ty::Predicate::Subtype(binder.fold_with(folder)), - ty::Predicate::RegionOutlives(ref binder) => - ty::Predicate::RegionOutlives(binder.fold_with(folder)), - ty::Predicate::TypeOutlives(ref binder) => - ty::Predicate::TypeOutlives(binder.fold_with(folder)), - ty::Predicate::Projection(ref binder) => - ty::Predicate::Projection(binder.fold_with(folder)), - ty::Predicate::WellFormed(data) => - ty::Predicate::WellFormed(data.fold_with(folder)), - ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => - ty::Predicate::ClosureKind(closure_def_id, closure_substs.fold_with(folder), kind), - ty::Predicate::ObjectSafe(trait_def_id) => - ty::Predicate::ObjectSafe(trait_def_id), - ty::Predicate::ConstEvaluatable(def_id, substs) => - ty::Predicate::ConstEvaluatable(def_id, substs.fold_with(folder)), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - match *self { - ty::Predicate::Trait(ref a) => a.visit_with(visitor), - ty::Predicate::Equate(ref binder) => binder.visit_with(visitor), - ty::Predicate::Subtype(ref binder) => binder.visit_with(visitor), - ty::Predicate::RegionOutlives(ref binder) => binder.visit_with(visitor), - ty::Predicate::TypeOutlives(ref binder) => binder.visit_with(visitor), - ty::Predicate::Projection(ref binder) => binder.visit_with(visitor), - ty::Predicate::WellFormed(data) => data.visit_with(visitor), - ty::Predicate::ClosureKind(_closure_def_id, closure_substs, _kind) => - closure_substs.visit_with(visitor), - ty::Predicate::ObjectSafe(_trait_def_id) => false, - ty::Predicate::ConstEvaluatable(_def_id, substs) => substs.visit_with(visitor), - } +EnumTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { + (ty::Predicate::Trait)(a), + (ty::Predicate::Equate)(a), + (ty::Predicate::Subtype)(a), + (ty::Predicate::RegionOutlives)(a), + (ty::Predicate::TypeOutlives)(a), + (ty::Predicate::Projection)(a), + (ty::Predicate::WellFormed)(a), + (ty::Predicate::ClosureKind)(a, b, c), + (ty::Predicate::ObjectSafe)(a), + (ty::Predicate::ConstEvaluatable)(a, b), } } @@ -1100,94 +870,51 @@ BraceStructTypeFoldableImpl! { } } -impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::EquatePredicate(self.0.fold_with(folder), self.1.fold_with(folder)) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.0.visit_with(visitor) || self.1.visit_with(visitor) - } +BraceStructTypeFoldableImpl! { + impl<'tcx, T> TypeFoldable<'tcx> for ty::ParamEnvAnd<'tcx, T> { + param_env, value + } where T: TypeFoldable<'tcx> } -impl<'tcx> TypeFoldable<'tcx> for ty::SubtypePredicate<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::SubtypePredicate { - a_is_expected: self.a_is_expected, - a: self.a.fold_with(folder), - b: self.b.fold_with(folder) - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.a.visit_with(visitor) || self.b.visit_with(visitor) +TupleStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> { + a, b } } -impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::TraitPredicate { - trait_ref: self.trait_ref.fold_with(folder) - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.trait_ref.visit_with(visitor) +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for ty::SubtypePredicate<'tcx> { + a_is_expected, a, b } } -impl<'tcx,T,U> TypeFoldable<'tcx> for ty::OutlivesPredicate - where T : TypeFoldable<'tcx>, - U : TypeFoldable<'tcx>, -{ - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::OutlivesPredicate(self.0.fold_with(folder), - self.1.fold_with(folder)) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.0.visit_with(visitor) || self.1.visit_with(visitor) +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> { + trait_ref } } -impl<'tcx> TypeFoldable<'tcx> for ty::ClosureUpvar<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::ClosureUpvar { - def: self.def, - span: self.span, - ty: self.ty.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.ty.visit_with(visitor) - } +TupleStructTypeFoldableImpl! { + impl<'tcx,T,U> TypeFoldable<'tcx> for ty::OutlivesPredicate { + a, b + } where T : TypeFoldable<'tcx>, U : TypeFoldable<'tcx>, } -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::error::ExpectedFound { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::error::ExpectedFound { - expected: self.expected.fold_with(folder), - found: self.found.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.expected.visit_with(visitor) || self.found.visit_with(visitor) +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for ty::ClosureUpvar<'tcx> { + def, span, ty } } -impl<'tcx> TypeFoldable<'tcx> for type_variable::Default<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - type_variable::Default { - ty: self.ty.fold_with(folder), - origin_span: self.origin_span, - def_id: self.def_id - } - } +BraceStructTypeFoldableImpl! { + impl<'tcx, T> TypeFoldable<'tcx> for ty::error::ExpectedFound { + expected, found + } where T: TypeFoldable<'tcx> +} - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.ty.visit_with(visitor) +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for type_variable::Default<'tcx> { + ty, origin_span, def_id } } @@ -1201,71 +928,29 @@ impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec } } -impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - use ty::error::TypeError::*; - - match *self { - Mismatch => Mismatch, - UnsafetyMismatch(x) => UnsafetyMismatch(x.fold_with(folder)), - AbiMismatch(x) => AbiMismatch(x.fold_with(folder)), - Mutability => Mutability, - TupleSize(x) => TupleSize(x), - FixedArraySize(x) => FixedArraySize(x), - ArgCount => ArgCount, - RegionsDoesNotOutlive(a, b) => { - RegionsDoesNotOutlive(a.fold_with(folder), b.fold_with(folder)) - }, - RegionsInsufficientlyPolymorphic(a, b) => { - RegionsInsufficientlyPolymorphic(a, b.fold_with(folder)) - }, - RegionsOverlyPolymorphic(a, b) => { - RegionsOverlyPolymorphic(a, b.fold_with(folder)) - }, - IntMismatch(x) => IntMismatch(x), - FloatMismatch(x) => FloatMismatch(x), - Traits(x) => Traits(x), - VariadicMismatch(x) => VariadicMismatch(x), - CyclicTy(t) => CyclicTy(t.fold_with(folder)), - ProjectionMismatched(x) => ProjectionMismatched(x), - ProjectionBoundsLength(x) => ProjectionBoundsLength(x), - Sorts(x) => Sorts(x.fold_with(folder)), - TyParamDefaultMismatch(ref x) => TyParamDefaultMismatch(x.fold_with(folder)), - ExistentialMismatch(x) => ExistentialMismatch(x.fold_with(folder)), - OldStyleLUB(ref x) => OldStyleLUB(x.fold_with(folder)), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - use ty::error::TypeError::*; - - match *self { - UnsafetyMismatch(x) => x.visit_with(visitor), - AbiMismatch(x) => x.visit_with(visitor), - RegionsDoesNotOutlive(a, b) => { - a.visit_with(visitor) || b.visit_with(visitor) - }, - RegionsInsufficientlyPolymorphic(_, b) | - RegionsOverlyPolymorphic(_, b) => { - b.visit_with(visitor) - }, - Sorts(x) => x.visit_with(visitor), - OldStyleLUB(ref x) => x.visit_with(visitor), - TyParamDefaultMismatch(ref x) => x.visit_with(visitor), - ExistentialMismatch(x) => x.visit_with(visitor), - CyclicTy(t) => t.visit_with(visitor), - Mismatch | - Mutability | - TupleSize(_) | - FixedArraySize(_) | - ArgCount | - IntMismatch(_) | - FloatMismatch(_) | - Traits(_) | - VariadicMismatch(_) | - ProjectionMismatched(_) | - ProjectionBoundsLength(_) => false, - } +EnumTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> { + (ty::error::TypeError::Mismatch), + (ty::error::TypeError::UnsafetyMismatch)(x), + (ty::error::TypeError::AbiMismatch)(x), + (ty::error::TypeError::Mutability), + (ty::error::TypeError::TupleSize)(x), + (ty::error::TypeError::FixedArraySize)(x), + (ty::error::TypeError::ArgCount), + (ty::error::TypeError::RegionsDoesNotOutlive)(a, b), + (ty::error::TypeError::RegionsInsufficientlyPolymorphic)(a, b), + (ty::error::TypeError::RegionsOverlyPolymorphic)(a, b), + (ty::error::TypeError::IntMismatch)(x), + (ty::error::TypeError::FloatMismatch)(x), + (ty::error::TypeError::Traits)(x), + (ty::error::TypeError::VariadicMismatch)(x), + (ty::error::TypeError::CyclicTy)(t), + (ty::error::TypeError::ProjectionMismatched)(x), + (ty::error::TypeError::ProjectionBoundsLength)(x), + (ty::error::TypeError::Sorts)(x), + (ty::error::TypeError::TyParamDefaultMismatch)(x), + (ty::error::TypeError::ExistentialMismatch)(x), + (ty::error::TypeError::OldStyleLUB)(x), } } From 49ddc45b8fad76011b554acf99ac9919a456a048 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 14 Feb 2018 16:00:07 -0500 Subject: [PATCH 02/22] require `Lifted` types to outlive `'tcx` --- src/librustc/ty/context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e4e07454c97ac..4715fb0197ec0 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1400,7 +1400,7 @@ impl<'gcx: 'tcx, 'tcx> GlobalCtxt<'gcx> { /// pointer differs. The latter case is possible if a primitive type, /// e.g. `()` or `u8`, was interned in a different context. pub trait Lift<'tcx> { - type Lifted; + type Lifted: 'tcx; fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option; } From 517ace50f93f8b09b7ac000be663a7cab708b2cc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 14 Feb 2018 15:54:22 -0500 Subject: [PATCH 03/22] change CopyTypeFoldableImpls to use Clone and absolute paths --- src/librustc/macros.rs | 12 ++++++------ src/librustc/ty/structural_impls.rs | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index 78a54c100e4e4..ef4ead8773142 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -147,22 +147,22 @@ macro_rules! impl_stable_hash_for_spanned { /// Used for types that are `Copy` and which **do not care arena /// allocated data** (i.e., don't need to be folded). #[macro_export] -macro_rules! CopyTypeFoldableImpls { +macro_rules! CloneTypeFoldableImpls { ($($ty:ty,)+) => { $( - impl<'tcx> Lift<'tcx> for $ty { + impl<'tcx> $crate::ty::Lift<'tcx> for $ty { type Lifted = Self; - fn lift_to_tcx<'a, 'gcx>(&self, _: TyCtxt<'a, 'gcx, 'tcx>) -> Option { - Some(*self) + fn lift_to_tcx<'a, 'gcx>(&self, _: $crate::ty::TyCtxt<'a, 'gcx, 'tcx>) -> Option { + Some(Clone::clone(self)) } } - impl<'tcx> TypeFoldable<'tcx> for $ty { + impl<'tcx> $crate::ty::fold::TypeFoldable<'tcx> for $ty { fn super_fold_with<'gcx: 'tcx, F: $crate::ty::fold::TypeFolder<'gcx, 'tcx>>( &self, _: &mut F ) -> $ty { - *self + Clone::clone(self) } fn super_visit_with>( diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 0bc6745e715e4..5ba14b7d08679 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -28,7 +28,7 @@ use std::rc::Rc; // For things that don't carry any arena-allocated data (and are // copy...), just add them to this list. -CopyTypeFoldableImpls! { +CloneTypeFoldableImpls! { (), bool, usize, From 32efc787088f17d5d4fb12d47e5af983572d9eab Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 14 Feb 2018 15:59:46 -0500 Subject: [PATCH 04/22] port a bunch of TypeFoldable impls to use macros --- src/librustc/mir/cache.rs | 4 + src/librustc/mir/mod.rs | 186 ++++++++++------------------ src/librustc/mir/tcx.rs | 24 +--- src/librustc/ty/relate.rs | 11 +- src/librustc/ty/structural_impls.rs | 13 ++ 5 files changed, 88 insertions(+), 150 deletions(-) diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs index efc2f647cfdf5..470a37ae0a61c 100644 --- a/src/librustc/mir/cache.rs +++ b/src/librustc/mir/cache.rs @@ -76,3 +76,7 @@ fn calculate_predecessors(mir: &Mir) -> IndexVec> { result } + +CloneTypeFoldableImpls! { + Cache, +} diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 475946468fa35..f6e03bf20c036 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2081,148 +2081,90 @@ pub enum ClosureOutlivesSubject<'tcx> { * TypeFoldable implementations for MIR types */ -impl<'tcx> TypeFoldable<'tcx> for Mir<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - Mir { - basic_blocks: self.basic_blocks.fold_with(folder), - visibility_scopes: self.visibility_scopes.clone(), - visibility_scope_info: self.visibility_scope_info.clone(), - promoted: self.promoted.fold_with(folder), - yield_ty: self.yield_ty.fold_with(folder), - generator_drop: self.generator_drop.fold_with(folder), - generator_layout: self.generator_layout.fold_with(folder), - local_decls: self.local_decls.fold_with(folder), - arg_count: self.arg_count, - upvar_decls: self.upvar_decls.clone(), - spread_arg: self.spread_arg, - span: self.span, - cache: cache::Cache::new() - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.basic_blocks.visit_with(visitor) || - self.generator_drop.visit_with(visitor) || - self.generator_layout.visit_with(visitor) || - self.yield_ty.visit_with(visitor) || - self.promoted.visit_with(visitor) || - self.local_decls.visit_with(visitor) - } +CloneTypeFoldableImpls! { + Mutability, + SourceInfo, + UpvarDecl, + ValidationOp, + VisibilityScopeData, + VisibilityScope, + VisibilityScopeInfo, } -impl<'tcx> TypeFoldable<'tcx> for GeneratorLayout<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - GeneratorLayout { - fields: self.fields.fold_with(folder), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.fields.visit_with(visitor) +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for Mir<'tcx> { + basic_blocks, + visibility_scopes, + visibility_scope_info, + promoted, + yield_ty, + generator_drop, + generator_layout, + local_decls, + arg_count, + upvar_decls, + spread_arg, + span, + cache, } } -impl<'tcx> TypeFoldable<'tcx> for LocalDecl<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - LocalDecl { - ty: self.ty.fold_with(folder), - ..self.clone() - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.ty.visit_with(visitor) +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for GeneratorLayout<'tcx> { + fields } } -impl<'tcx> TypeFoldable<'tcx> for BasicBlockData<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - BasicBlockData { - statements: self.statements.fold_with(folder), - terminator: self.terminator.fold_with(folder), - is_cleanup: self.is_cleanup - } +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for LocalDecl<'tcx> { + mutability, + is_user_variable, + internal, + ty, + name, + source_info, + syntactic_scope, } +} - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.statements.visit_with(visitor) || self.terminator.visit_with(visitor) +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for BasicBlockData<'tcx> { + statements, + terminator, + is_cleanup, } } -impl<'tcx> TypeFoldable<'tcx> for ValidationOperand<'tcx, Place<'tcx>> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ValidationOperand { - place: self.place.fold_with(folder), - ty: self.ty.fold_with(folder), - re: self.re, - mutbl: self.mutbl, - } +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for ValidationOperand<'tcx, Place<'tcx>> { + place, ty, re, mutbl } +} - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.place.visit_with(visitor) || self.ty.visit_with(visitor) +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> { + source_info, kind } } -impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - use mir::StatementKind::*; - - let kind = match self.kind { - Assign(ref place, ref rval) => Assign(place.fold_with(folder), rval.fold_with(folder)), - SetDiscriminant { ref place, variant_index } => SetDiscriminant { - place: place.fold_with(folder), - variant_index, - }, - StorageLive(ref local) => StorageLive(local.fold_with(folder)), - StorageDead(ref local) => StorageDead(local.fold_with(folder)), - InlineAsm { ref asm, ref outputs, ref inputs } => InlineAsm { - asm: asm.clone(), - outputs: outputs.fold_with(folder), - inputs: inputs.fold_with(folder) - }, - - // Note for future: If we want to expose the region scopes - // during the fold, we need to either generalize EndRegion - // to carry `[ty::Region]`, or extend the `TypeFolder` - // trait with a `fn fold_scope`. - EndRegion(ref region_scope) => EndRegion(region_scope.clone()), - - Validate(ref op, ref places) => - Validate(op.clone(), - places.iter().map(|operand| operand.fold_with(folder)).collect()), - - Nop => Nop, - }; - Statement { - source_info: self.source_info, - kind, - } +EnumTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for StatementKind<'tcx> { + (StatementKind::Assign)(a, b), + (StatementKind::SetDiscriminant) { place, variant_index }, + (StatementKind::StorageLive)(a), + (StatementKind::StorageDead)(a), + (StatementKind::InlineAsm) { asm, outputs, inputs }, + (StatementKind::Validate)(a, b), + (StatementKind::EndRegion)(a), + (StatementKind::Nop), } +} - fn super_visit_with>(&self, visitor: &mut V) -> bool { - use mir::StatementKind::*; - - match self.kind { - Assign(ref place, ref rval) => { place.visit_with(visitor) || rval.visit_with(visitor) } - SetDiscriminant { ref place, .. } => place.visit_with(visitor), - StorageLive(ref local) | - StorageDead(ref local) => local.visit_with(visitor), - InlineAsm { ref outputs, ref inputs, .. } => - outputs.visit_with(visitor) || inputs.visit_with(visitor), - - // Note for future: If we want to expose the region scopes - // during the visit, we need to either generalize EndRegion - // to carry `[ty::Region]`, or extend the `TypeVisitor` - // trait with a `fn visit_scope`. - EndRegion(ref _scope) => false, - - Validate(ref _op, ref places) => - places.iter().any(|ty_and_place| ty_and_place.visit_with(visitor)), - - Nop => false, - } - } +EnumTypeFoldableImpl! { + impl<'tcx, T> TypeFoldable<'tcx> for ClearCrossCrate { + (ClearCrossCrate::Clear), + (ClearCrossCrate::Set)(a), + } where T: TypeFoldable<'tcx> } impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index bbfb9c89b3fc4..a18cce12abf55 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -16,7 +16,6 @@ use mir::*; use ty::subst::{Subst, Substs}; use ty::{self, AdtDef, Ty, TyCtxt}; -use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use hir; use ty::util::IntTypeExt; @@ -100,25 +99,10 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for PlaceTy<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - match *self { - PlaceTy::Ty { ty } => PlaceTy::Ty { ty: ty.fold_with(folder) }, - PlaceTy::Downcast { adt_def, substs, variant_index } => { - PlaceTy::Downcast { - adt_def, - substs: substs.fold_with(folder), - variant_index, - } - } - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - match *self { - PlaceTy::Ty { ty } => ty.visit_with(visitor), - PlaceTy::Downcast { substs, .. } => substs.visit_with(visitor) - } +EnumTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for PlaceTy<'tcx> { + (PlaceTy::Ty) { ty }, + (PlaceTy::Downcast) { adt_def, substs, variant_index }, } } diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index a6c72728a5125..85ada10258213 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -18,7 +18,6 @@ use middle::const_val::ConstVal; use traits::Reveal; use ty::subst::{Kind, Substs}; use ty::{self, Ty, TyCtxt, TypeFoldable}; -use ty::fold::{TypeVisitor, TypeFolder}; use ty::error::{ExpectedFound, TypeError}; use util::common::ErrorReported; use std::rc::Rc; @@ -323,13 +322,9 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> { #[derive(Debug, Clone)] struct GeneratorWitness<'tcx>(&'tcx ty::Slice>); -impl<'tcx> TypeFoldable<'tcx> for GeneratorWitness<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - GeneratorWitness(self.0.fold_with(folder)) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.0.visit_with(visitor) +TupleStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for GeneratorWitness<'tcx> { + a } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 5ba14b7d08679..5b91f5025045b 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -33,11 +33,13 @@ CloneTypeFoldableImpls! { bool, usize, u64, + ::middle::region::Scope, ::syntax::ast::FloatTy, ::syntax::ast::NodeId, ::syntax_pos::symbol::Symbol, ::hir::def::Def, ::hir::def_id::DefId, + ::hir::InlineAsm, ::hir::MatchSource, ::hir::Mutability, ::hir::Unsafety, @@ -546,6 +548,17 @@ impl<'a, 'tcx> Lift<'tcx> for ty::layout::LayoutError<'a> { // can easily refactor the folding into the TypeFolder trait as // needed. +/// AdtDefs are basically the same as a DefId. +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::AdtDef { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self { + *self + } + + fn super_visit_with>(&self, _visitor: &mut V) -> bool { + false + } +} + impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> (T, U) { (self.0.fold_with(folder), self.1.fold_with(folder)) From 3410295fb6970e3aeb598e010d9c70a29cff4b06 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 9 Feb 2018 10:39:46 -0500 Subject: [PATCH 05/22] add `TypeRelation` and `Lift` impls for `Kind` --- src/librustc/ty/relate.rs | 27 ++++++++++++++++++++------- src/librustc/ty/subst.rs | 16 +++++++++++++++- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 85ada10258213..6d1caa3cbab2f 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -141,13 +141,7 @@ pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R, let params = a_subst.iter().zip(b_subst).enumerate().map(|(i, (a, b))| { let variance = variances.map_or(ty::Invariant, |v| v[i]); - if let (Some(a_ty), Some(b_ty)) = (a.as_type(), b.as_type()) { - Ok(Kind::from(relation.relate_with_variance(variance, &a_ty, &b_ty)?)) - } else if let (Some(a_r), Some(b_r)) = (a.as_region(), b.as_region()) { - Ok(Kind::from(relation.relate_with_variance(variance, &a_r, &b_r)?)) - } else { - bug!() - } + relation.relate_with_variance(variance, a, b) }); Ok(tcx.mk_substs(params)?) @@ -674,6 +668,25 @@ impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for Box { } } +impl<'tcx> Relate<'tcx> for Kind<'tcx> { + fn relate<'a, 'gcx, R>( + relation: &mut R, + a: &Kind<'tcx>, + b: &Kind<'tcx> + ) -> RelateResult<'tcx, Kind<'tcx>> + where + R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a, + { + if let (Some(a_ty), Some(b_ty)) = (a.as_type(), b.as_type()) { + Ok(Kind::from(relation.relate(&a_ty, &b_ty)?)) + } else if let (Some(a_r), Some(b_r)) = (a.as_region(), b.as_region()) { + Ok(Kind::from(relation.relate(&a_r, &b_r)?)) + } else { + bug!() + } + } +} + /////////////////////////////////////////////////////////////////////////// // Error handling diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 7c167f69ebd8c..e1f30261d296f 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -11,7 +11,7 @@ // Type substitutions. use hir::def_id::DefId; -use ty::{self, Slice, Region, Ty, TyCtxt}; +use ty::{self, Lift, Slice, Region, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use serialize::{self, Encodable, Encoder, Decodable, Decoder}; @@ -120,6 +120,20 @@ impl<'tcx> fmt::Display for Kind<'tcx> { } } +impl<'a, 'tcx> Lift<'tcx> for Kind<'a> { + type Lifted = Kind<'tcx>; + + fn lift_to_tcx<'cx, 'gcx>(&self, tcx: TyCtxt<'cx, 'gcx, 'tcx>) -> Option { + if let Some(ty) = self.as_type() { + ty.lift_to_tcx(tcx).map(Kind::from) + } else if let Some(r) = self.as_region() { + r.lift_to_tcx(tcx).map(Kind::from) + } else { + bug!() + } + } +} + impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { if let Some(ty) = self.as_type() { From 3c87e2c3fb7cd27a66fe8ff9da199e22d9cc9992 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 9 Feb 2018 11:24:18 -0500 Subject: [PATCH 06/22] fix typo in comment --- src/librustc/infer/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 7a386c144b738..1aea965ca7d25 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1278,7 +1278,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // it can be resolved to an int/float variable, which // can then be recursively resolved, hence the // recursion. Note though that we prevent type - // variables from unifying to other type variables + // variables from unifyxing to other type variables // directly (though they may be embedded // structurally), and we prevent cycles in any case, // so this recursion should always be of very limited From a533814a9993dfec29dc04bfdfa383e80c8b91b0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 9 Feb 2018 10:43:15 -0500 Subject: [PATCH 07/22] make regions "traceable" so you can do `infcx.at(..).eq(r1, r2)` --- src/librustc/infer/at.rs | 14 ++++++++ src/librustc/infer/error_reporting/mod.rs | 1 + src/librustc/infer/mod.rs | 43 ++++++----------------- 3 files changed, 26 insertions(+), 32 deletions(-) diff --git a/src/librustc/infer/at.rs b/src/librustc/infer/at.rs index 3fd7ee276729f..d9fbf4aa51482 100644 --- a/src/librustc/infer/at.rs +++ b/src/librustc/infer/at.rs @@ -281,6 +281,20 @@ impl<'tcx> ToTrace<'tcx> for Ty<'tcx> { } } +impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Self, + b: Self) + -> TypeTrace<'tcx> + { + TypeTrace { + cause: cause.clone(), + values: Regions(ExpectedFound::new(a_is_expected, a, b)) + } + } +} + impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> { fn to_trace(cause: &ObligationCause<'tcx>, a_is_expected: bool, diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 700d06acf11a4..7c7da47c7a8a7 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -895,6 +895,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { match *values { infer::Types(ref exp_found) => self.expected_found_str_ty(exp_found), + infer::Regions(ref exp_found) => self.expected_found_str(exp_found), infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found), infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found), } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 1aea965ca7d25..9c0d7cf5e38da 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -26,7 +26,7 @@ use ty::subst::{Kind, Subst, Substs}; use ty::{TyVid, IntVid, FloatVid}; use ty::{self, Ty, TyCtxt}; use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; -use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; +use ty::fold::TypeFoldable; use ty::relate::RelateResult; use traits::{self, ObligationCause, PredicateObligations, Reveal}; use rustc_data_structures::unify::{self, UnificationTable}; @@ -191,6 +191,7 @@ pub type SkolemizationMap<'tcx> = BTreeMap>; #[derive(Clone, Debug)] pub enum ValuePairs<'tcx> { Types(ExpectedFound>), + Regions(ExpectedFound>), TraitRefs(ExpectedFound>), PolyTraitRefs(ExpectedFound>), } @@ -1676,40 +1677,18 @@ impl RegionVariableOrigin { } } -impl<'tcx> TypeFoldable<'tcx> for ValuePairs<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - match *self { - ValuePairs::Types(ref ef) => { - ValuePairs::Types(ef.fold_with(folder)) - } - ValuePairs::TraitRefs(ref ef) => { - ValuePairs::TraitRefs(ef.fold_with(folder)) - } - ValuePairs::PolyTraitRefs(ref ef) => { - ValuePairs::PolyTraitRefs(ef.fold_with(folder)) - } - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - match *self { - ValuePairs::Types(ref ef) => ef.visit_with(visitor), - ValuePairs::TraitRefs(ref ef) => ef.visit_with(visitor), - ValuePairs::PolyTraitRefs(ref ef) => ef.visit_with(visitor), - } +EnumTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for ValuePairs<'tcx> { + (ValuePairs::Types)(a), + (ValuePairs::Regions)(a), + (ValuePairs::TraitRefs)(a), + (ValuePairs::PolyTraitRefs)(a), } } -impl<'tcx> TypeFoldable<'tcx> for TypeTrace<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - TypeTrace { - cause: self.cause.fold_with(folder), - values: self.values.fold_with(folder) - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.cause.visit_with(visitor) || self.values.visit_with(visitor) +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for TypeTrace<'tcx> { + cause, values } } From 97776fd7d60ae6b02810d7beba40dcc49bbed5c8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 9 Feb 2018 10:43:36 -0500 Subject: [PATCH 08/22] comment the purpose of `TransNormalize` --- src/librustc/infer/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 9c0d7cf5e38da..ff953c46d3bde 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -487,6 +487,10 @@ pub struct CombinedSnapshot<'a, 'tcx:'a> { /// Helper trait for shortening the lifetimes inside a /// value for post-type-checking normalization. +/// +/// This trait offers a normalization method where the inputs and +/// outputs both have the `'gcx` lifetime; the implementations +/// internally create inference contexts and/or lift as needed. pub trait TransNormalize<'gcx>: TypeFoldable<'gcx> { fn trans_normalize<'a, 'tcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, From 0a56f5357f2bd73685f09ef54b0dd376f1161b62 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 21 Feb 2018 04:16:25 -0500 Subject: [PATCH 09/22] random reformatting --- .../borrow_check/nll/type_check/liveness.rs | 10 +++----- .../borrow_check/nll/type_check/mod.rs | 23 +++++++++++-------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness.rs index a50b99937475e..5b3f439e0ebb9 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness.rs @@ -105,8 +105,7 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo for live_local in live_locals { debug!( "add_liveness_constraints: location={:?} live_local={:?}", - location, - live_local + location, live_local ); self.flow_inits.each_state_bit(|mpi_init| { @@ -157,8 +156,7 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo { debug!( "push_type_live_constraint(live_ty={:?}, location={:?})", - value, - location + value, location ); self.tcx.for_each_free_region(&value, |live_region| { @@ -182,9 +180,7 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo ) { debug!( "add_drop_live_constraint(dropped_local={:?}, dropped_ty={:?}, location={:?})", - dropped_local, - dropped_ty, - location + dropped_local, dropped_ty, location ); // If we end visiting the same type twice (usually due to a cycle involving 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 7ca8d0bdd500b..6cba617d19cd1 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -244,8 +244,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { fn sanitize_constant(&mut self, constant: &Constant<'tcx>, location: Location) { debug!( "sanitize_constant(constant={:?}, location={:?})", - constant, - location + constant, location ); let expected_ty = match constant.literal { @@ -690,8 +689,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let data = self.infcx.take_and_reset_region_constraints(); if !data.is_empty() { - debug!("fully_perform_op: constraints generated at {:?} are {:#?}", - locations, data); + debug!( + "fully_perform_op: constraints generated at {:?} are {:#?}", + locations, data + ); self.constraints .outlives_sets .push(OutlivesSet { locations, data }); @@ -1155,12 +1156,16 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } TerminatorKind::FalseUnwind { real_target, - unwind + unwind, } => { self.assert_iscleanup(mir, block_data, real_target, is_cleanup); if let Some(unwind) = unwind { if is_cleanup { - span_mirbug!(self, block_data, "cleanup in cleanup block via false unwind"); + span_mirbug!( + self, + block_data, + "cleanup in cleanup block via false unwind" + ); } self.assert_iscleanup(mir, block_data, unwind, true); } @@ -1453,8 +1458,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { debug!( "prove_aggregate_predicates(aggregate_kind={:?}, location={:?})", - aggregate_kind, - location + aggregate_kind, location ); let instantiated_predicates = match aggregate_kind { @@ -1520,8 +1524,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { fn prove_predicates(&mut self, predicates: &[ty::Predicate<'tcx>], location: Location) { debug!( "prove_predicates(predicates={:?}, location={:?})", - predicates, - location + predicates, location ); self.fully_perform_op(location.at_self(), |this| { let cause = this.misc(this.last_span); From ae6f77a4b39eaf2663fc928a6dd3da86ba4999b8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 20 Feb 2018 10:36:29 -0500 Subject: [PATCH 10/22] add handy helper for Cell, used for perf stats --- src/librustc/util/common.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 2971f3e853a99..3892b6cfed119 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -350,3 +350,13 @@ fn test_to_readable_str() { assert_eq!("1_000_000", to_readable_str(1_000_000)); assert_eq!("1_234_567", to_readable_str(1_234_567)); } + +pub trait CellUsizeExt { + fn increment(&self); +} + +impl CellUsizeExt for Cell { + fn increment(&self) { + self.set(self.get() + 1); + } +} From e18c96673fb10c9202cfbf93865a419dd99c4777 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 10 Feb 2018 13:18:02 -0500 Subject: [PATCH 11/22] refactor `ParamEnv::empty(Reveal)` into two distinct methods - `ParamEnv::empty()` -- does not reveal all, good for typeck - `ParamEnv::reveal_all()` -- does, good for trans - `param_env.with_reveal_all()` -- converts an existing parameter environment --- src/librustc/infer/mod.rs | 6 ++--- src/librustc/lint/context.rs | 3 +-- src/librustc/traits/coherence.rs | 4 +-- src/librustc/traits/error_reporting.rs | 3 +-- src/librustc/traits/mod.rs | 2 +- src/librustc/traits/select.rs | 2 +- src/librustc/traits/specialize/mod.rs | 4 +-- src/librustc/ty/instance.rs | 2 +- src/librustc/ty/layout.rs | 8 +++--- src/librustc/ty/mod.rs | 6 ++--- src/librustc/ty/relate.rs | 3 +-- src/librustc/ty/util.rs | 26 +++++++++++++++++--- src/librustc_driver/test.rs | 4 +-- src/librustc_lint/builtin.rs | 4 +-- src/librustc_mir/interpret/eval_context.rs | 3 +-- src/librustc_mir/monomorphize/collector.rs | 15 ++++++----- src/librustc_mir/monomorphize/mod.rs | 4 +-- src/librustc_mir/transform/qualify_consts.rs | 4 +-- src/librustc_passes/consts.rs | 3 +-- src/librustc_trans/callee.rs | 3 +-- src/librustc_trans/common.rs | 7 +++--- src/librustc_trans/context.rs | 5 ++-- src/librustc_trans/mir/block.rs | 3 +-- src/librustc_trans/mir/constant.rs | 3 +-- src/librustc_typeck/check/compare_method.rs | 4 +-- src/librustc_typeck/check/dropck.rs | 4 +-- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/collect.rs | 3 +-- src/librustc_typeck/lib.rs | 4 +-- 29 files changed, 75 insertions(+), 69 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index ff953c46d3bde..400ca03f4caed 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -28,7 +28,7 @@ use ty::{self, Ty, TyCtxt}; use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; use ty::fold::TypeFoldable; use ty::relate::RelateResult; -use traits::{self, ObligationCause, PredicateObligations, Reveal}; +use traits::{self, ObligationCause, PredicateObligations}; use rustc_data_structures::unify::{self, UnificationTable}; use std::cell::{Cell, RefCell, Ref, RefMut}; use std::collections::BTreeMap; @@ -563,7 +563,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { { debug!("fully_normalize_associated_types_in(t={:?})", value); - let param_env = ty::ParamEnv::empty(Reveal::All); + let param_env = ty::ParamEnv::reveal_all(); let value = self.erase_regions(value); if !value.has_projections() { @@ -593,7 +593,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { } self.infer_ctxt().enter(|infcx| { - value.trans_normalize(&infcx, env.reveal_all()) + value.trans_normalize(&infcx, env.with_reveal_all()) }) } } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index ed937046e5ed7..34bf4be9d200b 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -33,7 +33,6 @@ use lint::levels::{LintLevelSets, LintLevelsBuilder}; use middle::privacy::AccessLevels; use rustc_serialize::{Decoder, Decodable, Encoder, Encodable}; use session::{config, early_error, Session}; -use traits::Reveal; use ty::{self, TyCtxt, Ty}; use ty::layout::{LayoutError, LayoutOf, TyLayout}; use util::nodemap::FxHashMap; @@ -1003,7 +1002,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut cx = LateContext { tcx, tables: &ty::TypeckTables::empty(None), - param_env: ty::ParamEnv::empty(Reveal::UserFacing), + param_env: ty::ParamEnv::empty(), access_levels, lint_sess: LintSession::new(&tcx.sess.lint_store), last_ast_node_with_lint_attrs: ast::CRATE_NODE_ID, diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 7311b47974ac5..9860a19c928a3 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -12,7 +12,7 @@ use hir::def_id::{DefId, LOCAL_CRATE}; use syntax_pos::DUMMY_SP; -use traits::{self, Normalized, SelectionContext, Obligation, ObligationCause, Reveal}; +use traits::{self, Normalized, SelectionContext, Obligation, ObligationCause}; use traits::IntercrateMode; use traits::select::IntercrateAmbiguityCause; use ty::{self, Ty, TyCtxt}; @@ -119,7 +119,7 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, // types into scope; instead, we replace the generic types with // fresh type variables, and hence we do our evaluations in an // empty environment. - let param_env = ty::ParamEnv::empty(Reveal::UserFacing); + let param_env = ty::ParamEnv::empty(); let a_impl_header = with_fresh_ty_vars(selcx, param_env, a_def_id); let b_impl_header = with_fresh_ty_vars(selcx, param_env, b_def_id); diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 214d8ec325f2b..b5c2ccc017f28 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -21,7 +21,6 @@ use super::{ TraitNotObjectSafe, ConstEvalFailure, PredicateObligation, - Reveal, SelectionContext, SelectionError, ObjectSafetyViolation, @@ -141,7 +140,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // FIXME: I'm just not taking associated types at all here. // Eventually I'll need to implement param-env-aware // `Γ₁ ⊦ φ₁ => Γ₂ ⊦ φ₂` logic. - let param_env = ty::ParamEnv::empty(Reveal::UserFacing); + let param_env = ty::ParamEnv::empty(); if let Ok(_) = self.can_sub(param_env, error, implication) { debug!("error_implies: {:?} -> {:?} -> {:?}", cond, error, implication); return true diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 31836f7e3c57b..e716216f4f5b7 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -681,7 +681,7 @@ fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, predicates); let result = tcx.infer_ctxt().enter(|infcx| { - let param_env = ty::ParamEnv::empty(Reveal::All); + let param_env = ty::ParamEnv::reveal_all(); let mut selcx = SelectionContext::new(&infcx); let mut fulfill_cx = FulfillmentContext::new(); let cause = ObligationCause::dummy(); diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index cfeb456acefe6..4ac027c6fde8f 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -805,7 +805,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // value in order to work, so we can clear out the param env and get better // caching. (If the current param env is inconsistent, we don't care what happens). debug!("evaluate_trait_predicate_recursively({:?}) - in global", obligation); - obligation.param_env = ty::ParamEnv::empty(obligation.param_env.reveal); + obligation.param_env = obligation.param_env.without_caller_bounds(); } let stack = self.push_stack(previous_stack, &obligation); diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index afe29cc0e7baf..17f6cd27d969f 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -24,7 +24,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use hir::def_id::DefId; use infer::{InferCtxt, InferOk}; use ty::subst::{Subst, Substs}; -use traits::{self, Reveal, ObligationCause}; +use traits::{self, ObligationCause}; use traits::select::IntercrateAmbiguityCause; use ty::{self, TyCtxt, TypeFoldable}; use syntax_pos::DUMMY_SP; @@ -130,7 +130,7 @@ pub fn find_associated_item<'a, 'tcx>( match ancestors.defs(tcx, item.name, item.kind, trait_def_id).next() { Some(node_item) => { let substs = tcx.infer_ctxt().enter(|infcx| { - let param_env = ty::ParamEnv::empty(Reveal::All); + let param_env = ty::ParamEnv::reveal_all(); let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs); let substs = translate_substs(&infcx, param_env, impl_data.impl_def_id, substs, node_item.node); diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 63bf52a9bdf78..e2ab53bf8464d 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -200,7 +200,7 @@ impl<'a, 'b, 'tcx> Instance<'tcx> { _ => { if Some(def_id) == tcx.lang_items().drop_in_place_fn() { let ty = substs.type_at(0); - if ty.needs_drop(tcx, ty::ParamEnv::empty(traits::Reveal::All)) { + if ty.needs_drop(tcx, ty::ParamEnv::reveal_all()) { debug!(" => nontrivial drop glue"); ty::InstanceDef::DropGlue(def_id, Some(ty)) } else { diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index c3cd65230bd86..10ecf5d1bd5c2 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -2047,7 +2047,7 @@ impl<'a, 'tcx> LayoutOf> for LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { /// Computes the layout of a type. Note that this implicitly /// executes in "reveal all" mode. fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { - let param_env = self.param_env.reveal_all(); + let param_env = self.param_env.with_reveal_all(); let ty = self.tcx.normalize_associated_type_in_env(&ty, param_env); let details = self.tcx.layout_raw(param_env.and(ty))?; let layout = TyLayout { @@ -2073,9 +2073,9 @@ impl<'a, 'tcx> LayoutOf> for LayoutCx<'tcx, ty::maps::TyCtxtAt<'a, 'tcx /// Computes the layout of a type. Note that this implicitly /// executes in "reveal all" mode. fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { - let param_env = self.param_env.reveal_all(); - let ty = self.tcx.normalize_associated_type_in_env(&ty, param_env.reveal_all()); - let details = self.tcx.layout_raw(param_env.reveal_all().and(ty))?; + let param_env = self.param_env.with_reveal_all(); + let ty = self.tcx.normalize_associated_type_in_env(&ty, param_env); + let details = self.tcx.layout_raw(param_env.and(ty))?; let layout = TyLayout { ty, details diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f52f2ea0f9fc8..7a438ccadc4f9 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1375,7 +1375,7 @@ impl<'tcx> ParamEnv<'tcx> { } } else { ParamEnvAnd { - param_env: ParamEnv::empty(self.reveal), + param_env: self.without_caller_bounds(), value, } } @@ -1781,7 +1781,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { #[inline] pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> impl Iterator + 'a { - let param_env = ParamEnv::empty(traits::Reveal::UserFacing); + let param_env = ParamEnv::empty(); let repr_type = self.repr.discr_type(); let initial = repr_type.initial_discriminant(tcx.global_tcx()); let mut prev_discr = None::; @@ -1817,7 +1817,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { tcx: TyCtxt<'a, 'gcx, 'tcx>, variant_index: usize) -> ConstInt { - let param_env = ParamEnv::empty(traits::Reveal::UserFacing); + let param_env = ParamEnv::empty(); let repr_type = self.repr.discr_type(); let mut explicit_value = repr_type.initial_discriminant(tcx.global_tcx()); let mut explicit_index = variant_index; diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 6d1caa3cbab2f..90dba918b0816 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -15,7 +15,6 @@ use hir::def_id::DefId; use middle::const_val::ConstVal; -use traits::Reveal; use ty::subst::{Kind, Substs}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::error::{ExpectedFound, TypeError}; @@ -472,7 +471,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, ConstVal::Integral(x) => Ok(x.to_u64().unwrap()), ConstVal::Unevaluated(def_id, substs) => { // FIXME(eddyb) get the right param_env. - let param_env = ty::ParamEnv::empty(Reveal::UserFacing); + let param_env = ty::ParamEnv::empty(); match tcx.lift_to_global(&substs) { Some(substs) => { match tcx.const_eval(param_env.and((def_id, substs))) { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 34f05232adcab..6e4ed6dbf0810 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -151,9 +151,22 @@ pub enum Representability { impl<'tcx> ty::ParamEnv<'tcx> { /// Construct a trait environment suitable for contexts where - /// there are no where clauses in scope. - pub fn empty(reveal: Reveal) -> Self { - Self::new(ty::Slice::empty(), reveal) + /// there are no where clauses in scope. Hidden types (like `impl + /// Trait`) are left hidden, so this is suitable for ordinary + /// type-checking. + pub fn empty() -> Self { + Self::new(ty::Slice::empty(), Reveal::UserFacing) + } + + /// Construct a trait environment with no where clauses in scope + /// where the values of all `impl Trait` and other hidden types + /// are revealed. This is suitable for monomorphized, post-typeck + /// environments like trans or doing optimizations. + /// + /// NB. If you want to have predicates in scope, use `ParamEnv::new`, + /// or invoke `param_env.with_reveal_all()`. + pub fn reveal_all() -> Self { + Self::new(ty::Slice::empty(), Reveal::All) } /// Construct a trait environment with the given set of predicates. @@ -169,10 +182,15 @@ impl<'tcx> ty::ParamEnv<'tcx> { /// the desired behavior during trans and certain other special /// contexts; normally though we want to use `Reveal::UserFacing`, /// which is the default. - pub fn reveal_all(self) -> Self { + pub fn with_reveal_all(self) -> Self { ty::ParamEnv { reveal: Reveal::All, ..self } } + /// Returns this same environment but with no caller bounds. + pub fn without_caller_bounds(self) -> Self { + ty::ParamEnv { caller_bounds: ty::Slice::empty(), ..self } + } + pub fn can_type_implement_copy<'a>(self, tcx: TyCtxt<'a, 'tcx, 'tcx>, self_type: Ty<'tcx>, span: Span) diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 306e7e9c16dce..be6ac51be7a48 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -18,7 +18,7 @@ use rustc_lint; use rustc_resolve::MakeGlobMap; use rustc::middle::region; use rustc::ty::subst::{Kind, Subst}; -use rustc::traits::{ObligationCause, Reveal}; +use rustc::traits::ObligationCause; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::maps::OnDiskCache; use rustc::infer::{self, InferOk, InferResult}; @@ -153,7 +153,7 @@ fn test_env(source_string: &str, |tcx| { tcx.infer_ctxt().enter(|infcx| { let mut region_scope_tree = region::ScopeTree::default(); - let param_env = ty::ParamEnv::empty(Reveal::UserFacing); + let param_env = ty::ParamEnv::empty(); body(Env { infcx: &infcx, region_scope_tree: &mut region_scope_tree, diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index de55710bdf3d0..b183a1e4512a2 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -33,7 +33,7 @@ use rustc::hir::def_id::DefId; use rustc::cfg; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty}; -use rustc::traits::{self, Reveal}; +use rustc::traits; use rustc::hir::map as hir_map; use util::nodemap::NodeSet; use lint::{LateContext, LintContext, LintArray}; @@ -525,7 +525,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations { if def.has_dtor(cx.tcx) { return; } - let param_env = ty::ParamEnv::empty(Reveal::UserFacing); + let param_env = ty::ParamEnv::empty(); if !ty.moves_by_default(cx.tcx, param_env, item.span) { return; } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 3578164feb7c5..7580f728a55d3 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -5,7 +5,6 @@ use rustc::hir::def_id::DefId; use rustc::hir::map::definitions::DefPathData; use rustc::middle::const_val::ConstVal; use rustc::mir; -use rustc::traits::Reveal; use rustc::ty::layout::{self, Size, Align, HasDataLayout, LayoutOf, TyLayout}; use rustc::ty::subst::{Subst, Substs, Kind}; use rustc::ty::{self, Ty, TyCtxt}; @@ -1664,5 +1663,5 @@ pub fn resolve_drop_in_place<'a, 'tcx>( ) -> ty::Instance<'tcx> { let def_id = tcx.require_lang_item(::rustc::middle::lang_items::DropInPlaceFnLangItem); let substs = tcx.intern_substs(&[Kind::from(ty)]); - ty::Instance::resolve(tcx, ty::ParamEnv::empty(Reveal::All), def_id, substs).unwrap() + ty::Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap() } diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index a80dfaef0dab1..bbd504cf187dc 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -195,7 +195,6 @@ use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; use rustc::middle::const_val::ConstVal; use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem}; -use rustc::traits; use rustc::ty::subst::{Substs, Kind}; use rustc::ty::{self, TypeFoldable, Ty, TyCtxt}; use rustc::ty::adjustment::CustomCoerceUnsized; @@ -575,7 +574,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { let substs = self.tcx.trans_apply_param_substs(self.param_substs, &substs); let instance = ty::Instance::resolve(self.tcx, - ty::ParamEnv::empty(traits::Reveal::All), + ty::ParamEnv::reveal_all(), def_id, substs).unwrap(); collect_neighbours(self.tcx, instance, true, self.output); @@ -600,7 +599,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { (true, &ty::TyFnDef(def_id, substs)) if self.tcx.is_const_fn(def_id) => { let instance = ty::Instance::resolve(self.tcx, - ty::ParamEnv::empty(traits::Reveal::All), + ty::ParamEnv::reveal_all(), def_id, substs).unwrap(); Some(instance) @@ -676,7 +675,7 @@ fn visit_fn_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { if let ty::TyFnDef(def_id, substs) = ty.sty { let instance = ty::Instance::resolve(tcx, - ty::ParamEnv::empty(traits::Reveal::All), + ty::ParamEnv::reveal_all(), def_id, substs).unwrap(); visit_instance_use(tcx, instance, is_direct_call, output); @@ -798,7 +797,7 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| { let type_has_metadata = |ty: Ty<'tcx>| -> bool { use syntax_pos::DUMMY_SP; - if ty.is_sized(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) { + if ty.is_sized(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP) { return false; } let tail = tcx.struct_tail(ty); @@ -881,7 +880,7 @@ fn create_mono_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let methods = methods.iter().cloned().filter_map(|method| method) .map(|(def_id, substs)| ty::Instance::resolve( tcx, - ty::ParamEnv::empty(traits::Reveal::All), + ty::ParamEnv::reveal_all(), def_id, substs).unwrap()) .filter(|&instance| should_monomorphize_locally(tcx, &instance)) @@ -1035,7 +1034,7 @@ impl<'b, 'a, 'v> RootCollector<'b, 'a, 'v> { let start_instance = Instance::resolve( self.tcx, - ty::ParamEnv::empty(traits::Reveal::All), + ty::ParamEnv::reveal_all(), start_def_id, self.tcx.mk_substs(iter::once(Kind::from(main_ret_ty))) ).unwrap(); @@ -1084,7 +1083,7 @@ fn create_mono_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let instance = ty::Instance::resolve(tcx, - ty::ParamEnv::empty(traits::Reveal::All), + ty::ParamEnv::reveal_all(), method.def_id, callee_substs).unwrap(); diff --git a/src/librustc_mir/monomorphize/mod.rs b/src/librustc_mir/monomorphize/mod.rs index 95ebb6c970a58..bab1d325cd99c 100644 --- a/src/librustc_mir/monomorphize/mod.rs +++ b/src/librustc_mir/monomorphize/mod.rs @@ -154,7 +154,7 @@ pub fn resolve_drop_in_place<'a, 'tcx>( { let def_id = tcx.require_lang_item(DropInPlaceFnLangItem); let substs = tcx.intern_substs(&[Kind::from(ty)]); - Instance::resolve(tcx, ty::ParamEnv::empty(traits::Reveal::All), def_id, substs).unwrap() + Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap() } pub fn custom_coerce_unsize_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -168,7 +168,7 @@ pub fn custom_coerce_unsize_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, substs: tcx.mk_substs_trait(source_ty, &[target_ty]) }); - match tcx.trans_fulfill_obligation( (ty::ParamEnv::empty(traits::Reveal::All), trait_ref)) { + match tcx.trans_fulfill_obligation( (ty::ParamEnv::reveal_all(), trait_ref)) { traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap() } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index a8a7831c823f8..ea0f1e93a4ac9 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -21,7 +21,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::middle::const_val::ConstVal; -use rustc::traits::{self, Reveal}; +use rustc::traits; use rustc::ty::{self, TyCtxt, Ty, TypeFoldable}; use rustc::ty::cast::CastTy; use rustc::ty::maps::Providers; @@ -1237,7 +1237,7 @@ impl MirPass for QualifyAndPromoteConstants { } let ty = mir.return_ty(); tcx.infer_ctxt().enter(|infcx| { - let param_env = ty::ParamEnv::empty(Reveal::UserFacing); + let param_env = ty::ParamEnv::empty(); let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic); let mut fulfillment_cx = traits::FulfillmentContext::new(); fulfillment_cx.register_bound(&infcx, diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 60637bb61823f..38df1580e037d 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -40,7 +40,6 @@ use rustc::middle::mem_categorization::Categorization; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::maps::{queries, Providers}; use rustc::ty::subst::Substs; -use rustc::traits::Reveal; use rustc::util::common::ErrorReported; use rustc::util::nodemap::{ItemLocalSet, NodeSet}; use rustc::lint::builtin::CONST_ERR; @@ -97,7 +96,7 @@ fn rvalue_promotable_map<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, in_static: false, promotable: false, mut_rvalue_borrows: NodeSet(), - param_env: ty::ParamEnv::empty(Reveal::UserFacing), + param_env: ty::ParamEnv::empty(), identity_substs: Substs::empty(), result: ItemLocalSet(), }; diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index c3d5e08c73e7e..ecf1b6591ecf0 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -25,7 +25,6 @@ use type_of::LayoutLlvmExt; use rustc::hir::def_id::DefId; use rustc::ty::{self, TypeFoldable}; use rustc::ty::layout::LayoutOf; -use rustc::traits; use rustc::ty::subst::Substs; use rustc_back::PanicStrategy; @@ -185,7 +184,7 @@ pub fn resolve_and_get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, cx, ty::Instance::resolve( cx.tcx, - ty::ParamEnv::empty(traits::Reveal::All), + ty::ParamEnv::reveal_all(), def_id, substs ).unwrap() diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 9e745c3a1f5dd..30b31c561b3a1 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -25,7 +25,6 @@ use declare; use type_::Type; use type_of::LayoutLlvmExt; use value::Value; -use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::layout::{HasDataLayout, LayoutOf}; use rustc::ty::subst::Kind; @@ -41,15 +40,15 @@ use syntax_pos::{Span, DUMMY_SP}; pub use context::CodegenCx; pub fn type_needs_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { - ty.needs_drop(tcx, ty::ParamEnv::empty(traits::Reveal::All)) + ty.needs_drop(tcx, ty::ParamEnv::reveal_all()) } pub fn type_is_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { - ty.is_sized(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) + ty.is_sized(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP) } pub fn type_is_freeze<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { - ty.is_freeze(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) + ty.is_freeze(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP) } /* diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index a285e5f263ab7..a6ac3a1337170 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -14,7 +14,6 @@ use llvm::{ContextRef, ModuleRef, ValueRef}; use rustc::dep_graph::DepGraphSafe; use rustc::hir; use rustc::hir::def_id::DefId; -use rustc::traits; use debuginfo; use callee; use base; @@ -435,7 +434,7 @@ impl<'b, 'tcx> CodegenCx<'b, 'tcx> { pub fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool { use syntax_pos::DUMMY_SP; - if ty.is_sized(self.tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) { + if ty.is_sized(self.tcx, ty::ParamEnv::reveal_all(), DUMMY_SP) { return false; } @@ -464,7 +463,7 @@ impl<'a, 'tcx> LayoutOf> for &'a CodegenCx<'a, 'tcx> { type TyLayout = TyLayout<'tcx>; fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { - self.tcx.layout_of(ty::ParamEnv::empty(traits::Reveal::All).and(ty)) + self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)) .unwrap_or_else(|e| match e { LayoutError::SizeOverflow(_) => self.sess().fatal(&e.to_string()), _ => bug!("failed to get layout for `{}`: {}", ty, e) diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index bb2a7840faee7..d741e5b486f8e 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -13,7 +13,6 @@ use rustc::middle::lang_items; use rustc::middle::const_val::{ConstEvalErr, ConstInt, ErrKind}; use rustc::ty::{self, TypeFoldable}; use rustc::ty::layout::{self, LayoutOf}; -use rustc::traits; use rustc::mir; use abi::{Abi, FnType, ArgType, PassMode}; use base; @@ -441,7 +440,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { let (instance, mut llfn) = match callee.layout.ty.sty { ty::TyFnDef(def_id, substs) => { (Some(ty::Instance::resolve(bx.cx.tcx, - ty::ParamEnv::empty(traits::Reveal::All), + ty::ParamEnv::reveal_all(), def_id, substs).unwrap()), None) diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index d470f92b75231..440899a06b739 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -14,7 +14,6 @@ use rustc_const_math::ConstInt::*; use rustc_const_math::{ConstInt, ConstMathErr, MAX_F32_PLUS_HALF_ULP}; use rustc::hir::def_id::DefId; use rustc::infer::TransNormalize; -use rustc::traits; use rustc::mir; use rustc::mir::tcx::PlaceTy; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; @@ -298,7 +297,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { args: IndexVec, ConstEvalErr<'tcx>>>) -> Result, ConstEvalErr<'tcx>> { let instance = ty::Instance::resolve(cx.tcx, - ty::ParamEnv::empty(traits::Reveal::All), + ty::ParamEnv::reveal_all(), def_id, substs).unwrap(); let mir = cx.tcx.instance_mir(instance.def); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 4c10f28eb8e5d..6e84223063633 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -500,7 +500,7 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TraitContainer(_) => tcx.mk_self_type() }; let self_arg_ty = *tcx.fn_sig(method.def_id).input(0).skip_binder(); - let param_env = ty::ParamEnv::empty(Reveal::All); + let param_env = ty::ParamEnv::reveal_all(); tcx.infer_ctxt().enter(|infcx| { let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty).is_ok(); @@ -754,7 +754,7 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref); tcx.infer_ctxt().enter(|infcx| { - let param_env = ty::ParamEnv::empty(Reveal::UserFacing); + let param_env = ty::ParamEnv::empty(); let inh = Inherited::new(infcx, impl_c.def_id); let infcx = &inh.infcx; diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 4aed688027f76..db5c37bb13ce9 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -16,7 +16,7 @@ use rustc::infer::outlives::env::OutlivesEnvironment; use rustc::middle::region; use rustc::ty::subst::{Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::traits::{self, Reveal, ObligationCause}; +use rustc::traits::{self, ObligationCause}; use util::common::ErrorReported; use util::nodemap::FxHashSet; @@ -126,7 +126,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( // it did the wrong thing, so I chose to preserve existing // behavior, since it ought to be simply more // conservative. -nmatsakis - let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty(Reveal::UserFacing)); + let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty()); infcx.resolve_regions_and_report_errors(drop_impl_did, ®ion_scope_tree, &outlives_env); Ok(()) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 91fa3c5da6991..ddd1526563a34 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3988,7 +3988,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } hir::ExprRepeat(ref element, count) => { let count_def_id = tcx.hir.body_owner_def_id(count); - let param_env = ty::ParamEnv::empty(traits::Reveal::UserFacing); + let param_env = ty::ParamEnv::empty(); let substs = Substs::identity_for_item(tcx.global_tcx(), count_def_id); let count = tcx.const_eval(param_env.and((count_def_id, substs))); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 1c8d22e4666a6..ef9847721177d 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -30,7 +30,6 @@ use constrained_type_params as ctp; use middle::lang_items::SizedTraitLangItem; use middle::const_val::ConstVal; use middle::resolve_lifetime as rl; -use rustc::traits::Reveal; use rustc::ty::subst::Substs; use rustc::ty::{ToPredicate, ReprOptions}; use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; @@ -507,7 +506,7 @@ fn convert_variant_ctor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, variants: &[hir::Variant]) { - let param_env = ty::ParamEnv::empty(Reveal::UserFacing); + let param_env = ty::ParamEnv::empty(); let def = tcx.adt_def(def_id); let repr_type = def.repr.discr_type(); let initial = repr_type.initial_discriminant(tcx); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index af32738d9d04b..d79f499c7d9fc 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -109,7 +109,7 @@ use rustc::infer::InferOk; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::maps::Providers; -use rustc::traits::{FulfillmentContext, ObligationCause, ObligationCauseCode, Reveal}; +use rustc::traits::{FulfillmentContext, ObligationCause, ObligationCauseCode}; use session::{CompileIncomplete, config}; use util::common::time; @@ -157,7 +157,7 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, actual: Ty<'tcx>) -> bool { tcx.infer_ctxt().enter(|ref infcx| { - let param_env = ty::ParamEnv::empty(Reveal::UserFacing); + let param_env = ty::ParamEnv::empty(); let mut fulfill_cx = FulfillmentContext::new(); match infcx.at(&cause, param_env).eq(expected, actual) { Ok(InferOk { obligations, .. }) => { From 359c39b56ca13becf616f20cd5308d04deb9e1c0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 14 Feb 2018 05:08:02 -0500 Subject: [PATCH 12/22] move ParamEnv methods from `ty/util` to `ty/mod` --- src/librustc/ty/mod.rs | 43 ++++++++++++++++++++++++++++++++++++++++- src/librustc/ty/util.rs | 43 +---------------------------------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 7a438ccadc4f9..61de44be2eac3 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -28,7 +28,7 @@ use middle::resolve_lifetime::ObjectLifetimeDefault; use mir::Mir; use mir::GeneratorLayout; use session::CrateDisambiguator; -use traits; +use traits::{self, Reveal}; use ty; use ty::subst::{Subst, Substs}; use ty::util::IntTypeExt; @@ -1351,6 +1351,47 @@ pub struct ParamEnv<'tcx> { } impl<'tcx> ParamEnv<'tcx> { + /// Construct a trait environment suitable for contexts where + /// there are no where clauses in scope. Hidden types (like `impl + /// Trait`) are left hidden, so this is suitable for ordinary + /// type-checking. + pub fn empty() -> Self { + Self::new(ty::Slice::empty(), Reveal::UserFacing) + } + + /// Construct a trait environment with no where clauses in scope + /// where the values of all `impl Trait` and other hidden types + /// are revealed. This is suitable for monomorphized, post-typeck + /// environments like trans or doing optimizations. + /// + /// NB. If you want to have predicates in scope, use `ParamEnv::new`, + /// or invoke `param_env.with_reveal_all()`. + pub fn reveal_all() -> Self { + Self::new(ty::Slice::empty(), Reveal::All) + } + + /// Construct a trait environment with the given set of predicates. + pub fn new(caller_bounds: &'tcx ty::Slice>, + reveal: Reveal) + -> Self { + ty::ParamEnv { caller_bounds, reveal } + } + + /// Returns a new parameter environment with the same clauses, but + /// which "reveals" the true results of projections in all cases + /// (even for associated types that are specializable). This is + /// the desired behavior during trans and certain other special + /// contexts; normally though we want to use `Reveal::UserFacing`, + /// which is the default. + pub fn with_reveal_all(self) -> Self { + ty::ParamEnv { reveal: Reveal::All, ..self } + } + + /// Returns this same environment but with no caller bounds. + pub fn without_caller_bounds(self) -> Self { + ty::ParamEnv { caller_bounds: ty::Slice::empty(), ..self } + } + /// Creates a suitable environment in which to perform trait /// queries on the given value. This will either be `self` *or* /// the empty environment, depending on whether `value` references diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 6e4ed6dbf0810..2c0ae4931bc08 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -16,7 +16,7 @@ use hir::map::{DefPathData, Node}; use hir; use ich::NodeIdHashingMode; use middle::const_val::ConstVal; -use traits::{self, Reveal}; +use traits; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::fold::TypeVisitor; use ty::subst::{Subst, Kind}; @@ -150,47 +150,6 @@ pub enum Representability { } impl<'tcx> ty::ParamEnv<'tcx> { - /// Construct a trait environment suitable for contexts where - /// there are no where clauses in scope. Hidden types (like `impl - /// Trait`) are left hidden, so this is suitable for ordinary - /// type-checking. - pub fn empty() -> Self { - Self::new(ty::Slice::empty(), Reveal::UserFacing) - } - - /// Construct a trait environment with no where clauses in scope - /// where the values of all `impl Trait` and other hidden types - /// are revealed. This is suitable for monomorphized, post-typeck - /// environments like trans or doing optimizations. - /// - /// NB. If you want to have predicates in scope, use `ParamEnv::new`, - /// or invoke `param_env.with_reveal_all()`. - pub fn reveal_all() -> Self { - Self::new(ty::Slice::empty(), Reveal::All) - } - - /// Construct a trait environment with the given set of predicates. - pub fn new(caller_bounds: &'tcx ty::Slice>, - reveal: Reveal) - -> Self { - ty::ParamEnv { caller_bounds, reveal } - } - - /// Returns a new parameter environment with the same clauses, but - /// which "reveals" the true results of projections in all cases - /// (even for associated types that are specializable). This is - /// the desired behavior during trans and certain other special - /// contexts; normally though we want to use `Reveal::UserFacing`, - /// which is the default. - pub fn with_reveal_all(self) -> Self { - ty::ParamEnv { reveal: Reveal::All, ..self } - } - - /// Returns this same environment but with no caller bounds. - pub fn without_caller_bounds(self) -> Self { - ty::ParamEnv { caller_bounds: ty::Slice::empty(), ..self } - } - pub fn can_type_implement_copy<'a>(self, tcx: TyCtxt<'a, 'tcx, 'tcx>, self_type: Ty<'tcx>, span: Span) From 08951d5971e74c0990b3e36c336e3f226939e228 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 20 Feb 2018 10:37:35 -0500 Subject: [PATCH 13/22] change `ParamEnv::and` to sometimes keep the environment [VIC] In general, we've been moving towards a semantics where you can have contradictory where-clauses, and we try to honor them. There are already existing run-pass tests where we take that philosophy as well (e.g., `compile-fail/issue-36839.rs`). The current behavior of `and`, where it strips the environment, breaks that code. --- src/librustc/ty/mod.rs | 49 ++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 61de44be2eac3..907cbfe0a8189 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1393,31 +1393,38 @@ impl<'tcx> ParamEnv<'tcx> { } /// Creates a suitable environment in which to perform trait - /// queries on the given value. This will either be `self` *or* - /// the empty environment, depending on whether `value` references - /// type parameters that are in scope. (If it doesn't, then any - /// judgements should be completely independent of the context, - /// and hence we can safely use the empty environment so as to - /// enable more sharing across functions.) + /// queries on the given value. When type-checking, this is simply + /// the pair of the environment plus value. But when reveal is set to + /// All, then if `value` does not reference any type parameters, we will + /// pair it with the empty environment. This improves caching and is generally + /// invisible. /// - /// NB: This is a mildly dubious thing to do, in that a function - /// (or other environment) might have wacky where-clauses like + /// NB: We preserve the environment when type-checking because it + /// is possible for the user to have wacky where-clauses like /// `where Box: Copy`, which are clearly never - /// satisfiable. The code will at present ignore these, - /// effectively, when type-checking the body of said - /// function. This preserves existing behavior in any - /// case. --nmatsakis + /// satisfiable. We generally want to behave as if they were true, + /// although the surrounding function is never reachable. pub fn and>(self, value: T) -> ParamEnvAnd<'tcx, T> { - assert!(!value.needs_infer()); - if value.has_param_types() || value.has_self_ty() { - ParamEnvAnd { - param_env: self, - value, + match self.reveal { + Reveal::UserFacing => { + ParamEnvAnd { + param_env: self, + value, + } } - } else { - ParamEnvAnd { - param_env: self.without_caller_bounds(), - value, + + Reveal::All => { + if value.needs_infer() || value.has_param_types() || value.has_self_ty() { + ParamEnvAnd { + param_env: self, + value, + } + } else { + ParamEnvAnd { + param_env: self.without_caller_bounds(), + value, + } + } } } } From 85d12f38aa7cfc0e749f6a1ff00859d93b4f3aa2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 9 Feb 2018 10:39:36 -0500 Subject: [PATCH 14/22] add `canonicalize` method to `InferCtxt` --- src/librustc/ich/impls_ty.rs | 69 ++ src/librustc/infer/canonical.rs | 885 ++++++++++++++++++ src/librustc/infer/combine.rs | 1 + src/librustc/infer/error_reporting/mod.rs | 1 + src/librustc/infer/freshen.rs | 6 +- .../infer/lexical_region_resolve/mod.rs | 2 + src/librustc/infer/mod.rs | 8 +- src/librustc/lib.rs | 3 +- src/librustc/macros.rs | 19 + src/librustc/session/mod.rs | 5 + src/librustc/traits/select.rs | 15 +- src/librustc/ty/error.rs | 1 + src/librustc/ty/flags.rs | 12 +- src/librustc/ty/mod.rs | 9 +- src/librustc/ty/sty.rs | 12 + src/librustc/ty/util.rs | 3 + src/librustc/util/ppaux.rs | 9 + src/librustc_borrowck/borrowck/check_loans.rs | 1 + .../borrowck/gather_loans/mod.rs | 1 + src/librustc_const_eval/lib.rs | 1 + src/librustc_data_structures/indexed_vec.rs | 2 +- src/librustc_metadata/lib.rs | 2 + .../borrow_check/error_reporting.rs | 1 + src/librustc_save_analysis/lib.rs | 1 + src/librustc_typeck/variance/constraints.rs | 1 + src/librustdoc/clean/mod.rs | 1 + 26 files changed, 1057 insertions(+), 14 deletions(-) create mode 100644 src/librustc/infer/canonical.rs diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index d1e431597e745..9ad7c54cad5e6 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -19,6 +19,7 @@ use std::cell::RefCell; use std::hash as std_hash; use std::mem; use middle::region; +use infer::{self, canonical}; use traits; use ty; @@ -73,6 +74,9 @@ for ty::RegionKind { ty::ReEmpty => { // No variant fields to hash for these ... } + ty::ReCanonical(c) => { + c.hash_stable(hcx, hasher); + } ty::ReLateBound(db, ty::BrAnon(i)) => { db.depth.hash_stable(hcx, hasher); i.hash_stable(hcx, hasher); @@ -118,6 +122,16 @@ impl<'gcx> HashStable> for ty::RegionVid { } } +impl<'gcx> HashStable> for ty::CanonicalVar { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + impl<'gcx> HashStable> for ty::adjustment::AutoBorrow<'gcx> { fn hash_stable(&self, @@ -1028,3 +1042,58 @@ for traits::VtableGeneratorData<'gcx, N> where N: HashStable HashStable> +for canonical::Canonical where V: HashStable> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + let canonical::Canonical { + variables, + value, + } = self; + variables.hash_stable(hcx, hasher); + value.hash_stable(hcx, hasher); + } +} + +impl<'gcx> HashStable> +for canonical::CanonicalVarValues<'gcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + let canonical::CanonicalVarValues { + var_values, + } = self; + var_values.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct infer::canonical::CanonicalVarInfo { + kind +}); + +impl_stable_hash_for!(enum infer::canonical::CanonicalVarKind { + Ty(k), + Region +}); + +impl_stable_hash_for!(enum infer::canonical::CanonicalTyVarKind { + General, + Int, + Float +}); + +impl_stable_hash_for!( + impl<'tcx, R> for struct infer::canonical::QueryResult<'tcx, R> { + var_values, region_constraints, certainty, value + } +); + +impl_stable_hash_for!(struct infer::canonical::QueryRegionConstraints<'tcx> { + region_outlives, ty_outlives +}); + +impl_stable_hash_for!(enum infer::canonical::Certainty { + Proven, Ambiguous +}); diff --git a/src/librustc/infer/canonical.rs b/src/librustc/infer/canonical.rs new file mode 100644 index 0000000000000..d0f0f4e6fbba7 --- /dev/null +++ b/src/librustc/infer/canonical.rs @@ -0,0 +1,885 @@ +// 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. + +//! **Canonicalization** is the key to constructing a query in the +//! middle of type inference. Ordinarily, it is not possible to store +//! types from type inference in query keys, because they contain +//! references to inference variables whose lifetimes are too short +//! and so forth. Canonicalizing a value T1 using `canonicalize_query` +//! produces two things: +//! +//! - a value T2 where each unbound inference variable has been +//! replaced with a **canonical variable**; +//! - a map M (of type `CanonicalVarValues`) from those canonical +//! variables back to the original. +//! +//! We can then do queries using T2. These will give back constriants +//! on the canonical variables which can be translated, using the map +//! M, into constraints in our source context. This process of +//! translating the results back is done by the +//! `instantiate_query_result` method. + +use infer::{InferCtxt, InferOk, InferResult, RegionVariableOrigin, TypeVariableOrigin}; +use std::fmt::Debug; +use syntax::codemap::Span; +use traits::{Obligation, ObligationCause, PredicateObligation}; +use ty::{self, CanonicalVar, Lift, Region, Ty, TyCtxt, TypeFlags}; +use ty::subst::Kind; +use ty::fold::{TypeFoldable, TypeFolder}; +use util::common::CellUsizeExt; + +use rustc_data_structures::indexed_vec::IndexVec; +use rustc_data_structures::fx::FxHashMap; + +/// A "canonicalized" type `V` is one where all free inference +/// variables have been rewriten to "canonical vars". These are +/// numbered starting from 0 in order of first appearance. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct Canonical { + pub variables: IndexVec, + pub value: V, +} + +/// A set of values corresponding to the canonical variables from some +/// `Canonical`. You can give these values to +/// `canonical_value.substitute` to substitute them into the canonical +/// value at the right places. +/// +/// When you canonicalize a value `V`, you get back one of these +/// vectors with the original values that were replaced by canonical +/// variables. +/// +/// You can also use `infcx.fresh_inference_vars_for_canonical_vars` +/// to get back a `CanonicalVarValues` containing fresh inference +/// variables. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct CanonicalVarValues<'tcx> { + pub var_values: IndexVec>, +} + +/// Information about a canonical variable that is included with the +/// canonical value. This is sufficient information for code to create +/// a copy of the canonical value in some other inference context, +/// with fresh inference variables replacing the canonical values. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct CanonicalVarInfo { + pub kind: CanonicalVarKind, +} + +/// Describes the "kind" of the canonical variable. This is a "kind" +/// in the type-theory sense of the term -- i.e., a "meta" type system +/// that analyzes type-like values. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum CanonicalVarKind { + /// Some kind of type inference variable. + Ty(CanonicalTyVarKind), + + /// Region variable `'?R`. + Region, +} + +/// Rust actually has more than one category of type variables; +/// notably, the type variables we create for literals (e.g., 22 or +/// 22.) can only be instantiated with integral/float types (e.g., +/// usize or f32). In order to faithfully reproduce a type, we need to +/// know what set of types a given type variable can be unified with. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum CanonicalTyVarKind { + /// General type variable `?T` that can be unified with arbitrary types. + General, + + /// Integral type variable `?I` (that can only be unified with integral types). + Int, + + /// Floating-point type variable `?F` (that can only be unified with float types). + Float, +} + +/// After we execute a query with a canonicalized key, we get back a +/// `Canonical>`. You can use +/// `instantiate_query_result` to access the data in this result. +#[derive(Clone, Debug)] +pub struct QueryResult<'tcx, R> { + pub var_values: CanonicalVarValues<'tcx>, + pub region_constraints: QueryRegionConstraints<'tcx>, + pub certainty: Certainty, + pub value: R, +} + +/// Indicates whether or not we were able to prove the query to be +/// true. +#[derive(Copy, Clone, Debug)] +pub enum Certainty { + /// The query is known to be true, presuming that you apply the + /// given `var_values` and the region-constraints are satisfied. + Proven, + + /// The query is not known to be true, but also not known to be + /// false. The `var_values` represent *either* values that must + /// hold in order for the query to be true, or helpful tips that + /// *might* make it true. Currently rustc's trait solver cannot + /// distinguish the two (e.g., due to our preference for where + /// clauses over impls). + /// + /// After some unifiations and things have been done, it makes + /// sense to try and prove again -- of course, at that point, the + /// canonical form will be different, making this a distinct + /// query. + Ambiguous, +} + +impl Certainty { + pub fn is_proven(&self) -> bool { + match self { + Certainty::Proven => true, + Certainty::Ambiguous => false, + } + } + + pub fn is_ambiguous(&self) -> bool { + !self.is_proven() + } +} + +impl<'tcx, R> QueryResult<'tcx, R> { + pub fn is_proven(&self) -> bool { + self.certainty.is_proven() + } + + pub fn is_ambiguous(&self) -> bool { + !self.is_proven() + } +} + +impl<'tcx, R> Canonical> { + pub fn is_proven(&self) -> bool { + self.value.is_proven() + } + + pub fn is_ambiguous(&self) -> bool { + !self.is_proven() + } +} + +/// Subset of `RegionConstraintData` produced by trait query. +#[derive(Clone, Debug, Default)] +pub struct QueryRegionConstraints<'tcx> { + pub region_outlives: Vec<(Region<'tcx>, Region<'tcx>)>, + pub ty_outlives: Vec<(Ty<'tcx>, Region<'tcx>)>, +} + +/// Trait implemented by values that can be canonicalized. It mainly +/// serves to identify the interning table we will use. +pub trait Canonicalize<'gcx: 'tcx, 'tcx>: TypeFoldable<'tcx> + Lift<'gcx> { + type Canonicalized: 'gcx + Debug; + + /// After a value has been fully canonicalized and lifted, this + /// method will allocate it in a global arena. + fn intern(gcx: TyCtxt<'_, 'gcx, 'gcx>, value: Canonical) -> Self::Canonicalized; +} + +impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { + /// Creates a substitution S for the canonical value with fresh + /// inference variables and applies it to the canonical value. + /// Returns both the instantiated result *and* the substitution S. + /// + /// This is useful at the start of a query: it basically brings + /// the canonical value "into scope" within your new infcx. At the + /// end of processing, the substitution S (once canonicalized) + /// then represents the values that you computed for each of the + /// canonical inputs to your query. + pub fn instantiate_canonical_with_fresh_inference_vars( + &self, + span: Span, + canonical: &Canonical, + ) -> (T, CanonicalVarValues<'tcx>) + where + T: TypeFoldable<'tcx>, + { + let canonical_inference_vars = + self.fresh_inference_vars_for_canonical_vars(span, &canonical.variables); + let result = canonical.substitute(self.tcx, &canonical_inference_vars); + (result, canonical_inference_vars) + } + + /// Given the "infos" about the canonical variables from some + /// canonical, creates fresh inference variables with the same + /// characteristics. You can then use `substitute` to instantiate + /// the canonical variable with these inference variables. + pub fn fresh_inference_vars_for_canonical_vars( + &self, + span: Span, + variables: &IndexVec, + ) -> CanonicalVarValues<'tcx> { + let var_values: IndexVec> = variables + .iter() + .map(|info| self.fresh_inference_var_for_canonical_var(span, *info)) + .collect(); + + CanonicalVarValues { var_values } + } + + /// Given the "info" about a canonical variable, creates a fresh + /// inference variable with the same characteristics. + pub fn fresh_inference_var_for_canonical_var( + &self, + span: Span, + cv_info: CanonicalVarInfo, + ) -> Kind<'tcx> { + match cv_info.kind { + CanonicalVarKind::Ty(ty_kind) => { + let ty = match ty_kind { + CanonicalTyVarKind::General => { + self.next_ty_var(TypeVariableOrigin::MiscVariable(span)) + } + + CanonicalTyVarKind::Int => self.tcx.mk_int_var(self.next_int_var_id()), + + CanonicalTyVarKind::Float => self.tcx.mk_float_var(self.next_float_var_id()), + }; + Kind::from(ty) + } + + CanonicalVarKind::Region => { + Kind::from(self.next_region_var(RegionVariableOrigin::MiscVariable(span))) + } + } + } + + /// 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 + /// have been ambiguous; you should check the certainty level of + /// the query before applying this function.) + /// + /// It's easiest to explain what is happening here by + /// example. Imagine we start out with the query `?A: Foo<'static, + /// ?B>`. We would canonicalize that by introducing two variables: + /// + /// ?0: Foo<'?1, ?2> + /// + /// (Note that all regions get replaced with variables always, + /// even "known" regions like `'static`.) After canonicalization, + /// we also get back an array with the "original values" for each + /// canonicalized variable: + /// + /// [?A, 'static, ?B] + /// + /// Now we do the query and get back some result R. As part of that + /// result, we'll have an array of values for the canonical inputs. + /// For example, the canonical result might be: + /// + /// ``` + /// for<2> { + /// values = [ Vec, '1, ?0 ] + /// ^^ ^^ ^^ these are variables in the result! + /// ... + /// } + /// ``` + /// + /// Note that this result is itself canonical and may include some + /// variables (in this case, `?0`). + /// + /// What we want to do conceptually is to (a) instantiate each of the + /// canonical variables in the result with a fresh inference variable + /// and then (b) unify the values in the result with the original values. + /// Doing step (a) would yield a result of + /// + /// ``` + /// { + /// values = [ Vec, '?X, ?C ] + /// ^^ ^^^ fresh inference variables in `self` + /// .. + /// } + /// ``` + /// + /// Step (b) would then unify: + /// + /// ``` + /// ?A with Vec + /// 'static with '?X + /// ?B with ?C + /// ``` + /// + /// But what we actually do is a mildly optimized variant of + /// that. Rather than eagerly instantiating all of the canonical + /// values in the result with variables, we instead walk the + /// vector of values, looking for cases where the value is just a + /// canonical variable. In our example, `values[2]` is `?C`, so + /// that we means we can deduce that `?C := ?B and `'?X := + /// 'static`. This gives us a partial set of values. Anything for + /// which we do not find a value, we create an inference variable + /// for. **Then** we unify. + pub fn instantiate_query_result( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + original_values: &CanonicalVarValues<'tcx>, + query_result: &Canonical>, + ) -> InferResult<'tcx, R> + where + R: Debug + TypeFoldable<'tcx>, + { + debug!( + "instantiate_query_result(original_values={:#?}, query_result={:#?})", + original_values, query_result, + ); + + // Every canonical query result includes values for each of + // the inputs to the query. Therefore, we begin by unifying + // these values with the original inputs that were + // canonicalized. + let result_values = &query_result.value.var_values; + assert_eq!(original_values.len(), result_values.len()); + + // Quickly try to find initial values for the canonical + // variables in the result in terms of the query. We do this + // by iterating down the values that the query gave to each of + // the canonical inputs. If we find that one of those values + // is directly equal to one of the canonical variables in the + // result, then we can type the corresponding value from the + // input. See the example above. + let mut opt_values: IndexVec>> = + IndexVec::from_elem(None, &query_result.variables); + + // In terms of our example above, we are iterating over pairs like: + // [(?A, Vec), ('static, '?1), (?B, ?0)] + for (original_value, result_value) in original_values.iter().zip(result_values) { + if let Some(result_value) = result_value.as_type() { + // e.g., here `result_value` might be `?0` in the example above... + if let ty::TyInfer(ty::InferTy::CanonicalTy(index)) = result_value.sty { + // in which case we would set `canonical_vars[0]` to `Some(?U)`. + opt_values[index] = Some(original_value); + } + } else if let Some(result_value) = result_value.as_region() { + // e.g., here `result_value` might be `'?1` in the example above... + if let &ty::RegionKind::ReCanonical(index) = result_value { + // in which case we would set `canonical_vars[0]` to `Some('static)`. + opt_values[index] = Some(original_value); + } + } else { + bug!() + } + } + + // Create a result substitution: if we found a value for a + // given variable in the loop above, use that. Otherwise, use + // a fresh inference variable. + let result_subst = &CanonicalVarValues { + var_values: query_result + .variables + .iter_enumerated() + .map(|(index, info)| match opt_values[index] { + Some(k) => k, + None => self.fresh_inference_var_for_canonical_var(cause.span, *info), + }) + .collect(), + }; + + // Apply the result substitution to the query. + let QueryResult { + var_values: query_values, + region_constraints: query_region_constraints, + certainty: _, + value: user_result, + } = query_result.substitute(self.tcx, result_subst); + + // Unify the original values for the canonical variables in + // the input with the value found in the query + // post-substitution. Often, but not always, this is a no-op, + // because we already found the mapping in the first step. + let mut obligations = + self.unify_canonical_vars(cause, param_env, original_values, &query_values)? + .into_obligations(); + + obligations.extend(self.query_region_constraints_into_obligations( + cause, + param_env, + query_region_constraints, + )); + + Ok(InferOk { + value: user_result, + obligations, + }) + } + + /// Converts the region constraints resulting from a query into an + /// iterator of obligations. + fn query_region_constraints_into_obligations<'a>( + &self, + cause: &'a ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + query_region_constraints: QueryRegionConstraints<'tcx>, + ) -> impl Iterator> + 'a { + let QueryRegionConstraints { + region_outlives, + ty_outlives, + } = query_region_constraints; + + let region_obligations = region_outlives.into_iter().map(move |(r1, r2)| { + Obligation::new( + cause.clone(), + param_env, + ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r1, r2))), + ) + }); + + let ty_obligations = ty_outlives.into_iter().map(move |(t1, r2)| { + Obligation::new( + cause.clone(), + param_env, + ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t1, r2))), + ) + }); + + region_obligations.chain(ty_obligations) + } + + /// Given two sets of values for the same set of canonical variables, unify them. + pub fn unify_canonical_vars( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + variables1: &CanonicalVarValues<'tcx>, + variables2: &CanonicalVarValues<'tcx>, + ) -> InferResult<'tcx, ()> { + assert_eq!(variables1.var_values.len(), variables2.var_values.len()); + self.commit_if_ok(|_| { + let mut obligations = vec![]; + for (value1, value2) in variables1.var_values.iter().zip(&variables2.var_values) { + if let (Some(v1), Some(v2)) = (value1.as_type(), value2.as_type()) { + obligations.extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations()); + } else if let (Some(v1), Some(v2)) = (value1.as_region(), value2.as_region()) { + if let (ty::ReErased, ty::ReErased) = (v1, v2) { + // no action needed + } else { + obligations + .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations()); + } + } else { + bug!("kind mismatch, cannot unify {:?} and {:?}", value1, value2,); + } + } + Ok(InferOk { + value: (), + obligations, + }) + }) + } + + /// Canonicalizes a query value `V`. When we canonicalize a query, + /// we not only canonicalize unbound inference variables, but we + /// *also* replace all free regions whatsoever. So for example a + /// query like `T: Trait<'static>` would be canonicalized to + /// + /// T: Trait<'?0> + /// + /// with a mapping M that maps `'?0` to `'static`. + pub fn canonicalize_query(&self, value: &V) -> (V::Canonicalized, CanonicalVarValues<'tcx>) + where + V: Canonicalize<'gcx, 'tcx>, + { + self.tcx.sess.perf_stats.queries_canonicalized.increment(); + + Canonicalizer::canonicalize( + value, + Some(self), + self.tcx, + CanonicalizeAllFreeRegions(true), + ) + } + + /// Canonicalizes a query *response* `V`. When we canonicalize a + /// query response, we only canonicalize unbound inference + /// variables, and we leave other free regions alone. So, + /// continuing with the example from `canonicalize_query`, if + /// there was an input query `T: Trait<'static>`, it would have + /// been canonicalized to + /// + /// T: Trait<'?0> + /// + /// with a mapping M that maps `'?0` to `'static`. But if we found that there + /// exists only one possible impl of `Trait`, and it looks like + /// + /// impl Trait<'static> for T { .. } + /// + /// then we would prepare a query result R that (among other + /// things) includes a mapping to `'?0 := 'static`. When + /// canonicalizing this query result R, we would leave this + /// reference to `'static` alone. + pub fn canonicalize_response( + &self, + value: &V, + ) -> (V::Canonicalized, CanonicalVarValues<'tcx>) + where + V: Canonicalize<'gcx, 'tcx>, + { + Canonicalizer::canonicalize( + value, + Some(self), + self.tcx, + CanonicalizeAllFreeRegions(false), + ) + } +} + +impl<'cx, 'gcx> TyCtxt<'cx, 'gcx, 'gcx> { + /// Canonicalize a value that doesn't have any inference variables + /// or other things (and we know it). + pub fn canonicalize_global(self, value: &V) -> (V::Canonicalized, CanonicalVarValues<'gcx>) + where + V: Canonicalize<'gcx, 'gcx>, + { + Canonicalizer::canonicalize(value, None, self, CanonicalizeAllFreeRegions(false)) + } +} + +/// If this flag is true, then all free regions will be replaced with +/// a canonical var. This is used to make queries as generic as +/// possible. For example, the query `F: Foo<'static>` would be +/// canonicalized to `F: Foo<'0>`. +struct CanonicalizeAllFreeRegions(bool); + +struct Canonicalizer<'cx, 'gcx: 'tcx, 'tcx: 'cx> { + infcx: Option<&'cx InferCtxt<'cx, 'gcx, 'tcx>>, + tcx: TyCtxt<'cx, 'gcx, 'tcx>, + variables: IndexVec, + indices: FxHashMap, CanonicalVar>, + var_values: IndexVec>, + canonicalize_all_free_regions: CanonicalizeAllFreeRegions, +} + +impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { + self.tcx + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + match *r { + ty::ReLateBound(..) => { + // leave bound regions alone + r + } + + ty::ReVar(vid) => { + let r = self.infcx + .unwrap() + .borrow_region_constraints() + .opportunistic_resolve_var(self.tcx, vid); + let info = CanonicalVarInfo { + kind: CanonicalVarKind::Region, + }; + debug!("canonical: region var found with vid {:?}, \ + opportunistically resolved to {:?}", + vid, r); + let cvar = self.canonical_var(info, Kind::from(r)); + self.tcx().mk_region(ty::ReCanonical(cvar)) + } + + ty::ReStatic + | ty::ReEarlyBound(..) + | ty::ReFree(_) + | ty::ReScope(_) + | ty::ReSkolemized(..) + | ty::ReEmpty + | ty::ReErased => { + if self.canonicalize_all_free_regions.0 { + let info = CanonicalVarInfo { + kind: CanonicalVarKind::Region, + }; + let cvar = self.canonical_var(info, Kind::from(r)); + self.tcx().mk_region(ty::ReCanonical(cvar)) + } else { + r + } + } + + ty::ReClosureBound(..) | ty::ReCanonical(_) => { + bug!("canonical region encountered during canonicalization") + } + } + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + match t.sty { + ty::TyInfer(ty::TyVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::General, t), + + ty::TyInfer(ty::IntVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::Int, t), + + ty::TyInfer(ty::FloatVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::Float, t), + + ty::TyInfer(ty::FreshTy(_)) + | ty::TyInfer(ty::FreshIntTy(_)) + | ty::TyInfer(ty::FreshFloatTy(_)) => { + bug!("encountered a fresh type during canonicalization") + } + + ty::TyInfer(ty::CanonicalTy(_)) => { + bug!("encountered a canonical type during canonicalization") + } + + // Replace a `()` that "would've fallen back" to `!` with just `()`. + ty::TyTuple(ref tys, true) => { + assert!(tys.is_empty()); + self.tcx().mk_nil() + } + + ty::TyClosure(..) + | ty::TyGenerator(..) + | ty::TyGeneratorWitness(..) + | ty::TyBool + | ty::TyChar + | ty::TyInt(..) + | ty::TyUint(..) + | ty::TyFloat(..) + | ty::TyAdt(..) + | ty::TyStr + | ty::TyError + | ty::TyArray(..) + | ty::TySlice(..) + | ty::TyRawPtr(..) + | ty::TyRef(..) + | ty::TyFnDef(..) + | ty::TyFnPtr(_) + | ty::TyDynamic(..) + | ty::TyNever + | ty::TyTuple(_, false) + | ty::TyProjection(..) + | ty::TyForeign(..) + | ty::TyParam(..) + | ty::TyAnon(..) => t.super_fold_with(self), + } + } +} + +impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { + /// The main `canonicalize` method, shared impl of + /// `canonicalize_query` and `canonicalize_response`. + fn canonicalize( + value: &V, + infcx: Option<&'cx InferCtxt<'cx, 'gcx, 'tcx>>, + tcx: TyCtxt<'cx, 'gcx, 'tcx>, + canonicalize_all_free_regions: CanonicalizeAllFreeRegions, + ) -> (V::Canonicalized, CanonicalVarValues<'tcx>) + where + V: Canonicalize<'gcx, 'tcx>, + { + debug_assert!( + !value.has_type_flags(TypeFlags::HAS_CANONICAL_VARS), + "canonicalizing a canonical value: {:?}", + value, + ); + + let mut canonicalizer = Canonicalizer { + infcx, + tcx, + canonicalize_all_free_regions, + variables: IndexVec::default(), + indices: FxHashMap::default(), + var_values: IndexVec::default(), + }; + let out_value = value.fold_with(&mut canonicalizer); + + // Once we have canonicalized `out_value`, it should not + // contain anything that ties it to this inference context + // anymore, so it should live in the global arena. + let gcx = tcx.global_tcx(); + let out_value = gcx.lift(&out_value).unwrap_or_else(|| { + bug!( + "failed to lift `{:?}`, canonicalized from `{:?}`", + out_value, + value + ) + }); + + let canonical_value = V::intern( + tcx.global_tcx(), + Canonical { + variables: canonicalizer.variables, + value: out_value, + }, + ); + let canonical_var_values = CanonicalVarValues { + var_values: canonicalizer.var_values, + }; + (canonical_value, canonical_var_values) + } + + /// Creates a canonical variable replacing `kind` from the input, + /// or returns an existing variable if `kind` has already been + /// seen. `kind` is expected to be an unbound variable (or + /// potentially a free region). + fn canonical_var(&mut self, info: CanonicalVarInfo, kind: Kind<'tcx>) -> CanonicalVar { + let Canonicalizer { + indices, + variables, + var_values, + .. + } = self; + + indices + .entry(kind) + .or_insert_with(|| { + let cvar1 = variables.push(info); + let cvar2 = var_values.push(kind); + assert_eq!(cvar1, cvar2); + cvar1 + }) + .clone() + } + + /// Given a type variable `ty_var` of the given kind, first check + /// if `ty_var` is bound to anything; if so, canonicalize + /// *that*. Otherwise, create a new canonical variable for + /// `ty_var`. + fn canonicalize_ty_var(&mut self, ty_kind: CanonicalTyVarKind, ty_var: Ty<'tcx>) -> Ty<'tcx> { + let infcx = self.infcx.expect("encountered ty-var without infcx"); + let bound_to = infcx.shallow_resolve(ty_var); + if bound_to != ty_var { + self.fold_ty(bound_to) + } else { + let info = CanonicalVarInfo { + kind: CanonicalVarKind::Ty(ty_kind), + }; + let cvar = self.canonical_var(info, Kind::from(ty_var)); + self.tcx().mk_infer(ty::InferTy::CanonicalTy(cvar)) + } + } +} + +impl Canonical { + /// Instantiate the wrapped value, replacing each canonical value + /// with the value given in `var_values`. + pub fn substitute<'tcx>( + &self, + tcx: TyCtxt<'_, '_, 'tcx>, + var_values: &CanonicalVarValues<'tcx>, + ) -> V + where + V: TypeFoldable<'tcx>, + { + assert_eq!(self.variables.len(), var_values.var_values.len()); + self.value + .fold_with(&mut CanonicalVarValuesSubst { tcx, var_values }) + } +} + +struct CanonicalVarValuesSubst<'cx, 'gcx: 'tcx, 'tcx: 'cx> { + tcx: TyCtxt<'cx, 'gcx, 'tcx>, + var_values: &'cx CanonicalVarValues<'tcx>, +} + +impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for CanonicalVarValuesSubst<'cx, 'gcx, 'tcx> { + fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> { + self.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + match t.sty { + ty::TyInfer(ty::InferTy::CanonicalTy(c)) => { + self.var_values.var_values[c].as_type().unwrap_or_else(|| { + bug!( + "{:?} is a type but value is {:?}", + c, + self.var_values.var_values[c] + ) + }) + } + _ => t.super_fold_with(self), + } + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + match r { + ty::RegionKind::ReCanonical(c) => self.var_values.var_values[*c] + .as_region() + .unwrap_or_else(|| { + bug!( + "{:?} is a region but value is {:?}", + c, + self.var_values.var_values[*c] + ) + }), + _ => r.super_fold_with(self), + } + } +} + +CloneTypeFoldableImpls! { + ::infer::canonical::Certainty, + ::infer::canonical::CanonicalVarInfo, + ::infer::canonical::CanonicalVarKind, +} + +BraceStructTypeFoldableImpl! { + impl<'tcx, C> TypeFoldable<'tcx> for Canonical { + variables, + value, + } where C: TypeFoldable<'tcx> +} + +impl<'tcx> CanonicalVarValues<'tcx> { + fn iter<'a>(&'a self) -> impl Iterator> + 'a { + self.var_values.iter().cloned() + } + + fn len(&self) -> usize { + self.var_values.len() + } +} + +impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> { + type Item = Kind<'tcx>; + type IntoIter = ::std::iter::Cloned<::std::slice::Iter<'a, Kind<'tcx>>>; + + fn into_iter(self) -> Self::IntoIter { + self.var_values.iter().cloned() + } +} + +BraceStructLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for CanonicalVarValues<'a> { + type Lifted = CanonicalVarValues<'tcx>; + var_values, + } +} + +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for CanonicalVarValues<'tcx> { + var_values, + } +} + +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for QueryRegionConstraints<'tcx> { + region_outlives, ty_outlives + } +} + +BraceStructLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for QueryRegionConstraints<'a> { + type Lifted = QueryRegionConstraints<'tcx>; + region_outlives, ty_outlives + } +} + +BraceStructTypeFoldableImpl! { + impl<'tcx, R> TypeFoldable<'tcx> for QueryResult<'tcx, R> { + var_values, region_constraints, certainty, value + } where R: TypeFoldable<'tcx>, +} + +BraceStructLiftImpl! { + impl<'a, 'tcx, R> Lift<'tcx> for QueryResult<'a, R> { + type Lifted = QueryResult<'tcx, R::Lifted>; + var_values, region_constraints, certainty, value + } where R: Lift<'tcx> +} diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index f7bc092a3d7ae..13a19432384c7 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -476,6 +476,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, ' } } + ty::ReCanonical(..) | ty::ReClosureBound(..) => { span_bug!( self.span, diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 7c7da47c7a8a7..a56eded33fb67 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -239,6 +239,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } // We shouldn't encounter an error message with ReClosureBound. + ty::ReCanonical(..) | ty::ReClosureBound(..) => { bug!( "encountered unexpected ReClosureBound: {:?}", diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 8b61fcff2335e..ffbfd9c21bf8d 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -114,9 +114,10 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { self.tcx().types.re_erased } + ty::ReCanonical(..) | ty::ReClosureBound(..) => { bug!( - "encountered unexpected ReClosureBound: {:?}", + "encountered unexpected region: {:?}", r, ); } @@ -170,6 +171,9 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { t } + ty::TyInfer(ty::CanonicalTy(..)) => + bug!("encountered canonical ty during freshening"), + ty::TyGenerator(..) | ty::TyBool | ty::TyChar | diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs index 3ac4ec5bee416..00b2ac7449f7e 100644 --- a/src/librustc/infer/lexical_region_resolve/mod.rs +++ b/src/librustc/infer/lexical_region_resolve/mod.rs @@ -258,6 +258,8 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> { let tcx = self.region_rels.tcx; match (a, b) { + (&ty::ReCanonical(..), _) | + (_, &ty::ReCanonical(..)) | (&ty::ReClosureBound(..), _) | (_, &ty::ReClosureBound(..)) | (&ReLateBound(..), _) | diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 400ca03f4caed..111e1b774d869 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -50,6 +50,7 @@ use self::unify_key::ToType; pub mod anon_types; pub mod at; +pub mod canonical; mod combine; mod equate; pub mod error_reporting; @@ -473,6 +474,12 @@ impl<'tcx, T> InferOk<'tcx, T> { } } +impl<'tcx> InferOk<'tcx, ()> { + pub fn into_obligations(self) -> PredicateObligations<'tcx> { + self.obligations + } +} + #[must_use = "once you start a snapshot, you should always consume it"] pub struct CombinedSnapshot<'a, 'tcx:'a> { projection_cache_snapshot: traits::ProjectionCacheSnapshot, @@ -1703,4 +1710,3 @@ impl<'tcx> fmt::Debug for RegionObligation<'tcx> { self.sup_type) } } - diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 8c76e0182dfbd..8d074a5b83d92 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -55,8 +55,9 @@ #![feature(inclusive_range)] #![feature(inclusive_range_syntax)] #![cfg_attr(windows, feature(libc))] -#![feature(macro_vis_matcher)] #![feature(match_default_bindings)] +#![feature(macro_lifetime_matcher)] +#![feature(macro_vis_matcher)] #![feature(never_type)] #![feature(non_exhaustive)] #![feature(nonzero)] diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index ef4ead8773142..1cfa823a43c28 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -119,6 +119,25 @@ macro_rules! impl_stable_hash_for { } } }; + + (impl<$tcx:lifetime $(, $T:ident)*> for struct $struct_name:path { + $($field:ident),* $(,)* + }) => { + impl<$tcx, $($T,)*> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<$tcx>> for $struct_name + where $($T: ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<$tcx>>),* + { + #[inline] + fn hash_stable(&self, + __ctx: &mut $crate::ich::StableHashingContext<$tcx>, + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { + let $struct_name { + $(ref $field),* + } = *self; + + $( $field.hash_stable(__ctx, __hasher));* + } + } + }; } #[macro_export] diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 9d7a9acc3d533..0b5c83ba902ab 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -160,6 +160,8 @@ pub struct PerfStats { pub symbol_hash_time: Cell, /// The accumulated time spent decoding def path tables from metadata pub decode_def_path_tables_time: Cell, + /// Total number of values canonicalized queries constructed. + pub queries_canonicalized: Cell, } /// Enum to support dispatch of one-time diagnostics (in Session.diag_once) @@ -764,6 +766,8 @@ impl Session { duration_to_secs_str(self.perf_stats.symbol_hash_time.get())); println!("Total time spent decoding DefPath tables: {}", duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get())); + println!("Total queries canonicalized: {}", + self.perf_stats.queries_canonicalized.get()); } /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n. @@ -1026,6 +1030,7 @@ pub fn build_session_(sopts: config::Options, incr_comp_bytes_hashed: Cell::new(0), 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), }, code_stats: RefCell::new(CodeStats::new()), optimization_fuel_crate, diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 4ac027c6fde8f..21f7c7eb2ccf1 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2112,9 +2112,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyProjection(_) | ty::TyParam(_) | ty::TyAnon(..) => None, ty::TyInfer(ty::TyVar(_)) => Ambiguous, - ty::TyInfer(ty::FreshTy(_)) - | ty::TyInfer(ty::FreshIntTy(_)) - | ty::TyInfer(ty::FreshFloatTy(_)) => { + ty::TyInfer(ty::CanonicalTy(_)) | + ty::TyInfer(ty::FreshTy(_)) | + ty::TyInfer(ty::FreshIntTy(_)) | + ty::TyInfer(ty::FreshFloatTy(_)) => { bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); } @@ -2183,9 +2184,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Ambiguous } - ty::TyInfer(ty::FreshTy(_)) - | ty::TyInfer(ty::FreshIntTy(_)) - | ty::TyInfer(ty::FreshFloatTy(_)) => { + ty::TyInfer(ty::CanonicalTy(_)) | + ty::TyInfer(ty::FreshTy(_)) | + ty::TyInfer(ty::FreshIntTy(_)) | + ty::TyInfer(ty::FreshFloatTy(_)) => { bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); } @@ -2224,6 +2226,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyParam(..) | ty::TyForeign(..) | ty::TyProjection(..) | + ty::TyInfer(ty::CanonicalTy(_)) | ty::TyInfer(ty::TyVar(_)) | ty::TyInfer(ty::FreshTy(_)) | ty::TyInfer(ty::FreshIntTy(_)) | diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 583612f9590f1..1dc73e29e53ac 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -232,6 +232,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyInfer(ty::TyVar(_)) => "inferred type".to_string(), ty::TyInfer(ty::IntVar(_)) => "integral variable".to_string(), ty::TyInfer(ty::FloatVar(_)) => "floating-point variable".to_string(), + ty::TyInfer(ty::CanonicalTy(_)) | ty::TyInfer(ty::FreshTy(_)) => "skolemized type".to_string(), ty::TyInfer(ty::FreshIntTy(_)) => "skolemized integral type".to_string(), ty::TyInfer(ty::FreshFloatTy(_)) => "skolemized floating-point type".to_string(), diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 2889322a1ce77..4f9b89270dcce 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -112,8 +112,16 @@ impl FlagComputation { match infer { ty::FreshTy(_) | ty::FreshIntTy(_) | - ty::FreshFloatTy(_) => {} - _ => self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX) + ty::FreshFloatTy(_) | + ty::CanonicalTy(_) => { + self.add_flags(TypeFlags::HAS_CANONICAL_VARS); + } + + ty::TyVar(_) | + ty::IntVar(_) | + ty::FloatVar(_) => { + self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX) + } } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 907cbfe0a8189..2c6b37d1557d9 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -61,7 +61,7 @@ use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, use hir; -pub use self::sty::{Binder, DebruijnIndex}; +pub use self::sty::{Binder, CanonicalVar, DebruijnIndex}; pub use self::sty::{FnSig, GenSig, PolyFnSig, PolyGenSig}; pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate}; pub use self::sty::{ClosureSubsts, GeneratorInterior, TypeAndMut}; @@ -453,6 +453,10 @@ bitflags! { // Currently we can't normalize projections w/ bound regions. const HAS_NORMALIZABLE_PROJECTION = 1 << 12; + // Set if this includes a "canonical" type or region var -- + // ought to be true only for the results of canonicalization. + const HAS_CANONICAL_VARS = 1 << 13; + const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits | TypeFlags::HAS_SELF.bits | TypeFlags::HAS_RE_EARLY_BOUND.bits; @@ -471,7 +475,8 @@ bitflags! { TypeFlags::HAS_PROJECTION.bits | TypeFlags::HAS_TY_CLOSURE.bits | TypeFlags::HAS_LOCAL_NAMES.bits | - TypeFlags::KEEP_IN_LOCAL_TCX.bits; + TypeFlags::KEEP_IN_LOCAL_TCX.bits | + TypeFlags::HAS_CANONICAL_VARS.bits; } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 961c2650afdef..be7ebb776cc5d 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1042,6 +1042,9 @@ pub enum RegionKind { /// `ClosureRegionRequirements` that are produced by MIR borrowck. /// See `ClosureRegionRequirements` for more details. ReClosureBound(RegionVid), + + /// Canonicalized region, used only when preparing a trait query. + ReCanonical(CanonicalVar), } impl<'tcx> serialize::UseSpecializedDecodable for Region<'tcx> {} @@ -1091,8 +1094,13 @@ pub enum InferTy { FreshTy(u32), FreshIntTy(u32), FreshFloatTy(u32), + + /// Canonicalized type variable, used only when preparing a trait query. + CanonicalTy(CanonicalVar), } +newtype_index!(CanonicalVar); + /// A `ProjectionPredicate` for an `ExistentialTraitRef`. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct ExistentialProjection<'tcx> { @@ -1213,6 +1221,10 @@ impl RegionKind { } ty::ReErased => { } + ty::ReCanonical(..) => { + flags = flags | TypeFlags::HAS_FREE_REGIONS; + flags = flags | TypeFlags::HAS_CANONICAL_VARS; + } ty::ReClosureBound(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 2c0ae4931bc08..778bd59ee9adf 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -798,6 +798,9 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> ty::ReEmpty => { // No variant fields to hash for these ... } + ty::ReCanonical(c) => { + self.hash(c); + } ty::ReLateBound(db, ty::BrAnon(i)) => { self.hash(db.depth); self.hash(i); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 37d1c568515b5..0c15a02bd9be2 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -721,6 +721,9 @@ define_print! { ty::ReEarlyBound(ref data) => { write!(f, "{}", data.name) } + ty::ReCanonical(_) => { + write!(f, "'_") + } ty::ReLateBound(_, br) | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | ty::ReSkolemized(_, br) => { @@ -785,6 +788,10 @@ define_print! { write!(f, "{:?}", vid) } + ty::ReCanonical(c) => { + write!(f, "'?{}", c.index()) + } + ty::ReSkolemized(id, ref bound_region) => { write!(f, "ReSkolemized({}, {:?})", id.index, bound_region) } @@ -888,6 +895,7 @@ define_print! { ty::TyVar(_) => write!(f, "_"), ty::IntVar(_) => write!(f, "{}", "{integer}"), ty::FloatVar(_) => write!(f, "{}", "{float}"), + ty::CanonicalTy(_) => write!(f, "_"), ty::FreshTy(v) => write!(f, "FreshTy({})", v), ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v), ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v) @@ -899,6 +907,7 @@ define_print! { ty::TyVar(ref v) => write!(f, "{:?}", v), ty::IntVar(ref v) => write!(f, "{:?}", v), ty::FloatVar(ref v) => write!(f, "{:?}", v), + ty::CanonicalTy(v) => write!(f, "?{:?}", v.index()), ty::FreshTy(v) => write!(f, "FreshTy({:?})", v), ty::FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v), ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v) diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 9888b2fffc779..a01b3cbf47bee 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -427,6 +427,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { // These cannot exist in borrowck RegionKind::ReVar(..) | + RegionKind::ReCanonical(..) | RegionKind::ReSkolemized(..) | RegionKind::ReClosureBound(..) | RegionKind::ReErased => span_bug!(borrow_span, diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 5cbe2822e5c03..49234f4ed7fde 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -366,6 +366,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { ty::ReStatic => self.item_ub, + ty::ReCanonical(_) | ty::ReEmpty | ty::ReClosureBound(..) | ty::ReLateBound(..) | diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 9d636b48bd0c5..459aa9ea488fd 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -23,6 +23,7 @@ #![feature(slice_patterns)] #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(macro_lifetime_matcher)] #![feature(i128_type)] #![feature(from_ref)] diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index b11ca107af7dd..66154e08a7bc4 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -324,7 +324,7 @@ macro_rules! newtype_index { ); } -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq, Hash)] pub struct IndexVec { pub raw: Vec, _marker: PhantomData diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 2d015fa81f925..dfbb047327420 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -18,7 +18,9 @@ #![feature(fs_read_write)] #![feature(i128_type)] #![feature(libc)] +#![feature(macro_lifetime_matcher)] #![feature(proc_macro_internals)] +#![feature(macro_lifetime_matcher)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(specialization)] diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 34551e8e76f59..c23bab236b3fd 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -434,6 +434,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { (RegionKind::ReLateBound(_, _), _) | (RegionKind::ReSkolemized(_, _), _) | (RegionKind::ReClosureBound(_), _) | + (RegionKind::ReCanonical(_), _) | (RegionKind::ReErased, _) => { span_bug!(drop_span, "region does not make sense in this context"); }, diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 490dc4e5ac4a9..953747756517d 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -13,6 +13,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] #![feature(custom_attribute)] +#![feature(macro_lifetime_matcher)] #![allow(unused_attributes)] #[macro_use] diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index f7e10a4a47d37..d418d495b4ebc 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -422,6 +422,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // way early-bound regions do, so we skip them here. } + ty::ReCanonical(_) | ty::ReFree(..) | ty::ReClosureBound(..) | ty::ReScope(..) | diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4543b246b83ad..3097cec90b62a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1489,6 +1489,7 @@ impl Clean> for ty::RegionKind { ty::ReSkolemized(..) | ty::ReEmpty | ty::ReClosureBound(_) | + ty::ReCanonical(_) | ty::ReErased => None } } From 7f495d970eae30d782f1df8a005a2a9d2a652a1b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 23 Feb 2018 15:30:27 -0500 Subject: [PATCH 15/22] in `Foo(X)` dep-nodes, allow X to be a `ty` not a `tt` Before, the identifier `X` was also used when generating a pattern to match against the dep-node. So `Foo(DefId)` would generate a match pattern like: match foo { Foo(DefId) => ... } This does not scale to more general types like `&'tcx Ty<'tcx>`. Therefore, we now require *exactly one* argument (the macro was internally tupling anyway, and no actual nodes use more than one argument), and then we can generate a fixed pattern like: match foo { Foo(arg) => ... } Huzzah. (Also, hygiene is nice.) --- src/librustc/dep_graph/dep_node.rs | 45 ++++++++++++++++-------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 4034055d04155..f4c5fd7ca6369 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -80,6 +80,10 @@ macro_rules! erase { ($x:tt) => ({}) } +macro_rules! replace { + ($x:tt with $($y:tt)*) => ($($y)*) +} + macro_rules! is_anon_attr { (anon) => (true); ($attr:ident) => (false); @@ -111,7 +115,7 @@ macro_rules! define_dep_nodes { (<$tcx:tt> $( [$($attr:ident),* ] - $variant:ident $(( $($tuple_arg:tt),* ))* + $variant:ident $(( $tuple_arg_ty:ty $(,)* ))* $({ $($struct_arg_name:ident : $struct_arg_ty:ty),* })* ,)* ) => ( @@ -134,7 +138,7 @@ macro_rules! define_dep_nodes { // tuple args $({ - return <( $($tuple_arg,)* ) as DepNodeParams> + return <$tuple_arg_ty as DepNodeParams> ::CAN_RECONSTRUCT_QUERY_KEY; })* @@ -186,7 +190,7 @@ macro_rules! define_dep_nodes { DepKind :: $variant => { // tuple args $({ - $(erase!($tuple_arg);)* + erase!($tuple_arg_ty); return true; })* @@ -205,7 +209,7 @@ macro_rules! define_dep_nodes { pub enum DepConstructor<$tcx> { $( - $variant $(( $($tuple_arg),* ))* + $variant $(( $tuple_arg_ty ))* $({ $($struct_arg_name : $struct_arg_ty),* })* ),* } @@ -227,15 +231,14 @@ macro_rules! define_dep_nodes { { match dep { $( - DepConstructor :: $variant $(( $($tuple_arg),* ))* + DepConstructor :: $variant $(( replace!(($tuple_arg_ty) with arg) ))* $({ $($struct_arg_name),* })* => { // tuple args $({ - let tupled_args = ( $($tuple_arg,)* ); - let hash = DepNodeParams::to_fingerprint(&tupled_args, - tcx); + erase!($tuple_arg_ty); + let hash = DepNodeParams::to_fingerprint(&arg, tcx); let dep_node = DepNode { kind: DepKind::$variant, hash @@ -247,7 +250,7 @@ macro_rules! define_dep_nodes { tcx.sess.opts.debugging_opts.query_dep_graph) { tcx.dep_graph.register_dep_node_debug_str(dep_node, || { - tupled_args.to_debug_str(tcx) + arg.to_debug_str(tcx) }); } @@ -679,43 +682,43 @@ impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a, T> DepNodeParams<'a, 'gcx, 'tcx> for T } } -impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for (DefId,) { +impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for DefId { const CAN_RECONSTRUCT_QUERY_KEY: bool = true; fn to_fingerprint(&self, tcx: TyCtxt) -> Fingerprint { - tcx.def_path_hash(self.0).0 + tcx.def_path_hash(*self).0 } fn to_debug_str(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> String { - tcx.item_path_str(self.0) + tcx.item_path_str(*self) } } -impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for (DefIndex,) { +impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for DefIndex { const CAN_RECONSTRUCT_QUERY_KEY: bool = true; fn to_fingerprint(&self, tcx: TyCtxt) -> Fingerprint { - tcx.hir.definitions().def_path_hash(self.0).0 + tcx.hir.definitions().def_path_hash(*self).0 } fn to_debug_str(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> String { - tcx.item_path_str(DefId::local(self.0)) + tcx.item_path_str(DefId::local(*self)) } } -impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for (CrateNum,) { +impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for CrateNum { const CAN_RECONSTRUCT_QUERY_KEY: bool = true; fn to_fingerprint(&self, tcx: TyCtxt) -> Fingerprint { let def_id = DefId { - krate: self.0, + krate: *self, index: CRATE_DEF_INDEX, }; tcx.def_path_hash(def_id).0 } fn to_debug_str(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> String { - tcx.crate_name(self.0).as_str().to_string() + tcx.crate_name(*self).as_str().to_string() } } @@ -743,17 +746,17 @@ impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for (DefId, De } } -impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for (HirId,) { +impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for HirId { const CAN_RECONSTRUCT_QUERY_KEY: bool = false; // We actually would not need to specialize the implementation of this // method but it's faster to combine the hashes than to instantiate a full // hashing context and stable-hashing state. fn to_fingerprint(&self, tcx: TyCtxt) -> Fingerprint { - let (HirId { + let HirId { owner, local_id: ItemLocalId(local_id), - },) = *self; + } = *self; let def_path_hash = tcx.def_path_hash(DefId::local(owner)); let local_id = Fingerprint::from_smaller_hash(local_id as u64); From 01d0dc825f5bcd1eda508060507eb59d34a557c0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 21 Feb 2018 14:50:27 -0500 Subject: [PATCH 16/22] introduce `infcx.at(..).normalize(..)` operation [VIC] It is backed by the new `normalize_projection_ty` query, which uses canonicalization. --- src/Cargo.lock | 18 ++ src/librustc/dep_graph/dep_node.rs | 11 +- src/librustc/infer/at.rs | 6 +- src/librustc/infer/mod.rs | 11 + src/librustc/infer/outlives/obligations.rs | 10 + src/librustc/infer/region_constraints/mod.rs | 4 + src/librustc/session/mod.rs | 11 + src/librustc/traits/mod.rs | 2 + src/librustc/traits/query/mod.rs | 25 ++ src/librustc/traits/query/normalize.rs | 251 ++++++++++++++++++ src/librustc/ty/context.rs | 88 +++++- src/librustc/ty/maps/config.rs | 12 +- src/librustc/ty/maps/keys.rs | 13 +- src/librustc/ty/maps/mod.rs | 16 +- src/librustc/ty/maps/plumbing.rs | 1 + src/librustc/ty/mod.rs | 2 +- src/librustc_driver/Cargo.toml | 1 + src/librustc_driver/driver.rs | 2 + src/librustc_driver/lib.rs | 1 + .../borrow_check/nll/type_check/mod.rs | 18 +- src/librustc_traits/Cargo.toml | 22 ++ src/librustc_traits/lib.rs | 37 +++ .../normalize_projection_ty.rs | 55 ++++ src/librustc_traits/util.rs | 117 ++++++++ 24 files changed, 716 insertions(+), 18 deletions(-) create mode 100644 src/librustc/traits/query/mod.rs create mode 100644 src/librustc/traits/query/normalize.rs create mode 100644 src/librustc_traits/Cargo.toml create mode 100644 src/librustc_traits/lib.rs create mode 100644 src/librustc_traits/normalize_projection_ty.rs create mode 100644 src/librustc_traits/util.rs diff --git a/src/Cargo.lock b/src/Cargo.lock index 7dc8374e3e8fd..86d1f71d2c050 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1846,6 +1846,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", @@ -2026,6 +2027,23 @@ 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.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc 0.0.0", + "rustc_const_eval 0.0.0", + "rustc_const_math 0.0.0", + "rustc_data_structures 0.0.0", + "rustc_errors 0.0.0", + "serialize 0.0.0", + "syntax 0.0.0", + "syntax_pos 0.0.0", +] + [[package]] name = "rustc_trans" version = "0.0.0" diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index f4c5fd7ca6369..8f45e76f4ad62 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -60,18 +60,17 @@ //! user of the `DepNode` API of having to know how to compute the expected //! fingerprint for a given set of node parameters. +use ich::{Fingerprint, StableHashingContext}; +use infer::canonical::Canonical; use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; use hir::map::DefPathHash; use hir::{HirId, ItemLocalId}; - -use ich::Fingerprint; -use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty}; -use ty::subst::Substs; use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; -use ich::StableHashingContext; use std::fmt; use std::hash::Hash; use syntax_pos::symbol::InternedString; +use ty::{self, 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 @@ -633,6 +632,8 @@ define_dep_nodes!( <'tcx> [] CompileCodegenUnit(InternedString), [input] OutputFilenames, [anon] NormalizeTy, + [] NormalizeProjectionTy { ty: &'tcx Canonical>> }, + // We use this for most things when incr. comp. is turned off. [] Null, diff --git a/src/librustc/infer/at.rs b/src/librustc/infer/at.rs index d9fbf4aa51482..89dbc76c8a65c 100644 --- a/src/librustc/infer/at.rs +++ b/src/librustc/infer/at.rs @@ -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> { diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 111e1b774d869..d94e25c5326eb 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -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>, @@ -1256,6 +1257,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( + &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 diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc/infer/outlives/obligations.rs index 36e657f78b4b2..e5461685bd470 100644 --- a/src/librustc/infer/outlives/obligations.rs +++ b/src/librustc/infer/outlives/obligations.rs @@ -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 diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs index be196192371fd..8f3b1bea8d8e3 100644 --- a/src/librustc/infer/region_constraints/mod.rs +++ b/src/librustc/infer/region_constraints/mod.rs @@ -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() } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 0b5c83ba902ab..401f66c9cfbc3 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -162,6 +162,11 @@ pub struct PerfStats { pub decode_def_path_tables_time: Cell, /// Total number of values canonicalized queries constructed. pub queries_canonicalized: Cell, + /// Number of times we canonicalized a value and found that the + /// result had already been canonicalized. + pub canonicalized_values_allocated: Cell, + /// Number of times this query is invoked. + pub normalize_projection_ty: Cell, } /// Enum to support dispatch of one-time diagnostics (in Session.diag_once) @@ -768,6 +773,10 @@ impl Session { duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get())); 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. @@ -1031,6 +1040,8 @@ pub fn build_session_(sopts: config::Options, 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, diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index e716216f4f5b7..9f86c8ebc2341 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -60,6 +60,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 { diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs new file mode 100644 index 0000000000000..75667ec8ec9a7 --- /dev/null +++ b/src/librustc/traits/query/mod.rs @@ -0,0 +1,25 @@ +// 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. + +//! 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`. + +pub mod normalize; + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct NoSolution; + +pub type Fallible = Result; + +impl_stable_hash_for!(struct NoSolution { }); diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs new file mode 100644 index 0000000000000..044528f3a8eb9 --- /dev/null +++ b/src/librustc/traits/query/normalize.rs @@ -0,0 +1,251 @@ +// 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. + +//! 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 std::rc::Rc; +use traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; +use traits::project::Normalized; +use ty::{self, CanonicalIntern, 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(&self, value: &T) -> Result, 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, + }) + } + } +} + +pub type CanonicalProjectionGoal<'tcx> = Canonical>>; + +/// 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>, + 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 { + if substs.needs_infer() { + let identity_substs = Substs::identity_for_item(self.tcx(), def_id); + let data = self.param_env.and((def_id, identity_substs)); + match self.tcx().lift_to_global(&data) { + Some(data) => match self.tcx().const_eval(data) { + Ok(evaluated) => { + let evaluated = evaluated.subst(self.tcx(), substs); + return self.fold_const(evaluated); + } + Err(_) => {} + }, + None => {} + } + } else { + let data = self.param_env.and((def_id, substs)); + match self.tcx().lift_to_global(&data) { + Some(data) => match self.tcx().const_eval(data) { + Ok(evaluated) => return self.fold_const(evaluated), + Err(_) => {} + }, + None => {} + } + } + } + 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 = &'gcx CanonicalProjectionGoal<'gcx>; + + fn intern(gcx: TyCtxt<'_, 'gcx, 'gcx>, value: Canonical) -> Self::Canonicalized { + value.intern_into(gcx) + } +} + +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>>>; + + fn intern(_gcx: TyCtxt<'_, 'gcx, 'gcx>, value: Canonical) -> Self::Canonicalized { + Rc::new(value) + } +} + +impl_stable_hash_for!(struct NormalizationResult<'tcx> { + normalized_ty +}); diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 4715fb0197ec0..1f6cc08bd7fde 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -35,6 +35,7 @@ use ty::subst::{Kind, Substs}; use ty::ReprOptions; use ty::Instance; use traits; +use traits::query::normalize::CanonicalProjectionGoal; use ty::{self, Ty, TypeAndMut}; use ty::{TyS, TypeVariants, Slice}; use ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorInterior, Region, Const}; @@ -46,6 +47,7 @@ use ty::layout::{LayoutDetails, TargetDataLayout}; use ty::maps; use ty::steal::Steal; use ty::BindingMode; +use util::common::CellUsizeExt; use util::nodemap::{NodeMap, NodeSet, DefIdSet, ItemLocalMap}; use util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::accumulate_vec::AccumulateVec; @@ -104,6 +106,8 @@ pub struct GlobalArenas<'tcx> { tables: TypedArena>, /// miri allocations const_allocs: TypedArena, + + canonical_projection_goal_arena: TypedArena>, } impl<'tcx> GlobalArenas<'tcx> { @@ -117,6 +121,7 @@ impl<'tcx> GlobalArenas<'tcx> { mir: TypedArena::new(), tables: TypedArena::new(), const_allocs: TypedArena::new(), + canonical_projection_goal_arena: TypedArena::new(), } } } @@ -886,8 +891,15 @@ pub struct GlobalCtxt<'tcx> { pub tx_to_llvm_workers: mpsc::Sender>, output_filenames: Arc, + + /// HashSet used to canonicalize interned canonical projection + /// goals. Each new unique instance is allocated in an arena for + /// use as a query key. + canonical_projection_goal_set: RefCell>>, } +type InternedCanonicalProjectionGoal<'tcx> = Interned<'tcx, CanonicalProjectionGoal<'tcx>>; + /// Everything needed to efficiently work with interned allocations #[derive(Debug, Default)] pub struct InterpretInterner<'tcx> { @@ -1202,6 +1214,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { dep_graph: dep_graph.clone(), on_disk_query_result_cache, types: common_types, + canonical_projection_goal_set: RefCell::new(FxHashSet()), trait_map, export_map: resolutions.export_map.into_iter().map(|(k, v)| { (k, Rc::new(v)) @@ -1686,7 +1699,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { /// An entry in an interner. -struct Interned<'tcx, T: 'tcx+?Sized>(&'tcx T); +pub struct Interned<'tcx, T: 'tcx+?Sized>(&'tcx T); // FIXME pub is just for annoying privacy rules // NB: An Interned compares and hashes as a sty. impl<'tcx> PartialEq for Interned<'tcx, TyS<'tcx>> { @@ -1742,6 +1755,26 @@ impl<'tcx> Borrow for Interned<'tcx, RegionKind> { } } +impl<'tcx> Borrow> for Interned<'tcx, CanonicalProjectionGoal<'tcx>> { + fn borrow<'a>(&'a self) -> &'a CanonicalProjectionGoal<'tcx> { + &self.0 + } +} + +impl<'tcx> PartialEq for Interned<'tcx, CanonicalProjectionGoal<'tcx>> { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl<'tcx> Eq for Interned<'tcx, CanonicalProjectionGoal<'tcx>> { } + +impl<'tcx> Hash for Interned<'tcx, CanonicalProjectionGoal<'tcx>> { + fn hash(&self, s: &mut H) { + self.0.hash(s) + } +} + impl<'tcx: 'lcx, 'lcx> Borrow<[ExistentialPredicate<'lcx>]> for Interned<'tcx, Slice>> { fn borrow<'a>(&'a self) -> &'a [ExistentialPredicate<'lcx>] { @@ -2405,3 +2438,56 @@ pub fn provide(providers: &mut ty::maps::Providers) { tcx.fully_normalize_associated_types_in(&ty) }; } + +/// A trait implemented by types that can be canonicalized. +pub trait CanonicalIntern<'gcx> +where + Self: Sized + Hash + Eq, + Self: 'gcx, +{ + /// The arena in which new instances of this type should be mapped. + fn arena(gcx: TyCtxt<'_, 'gcx, '_>) -> &'gcx TypedArena; + + /// The set which we will use to detect duplicates. + fn set<'cx>(gcx: TyCtxt<'cx, 'gcx, '_>) -> &'cx RefCell>>; + + /// If `self` has already been interned, return that value. + /// Otherwise, move into the global arena and return resulting + /// reference. + fn intern_into(self, gcx: TyCtxt<'_, 'gcx, '_>) -> &'gcx Self; +} + +impl<'gcx> CanonicalIntern<'gcx> for CanonicalProjectionGoal<'gcx> { + fn arena(gcx: TyCtxt<'_, 'gcx, '_>) -> &'gcx TypedArena { + &gcx.global_arenas.canonical_projection_goal_arena + } + + fn set<'cx>(gcx: TyCtxt<'cx, 'gcx, '_>) -> &'cx RefCell>> { + &gcx.canonical_projection_goal_set + } + + fn intern_into(self, gcx: TyCtxt<'_, 'gcx, '_>) -> &'gcx Self { + intern_into_impl(self, gcx) + } +} + +/// Annoyingly, we can't put this in the trait definition because of +/// the dependencies on the private `Interned` type. This situation +/// should only be temporary. +fn intern_into_impl<'gcx, T>(value: T, gcx: TyCtxt<'_, 'gcx, '_>) -> &'gcx T +where T: CanonicalIntern<'gcx>, + Interned<'gcx, T>: Eq, + Interned<'gcx, T>: Hash, + Interned<'gcx, T>: Borrow, +{ + let set = T::set(gcx); + if let Some(i) = set.borrow().get(&value) { + return i.0; + } + + gcx.sess.perf_stats.canonicalized_values_allocated.increment(); + + let p = T::arena(gcx).alloc(value); + set.borrow_mut().insert(Interned(p)); + p +} diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index eb07876b05f26..93f9ceb02a21c 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -10,7 +10,8 @@ use dep_graph::SerializedDepNodeIndex; use hir::def_id::{CrateNum, DefId, DefIndex}; -use ty::{self, Ty, TyCtxt}; +use infer::canonical::Canonical; +use ty::{self, ParamEnvAnd, Ty, TyCtxt}; use ty::maps::queries; use ty::subst::Substs; @@ -50,6 +51,15 @@ impl<'tcx, M: QueryConfig> QueryDescription<'tcx> for M { } } +impl<'tcx> QueryDescription<'tcx> for queries::normalize_projection_ty<'tcx> { + fn describe( + _tcx: TyCtxt, + goal: &'tcx Canonical>>, + ) -> 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/maps/keys.rs b/src/librustc/ty/maps/keys.rs index b7b64c9761a8e..d60a6b5ab3820 100644 --- a/src/librustc/ty/maps/keys.rs +++ b/src/librustc/ty/maps/keys.rs @@ -11,7 +11,8 @@ //! Defines the set of legal keys that can be used in queries. use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex}; -use ty::{self, Ty, TyCtxt}; +use infer::canonical::Canonical; +use ty::{self, ParamEnvAnd, Ty, TyCtxt}; use ty::subst::Substs; use ty::fast_reject::SimplifiedType; @@ -159,3 +160,13 @@ impl Key for InternedString { DUMMY_SP } } + +impl<'tcx> Key for &'tcx Canonical>> { + fn map_crate(&self) -> CrateNum { + LOCAL_CRATE + } + + fn default_span(&self, _tcx: TyCtxt) -> Span { + DUMMY_SP + } +} diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 21ffe6b895e72..ca8e62c79148d 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -14,6 +14,7 @@ use hir::def_id::{CrateNum, DefId, DefIndex}; use hir::def::{Def, Export}; use hir::{self, TraitCandidate, ItemLocalId}; use hir::svh::Svh; +use infer::canonical::{Canonical, QueryResult}; use lint; use middle::borrowck::BorrowCheckResult; use middle::const_val; @@ -32,8 +33,10 @@ use mir; use session::{CompileResult, CrateDisambiguator}; use session::config::OutputFilenames; use traits::Vtable; +use traits::query::NoSolution; +use traits::query::normalize::NormalizationResult; use traits::specialization_graph; -use ty::{self, CrateInherentImpls, Ty, TyCtxt}; +use ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; use ty::steal::Steal; use ty::subst::Substs; use util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet}; @@ -364,6 +367,11 @@ 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: normalize_projection_ty_node( + &'tcx Canonical>> + ) -> Result>>>, NoSolution>, + [] fn substitute_normalize_and_test_predicates: substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool, @@ -515,6 +523,12 @@ fn normalize_ty_node<'tcx>(_: Ty<'tcx>) -> DepConstructor<'tcx> { DepConstructor::NormalizeTy } +fn normalize_projection_ty_node<'tcx>( + ty: &'tcx Canonical>> +) -> DepConstructor<'tcx> { + DepConstructor::NormalizeProjectionTy { ty } +} + fn substitute_normalize_and_test_predicates_node<'tcx>(key: (DefId, &'tcx Substs<'tcx>)) -> DepConstructor<'tcx> { DepConstructor::SubstituteNormalizeAndTestPredicates { key } diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index f02c7cbd0ea3e..3e46c314df497 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -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 | diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 2c6b37d1557d9..9cf705a696484 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -79,7 +79,7 @@ pub use self::sty::TypeVariants::*; pub use self::binding::BindingMode; pub use self::binding::BindingMode::*; -pub use self::context::{TyCtxt, GlobalArenas, AllArenas, tls, keep_local}; +pub use self::context::{TyCtxt, GlobalArenas, CanonicalIntern, AllArenas, tls, keep_local}; pub use self::context::{Lift, TypeckTables}; pub use self::instance::{Instance, InstanceDef}; diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index 18493b8bb3940..bab59d1ff6873 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -29,6 +29,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" } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index b8a1fe9910540..40e3f903c3460 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -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; @@ -940,6 +941,7 @@ pub fn default_provide(providers: &mut ty::maps::Providers) { reachable::provide(providers); rustc_const_eval::provide(providers); rustc_passes::provide(providers); + rustc_traits::provide(providers); middle::region::provide(providers); cstore::provide(providers); lint::provide(providers); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index f872fd475461e..c5e96b7f87085 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -47,6 +47,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; 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 6cba617d19cd1..266fb72ac9507 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -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}; @@ -1571,10 +1572,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() } diff --git a/src/librustc_traits/Cargo.toml b/src/librustc_traits/Cargo.toml new file mode 100644 index 0000000000000..fe83344e69952 --- /dev/null +++ b/src/librustc_traits/Cargo.toml @@ -0,0 +1,22 @@ +[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 = "0.3" +rustc = { path = "../librustc" } +rustc_const_eval = { path = "../librustc_const_eval" } +rustc_const_math = { path = "../librustc_const_math" } +rustc_data_structures = { path = "../librustc_data_structures" } +rustc_errors = { path = "../librustc_errors" } +serialize = { path = "../libserialize" } +syntax = { path = "../libsyntax" } +syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs new file mode 100644 index 0000000000000..0d92404d24b08 --- /dev/null +++ b/src/librustc_traits/lib.rs @@ -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 or the MIT license +// , 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 + }; +} diff --git a/src/librustc_traits/normalize_projection_ty.rs b/src/librustc_traits/normalize_projection_ty.rs new file mode 100644 index 0000000000000..0c43f02aaa063 --- /dev/null +++ b/src/librustc_traits/normalize_projection_ty.rs @@ -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 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::traits::{self, FulfillmentContext, Normalized, ObligationCause, + SelectionContext}; +use rustc::traits::query::{NoSolution, normalize::NormalizationResult}; +use rustc::ty::{self, 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: &'tcx Canonical>>, +) -> Result>>>, 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, + ) + }) +} diff --git a/src/librustc_traits/util.rs b/src/librustc_traits/util.rs new file mode 100644 index 0000000000000..976eb442a0d13 --- /dev/null +++ b/src/librustc_traits/util.rs @@ -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 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, 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> = + 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_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) +} From 3ee7e2b4b3ea4c362c880d09b6475119f40dec20 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 21 Feb 2018 10:55:16 -0500 Subject: [PATCH 17/22] introduce `infcx.at(..).dropck_outlives(..)` operaton [VIC] Backed by a canonicalized query. This computes all the types/regions that need to be live when the destructor runs (i.e., that the dtor may access). --- src/librustc/ich/impls_ty.rs | 6 - src/librustc/traits/query/dropck_outlives.rs | 183 +++++++++++ src/librustc/traits/query/mod.rs | 1 + src/librustc/ty/context.rs | 43 +++ src/librustc/ty/maps/config.rs | 6 + src/librustc/ty/maps/keys.rs | 10 + src/librustc/ty/maps/mod.rs | 12 +- src/librustc/ty/maps/values.rs | 6 - src/librustc/ty/mod.rs | 80 +---- src/librustc/ty/util.rs | 94 ------ .../borrow_check/nll/type_check/liveness.rs | 91 ++---- src/librustc_traits/dropck_outlives.rs | 285 ++++++++++++++++++ src/librustc_traits/lib.rs | 3 + src/librustc_typeck/check/dropck.rs | 54 +--- src/librustc_typeck/check/regionck.rs | 6 +- 15 files changed, 583 insertions(+), 297 deletions(-) create mode 100644 src/librustc/traits/query/dropck_outlives.rs create mode 100644 src/librustc_traits/dropck_outlives.rs diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 9ad7c54cad5e6..7d8d167d471e6 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -818,12 +818,6 @@ impl_stable_hash_for!(struct ty::Destructor { did }); -impl_stable_hash_for!(struct ty::DtorckConstraint<'tcx> { - outlives, - dtorck_types -}); - - impl<'gcx> HashStable> for ty::CrateVariancesMap { fn hash_stable(&self, hcx: &mut StableHashingContext<'gcx>, diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs new file mode 100644 index 0000000000000..9a48331aeaf65 --- /dev/null +++ b/src/librustc/traits/query/dropck_outlives.rs @@ -0,0 +1,183 @@ +// 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 infer::at::At; +use infer::canonical::{Canonical, Canonicalize, QueryResult}; +use infer::InferOk; +use std::iter::FromIterator; +use ty::{self, CanonicalIntern, Ty, TyCtxt}; +use ty::subst::Kind; +use std::rc::Rc; + +pub type CanonicalTyGoal<'tcx> = Canonical>>; + +impl<'cx, 'gcx, 'tcx> At<'cx, 'gcx, 'tcx> { + /// Given a type `ty` of some value being dropped, computes a set + /// of "kinds" (types, regions) that must be outlive the execution + /// of the destructor. These basically correspond to data that the + /// destructor might access. This is used during regionck to + /// impose "outlives" constraints on any lifetimes referenced + /// within. + /// + /// The rules here are given by the "dropck" RFCs, notably [#1238] + /// and [#1327]. This is a fixed-point computation, where we + /// explore all the data that will be dropped (transitively) when + /// a value of type `ty` is dropped. For each type T that will be + /// dropped and which has a destructor, we must assume that all + /// the types/regions of T are live during the destructor, unless + /// they are marked with a special attribute (`#[may_dangle]`). + /// + /// [#1238]: https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md + /// [#1327]: https://github.com/rust-lang/rfcs/blob/master/text/1327-dropck-param-eyepatch.md + pub fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec>> { + let tcx = self.infcx.tcx; + let gcx = tcx.global_tcx(); + let (c_ty, orig_values) = self.infcx.canonicalize_query(&self.param_env.and(ty)); + let span = self.cause.span; + match &gcx.dropck_outlives(c_ty) { + Ok(result) if result.is_proven() => { + match self.infcx.instantiate_query_result( + self.cause, + self.param_env, + &orig_values, + result, + ) { + Ok(InferOk { + value: DropckOutlivesResult { kinds, overflows }, + obligations, + }) => { + for overflow_ty in overflows.into_iter().take(1) { + let mut err = struct_span_err!( + tcx.sess, + span, + E0320, + "overflow while adding drop-check rules for {}", + self.infcx.resolve_type_vars_if_possible(&ty), + ); + err.note(&format!("overflowed on {}", overflow_ty)); + err.emit(); + } + + return InferOk { + value: kinds, + obligations, + }; + } + + Err(_) => { /* fallthrough to error-handling code below */ } + } + } + + _ => { /* fallthrough to error-handling code below */ } + } + + // Errors and ambiuity in dropck occur in two cases: + // - unresolved inference variables at the end of typeck + // - non well-formed types where projections cannot be resolved + // Either of these should hvae created an error before. + tcx.sess + .delay_span_bug(span, "dtorck encountered internal error"); + return InferOk { + value: vec![], + obligations: vec![], + }; + } +} + +#[derive(Clone, Debug)] +pub struct DropckOutlivesResult<'tcx> { + pub kinds: Vec>, + pub overflows: Vec>, +} + +/// A set of constraints that need to be satisfied in order for +/// a type to be valid for destruction. +#[derive(Clone, Debug)] +pub struct DtorckConstraint<'tcx> { + /// Types that are required to be alive in order for this + /// type to be valid for destruction. + pub outlives: Vec>, + + /// Types that could not be resolved: projections and params. + pub dtorck_types: Vec>, + + /// If, during the computation of the dtorck constraint, we + /// overflow, that gets recorded here. The caller is expected to + /// report an error. + pub overflows: Vec>, +} + +impl<'tcx> DtorckConstraint<'tcx> { + pub fn empty() -> DtorckConstraint<'tcx> { + DtorckConstraint { + outlives: vec![], + dtorck_types: vec![], + overflows: vec![], + } + } +} + +impl<'tcx> FromIterator> for DtorckConstraint<'tcx> { + fn from_iter>>(iter: I) -> Self { + let mut result = Self::empty(); + + for DtorckConstraint { + outlives, + dtorck_types, + overflows, + } in iter + { + result.outlives.extend(outlives); + result.dtorck_types.extend(dtorck_types); + result.overflows.extend(overflows); + } + + result + } +} +impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for ty::ParamEnvAnd<'tcx, Ty<'tcx>> { + type Canonicalized = &'gcx CanonicalTyGoal<'gcx>; + + fn intern(gcx: TyCtxt<'_, 'gcx, 'gcx>, value: Canonical) -> Self::Canonicalized { + value.intern_into(gcx) + } +} + +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for DropckOutlivesResult<'tcx> { + kinds, overflows + } +} + +BraceStructLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for DropckOutlivesResult<'a> { + type Lifted = DropckOutlivesResult<'tcx>; + kinds, overflows + } +} + +impl_stable_hash_for!(struct DropckOutlivesResult<'tcx> { + kinds, overflows +}); + +impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for QueryResult<'tcx, DropckOutlivesResult<'tcx>> { + // we ought to intern this, but I'm too lazy just now + type Canonicalized = Rc>>>; + + fn intern(_gcx: TyCtxt<'_, 'gcx, 'gcx>, value: Canonical) -> Self::Canonicalized { + Rc::new(value) + } +} + +impl_stable_hash_for!(struct DtorckConstraint<'tcx> { + outlives, + dtorck_types, + overflows +}); diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs index 75667ec8ec9a7..421c639fd35d1 100644 --- a/src/librustc/traits/query/mod.rs +++ b/src/librustc/traits/query/mod.rs @@ -15,6 +15,7 @@ //! The providers for the queries defined here can be found in //! `librustc_traits`. +pub mod dropck_outlives; pub mod normalize; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 1f6cc08bd7fde..407581659540c 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -35,6 +35,7 @@ use ty::subst::{Kind, Substs}; use ty::ReprOptions; use ty::Instance; use traits; +use traits::query::dropck_outlives::CanonicalTyGoal; use traits::query::normalize::CanonicalProjectionGoal; use ty::{self, Ty, TypeAndMut}; use ty::{TyS, TypeVariants, Slice}; @@ -107,6 +108,7 @@ pub struct GlobalArenas<'tcx> { /// miri allocations const_allocs: TypedArena, + canonical_ty_goal_arena: TypedArena>, canonical_projection_goal_arena: TypedArena>, } @@ -122,6 +124,7 @@ impl<'tcx> GlobalArenas<'tcx> { tables: TypedArena::new(), const_allocs: TypedArena::new(), canonical_projection_goal_arena: TypedArena::new(), + canonical_ty_goal_arena: TypedArena::new(), } } } @@ -892,6 +895,11 @@ pub struct GlobalCtxt<'tcx> { output_filenames: Arc, + /// HashSet used to canonicalize interned canonical types for the + /// `dropck_outlives` query. Each new unique instance is allocated + /// in an arena for use as a query key. + canonical_ty_goal_set: RefCell>>>, + /// HashSet used to canonicalize interned canonical projection /// goals. Each new unique instance is allocated in an arena for /// use as a query key. @@ -1215,6 +1223,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { on_disk_query_result_cache, types: common_types, canonical_projection_goal_set: RefCell::new(FxHashSet()), + canonical_ty_goal_set: RefCell::new(FxHashSet()), trait_map, export_map: resolutions.export_map.into_iter().map(|(k, v)| { (k, Rc::new(v)) @@ -1755,6 +1764,26 @@ impl<'tcx> Borrow for Interned<'tcx, RegionKind> { } } +impl<'tcx> Borrow> for Interned<'tcx, CanonicalTyGoal<'tcx>> { + fn borrow<'a>(&'a self) -> &'a CanonicalTyGoal<'tcx> { + &self.0 + } +} + +impl<'tcx> PartialEq for Interned<'tcx, CanonicalTyGoal<'tcx>> { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl<'tcx> Eq for Interned<'tcx, CanonicalTyGoal<'tcx>> { } + +impl<'tcx> Hash for Interned<'tcx, CanonicalTyGoal<'tcx>> { + fn hash(&self, s: &mut H) { + self.0.hash(s) + } +} + impl<'tcx> Borrow> for Interned<'tcx, CanonicalProjectionGoal<'tcx>> { fn borrow<'a>(&'a self) -> &'a CanonicalProjectionGoal<'tcx> { &self.0 @@ -2457,6 +2486,20 @@ where fn intern_into(self, gcx: TyCtxt<'_, 'gcx, '_>) -> &'gcx Self; } +impl<'gcx> CanonicalIntern<'gcx> for CanonicalTyGoal<'gcx> { + fn arena(gcx: TyCtxt<'_, 'gcx, '_>) -> &'gcx TypedArena { + &gcx.global_arenas.canonical_ty_goal_arena + } + + fn set<'cx>(gcx: TyCtxt<'cx, 'gcx, '_>) -> &'cx RefCell>> { + &gcx.canonical_ty_goal_set + } + + fn intern_into(self, gcx: TyCtxt<'_, 'gcx, '_>) -> &'gcx Self { + intern_into_impl(self, gcx) + } +} + impl<'gcx> CanonicalIntern<'gcx> for CanonicalProjectionGoal<'gcx> { fn arena(gcx: TyCtxt<'_, 'gcx, '_>) -> &'gcx TypedArena { &gcx.global_arenas.canonical_projection_goal_arena diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index 93f9ceb02a21c..465e44ae9559f 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -60,6 +60,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::normalize_projection_ty<'tcx> { } } +impl<'tcx> QueryDescription<'tcx> for queries::dropck_outlives<'tcx> { + fn describe(_tcx: TyCtxt, goal: &'tcx Canonical>>) -> String { + format!("computing dropck types for `{:?}`", 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/maps/keys.rs b/src/librustc/ty/maps/keys.rs index d60a6b5ab3820..ca2f13c97bdd9 100644 --- a/src/librustc/ty/maps/keys.rs +++ b/src/librustc/ty/maps/keys.rs @@ -170,3 +170,13 @@ impl<'tcx> Key for &'tcx Canonical>> { DUMMY_SP } } + +impl<'tcx> Key for &'tcx Canonical>> { + fn map_crate(&self) -> CrateNum { + LOCAL_CRATE + } + + fn default_span(&self, _tcx: TyCtxt) -> Span { + DUMMY_SP + } +} diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index ca8e62c79148d..f675c102ce0e4 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -34,6 +34,7 @@ use session::{CompileResult, CrateDisambiguator}; use session::config::OutputFilenames; use traits::Vtable; use traits::query::NoSolution; +use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult}; use traits::query::normalize::NormalizationResult; use traits::specialization_graph; use ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; @@ -112,7 +113,9 @@ define_maps! { <'tcx> [] fn adt_def: AdtDefOfItem(DefId) -> &'tcx ty::AdtDef, [] fn adt_destructor: AdtDestructor(DefId) -> Option, [] fn adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>], - [] fn adt_dtorck_constraint: DtorckConstraint(DefId) -> ty::DtorckConstraint<'tcx>, + [] fn adt_dtorck_constraint: DtorckConstraint( + DefId + ) -> Result, NoSolution>, /// True if this is a const fn [] fn is_const_fn: IsConstFn(DefId) -> bool, @@ -372,6 +375,11 @@ define_maps! { <'tcx> &'tcx Canonical>> ) -> Result>>>, NoSolution>, + /// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead. + [] fn dropck_outlives: normalize_ty_node( + &'tcx Canonical>> + ) -> Result>>>, NoSolution>, + [] fn substitute_normalize_and_test_predicates: substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool, @@ -519,7 +527,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> { +fn normalize_ty_node<'tcx, T>(_: T) -> DepConstructor<'tcx> { DepConstructor::NormalizeTy } diff --git a/src/librustc/ty/maps/values.rs b/src/librustc/ty/maps/values.rs index 165798d19f196..8d38d7dbbbbff 100644 --- a/src/librustc/ty/maps/values.rs +++ b/src/librustc/ty/maps/values.rs @@ -35,12 +35,6 @@ impl<'tcx> Value<'tcx> for Ty<'tcx> { } } -impl<'tcx> Value<'tcx> for ty::DtorckConstraint<'tcx> { - fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self { - Self::empty() - } -} - impl<'tcx> Value<'tcx> for ty::SymbolName { fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self { ty::SymbolName { name: Symbol::intern("").as_str() } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 9cf705a696484..a77f265713c41 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -33,8 +33,7 @@ use ty; use ty::subst::{Subst, Substs}; use ty::util::IntTypeExt; use ty::walk::TypeWalker; -use util::common::ErrorReported; -use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet}; +use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; use serialize::{self, Encodable, Encoder}; use std::cell::RefCell; @@ -42,7 +41,6 @@ use std::cmp; use std::cmp::Ordering; use std::fmt; use std::hash::{Hash, Hasher}; -use std::iter::FromIterator; use std::ops::Deref; use std::rc::Rc; use std::slice; @@ -2581,38 +2579,6 @@ fn adt_sized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, result } -/// Calculates the dtorck constraint for a type. -fn adt_dtorck_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> DtorckConstraint<'tcx> { - let def = tcx.adt_def(def_id); - let span = tcx.def_span(def_id); - debug!("dtorck_constraint: {:?}", def); - - if def.is_phantom_data() { - let result = DtorckConstraint { - outlives: vec![], - dtorck_types: vec![ - tcx.mk_param_from_def(&tcx.generics_of(def_id).types[0]) - ] - }; - debug!("dtorck_constraint: {:?} => {:?}", def, result); - return result; - } - - let mut result = def.all_fields() - .map(|field| tcx.type_of(field.did)) - .map(|fty| tcx.dtorck_constraint_for_ty(span, fty, 0, fty)) - .collect::>() - .unwrap_or(DtorckConstraint::empty()); - result.outlives.extend(tcx.destructor_constraints(def)); - result.dedup(); - - debug!("dtorck_constraint: {:?} => {:?}", def, result); - - result -} - fn associated_item_def_ids<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Rc> { @@ -2727,7 +2693,6 @@ pub fn provide(providers: &mut ty::maps::Providers) { associated_item, associated_item_def_ids, adt_sized_constraint, - adt_dtorck_constraint, def_span, param_env, trait_of_item, @@ -2750,49 +2715,6 @@ pub struct CrateInherentImpls { pub inherent_impls: DefIdMap>>, } -/// A set of constraints that need to be satisfied in order for -/// a type to be valid for destruction. -#[derive(Clone, Debug)] -pub struct DtorckConstraint<'tcx> { - /// Types that are required to be alive in order for this - /// type to be valid for destruction. - pub outlives: Vec>, - /// Types that could not be resolved: projections and params. - pub dtorck_types: Vec>, -} - -impl<'tcx> FromIterator> for DtorckConstraint<'tcx> -{ - fn from_iter>>(iter: I) -> Self { - let mut result = Self::empty(); - - for constraint in iter { - result.outlives.extend(constraint.outlives); - result.dtorck_types.extend(constraint.dtorck_types); - } - - result - } -} - - -impl<'tcx> DtorckConstraint<'tcx> { - fn empty() -> DtorckConstraint<'tcx> { - DtorckConstraint { - outlives: vec![], - dtorck_types: vec![] - } - } - - fn dedup<'a>(&mut self) { - let mut outlives = FxHashSet(); - let mut dtorck_types = FxHashSet(); - - self.outlives.retain(|&val| outlives.replace(val).is_none()); - self.dtorck_types.retain(|&val| dtorck_types.replace(val).is_none()); - } -} - #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable)] pub struct SymbolName { // FIXME: we don't rely on interning or equality here - better have diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 778bd59ee9adf..4632b092d1a84 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -19,7 +19,6 @@ use middle::const_val::ConstVal; use traits; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::fold::TypeVisitor; -use ty::subst::{Subst, Kind}; use ty::TypeVariants::*; use util::common::ErrorReported; use middle::lang_items; @@ -502,99 +501,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { result } - /// Return a set of constraints that needs to be satisfied in - /// order for `ty` to be valid for destruction. - pub fn dtorck_constraint_for_ty(self, - span: Span, - for_ty: Ty<'tcx>, - depth: usize, - ty: Ty<'tcx>) - -> Result, ErrorReported> - { - debug!("dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})", - span, for_ty, depth, ty); - - if depth >= self.sess.recursion_limit.get() { - let mut err = struct_span_err!( - self.sess, span, E0320, - "overflow while adding drop-check rules for {}", for_ty); - err.note(&format!("overflowed on {}", ty)); - err.emit(); - return Err(ErrorReported); - } - - let result = match ty.sty { - ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | - ty::TyFloat(_) | ty::TyStr | ty::TyNever | ty::TyForeign(..) | - ty::TyRawPtr(..) | ty::TyRef(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) | - ty::TyGeneratorWitness(..) => { - // these types never have a destructor - Ok(ty::DtorckConstraint::empty()) - } - - ty::TyArray(ety, _) | ty::TySlice(ety) => { - // single-element containers, behave like their element - self.dtorck_constraint_for_ty(span, for_ty, depth+1, ety) - } - - ty::TyTuple(tys, _) => { - tys.iter().map(|ty| { - self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty) - }).collect() - } - - ty::TyClosure(def_id, substs) => { - substs.upvar_tys(def_id, self).map(|ty| { - self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty) - }).collect() - } - - ty::TyGenerator(def_id, substs, _) => { - // Note that the interior types are ignored here. - // Any type reachable inside the interior must also be reachable - // through the upvars. - substs.upvar_tys(def_id, self).map(|ty| { - self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty) - }).collect() - } - - ty::TyAdt(def, substs) => { - let ty::DtorckConstraint { - dtorck_types, outlives - } = self.at(span).adt_dtorck_constraint(def.did); - Ok(ty::DtorckConstraint { - // FIXME: we can try to recursively `dtorck_constraint_on_ty` - // there, but that needs some way to handle cycles. - dtorck_types: dtorck_types.subst(self, substs), - outlives: outlives.subst(self, substs) - }) - } - - // Objects must be alive in order for their destructor - // to be called. - ty::TyDynamic(..) => Ok(ty::DtorckConstraint { - outlives: vec![Kind::from(ty)], - dtorck_types: vec![], - }), - - // Types that can't be resolved. Pass them forward. - ty::TyProjection(..) | ty::TyAnon(..) | ty::TyParam(..) => { - Ok(ty::DtorckConstraint { - outlives: vec![], - dtorck_types: vec![ty], - }) - } - - ty::TyInfer(..) | ty::TyError => { - self.sess.delay_span_bug(span, "unresolved type in dtorck"); - Err(ErrorReported) - } - }; - - debug!("dtorck_constraint_for_ty({:?}) = {:?}", ty, result); - result - } - pub fn is_closure(self, def_id: DefId) -> bool { self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr } diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness.rs index 5b3f439e0ebb9..d19fd2bb5969d 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness.rs @@ -14,13 +14,9 @@ use dataflow::MaybeInitializedPlaces; use dataflow::move_paths::{HasMoveData, MoveData}; use rustc::mir::{BasicBlock, Location, Mir}; use rustc::mir::Local; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc::traits; +use rustc::ty::{Ty, TyCtxt, TypeFoldable}; use rustc::infer::InferOk; -use rustc::util::common::ErrorReported; use borrow_check::nll::type_check::AtLocation; -use rustc_data_structures::fx::FxHashSet; -use syntax::codemap::DUMMY_SP; use util::liveness::LivenessResults; use super::TypeChecker; @@ -193,73 +189,34 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo // // For this reason, we avoid calling TypeChecker.normalize, instead doing all normalization // ourselves in one large 'fully_perform_op' callback. - let (type_constraints, kind_constraints) = self.cx.fully_perform_op(location.at_self(), - |cx| { - - let tcx = cx.infcx.tcx; - let mut selcx = traits::SelectionContext::new(cx.infcx); - let cause = cx.misc(cx.last_span); - - let mut types = vec![(dropped_ty, 0)]; - let mut final_obligations = Vec::new(); - let mut type_constraints = Vec::new(); - let mut kind_constraints = Vec::new(); - - let mut known = FxHashSet(); - - while let Some((ty, depth)) = types.pop() { - let span = DUMMY_SP; // FIXME - let result = match tcx.dtorck_constraint_for_ty(span, dropped_ty, depth, ty) { - Ok(result) => result, - Err(ErrorReported) => { - continue; - } - }; - - let ty::DtorckConstraint { - outlives, - dtorck_types, - } = result; - - // All things in the `outlives` array may be touched by - // the destructor and must be live at this point. - for outlive in outlives { + let kind_constraints = self.cx + .fully_perform_op(location.at_self(), |cx| { + let span = cx.last_span; + + let mut final_obligations = Vec::new(); + let mut kind_constraints = Vec::new(); + + let InferOk { + value: kinds, + obligations, + } = cx.infcx + .at(&cx.misc(span), cx.param_env) + .dropck_outlives(dropped_ty); + for kind in kinds { + // All things in the `outlives` array may be touched by + // the destructor and must be live at this point. let cause = Cause::DropVar(dropped_local, location); - kind_constraints.push((outlive, location, cause)); + kind_constraints.push((kind, location, cause)); } - // However, there may also be some types that - // `dtorck_constraint_for_ty` could not resolve (e.g., - // associated types and parameters). We need to normalize - // associated types here and possibly recursively process. - for ty in dtorck_types { - let traits::Normalized { value: ty, obligations } = - traits::normalize(&mut selcx, cx.param_env, cause.clone(), &ty); - - final_obligations.extend(obligations); + final_obligations.extend(obligations); - let ty = cx.infcx.resolve_type_and_region_vars_if_possible(&ty); - match ty.sty { - ty::TyParam(..) | ty::TyProjection(..) | ty::TyAnon(..) => { - let cause = Cause::DropVar(dropped_local, location); - type_constraints.push((ty, location, cause)); - } - - _ => if known.insert(ty) { - types.push((ty, depth + 1)); - }, - } - } - } - - Ok(InferOk { - value: (type_constraints, kind_constraints), obligations: final_obligations + Ok(InferOk { + value: kind_constraints, + obligations: final_obligations, + }) }) - }).unwrap(); - - for (ty, location, cause) in type_constraints { - self.push_type_live_constraint(ty, location, cause); - } + .unwrap(); for (kind, location, cause) in kind_constraints { self.push_type_live_constraint(kind, location, cause); diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs new file mode 100644 index 0000000000000..74529e5452064 --- /dev/null +++ b/src/librustc_traits/dropck_outlives.rs @@ -0,0 +1,285 @@ +// 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::hir::def_id::DefId; +use rustc::traits::{FulfillmentContext, Normalized, ObligationCause}; +use rustc::traits::query::NoSolution; +use rustc::traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult}; +use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt, subst::Kind}; +use rustc::ty::subst::Subst; +use rustc::util::nodemap::FxHashSet; +use std::rc::Rc; +use syntax::codemap::{Span, DUMMY_SP}; +use util; + +crate fn dropck_outlives<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + goal: &'tcx Canonical>>, +) -> Result>>>, NoSolution> { + debug!("dropck_outlives(goal={:#?})", goal); + + tcx.infer_ctxt().enter(|ref infcx| { + let tcx = infcx.tcx; + let ( + ParamEnvAnd { + param_env, + value: for_ty, + }, + canonical_inference_vars, + ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &goal); + + 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 + // `dtorck_constraint_for_ty`. This may produce new types that + // have to be pushed on the stack. This continues until we have explored + // all the reachable types from the type `for_ty`. + // + // Example: Imagine that we have the following code: + // + // ```rust + // struct A { + // value: B, + // children: Vec, + // } + // + // struct B { + // value: u32 + // } + // + // fn f() { + // let a: A = ...; + // .. + // } // here, `a` is dropped + // ``` + // + // at the point where `a` is dropped, we need to figure out + // which types inside of `a` contain region data that may be + // accessed by any destructors in `a`. We begin by pushing `A` + // onto the stack, as that is the type of `a`. We will then + // invoke `dtorck_constraint_for_ty` which will expand `A` + // into the types of its fields `(B, Vec)`. These will get + // pushed onto the stack. Eventually, expanding `Vec` will + // lead to us trying to push `A` a second time -- to prevent + // infinite recusion, we notice that `A` was already pushed + // once and stop. + let mut ty_stack = vec![(for_ty, 0)]; + + // Set used to detect infinite recursion. + let mut ty_set = FxHashSet(); + + let fulfill_cx = &mut FulfillmentContext::new(); + + let cause = ObligationCause::dummy(); + while let Some((ty, depth)) = ty_stack.pop() { + let DtorckConstraint { + dtorck_types, + outlives, + overflows, + } = dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty)?; + + // "outlives" represent types/regions that may be touched + // by a destructor. + result.kinds.extend(outlives); + result.overflows.extend(overflows); + + // dtorck types are "types that will get dropped but which + // do not themselves define a destructor", more or less. We have + // to push them onto the stack to be expanded. + for ty in dtorck_types { + match infcx.at(&cause, param_env).normalize(&ty) { + Ok(Normalized { + value: ty, + obligations, + }) => { + fulfill_cx.register_predicate_obligations(infcx, obligations); + + debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); + + match ty.sty { + // All parameters live for the duration of the + // function. + ty::TyParam(..) => {} + + // A projection that we couldn't resolve - it + // might have a destructor. + ty::TyProjection(..) | ty::TyAnon(..) => { + result.kinds.push(Kind::from(ty)); + } + + _ => { + if ty_set.insert(ty) { + ty_stack.push((ty, depth + 1)); + } + } + } + } + + // We don't actually expect to fail to normalize. + // That implies a WF error somewhere else. + Err(NoSolution) => { + return Err(NoSolution); + } + } + } + } + + debug!("dropck_outlives: result = {:#?}", result); + + util::make_query_response(infcx, canonical_inference_vars, result, fulfill_cx) + }) +} + +/// Return a set of constraints that needs to be satisfied in +/// order for `ty` to be valid for destruction. +fn dtorck_constraint_for_ty<'a, 'gcx, 'tcx>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + span: Span, + for_ty: Ty<'tcx>, + depth: usize, + ty: Ty<'tcx>, +) -> Result, NoSolution> { + debug!( + "dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})", + span, for_ty, depth, ty + ); + + if depth >= tcx.sess.recursion_limit.get() { + return Ok(DtorckConstraint { + outlives: vec![], + dtorck_types: vec![], + overflows: vec![ty], + }); + } + + let result = match ty.sty { + ty::TyBool + | ty::TyChar + | ty::TyInt(_) + | ty::TyUint(_) + | ty::TyFloat(_) + | ty::TyStr + | ty::TyNever + | ty::TyForeign(..) + | ty::TyRawPtr(..) + | ty::TyRef(..) + | ty::TyFnDef(..) + | ty::TyFnPtr(_) + | ty::TyGeneratorWitness(..) => { + // these types never have a destructor + Ok(DtorckConstraint::empty()) + } + + ty::TyArray(ety, _) | ty::TySlice(ety) => { + // single-element containers, behave like their element + dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ety) + } + + ty::TyTuple(tys, _) => tys.iter() + .map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty)) + .collect(), + + ty::TyClosure(def_id, substs) => substs + .upvar_tys(def_id, tcx) + .map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty)) + .collect(), + + ty::TyGenerator(def_id, substs, _) => { + // Note that the interior types are ignored here. + // Any type reachable inside the interior must also be reachable + // through the upvars. + substs + .upvar_tys(def_id, tcx) + .map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty)) + .collect() + } + + ty::TyAdt(def, substs) => { + let DtorckConstraint { + dtorck_types, + outlives, + overflows, + } = tcx.at(span).adt_dtorck_constraint(def.did)?; + Ok(DtorckConstraint { + // FIXME: we can try to recursively `dtorck_constraint_on_ty` + // there, but that needs some way to handle cycles. + dtorck_types: dtorck_types.subst(tcx, substs), + outlives: outlives.subst(tcx, substs), + overflows: overflows.subst(tcx, substs), + }) + } + + // Objects must be alive in order for their destructor + // to be called. + ty::TyDynamic(..) => Ok(DtorckConstraint { + outlives: vec![Kind::from(ty)], + dtorck_types: vec![], + overflows: vec![], + }), + + // Types that can't be resolved. Pass them forward. + ty::TyProjection(..) | ty::TyAnon(..) | ty::TyParam(..) => Ok(DtorckConstraint { + outlives: vec![], + dtorck_types: vec![ty], + overflows: vec![], + }), + + ty::TyInfer(..) | ty::TyError => { + // By the time this code runs, all type variables ought to + // be fully resolved. + Err(NoSolution) + } + }; + + debug!("dtorck_constraint_for_ty({:?}) = {:?}", ty, result); + result +} + +/// Calculates the dtorck constraint for a type. +crate fn adt_dtorck_constraint<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, +) -> Result, NoSolution> { + let def = tcx.adt_def(def_id); + let span = tcx.def_span(def_id); + debug!("dtorck_constraint: {:?}", def); + + if def.is_phantom_data() { + let result = DtorckConstraint { + outlives: vec![], + dtorck_types: vec![tcx.mk_param_from_def(&tcx.generics_of(def_id).types[0])], + overflows: vec![], + }; + debug!("dtorck_constraint: {:?} => {:?}", def, result); + return Ok(result); + } + + 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.outlives.extend(tcx.destructor_constraints(def)); + dedup_dtorck_constraint(&mut result); + + debug!("dtorck_constraint: {:?} => {:?}", def, result); + + Ok(result) +} + +fn dedup_dtorck_constraint<'tcx>(c: &mut DtorckConstraint<'tcx>) { + let mut outlives = FxHashSet(); + let mut dtorck_types = FxHashSet(); + + c.outlives.retain(|&val| outlives.replace(val).is_none()); + c.dtorck_types + .retain(|&val| dtorck_types.replace(val).is_none()); +} diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs index 0d92404d24b08..59083dcfbf0f4 100644 --- a/src/librustc_traits/lib.rs +++ b/src/librustc_traits/lib.rs @@ -24,6 +24,7 @@ extern crate rustc_data_structures; extern crate syntax; extern crate syntax_pos; +mod dropck_outlives; mod normalize_projection_ty; mod util; @@ -31,6 +32,8 @@ use rustc::ty::maps::Providers; pub fn provide(p: &mut Providers) { *p = Providers { + dropck_outlives: dropck_outlives::dropck_outlives, + adt_dtorck_constraint: dropck_outlives::adt_dtorck_constraint, normalize_projection_ty: normalize_projection_ty::normalize_projection_ty, ..*p }; diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index db5c37bb13ce9..c62e31637821a 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -18,8 +18,8 @@ use rustc::ty::subst::{Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::traits::{self, ObligationCause}; use util::common::ErrorReported; -use util::nodemap::FxHashSet; +use syntax::ast; use syntax_pos::Span; /// check_drop_impl confirms that the Drop implementation identified by @@ -282,6 +282,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( rcx: &mut RegionCtxt<'a, 'gcx, 'tcx>, ty: Ty<'tcx>, span: Span, + body_id: ast::NodeId, scope: region::Scope) -> Result<(), ErrorReported> { @@ -297,47 +298,18 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( }; let parent_scope = rcx.tcx.mk_region(ty::ReScope(parent_scope)); let origin = || infer::SubregionOrigin::SafeDestructor(span); - - let ty = rcx.fcx.resolve_type_vars_if_possible(&ty); - let for_ty = ty; - let mut types = vec![(ty, 0)]; - let mut known = FxHashSet(); - while let Some((ty, depth)) = types.pop() { - let ty::DtorckConstraint { - dtorck_types, outlives - } = rcx.tcx.dtorck_constraint_for_ty(span, for_ty, depth, ty)?; - - for ty in dtorck_types { - let ty = rcx.fcx.normalize_associated_types_in(span, &ty); - let ty = rcx.fcx.resolve_type_vars_with_obligations(ty); - let ty = rcx.fcx.resolve_type_and_region_vars_if_possible(&ty); - match ty.sty { - // All parameters live for the duration of the - // function. - ty::TyParam(..) => {} - - // A projection that we couldn't resolve - it - // might have a destructor. - ty::TyProjection(..) | ty::TyAnon(..) => { - rcx.type_must_outlive(origin(), ty, parent_scope); - } - - _ => { - if let None = known.replace(ty) { - types.push((ty, depth+1)); - } - } - } - } - - for outlive in outlives { - if let Some(r) = outlive.as_region() { - rcx.sub_regions(origin(), parent_scope, r); - } else if let Some(ty) = outlive.as_type() { - rcx.type_must_outlive(origin(), ty, parent_scope); - } + let cause = &ObligationCause::misc(span, body_id); + let infer_ok = rcx.infcx.at(cause, rcx.fcx.param_env).dropck_outlives(ty); + debug!("dropck_outlives = {:#?}", infer_ok); + let kinds = rcx.fcx.register_infer_ok_obligations(infer_ok); + for kind in kinds { + if let Some(r) = kind.as_region() { + rcx.sub_regions(origin(), parent_scope, r); + } else if let Some(ty) = kind.as_type() { + rcx.type_must_outlive(origin(), ty, parent_scope); + } else { + bug!() } } - Ok(()) } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index b5bf59fef9afc..4a4337bd710c1 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -411,8 +411,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { self.type_of_node_must_outlive(origin, hir_id, var_region); let typ = self.resolve_node_type(hir_id); + let body_id = self.body_id; let _ = dropck::check_safety_of_destructor_if_necessary( - self, typ, span, var_scope); + self, typ, span, body_id, var_scope); }) } } @@ -884,8 +885,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { match *region { ty::ReScope(rvalue_scope) => { let typ = self.resolve_type(cmt.ty); + let body_id = self.body_id; let _ = dropck::check_safety_of_destructor_if_necessary( - self, typ, span, rvalue_scope); + self, typ, span, body_id, rvalue_scope); } ty::ReStatic => {} _ => { From 55fc165f27b423599f24824b17afe9a0f2d19304 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 21 Feb 2018 11:24:13 -0500 Subject: [PATCH 18/22] introduce `tcx.normalize_erasing_regions(..)` operaton [VIC] --- src/librustc/session/mod.rs | 5 ++ src/librustc/traits/query/mod.rs | 1 + .../traits/query/normalize_erasing_regions.rs | 81 +++++++++++++++++++ src/librustc/ty/maps/config.rs | 6 ++ src/librustc/ty/maps/mod.rs | 6 ++ src/librustc_traits/lib.rs | 4 + .../normalize_erasing_regions.rs | 37 +++++++++ 7 files changed, 140 insertions(+) create mode 100644 src/librustc/traits/query/normalize_erasing_regions.rs create mode 100644 src/librustc_traits/normalize_erasing_regions.rs diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 401f66c9cfbc3..bf4f2640387c0 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -166,6 +166,8 @@ pub struct PerfStats { /// result had already been canonicalized. pub canonicalized_values_allocated: Cell, /// Number of times this query is invoked. + pub normalize_ty_after_erasing_regions: Cell, + /// Number of times this query is invoked. pub normalize_projection_ty: Cell, } @@ -775,6 +777,8 @@ impl Session { self.perf_stats.queries_canonicalized.get()); println!("Total canonical values interned: {}", self.perf_stats.canonicalized_values_allocated.get()); + println!("normalize_ty_after_erasing_regions: {}", + self.perf_stats.normalize_ty_after_erasing_regions.get()); println!("normalize_projection_ty: {}", self.perf_stats.normalize_projection_ty.get()); } @@ -1041,6 +1045,7 @@ pub fn build_session_(sopts: config::Options, decode_def_path_tables_time: Cell::new(Duration::from_secs(0)), queries_canonicalized: Cell::new(0), canonicalized_values_allocated: Cell::new(0), + normalize_ty_after_erasing_regions: Cell::new(0), normalize_projection_ty: Cell::new(0), }, code_stats: RefCell::new(CodeStats::new()), diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs index 421c639fd35d1..a76cf51e17e46 100644 --- a/src/librustc/traits/query/mod.rs +++ b/src/librustc/traits/query/mod.rs @@ -17,6 +17,7 @@ pub mod dropck_outlives; pub mod normalize; +pub mod normalize_erasing_regions; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct NoSolution; diff --git a/src/librustc/traits/query/normalize_erasing_regions.rs b/src/librustc/traits/query/normalize_erasing_regions.rs new file mode 100644 index 0000000000000..d2d8da88e2de5 --- /dev/null +++ b/src/librustc/traits/query/normalize_erasing_regions.rs @@ -0,0 +1,81 @@ +// 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. + +//! Methods for normalizing when you don't care about regions (and +//! aren't doing type inference). If either of those things don't +//! apply to you, use `infcx.normalize(...)`. +//! +//! The methods in this file use a `TypeFolder` to recursively process +//! contents, invoking the underlying +//! `normalize_ty_after_erasing_regions` query for each type found +//! within. (This underlying query is what is cached.) + +use ty::{self, Ty, TyCtxt}; +use ty::fold::{TypeFoldable, TypeFolder}; + +impl<'cx, 'tcx> TyCtxt<'cx, 'tcx, 'tcx> { + /// Erase the regions in `value` and then fully normalize all the + /// types found within. The result will also have regions erased. + /// + /// This is appropriate to use only after type-check: it assumes + /// that normalization will succeed, for example. + pub fn normalize_erasing_regions(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T + where + T: TypeFoldable<'tcx>, + { + // Erase first before we do the real query -- this keeps the + // cache from being too polluted. + let value = self.erase_regions(&value); + if !value.has_projections() { + value + } else { + value.fold_with(&mut NormalizeAfterErasingRegionsFolder { + tcx: self, + param_env: param_env, + }) + } + } + + /// If you have a `Binder`, you can do this to strip out the + /// late-bound regions and then normalize the result, yielding up + /// a `T` (with regions erased). This is appropriate when the + /// binder is being instantiated at the call site. + /// + /// NB. Currently, higher-ranked type bounds inhibit + /// normalization. Therefore, each time we erase them in + /// translation, we need to normalize the contents. + pub fn normalize_erasing_late_bound_regions( + self, + param_env: ty::ParamEnv<'tcx>, + value: &ty::Binder, + ) -> T + where + T: TypeFoldable<'tcx>, + { + assert!(!value.needs_subst()); + let value = self.erase_late_bound_regions(value); + self.normalize_erasing_regions(param_env, value) + } +} + +struct NormalizeAfterErasingRegionsFolder<'cx, 'tcx: 'cx> { + tcx: TyCtxt<'cx, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, +} + +impl<'cx, 'tcx> TypeFolder<'tcx, 'tcx> for NormalizeAfterErasingRegionsFolder<'cx, 'tcx> { + fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + self.tcx.normalize_ty_after_erasing_regions(self.param_env.and(ty)) + } +} diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index 465e44ae9559f..8419bcf686b08 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -66,6 +66,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::dropck_outlives<'tcx> { } } +impl<'tcx> QueryDescription<'tcx> for queries::normalize_ty_after_erasing_regions<'tcx> { + fn describe(_tcx: TyCtxt, goal: ParamEnvAnd<'tcx, Ty<'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/maps/mod.rs b/src/librustc/ty/maps/mod.rs index f675c102ce0e4..af68d445c55fd 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -375,6 +375,11 @@ define_maps! { <'tcx> &'tcx Canonical>> ) -> Result>>>, NoSolution>, + /// Do not call this query directly: invoke `normalize_erasing_regions` instead. + [] fn normalize_ty_after_erasing_regions: normalize_ty_node( + ParamEnvAnd<'tcx, Ty<'tcx>> + ) -> Ty<'tcx>, + /// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead. [] fn dropck_outlives: normalize_ty_node( &'tcx Canonical>> @@ -527,6 +532,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, T>(_: T) -> DepConstructor<'tcx> { DepConstructor::NormalizeTy } diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs index 59083dcfbf0f4..45d23a2733a2a 100644 --- a/src/librustc_traits/lib.rs +++ b/src/librustc_traits/lib.rs @@ -19,6 +19,7 @@ #[macro_use] extern crate log; +#[macro_use] extern crate rustc; extern crate rustc_data_structures; extern crate syntax; @@ -26,6 +27,7 @@ extern crate syntax_pos; mod dropck_outlives; mod normalize_projection_ty; +mod normalize_erasing_regions; mod util; use rustc::ty::maps::Providers; @@ -35,6 +37,8 @@ pub fn provide(p: &mut Providers) { dropck_outlives: dropck_outlives::dropck_outlives, adt_dtorck_constraint: dropck_outlives::adt_dtorck_constraint, normalize_projection_ty: normalize_projection_ty::normalize_projection_ty, + normalize_ty_after_erasing_regions: + normalize_erasing_regions::normalize_ty_after_erasing_regions, ..*p }; } diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/src/librustc_traits/normalize_erasing_regions.rs new file mode 100644 index 0000000000000..805bf1030b3f6 --- /dev/null +++ b/src/librustc_traits/normalize_erasing_regions.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::traits::{Normalized, ObligationCause}; +use rustc::traits::query::NoSolution; +use rustc::ty::{ParamEnvAnd, Ty, TyCtxt}; +use rustc::util::common::CellUsizeExt; + +crate fn normalize_ty_after_erasing_regions<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + goal: ParamEnvAnd<'tcx, Ty<'tcx>>, +) -> Ty<'tcx> { + let ParamEnvAnd { param_env, value } = goal; + tcx.sess.perf_stats.normalize_ty_after_erasing_regions.increment(); + tcx.infer_ctxt().enter(|infcx| { + let cause = ObligationCause::dummy(); + match infcx.at(&cause, param_env).normalize(&value) { + Ok(Normalized { value: normalized_value, obligations: _ }) => { + // ^^^^^^^^^^^ + // We don't care about the `obligations`, + // they are always only region relations, + // and we are about to erase those anyway. + let normalized_value = infcx.resolve_type_vars_if_possible(&normalized_value); + let normalized_value = infcx.tcx.erase_regions(&normalized_value); + tcx.lift_to_global(&normalized_value).unwrap() + } + Err(NoSolution) => bug!("could not fully normalize `{:?}`", value), + } + }) +} From 3937a5e77b8c7165a1c3267219425da1f3984fff Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 10 Feb 2018 06:22:13 -0500 Subject: [PATCH 19/22] transition various normalization functions to the new methods In particular: - `fully_normalize_monormophic_ty` => `normalize_erasing_regions` - `normalize_associated_type_in_env` => `normalize_erasing_regions` - `fully_normalize_associated_types_in` => `normalize_erasing_regions` - `erase_late_bound_regions_and_normalize` => `normalize_erasing_late_bound_regions` --- src/librustc/infer/mod.rs | 136 +------------------ src/librustc/traits/mod.rs | 5 +- src/librustc/traits/trans/mod.rs | 80 +---------- src/librustc/ty/context.rs | 3 - src/librustc/ty/instance.rs | 2 +- src/librustc/ty/layout.rs | 12 +- src/librustc/ty/maps/config.rs | 6 - src/librustc/ty/maps/mod.rs | 1 - src/librustc_const_eval/eval.rs | 2 +- src/librustc_lint/types.rs | 19 +-- src/librustc_mir/borrow_check/mod.rs | 2 +- src/librustc_mir/interpret/eval_context.rs | 6 +- src/librustc_mir/interpret/terminator/mod.rs | 15 +- src/librustc_mir/monomorphize/item.rs | 5 +- src/librustc_mir/monomorphize/mod.rs | 2 +- src/librustc_mir/shim.rs | 9 +- src/librustc_mir/util/elaborate_drops.rs | 9 +- src/librustc_trans/abi.rs | 2 +- src/librustc_trans/base.rs | 2 +- src/librustc_trans/debuginfo/metadata.rs | 9 +- src/librustc_trans/debuginfo/mod.rs | 6 +- src/librustc_trans/debuginfo/type_names.rs | 8 +- src/librustc_trans/declare.rs | 4 +- src/librustc_trans/intrinsic.rs | 7 +- src/librustc_trans/mir/block.rs | 10 +- src/librustc_trans/mir/constant.rs | 8 +- src/librustc_trans/mir/mod.rs | 3 +- src/librustc_trans/type_of.rs | 5 +- 28 files changed, 97 insertions(+), 281 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index d94e25c5326eb..d90dff97dbeae 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -21,7 +21,6 @@ use hir::def_id::DefId; use middle::free_region::RegionRelations; use middle::region; use middle::lang_items; -use mir::tcx::PlaceTy; use ty::subst::{Kind, Subst, Substs}; use ty::{TyVid, IntVid, FloatVid}; use ty::{self, Ty, TyCtxt}; @@ -35,7 +34,7 @@ use std::collections::BTreeMap; use std::fmt; use syntax::ast; use errors::DiagnosticBuilder; -use syntax_pos::{self, Span, DUMMY_SP}; +use syntax_pos::{self, Span}; use util::nodemap::FxHashMap; use arena::DroplessArena; @@ -493,140 +492,7 @@ pub struct CombinedSnapshot<'a, 'tcx:'a> { _in_progress_tables: Option>>, } -/// Helper trait for shortening the lifetimes inside a -/// value for post-type-checking normalization. -/// -/// This trait offers a normalization method where the inputs and -/// outputs both have the `'gcx` lifetime; the implementations -/// internally create inference contexts and/or lift as needed. -pub trait TransNormalize<'gcx>: TypeFoldable<'gcx> { - fn trans_normalize<'a, 'tcx>(&self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>) - -> Self; -} - -macro_rules! items { ($($item:item)+) => ($($item)+) } -macro_rules! impl_trans_normalize { - ($lt_gcx:tt, $($ty:ty),+) => { - items!($(impl<$lt_gcx> TransNormalize<$lt_gcx> for $ty { - fn trans_normalize<'a, 'tcx>(&self, - infcx: &InferCtxt<'a, $lt_gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>) - -> Self { - infcx.normalize_projections_in(param_env, self) - } - })+); - } -} - -impl_trans_normalize!('gcx, - Ty<'gcx>, - &'gcx ty::Const<'gcx>, - &'gcx Substs<'gcx>, - ty::FnSig<'gcx>, - ty::PolyFnSig<'gcx>, - ty::ClosureSubsts<'gcx>, - ty::PolyTraitRef<'gcx>, - ty::ExistentialTraitRef<'gcx> -); - -impl<'gcx> TransNormalize<'gcx> for PlaceTy<'gcx> { - fn trans_normalize<'a, 'tcx>(&self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>) - -> Self { - match *self { - PlaceTy::Ty { ty } => PlaceTy::Ty { ty: ty.trans_normalize(infcx, param_env) }, - PlaceTy::Downcast { adt_def, substs, variant_index } => { - PlaceTy::Downcast { - adt_def, - substs: substs.trans_normalize(infcx, param_env), - variant_index, - } - } - } - } -} - -// NOTE: Callable from trans only! -impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { - /// Currently, higher-ranked type bounds inhibit normalization. Therefore, - /// each time we erase them in translation, we need to normalize - /// the contents. - pub fn erase_late_bound_regions_and_normalize(self, value: &ty::Binder) - -> T - where T: TransNormalize<'tcx> - { - assert!(!value.needs_subst()); - let value = self.erase_late_bound_regions(value); - self.fully_normalize_associated_types_in(&value) - } - - /// Fully normalizes any associated types in `value`, using an - /// empty environment and `Reveal::All` mode (therefore, suitable - /// only for monomorphized code during trans, basically). - pub fn fully_normalize_associated_types_in(self, value: &T) -> T - where T: TransNormalize<'tcx> - { - debug!("fully_normalize_associated_types_in(t={:?})", value); - - let param_env = ty::ParamEnv::reveal_all(); - let value = self.erase_regions(value); - - if !value.has_projections() { - return value; - } - - self.infer_ctxt().enter(|infcx| { - value.trans_normalize(&infcx, param_env) - }) - } - - /// Does a best-effort to normalize any associated types in - /// `value`; this includes revealing specializable types, so this - /// should be not be used during type-checking, but only during - /// optimization and code generation. - pub fn normalize_associated_type_in_env( - self, value: &T, env: ty::ParamEnv<'tcx> - ) -> T - where T: TransNormalize<'tcx> - { - debug!("normalize_associated_type_in_env(t={:?})", value); - - let value = self.erase_regions(value); - - if !value.has_projections() { - return value; - } - - self.infer_ctxt().enter(|infcx| { - value.trans_normalize(&infcx, env.with_reveal_all()) - }) - } -} - impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { - fn normalize_projections_in(&self, param_env: ty::ParamEnv<'tcx>, value: &T) -> T::Lifted - where T: TypeFoldable<'tcx> + ty::Lift<'gcx> - { - let mut selcx = traits::SelectionContext::new(self); - let cause = traits::ObligationCause::dummy(); - let traits::Normalized { value: result, obligations } = - traits::normalize(&mut selcx, param_env, cause, value); - - debug!("normalize_projections_in: result={:?} obligations={:?}", - result, obligations); - - let mut fulfill_cx = traits::FulfillmentContext::new(); - - for obligation in obligations { - fulfill_cx.register_predicate_obligation(self, obligation); - } - - self.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result) - } - /// Finishes processes any obligations that remain in the /// fulfillment context, and then returns the result with all type /// variables removed and regions erased. Because this is intended diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 9f86c8ebc2341..cf521aa1bd594 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -756,7 +756,10 @@ fn vtable_methods<'a, 'tcx>( // the trait type may have higher-ranked lifetimes in it; // so erase them if they appear, so that we get the type // at some particular call site - let substs = tcx.erase_late_bound_regions_and_normalize(&ty::Binder(substs)); + let substs = tcx.normalize_erasing_late_bound_regions( + ty::ParamEnv::reveal_all(), + &ty::Binder(substs), + ); // It's possible that the method relies on where clauses that // do not hold for this particular set of type parameters. diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs index c873580e3ad6c..c97f6f199d2f5 100644 --- a/src/librustc/traits/trans/mod.rs +++ b/src/librustc/traits/trans/mod.rs @@ -14,14 +14,13 @@ // general routines. use dep_graph::{DepKind, DepTrackingMapConfig}; -use infer::TransNormalize; use std::marker::PhantomData; use syntax_pos::DUMMY_SP; use hir::def_id::DefId; use traits::{FulfillmentContext, Obligation, ObligationCause, SelectionContext, Vtable}; use ty::{self, Ty, TyCtxt}; use ty::subst::{Subst, Substs}; -use ty::fold::{TypeFoldable, TypeFolder}; +use ty::fold::TypeFoldable; /// Attempts to resolve an obligation to a vtable.. The result is /// a shallow vtable resolution -- meaning that we do not @@ -93,12 +92,11 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { param_substs: &Substs<'tcx>, value: &T) -> T - where T: TransNormalize<'tcx> + where T: TypeFoldable<'tcx> { debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value); let substituted = value.subst(self, param_substs); - let substituted = self.erase_regions(&substituted); - AssociatedTypeNormalizer::new(self).fold(&substituted) + self.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substituted) } pub fn trans_apply_param_substs_env( @@ -108,7 +106,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { value: &T, ) -> T where - T: TransNormalize<'tcx>, + T: TypeFoldable<'tcx>, { debug!( "apply_param_substs_env(param_substs={:?}, value={:?}, param_env={:?})", @@ -117,8 +115,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { param_env, ); let substituted = value.subst(self, param_substs); - let substituted = self.erase_regions(&substituted); - AssociatedTypeNormalizerEnv::new(self, param_env).fold(&substituted) + self.normalize_erasing_regions(param_env, substituted) } pub fn trans_impl_self_ty(&self, def_id: DefId, substs: &'tcx Substs<'tcx>) @@ -128,73 +125,6 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { } } -struct AssociatedTypeNormalizer<'a, 'gcx: 'a> { - tcx: TyCtxt<'a, 'gcx, 'gcx>, -} - -impl<'a, 'gcx> AssociatedTypeNormalizer<'a, 'gcx> { - fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>) -> Self { - AssociatedTypeNormalizer { tcx } - } - - fn fold>(&mut self, value: &T) -> T { - if !value.has_projections() { - value.clone() - } else { - value.fold_with(self) - } - } -} - -impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> { - fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> { - self.tcx - } - - fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> { - if !ty.has_projections() { - ty - } else { - debug!("AssociatedTypeNormalizer: ty={:?}", ty); - self.tcx.fully_normalize_monormophic_ty(ty) - } - } -} - -struct AssociatedTypeNormalizerEnv<'a, 'gcx: 'a> { - tcx: TyCtxt<'a, 'gcx, 'gcx>, - param_env: ty::ParamEnv<'gcx>, -} - -impl<'a, 'gcx> AssociatedTypeNormalizerEnv<'a, 'gcx> { - fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>, param_env: ty::ParamEnv<'gcx>) -> Self { - Self { tcx, param_env } - } - - fn fold>(&mut self, value: &T) -> T { - if !value.has_projections() { - value.clone() - } else { - value.fold_with(self) - } - } -} - -impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizerEnv<'a, 'gcx> { - fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> { - self.tcx - } - - fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> { - if !ty.has_projections() { - ty - } else { - debug!("AssociatedTypeNormalizerEnv: ty={:?}", ty); - self.tcx.normalize_associated_type_in_env(&ty, self.param_env) - } - } -} - // Implement DepTrackingMapConfig for `trait_cache` pub struct TraitSelectionCache<'tcx> { data: PhantomData<&'tcx ()> diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 407581659540c..227f33789cef0 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -2463,9 +2463,6 @@ pub fn provide(providers: &mut ty::maps::Providers) { assert_eq!(cnum, LOCAL_CRATE); tcx.sess.features.borrow().clone_closures }; - providers.fully_normalize_monormophic_ty = |tcx, ty| { - tcx.fully_normalize_associated_types_in(&ty) - }; } /// A trait implemented by types that can be canonicalized. diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index e2ab53bf8464d..19be84eb7cf64 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -353,7 +353,7 @@ fn fn_once_adapter_instance<'a, 'tcx>( closure_did, substs); let sig = substs.closure_sig(closure_did, tcx); - let sig = tcx.erase_late_bound_regions_and_normalize(&sig); + let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); assert_eq!(sig.inputs().len(), 1); let substs = tcx.mk_substs([ Kind::from(self_ty), diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 10ecf5d1bd5c2..a4a0d83371cfe 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1202,7 +1202,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { data_ptr.valid_range.start = 1; } - let pointee = tcx.normalize_associated_type_in_env(&pointee, param_env); + let pointee = tcx.normalize_erasing_regions(param_env, pointee); if pointee.is_sized(tcx, param_env, DUMMY_SP) { return Ok(tcx.intern_layout(LayoutDetails::scalar(self, data_ptr))); } @@ -1230,7 +1230,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { // Arrays and slices. ty::TyArray(element, mut count) => { if count.has_projections() { - count = tcx.normalize_associated_type_in_env(&count, param_env); + count = tcx.normalize_erasing_regions(param_env, count); if count.has_projections() { return Err(LayoutError::Unknown(ty)); } @@ -1675,7 +1675,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { // Types with no meaningful known layout. ty::TyProjection(_) | ty::TyAnon(..) => { - let normalized = tcx.normalize_associated_type_in_env(&ty, param_env); + let normalized = tcx.normalize_erasing_regions(param_env, ty); if ty == normalized { return Err(LayoutError::Unknown(ty)); } @@ -1942,7 +1942,7 @@ impl<'a, 'tcx> SizeSkeleton<'tcx> { } ty::TyProjection(_) | ty::TyAnon(..) => { - let normalized = tcx.normalize_associated_type_in_env(&ty, param_env); + let normalized = tcx.normalize_erasing_regions(param_env, ty); if ty == normalized { Err(err) } else { @@ -2048,7 +2048,7 @@ impl<'a, 'tcx> LayoutOf> for LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { /// executes in "reveal all" mode. fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { let param_env = self.param_env.with_reveal_all(); - let ty = self.tcx.normalize_associated_type_in_env(&ty, param_env); + let ty = self.tcx.normalize_erasing_regions(param_env, ty); let details = self.tcx.layout_raw(param_env.and(ty))?; let layout = TyLayout { ty, @@ -2074,7 +2074,7 @@ impl<'a, 'tcx> LayoutOf> for LayoutCx<'tcx, ty::maps::TyCtxtAt<'a, 'tcx /// executes in "reveal all" mode. fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { let param_env = self.param_env.with_reveal_all(); - let ty = self.tcx.normalize_associated_type_in_env(&ty, param_env); + let ty = self.tcx.normalize_erasing_regions(param_env, ty); let details = self.tcx.layout_raw(param_env.and(ty))?; let layout = TyLayout { ty, diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index 8419bcf686b08..96bf6d07a315c 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -609,12 +609,6 @@ impl<'tcx> QueryDescription<'tcx> for queries::has_copy_closures<'tcx> { } } -impl<'tcx> QueryDescription<'tcx> for queries::fully_normalize_monormophic_ty<'tcx> { - fn describe(_tcx: TyCtxt, _: Ty) -> String { - format!("normalizing types") - } -} - impl<'tcx> QueryDescription<'tcx> for queries::typeck_tables_of<'tcx> { #[inline] fn cache_on_disk(def_id: Self::Key) -> bool { diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index af68d445c55fd..663f9f64c9a58 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -368,7 +368,6 @@ define_maps! { <'tcx> // Normally you would just use `tcx.erase_regions(&value)`, // however, which uses this query as a kind of cache. [] 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: normalize_projection_ty_node( diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 8e4ec93c14bae..58e58e6ac7f1c 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -266,7 +266,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, match cx.tables.qpath_def(qpath, e.hir_id) { Def::Const(def_id) | Def::AssociatedConst(def_id) => { - let substs = tcx.normalize_associated_type_in_env(&substs, cx.param_env); + let substs = tcx.normalize_erasing_regions(cx.param_env, substs); match tcx.at(e.span).const_eval(cx.param_env.and((def_id, substs))) { Ok(val) => val, Err(ConstEvalErr { kind: TypeckError, .. }) => { diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index f734f3182a931..c98f767df5a5a 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -13,7 +13,7 @@ use rustc::hir::def_id::DefId; use rustc::hir::map as hir_map; use rustc::ty::subst::Substs; -use rustc::ty::{self, AdtKind, Ty, TyCtxt}; +use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; use rustc::ty::layout::{self, LayoutOf}; use middle::const_val::ConstVal; use rustc_const_eval::ConstContext; @@ -448,8 +448,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // make sure the fields are actually safe. let mut all_phantom = true; for field in &def.non_enum_variant().fields { - let field_ty = cx.fully_normalize_associated_types_in( - &field.ty(cx, substs) + let field_ty = cx.normalize_erasing_regions( + ParamEnv::reveal_all(), + field.ty(cx, substs), ); // repr(transparent) types are allowed to have arbitrary ZSTs, not just // PhantomData -- skip checking all ZST fields @@ -493,8 +494,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let mut all_phantom = true; for field in &def.non_enum_variant().fields { - let field_ty = cx.fully_normalize_associated_types_in( - &field.ty(cx, substs) + let field_ty = cx.normalize_erasing_regions( + ParamEnv::reveal_all(), + field.ty(cx, substs), ); let r = self.check_type_for_ffi(cache, field_ty); match r { @@ -548,8 +550,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // Check the contained variants. for variant in &def.variants { for field in &variant.fields { - let arg = cx.fully_normalize_associated_types_in( - &field.ty(cx, substs) + let arg = cx.normalize_erasing_regions( + ParamEnv::reveal_all(), + field.ty(cx, substs), ); let r = self.check_type_for_ffi(cache, arg); match r { @@ -666,7 +669,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>) { // it is only OK to use this function because extern fns cannot have // any generic types right now: - let ty = self.cx.tcx.fully_normalize_associated_types_in(&ty); + let ty = self.cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); match self.check_type_for_ffi(&mut FxHashSet(), ty) { FfiResult::FfiSafe => {} diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index c6ed971f767cf..09a5302e996f4 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -750,7 +750,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { for (index, field) in def.all_fields().enumerate() { let gcx = self.tcx.global_tcx(); let field_ty = field.ty(gcx, substs); - let field_ty = gcx.normalize_associated_type_in_env(&field_ty, self.param_env); + let field_ty = gcx.normalize_erasing_regions(self.param_env, field_ty); let place = drop_place.clone().field(Field::new(index), field_ty); self.visit_terminator_drop( diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 7580f728a55d3..512252d3b7018 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -311,10 +311,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { pub fn monomorphize(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { // miri doesn't care about lifetimes, and will choke on some crazy ones // let's simply get rid of them - let without_lifetimes = self.tcx.erase_regions(&ty); - let substituted = without_lifetimes.subst(self.tcx, substs); - let substituted = self.tcx.fully_normalize_monormophic_ty(&substituted); - substituted + let substituted = ty.subst(self.tcx, substs); + self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substituted) } /// Return the size and aligment of the value at the given type. diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs index 606bda51edb1f..941b09cf36a10 100644 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ b/src/librustc_mir/interpret/terminator/mod.rs @@ -76,8 +76,14 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { match instance_ty.sty { ty::TyFnDef(..) => { let real_sig = instance_ty.fn_sig(self.tcx); - let sig = self.tcx.erase_late_bound_regions_and_normalize(&sig); - let real_sig = self.tcx.erase_late_bound_regions_and_normalize(&real_sig); + let sig = self.tcx.normalize_erasing_late_bound_regions( + ty::ParamEnv::reveal_all(), + &sig, + ); + let real_sig = self.tcx.normalize_erasing_late_bound_regions( + ty::ParamEnv::reveal_all(), + &real_sig, + ); if !self.check_sig_compat(sig, real_sig)? { return err!(FunctionPointerTyMismatch(real_sig, sig)); } @@ -96,7 +102,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } }; let args = self.operands_to_args(args)?; - let sig = self.tcx.erase_late_bound_regions_and_normalize(&sig); + let sig = self.tcx.normalize_erasing_late_bound_regions( + ty::ParamEnv::reveal_all(), + &sig, + ); self.eval_fn_call( fn_def, destination, diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index a5078187a57e3..8a3236e17c651 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -387,7 +387,10 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { output.push_str("fn("); - let sig = self.tcx.erase_late_bound_regions_and_normalize(&sig); + let sig = self.tcx.normalize_erasing_late_bound_regions( + ty::ParamEnv::reveal_all(), + &sig, + ); if !sig.inputs().is_empty() { for ¶meter_type in sig.inputs() { diff --git a/src/librustc_mir/monomorphize/mod.rs b/src/librustc_mir/monomorphize/mod.rs index bab1d325cd99c..ef34d4cdcbc20 100644 --- a/src/librustc_mir/monomorphize/mod.rs +++ b/src/librustc_mir/monomorphize/mod.rs @@ -88,7 +88,7 @@ fn fn_once_adapter_instance<'a, 'tcx>( closure_did, substs); let sig = substs.closure_sig(closure_did, tcx); - let sig = tcx.erase_late_bound_regions_and_normalize(&sig); + let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); assert_eq!(sig.inputs().len(), 1); let substs = tcx.mk_substs([ Kind::from(self_ty), diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index e6ebdd3d6c167..12898033ed7e0 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -832,14 +832,11 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, let tcx = infcx.tcx; let gcx = tcx.global_tcx(); let def_id = tcx.hir.local_def_id(ctor_id); - let sig = gcx.fn_sig(def_id).no_late_bound_regions() - .expect("LBR in ADT constructor signature"); - let sig = gcx.erase_regions(&sig); let param_env = gcx.param_env(def_id); - // Normalize the sig now that we have liberated the late-bound - // regions. - let sig = gcx.normalize_associated_type_in_env(&sig, param_env); + // Normalize the sig. + let sig = gcx.fn_sig(def_id).no_late_bound_regions().expect("LBR in ADT constructor signature"); + let sig = gcx.normalize_erasing_regions(param_env, sig); let (adt_def, substs) = match sig.output().sty { ty::TyAdt(adt_def, substs) => (adt_def, substs), diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index e2feb0ed39054..0f346a8986680 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -205,11 +205,10 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> let field = Field::new(i); let subpath = self.elaborator.field_subpath(variant_path, field); - let field_ty = - self.tcx().normalize_associated_type_in_env( - &f.ty(self.tcx(), substs), - self.elaborator.param_env() - ); + let field_ty = self.tcx().normalize_erasing_regions( + self.elaborator.param_env(), + f.ty(self.tcx(), substs), + ); (base_place.clone().field(field, field_ty), subpath) }).collect() } diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 12698964d2e65..068fa5547863b 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -648,7 +648,7 @@ impl<'a, 'tcx> FnType<'tcx> { -> Self { let fn_ty = instance.ty(cx.tcx); let sig = ty_fn_sig(cx, fn_ty); - let sig = cx.tcx.erase_late_bound_regions_and_normalize(&sig); + let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); FnType::new(cx, sig, &[]) } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 466a86e7ea558..d62aa8a1d1e10 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -471,7 +471,7 @@ pub fn trans_instance<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, instance: Instance<'tc let fn_ty = instance.ty(cx.tcx); let sig = common::ty_fn_sig(cx, fn_ty); - let sig = cx.tcx.erase_late_bound_regions_and_normalize(&sig); + let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); let lldecl = match cx.instances.borrow().get(&instance) { Some(&val) => val, diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 62ba91840d95e..ecf91dec92be3 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -30,7 +30,7 @@ use rustc::ty::util::TypeIdHasher; use rustc::ich::Fingerprint; use rustc::ty::Instance; use common::CodegenCx; -use rustc::ty::{self, AdtKind, Ty, TyCtxt}; +use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; use rustc::ty::layout::{self, Align, LayoutOf, Size, TyLayout}; use rustc::session::config; use rustc::util::nodemap::FxHashMap; @@ -353,7 +353,10 @@ fn subroutine_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, span: Span) -> MetadataCreationResult { - let signature = cx.tcx.erase_late_bound_regions_and_normalize(&signature); + let signature = cx.tcx.normalize_erasing_late_bound_regions( + ty::ParamEnv::reveal_all(), + &signature, + ); let mut signature_metadata: Vec = Vec::with_capacity(signature.inputs().len() + 1); @@ -589,7 +592,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, } ty::TyGenerator(def_id, substs, _) => { let upvar_tys : Vec<_> = substs.field_tys(def_id, cx.tcx).map(|t| { - cx.tcx.fully_normalize_associated_types_in(&t) + cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t) }).collect(); prepare_tuple_metadata(cx, t, diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 9071eb776d529..cb4c4079b7991 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -30,7 +30,7 @@ use abi::Abi; use common::CodegenCx; use builder::Builder; use monomorphize::Instance; -use rustc::ty::{self, Ty}; +use rustc::ty::{self, ParamEnv, Ty}; use rustc::mir; use rustc::session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}; use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet}; @@ -378,7 +378,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, name_to_append_suffix_to.push_str(","); } - let actual_type = cx.tcx.fully_normalize_associated_types_in(&actual_type); + let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), actual_type); // Add actual type name to <...> clause of function name let actual_type_name = compute_debuginfo_type_name(cx, actual_type, @@ -391,7 +391,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, let template_params: Vec<_> = if cx.sess().opts.debuginfo == FullDebugInfo { let names = get_type_parameter_names(cx, generics); substs.types().zip(names).map(|(ty, name)| { - let actual_type = cx.tcx.fully_normalize_associated_types_in(&ty); + let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); let actual_type_metadata = type_metadata(cx, actual_type, syntax_pos::DUMMY_SP); let name = CString::new(name.as_str().as_bytes()).unwrap(); unsafe { diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 6490d109f2936..c43ad99e0004d 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -117,8 +117,10 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, }, ty::TyDynamic(ref trait_data, ..) => { if let Some(principal) = trait_data.principal() { - let principal = cx.tcx.erase_late_bound_regions_and_normalize( - &principal); + let principal = cx.tcx.normalize_erasing_late_bound_regions( + ty::ParamEnv::reveal_all(), + &principal, + ); push_item_name(cx, principal.def_id, false, output); push_type_params(cx, principal.substs, output); } @@ -138,7 +140,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, output.push_str("fn("); - let sig = cx.tcx.erase_late_bound_regions_and_normalize(&sig); + let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); if !sig.inputs().is_empty() { for ¶meter_type in sig.inputs() { push_debuginfo_type_name(cx, parameter_type, true, output); diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs index aa1cd0c27e795..c2010feb1b638 100644 --- a/src/librustc_trans/declare.rs +++ b/src/librustc_trans/declare.rs @@ -22,7 +22,7 @@ use llvm::{self, ValueRef}; use llvm::AttributePlace::Function; -use rustc::ty::Ty; +use rustc::ty::{self, Ty}; use rustc::session::config::Sanitizer; use rustc_back::PanicStrategy; use abi::{Abi, FnType}; @@ -127,7 +127,7 @@ pub fn declare_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, name: &str, fn_type: Ty<'tcx>) -> ValueRef { debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type); let sig = common::ty_fn_sig(cx, fn_type); - let sig = cx.tcx.erase_late_bound_regions_and_normalize(&sig); + let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); debug!("declare_rust_fn (after region erasure) sig={:?}", sig); let fty = FnType::new(cx, sig, &[]); diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index b1f1fb52c907d..68b4c900c8e8f 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -100,7 +100,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, }; let sig = callee_ty.fn_sig(tcx); - let sig = tcx.erase_late_bound_regions_and_normalize(&sig); + let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); let arg_tys = sig.inputs(); let ret_ty = sig.output(); let name = &*tcx.item_name(def_id); @@ -1031,7 +1031,10 @@ fn generic_simd_intrinsic<'a, 'tcx>( let tcx = bx.tcx(); - let sig = tcx.erase_late_bound_regions_and_normalize(&callee_ty.fn_sig(tcx)); + let sig = tcx.normalize_erasing_late_bound_regions( + ty::ParamEnv::reveal_all(), + &callee_ty.fn_sig(tcx), + ); let arg_tys = sig.inputs(); // every intrinsic takes a SIMD vector as its first argument diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index d741e5b486f8e..7ca287582fb58 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -281,7 +281,10 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { ty::TyDynamic(..) => { let fn_ty = drop_fn.ty(bx.cx.tcx); let sig = common::ty_fn_sig(bx.cx, fn_ty); - let sig = bx.tcx().erase_late_bound_regions_and_normalize(&sig); + let sig = bx.tcx().normalize_erasing_late_bound_regions( + ty::ParamEnv::reveal_all(), + &sig, + ); let fn_ty = FnType::new_vtable(bx.cx, sig, &[]); args = &args[..1]; (meth::DESTRUCTOR.get_fn(&bx, place.llextra, &fn_ty), fn_ty) @@ -452,7 +455,10 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { }; let def = instance.map(|i| i.def); let sig = callee.layout.ty.fn_sig(bx.tcx()); - let sig = bx.tcx().erase_late_bound_regions_and_normalize(&sig); + let sig = bx.tcx().normalize_erasing_late_bound_regions( + ty::ParamEnv::reveal_all(), + &sig, + ); let abi = sig.abi; // Handle intrinsics old trans wants Expr's for, ourselves. diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 440899a06b739..7c5b3a5f3a5b5 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -13,7 +13,6 @@ use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind}; use rustc_const_math::ConstInt::*; use rustc_const_math::{ConstInt, ConstMathErr, MAX_F32_PLUS_HALF_ULP}; use rustc::hir::def_id::DefId; -use rustc::infer::TransNormalize; use rustc::mir; use rustc::mir::tcx::PlaceTy; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; @@ -305,7 +304,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } fn monomorphize(&self, value: &T) -> T - where T: TransNormalize<'tcx> + where T: TypeFoldable<'tcx> { self.cx.tcx.trans_apply_param_substs(self.substs, value) } @@ -736,7 +735,10 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { .unwrap().def_id; // Now create its substs [Closure, Tuple] let input = substs.closure_sig(def_id, tcx).input(0); - let input = tcx.erase_late_bound_regions_and_normalize(&input); + let input = tcx.normalize_erasing_late_bound_regions( + ty::ParamEnv::reveal_all(), + &input, + ); let substs = tcx.mk_substs([operand.ty, input] .iter().cloned().map(Kind::from)); callee::resolve_and_get_fn(self.cx, call_once, substs) diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index da01592d9118a..98c7b2da6f034 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -15,7 +15,6 @@ use rustc::ty::{self, TypeFoldable}; use rustc::ty::layout::{LayoutOf, TyLayout}; use rustc::mir::{self, Mir}; use rustc::ty::subst::Substs; -use rustc::infer::TransNormalize; use rustc::session::config::FullDebugInfo; use base; use builder::Builder; @@ -104,7 +103,7 @@ pub struct FunctionCx<'a, 'tcx:'a> { impl<'a, 'tcx> FunctionCx<'a, 'tcx> { pub fn monomorphize(&self, value: &T) -> T - where T: TransNormalize<'tcx> + where T: TypeFoldable<'tcx> { self.cx.tcx.trans_apply_param_substs(self.param_substs, value) } diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index af957500f7002..f37114ee4acd1 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -258,7 +258,10 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { cx.layout_of(self.ty.boxed_ty()).llvm_type(cx).ptr_to() } ty::TyFnPtr(sig) => { - let sig = cx.tcx.erase_late_bound_regions_and_normalize(&sig); + let sig = cx.tcx.normalize_erasing_late_bound_regions( + ty::ParamEnv::reveal_all(), + &sig, + ); FnType::new(cx, sig, &[]).llvm_type(cx).ptr_to() } _ => self.scalar_llvm_type_at(cx, scalar, Size::from_bytes(0)) From d1ee1b2a5317893098e43841b8e6753ceb5dfd33 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 13 Feb 2018 09:15:01 -0500 Subject: [PATCH 20/22] move `drain_fulfillment_cx_or_panic` to be private to traits::trans --- src/librustc/infer/mod.rs | 40 ----------------------------- src/librustc/traits/trans/mod.rs | 44 ++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 40 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index d90dff97dbeae..cfec86ea4f802 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -493,46 +493,6 @@ pub struct CombinedSnapshot<'a, 'tcx:'a> { } impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { - /// Finishes processes any obligations that remain in the - /// fulfillment context, and then returns the result with all type - /// variables removed and regions erased. Because this is intended - /// for use after type-check has completed, if any errors occur, - /// it will panic. It is used during normalization and other cases - /// where processing the obligations in `fulfill_cx` may cause - /// type inference variables that appear in `result` to be - /// unified, and hence we need to process those obligations to get - /// the complete picture of the type. - pub fn drain_fulfillment_cx_or_panic(&self, - span: Span, - fulfill_cx: &mut traits::FulfillmentContext<'tcx>, - result: &T) - -> T::Lifted - where T: TypeFoldable<'tcx> + ty::Lift<'gcx> - { - debug!("drain_fulfillment_cx_or_panic()"); - - // In principle, we only need to do this so long as `result` - // contains unbound type parameters. It could be a slight - // optimization to stop iterating early. - match fulfill_cx.select_all_or_error(self) { - Ok(()) => { } - Err(errors) => { - span_bug!(span, "Encountered errors `{:?}` resolving bounds after type-checking", - errors); - } - } - - let result = self.resolve_type_vars_if_possible(result); - let result = self.tcx.erase_regions(&result); - - match self.tcx.lift_to_global(&result) { - Some(result) => result, - None => { - span_bug!(span, "Uninferred types/regions in `{:?}`", result); - } - } - } - pub fn is_in_snapshot(&self) -> bool { self.in_snapshot.get() } diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs index c97f6f199d2f5..86f9d168ad304 100644 --- a/src/librustc/traits/trans/mod.rs +++ b/src/librustc/traits/trans/mod.rs @@ -17,6 +17,8 @@ use dep_graph::{DepKind, DepTrackingMapConfig}; use std::marker::PhantomData; use syntax_pos::DUMMY_SP; use hir::def_id::DefId; +use infer::InferCtxt; +use syntax_pos::Span; use traits::{FulfillmentContext, Obligation, ObligationCause, SelectionContext, Vtable}; use ty::{self, Ty, TyCtxt}; use ty::subst::{Subst, Substs}; @@ -151,3 +153,45 @@ impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> { DepKind::TraitSelect } } + +impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { + /// Finishes processes any obligations that remain in the + /// fulfillment context, and then returns the result with all type + /// variables removed and regions erased. Because this is intended + /// for use after type-check has completed, if any errors occur, + /// it will panic. It is used during normalization and other cases + /// where processing the obligations in `fulfill_cx` may cause + /// type inference variables that appear in `result` to be + /// unified, and hence we need to process those obligations to get + /// the complete picture of the type. + fn drain_fulfillment_cx_or_panic(&self, + span: Span, + fulfill_cx: &mut FulfillmentContext<'tcx>, + result: &T) + -> T::Lifted + where T: TypeFoldable<'tcx> + ty::Lift<'gcx> + { + debug!("drain_fulfillment_cx_or_panic()"); + + // In principle, we only need to do this so long as `result` + // contains unbound type parameters. It could be a slight + // optimization to stop iterating early. + match fulfill_cx.select_all_or_error(self) { + Ok(()) => { } + Err(errors) => { + span_bug!(span, "Encountered errors `{:?}` resolving bounds after type-checking", + errors); + } + } + + let result = self.resolve_type_vars_if_possible(result); + let result = self.tcx.erase_regions(&result); + + match self.tcx.lift_to_global(&result) { + Some(result) => result, + None => { + span_bug!(span, "Uninferred types/regions in `{:?}`", result); + } + } + } +} From a4e763ce92b6babb857754fd73618aa104c16761 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 21 Feb 2018 19:40:59 -0500 Subject: [PATCH 21/22] update test: `victim` is now `Copy` because of the where-clause --- src/test/compile-fail/issue-42796.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/compile-fail/issue-42796.rs b/src/test/compile-fail/issue-42796.rs index 10622eccbdcd1..b07c23c3fc72d 100644 --- a/src/test/compile-fail/issue-42796.rs +++ b/src/test/compile-fail/issue-42796.rs @@ -17,7 +17,7 @@ impl Mirror for T { } pub fn poison(victim: String) where >::Image: Copy { - loop { drop(victim); } //~ ERROR use of moved value + loop { drop(victim); } } fn main() { From 41d762fb5d561e790ff5fcd1fe9caf10a1fe1218 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 23 Feb 2018 15:34:22 -0500 Subject: [PATCH 22/22] remove the overloaded anon nodes, and convert to `()`-style depnodes This means we require less crappy glue code. We couldn't use `()`-style before because we needed a more general notion of type. --- src/librustc/dep_graph/dep_node.rs | 5 +++-- src/librustc/ty/maps/mod.rs | 16 +++------------- src/librustc/ty/maps/plumbing.rs | 3 ++- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 8f45e76f4ad62..5eaa0b42661a8 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -631,8 +631,9 @@ define_dep_nodes!( <'tcx> [] CodegenUnit(InternedString), [] CompileCodegenUnit(InternedString), [input] OutputFilenames, - [anon] NormalizeTy, - [] NormalizeProjectionTy { ty: &'tcx Canonical>> }, + [] NormalizeProjectionTy(&'tcx Canonical>>), + [] NormalizeTyAfterErasingRegions(ParamEnvAnd<'tcx, Ty<'tcx>>), + [] DropckOutlives(&'tcx Canonical>>), // We use this for most things when incr. comp. is turned off. [] Null, diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 663f9f64c9a58..1168851561a8f 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -370,17 +370,17 @@ define_maps! { <'tcx> [] fn erase_regions_ty: erase_regions_ty(Ty<'tcx>) -> Ty<'tcx>, /// Do not call this query directly: invoke `normalize` instead. - [] fn normalize_projection_ty: normalize_projection_ty_node( + [] fn normalize_projection_ty: NormalizeProjectionTy( &'tcx Canonical>> ) -> Result>>>, NoSolution>, /// Do not call this query directly: invoke `normalize_erasing_regions` instead. - [] fn normalize_ty_after_erasing_regions: normalize_ty_node( + [] fn normalize_ty_after_erasing_regions: NormalizeTyAfterErasingRegions( ParamEnvAnd<'tcx, Ty<'tcx>> ) -> Ty<'tcx>, /// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead. - [] fn dropck_outlives: normalize_ty_node( + [] fn dropck_outlives: DropckOutlives( &'tcx Canonical>> ) -> Result>>>, NoSolution>, @@ -532,16 +532,6 @@ fn vtable_methods_node<'tcx>(trait_ref: ty::PolyTraitRef<'tcx>) -> DepConstructo DepConstructor::VtableMethods{ trait_ref } } -fn normalize_ty_node<'tcx, T>(_: T) -> DepConstructor<'tcx> { - DepConstructor::NormalizeTy -} - -fn normalize_projection_ty_node<'tcx>( - ty: &'tcx Canonical>> -) -> DepConstructor<'tcx> { - DepConstructor::NormalizeProjectionTy { ty } -} - fn substitute_normalize_and_test_predicates_node<'tcx>(key: (DefId, &'tcx Substs<'tcx>)) -> DepConstructor<'tcx> { DepConstructor::SubstituteNormalizeAndTestPredicates { key } diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 3e46c314df497..878ade737455a 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -772,8 +772,9 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::FulfillObligation | DepKind::VtableMethods | DepKind::EraseRegionsTy | - DepKind::NormalizeTy | DepKind::NormalizeProjectionTy | + DepKind::NormalizeTyAfterErasingRegions | + DepKind::DropckOutlives | DepKind::SubstituteNormalizeAndTestPredicates | DepKind::InstanceDefSizeEstimate |