Skip to content

Commit 931a3c4

Browse files
committed
Detect and store object-lifetime-defaults.
1 parent c5db290 commit 931a3c4

File tree

6 files changed

+228
-6
lines changed

6 files changed

+228
-6
lines changed

src/librustc/metadata/tydecode.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -824,14 +824,32 @@ fn parse_type_param_def_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F)
824824
assert_eq!(next(st), '|');
825825
let bounds = parse_bounds_(st, conv);
826826
let default = parse_opt(st, |st| parse_ty_(st, conv));
827+
let object_lifetime_default = parse_object_lifetime_default(st, conv);
827828

828829
ty::TypeParameterDef {
829830
name: name,
830831
def_id: def_id,
831832
space: space,
832833
index: index,
833834
bounds: bounds,
834-
default: default
835+
default: default,
836+
object_lifetime_default: object_lifetime_default,
837+
}
838+
}
839+
840+
fn parse_object_lifetime_default<'a,'tcx, F>(st: &mut PState<'a,'tcx>,
841+
conv: &mut F)
842+
-> Option<ty::ObjectLifetimeDefault>
843+
where F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
844+
{
845+
match next(st) {
846+
'n' => None,
847+
'a' => Some(ty::ObjectLifetimeDefault::Ambiguous),
848+
's' => {
849+
let region = parse_region_(st, conv);
850+
Some(ty::ObjectLifetimeDefault::Specific(region))
851+
}
852+
_ => panic!("parse_object_lifetime_default: bad input")
835853
}
836854
}
837855

src/librustc/metadata/tyencode.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,21 @@ pub fn enc_type_param_def<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tc
414414
v.space.to_uint(), v.index);
415415
enc_bounds(w, cx, &v.bounds);
416416
enc_opt(w, v.default, |w, t| enc_ty(w, cx, t));
417+
enc_object_lifetime_default(w, cx, v.object_lifetime_default);
418+
}
419+
420+
fn enc_object_lifetime_default<'a, 'tcx>(w: &mut SeekableMemWriter,
421+
cx: &ctxt<'a, 'tcx>,
422+
default: Option<ty::ObjectLifetimeDefault>)
423+
{
424+
match default {
425+
None => mywrite!(w, "n"),
426+
Some(ty::ObjectLifetimeDefault::Ambiguous) => mywrite!(w, "a"),
427+
Some(ty::ObjectLifetimeDefault::Specific(r)) => {
428+
mywrite!(w, "s");
429+
enc_region(w, cx, r);
430+
}
431+
}
417432
}
418433

419434
pub fn enc_predicate<'a, 'tcx>(w: &mut SeekableMemWriter,

src/librustc/middle/ty.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1758,6 +1758,21 @@ impl fmt::Debug for IntVarValue {
17581758
}
17591759
}
17601760

1761+
/// Default region to use for the bound of objects that are
1762+
/// supplied as the value for this type parameter. This is derived
1763+
/// from `T:'a` annotations appearing in the type definition. If
1764+
/// this is `None`, then the default is inherited from the
1765+
/// surrounding context. See RFC #599 for details.
1766+
#[derive(Copy, Clone, Debug)]
1767+
pub enum ObjectLifetimeDefault {
1768+
/// Require an explicit annotation. Occurs when multiple
1769+
/// `T:'a` constraints are found.
1770+
Ambiguous,
1771+
1772+
/// Use the given region as the default.
1773+
Specific(Region),
1774+
}
1775+
17611776
#[derive(Clone, Debug)]
17621777
pub struct TypeParameterDef<'tcx> {
17631778
pub name: ast::Name,
@@ -1766,6 +1781,7 @@ pub struct TypeParameterDef<'tcx> {
17661781
pub index: u32,
17671782
pub bounds: ParamBounds<'tcx>,
17681783
pub default: Option<Ty<'tcx>>,
1784+
pub object_lifetime_default: Option<ObjectLifetimeDefault>,
17691785
}
17701786

17711787
#[derive(RustcEncodable, RustcDecodable, Clone, Debug)]
@@ -7386,3 +7402,12 @@ impl<'a, 'tcx> Repr<'tcx> for ParameterEnvironment<'a, 'tcx> {
73867402
self.caller_bounds.repr(tcx))
73877403
}
73887404
}
7405+
7406+
impl<'tcx> Repr<'tcx> for ObjectLifetimeDefault {
7407+
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
7408+
match *self {
7409+
ObjectLifetimeDefault::Ambiguous => format!("Ambiguous"),
7410+
ObjectLifetimeDefault::Specific(ref r) => r.repr(tcx),
7411+
}
7412+
}
7413+
}

