Skip to content

Commit 9c0413b

Browse files
committed
Modify implicator to take a "syntactic" approach, ensuring that fns and
object types impose minimal constraints on their arguments. Also modify regionck to consider `<P0 as TraitRef<P1..Pn>>::Foo: 'r` to hold if `Pi: 'r` (for all `i`). This is a fallback, because in some cases we can impose looser requirements. Currently the inference is sound but not precise. Fixes rust-lang#24622. Adapted cherry-pick of 45f93290969f19d8217a2e4dff7b12dc81957eb6.
1 parent 0666255 commit 9c0413b

20 files changed

+651
-107
lines changed

src/librustc/middle/expr_use_visitor.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ impl OverloadedCallType {
239239
// supplies types from the tree. After type checking is complete, you
240240
// can just use the tcx as the typer.
241241

242-
pub struct ExprUseVisitor<'d,'t,'a: 't, 'tcx:'a> {
242+
pub struct ExprUseVisitor<'d, 't, 'a: 't, 'tcx:'a+'d> {
243243
typer: &'t infer::InferCtxt<'a, 'tcx>,
244244
mc: mc::MemCategorizationContext<'t, 'a, 'tcx>,
245245
delegate: &'d mut (Delegate<'tcx>+'d),

src/librustc/middle/implicator.rs

+38-3
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ struct Implicator<'a, 'tcx: 'a> {
4141
visited: FnvHashSet<Ty<'tcx>>,
4242
}
4343

44-
/// This routine computes the well-formedness constraints that must hold for the type `ty` to
45-
/// appear in a context with lifetime `outer_region`
44+
/// This routine computes the full set of well-formedness constraints
45+
/// that must hold for the type `ty` to appear in a context with
46+
/// lifetime `outer_region`.
4647
pub fn implications<'a,'tcx>(
4748
infcx: &'a InferCtxt<'a,'tcx>,
4849
body_id: ast::NodeId,
@@ -90,12 +91,15 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
9091
ty::TyInt(..) |
9192
ty::TyUint(..) |
9293
ty::TyFloat(..) |
93-
ty::TyBareFn(..) |
9494
ty::TyError |
9595
ty::TyStr => {
9696
// No borrowed content reachable here.
9797
}
9898

99+
ty::TyBareFn(..) => {
100+
self.accumulate_referenced_regions_and_types(ty);
101+
}
102+
99103
ty::TyClosure(def_id, substs) => {
100104
let &(r_a, opt_ty) = self.stack.last().unwrap();
101105
self.out.push(Implication::RegionSubClosure(opt_ty, r_a, def_id, substs));
@@ -382,6 +386,37 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
382386
// constraint above
383387
self.out.push(Implication::RegionSubRegion(Some(ty), r_d, r_c));
384388
}
389+
390+
self.accumulate_referenced_regions_and_types(ty);
391+
}
392+
393+
fn accumulate_referenced_regions_and_types(&mut self,
394+
iface_ty: Ty<'tcx>)
395+
{
396+
// for now, `iface_ty` represents some type that is a fn or
397+
// trait object argument, and because those appear underneath
398+
// forall binders, we do not enforce the full WF requirements,
399+
// just the lifetime "outlives" requirements.
400+
for ty in iface_ty.walk() {
401+
match ty.sty {
402+
ty::TyParam(p) => {
403+
self.push_param_constraint_from_top(p);
404+
}
405+
406+
_ => { }
407+
}
408+
409+
for r in ty.regions() {
410+
match r {
411+
ty::ReLateBound(..) => {
412+
// skip late-bound regions
413+
}
414+
_ => {
415+
self.push_region_constraint_from_top(r);
416+
}
417+
}
418+
}
419+
}
385420
}
386421

387422
fn fully_normalize<T>(&self, value: &T) -> Result<T,ErrorReported>

src/librustc/middle/infer/error_reporting.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,7 @@ pub trait ErrorReporting<'tcx> {
241241
fn report_generic_bound_failure(&self,
242242
origin: SubregionOrigin<'tcx>,
243243
kind: GenericKind<'tcx>,
244-
sub: Region,
245-
sups: Vec<Region>);
244+
sub: Region);
246245

247246
fn report_sub_sup_conflict(&self,
248247
var_origin: RegionVariableOrigin,
@@ -294,8 +293,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
294293
self.report_concrete_failure(origin, sub, sup);
295294
}
296295

297-
GenericBoundFailure(kind, param_ty, sub, sups) => {
298-
self.report_generic_bound_failure(kind, param_ty, sub, sups);
296+
GenericBoundFailure(kind, param_ty, sub) => {
297+
self.report_generic_bound_failure(kind, param_ty, sub);
299298
}
300299

301300
SubSupConflict(var_origin,
@@ -529,8 +528,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
529528
fn report_generic_bound_failure(&self,
530529
origin: SubregionOrigin<'tcx>,
531530
bound_kind: GenericKind<'tcx>,
532-
sub: Region,
533-
_sups: Vec<Region>)
531+
sub: Region)
534532
{
535533
// FIXME: it would be better to report the first error message
536534
// with the span of the parameter itself, rather than the span

src/librustc/middle/infer/mod.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub use self::ValuePairs::*;
2020
pub use self::fixup_err::*;
2121
pub use middle::ty::IntVarValue;
2222
pub use self::freshen::TypeFreshener;
23-
pub use self::region_inference::GenericKind;
23+
pub use self::region_inference::{GenericKind, VerifyBound};
2424

2525
use middle::free_region::FreeRegionMap;
2626
use middle::mem_categorization as mc;
@@ -1284,13 +1284,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
12841284
origin: SubregionOrigin<'tcx>,
12851285
kind: GenericKind<'tcx>,
12861286
a: ty::Region,
1287-
bs: Vec<ty::Region>) {
1287+
bound: VerifyBound) {
12881288
debug!("verify_generic_bound({:?}, {:?} <: {:?})",
12891289
kind,
12901290
a,
1291-
bs);
1291+
bound);
12921292

1293-
self.region_vars.verify_generic_bound(origin, kind, a, bs);
1293+
self.region_vars.verify_generic_bound(origin, kind, a, bound);
12941294
}
12951295

12961296
pub fn can_equate<'b,T>(&'b self, a: &T, b: &T) -> UnitResult<'tcx>

