Skip to content

Commit 5562663

Browse files
committed
make resolve_regions_and_report_errors take an OutlivesEnv
This revealed some shortcomings, one of which is fixed. Fixes #45937.
1 parent abd7d88 commit 5562663

File tree

9 files changed

+108
-53
lines changed

9 files changed

+108
-53
lines changed

src/librustc/infer/mod.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ use self::higher_ranked::HrMatchResult;
4444
use self::region_constraints::{RegionConstraintCollector, RegionSnapshot};
4545
use self::region_constraints::{GenericKind, VerifyBound, RegionConstraintData, VarOrigins};
4646
use self::lexical_region_resolve::LexicalRegionResolutions;
47-
use self::outlives::free_region_map::FreeRegionMap;
47+
use self::outlives::env::OutlivesEnvironment;
4848
use self::type_variable::TypeVariableOrigin;
4949
use self::unify_key::ToType;
5050

@@ -66,8 +66,6 @@ mod sub;
6666
pub mod type_variable;
6767
pub mod unify_key;
6868

69-
pub use self::outlives::env::OutlivesEnvironment;
70-
7169
#[must_use]
7270
pub struct InferOk<'tcx, T> {
7371
pub value: T,
@@ -1158,15 +1156,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
11581156
pub fn resolve_regions_and_report_errors(&self,
11591157
region_context: DefId,
11601158
region_map: &region::ScopeTree,
1161-
free_regions: &FreeRegionMap<'tcx>) {
1159+
outlives_env: &OutlivesEnvironment<'tcx>) {
11621160
assert!(self.is_tainted_by_errors() || self.region_obligations.borrow().is_empty(),
11631161
"region_obligations not empty: {:#?}",
11641162
self.region_obligations.borrow());
11651163

11661164
let region_rels = &RegionRelations::new(self.tcx,
11671165
region_context,
11681166
region_map,
1169-
free_regions);
1167+
outlives_env.free_region_map());
11701168
let (var_origins, data) = self.region_constraints.borrow_mut()
11711169
.take()
11721170
.expect("regions already resolved")

src/librustc/infer/outlives/env.rs

+30-6
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,15 @@ pub struct OutlivesEnvironment<'tcx> {
4444

4545
impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
4646
pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self {
47-
let mut free_region_map = FreeRegionMap::new();
48-
free_region_map.relate_free_regions_from_predicates(&param_env.caller_bounds);
49-
50-
OutlivesEnvironment {
47+
let mut env = OutlivesEnvironment {
5148
param_env,
52-
free_region_map,
49+
free_region_map: FreeRegionMap::new(),
5350
region_bound_pairs: vec![],
54-
}
51+
};
52+
53+
env.init_free_regions_from_predicates();
54+
55+
env
5556
}
5657

5758
/// Borrows current value of the `free_region_map`.
@@ -183,4 +184,27 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
183184
}
184185
}
185186
}
187+
188+
fn init_free_regions_from_predicates(&mut self) {
189+
debug!("init_free_regions_from_predicates()");
190+
for predicate in self.param_env.caller_bounds {
191+
debug!("init_free_regions_from_predicates: predicate={:?}", predicate);
192+
match *predicate {
193+
ty::Predicate::Projection(..) |
194+
ty::Predicate::Trait(..) |
195+
ty::Predicate::Equate(..) |
196+
ty::Predicate::Subtype(..) |
197+
ty::Predicate::WellFormed(..) |
198+
ty::Predicate::ObjectSafe(..) |
199+
ty::Predicate::ClosureKind(..) |
200+
ty::Predicate::TypeOutlives(..) |
201+
ty::Predicate::ConstEvaluatable(..) => {
202+
// No region bounds here
203+
}
204+
ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
205+
self.free_region_map.relate_regions(r_b, r_a);
206+
}
207+
}
208+
}
209+
}
186210
}

src/librustc/infer/outlives/free_region_map.rs

+2-25
Original file line numberDiff line numberDiff line change
@@ -29,31 +29,8 @@ impl<'tcx> FreeRegionMap<'tcx> {
2929
self.relation.is_empty()
3030
}
3131