src/librustc/middle/ty_fold.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,19 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> {
379379
index: self.index,
380380
bounds: self.bounds.fold_with(folder),
381381
default: self.default.fold_with(folder),
382+
object_lifetime_default: self.object_lifetime_default.fold_with(folder),
383+
}
384+
}
385+
}
386+
387+
impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault {
388+
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ObjectLifetimeDefault {
389+
match *self {
390+
ty::ObjectLifetimeDefault::Ambiguous =>
391+
ty::ObjectLifetimeDefault::Ambiguous,
392+
393+
ty::ObjectLifetimeDefault::Specific(r) =>
394+
ty::ObjectLifetimeDefault::Specific(r.fold_with(folder)),
382395
}
383396
}
384397
}

src/librustc_typeck/collect.rs

Lines changed: 124 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ There are some shortcomings in this design:
8686
*/
8787

8888
use astconv::{self, AstConv, ty_of_arg, ast_ty_to_ty, ast_region_to_region};
89+
use middle::def;
8990
use middle::lang_items::SizedTraitLangItem;
9091
use middle::region;
9192
use middle::resolve_lifetime;
@@ -1199,8 +1200,23 @@ fn convert_typed_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
11991200
predicates.clone());
12001201
assert!(prev_predicates.is_none());
12011202

1202-
return (scheme, predicates);
1203+
// Debugging aid.
1204+
if ty::has_attr(tcx, local_def(it.id), "rustc_object_lifetime_default") {
1205+
let object_lifetime_default_reprs: String =
1206+
scheme.generics.types.iter()
1207+
.map(|t| match t.object_lifetime_default {
1208+
Some(ty::ObjectLifetimeDefault::Specific(r)) =>
1209+
r.user_string(tcx),
1210+
d =>
1211+
d.repr(ccx.tcx()),
1212+
})
1213+
.collect::<Vec<String>>()
1214+
.connect(",");
1215+
1216+
tcx.sess.span_err(it.span, &object_lifetime_default_reprs);
1217+
}
12031218

1219+
return (scheme, predicates);
12041220
}
12051221

12061222
fn type_scheme_of_foreign_item<'a, 'tcx>(
@@ -1269,6 +1285,7 @@ fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
12691285
subst::TypeSpace,
12701286
&generics.lifetimes[],
12711287
&generics.ty_params[],
1288+
&generics.where_clause,
12721289
ty::Generics::empty())
12731290
}
12741291

@@ -1298,6 +1315,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
12981315
subst::TypeSpace,
12991316
&ast_generics.lifetimes[],
13001317
&ast_generics.ty_params[],
1318+
&ast_generics.where_clause,
13011319
ty::Generics::empty());
13021320

13031321
// Add in the self type parameter.
@@ -1321,7 +1339,8 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
13211339
trait_bounds: vec!(ty::Binder(self_trait_ref.clone())),
13221340
projection_bounds: vec!(),
13231341
},
1324-
default: None
1342+
default: None,
1343+
object_lifetime_default: None,
13251344
};
13261345

13271346
ccx.tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone());
@@ -1341,6 +1360,7 @@ fn ty_generics_for_fn_or_method<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
13411360
subst::FnSpace,
13421361
&early_lifetimes[],
13431362
&generics.ty_params[],
1363+
&generics.where_clause,
13441364
base_generics)
13451365
}
13461366

@@ -1487,6 +1507,7 @@ fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
14871507
space: subst::ParamSpace,
14881508
lifetime_defs: &[ast::LifetimeDef],
14891509
types: &[ast::TyParam],
1510+
where_clause: &ast::WhereClause,
14901511
base_generics: ty::Generics<'tcx>)
14911512
-> ty::Generics<'tcx>
14921513
{
@@ -1511,7 +1532,7 @@ fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
15111532

15121533
// Now create the real type parameters.
15131534
for (i, param) in types.iter().enumerate() {
1514-
let def = get_or_create_type_parameter_def(ccx, space, param, i as u32);
1535+
let def = get_or_create_type_parameter_def(ccx, space, param, i as u32, where_clause);
15151536
debug!("ty_generics: def for type param: {:?}, {:?}", def, space);
15161537
result.types.push(space, def);
15171538
}
@@ -1522,7 +1543,8 @@ fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
15221543
fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
15231544
space: subst::ParamSpace,
15241545
param: &ast::TyParam,
1525-
index: u32)
1546+
index: u32,
1547+
where_clause: &ast::WhereClause)
15261548
-> ty::TypeParameterDef<'tcx>
15271549
{
15281550
let tcx = ccx.tcx;
@@ -1558,20 +1580,117 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
15581580
}
15591581
};
15601582

1583+
let object_lifetime_default =
1584+
compute_object_lifetime_default(ccx, space, index, &param.bounds, where_clause);
1585+
15611586
let def = ty::TypeParameterDef {
15621587
space: space,
15631588
index: index,
15641589
name: param.ident.name,
15651590
def_id: local_def(param.id),
15661591
bounds: bounds,
1567-
default: default
1592+
default: default,
1593+
object_lifetime_default: object_lifetime_default,
15681594
};
15691595