src/librustc/middle/infer/region_inference/mod.rs

+128-24
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,41 @@ pub enum Verify<'tcx> {
6565
// outlive `RS`. Therefore verify that `R <= RS[i]` for some
6666
// `i`. Inference variables may be involved (but this verification
6767
// step doesn't influence inference).
68-
VerifyGenericBound(GenericKind<'tcx>, SubregionOrigin<'tcx>, Region, Vec<Region>),
68+
VerifyGenericBound(GenericKind<'tcx>, SubregionOrigin<'tcx>, Region, VerifyBound),
6969
}
7070

71-
#[derive(Clone, PartialEq, Eq)]
71+
#[derive(Copy, Clone, PartialEq, Eq)]
7272
pub enum GenericKind<'tcx> {
7373
Param(ty::ParamTy),
7474
Projection(ty::ProjectionTy<'tcx>),
7575
}
7676

77+
// When we introduce a verification step, we wish to test that a
78+
// particular region (let's call it `'min`) meets some bound.
79+
// The bound is described the by the following grammar:
80+
#[derive(Debug)]
81+
pub enum VerifyBound {
82+
// B = exists {R} --> some 'r in {R} must outlive 'min
83+
//
84+
// Put another way, the subject value is known to outlive all
85+
// regions in {R}, so if any of those outlives 'min, then the
86+
// bound is met.
87+
AnyRegion(Vec<Region>),
88+
89+
// B = forall {R} --> all 'r in {R} must outlive 'min
90+
//
91+
// Put another way, the subject value is known to outlive some
92+
// region in {R}, so if all of those outlives 'min, then the bound
93+
// is met.
94+
AllRegions(Vec<Region>),
95+
96+
// B = exists {B} --> 'min must meet some bound b in {B}
97+
AnyBound(Vec<VerifyBound>),
98+
99+
// B = forall {B} --> 'min must meet all bounds b in {B}
100+
AllBounds(Vec<VerifyBound>),
101+
}
102+
77103
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
78104
pub struct TwoRegions {
79105
a: Region,
@@ -103,12 +129,11 @@ pub enum RegionResolutionError<'tcx> {
103129
/// `o` requires that `a <= b`, but this does not hold
104130
ConcreteFailure(SubregionOrigin<'tcx>, Region, Region),
105131

106-
/// `GenericBoundFailure(p, s, a, bs)
132+
/// `GenericBoundFailure(p, s, a)
107133
///
108134
/// The parameter/associated-type `p` must be known to outlive the lifetime
109-
/// `a`, but it is only known to outlive `bs` (and none of the
110-
/// regions in `bs` outlive `a`).
111-
GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region, Vec<Region>),
135+
/// `a` (but none of the known bounds are sufficient).
136+
GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region),
112137

