Skip to content

Commit 50c952b

Browse files
committed
Auto merge of #26370 - nikomatsakis:better-object-defaults-warn, r=nikomatsakis
This is an implementation of RFC rust-lang/rfcs#1156. It includes the code to implement the new rules, but that code is currently disabled. It also includes code to issue warnings when the change will cause breakage. These warnings try hard to be targeted but are also somewhat approximate. They could, with some effort, be made *more* targeted by adjusting the code in ty_relate that propagates the "will change" flag to consider the specific operation. Might be worth doing. r? @pnkfelix (I think you understand region inference best)
2 parents f027bdc + db5f3bc commit 50c952b

30 files changed

+479
-89
lines changed

src/librustc/diagnostics.rs

+36
Original file line numberDiff line numberDiff line change
@@ -1160,6 +1160,42 @@ static mut FOO: Option<Box<usize>> = None;
11601160
// error: mutable statics are not allowed to have destructors
11611161
static mut BAR: Option<Vec<i32>> = None;
11621162
```
1163+
"##,
1164+
1165+
E0398: r##"
1166+
In Rust 1.3, the default object lifetime bounds are expected to
1167+
change, as described in RFC #1156 [1]. You are getting a warning
1168+
because the compiler thinks it is possible that this change will cause
1169+
a compilation error in your code. It is possible, though unlikely,
1170+
that this is a false alarm.
1171+
1172+
The heart of the change is that where `&'a Box<SomeTrait>` used to
1173+
default to `&'a Box<SomeTrait+'a>`, it now defaults to `&'a
1174+
Box<SomeTrait+'static>` (here, `SomeTrait` is the name of some trait
1175+
type). Note that the only types which are affected are references to
1176+
boxes, like `&Box<SomeTrait>` or `&[Box<SomeTrait>]`. More common
1177+
types like `&SomeTrait` or `Box<SomeTrait>` are unaffected.
1178+
1179+
To silence this warning, edit your code to use an explicit bound.
1180+
Most of the time, this means that you will want to change the
1181+
signature of a function that you are calling. For example, if
1182+
the error is reported on a call like `foo(x)`, and `foo` is
1183+
defined as follows:
1184+
1185+
```
1186+
fn foo(arg: &Box<SomeTrait>) { ... }
1187+
```
1188+
1189+
you might change it to:
1190+
1191+
```
1192+
fn foo<'a>(arg: &Box<SomeTrait+'a>) { ... }
1193+
```
1194+
1195+
This explicitly states that you expect the trait object `SomeTrait` to
1196+
contain references (with a maximum lifetime of `'a`).
1197+
1198+
[1]: https://github.com/rust-lang/rfcs/pull/1156
11631199
"##
11641200

11651201
}

src/librustc/metadata/tydecode.rs

+12-5
Original file line numberDiff line numberDiff line change
@@ -843,15 +843,15 @@ fn parse_type_param_def_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F)
843843

844844
fn parse_object_lifetime_default<'a,'tcx, F>(st: &mut PState<'a,'tcx>,
845845
conv: &mut F)
846-
-> Option<ty::ObjectLifetimeDefault>
846+
-> ty::ObjectLifetimeDefault
847847
where F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
848848
{
849849
match next(st) {
850-
'n' => None,
851-
'a' => Some(ty::ObjectLifetimeDefault::Ambiguous),
850+
'a' => ty::ObjectLifetimeDefault::Ambiguous,
851+
'b' => ty::ObjectLifetimeDefault::BaseDefault,
852852
's' => {
853853
let region = parse_region_(st, conv);
854-
Some(ty::ObjectLifetimeDefault::Specific(region))
854+
ty::ObjectLifetimeDefault::Specific(region)
855855
}
856856
_ => panic!("parse_object_lifetime_default: bad input")
857857
}
@@ -887,9 +887,16 @@ fn parse_existential_bounds_<'a,'tcx, F>(st: &mut PState<'a,'tcx>,
887887
}
888888
}
889889

890+
let region_bound_will_change = match next(st) {
891+
'y' => true,
892+
'n' => false,
893+
c => panic!("parse_ty: expected y/n not '{}'", c)
894+
};
895+
890896
return ty::ExistentialBounds { region_bound: region_bound,
891897
builtin_bounds: builtin_bounds,
892-
projection_bounds: projection_bounds };
898+
projection_bounds: projection_bounds,
899+
region_bound_will_change: region_bound_will_change };
893900
}
894901