32-
pub fn relate_free_regions_from_predicates(&mut self,
33-
predicates: &[ty::Predicate<'tcx>]) {
34-
debug!("relate_free_regions_from_predicates(predicates={:?})", predicates);
35-
for predicate in predicates {
36-
match *predicate {
37-
ty::Predicate::Projection(..) |
38-
ty::Predicate::Trait(..) |
39-
ty::Predicate::Equate(..) |
40-
ty::Predicate::Subtype(..) |
41-
ty::Predicate::WellFormed(..) |
42-
ty::Predicate::ObjectSafe(..) |
43-
ty::Predicate::ClosureKind(..) |
44-
ty::Predicate::TypeOutlives(..) |
45-
ty::Predicate::ConstEvaluatable(..) => {
46-
// No region bounds here
47-
}
48-
ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
49-
self.relate_regions(r_b, r_a);
50-
}
51-
}
52-
}
53-
}
54-
55-
/// Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`.
56-
/// (with the exception that `'static: 'x` is not notable)
32+
// Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`.
33+
// (with the exception that `'static: 'x` is not notable)
5734
pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
5835
debug!("relate_regions(sub={:?}, sup={:?})", sub, sup);
5936
if is_free_or_static(sub) && is_free(sup) {

src/librustc/traits/mod.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub use self::ObligationCauseCode::*;
1717

1818
use hir;
1919
use hir::def_id::DefId;
20-
use infer::outlives::free_region_map::FreeRegionMap;
20+
use infer::outlives::env::OutlivesEnvironment;
2121
use middle::const_val::ConstEvalErr;
2222
use middle::region;
2323
use ty::subst::Substs;
@@ -554,9 +554,13 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
554554
predicates);
555555

556556
let region_scope_tree = region::ScopeTree::default();
557-
let free_regions = FreeRegionMap::new();
558557

559-
infcx.resolve_regions_and_report_errors(region_context, &region_scope_tree, &free_regions);
558+
// We can use the `elaborated_env` here; the region code only
559+
// cares about declarations like `'a: 'b`.
560+
let outlives_env = OutlivesEnvironment::new(elaborated_env);
561+
562+
infcx.resolve_regions_and_report_errors(region_context, &region_scope_tree, &outlives_env);
563+
560564
let predicates = match infcx.fully_resolve(&predicates) {
561565
Ok(predicates) => predicates,
562566
Err(fixup_err) => {

src/librustc_driver/test.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ use driver;
1717
use rustc_lint;
1818
use rustc_resolve::MakeGlobMap;
1919
use rustc_trans;
20-
use rustc::middle::free_region::FreeRegionMap;
2120
use rustc::middle::region;
2221
use rustc::middle::resolve_lifetime;
2322
use rustc::ty::subst::{Kind, Subst};
2423
use rustc::traits::{ObligationCause, Reveal};
2524
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
2625
use rustc::ty::maps::OnDiskCache;
2726
use rustc::infer::{self, InferOk, InferResult};
27+
use rustc::infer::outlives::env::OutlivesEnvironment;
2828
use rustc::infer::type_variable::TypeVariableOrigin;
2929
use rustc_metadata::cstore::CStore;
3030
use rustc::hir::map as hir_map;
@@ -162,14 +162,15 @@ fn test_env<F>(source_string: &str,
162162
|tcx| {
163163
tcx.infer_ctxt().enter(|infcx| {
164164
let mut region_scope_tree = region::ScopeTree::default();
165+
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
165166
body(Env {
166167
infcx: &infcx,
167168
region_scope_tree: &mut region_scope_tree,
168-
param_env: ty::ParamEnv::empty(Reveal::UserFacing),
169+
param_env: param_env,
169170
});
170-
let free_regions = FreeRegionMap::new();
171+
let outlives_env = OutlivesEnvironment::new(param_env);
171172
let def_id = tcx.hir.local_def_id(ast::CRATE_NODE_ID);
172-
infcx.resolve_regions_and_report_errors(def_id, &region_scope_tree, &free_regions);
173+
infcx.resolve_regions_and_report_errors(def_id, &region_scope_tree, &outlives_env);
173174
assert_eq!(tcx.sess.err_count(), expected_err_count);
174175
});
175176
});

src/librustc_typeck/check/dropck.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ use check::regionck::RegionCtxt;
1212

1313
use hir::def_id::DefId;
1414
use rustc::infer::{self, InferOk};
15-
use rustc::infer::outlives::free_region_map::FreeRegionMap;
15+
use rustc::infer::outlives::env::OutlivesEnvironment;
1616
use rustc::middle::region;
1717
use rustc::ty::subst::{Subst, Substs};
1818
use rustc::ty::{self, Ty, TyCtxt};
19-
use rustc::traits::{self, ObligationCause};
19+
use rustc::traits::{self, Reveal, ObligationCause};
2020
use util::common::ErrorReported;
2121
use util::nodemap::FxHashSet;
2222

@@ -115,8 +115,18 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
115115
}
116116

117117
let region_scope_tree = region::ScopeTree::default();
118-
let free_regions = FreeRegionMap::new();
119-
infcx.resolve_regions_and_report_errors(drop_impl_did, &region_scope_tree, &free_regions);
118+
119+
// NB. It seems a bit... suspicious to use an empty param-env
120+
// here. The correct thing, I imagine, would be
121+
// `OutlivesEnvironment::new(impl_param_env)`, which would
122+
// allow region solving to take any `a: 'b` relations on the
123+
// impl into account. But I could not create a test case where
124+
// it did the wrong thing, so I chose to preserve existing
125+
// behavior, since it ought to be simply more
126+
// conservative. -nmatsakis
127+
let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty(Reveal::UserFacing));
128+
129+
infcx.resolve_regions_and_report_errors(drop_impl_did, &region_scope_tree, &outlives_env);
120130
Ok(())
121131
})
122132
}