113138
/// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`:
114139
///
@@ -409,6 +434,14 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
409434
debug!("RegionVarBindings: add_verify({:?})",
410435
verify);
411436

437+
// skip no-op cases known to be satisfied
438+
match verify {
439+
VerifyGenericBound(_, _, _, VerifyBound::AllBounds(ref bs)) if bs.len() == 0 => {
440+
return;
441+
}
442+
_ => { }
443+
}
444+
412445
let mut verifys = self.verifys.borrow_mut();
413446
let index = verifys.len();
414447
verifys.push(verify);
@@ -498,8 +531,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
498531
origin: SubregionOrigin<'tcx>,
499532
kind: GenericKind<'tcx>,
500533
sub: Region,
501-
sups: Vec<Region>) {
502-
self.add_verify(VerifyGenericBound(kind, origin, sub, sups));
534+
bound: VerifyBound) {
535+
self.add_verify(VerifyGenericBound(kind, origin, sub, bound));
503536
}
504537

505538
pub fn lub_regions(&self,
@@ -664,12 +697,11 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
664697
&mut result_set, r,
665698
a, b);
666699
}
667-
VerifyGenericBound(_, _, a, ref bs) => {
668-
for &b in bs {
669-
consider_adding_bidirectional_edges(
670-
&mut result_set, r,
671-
a, b);
672-
}
700+
VerifyGenericBound(_, _, a, ref bound) => {
701+
bound.for_each_region(&mut |b| {
702+
consider_adding_bidirectional_edges(&mut result_set, r,
703+
a, b)
704+
});
673705
}
674706
}
675707
}
@@ -1264,20 +1296,13 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
12641296
errors.push(ConcreteFailure((*origin).clone(), sub, sup));
12651297
}
12661298

