Skip to content

Commit f9e53c7

Browse files
committed
Auto merge of #24553 - nikomatsakis:issue-22779-overconstrained-impl, r=pnkfelix
Rather than storing the relations between free-regions in a global table, introduce a `FreeRegionMap` data structure. regionck computes the `FreeRegionMap` for each fn and stores the result into the tcx so that borrowck can use it (this could perhaps be refactored to have borrowck recompute the map, but it's a bid tedious to recompute due to the interaction of closures and free fns). The main reason to do this is because of #22779 -- using a global table was incorrect because when validating impl method signatures, we want to use the free region relationships from the *trait*, not the impl. Fixes #22779.
2 parents 2214860 + 55ffd2e commit f9e53c7

19 files changed

+447
-234
lines changed

src/librustc/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,10 @@ pub mod middle {
106106
pub mod entry;
107107
pub mod expr_use_visitor;
108108
pub mod fast_reject;
109+
pub mod free_region;
109110
pub mod intrinsicck;
110111
pub mod infer;
112+
pub mod implicator;
111113
pub mod lang_items;
112114
pub mod liveness;
113115
pub mod mem_categorization;

src/librustc/middle/free_region.rs

+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// Copyright 2012-2014 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+
//! This file defines
12+
13+
use middle::implicator::Implication;
14+
use middle::ty::{self, FreeRegion};
15+
use util::common::can_reach;
16+
use util::nodemap::FnvHashMap;
17+
use util::ppaux::Repr;
18+
19+
#[derive(Clone)]
20+
pub struct FreeRegionMap {
21+
/// `free_region_map` maps from a free region `a` to a list of
22+
/// free regions `bs` such that `a <= b for all b in bs`
23+
map: FnvHashMap<FreeRegion, Vec<FreeRegion>>,
24+
}
25+
26+
impl FreeRegionMap {
27+
pub fn new() -> FreeRegionMap {
28+
FreeRegionMap { map: FnvHashMap() }
29+
}
30+
31+
pub fn relate_free_regions_from_implications<'tcx>(&mut self,
32+
tcx: &ty::ctxt<'tcx>,
33+
implications: &[Implication<'tcx>])
34+
{
35+
for implication in implications {
36+
debug!("implication: {}", implication.repr(tcx));
37+
match *implication {
38+
Implication::RegionSubRegion(_, ty::ReFree(free_a), ty::ReFree(free_b)) => {
39+
self.relate_free_regions(free_a, free_b);
40+
}
41+
Implication::RegionSubRegion(..) |
42+
Implication::RegionSubClosure(..) |
43+
Implication::RegionSubGeneric(..) |
44+
Implication::Predicate(..) => {
45+
}
46+
}
47+
}
48+
}
49+
50+
pub fn relate_free_regions_from_predicates<'tcx>(&mut self,
51+
tcx: &ty::ctxt<'tcx>,
52+
predicates: &[ty::Predicate<'tcx>]) {
53+
debug!("relate_free_regions_from_predicates(predicates={})", predicates.repr(tcx));
54+
for predicate in predicates {
55+
match *predicate {
56+
ty::Predicate::Projection(..) |
57+
ty::Predicate::Trait(..) |
58+
ty::Predicate::Equate(..) |
59+
ty::Predicate::TypeOutlives(..) => {
60+
// No region bounds here
61+
}
62+
ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
63+
match (r_a, r_b) {
64+
(ty::ReFree(fr_a), ty::ReFree(fr_b)) => {
65+
// Record that `'a:'b`. Or, put another way, `'b <= 'a`.
66+
self.relate_free_regions(fr_b, fr_a);
67+
}
68+
_ => {
69+
// All named regions are instantiated with free regions.
70+
tcx.sess.bug(
71+
&format!("record_region_bounds: non free region: {} / {}",
72+
r_a.repr(tcx),
73+
r_b.repr(tcx)));
74+
}
75+
}
76+
}
77+
}
78+
}
79+
}
80+
81+
pub fn relate_free_regions(&mut self, sub: FreeRegion, sup: FreeRegion) {
82+
let mut sups = self.map.entry(sub).or_insert(Vec::new());
83+
if !sups.contains(&sup) {
84+
sups.push(sup);
85+
}
86+
}
87+
88+
/// Determines whether two free regions have a subregion relationship
89+
/// by walking the graph encoded in `map`. Note that
90+
/// it is possible that `sub != sup` and `sub <= sup` and `sup <= sub`
91+
/// (that is, the user can give two different names to the same lifetime).
92+
pub fn sub_free_region(&self, sub: FreeRegion, sup: FreeRegion) -> bool {
93+
can_reach(&self.map, sub, sup)
94+
}
95+
96+
/// Determines whether one region is a subregion of another. This is intended to run *after
97+
/// inference* and sadly the logic is somewhat duplicated with the code in infer.rs.
98+
pub fn is_subregion_of(&self,
99+
tcx: &ty::ctxt,
100+
sub_region: ty::Region,
101+
super_region: ty::Region)
102+
-> bool {
103+
debug!("is_subregion_of(sub_region={:?}, super_region={:?})",
104+
sub_region, super_region);
105+
106+
sub_region == super_region || {
107+
match (sub_region, super_region) {
108+
(ty::ReEmpty, _) |
109+
(_, ty::ReStatic) =>
110+
true,
111+
112+
(ty::ReScope(sub_scope), ty::ReScope(super_scope)) =>
113+
tcx.region_maps.is_subscope_of(sub_scope, super_scope),
114+
115+
(ty::ReScope(sub_scope), ty::ReFree(ref fr)) =>
116+
tcx.region_maps.is_subscope_of(sub_scope, fr.scope.to_code_extent()),
117+
118+
(ty::ReFree(sub_fr), ty::ReFree(super_fr)) =>
119+
self.sub_free_region(sub_fr, super_fr),
120+
121+
_ =>
122+
false,
123+
}
124+
}
125+
}
126+
}
127+

src/librustc_typeck/check/implicator.rs src/librustc/middle/implicator.rs

+34-2
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,10 @@
1010

1111
// #![warn(deprecated_mode)]
1212

13-
use astconv::object_region_bounds;
1413
use middle::infer::{InferCtxt, GenericKind};
1514
use middle::subst::Substs;
1615
use middle::traits;
17-
use middle::ty::{self, ToPolyTraitRef, Ty};
16+
use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
1817
use middle::ty_fold::{TypeFoldable, TypeFolder};
1918

2019
use std::rc::Rc;
@@ -423,6 +422,39 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
423422
}
424423
}
425424