15701596
tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone());
15711597

15721598
def
15731599
}
15741600

1601+
/// Scan the bounds and where-clauses on a parameter to extract bounds
1602+
/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault`.
1603+
/// This runs as part of computing the minimal type scheme, so we
1604+
/// intentionally avoid just asking astconv to convert all the where
1605+
/// clauses into a `ty::Predicate`. This is because that could induce
1606+
/// artificial cycles.
1607+
fn compute_object_lifetime_default<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
1608+
space: subst::ParamSpace,
1609+
index: u32,
1610+
param_bounds: &[ast::TyParamBound],
1611+
where_clause: &ast::WhereClause)
1612+
-> Option<ty::ObjectLifetimeDefault>
1613+
{
1614+
let inline_bounds = from_bounds(ccx, param_bounds);
1615+
let where_bounds = from_predicates(ccx, space, index, &where_clause.predicates);
1616+
let all_bounds: HashSet<_> = inline_bounds.into_iter()
1617+
.chain(where_bounds.into_iter())
1618+
.collect();
1619+
return if all_bounds.len() > 1 {
1620+
Some(ty::ObjectLifetimeDefault::Ambiguous)
1621+
} else {
1622+
all_bounds.into_iter()
1623+
.next()
1624+
.map(ty::ObjectLifetimeDefault::Specific)
1625+
};
1626+
1627+
fn from_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
1628+
bounds: &[ast::TyParamBound])
1629+
-> Vec<ty::Region>
1630+
{
1631+
bounds.iter()
1632+
.filter_map(|bound| {
1633+
match *bound {
1634+
ast::TraitTyParamBound(..) =>
1635+
None,
1636+
ast::RegionTyParamBound(ref lifetime) =>
1637+
Some(astconv::ast_region_to_region(ccx.tcx(), lifetime)),
1638+
}
1639+
})
1640+
.collect()
1641+
}
1642+
1643+
fn from_predicates<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
1644+
space: subst::ParamSpace,
1645+
index: u32,
1646+
predicates: &[ast::WherePredicate])
1647+
-> Vec<ty::Region>
1648+
{
1649+
predicates.iter()
1650+
.flat_map(|predicate| {
1651+
match *predicate {
1652+
ast::WherePredicate::BoundPredicate(ref data) => {
1653+
if data.bound_lifetimes.len() == 0 &&
1654+
is_param(ccx, &data.bounded_ty, space, index)
1655+
{
1656+
from_bounds(ccx, &data.bounds).into_iter()
1657+
} else {
1658+
Vec::new().into_iter()
1659+
}
1660+
}
1661+
ast::WherePredicate::RegionPredicate(..) |
1662+
ast::WherePredicate::EqPredicate(..) => {
1663+
Vec::new().into_iter()
1664+
}
1665+
}
1666+
})
1667+
.collect()
1668+
}
1669+
1670+
fn is_param(ccx: &CollectCtxt,
1671+
ast_ty: &ast::Ty,
1672+
space: subst::ParamSpace,
1673+
index: u32)
1674+
-> bool
1675+
{
1676+
match ast_ty.node {
1677+
ast::TyPath(_, id) => {
1678+
match ccx.tcx.def_map.borrow()[id] {
1679+
def::DefTyParam(s, i, _, _) => {
1680+
space == s && index == i
1681+
}
1682+
_ => {
1683+
false
1684+
}
1685+
}
1686+
}
1687+
_ => {
1688+
false
1689+
}
1690+
}
1691+
}
1692+
}
1693+
15751694
enum SizedByDefault { Yes, No }
15761695

15771696
/// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2015 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+
#[rustc_object_lifetime_default]
12+
struct A<T>(T); //~ ERROR None
13+
14+
#[rustc_object_lifetime_default]
15+
struct B<'a,T>(&'a (), T); //~ ERROR None
16+
17+
#[rustc_object_lifetime_default]
18+
struct C<'a,T:'a>(&'a T); //~ ERROR 'a
19+
20+
#[rustc_object_lifetime_default]
21+
struct D<'a,'b,T:'a+'b>(&'a T, &'b T); //~ ERROR Ambiguous
22+
23+
#[rustc_object_lifetime_default]
24+
struct E<'a,'b:'a,T:'b>(&'a T, &'b T); //~ ERROR 'b
25+
26+
#[rustc_object_lifetime_default]
27+
struct F<'a,'b,T:'a,U:'b>(&'a T, &'b U); //~ ERROR 'a,'b
28+
29+
#[rustc_object_lifetime_default]
30+
struct G<'a,'b,T:'a,U:'a+'b>(&'a T, &'b U); //~ ERROR 'a,Ambiguous
31+
32+
fn main() { }

0 commit comments

Comments
 (0)