1267-
VerifyGenericBound(ref kind, ref origin, sub, ref sups) => {
1299+
VerifyGenericBound(ref kind, ref origin, sub, ref bound) => {
12681300
let sub = normalize(values, sub);
1269-
if sups.iter()
1270-
.map(|&sup| normalize(values, sup))
1271-
.any(|sup| free_regions.is_subregion_of(self.tcx, sub, sup))
1272-
{
1301+
if bound.is_met(self.tcx, free_regions, values, sub) {
12731302
continue;
12741303
}
12751304

1276-
let sups = sups.iter().map(|&sup| normalize(values, sup))
1277-
.collect();
1278-
errors.push(
1279-
GenericBoundFailure(
1280-
(*origin).clone(), kind.clone(), sub, sups));
1305+
errors.push(GenericBoundFailure((*origin).clone(), kind.clone(), sub));
12811306
}
12821307
}
12831308
}
@@ -1723,3 +1748,82 @@ impl<'tcx> GenericKind<'tcx> {
17231748
}
17241749
}
17251750
}
1751+
1752+
impl VerifyBound {
1753+
fn for_each_region(&self, f: &mut FnMut(ty::Region)) {
1754+
match self {
1755+
&VerifyBound::AnyRegion(ref rs) |
1756+
&VerifyBound::AllRegions(ref rs) =>
1757+
for &r in rs { f(r); },
1758+
1759+
&VerifyBound::AnyBound(ref bs) |
1760+
&VerifyBound::AllBounds(ref bs) =>
1761+
for b in bs { b.for_each_region(f); },
1762+
}
1763+
}
1764+
1765+
pub fn must_hold(&self) -> bool {
1766+
match self {
1767+
&VerifyBound::AnyRegion(ref bs) => bs.contains(&ty::ReStatic),
1768+
&VerifyBound::AllRegions(ref bs) => bs.is_empty(),
1769+
&VerifyBound::AnyBound(ref bs) => bs.iter().any(|b| b.must_hold()),
1770+
&VerifyBound::AllBounds(ref bs) => bs.iter().all(|b| b.must_hold()),
1771+
}
1772+
}
1773+
1774+
pub fn cannot_hold(&self) -> bool {
1775+
match self {
1776+
&VerifyBound::AnyRegion(ref bs) => bs.is_empty(),
1777+
&VerifyBound::AllRegions(ref bs) => bs.contains(&ty::ReEmpty),
1778+
&VerifyBound::AnyBound(ref bs) => bs.iter().all(|b| b.cannot_hold()),
1779+
&VerifyBound::AllBounds(ref bs) => bs.iter().any(|b| b.cannot_hold()),
1780+
}
1781+
}
1782+
1783+
pub fn or(self, vb: VerifyBound) -> VerifyBound {
1784+
if self.must_hold() || vb.cannot_hold() {
1785+
self
1786+
} else if self.cannot_hold() || vb.must_hold() {
1787+
vb
1788+
} else {
1789+
VerifyBound::AnyBound(vec![self, vb])
1790+
}
1791+
}
1792+
1793+
pub fn and(self, vb: VerifyBound) -> VerifyBound {
1794+
if self.must_hold() && vb.must_hold() {
1795+
self
1796+
} else if self.cannot_hold() && vb.cannot_hold() {
1797+
self
1798+
} else {
1799+
VerifyBound::AllBounds(vec![self, vb])
1800+
}
1801+
}
1802+
1803+
fn is_met<'tcx>(&self,
1804+
tcx: &ty::ctxt<'tcx>,
1805+
free_regions: &FreeRegionMap,
1806+
var_values: &Vec<VarValue>,
1807+
min: ty::Region)
1808+
-> bool {
1809+
match self {
1810+
&VerifyBound::AnyRegion(ref rs) =>
1811+
rs.iter()
1812+
.map(|&r| normalize(var_values, r))
1813+
.any(|r| free_regions.is_subregion_of(tcx, min, r)),
1814+
1815+
&VerifyBound::AllRegions(ref rs) =>
1816+
rs.iter()
1817+
.map(|&r| normalize(var_values, r))
1818+
.all(|r| free_regions.is_subregion_of(tcx, min, r)),
1819+
1820+
&VerifyBound::AnyBound(ref bs) =>
1821+
bs.iter()
1822+
.any(|b| b.is_met(tcx, free_regions, var_values, min)),
1823+
1824+
&VerifyBound::AllBounds(ref bs) =>
1825+
bs.iter()
1826+
.all(|b| b.is_met(tcx, free_regions, var_values, min)),
1827+
}
1828+
}
1829+
}

0 commit comments

Comments
 (0)