425+
/// Given an object type like `SomeTrait+Send`, computes the lifetime
426+
/// bounds that must hold on the elided self type. These are derived
427+
/// from the declarations of `SomeTrait`, `Send`, and friends -- if
428+
/// they declare `trait SomeTrait : 'static`, for example, then
429+
/// `'static` would appear in the list. The hard work is done by
430+
/// `ty::required_region_bounds`, see that for more information.
431+
pub fn object_region_bounds<'tcx>(
432+
tcx: &ty::ctxt<'tcx>,
433+
principal: &ty::PolyTraitRef<'tcx>,
434+
others: ty::BuiltinBounds)
435+
-> Vec<ty::Region>
436+
{
437+
// Since we don't actually *know* the self type for an object,
438+
// this "open(err)" serves as a kind of dummy standin -- basically
439+
// a skolemized type.
440+
let open_ty = ty::mk_infer(tcx, ty::FreshTy(0));
441+
442+
// Note that we preserve the overall binding levels here.
443+
assert!(!open_ty.has_escaping_regions());
444+
let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty));
445+
let trait_refs = vec!(ty::Binder(Rc::new(ty::TraitRef::new(principal.0.def_id, substs))));
446+
447+
let param_bounds = ty::ParamBounds {
448+
region_bounds: Vec::new(),
449+
builtin_bounds: others,
450+
trait_bounds: trait_refs,
451+
projection_bounds: Vec::new(), // not relevant to computing region bounds
452+
};
453+
454+
let predicates = ty::predicates(tcx, open_ty, &param_bounds);
455+
ty::required_region_bounds(tcx, open_ty, predicates)
456+
}
457+
426458
impl<'tcx> Repr<'tcx> for Implication<'tcx> {
427459
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
428460
match *self {

src/librustc/middle/infer/mod.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub use middle::ty::IntVarValue;
2222
pub use self::freshen::TypeFreshener;
2323
pub use self::region_inference::GenericKind;
2424

25+
use middle::free_region::FreeRegionMap;
2526
use middle::subst;
2627
use middle::subst::Substs;
2728
use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, UnconstrainedNumeric};
@@ -855,8 +856,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
855856
self.region_vars.new_bound(debruijn)
856857
}
857858

858-
pub fn resolve_regions_and_report_errors(&self, subject_node_id: ast::NodeId) {
859-
let errors = self.region_vars.resolve_regions(subject_node_id);
859+
pub fn resolve_regions_and_report_errors(&self,
860+
free_regions: &FreeRegionMap,
861+
subject_node_id: ast::NodeId) {
862+
let errors = self.region_vars.resolve_regions(free_regions, subject_node_id);
860863
self.report_region_errors(&errors); // see error_reporting.rs
861864
}
862865

0 commit comments

Comments
 (0)