diff options
Diffstat (limited to 'compiler/rustc_traits/src')
-rw-r--r-- | compiler/rustc_traits/src/chalk/db.rs | 2 | ||||
-rw-r--r-- | compiler/rustc_traits/src/dropck_outlives.rs | 220 | ||||
-rw-r--r-- | compiler/rustc_traits/src/evaluate_obligation.rs | 20 | ||||
-rw-r--r-- | compiler/rustc_traits/src/implied_outlives_bounds.rs | 7 | ||||
-rw-r--r-- | compiler/rustc_traits/src/lib.rs | 1 | ||||
-rw-r--r-- | compiler/rustc_traits/src/normalize_erasing_regions.rs | 46 | ||||
-rw-r--r-- | compiler/rustc_traits/src/type_op.rs | 10 |
7 files changed, 147 insertions, 159 deletions
diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index ff5ca0cbc..0de28b826 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -7,8 +7,8 @@ //! `crate::chalk::lowering` (to lower rustc types into Chalk types). use rustc_middle::traits::ChalkRustInterner as RustInterner; -use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::{self, AssocKind, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable}; +use rustc_middle::ty::{InternalSubsts, SubstsRef}; use rustc_ast::ast; use rustc_attr as attr; diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs index a20de08b4..d5a8ca5ea 100644 --- a/compiler/rustc_traits/src/dropck_outlives.rs +++ b/compiler/rustc_traits/src/dropck_outlives.rs @@ -4,7 +4,7 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::subst::{InternalSubsts, Subst}; +use rustc_middle::ty::InternalSubsts; use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt}; use rustc_span::source_map::{Span, DUMMY_SP}; use rustc_trait_selection::traits::query::dropck_outlives::trivial_dropck_outlives; @@ -27,128 +27,120 @@ fn dropck_outlives<'tcx>( ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>, NoSolution> { debug!("dropck_outlives(goal={:#?})", canonical_goal); - tcx.infer_ctxt().enter_with_canonical( - DUMMY_SP, - &canonical_goal, - |ref infcx, goal, canonical_inference_vars| { - let tcx = infcx.tcx; - let ParamEnvAnd { param_env, value: for_ty } = 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<A>, - // } - // - // 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<A>)`. These will get - // pushed onto the stack. Eventually, expanding `Vec<A>` will - // lead to us trying to push `A` a second time -- to prevent - // infinite recursion, 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::default(); - - let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); - - let cause = ObligationCause::dummy(); - let mut constraints = DropckConstraint::empty(); - while let Some((ty, depth)) = ty_stack.pop() { - debug!( - "{} kinds, {} overflows, {} ty_stack", - result.kinds.len(), - result.overflows.len(), - ty_stack.len() - ); - dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?; - - // "outlives" represent types/regions that may be touched - // by a destructor. - result.kinds.append(&mut constraints.outlives); - result.overflows.append(&mut constraints.overflows); - - // If we have even one overflow, we should stop trying to evaluate further -- - // chances are, the subsequent overflows for this evaluation won't provide useful - // information and will just decrease the speed at which we can emit these errors - // (since we'll be printing for just that much longer for the often enormous types - // that result here). - if !result.overflows.is_empty() { - break; - } + let (ref infcx, goal, canonical_inference_vars) = + tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal); + let tcx = infcx.tcx; + let ParamEnvAnd { param_env, value: for_ty } = 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<A>, + // } + // + // 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<A>)`. These will get + // pushed onto the stack. Eventually, expanding `Vec<A>` will + // lead to us trying to push `A` a second time -- to prevent + // infinite recursion, 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::default(); + + let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); + + let cause = ObligationCause::dummy(); + let mut constraints = DropckConstraint::empty(); + while let Some((ty, depth)) = ty_stack.pop() { + debug!( + "{} kinds, {} overflows, {} ty_stack", + result.kinds.len(), + result.overflows.len(), + ty_stack.len() + ); + dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?; + + // "outlives" represent types/regions that may be touched + // by a destructor. + result.kinds.append(&mut constraints.outlives); + result.overflows.append(&mut constraints.overflows); + + // If we have even one overflow, we should stop trying to evaluate further -- + // chances are, the subsequent overflows for this evaluation won't provide useful + // information and will just decrease the speed at which we can emit these errors + // (since we'll be printing for just that much longer for the often enormous types + // that result here). + if !result.overflows.is_empty() { + break; + } - // 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 constraints.dtorck_types.drain(..) { - 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.kind() { - // All parameters live for the duration of the - // function. - ty::Param(..) => {} - - // A projection that we couldn't resolve - it - // might have a destructor. - ty::Projection(..) | ty::Opaque(..) => { - result.kinds.push(ty.into()); - } - - _ => { - if ty_set.insert(ty) { - ty_stack.push((ty, depth + 1)); - } - } - } + // 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 constraints.dtorck_types.drain(..) { + 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.kind() { + // All parameters live for the duration of the + // function. + ty::Param(..) => {} + + // A projection that we couldn't resolve - it + // might have a destructor. + ty::Projection(..) | ty::Opaque(..) => { + result.kinds.push(ty.into()); } - // We don't actually expect to fail to normalize. - // That implies a WF error somewhere else. - Err(NoSolution) => { - return Err(NoSolution); + _ => { + 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); + debug!("dropck_outlives: result = {:#?}", result); - infcx.make_canonicalized_query_response( - canonical_inference_vars, - result, - &mut *fulfill_cx, - ) - }, - ) + infcx.make_canonicalized_query_response(canonical_inference_vars, result, &mut *fulfill_cx) } /// Returns a set of constraints that needs to be satisfied in diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs index 49c9ba459..493d5de08 100644 --- a/compiler/rustc_traits/src/evaluate_obligation.rs +++ b/compiler/rustc_traits/src/evaluate_obligation.rs @@ -18,17 +18,15 @@ fn evaluate_obligation<'tcx>( debug!("evaluate_obligation(canonical_goal={:#?})", canonical_goal); // HACK This bubble is required for this tests to pass: // impl-trait/issue99642.rs - tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter_with_canonical( - DUMMY_SP, - &canonical_goal, - |ref infcx, goal, _canonical_inference_vars| { - debug!("evaluate_obligation: goal={:#?}", goal); - let ParamEnvAnd { param_env, value: predicate } = goal; + let (ref infcx, goal, _canonical_inference_vars) = tcx + .infer_ctxt() + .with_opaque_type_inference(DefiningAnchor::Bubble) + .build_with_canonical(DUMMY_SP, &canonical_goal); + debug!("evaluate_obligation: goal={:#?}", goal); + let ParamEnvAnd { param_env, value: predicate } = goal; - let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical); - let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate); + let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical); + let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate); - selcx.evaluate_root_obligation(&obligation) - }, - ) + selcx.evaluate_root_obligation(&obligation) } diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 691b79f10..7d36b9558 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -35,7 +35,7 @@ fn implied_outlives_bounds<'tcx>( } fn compute_implied_outlives_bounds<'tcx>( - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, ) -> Fallible<Vec<OutlivesBound<'tcx>>> { @@ -79,7 +79,7 @@ fn compute_implied_outlives_bounds<'tcx>( // implied bounds in some cases, mostly when dealing with projections. fulfill_cx.register_predicate_obligations( infcx, - obligations.iter().filter(|o| o.predicate.has_infer_types_or_consts()).cloned(), + obligations.iter().filter(|o| o.predicate.has_non_region_infer()).cloned(), ); // From the full set of obligations, just filter down to the @@ -156,6 +156,9 @@ fn implied_bounds_from_components<'tcx>( Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)), Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)), Component::Projection(p) => Some(OutlivesBound::RegionSubProjection(sub_region, p)), + Component::Opaque(def_id, substs) => { + Some(OutlivesBound::RegionSubOpaque(sub_region, def_id, substs)) + } Component::EscapingProjection(_) => // If the projection has escaping regions, don't // try to infer any implied bounds even for its diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index 2d39e973e..0da28737f 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -3,7 +3,6 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] -#![cfg_attr(bootstrap, feature(let_else))] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 5d394ed22..2da64d73d 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -18,9 +18,6 @@ pub(crate) fn provide(p: &mut Providers) { try_normalize_after_erasing_regions(tcx, goal) }, - try_normalize_mir_const_after_erasing_regions: |tcx, goal| { - try_normalize_after_erasing_regions(tcx, goal) - }, ..*p }; } @@ -30,30 +27,29 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + goal: ParamEnvAnd<'tcx, T>, ) -> Result<T, NoSolution> { let ParamEnvAnd { param_env, value } = goal; - tcx.infer_ctxt().enter(|infcx| { - let cause = ObligationCause::dummy(); - match infcx.at(&cause, param_env).normalize(value) { - Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => { - // We don't care about the `obligations`; they are - // always only region relations, and we are about to - // erase those anyway: - debug_assert_eq!( - normalized_obligations.iter().find(|p| not_outlives_predicate(p.predicate)), - None, - ); + let infcx = tcx.infer_ctxt().build(); + let cause = ObligationCause::dummy(); + match infcx.at(&cause, param_env).normalize(value) { + Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => { + // We don't care about the `obligations`; they are + // always only region relations, and we are about to + // erase those anyway: + debug_assert_eq!( + normalized_obligations.iter().find(|p| not_outlives_predicate(p.predicate)), + None, + ); - let resolved_value = infcx.resolve_vars_if_possible(normalized_value); - // It's unclear when `resolve_vars` would have an effect in a - // fresh `InferCtxt`. If this assert does trigger, it will give - // us a test case. - debug_assert_eq!(normalized_value, resolved_value); - let erased = infcx.tcx.erase_regions(resolved_value); - debug_assert!(!erased.needs_infer(), "{:?}", erased); - Ok(erased) - } - Err(NoSolution) => Err(NoSolution), + let resolved_value = infcx.resolve_vars_if_possible(normalized_value); + // It's unclear when `resolve_vars` would have an effect in a + // fresh `InferCtxt`. If this assert does trigger, it will give + // us a test case. + debug_assert_eq!(normalized_value, resolved_value); + let erased = infcx.tcx.erase_regions(resolved_value); + debug_assert!(!erased.needs_infer(), "{:?}", erased); + Ok(erased) } - }) + Err(NoSolution) => Err(NoSolution), + } } fn not_outlives_predicate<'tcx>(p: ty::Predicate<'tcx>) -> bool { diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index 1bb6506b3..bca7458ed 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -5,10 +5,10 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{ObligationCauseCode, TraitEngineExt as _}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::subst::{GenericArg, Subst, UserSelfTy, UserSubsts}; use rustc_middle::ty::{ self, EarlyBinder, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable, Variance, }; +use rustc_middle::ty::{GenericArg, UserSelfTy, UserSubsts}; use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Predicate, ToPredicate}; use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtBuilderExt; @@ -51,7 +51,7 @@ fn type_op_ascribe_user_type<'tcx>( /// this query can be re-run to better track the span of the obligation cause, and improve the error /// message. Do not call directly unless you're in that very specific context. pub fn type_op_ascribe_user_type_with_span<'a, 'tcx: 'a>( - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, fulfill_cx: &'a mut dyn TraitEngine<'tcx>, key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>, span: Option<Span>, @@ -68,7 +68,7 @@ pub fn type_op_ascribe_user_type_with_span<'a, 'tcx: 'a>( } struct AscribeUserTypeCx<'me, 'tcx> { - infcx: &'me InferCtxt<'me, 'tcx>, + infcx: &'me InferCtxt<'tcx>, param_env: ParamEnv<'tcx>, span: Span, fulfill_cx: &'me mut dyn TraitEngine<'tcx>, @@ -210,7 +210,7 @@ fn type_op_eq<'tcx>( } fn type_op_normalize<'tcx, T>( - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, fulfill_cx: &mut dyn TraitEngine<'tcx>, key: ParamEnvAnd<'tcx, Normalize<T>>, ) -> Fallible<T> @@ -285,7 +285,7 @@ fn type_op_prove_predicate<'tcx>( /// this query can be re-run to better track the span of the obligation cause, and improve the error /// message. Do not call directly unless you're in that very specific context. pub fn type_op_prove_predicate_with_cause<'a, 'tcx: 'a>( - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, fulfill_cx: &'a mut dyn TraitEngine<'tcx>, key: ParamEnvAnd<'tcx, ProvePredicate<'tcx>>, cause: ObligationCause<'tcx>, |