895902
fn parse_builtin_bounds<F>(st: &mut PState, mut _conv: F) -> ty::BuiltinBounds where

src/librustc/metadata/tyencode.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,8 @@ pub fn enc_existential_bounds<'a,'tcx>(w: &mut Encoder,
390390
}
391391

392392
mywrite!(w, ".");
393+
394+
mywrite!(w, "{}", if bs.region_bound_will_change {'y'} else {'n'});
393395
}
394396

395397
pub fn enc_region_bounds<'a, 'tcx>(w: &mut Encoder,
@@ -414,12 +416,12 @@ pub fn enc_type_param_def<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>,
414416

415417
fn enc_object_lifetime_default<'a, 'tcx>(w: &mut Encoder,
416418
cx: &ctxt<'a, 'tcx>,
417-
default: Option<ty::ObjectLifetimeDefault>)
419+
default: ty::ObjectLifetimeDefault)
418420
{
419421
match default {
420-
None => mywrite!(w, "n"),
421-
Some(ty::ObjectLifetimeDefault::Ambiguous) => mywrite!(w, "a"),
422-
Some(ty::ObjectLifetimeDefault::Specific(r)) => {
422+
ty::ObjectLifetimeDefault::Ambiguous => mywrite!(w, "a"),
423+
ty::ObjectLifetimeDefault::BaseDefault => mywrite!(w, "b"),
424+
ty::ObjectLifetimeDefault::Specific(r) => {
423425
mywrite!(w, "s");
424426
enc_region(w, cx, r);
425427
}

src/librustc/middle/infer/bivariate.rs

+5
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Bivariate<'a, 'tcx> {
4949

5050
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
5151

52+
fn will_change(&mut self, _: bool, _: bool) -> bool {
53+
// since we are not comparing regions, we don't care
54+
false
55+
}
56+
5257
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
5358
variance: ty::Variance,
5459
a: &T,

src/librustc/middle/infer/combine.rs

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ pub struct CombineFields<'a, 'tcx: 'a> {
5656
pub infcx: &'a InferCtxt<'a, 'tcx>,
5757
pub a_is_expected: bool,
5858
pub trace: TypeTrace<'tcx>,
59+
pub cause: Option<ty_relate::Cause>,
5960
}
6061

6162
pub fn super_combine_tys<'a,'tcx:'a,R>(infcx: &InferCtxt<'a, 'tcx>,

src/librustc/middle/infer/equate.rs

+5
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ impl<'a, 'tcx> TypeRelation<'a,'tcx> for Equate<'a, 'tcx> {
3434

3535
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
3636

37+
fn will_change(&mut self, a: bool, b: bool) -> bool {
38+
// if either side changed from what it was, that could cause equality to fail
39+
a || b
40+
}
41+
3742
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
3843
_: ty::Variance,
3944
a: &T,

src/librustc/middle/infer/error_reporting.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
593593
sub: Region,
594594
sup: Region) {
595595
match origin {
596-
infer::Subtype(trace) => {
596+
infer::Subtype(trace) |
597+
infer::DefaultExistentialBound(trace) => {
597598
let terr = ty::terr_regions_does_not_outlive(sup, sub);
598599
self.report_and_explain_type_error(trace, &terr);
599600
}
@@ -1569,7 +1570,8 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
15691570

15701571
fn note_region_origin(&self, origin: &SubregionOrigin<'tcx>) {
15711572
match *origin {
1572-
infer::Subtype(ref trace) => {
1573+
infer::Subtype(ref trace) |
1574+
infer::DefaultExistentialBound(ref trace) => {
15731575
let desc = match trace.origin {
15741576
infer::Misc(_) => {
15751577
"types are compatible"

src/librustc/middle/infer/glb.rs

+10
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Glb<'a, 'tcx> {
3535

3636
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
3737

38+
fn will_change(&mut self, a: bool, b: bool) -> bool {
39+
// Hmm, so the result of GLB will still be a LB if one or both
40+
// sides change to 'static, but it may no longer be the GLB.
41+
// I'm going to go with `a || b` here to be conservative,
42+
// since the result of this operation may be affected, though
43+
// I think it would mostly be more accepting than before (since the result
44+
// would be a bigger region).
45+
a || b
46+
}
47+
3848
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
3949
variance: ty::Variance,
4050
a: &T,

src/librustc/middle/infer/lub.rs

+5
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Lub<'a, 'tcx> {
3535

3636
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
3737

38+
fn will_change(&mut self, a: bool, b: bool) -> bool {
39+
// result will be 'static if a || b
40+
a || b
41+
}
42+
3843
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
3944
variance: ty::Variance,
4045
a: &T,

src/librustc/middle/infer/mod.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,9 @@ pub enum SubregionOrigin<'tcx> {
194194
// Arose from a subtyping relation
195195
Subtype(TypeTrace<'tcx>),
196196

197+
// Arose from a subtyping relation
198+
DefaultExistentialBound(TypeTrace<'tcx>),
199+
197200
// Stack-allocated closures cannot outlive innermost loop
198201
// or function so as to ensure we only require finite stack
199202
InfStackClosure(Span),
@@ -658,7 +661,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
658661
-> CombineFields<'a, 'tcx> {
659662
CombineFields {infcx: self,
660663
a_is_expected: a_is_expected,
661-
trace: trace}
664+
trace: trace,
665+
cause: None}
662666
}
663667

664668
// public so that it can be used from the rustc_driver unit tests
@@ -1464,6 +1468,7 @@ impl<'tcx> SubregionOrigin<'tcx> {
14641468
pub fn span(&self) -> Span {
14651469
match *self {
14661470
Subtype(ref a) => a.span(),
1471+
DefaultExistentialBound(ref a) => a.span(),
14671472
InfStackClosure(a) => a,
14681473
InvokeClosure(a) => a,
14691474
DerefPointer(a) => a,

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

+47
Original file line numberDiff line numberDiff line change
@@ -1358,9 +1358,56 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
13581358
}
13591359
}
13601360

1361+
// Check for future hostile edges tied to a bad default
1362+
self.report_future_hostility(&graph);
1363+
13611364
(0..self.num_vars() as usize).map(|idx| var_data[idx].value).collect()
13621365
}
13631366

1367+
fn report_future_hostility(&self, graph: &RegionGraph) {
1368+
let constraints = self.constraints.borrow();
1369+
for edge in graph.all_edges() {
1370+
match constraints[&edge.data] {
1371+
SubregionOrigin::DefaultExistentialBound(_) => {
1372+
// this will become 'static in the future
1373+
}
1374+
_ => { continue; }
1375+
}
1376+
1377+
// this constraint will become a 'static constraint in the
1378+
// future, so walk outward and see if we have any hard
1379+
// bounds that could not be inferred to 'static
1380+
for nid in graph.depth_traverse(edge.target()) {
1381+
for (_, succ) in graph.outgoing_edges(nid) {
1382+
match succ.data {
1383+
ConstrainVarSubReg(_, r) => {
1384+
match r {
1385+
ty::ReStatic | ty::ReInfer(_) => {
1386+
/* OK */
1387+
}
1388+
ty::ReFree(_) | ty::ReScope(_) | ty::ReEmpty => {
1389+
span_warn!(
1390+
self.tcx.sess,
1391+
constraints[&edge.data].span(),
1392+
E0398,
1393+
"this code may fail to compile in Rust 1.3 due to \
1394+
the proposed change in object lifetime bound defaults");
1395+
return; // only issue the warning once per fn
1396+
}
1397+
ty::ReEarlyBound(..) | ty::ReLateBound(..) => {
1398+
self.tcx.sess.span_bug(
1399+
constraints[&succ.data].span(),
1400+
"relation to bound region");
1401+
}
1402+
}
1403+
}
1404+
_ => { }
1405+
}
1406+
}
1407+
}
1408+
}
1409+
}
1410+
13641411
fn construct_graph(&self) -> RegionGraph {
13651412
let num_vars = self.num_vars();
13661413

src/librustc/middle/infer/sub.rs

+31-8
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,17 @@
1010

1111
use super::combine::{self, CombineFields};
1212
use super::higher_ranked::HigherRankedRelations;
13-
use super::Subtype;
13+
use super::SubregionOrigin;
1414
use super::type_variable::{SubtypeOf, SupertypeOf};
1515

1616
use middle::ty::{self, Ty};
1717
use middle::ty::TyVar;
18-
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
18+
use middle::ty_relate::{Cause, Relate, RelateResult, TypeRelation};
19+
use std::mem;
1920

2021
/// "Greatest lower bound" (common subtype)
2122
pub struct Sub<'a, 'tcx: 'a> {
22-
fields: CombineFields<'a, 'tcx>
23+
fields: CombineFields<'a, 'tcx>,
2324
}
2425

2526
impl<'a, 'tcx> Sub<'a, 'tcx> {
@@ -33,6 +34,25 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Sub<'a, 'tcx> {
3334
fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.infcx.tcx }
3435
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
3536

37+
fn with_cause<F,R>(&mut self, cause: Cause, f: F) -> R
38+
where F: FnOnce(&mut Self) -> R
39+
{
40+
debug!("sub with_cause={:?}", cause);
41+
let old_cause = mem::replace(&mut self.fields.cause, Some(cause));
42+
let r = f(self);
43+
debug!("sub old_cause={:?}", old_cause);
44+
self.fields.cause = old_cause;
45+
r
46+
}
47+
48+
fn will_change(&mut self, a: bool, b: bool) -> bool {
49+
// if we have (Foo+'a) <: (Foo+'b), this requires that 'a:'b.
50+
// So if 'a becomes 'static, no additional errors can occur.
51+
// OTOH, if 'a stays the same, but 'b becomes 'static, we
52+
// could have a problem.
53+
!a && b
54+
}
55+
3656
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
3757
variance: ty::Variance,
3858
a: &T,
@@ -84,11 +104,14 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Sub<'a, 'tcx> {
84104
}
85105

86106
fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
87-
debug!("{}.regions({:?}, {:?})",
88-
self.tag(),
89-
a,
90-
b);
91-
let origin = Subtype(self.fields.trace.clone());
107+
debug!("{}.regions({:?}, {:?}) self.cause={:?}",
108+
self.tag(), a, b, self.fields.cause);
109+
let origin = match self.fields.cause {
110+
Some(Cause::ExistentialRegionBound(true)) =>
111+
SubregionOrigin::DefaultExistentialBound(self.fields.trace.clone()),
112+
_ =>
113+
SubregionOrigin::Subtype(self.fields.trace.clone()),
114+
};
92115
self.fields.infcx.region_vars.make_subregion(origin, a, b);
93116
Ok(a)
94117
}

src/librustc/middle/traits/select.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2445,6 +2445,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
24452445
region_bound: data_b.bounds.region_bound,
24462446
builtin_bounds: data_b.bounds.builtin_bounds,
24472447
projection_bounds: data_a.bounds.projection_bounds.clone(),
2448+
region_bound_will_change: data_b.bounds.region_bound_will_change,
24482449
};
24492450

24502451
let new_trait = tcx.mk_trait(data_a.principal.clone(), bounds);

src/librustc/middle/ty.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -2055,6 +2055,11 @@ pub struct ExistentialBounds<'tcx> {
20552055
pub region_bound: ty::Region,
20562056
pub builtin_bounds: BuiltinBounds,
20572057
pub projection_bounds: Vec<PolyProjectionPredicate<'tcx>>,
2058+
2059+
// If true, this TyTrait used a "default bound" in the surface
2060+
// syntax. This makes no difference to the type system but is
2061+
// handy for error reporting.
2062+
pub region_bound_will_change: bool,
20582063
}
20592064

20602065
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
@@ -2245,6 +2250,9 @@ pub enum ObjectLifetimeDefault {
22452250
/// `T:'a` constraints are found.
22462251
Ambiguous,
22472252

2253+
/// Use the base default, typically 'static, but in a fn body it is a fresh variable
2254+
BaseDefault,
2255+
22482256
/// Use the given region as the default.
22492257
Specific(Region),
22502258
}
@@ -2256,7 +2264,7 @@ pub struct TypeParameterDef<'tcx> {
22562264
pub space: subst::ParamSpace,
22572265
pub index: u32,
22582266
pub default: Option<Ty<'tcx>>,
2259-
pub object_lifetime_default: Option<ObjectLifetimeDefault>,
2267+
pub object_lifetime_default: ObjectLifetimeDefault,
22602268
}
22612269

22622270
#[derive(RustcEncodable, RustcDecodable, Clone, Debug)]
@@ -7328,6 +7336,7 @@ impl<'tcx> fmt::Debug for ObjectLifetimeDefault {
73287336
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73297337
match *self {
73307338
ObjectLifetimeDefault::Ambiguous => write!(f, "Ambiguous"),
7339+
ObjectLifetimeDefault::BaseDefault => write!(f, "BaseDefault"),
73317340
ObjectLifetimeDefault::Specific(ref r) => write!(f, "{:?}", r),
73327341
}
73337342
}

0 commit comments

Comments
 (0)