diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index ef564ac89f906..78e57c6a5d78f 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -649,6 +649,7 @@ define_dep_nodes!( <'tcx> [input] OutputFilenames, [] NormalizeProjectionTy(CanonicalProjectionGoal<'tcx>), [] NormalizeTyAfterErasingRegions(ParamEnvAnd<'tcx, Ty<'tcx>>), + [] ImpliedOutlivesBounds(CanonicalTyGoal<'tcx>), [] DropckOutlives(CanonicalTyGoal<'tcx>), [] EvaluateObligation(CanonicalPredicateGoal<'tcx>), [] TypeOpEq(CanonicalTypeOpEqGoal<'tcx>), diff --git a/src/librustc/infer/canonical/query_result.rs b/src/librustc/infer/canonical/query_result.rs index 02684d962ba8d..f0b6d25e9dae8 100644 --- a/src/librustc/infer/canonical/query_result.rs +++ b/src/librustc/infer/canonical/query_result.rs @@ -18,8 +18,10 @@ //! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html use infer::canonical::substitute::substitute_value; -use infer::canonical::{Canonical, CanonicalVarKind, CanonicalVarValues, CanonicalizedQueryResult, - Certainty, QueryRegionConstraint, QueryResult, SmallCanonicalVarValues}; +use infer::canonical::{ + Canonical, CanonicalVarKind, CanonicalVarValues, CanonicalizedQueryResult, Certainty, + QueryRegionConstraint, QueryResult, SmallCanonicalVarValues, +}; use infer::region_constraints::{Constraint, RegionConstraintData}; use infer::InferCtxtBuilder; use infer::{InferCtxt, InferOk, InferResult, RegionObligation}; @@ -276,9 +278,9 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { for (index, original_value) in original_values.iter().enumerate() { // ...with the value `v_r` of that variable from the query. - let result_value = query_result - .substitute_projected(self.tcx, &result_subst, - |v| &v.var_values[CanonicalVar::new(index)]); + let result_value = query_result.substitute_projected(self.tcx, &result_subst, |v| { + &v.var_values[CanonicalVar::new(index)] + }); match (original_value.unpack(), result_value.unpack()) { (UnpackedKind::Lifetime(ty::ReErased), UnpackedKind::Lifetime(ty::ReErased)) => { // no action needed @@ -312,11 +314,13 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { // ...also include the other query region constraints from the query. output_query_region_constraints.reserve(query_result.value.region_constraints.len()); for r_c in query_result.value.region_constraints.iter() { - output_query_region_constraints.push(r_c.map_bound(|ty::OutlivesPredicate(k1, r2)| { - let k1 = substitute_value(self.tcx, &result_subst, &k1); - let r2 = substitute_value(self.tcx, &result_subst, &r2); - ty::OutlivesPredicate(k1, r2) - })); + let &ty::OutlivesPredicate(k1, r2) = r_c.skip_binder(); // reconstructed below + let k1 = substitute_value(self.tcx, &result_subst, &k1); + let r2 = substitute_value(self.tcx, &result_subst, &r2); + if k1 != r2.into() { + output_query_region_constraints + .push(ty::Binder::bind(ty::OutlivesPredicate(k1, r2))); + } } let user_result: R = diff --git a/src/librustc/infer/outlives/bounds.rs b/src/librustc/infer/outlives/bounds.rs deleted file mode 100644 index 57abdd18d353c..0000000000000 --- a/src/librustc/infer/outlives/bounds.rs +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright 2012-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::InferCtxt; -use syntax::ast; -use syntax::codemap::Span; -use traits::{FulfillmentContext, TraitEngine, TraitEngineExt}; -use ty::{self, Ty, TypeFoldable}; -use ty::outlives::Component; -use ty::wf; - -/// Outlives bounds are relationships between generic parameters, -/// whether they both be regions (`'a: 'b`) or whether types are -/// involved (`T: 'a`). These relationships can be extracted from the -/// full set of predicates we understand or also from types (in which -/// case they are called implied bounds). They are fed to the -/// `OutlivesEnv` which in turn is supplied to the region checker and -/// other parts of the inference system. -#[derive(Debug)] -pub enum OutlivesBound<'tcx> { - RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>), - RegionSubParam(ty::Region<'tcx>, ty::ParamTy), - RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>), -} - -impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { - /// Implied bounds are region relationships that we deduce - /// automatically. The idea is that (e.g.) a caller must check that a - /// function's argument types are well-formed immediately before - /// calling that fn, and hence the *callee* can assume that its - /// argument types are well-formed. This may imply certain relationships - /// between generic parameters. For example: - /// - /// fn foo<'a,T>(x: &'a T) - /// - /// can only be called with a `'a` and `T` such that `&'a T` is WF. - /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. - /// - /// # Parameters - /// - /// - `param_env`, the where-clauses in scope - /// - `body_id`, the body-id to use when normalizing assoc types. - /// Note that this may cause outlives obligations to be injected - /// into the inference context with this body-id. - /// - `ty`, the type that we are supposed to assume is WF. - /// - `span`, a span to use when normalizing, hopefully not important, - /// might be useful if a `bug!` occurs. - pub fn implied_outlives_bounds( - &self, - param_env: ty::ParamEnv<'tcx>, - body_id: ast::NodeId, - ty: Ty<'tcx>, - span: Span, - ) -> Vec> { - let tcx = self.tcx; - - // Sometimes when we ask what it takes for T: WF, we get back that - // U: WF is required; in that case, we push U onto this stack and - // process it next. Currently (at least) these resulting - // predicates are always guaranteed to be a subset of the original - // type, so we need not fear non-termination. - let mut wf_types = vec![ty]; - - let mut implied_bounds = vec![]; - - let mut fulfill_cx = FulfillmentContext::new(); - - while let Some(ty) = wf_types.pop() { - // Compute the obligations for `ty` to be well-formed. If `ty` is - // an unresolved inference variable, just substituted an empty set - // -- because the return type here is going to be things we *add* - // to the environment, it's always ok for this set to be smaller - // than the ultimate set. (Note: normally there won't be - // unresolved inference variables here anyway, but there might be - // during typeck under some circumstances.) - let obligations = wf::obligations(self, param_env, body_id, ty, span).unwrap_or(vec![]); - - // NB: All of these predicates *ought* to be easily proven - // true. In fact, their correctness is (mostly) implied by - // other parts of the program. However, in #42552, we had - // an annoying scenario where: - // - // - Some `T::Foo` gets normalized, resulting in a - // variable `_1` and a `T: Trait` constraint - // (not sure why it couldn't immediately get - // solved). This result of `_1` got cached. - // - These obligations were dropped on the floor here, - // rather than being registered. - // - Then later we would get a request to normalize - // `T::Foo` which would result in `_1` being used from - // the cache, but hence without the `T: Trait` - // constraint. As a result, `_1` never gets resolved, - // and we get an ICE (in dropck). - // - // Therefore, we register any predicates involving - // inference variables. We restrict ourselves to those - // involving inference variables both for efficiency and - // to avoids duplicate errors that otherwise show up. - fulfill_cx.register_predicate_obligations( - self, - obligations - .iter() - .filter(|o| o.predicate.has_infer_types()) - .cloned(), - ); - - // From the full set of obligations, just filter down to the - // region relationships. - implied_bounds.extend(obligations.into_iter().flat_map(|obligation| { - assert!(!obligation.has_escaping_regions()); - match obligation.predicate { - ty::Predicate::Trait(..) | - ty::Predicate::Subtype(..) | - ty::Predicate::Projection(..) | - ty::Predicate::ClosureKind(..) | - ty::Predicate::ObjectSafe(..) | - ty::Predicate::ConstEvaluatable(..) => vec![], - - ty::Predicate::WellFormed(subty) => { - wf_types.push(subty); - vec![] - } - - ty::Predicate::RegionOutlives(ref data) => match data.no_late_bound_regions() { - None => vec![], - Some(ty::OutlivesPredicate(r_a, r_b)) => { - vec![OutlivesBound::RegionSubRegion(r_b, r_a)] - } - }, - - ty::Predicate::TypeOutlives(ref data) => match data.no_late_bound_regions() { - None => vec![], - Some(ty::OutlivesPredicate(ty_a, r_b)) => { - let ty_a = self.resolve_type_vars_if_possible(&ty_a); - let components = tcx.outlives_components(ty_a); - Self::implied_bounds_from_components(r_b, components) - } - }, - } - })); - } - - // Ensure that those obligations that we had to solve - // get solved *here*. - match fulfill_cx.select_all_or_error(self) { - Ok(()) => (), - Err(errors) => self.report_fulfillment_errors(&errors, None, false), - } - - implied_bounds - } - - /// When we have an implied bound that `T: 'a`, we can further break - /// this down to determine what relationships would have to hold for - /// `T: 'a` to hold. We get to assume that the caller has validated - /// those relationships. - fn implied_bounds_from_components( - sub_region: ty::Region<'tcx>, - sup_components: Vec>, - ) -> Vec> { - sup_components - .into_iter() - .flat_map(|component| { - match component { - Component::Region(r) => - vec![OutlivesBound::RegionSubRegion(sub_region, r)], - Component::Param(p) => - vec![OutlivesBound::RegionSubParam(sub_region, p)], - Component::Projection(p) => - vec![OutlivesBound::RegionSubProjection(sub_region, p)], - Component::EscapingProjection(_) => - // If the projection has escaping regions, don't - // try to infer any implied bounds even for its - // free components. This is conservative, because - // the caller will still have to prove that those - // free components outlive `sub_region`. But the - // idea is that the WAY that the caller proves - // that may change in the future and we want to - // give ourselves room to get smarter here. - vec![], - Component::UnresolvedInferenceVariable(..) => - vec![], - } - }) - .collect() - } -} - -pub fn explicit_outlives_bounds<'tcx>( - param_env: ty::ParamEnv<'tcx>, -) -> impl Iterator> + 'tcx { - debug!("explicit_outlives_bounds()"); - param_env - .caller_bounds - .into_iter() - .filter_map(move |predicate| match predicate { - ty::Predicate::Projection(..) | - ty::Predicate::Trait(..) | - ty::Predicate::Subtype(..) | - ty::Predicate::WellFormed(..) | - ty::Predicate::ObjectSafe(..) | - ty::Predicate::ClosureKind(..) | - ty::Predicate::TypeOutlives(..) | - ty::Predicate::ConstEvaluatable(..) => None, - ty::Predicate::RegionOutlives(ref data) => data.no_late_bound_regions().map( - |ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a), - ), - }) -} diff --git a/src/librustc/infer/outlives/env.rs b/src/librustc/infer/outlives/env.rs index d47507592f80d..7f59a6794efbd 100644 --- a/src/librustc/infer/outlives/env.rs +++ b/src/librustc/infer/outlives/env.rs @@ -10,7 +10,7 @@ use infer::{GenericKind, InferCtxt}; use infer::outlives::free_region_map::FreeRegionMap; -use infer::outlives::bounds::{self, OutlivesBound}; +use traits::query::outlives_bounds::{self, OutlivesBound}; use ty::{self, Ty}; use syntax::ast; @@ -50,7 +50,7 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> { region_bound_pairs: vec![], }; - env.add_outlives_bounds(None, bounds::explicit_outlives_bounds(param_env)); + env.add_outlives_bounds(None, outlives_bounds::explicit_outlives_bounds(param_env)); env } diff --git a/src/librustc/infer/outlives/mod.rs b/src/librustc/infer/outlives/mod.rs index 93079b046690c..bb3703b215732 100644 --- a/src/librustc/infer/outlives/mod.rs +++ b/src/librustc/infer/outlives/mod.rs @@ -12,5 +12,4 @@ pub mod env; pub mod free_region_map; -pub mod bounds; pub mod obligations; diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs index 54b67edb1360b..35f17aebc0443 100644 --- a/src/librustc/traits/query/mod.rs +++ b/src/librustc/traits/query/mod.rs @@ -23,6 +23,7 @@ pub mod dropck_outlives; pub mod evaluate_obligation; pub mod normalize; pub mod normalize_erasing_regions; +pub mod outlives_bounds; pub mod type_op; pub type CanonicalProjectionGoal<'tcx> = diff --git a/src/librustc/traits/query/outlives_bounds.rs b/src/librustc/traits/query/outlives_bounds.rs new file mode 100644 index 0000000000000..f79ce73ad928a --- /dev/null +++ b/src/librustc/traits/query/outlives_bounds.rs @@ -0,0 +1,171 @@ +// Copyright 2012-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::InferCtxt; +use syntax::ast; +use syntax::codemap::Span; +use rustc_data_structures::small_vec::SmallVec; +use traits::{FulfillmentContext, ObligationCause, TraitEngine, TraitEngineExt}; +use traits::query::NoSolution; +use ty::{self, Ty, TyCtxt}; + +use ich::StableHashingContext; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use std::mem; + +/// Outlives bounds are relationships between generic parameters, +/// whether they both be regions (`'a: 'b`) or whether types are +/// involved (`T: 'a`). These relationships can be extracted from the +/// full set of predicates we understand or also from types (in which +/// case they are called implied bounds). They are fed to the +/// `OutlivesEnv` which in turn is supplied to the region checker and +/// other parts of the inference system. +#[derive(Clone, Debug)] +pub enum OutlivesBound<'tcx> { + RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>), + RegionSubParam(ty::Region<'tcx>, ty::ParamTy), + RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>), +} + +EnumLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for self::OutlivesBound<'a> { + type Lifted = self::OutlivesBound<'tcx>; + (self::OutlivesBound::RegionSubRegion)(a, b), + (self::OutlivesBound::RegionSubParam)(a, b), + (self::OutlivesBound::RegionSubProjection)(a, b), + } +} + +EnumTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for self::OutlivesBound<'tcx> { + (self::OutlivesBound::RegionSubRegion)(a, b), + (self::OutlivesBound::RegionSubParam)(a, b), + (self::OutlivesBound::RegionSubProjection)(a, b), + } +} + +impl<'a, 'tcx> HashStable> for OutlivesBound<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + OutlivesBound::RegionSubRegion(ref a, ref b) => { + a.hash_stable(hcx, hasher); + b.hash_stable(hcx, hasher); + } + OutlivesBound::RegionSubParam(ref a, ref b) => { + a.hash_stable(hcx, hasher); + b.hash_stable(hcx, hasher); + } + OutlivesBound::RegionSubProjection(ref a, ref b) => { + a.hash_stable(hcx, hasher); + b.hash_stable(hcx, hasher); + } + } + } +} + +impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { + /// Implied bounds are region relationships that we deduce + /// automatically. The idea is that (e.g.) a caller must check that a + /// function's argument types are well-formed immediately before + /// calling that fn, and hence the *callee* can assume that its + /// argument types are well-formed. This may imply certain relationships + /// between generic parameters. For example: + /// + /// fn foo<'a,T>(x: &'a T) + /// + /// can only be called with a `'a` and `T` such that `&'a T` is WF. + /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. + /// + /// # Parameters + /// + /// - `param_env`, the where-clauses in scope + /// - `body_id`, the body-id to use when normalizing assoc types. + /// Note that this may cause outlives obligations to be injected + /// into the inference context with this body-id. + /// - `ty`, the type that we are supposed to assume is WF. + /// - `span`, a span to use when normalizing, hopefully not important, + /// might be useful if a `bug!` occurs. + pub fn implied_outlives_bounds( + &self, + param_env: ty::ParamEnv<'tcx>, + body_id: ast::NodeId, + ty: Ty<'tcx>, + span: Span, + ) -> Vec> { + debug!("implied_outlives_bounds(ty = {:?})", ty); + + let mut orig_values = SmallVec::new(); + let key = self.canonicalize_query(¶m_env.and(ty), &mut orig_values); + let result = match self.tcx.global_tcx().implied_outlives_bounds(key) { + Ok(r) => r, + Err(NoSolution) => { + self.tcx.sess.delay_span_bug( + span, + "implied_outlives_bounds failed to solve all obligations" + ); + return vec![]; + } + }; + assert!(result.value.is_proven()); + + let result = self.instantiate_query_result_and_region_obligations( + &ObligationCause::misc(span, body_id), param_env, &orig_values, &result); + debug!("implied_outlives_bounds for {:?}: {:#?}", ty, result); + let result = match result { + Ok(v) => v, + Err(_) => { + self.tcx.sess.delay_span_bug( + span, + "implied_outlives_bounds failed to instantiate" + ); + return vec![]; + } + }; + + // Instantiation may have produced new inference variables and constraints on those + // variables. Process these constraints. + let mut fulfill_cx = FulfillmentContext::new(); + fulfill_cx.register_predicate_obligations(self, result.obligations); + if let Err(_) = fulfill_cx.select_all_or_error(self) { + self.tcx.sess.delay_span_bug( + span, + "implied_outlives_bounds failed to solve obligations from instantiation" + ); + } + + result.value + } +} + +pub fn explicit_outlives_bounds<'tcx>( + param_env: ty::ParamEnv<'tcx>, +) -> impl Iterator> + 'tcx { + debug!("explicit_outlives_bounds()"); + param_env + .caller_bounds + .into_iter() + .filter_map(move |predicate| match predicate { + ty::Predicate::Projection(..) | + ty::Predicate::Trait(..) | + ty::Predicate::Subtype(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | + ty::Predicate::ClosureKind(..) | + ty::Predicate::TypeOutlives(..) | + ty::Predicate::ConstEvaluatable(..) => None, + ty::Predicate::RegionOutlives(ref data) => data.no_late_bound_regions().map( + |ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a), + ), + }) +} diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs index bd6217e28c755..8db33032625b2 100644 --- a/src/librustc/ty/query/config.rs +++ b/src/librustc/ty/query/config.rs @@ -87,6 +87,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::normalize_projection_ty<'tcx> { } } +impl<'tcx> QueryDescription<'tcx> for queries::implied_outlives_bounds<'tcx> { + fn describe(_tcx: TyCtxt, goal: CanonicalTyGoal<'tcx>) -> String { + format!("computing implied outlives bounds for `{:?}`", goal) + } +} + impl<'tcx> QueryDescription<'tcx> for queries::dropck_outlives<'tcx> { fn describe(_tcx: TyCtxt, goal: CanonicalTyGoal<'tcx>) -> String { format!("computing dropck types for `{:?}`", goal) diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index 2fb289d023606..1b1020c9bd86d 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -38,6 +38,7 @@ use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal, NoSolution}; use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult}; use traits::query::normalize::NormalizationResult; +use traits::query::outlives_bounds::OutlivesBound; use traits::specialization_graph; use traits::Clauses; use ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; @@ -551,6 +552,13 @@ define_queries! { <'tcx> ParamEnvAnd<'tcx, Ty<'tcx>> ) -> Ty<'tcx>, + [] fn implied_outlives_bounds: ImpliedOutlivesBounds( + CanonicalTyGoal<'tcx> + ) -> Result< + Lrc>>>>, + NoSolution, + >, + /// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead. [] fn dropck_outlives: DropckOutlives( CanonicalTyGoal<'tcx> diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 78e1a6425465b..7a9827b50a176 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -1036,6 +1036,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::ConstValueToAllocation | DepKind::NormalizeProjectionTy | DepKind::NormalizeTyAfterErasingRegions | + DepKind::ImpliedOutlivesBounds | DepKind::DropckOutlives | DepKind::EvaluateObligation | DepKind::TypeOpEq | diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 874dabaf1c9e7..ad29f808285b1 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -56,6 +56,7 @@ CloneTypeFoldableAndLiftImpls! { ::ty::BoundRegion, ::ty::ClosureKind, ::ty::IntVarValue, + ::ty::ParamTy, ::syntax_pos::Span, } diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs index 8590e3d0765f0..e7930b2148156 100644 --- a/src/librustc_mir/borrow_check/nll/universal_regions.rs +++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs @@ -25,10 +25,10 @@ use either::Either; use rustc::hir::def_id::DefId; use rustc::hir::{self, BodyOwnerKind, HirId}; -use rustc::infer::outlives::bounds::{self, OutlivesBound}; use rustc::infer::outlives::free_region_map::FreeRegionRelations; use rustc::infer::region_constraints::GenericKind; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; +use rustc::traits::query::outlives_bounds::{self, OutlivesBound}; use rustc::ty::fold::TypeFoldable; use rustc::ty::subst::Substs; use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid, Ty, TyCtxt}; @@ -494,7 +494,10 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> { let num_universals = self.infcx.num_region_vars(); // Insert the facts we know from the predicates. Why? Why not. - self.add_outlives_bounds(&indices, bounds::explicit_outlives_bounds(param_env)); + self.add_outlives_bounds( + &indices, + outlives_bounds::explicit_outlives_bounds(param_env), + ); // Add the implied bounds from inputs and outputs. for ty in inputs_and_output { diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs new file mode 100644 index 0000000000000..b6560fae110d5 --- /dev/null +++ b/src/librustc_traits/implied_outlives_bounds.rs @@ -0,0 +1,185 @@ +// Copyright 2018 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. + +//! Provider for the `implied_outlives_bounds` query. +//! Do not call this query directory. See [`rustc::traits::query::implied_outlives_bounds`]. + +use rustc::infer::InferCtxt; +use rustc::infer::canonical::{self, Canonical}; +use rustc::traits::{TraitEngine, TraitEngineExt}; +use rustc::traits::query::outlives_bounds::OutlivesBound; +use rustc::traits::query::{CanonicalTyGoal, Fallible, NoSolution}; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::outlives::Component; +use rustc::ty::query::Providers; +use rustc::ty::wf; +use syntax::ast::DUMMY_NODE_ID; +use syntax::codemap::DUMMY_SP; +use rustc::traits::FulfillmentContext; + +use rustc_data_structures::sync::Lrc; + +crate fn provide(p: &mut Providers) { + *p = Providers { + implied_outlives_bounds, + ..*p + }; +} + +fn implied_outlives_bounds<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + goal: CanonicalTyGoal<'tcx>, +) -> Result< + Lrc>>>>, + NoSolution, +> { + tcx.infer_ctxt() + .enter_canonical_trait_query(&goal, |infcx, _fulfill_cx, key| { + let (param_env, ty) = key.into_parts(); + compute_implied_outlives_bounds(&infcx, param_env, ty) + }) +} + +fn compute_implied_outlives_bounds<'tcx>( + infcx: &InferCtxt<'_, '_, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx> +) -> Fallible>> { + let tcx = infcx.tcx; + + // Sometimes when we ask what it takes for T: WF, we get back that + // U: WF is required; in that case, we push U onto this stack and + // process it next. Currently (at least) these resulting + // predicates are always guaranteed to be a subset of the original + // type, so we need not fear non-termination. + let mut wf_types = vec![ty]; + + let mut implied_bounds = vec![]; + + let mut fulfill_cx = FulfillmentContext::new(); + + while let Some(ty) = wf_types.pop() { + // Compute the obligations for `ty` to be well-formed. If `ty` is + // an unresolved inference variable, just substituted an empty set + // -- because the return type here is going to be things we *add* + // to the environment, it's always ok for this set to be smaller + // than the ultimate set. (Note: normally there won't be + // unresolved inference variables here anyway, but there might be + // during typeck under some circumstances.) + let obligations = + wf::obligations(infcx, param_env, DUMMY_NODE_ID, ty, DUMMY_SP).unwrap_or(vec![]); + + // NB: All of these predicates *ought* to be easily proven + // true. In fact, their correctness is (mostly) implied by + // other parts of the program. However, in #42552, we had + // an annoying scenario where: + // + // - Some `T::Foo` gets normalized, resulting in a + // variable `_1` and a `T: Trait` constraint + // (not sure why it couldn't immediately get + // solved). This result of `_1` got cached. + // - These obligations were dropped on the floor here, + // rather than being registered. + // - Then later we would get a request to normalize + // `T::Foo` which would result in `_1` being used from + // the cache, but hence without the `T: Trait` + // constraint. As a result, `_1` never gets resolved, + // and we get an ICE (in dropck). + // + // Therefore, we register any predicates involving + // inference variables. We restrict ourselves to those + // involving inference variables both for efficiency and + // to avoids duplicate errors that otherwise show up. + fulfill_cx.register_predicate_obligations( + infcx, + obligations + .iter() + .filter(|o| o.predicate.has_infer_types()) + .cloned(), + ); + + // From the full set of obligations, just filter down to the + // region relationships. + implied_bounds.extend(obligations.into_iter().flat_map(|obligation| { + assert!(!obligation.has_escaping_regions()); + match obligation.predicate { + ty::Predicate::Trait(..) | + ty::Predicate::Subtype(..) | + ty::Predicate::Projection(..) | + ty::Predicate::ClosureKind(..) | + ty::Predicate::ObjectSafe(..) | + ty::Predicate::ConstEvaluatable(..) => vec![], + + ty::Predicate::WellFormed(subty) => { + wf_types.push(subty); + vec![] + } + + ty::Predicate::RegionOutlives(ref data) => match data.no_late_bound_regions() { + None => vec![], + Some(ty::OutlivesPredicate(r_a, r_b)) => { + vec![OutlivesBound::RegionSubRegion(r_b, r_a)] + } + }, + + ty::Predicate::TypeOutlives(ref data) => match data.no_late_bound_regions() { + None => vec![], + Some(ty::OutlivesPredicate(ty_a, r_b)) => { + let ty_a = infcx.resolve_type_vars_if_possible(&ty_a); + let components = tcx.outlives_components(ty_a); + implied_bounds_from_components(r_b, components) + } + }, + } + })); + } + + // Ensure that those obligations that we had to solve + // get solved *here*. + match fulfill_cx.select_all_or_error(infcx) { + Ok(()) => Ok(implied_bounds), + Err(_) => Err(NoSolution), + } +} + +/// When we have an implied bound that `T: 'a`, we can further break +/// this down to determine what relationships would have to hold for +/// `T: 'a` to hold. We get to assume that the caller has validated +/// those relationships. +fn implied_bounds_from_components( + sub_region: ty::Region<'tcx>, + sup_components: Vec>, +) -> Vec> { + sup_components + .into_iter() + .flat_map(|component| { + match component { + Component::Region(r) => + vec![OutlivesBound::RegionSubRegion(sub_region, r)], + Component::Param(p) => + vec![OutlivesBound::RegionSubParam(sub_region, p)], + Component::Projection(p) => + vec![OutlivesBound::RegionSubProjection(sub_region, p)], + Component::EscapingProjection(_) => + // If the projection has escaping regions, don't + // try to infer any implied bounds even for its + // free components. This is conservative, because + // the caller will still have to prove that those + // free components outlive `sub_region`. But the + // idea is that the WAY that the caller proves + // that may change in the future and we want to + // give ourselves room to get smarter here. + vec![], + Component::UnresolvedInferenceVariable(..) => + vec![], + } + }) + .collect() +} diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs index cd55b5ddc5bf1..2a4cacb5623ec 100644 --- a/src/librustc_traits/lib.rs +++ b/src/librustc_traits/lib.rs @@ -33,6 +33,7 @@ extern crate syntax_pos; mod chalk_context; mod dropck_outlives; mod evaluate_obligation; +mod implied_outlives_bounds; mod normalize_projection_ty; mod normalize_erasing_regions; pub mod lowering; @@ -43,6 +44,7 @@ use rustc::ty::query::Providers; pub fn provide(p: &mut Providers) { dropck_outlives::provide(p); evaluate_obligation::provide(p); + implied_outlives_bounds::provide(p); lowering::provide(p); normalize_projection_ty::provide(p); normalize_erasing_regions::provide(p); diff --git a/src/test/ui/issue-20831-debruijn.rs b/src/test/ui/issue-20831-debruijn.rs index 3f00f561ae96f..6ad97d072df86 100644 --- a/src/test/ui/issue-20831-debruijn.rs +++ b/src/test/ui/issue-20831-debruijn.rs @@ -38,6 +38,8 @@ impl<'a> Publisher<'a> for MyStruct<'a> { fn subscribe(&mut self, t : Box::Output> + 'a>) { // Not obvious, but there is an implicit lifetime here -------^ //~^^ ERROR cannot infer + //~| ERROR mismatched types + //~| ERROR mismatched types // // The fact that `Publisher` is using an implicit lifetime is // what was causing the debruijn accounting to be off, so diff --git a/src/test/ui/issue-20831-debruijn.stderr b/src/test/ui/issue-20831-debruijn.stderr index fc9a0fdbe5438..556d8b402c457 100644 --- a/src/test/ui/issue-20831-debruijn.stderr +++ b/src/test/ui/issue-20831-debruijn.stderr @@ -1,10 +1,72 @@ +error[E0308]: mismatched types + --> $DIR/issue-20831-debruijn.rs:38:5 + | +LL | / fn subscribe(&mut self, t : Box::Output> + 'a>) { +LL | | // Not obvious, but there is an implicit lifetime here -------^ +LL | | //~^^ ERROR cannot infer +LL | | //~| ERROR mismatched types +... | +LL | | self.sub = t; +LL | | } + | |_____^ lifetime mismatch + | + = note: expected type `'a` + found type `` +note: the anonymous lifetime #2 defined on the method body at 38:5... + --> $DIR/issue-20831-debruijn.rs:38:5 + | +LL | / fn subscribe(&mut self, t : Box::Output> + 'a>) { +LL | | // Not obvious, but there is an implicit lifetime here -------^ +LL | | //~^^ ERROR cannot infer +LL | | //~| ERROR mismatched types +... | +LL | | self.sub = t; +LL | | } + | |_____^ +note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 36:6 + --> $DIR/issue-20831-debruijn.rs:36:6 + | +LL | impl<'a> Publisher<'a> for MyStruct<'a> { + | ^^ + +error[E0308]: mismatched types + --> $DIR/issue-20831-debruijn.rs:38:5 + | +LL | / fn subscribe(&mut self, t : Box::Output> + 'a>) { +LL | | // Not obvious, but there is an implicit lifetime here -------^ +LL | | //~^^ ERROR cannot infer +LL | | //~| ERROR mismatched types +... | +LL | | self.sub = t; +LL | | } + | |_____^ lifetime mismatch + | + = note: expected type `'a` + found type `` +note: the lifetime 'a as defined on the impl at 36:6... + --> $DIR/issue-20831-debruijn.rs:36:6 + | +LL | impl<'a> Publisher<'a> for MyStruct<'a> { + | ^^ +note: ...does not necessarily outlive the anonymous lifetime #2 defined on the method body at 38:5 + --> $DIR/issue-20831-debruijn.rs:38:5 + | +LL | / fn subscribe(&mut self, t : Box::Output> + 'a>) { +LL | | // Not obvious, but there is an implicit lifetime here -------^ +LL | | //~^^ ERROR cannot infer +LL | | //~| ERROR mismatched types +... | +LL | | self.sub = t; +LL | | } + | |_____^ + error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements --> $DIR/issue-20831-debruijn.rs:38:5 | LL | / fn subscribe(&mut self, t : Box::Output> + 'a>) { LL | | // Not obvious, but there is an implicit lifetime here -------^ LL | | //~^^ ERROR cannot infer -LL | | // +LL | | //~| ERROR mismatched types ... | LL | | self.sub = t; LL | | } @@ -16,7 +78,7 @@ note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on th LL | / fn subscribe(&mut self, t : Box::Output> + 'a>) { LL | | // Not obvious, but there is an implicit lifetime here -------^ LL | | //~^^ ERROR cannot infer -LL | | // +LL | | //~| ERROR mismatched types ... | LL | | self.sub = t; LL | | } @@ -30,6 +92,7 @@ LL | impl<'a> Publisher<'a> for MyStruct<'a> { expected Publisher<'_> found Publisher<'_> -error: aborting due to previous error +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0495`. +Some errors occurred: E0308, E0495. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/nll/issue-52078.rs b/src/test/ui/nll/issue-52078.rs new file mode 100644 index 0000000000000..1fd00db536cf6 --- /dev/null +++ b/src/test/ui/nll/issue-52078.rs @@ -0,0 +1,37 @@ +// Copyright 2017 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. + +#![feature(nll)] +#![allow(unused_variables)] + +// Regression test for #52078: we were failing to infer a relationship +// between `'a` and `'b` below due to inference variables introduced +// during the normalization process. +// +// compile-pass + +struct Drain<'a, T: 'a> { + _marker: ::std::marker::PhantomData<&'a T>, +} + +trait Join { + type Value; + fn get(value: &mut Self::Value); +} + +impl<'a, T> Join for Drain<'a, T> { + type Value = &'a mut Option; + + fn get<'b>(value: &'b mut Self::Value) { + } +} + +fn main() { +}