mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
make resolve_regions_and_report_errors
take an OutlivesEnv
This revealed some shortcomings, one of which is fixed. Fixes #45937.
This commit is contained in:
parent
abd7d88139
commit
5562663a6c
@ -44,7 +44,7 @@ use self::higher_ranked::HrMatchResult;
|
||||
use self::region_constraints::{RegionConstraintCollector, RegionSnapshot};
|
||||
use self::region_constraints::{GenericKind, VerifyBound, RegionConstraintData, VarOrigins};
|
||||
use self::lexical_region_resolve::LexicalRegionResolutions;
|
||||
use self::outlives::free_region_map::FreeRegionMap;
|
||||
use self::outlives::env::OutlivesEnvironment;
|
||||
use self::type_variable::TypeVariableOrigin;
|
||||
use self::unify_key::ToType;
|
||||
|
||||
@ -66,8 +66,6 @@ mod sub;
|
||||
pub mod type_variable;
|
||||
pub mod unify_key;
|
||||
|
||||
pub use self::outlives::env::OutlivesEnvironment;
|
||||
|
||||
#[must_use]
|
||||
pub struct InferOk<'tcx, T> {
|
||||
pub value: T,
|
||||
@ -1158,7 +1156,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
pub fn resolve_regions_and_report_errors(&self,
|
||||
region_context: DefId,
|
||||
region_map: ®ion::ScopeTree,
|
||||
free_regions: &FreeRegionMap<'tcx>) {
|
||||
outlives_env: &OutlivesEnvironment<'tcx>) {
|
||||
assert!(self.is_tainted_by_errors() || self.region_obligations.borrow().is_empty(),
|
||||
"region_obligations not empty: {:#?}",
|
||||
self.region_obligations.borrow());
|
||||
@ -1166,7 +1164,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
let region_rels = &RegionRelations::new(self.tcx,
|
||||
region_context,
|
||||
region_map,
|
||||
free_regions);
|
||||
outlives_env.free_region_map());
|
||||
let (var_origins, data) = self.region_constraints.borrow_mut()
|
||||
.take()
|
||||
.expect("regions already resolved")
|
||||
|
@ -44,14 +44,15 @@ pub struct OutlivesEnvironment<'tcx> {
|
||||
|
||||
impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
|
||||
pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self {
|
||||
let mut free_region_map = FreeRegionMap::new();
|
||||
free_region_map.relate_free_regions_from_predicates(¶m_env.caller_bounds);
|
||||
|
||||
OutlivesEnvironment {
|
||||
let mut env = OutlivesEnvironment {
|
||||
param_env,
|
||||
free_region_map,
|
||||
free_region_map: FreeRegionMap::new(),
|
||||
region_bound_pairs: vec![],
|
||||
}
|
||||
};
|
||||
|
||||
env.init_free_regions_from_predicates();
|
||||
|
||||
env
|
||||
}
|
||||
|
||||
/// Borrows current value of the `free_region_map`.
|
||||
@ -183,4 +184,27 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init_free_regions_from_predicates(&mut self) {
|
||||
debug!("init_free_regions_from_predicates()");
|
||||
for predicate in self.param_env.caller_bounds {
|
||||
debug!("init_free_regions_from_predicates: predicate={:?}", predicate);
|
||||
match *predicate {
|
||||
ty::Predicate::Projection(..) |
|
||||
ty::Predicate::Trait(..) |
|
||||
ty::Predicate::Equate(..) |
|
||||
ty::Predicate::Subtype(..) |
|
||||
ty::Predicate::WellFormed(..) |
|
||||
ty::Predicate::ObjectSafe(..) |
|
||||
ty::Predicate::ClosureKind(..) |
|
||||
ty::Predicate::TypeOutlives(..) |
|
||||
ty::Predicate::ConstEvaluatable(..) => {
|
||||
// No region bounds here
|
||||
}
|
||||
ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
|
||||
self.free_region_map.relate_regions(r_b, r_a);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,31 +29,8 @@ impl<'tcx> FreeRegionMap<'tcx> {
|
||||
self.relation.is_empty()
|
||||
}
|
||||
|
||||
pub fn relate_free_regions_from_predicates(&mut self,
|
||||
predicates: &[ty::Predicate<'tcx>]) {
|
||||
debug!("relate_free_regions_from_predicates(predicates={:?})", predicates);
|
||||
for predicate in predicates {
|
||||
match *predicate {
|
||||
ty::Predicate::Projection(..) |
|
||||
ty::Predicate::Trait(..) |
|
||||
ty::Predicate::Equate(..) |
|
||||
ty::Predicate::Subtype(..) |
|
||||
ty::Predicate::WellFormed(..) |
|
||||
ty::Predicate::ObjectSafe(..) |
|
||||
ty::Predicate::ClosureKind(..) |
|
||||
ty::Predicate::TypeOutlives(..) |
|
||||
ty::Predicate::ConstEvaluatable(..) => {
|
||||
// No region bounds here
|
||||
}
|
||||
ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
|
||||
self.relate_regions(r_b, r_a);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`.
|
||||
/// (with the exception that `'static: 'x` is not notable)
|
||||
// Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`.
|
||||
// (with the exception that `'static: 'x` is not notable)
|
||||
pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
|
||||
debug!("relate_regions(sub={:?}, sup={:?})", sub, sup);
|
||||
if is_free_or_static(sub) && is_free(sup) {
|
||||
|
@ -17,7 +17,7 @@ pub use self::ObligationCauseCode::*;
|
||||
|
||||
use hir;
|
||||
use hir::def_id::DefId;
|
||||
use infer::outlives::free_region_map::FreeRegionMap;
|
||||
use infer::outlives::env::OutlivesEnvironment;
|
||||
use middle::const_val::ConstEvalErr;
|
||||
use middle::region;
|
||||
use ty::subst::Substs;
|
||||
@ -554,9 +554,13 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
predicates);
|
||||
|
||||
let region_scope_tree = region::ScopeTree::default();
|
||||
let free_regions = FreeRegionMap::new();
|
||||
|
||||
infcx.resolve_regions_and_report_errors(region_context, ®ion_scope_tree, &free_regions);
|
||||
// We can use the `elaborated_env` here; the region code only
|
||||
// cares about declarations like `'a: 'b`.
|
||||
let outlives_env = OutlivesEnvironment::new(elaborated_env);
|
||||
|
||||
infcx.resolve_regions_and_report_errors(region_context, ®ion_scope_tree, &outlives_env);
|
||||
|
||||
let predicates = match infcx.fully_resolve(&predicates) {
|
||||
Ok(predicates) => predicates,
|
||||
Err(fixup_err) => {
|
||||
|
@ -17,7 +17,6 @@ use driver;
|
||||
use rustc_lint;
|
||||
use rustc_resolve::MakeGlobMap;
|
||||
use rustc_trans;
|
||||
use rustc::middle::free_region::FreeRegionMap;
|
||||
use rustc::middle::region;
|
||||
use rustc::middle::resolve_lifetime;
|
||||
use rustc::ty::subst::{Kind, Subst};
|
||||
@ -25,6 +24,7 @@ use rustc::traits::{ObligationCause, Reveal};
|
||||
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc::ty::maps::OnDiskCache;
|
||||
use rustc::infer::{self, InferOk, InferResult};
|
||||
use rustc::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc::infer::type_variable::TypeVariableOrigin;
|
||||
use rustc_metadata::cstore::CStore;
|
||||
use rustc::hir::map as hir_map;
|
||||
@ -162,14 +162,15 @@ fn test_env<F>(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);
|
||||
body(Env {
|
||||
infcx: &infcx,
|
||||
region_scope_tree: &mut region_scope_tree,
|
||||
param_env: ty::ParamEnv::empty(Reveal::UserFacing),
|
||||
param_env: param_env,
|
||||
});
|
||||
let free_regions = FreeRegionMap::new();
|
||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||
let def_id = tcx.hir.local_def_id(ast::CRATE_NODE_ID);
|
||||
infcx.resolve_regions_and_report_errors(def_id, ®ion_scope_tree, &free_regions);
|
||||
infcx.resolve_regions_and_report_errors(def_id, ®ion_scope_tree, &outlives_env);
|
||||
assert_eq!(tcx.sess.err_count(), expected_err_count);
|
||||
});
|
||||
});
|
||||
|
@ -12,11 +12,11 @@ use check::regionck::RegionCtxt;
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use rustc::infer::{self, InferOk};
|
||||
use rustc::infer::outlives::free_region_map::FreeRegionMap;
|
||||
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, ObligationCause};
|
||||
use rustc::traits::{self, Reveal, ObligationCause};
|
||||
use util::common::ErrorReported;
|
||||
use util::nodemap::FxHashSet;
|
||||
|
||||
@ -115,8 +115,18 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
|
||||
}
|
||||
|
||||
let region_scope_tree = region::ScopeTree::default();
|
||||
let free_regions = FreeRegionMap::new();
|
||||
infcx.resolve_regions_and_report_errors(drop_impl_did, ®ion_scope_tree, &free_regions);
|
||||
|
||||
// NB. It seems a bit... suspicious to use an empty param-env
|
||||
// here. The correct thing, I imagine, would be
|
||||
// `OutlivesEnvironment::new(impl_param_env)`, which would
|
||||
// allow region solving to take any `a: 'b` relations on the
|
||||
// impl into account. But I could not create a test case where
|
||||
// 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));
|
||||
|
||||
infcx.resolve_regions_and_report_errors(drop_impl_did, ®ion_scope_tree, &outlives_env);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
@ -90,7 +90,8 @@ use middle::region;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::infer::{self, OutlivesEnvironment};
|
||||
use rustc::infer;
|
||||
use rustc::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc::ty::adjustment;
|
||||
use rustc::ty::outlives::Component;
|
||||
|
||||
@ -553,7 +554,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||
fn resolve_regions_and_report_errors(&self) {
|
||||
self.fcx.resolve_regions_and_report_errors(self.subject_def_id,
|
||||
&self.region_scope_tree,
|
||||
self.outlives_environment.free_region_map());
|
||||
&self.outlives_environment);
|
||||
}
|
||||
|
||||
fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat) {
|
||||
|
@ -11,7 +11,7 @@
|
||||
//! Check properties that are required by built-in traits and set
|
||||
//! up data structures required by type-checking/translation.
|
||||
|
||||
use rustc::infer::outlives::free_region_map::FreeRegionMap;
|
||||
use rustc::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc::middle::region;
|
||||
use rustc::middle::lang_items::UnsizeTraitLangItem;
|
||||
|
||||
@ -391,9 +391,12 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
|
||||
// Finally, resolve all regions.
|
||||
let region_scope_tree = region::ScopeTree::default();
|
||||
let mut free_regions = FreeRegionMap::new();
|
||||
free_regions.relate_free_regions_from_predicates(¶m_env.caller_bounds);
|
||||
infcx.resolve_regions_and_report_errors(impl_did, ®ion_scope_tree, &free_regions);
|
||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||
infcx.resolve_regions_and_report_errors(
|
||||
impl_did,
|
||||
®ion_scope_tree,
|
||||
&outlives_env,
|
||||
);
|
||||
|
||||
CoerceUnsizedInfo {
|
||||
custom_kind: kind
|
||||
|
@ -0,0 +1,37 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that we are able to normalize in the list of where-clauses,
|
||||
// even if `'a: 'b` is required.
|
||||
|
||||
trait Project<'a, 'b> {
|
||||
type Item;
|
||||
}
|
||||
|
||||
impl<'a, 'b> Project<'a, 'b> for ()
|
||||
where 'a: 'b
|
||||
{
|
||||
type Item = ();
|
||||
}
|
||||
|
||||
// No error here, we have 'a: 'b. We used to report an error here
|
||||
// though, see https://github.com/rust-lang/rust/issues/45937.
|
||||
fn foo<'a: 'b, 'b>()
|
||||
where <() as Project<'a, 'b>>::Item : Eq
|
||||
{
|
||||
}
|
||||
|
||||
// Here we get an error: we need `'a: 'b`.
|
||||
fn bar<'a, 'b>() //~ ERROR cannot infer
|
||||
where <() as Project<'a, 'b>>::Item : Eq
|
||||
{
|
||||
}
|
||||
|
||||
fn main() { }
|
Loading…
Reference in New Issue
Block a user