src/librustc_typeck/check/regionck.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ use middle::region;
9090
use rustc::hir::def_id::DefId;
9191
use rustc::ty::subst::Substs;
9292
use rustc::ty::{self, Ty};
93-
use rustc::infer::{self, OutlivesEnvironment};
93+
use rustc::infer;
94+
use rustc::infer::outlives::env::OutlivesEnvironment;
9495
use rustc::ty::adjustment;
9596
use rustc::ty::outlives::Component;
9697

@@ -553,7 +554,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
553554
fn resolve_regions_and_report_errors(&self) {
554555
self.fcx.resolve_regions_and_report_errors(self.subject_def_id,
555556
&self.region_scope_tree,
556-
self.outlives_environment.free_region_map());
557+
&self.outlives_environment);
557558
}
558559

559560
fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat) {

src/librustc_typeck/coherence/builtin.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
//! Check properties that are required by built-in traits and set
1212
//! up data structures required by type-checking/translation.
1313
14-
use rustc::infer::outlives::free_region_map::FreeRegionMap;
14+
use rustc::infer::outlives::env::OutlivesEnvironment;
1515
use rustc::middle::region;
1616
use rustc::middle::lang_items::UnsizeTraitLangItem;
1717

@@ -391,9 +391,12 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
391391

392392
// Finally, resolve all regions.
393393
let region_scope_tree = region::ScopeTree::default();
394-
let mut free_regions = FreeRegionMap::new();
395-
free_regions.relate_free_regions_from_predicates(&param_env.caller_bounds);
396-
infcx.resolve_regions_and_report_errors(impl_did, &region_scope_tree, &free_regions);
394+
let outlives_env = OutlivesEnvironment::new(param_env);
395+
infcx.resolve_regions_and_report_errors(
396+
impl_did,
397+
&region_scope_tree,
398+
&outlives_env,
399+
);
397400

398401
CoerceUnsizedInfo {
399402
custom_kind: kind
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that we are able to normalize in the list of where-clauses,
12+
// even if `'a: 'b` is required.
13+
14+
trait Project<'a, 'b> {
15+
type Item;
16+
}
17+
18+
impl<'a, 'b> Project<'a, 'b> for ()
19+
where 'a: 'b
20+
{
21+
type Item = ();
22+
}
23+
24+
// No error here, we have 'a: 'b. We used to report an error here
25+
// though, see https://github.com/rust-lang/rust/issues/45937.
26+
fn foo<'a: 'b, 'b>()
27+
where <() as Project<'a, 'b>>::Item : Eq
28+
{
29+
}
30+
31+
// Here we get an error: we need `'a: 'b`.
32+
fn bar<'a, 'b>() //~ ERROR cannot infer
33+
where <() as Project<'a, 'b>>::Item : Eq
34+
{
35+
}
36+
37+
fn main() { }

0 commit comments

Comments
 (0)