rustc: move object default lifetimes to resolve_lifetimes.
This commit is contained in:
parent
c5befdc630
commit
4eac052a33
16 changed files with 445 additions and 459 deletions
|
@ -28,6 +28,7 @@ use hir::map as hir_map;
|
|||
use hir::map::definitions::{Definitions, DefKey, DisambiguatedDefPathData};
|
||||
use hir::svh::Svh;
|
||||
use middle::lang_items;
|
||||
use middle::resolve_lifetime::ObjectLifetimeDefault;
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use mir::Mir;
|
||||
use session::Session;
|
||||
|
@ -183,6 +184,8 @@ pub trait CrateStore<'tcx> {
|
|||
fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
|
||||
-> ty::Generics<'tcx>;
|
||||
fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize);
|
||||
fn item_generics_object_lifetime_defaults(&self, def: DefId)
|
||||
-> Vec<ObjectLifetimeDefault>;
|
||||
fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>;
|
||||
fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef;
|
||||
fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> &'tcx ty::AdtDef;
|
||||
|
@ -334,6 +337,9 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
|
|||
-> ty::Generics<'tcx> { bug!("item_generics") }
|
||||
fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize)
|
||||
{ bug!("item_generics_own_param_counts") }
|
||||
fn item_generics_object_lifetime_defaults(&self, def: DefId)
|
||||
-> Vec<ObjectLifetimeDefault>
|
||||
{ bug!("item_generics_object_lifetime_defaults") }
|
||||
fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute> { bug!("item_attrs") }
|
||||
fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef
|
||||
{ bug!("trait_def") }
|
||||
|
|
|
@ -26,11 +26,12 @@ use ty;
|
|||
use std::cell::Cell;
|
||||
use std::mem::replace;
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::ptr::P;
|
||||
use syntax::symbol::keywords;
|
||||
use syntax_pos::Span;
|
||||
use errors::DiagnosticBuilder;
|
||||
use util::nodemap::{NodeMap, FxHashSet, FxHashMap};
|
||||
use util::nodemap::{NodeMap, FxHashSet, FxHashMap, DefIdMap};
|
||||
use rustc_back::slice;
|
||||
|
||||
use hir;
|
||||
|
@ -102,8 +103,46 @@ impl Region {
|
|||
_ => self
|
||||
}
|
||||
}
|
||||
|
||||
fn subst(self, params: &[hir::Lifetime], map: &NamedRegionMap)
|
||||
-> Option<Region> {
|
||||
if let Region::EarlyBound(index, _) = self {
|
||||
params.get(index as usize).and_then(|lifetime| {
|
||||
map.defs.get(&lifetime.id).cloned()
|
||||
})
|
||||
} else {
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A set containing, at most, one known element.
|
||||
/// If two distinct values are inserted into a set, then it
|
||||
/// becomes `Many`, which can be used to detect ambiguities.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
|
||||
pub enum Set1<T> {
|
||||
Empty,
|
||||
One(T),
|
||||
Many
|
||||
}
|
||||
|
||||
impl<T: PartialEq> Set1<T> {
|
||||
pub fn insert(&mut self, value: T) {
|
||||
if let Set1::Empty = *self {
|
||||
*self = Set1::One(value);
|
||||
return;
|
||||
}
|
||||
if let Set1::One(ref old) = *self {
|
||||
if *old == value {
|
||||
return;
|
||||
}
|
||||
}
|
||||
*self = Set1::Many;
|
||||
}
|
||||
}
|
||||
|
||||
pub type ObjectLifetimeDefault = Set1<Region>;
|
||||
|
||||
// Maps the id of each lifetime reference to the lifetime decl
|
||||
// that it corresponds to.
|
||||
pub struct NamedRegionMap {
|
||||
|
@ -115,6 +154,10 @@ pub struct NamedRegionMap {
|
|||
// are named regions appearing in fn arguments that do not appear
|
||||
// in where-clauses
|
||||
pub late_bound: NodeMap<ty::Issue32330>,
|
||||
|
||||
// For each type and trait definition, maps type parameters
|
||||
// to the trait object lifetime defaults computed from them.
|
||||
pub object_lifetime_defaults: NodeMap<Vec<ObjectLifetimeDefault>>,
|
||||
}
|
||||
|
||||
struct LifetimeContext<'a, 'tcx: 'a> {
|
||||
|
@ -141,6 +184,9 @@ struct LifetimeContext<'a, 'tcx: 'a> {
|
|||
|
||||
// List of labels in the function/method currently under analysis.
|
||||
labels_in_fn: Vec<(ast::Name, Span)>,
|
||||
|
||||
// Cache for cross-crate per-definition object lifetime defaults.
|
||||
xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -170,6 +216,14 @@ enum Scope<'a> {
|
|||
s: ScopeRef<'a>
|
||||
},
|
||||
|
||||
/// Use a specific lifetime (if `Some`) or leave it unset (to be
|
||||
/// inferred in a function body or potentially error outside one),
|
||||
/// for the default choice of lifetime in a trait object type.
|
||||
ObjectLifetimeDefault {
|
||||
lifetime: Option<Region>,
|
||||
s: ScopeRef<'a>
|
||||
},
|
||||
|
||||
Root
|
||||
}
|
||||
|
||||
|
@ -208,6 +262,7 @@ pub fn krate(sess: &Session,
|
|||
let mut map = NamedRegionMap {
|
||||
defs: NodeMap(),
|
||||
late_bound: NodeMap(),
|
||||
object_lifetime_defaults: compute_object_lifetime_defaults(sess, hir_map),
|
||||
};
|
||||
sess.track_errors(|| {
|
||||
let mut visitor = LifetimeContext {
|
||||
|
@ -217,6 +272,7 @@ pub fn krate(sess: &Session,
|
|||
scope: ROOT_SCOPE,
|
||||
trait_ref_hack: false,
|
||||
labels_in_fn: vec![],
|
||||
xcrate_object_lifetime_defaults: DefIdMap(),
|
||||
};
|
||||
for (_, item) in &krate.items {
|
||||
visitor.visit_item(item);
|
||||
|
@ -326,10 +382,20 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
for bound in bounds {
|
||||
self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
|
||||
}
|
||||
if !lifetime.is_elided() {
|
||||
if lifetime.is_elided() {
|
||||
self.resolve_object_lifetime_default(lifetime)
|
||||
} else {
|
||||
self.visit_lifetime(lifetime);
|
||||
}
|
||||
}
|
||||
hir::TyRptr(ref lifetime_ref, ref mt) => {
|
||||
self.visit_lifetime(lifetime_ref);
|
||||
let scope = Scope::ObjectLifetimeDefault {
|
||||
lifetime: self.map.defs.get(&lifetime_ref.id).cloned(),
|
||||
s: self.scope
|
||||
};
|
||||
self.with(scope, |_, this| this.visit_ty(&mt.ty));
|
||||
}
|
||||
_ => {
|
||||
intravisit::walk_ty(self, ty)
|
||||
}
|
||||
|
@ -372,20 +438,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
self.resolve_lifetime_ref(lifetime_ref);
|
||||
}
|
||||
|
||||
fn visit_path_parameters(&mut self, _: Span, params: &'tcx hir::PathParameters) {
|
||||
match *params {
|
||||
hir::AngleBracketedParameters(ref data) => {
|
||||
if data.lifetimes.iter().all(|l| l.is_elided()) {
|
||||
self.resolve_elided_lifetimes(&data.lifetimes);
|
||||
} else {
|
||||
for l in &data.lifetimes { self.visit_lifetime(l); }
|
||||
}
|
||||
for ty in &data.types { self.visit_ty(ty); }
|
||||
for b in &data.bindings { self.visit_assoc_type_binding(b); }
|
||||
}
|
||||
hir::ParenthesizedParameters(ref data) => {
|
||||
self.visit_fn_like_elision(&data.inputs, data.output.as_ref());
|
||||
}
|
||||
fn visit_path(&mut self, path: &'tcx hir::Path, _: ast::NodeId) {
|
||||
for (i, segment) in path.segments.iter().enumerate() {
|
||||
let depth = path.segments.len() - i - 1;
|
||||
self.visit_segment_parameters(path.def, depth, &segment.parameters);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -466,7 +522,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
for lifetime in &trait_ref.bound_lifetimes {
|
||||
this.visit_lifetime_def(lifetime);
|
||||
}
|
||||
intravisit::walk_path(this, &trait_ref.trait_ref.path)
|
||||
this.visit_trait_ref(&trait_ref.trait_ref)
|
||||
})
|
||||
} else {
|
||||
self.visit_trait_ref(&trait_ref.trait_ref)
|
||||
|
@ -585,7 +641,8 @@ fn extract_labels(ctxt: &mut LifetimeContext, body: &hir::Body) {
|
|||
loop {
|
||||
match *scope {
|
||||
Scope::Body { s, .. } |
|
||||
Scope::Elision { s, .. } => { scope = s; }
|
||||
Scope::Elision { s, .. } |
|
||||
Scope::ObjectLifetimeDefault { s, .. } => { scope = s; }
|
||||
|
||||
Scope::Root => { return; }
|
||||
|
||||
|
@ -606,6 +663,103 @@ fn extract_labels(ctxt: &mut LifetimeContext, body: &hir::Body) {
|
|||
}
|
||||
}
|
||||
|
||||
fn compute_object_lifetime_defaults(sess: &Session, hir_map: &Map)
|
||||
-> NodeMap<Vec<ObjectLifetimeDefault>> {
|
||||
let mut map = NodeMap();
|
||||
for item in hir_map.krate().items.values() {
|
||||
match item.node {
|
||||
hir::ItemStruct(_, ref generics) |
|
||||
hir::ItemUnion(_, ref generics) |
|
||||
hir::ItemEnum(_, ref generics) |
|
||||
hir::ItemTy(_, ref generics) |
|
||||
hir::ItemTrait(_, ref generics, ..) => {
|
||||
let result = object_lifetime_defaults_for_item(hir_map, generics);
|
||||
|
||||
// Debugging aid.
|
||||
if attr::contains_name(&item.attrs, "rustc_object_lifetime_default") {
|
||||
let object_lifetime_default_reprs: String =
|
||||
result.iter().map(|set| {
|
||||
match *set {
|
||||
Set1::Empty => "BaseDefault".to_string(),
|
||||
Set1::One(Region::Static) => "'static".to_string(),
|
||||
Set1::One(Region::EarlyBound(i, _)) => {
|
||||
generics.lifetimes[i as usize].lifetime.name.to_string()
|
||||
}
|
||||
Set1::One(_) => bug!(),
|
||||
Set1::Many => "Ambiguous".to_string(),
|
||||
}
|
||||
}).collect::<Vec<String>>().join(",");
|
||||
sess.span_err(item.span, &object_lifetime_default_reprs);
|
||||
}
|
||||
|
||||
map.insert(item.id, result);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
map
|
||||
}
|
||||
|
||||
/// Scan the bounds and where-clauses on parameters to extract bounds
|
||||
/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault`
|
||||
/// for each type parameter.
|
||||
fn object_lifetime_defaults_for_item(hir_map: &Map, generics: &hir::Generics)
|
||||
-> Vec<ObjectLifetimeDefault> {
|
||||
fn add_bounds(set: &mut Set1<ast::Name>, bounds: &[hir::TyParamBound]) {
|
||||
for bound in bounds {
|
||||
if let hir::RegionTyParamBound(ref lifetime) = *bound {
|
||||
set.insert(lifetime.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generics.ty_params.iter().map(|param| {
|
||||
let mut set = Set1::Empty;
|
||||
|
||||
add_bounds(&mut set, ¶m.bounds);
|
||||
|
||||
let param_def_id = hir_map.local_def_id(param.id);
|
||||
for predicate in &generics.where_clause.predicates {
|
||||
// Look for `type: ...` where clauses.
|
||||
let data = match *predicate {
|
||||
hir::WherePredicate::BoundPredicate(ref data) => data,
|
||||
_ => continue
|
||||
};
|
||||
|
||||
// Ignore `for<'a> type: ...` as they can change what
|
||||
// lifetimes mean (although we could "just" handle it).
|
||||
if !data.bound_lifetimes.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let def = match data.bounded_ty.node {
|
||||
hir::TyPath(hir::QPath::Resolved(None, ref path)) => path.def,
|
||||
_ => continue
|
||||
};
|
||||
|
||||
if def == Def::TyParam(param_def_id) {
|
||||
add_bounds(&mut set, &data.bounds);
|
||||
}
|
||||
}
|
||||
|
||||
match set {
|
||||
Set1::Empty => Set1::Empty,
|
||||
Set1::One(name) => {
|
||||
if name == keywords::StaticLifetime.name() {
|
||||
Set1::One(Region::Static)
|
||||
} else {
|
||||
generics.lifetimes.iter().enumerate().find(|&(_, def)| {
|
||||
def.lifetime.name == name
|
||||
}).map_or(Set1::Many, |(i, def)| {
|
||||
Set1::One(Region::EarlyBound(i as u32, def.lifetime.id))
|
||||
})
|
||||
}
|
||||
}
|
||||
Set1::Many => Set1::Many
|
||||
}
|
||||
}).collect()
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||
// FIXME(#37666) this works around a limitation in the region inferencer
|
||||
fn hack<F>(&mut self, f: F) where
|
||||
|
@ -619,6 +773,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
{
|
||||
let LifetimeContext {sess, hir_map, ref mut map, ..} = *self;
|
||||
let labels_in_fn = replace(&mut self.labels_in_fn, vec![]);
|
||||
let xcrate_object_lifetime_defaults =
|
||||
replace(&mut self.xcrate_object_lifetime_defaults, DefIdMap());
|
||||
let mut this = LifetimeContext {
|
||||
sess: sess,
|
||||
hir_map: hir_map,
|
||||
|
@ -626,11 +782,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
scope: &wrap_scope,
|
||||
trait_ref_hack: self.trait_ref_hack,
|
||||
labels_in_fn: labels_in_fn,
|
||||
xcrate_object_lifetime_defaults: xcrate_object_lifetime_defaults,
|
||||
};
|
||||
debug!("entering scope {:?}", this.scope);
|
||||
f(self.scope, &mut this);
|
||||
debug!("exiting scope {:?}", this.scope);
|
||||
self.labels_in_fn = this.labels_in_fn;
|
||||
self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults;
|
||||
}
|
||||
|
||||
/// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
|
||||
|
@ -727,7 +885,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
Scope::Elision { s, .. } => {
|
||||
Scope::Elision { s, .. } |
|
||||
Scope::ObjectLifetimeDefault { s, .. } => {
|
||||
scope = s;
|
||||
}
|
||||
}
|
||||
|
@ -763,6 +922,109 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_segment_parameters(&mut self,
|
||||
def: Def,
|
||||
depth: usize,
|
||||
params: &'tcx hir::PathParameters) {
|
||||
let data = match *params {
|
||||
hir::ParenthesizedParameters(ref data) => {
|
||||
self.visit_fn_like_elision(&data.inputs, data.output.as_ref());
|
||||
return;
|
||||
}
|
||||
hir::AngleBracketedParameters(ref data) => data
|
||||
};
|
||||
|
||||
if data.lifetimes.iter().all(|l| l.is_elided()) {
|
||||
self.resolve_elided_lifetimes(&data.lifetimes);
|
||||
} else {
|
||||
for l in &data.lifetimes { self.visit_lifetime(l); }
|
||||
}
|
||||
|
||||
// Figure out if this is a type/trait segment,
|
||||
// which requires object lifetime defaults.
|
||||
let parent_def_id = |this: &mut Self, def_id: DefId| {
|
||||
let def_key = if def_id.is_local() {
|
||||
this.hir_map.def_key(def_id)
|
||||
} else {
|
||||
this.sess.cstore.def_key(def_id)
|
||||
};
|
||||
DefId {
|
||||
krate: def_id.krate,
|
||||
index: def_key.parent.expect("missing parent")
|
||||
}
|
||||
};
|
||||
let type_def_id = match def {
|
||||
Def::AssociatedTy(def_id) if depth == 1 => {
|
||||
Some(parent_def_id(self, def_id))
|
||||
}
|
||||
Def::Variant(def_id) if depth == 0 => {
|
||||
Some(parent_def_id(self, def_id))
|
||||
}
|
||||
Def::Struct(def_id) |
|
||||
Def::Union(def_id) |
|
||||
Def::Enum(def_id) |
|
||||
Def::TyAlias(def_id) |
|
||||
Def::Trait(def_id) if depth == 0 => Some(def_id),
|
||||
_ => None
|
||||
};
|
||||
|
||||
let object_lifetime_defaults = type_def_id.map_or(vec![], |def_id| {
|
||||
let in_body = {
|
||||
let mut scope = self.scope;
|
||||
loop {
|
||||
match *scope {
|
||||
Scope::Root => break false,
|
||||
|
||||
Scope::Body { .. } => break true,
|
||||
|
||||
Scope::Binder { s, .. } |
|
||||
Scope::Elision { s, .. } |
|
||||
Scope::ObjectLifetimeDefault { s, .. } => {
|
||||
scope = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let map = &self.map;
|
||||
let unsubst = if let Some(id) = self.hir_map.as_local_node_id(def_id) {
|
||||
&map.object_lifetime_defaults[&id]
|
||||
} else {
|
||||
let cstore = &self.sess.cstore;
|
||||
self.xcrate_object_lifetime_defaults.entry(def_id).or_insert_with(|| {
|
||||
cstore.item_generics_object_lifetime_defaults(def_id)
|
||||
})
|
||||
};
|
||||
unsubst.iter().map(|set| {
|
||||
match *set {
|
||||
Set1::Empty => {
|
||||
if in_body {
|
||||
None
|
||||
} else {
|
||||
Some(Region::Static)
|
||||
}
|
||||
}
|
||||
Set1::One(r) => r.subst(&data.lifetimes, map),
|
||||
Set1::Many => None
|
||||
}
|
||||
}).collect()
|
||||
});
|
||||
|
||||
for (i, ty) in data.types.iter().enumerate() {
|
||||
if let Some(<) = object_lifetime_defaults.get(i) {
|
||||
let scope = Scope::ObjectLifetimeDefault {
|
||||
lifetime: lt,
|
||||
s: self.scope
|
||||
};
|
||||
self.with(scope, |_, this| this.visit_ty(ty));
|
||||
} else {
|
||||
self.visit_ty(ty);
|
||||
}
|
||||
}
|
||||
|
||||
for b in &data.bindings { self.visit_assoc_type_binding(b); }
|
||||
}
|
||||
|
||||
fn visit_fn_like_elision(&mut self, inputs: &'tcx [P<hir::Ty>],
|
||||
output: Option<&'tcx P<hir::Ty>>) {
|
||||
let mut arg_elide = Elide::FreshLateAnon(Cell::new(0));
|
||||
|
@ -962,7 +1224,19 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
if let hir::TyBareFn(_) = ty.node {
|
||||
self.binder_depth += 1;
|
||||
}
|
||||
intravisit::walk_ty(self, ty);
|
||||
if let hir::TyTraitObject(ref bounds, ref lifetime) = ty.node {
|
||||
for bound in bounds {
|
||||
self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
|
||||
}
|
||||
|
||||
// Stay on the safe side and don't include the object
|
||||
// lifetime default (which may not end up being used).
|
||||
if !lifetime.is_elided() {
|
||||
self.visit_lifetime(lifetime);
|
||||
}
|
||||
} else {
|
||||
intravisit::walk_ty(self, ty);
|
||||
}
|
||||
if let hir::TyBareFn(_) = ty.node {
|
||||
self.binder_depth -= 1;
|
||||
}
|
||||
|
@ -1045,6 +1319,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Scope::ObjectLifetimeDefault { s, .. } => {
|
||||
scope = s;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1134,6 +1412,28 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn resolve_object_lifetime_default(&mut self, lifetime_ref: &hir::Lifetime) {
|
||||
let mut late_depth = 0;
|
||||
let mut scope = self.scope;
|
||||
let lifetime = loop {
|
||||
match *scope {
|
||||
Scope::Binder { s, .. } => {
|
||||
late_depth += 1;
|
||||
scope = s;
|
||||
}
|
||||
|
||||
Scope::Root |
|
||||
Scope::Elision { .. } => break Region::Static,
|
||||
|
||||
Scope::Body { .. } |
|
||||
Scope::ObjectLifetimeDefault { lifetime: None, .. } => return,
|
||||
|
||||
Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l
|
||||
}
|
||||
};
|
||||
self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth));
|
||||
}
|
||||
|
||||
fn check_lifetime_defs(&mut self, old_scope: ScopeRef, lifetimes: &[hir::LifetimeDef]) {
|
||||
for i in 0..lifetimes.len() {
|
||||
let lifetime_i = &lifetimes[i];
|
||||
|
@ -1192,7 +1492,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
loop {
|
||||
match *old_scope {
|
||||
Scope::Body { s, .. } |
|
||||
Scope::Elision { s, .. } => {
|
||||
Scope::Elision { s, .. } |
|
||||
Scope::ObjectLifetimeDefault { s, .. } => {
|
||||
old_scope = s;
|
||||
}
|
||||
|
||||
|
|
|
@ -592,24 +592,6 @@ pub enum IntVarValue {
|
|||
UintType(ast::UintTy),
|
||||
}
|
||||
|
||||
/// Default region to use for the bound of objects that are
|
||||
/// supplied as the value for this type parameter. This is derived
|
||||
/// from `T:'a` annotations appearing in the type definition. If
|
||||
/// this is `None`, then the default is inherited from the
|
||||
/// surrounding context. See RFC #599 for details.
|
||||
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
|
||||
pub enum ObjectLifetimeDefault<'tcx> {
|
||||
/// Require an explicit annotation. Occurs when multiple
|
||||
/// `T:'a` constraints are found.
|
||||
Ambiguous,
|
||||
|
||||
/// Use the base default, typically 'static, but in a fn body it is a fresh variable
|
||||
BaseDefault,
|
||||
|
||||
/// Use the given region as the default.
|
||||
Specific(&'tcx Region),
|
||||
}
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable)]
|
||||
pub struct TypeParameterDef<'tcx> {
|
||||
pub name: Name,
|
||||
|
@ -617,7 +599,6 @@ pub struct TypeParameterDef<'tcx> {
|
|||
pub index: u32,
|
||||
pub default_def_id: DefId, // for use in error reporing about defaults
|
||||
pub default: Option<Ty<'tcx>>,
|
||||
pub object_lifetime_default: ObjectLifetimeDefault<'tcx>,
|
||||
|
||||
/// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute
|
||||
/// on generic parameter `T`, asserts data behind the parameter
|
||||
|
|
|
@ -726,36 +726,12 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> {
|
|||
index: self.index,
|
||||
default: self.default.fold_with(folder),
|
||||
default_def_id: self.default_def_id,
|
||||
object_lifetime_default: self.object_lifetime_default.fold_with(folder),
|
||||
pure_wrt_drop: self.pure_wrt_drop,
|
||||
}
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
self.default.visit_with(visitor) ||
|
||||
self.object_lifetime_default.visit_with(visitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault<'tcx> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
match *self {
|
||||
ty::ObjectLifetimeDefault::Ambiguous =>
|
||||
ty::ObjectLifetimeDefault::Ambiguous,
|
||||
|
||||
ty::ObjectLifetimeDefault::BaseDefault =>
|
||||
ty::ObjectLifetimeDefault::BaseDefault,
|
||||
|
||||
ty::ObjectLifetimeDefault::Specific(r) =>
|
||||
ty::ObjectLifetimeDefault::Specific(r.fold_with(folder)),
|
||||
}
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
match *self {
|
||||
ty::ObjectLifetimeDefault::Specific(r) => r.visit_with(visitor),
|
||||
_ => false,
|
||||
}
|
||||
self.default.visit_with(visitor)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -523,16 +523,6 @@ impl<'tcx> fmt::Debug for ty::ParameterEnvironment<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for ty::ObjectLifetimeDefault<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
ty::ObjectLifetimeDefault::Ambiguous => write!(f, "Ambiguous"),
|
||||
ty::ObjectLifetimeDefault::BaseDefault => write!(f, "BaseDefault"),
|
||||
ty::ObjectLifetimeDefault::Specific(ref r) => write!(f, "{:?}", r),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ty::Region {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if verbose() {
|
||||
|
|
|
@ -17,6 +17,7 @@ use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind, ExternC
|
|||
use rustc::middle::cstore::{NativeLibrary, LinkMeta, LinkagePreference, LoadedMacro};
|
||||
use rustc::hir::def::{self, Def};
|
||||
use rustc::middle::lang_items;
|
||||
use rustc::middle::resolve_lifetime::ObjectLifetimeDefault;
|
||||
use rustc::session::Session;
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
|
||||
|
@ -115,6 +116,12 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
|
|||
self.get_crate_data(def.krate).generics_own_param_counts(def.index)
|
||||
}
|
||||
|
||||
fn item_generics_object_lifetime_defaults(&self, def: DefId)
|
||||
-> Vec<ObjectLifetimeDefault> {
|
||||
self.dep_graph.read(DepNode::MetaData(def));
|
||||
self.get_crate_data(def.krate).generics_object_lifetime_defaults(def.index)
|
||||
}
|
||||
|
||||
fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>
|
||||
{
|
||||
self.dep_graph.read(DepNode::MetaData(def_id));
|
||||
|
|
|
@ -20,6 +20,7 @@ use rustc::middle::cstore::LinkagePreference;
|
|||
use rustc::hir::def::{self, Def, CtorKind};
|
||||
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
|
||||
use rustc::middle::lang_items;
|
||||
use rustc::middle::resolve_lifetime::ObjectLifetimeDefault;
|
||||
use rustc::session::Session;
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::ty::subst::Substs;
|
||||
|
@ -614,6 +615,12 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
(g.regions.len, g.types.len)
|
||||
}
|
||||
|
||||
pub fn generics_object_lifetime_defaults(&self, item_id: DefIndex)
|
||||
-> Vec<ObjectLifetimeDefault> {
|
||||
self.entry(item_id).generics.unwrap().decode(self)
|
||||
.object_lifetime_defaults.decode(self).collect()
|
||||
}
|
||||
|
||||
pub fn get_type(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
|
||||
self.entry(id).ty.unwrap().decode((self, tcx))
|
||||
}
|
||||
|
|
|
@ -422,6 +422,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
let g = tcx.item_generics(def_id);
|
||||
let regions = self.lazy_seq_ref(&g.regions);
|
||||
let types = self.lazy_seq_ref(&g.types);
|
||||
let mut object_lifetime_defaults = LazySeq::empty();
|
||||
if let Some(id) = tcx.hir.as_local_node_id(def_id) {
|
||||
if let Some(o) = tcx.named_region_map.object_lifetime_defaults.get(&id) {
|
||||
object_lifetime_defaults = self.lazy_seq_ref(o);
|
||||
}
|
||||
}
|
||||
self.lazy(&Generics {
|
||||
parent: g.parent,
|
||||
parent_regions: g.parent_regions,
|
||||
|
@ -429,6 +435,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
regions: regions,
|
||||
types: types,
|
||||
has_self: g.has_self,
|
||||
object_lifetime_defaults: object_lifetime_defaults,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ use rustc::hir::def::{self, CtorKind};
|
|||
use rustc::hir::def_id::{DefIndex, DefId};
|
||||
use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary};
|
||||
use rustc::middle::lang_items;
|
||||
use rustc::middle::resolve_lifetime::ObjectLifetimeDefault;
|
||||
use rustc::mir;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc_back::PanicStrategy;
|
||||
|
@ -258,6 +259,7 @@ pub struct Generics<'tcx> {
|
|||
pub regions: LazySeq<ty::RegionParameterDef<'tcx>>,
|
||||
pub types: LazySeq<ty::TypeParameterDef<'tcx>>,
|
||||
pub has_self: bool,
|
||||
pub object_lifetime_defaults: LazySeq<ObjectLifetimeDefault>,
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
//! Conversion from AST representation of types to the ty.rs
|
||||
//! representation. The main routine here is `ast_ty_to_ty()`: each use
|
||||
//! is parameterized by an instance of `AstConv` and a `RegionScope`.
|
||||
//! is parameterized by an instance of `AstConv`.
|
||||
//!
|
||||
//! The parameterization of `ast_ty_to_ty()` is because it behaves
|
||||
//! somewhat differently during the collect and check phases,
|
||||
|
@ -22,31 +22,6 @@
|
|||
//! an error). In the check phase, when the FnCtxt is used as the
|
||||
//! `AstConv`, `get_item_type()` just looks up the item type in
|
||||
//! `tcx.types` (using `TyCtxt::item_type`).
|
||||
//!
|
||||
//! The `RegionScope` trait controls what happens when the user does
|
||||
//! not specify a region in some location where a region is required
|
||||
//! (e.g., if the user writes `&Foo` as a type rather than `&'a Foo`).
|
||||
//! See the `rscope` module for more details.
|
||||
//!
|
||||
//! Unlike the `AstConv` trait, the region scope can change as we descend
|
||||
//! the type. This is to accommodate the fact that (a) fn types are binding
|
||||
//! scopes and (b) the default region may change. To understand case (a),
|
||||
//! consider something like:
|
||||
//!
|
||||
//! type foo = { x: &a.int, y: |&a.int| }
|
||||
//!
|
||||
//! The type of `x` is an error because there is no region `a` in scope.
|
||||
//! In the type of `y`, however, region `a` is considered a bound region
|
||||
//! as it does not already appear in scope.
|
||||
//!
|
||||
//! Case (b) says that if you have a type:
|
||||
//! type foo<'a> = ...;
|
||||
//! type bar = fn(&foo, &a.foo)
|
||||
//! The fully expanded version of type bar is:
|
||||
//! type bar = fn(&'foo &, &a.foo<'a>)
|
||||
//! Note that the self region for the `foo` defaulted to `&` in the first
|
||||
//! case but `&a` in the second. Basically, defaults that appear inside
|
||||
//! an rptr (`&r.T`) use the region `r` that appears in the rptr.
|
||||
|
||||
use rustc_const_eval::eval_length;
|
||||
use rustc_data_structures::accumulate_vec::AccumulateVec;
|
||||
|
@ -61,8 +36,6 @@ use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable};
|
|||
use rustc::ty::wf::object_region_bounds;
|
||||
use rustc_back::slice;
|
||||
use require_c_abi_if_variadic;
|
||||
use rscope::{RegionScope, ObjectLifetimeDefaultRscope, ShiftedRscope};
|
||||
use rscope::ExplicitRscope;
|
||||
use util::common::{ErrorReported, FN_OUTPUT_NAME};
|
||||
use util::nodemap::{NodeMap, FxHashSet};
|
||||
|
||||
|
@ -110,7 +83,7 @@ pub trait AstConv<'gcx, 'tcx> {
|
|||
|
||||
/// What lifetime should we use when a lifetime is omitted (and not elided)?
|
||||
fn re_infer(&self, span: Span, _def: Option<&ty::RegionParameterDef>)
|
||||
-> &'tcx ty::Region;
|
||||
-> Option<&'tcx ty::Region>;
|
||||
|
||||
/// What type should we use when a type is omitted?
|
||||
fn ty_infer(&self, span: Span) -> Ty<'tcx>;
|
||||
|
@ -220,7 +193,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
// (*) -- not late-bound, won't change
|
||||
}
|
||||
|
||||
None => self.re_infer(lifetime.span, def)
|
||||
None => {
|
||||
self.re_infer(lifetime.span, def).expect("unelided lifetime in signature")
|
||||
}
|
||||
};
|
||||
|
||||
debug!("ast_region_to_region(lifetime={:?}) yields {:?}",
|
||||
|
@ -233,7 +208,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
/// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`,
|
||||
/// returns an appropriate set of substitutions for this particular reference to `I`.
|
||||
pub fn ast_path_substs_for_ty(&self,
|
||||
rscope: &RegionScope,
|
||||
span: Span,
|
||||
def_id: DefId,
|
||||
item_segment: &hir::PathSegment)
|
||||
|
@ -258,8 +232,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
}
|
||||
|
||||
let (substs, assoc_bindings) =
|
||||
self.create_substs_for_ast_path(rscope,
|
||||
span,
|
||||
self.create_substs_for_ast_path(span,
|
||||
def_id,
|
||||
&item_segment.parameters,
|
||||
None);
|
||||
|
@ -275,7 +248,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
///
|
||||
/// Note that the type listing given here is *exactly* what the user provided.
|
||||
fn create_substs_for_ast_path(&self,
|
||||
rscope: &RegionScope,
|
||||
span: Span,
|
||||
def_id: DefId,
|
||||
parameters: &hir::PathParameters,
|
||||
|
@ -357,11 +329,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
// A provided type parameter.
|
||||
match *parameters {
|
||||
hir::AngleBracketedParameters(ref data) => {
|
||||
self.ast_ty_arg_to_ty(rscope, Some(def), substs, &data.types[i])
|
||||
self.ast_ty_to_ty(&data.types[i])
|
||||
}
|
||||
hir::ParenthesizedParameters(ref data) => {
|
||||
assert_eq!(i, 0);
|
||||
let (ty, assoc) = self.convert_parenthesized_parameters(substs, data);
|
||||
let (ty, assoc) = self.convert_parenthesized_parameters(data);
|
||||
output_assoc_binding = Some(assoc);
|
||||
ty
|
||||
}
|
||||
|
@ -406,7 +378,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
data.bindings.iter().map(|b| {
|
||||
ConvertedBinding {
|
||||
item_name: b.name,
|
||||
ty: self.ast_ty_to_ty(rscope, &b.ty),
|
||||
ty: self.ast_ty_to_ty(&b.ty),
|
||||
span: b.span
|
||||
}
|
||||
}).collect()
|
||||
|
@ -415,7 +387,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
vec![output_assoc_binding.unwrap_or_else(|| {
|
||||
// This is an error condition, but we should
|
||||
// get the associated type binding anyway.
|
||||
self.convert_parenthesized_parameters(substs, data).1
|
||||
self.convert_parenthesized_parameters(data).1
|
||||
})]
|
||||
}
|
||||
};
|
||||
|
@ -427,17 +399,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
}
|
||||
|
||||
fn convert_parenthesized_parameters(&self,
|
||||
region_substs: &[Kind<'tcx>],
|
||||
data: &hir::ParenthesizedParameterData)
|
||||
-> (Ty<'tcx>, ConvertedBinding<'tcx>)
|
||||
{
|
||||
let inputs = self.tcx().mk_type_list(data.inputs.iter().map(|a_t| {
|
||||
self.ast_ty_arg_to_ty(&ExplicitRscope, None, region_substs, a_t)
|
||||
self.ast_ty_to_ty(a_t)
|
||||
}));
|
||||
|
||||
let (output, output_span) = match data.output {
|
||||
Some(ref output_ty) => {
|
||||
(self.ast_ty_to_ty(&ExplicitRscope, output_ty), output_ty.span)
|
||||
(self.ast_ty_to_ty(output_ty), output_ty.span)
|
||||
}
|
||||
None => {
|
||||
(self.tcx().mk_nil(), data.span)
|
||||
|
@ -460,14 +431,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
/// If the `projections` argument is `None`, then assoc type bindings like `Foo<T=X>`
|
||||
/// are disallowed. Otherwise, they are pushed onto the vector given.
|
||||
pub fn instantiate_mono_trait_ref(&self,
|
||||
rscope: &RegionScope,
|
||||
trait_ref: &hir::TraitRef,
|
||||
self_ty: Ty<'tcx>)
|
||||
-> ty::TraitRef<'tcx>
|
||||
{
|
||||
let trait_def_id = self.trait_def_id(trait_ref);
|
||||
self.ast_path_to_mono_trait_ref(rscope,
|
||||
trait_ref.path.span,
|
||||
self.ast_path_to_mono_trait_ref(trait_ref.path.span,
|
||||
trait_def_id,
|
||||
self_ty,
|
||||
trait_ref.path.segments.last().unwrap())
|
||||
|
@ -488,7 +457,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
}
|
||||
|
||||
pub fn instantiate_poly_trait_ref(&self,
|
||||
rscope: &RegionScope,
|
||||
ast_trait_ref: &hir::PolyTraitRef,
|
||||
self_ty: Ty<'tcx>,
|
||||
poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
|
||||
|
@ -498,16 +466,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
let trait_def_id = self.trait_def_id(trait_ref);
|
||||
|
||||
debug!("ast_path_to_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id);
|
||||
// The trait reference introduces a binding level here, so
|
||||
// we need to shift the `rscope`. It'd be nice if we could
|
||||
// do away with this rscope stuff and work this knowledge
|
||||
// into resolve_lifetimes, as we do with non-omitted
|
||||
// lifetimes. Oh well, not there yet.
|
||||
let shifted_rscope = &ShiftedRscope::new(rscope);
|
||||
|
||||
let (substs, assoc_bindings) =
|
||||
self.create_substs_for_ast_trait_ref(shifted_rscope,
|
||||
trait_ref.path.span,
|
||||
self.create_substs_for_ast_trait_ref(trait_ref.path.span,
|
||||
trait_def_id,
|
||||
self_ty,
|
||||
trait_ref.path.segments.last().unwrap());
|
||||
|
@ -528,7 +489,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
}
|
||||
|
||||
fn ast_path_to_mono_trait_ref(&self,
|
||||
rscope: &RegionScope,
|
||||
span: Span,
|
||||
trait_def_id: DefId,
|
||||
self_ty: Ty<'tcx>,
|
||||
|
@ -536,8 +496,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
-> ty::TraitRef<'tcx>
|
||||
{
|
||||
let (substs, assoc_bindings) =
|
||||
self.create_substs_for_ast_trait_ref(rscope,
|
||||
span,
|
||||
self.create_substs_for_ast_trait_ref(span,
|
||||
trait_def_id,
|
||||
self_ty,
|
||||
trait_segment);
|
||||
|
@ -546,7 +505,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
}
|
||||
|
||||
fn create_substs_for_ast_trait_ref(&self,
|
||||
rscope: &RegionScope,
|
||||
span: Span,
|
||||
trait_def_id: DefId,
|
||||
self_ty: Ty<'tcx>,
|
||||
|
@ -590,8 +548,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
}
|
||||
}
|
||||
|
||||
self.create_substs_for_ast_path(rscope,
|
||||
span,
|
||||
self.create_substs_for_ast_path(span,
|
||||
trait_def_id,
|
||||
&trait_segment.parameters,
|
||||
Some(self_ty))
|
||||
|
@ -700,7 +657,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
}
|
||||
|
||||
fn ast_path_to_ty(&self,
|
||||
rscope: &RegionScope,
|
||||
span: Span,
|
||||
did: DefId,
|
||||
item_segment: &hir::PathSegment)
|
||||
|
@ -714,8 +670,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
}
|
||||
};
|
||||
|
||||
let substs = self.ast_path_substs_for_ty(rscope,
|
||||
span,
|
||||
let substs = self.ast_path_substs_for_ty(span,
|
||||
did,
|
||||
item_segment);
|
||||
|
||||
|
@ -737,7 +692,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
}
|
||||
|
||||
fn conv_object_ty_poly_trait_ref(&self,
|
||||
rscope: &RegionScope,
|
||||
span: Span,
|
||||
trait_bounds: &[hir::PolyTraitRef],
|
||||
lifetime: &hir::Lifetime)
|
||||
|
@ -753,8 +707,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
|
||||
let mut projection_bounds = vec![];
|
||||
let dummy_self = tcx.mk_ty(TRAIT_OBJECT_DUMMY_SELF);
|
||||
let principal = self.instantiate_poly_trait_ref(rscope,
|
||||
&trait_bounds[0],
|
||||
let principal = self.instantiate_poly_trait_ref(&trait_bounds[0],
|
||||
dummy_self,
|
||||
&mut projection_bounds);
|
||||
|
||||
|
@ -839,15 +792,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
self.ast_region_to_region(lifetime, None)
|
||||
} else {
|
||||
self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| {
|
||||
tcx.mk_region(match rscope.object_lifetime_default(span) {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
span_err!(self.tcx().sess, span, E0228,
|
||||
if tcx.named_region_map.defs.contains_key(&lifetime.id) {
|
||||
self.ast_region_to_region(lifetime, None)
|
||||
} else {
|
||||
self.re_infer(span, None).unwrap_or_else(|| {
|
||||
span_err!(tcx.sess, span, E0228,
|
||||
"the lifetime bound for this object type cannot be deduced \
|
||||
from context; please supply an explicit bound");
|
||||
ty::ReStatic
|
||||
}
|
||||
})
|
||||
tcx.mk_region(ty::ReStatic)
|
||||
})
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
|
@ -1059,7 +1013,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
}
|
||||
|
||||
fn qpath_to_ty(&self,
|
||||
rscope: &RegionScope,
|
||||
span: Span,
|
||||
opt_self_ty: Option<Ty<'tcx>>,
|
||||
trait_def_id: DefId,
|
||||
|
@ -1084,8 +1037,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
|
||||
debug!("qpath_to_ty: self_type={:?}", self_ty);
|
||||
|
||||
let trait_ref = self.ast_path_to_mono_trait_ref(rscope,
|
||||
span,
|
||||
let trait_ref = self.ast_path_to_mono_trait_ref(span,
|
||||
trait_def_id,
|
||||
self_ty,
|
||||
trait_segment);
|
||||
|
@ -1095,38 +1047,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
self.projected_ty(span, trait_ref, item_segment.name)
|
||||
}
|
||||
|
||||
/// Convert a type supplied as value for a type argument from AST into our
|
||||
/// our internal representation. This is the same as `ast_ty_to_ty` but that
|
||||
/// it applies the object lifetime default.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `this`, `rscope`: the surrounding context
|
||||
/// * `def`: the type parameter being instantiated (if available)
|
||||
/// * `region_substs`: a partial substitution consisting of
|
||||
/// only the region type parameters being supplied to this type.
|
||||
/// * `ast_ty`: the ast representation of the type being supplied
|
||||
fn ast_ty_arg_to_ty(&self,
|
||||
rscope: &RegionScope,
|
||||
def: Option<&ty::TypeParameterDef<'tcx>>,
|
||||
region_substs: &[Kind<'tcx>],
|
||||
ast_ty: &hir::Ty)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
let tcx = self.tcx();
|
||||
|
||||
if let Some(def) = def {
|
||||
let object_lifetime_default = def.object_lifetime_default.subst(tcx, region_substs);
|
||||
let rscope1 = &ObjectLifetimeDefaultRscope::new(rscope, object_lifetime_default);
|
||||
self.ast_ty_to_ty(rscope1, ast_ty)
|
||||
} else {
|
||||
self.ast_ty_to_ty(rscope, ast_ty)
|
||||
}
|
||||
}
|
||||
|
||||
// Check a type Path and convert it to a Ty.
|
||||
pub fn def_to_ty(&self,
|
||||
rscope: &RegionScope,
|
||||
opt_self_ty: Option<Ty<'tcx>>,
|
||||
path: &hir::Path,
|
||||
permit_variants: bool)
|
||||
|
@ -1141,15 +1063,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => {
|
||||
assert_eq!(opt_self_ty, None);
|
||||
tcx.prohibit_type_params(path.segments.split_last().unwrap().1);
|
||||
self.ast_path_to_ty(rscope, span, did, path.segments.last().unwrap())
|
||||
self.ast_path_to_ty(span, did, path.segments.last().unwrap())
|
||||
}
|
||||
Def::Variant(did) if permit_variants => {
|
||||
// Convert "variant type" as if it were a real type.
|
||||
// The resulting `Ty` is type of the variant's enum for now.
|
||||
assert_eq!(opt_self_ty, None);
|
||||
tcx.prohibit_type_params(path.segments.split_last().unwrap().1);
|
||||
self.ast_path_to_ty(rscope,
|
||||
span,
|
||||
self.ast_path_to_ty(span,
|
||||
tcx.parent_def_id(did).unwrap(),
|
||||
path.segments.last().unwrap())
|
||||
}
|
||||
|
@ -1207,8 +1128,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
Def::AssociatedTy(def_id) => {
|
||||
tcx.prohibit_type_params(&path.segments[..path.segments.len()-2]);
|
||||
let trait_did = tcx.parent_def_id(def_id).unwrap();
|
||||
self.qpath_to_ty(rscope,
|
||||
span,
|
||||
self.qpath_to_ty(span,
|
||||
opt_self_ty,
|
||||
trait_did,
|
||||
&path.segments[path.segments.len()-2],
|
||||
|
@ -1228,7 +1148,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
|
||||
/// Parses the programmer's textual representation of a type into our
|
||||
/// internal notion of a type.
|
||||
pub fn ast_ty_to_ty(&self, rscope: &RegionScope, ast_ty: &hir::Ty) -> Ty<'tcx> {
|
||||
pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
|
||||
debug!("ast_ty_to_ty(id={:?}, ast_ty={:?})",
|
||||
ast_ty.id, ast_ty);
|
||||
|
||||
|
@ -1241,29 +1161,25 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
|
||||
let result_ty = match ast_ty.node {
|
||||
hir::TySlice(ref ty) => {
|
||||
tcx.mk_slice(self.ast_ty_to_ty(rscope, &ty))
|
||||
tcx.mk_slice(self.ast_ty_to_ty(&ty))
|
||||
}
|
||||
hir::TyPtr(ref mt) => {
|
||||
tcx.mk_ptr(ty::TypeAndMut {
|
||||
ty: self.ast_ty_to_ty(rscope, &mt.ty),
|
||||
ty: self.ast_ty_to_ty(&mt.ty),
|
||||
mutbl: mt.mutbl
|
||||
})
|
||||
}
|
||||
hir::TyRptr(ref region, ref mt) => {
|
||||
let r = self.ast_region_to_region(region, None);
|
||||
debug!("TyRef r={:?}", r);
|
||||
let rscope1 =
|
||||
&ObjectLifetimeDefaultRscope::new(
|
||||
rscope,
|
||||
ty::ObjectLifetimeDefault::Specific(r));
|
||||
let t = self.ast_ty_to_ty(rscope1, &mt.ty);
|
||||
let t = self.ast_ty_to_ty(&mt.ty);
|
||||
tcx.mk_ref(r, ty::TypeAndMut {ty: t, mutbl: mt.mutbl})
|
||||
}
|
||||
hir::TyNever => {
|
||||
tcx.types.never
|
||||
},
|
||||
hir::TyTup(ref fields) => {
|
||||
tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(rscope, &t)))
|
||||
tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(&t)))
|
||||
}
|
||||
hir::TyBareFn(ref bf) => {
|
||||
require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
|
||||
|
@ -1309,7 +1225,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
tcx.mk_fn_ptr(bare_fn_ty)
|
||||
}
|
||||
hir::TyTraitObject(ref bounds, ref lifetime) => {
|
||||
self.conv_object_ty_poly_trait_ref(rscope, ast_ty.span, bounds, lifetime)
|
||||
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime)
|
||||
}
|
||||
hir::TyImplTrait(ref bounds) => {
|
||||
use collect::{compute_bounds, SizedByDefault};
|
||||
|
@ -1381,13 +1297,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
hir::TyPath(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
|
||||
debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path);
|
||||
let opt_self_ty = maybe_qself.as_ref().map(|qself| {
|
||||
self.ast_ty_to_ty(rscope, qself)
|
||||
self.ast_ty_to_ty(qself)
|
||||
});
|
||||
self.def_to_ty(rscope, opt_self_ty, path, false)
|
||||
self.def_to_ty(opt_self_ty, path, false)
|
||||
}
|
||||
hir::TyPath(hir::QPath::TypeRelative(ref qself, ref segment)) => {
|
||||
debug!("ast_ty_to_ty: qself={:?} segment={:?}", qself, segment);
|
||||
let ty = self.ast_ty_to_ty(rscope, qself);
|
||||
let ty = self.ast_ty_to_ty(qself);
|
||||
|
||||
let def = if let hir::TyPath(hir::QPath::Resolved(_, ref path)) = qself.node {
|
||||
path.def
|
||||
|
@ -1398,7 +1314,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
}
|
||||
hir::TyArray(ref ty, length) => {
|
||||
if let Ok(length) = eval_length(tcx.global_tcx(), length, "array length") {
|
||||
tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), length)
|
||||
tcx.mk_array(self.ast_ty_to_ty(&ty), length)
|
||||
} else {
|
||||
self.tcx().types.err
|
||||
}
|
||||
|
@ -1426,7 +1342,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
}
|
||||
|
||||
pub fn ty_of_arg(&self,
|
||||
rscope: &RegionScope,
|
||||
ty: &hir::Ty,
|
||||
expected_ty: Option<Ty<'tcx>>)
|
||||
-> Ty<'tcx>
|
||||
|
@ -1434,7 +1349,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
match ty.node {
|
||||
hir::TyInfer if expected_ty.is_some() => expected_ty.unwrap(),
|
||||
hir::TyInfer => self.ty_infer(ty.span),
|
||||
_ => self.ast_ty_to_ty(rscope, ty),
|
||||
_ => self.ast_ty_to_ty(ty),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1446,10 +1361,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
debug!("ty_of_fn");
|
||||
|
||||
let input_tys: Vec<Ty> =
|
||||
decl.inputs.iter().map(|a| self.ty_of_arg(&ExplicitRscope, a, None)).collect();
|
||||
decl.inputs.iter().map(|a| self.ty_of_arg(a, None)).collect();
|
||||
|
||||
let output_ty = match decl.output {
|
||||
hir::Return(ref output) => self.ast_ty_to_ty(&ExplicitRscope, output),
|
||||
hir::Return(ref output) => self.ast_ty_to_ty(output),
|
||||
hir::DefaultReturn(..) => self.tcx().mk_nil(),
|
||||
};
|
||||
|
||||
|
@ -1486,7 +1401,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
None
|
||||
}
|
||||
});
|
||||
self.ty_of_arg(&ExplicitRscope, a, expected_arg_ty)
|
||||
self.ty_of_arg(a, expected_arg_ty)
|
||||
});
|
||||
|
||||
let expected_ret_ty = expected_sig.as_ref().map(|e| e.output());
|
||||
|
@ -1502,7 +1417,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
expected_ret_ty.unwrap(),
|
||||
_ if is_infer => self.ty_infer(decl.output.span()),
|
||||
hir::Return(ref output) =>
|
||||
self.ast_ty_to_ty(&ExplicitRscope, &output),
|
||||
self.ast_ty_to_ty(&output),
|
||||
hir::DefaultReturn(..) => bug!(),
|
||||
};
|
||||
|
||||
|
|
|
@ -97,7 +97,6 @@ use rustc::ty::adjustment;
|
|||
use rustc::ty::fold::{BottomUpFolder, TypeFoldable};
|
||||
use rustc::ty::util::{Representability, IntTypeExt};
|
||||
use require_c_abi_if_variadic;
|
||||
use rscope::RegionScope;
|
||||
use session::{Session, CompileResult};
|
||||
use CrateCtxt;
|
||||
use TypeAndSubsts;
|
||||
|
@ -1411,12 +1410,12 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
fn re_infer(&self, span: Span, def: Option<&ty::RegionParameterDef>)
|
||||
-> &'tcx ty::Region {
|
||||
-> Option<&'tcx ty::Region> {
|
||||
let v = match def {
|
||||
Some(def) => infer::EarlyBoundRegion(span, def.name),
|
||||
None => infer::MiscVariable(span)
|
||||
};
|
||||
self.next_region_var(v)
|
||||
Some(self.next_region_var(v))
|
||||
}
|
||||
|
||||
fn ty_infer(&self, span: Span) -> Ty<'tcx> {
|
||||
|
@ -1459,23 +1458,6 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> RegionScope for FnCtxt<'a, 'gcx, 'tcx> {
|
||||
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
|
||||
Some(self.base_object_lifetime_default(span))
|
||||
}
|
||||
|
||||
fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
|
||||
// RFC #599 specifies that object lifetime defaults take
|
||||
// precedence over other defaults. But within a fn body we
|
||||
// don't have a *default* region, rather we use inference to
|
||||
// find the *correct* region, which is strictly more general
|
||||
// (and anyway, within a fn body the right region may not even
|
||||
// be something the user can write explicitly, since it might
|
||||
// be some expression).
|
||||
*self.next_region_var(infer::MiscVariable(span))
|
||||
}
|
||||
}
|
||||
|
||||
/// Controls whether the arguments are tupled. This is used for the call
|
||||
/// operator.
|
||||
///
|
||||
|
@ -1832,7 +1814,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn to_ty(&self, ast_t: &hir::Ty) -> Ty<'tcx> {
|
||||
let t = AstConv::ast_ty_to_ty(self, self, ast_t);
|
||||
let t = AstConv::ast_ty_to_ty(self, ast_t);
|
||||
self.register_wf_obligation(t, ast_t.span, traits::MiscObligation);
|
||||
t
|
||||
}
|
||||
|
@ -3976,7 +3958,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
match *qpath {
|
||||
hir::QPath::Resolved(ref maybe_qself, ref path) => {
|
||||
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself));
|
||||
let ty = AstConv::def_to_ty(self, self, opt_self_ty, path, true);
|
||||
let ty = AstConv::def_to_ty(self, opt_self_ty, path, true);
|
||||
(path.def, ty)
|
||||
}
|
||||
hir::QPath::TypeRelative(ref qself, ref segment) => {
|
||||
|
@ -4411,7 +4393,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
if let Some(lifetime) = lifetimes.get(i) {
|
||||
AstConv::ast_region_to_region(self, lifetime, Some(def))
|
||||
} else {
|
||||
self.re_infer(span, Some(def))
|
||||
self.re_infer(span, Some(def)).unwrap()
|
||||
}
|
||||
}, |def, substs| {
|
||||
let mut i = def.index as usize;
|
||||
|
|
|
@ -68,10 +68,9 @@ use rustc::ty::subst::Substs;
|
|||
use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContainer};
|
||||
use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
|
||||
use rustc::ty::util::IntTypeExt;
|
||||
use rscope::*;
|
||||
use rustc::dep_graph::DepNode;
|
||||
use util::common::{ErrorReported, MemoizationMap};
|
||||
use util::nodemap::{NodeMap, FxHashMap, FxHashSet};
|
||||
use util::nodemap::{NodeMap, FxHashMap};
|
||||
use CrateCtxt;
|
||||
|
||||
use rustc_const_math::ConstInt;
|
||||
|
@ -373,8 +372,8 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
|
|||
}
|
||||
|
||||
impl<'a,'tcx> ItemCtxt<'a,'tcx> {
|
||||
fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &hir::Ty) -> Ty<'tcx> {
|
||||
AstConv::ast_ty_to_ty(self, rs, ast_ty)
|
||||
fn to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
|
||||
AstConv::ast_ty_to_ty(self, ast_ty)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -437,9 +436,9 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
|
|||
None
|
||||
}
|
||||
|
||||
fn re_infer(&self, span: Span, _def: Option<&ty::RegionParameterDef>)
|
||||
-> &'tcx ty::Region {
|
||||
span_bug!(span, "unelided lifetime in signature");
|
||||
fn re_infer(&self, _span: Span, _def: Option<&ty::RegionParameterDef>)
|
||||
-> Option<&'tcx ty::Region> {
|
||||
None
|
||||
}
|
||||
|
||||
fn ty_infer(&self, span: Span) -> Ty<'tcx> {
|
||||
|
@ -631,7 +630,7 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
field: &hir::StructField,
|
||||
ty_f: &'tcx ty::FieldDef)
|
||||
{
|
||||
let tt = ccx.icx(struct_predicates).to_ty(&ExplicitRscope, &field.ty);
|
||||
let tt = ccx.icx(struct_predicates).to_ty(&field.ty);
|
||||
ccx.tcx.item_types.borrow_mut().insert(ty_f.did, tt);
|
||||
|
||||
let def_id = ccx.tcx.hir.local_def_id(field.id);
|
||||
|
@ -757,7 +756,6 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
|
|||
hir::ItemDefaultImpl(_, ref ast_trait_ref) => {
|
||||
let trait_ref =
|
||||
AstConv::instantiate_mono_trait_ref(&ccx.icx(&()),
|
||||
&ExplicitRscope,
|
||||
ast_trait_ref,
|
||||
tcx.mk_self_type());
|
||||
|
||||
|
@ -779,12 +777,11 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
|
|||
|
||||
debug!("convert: impl_bounds={:?}", ty_predicates);
|
||||
|
||||
let selfty = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, &selfty);
|
||||
let selfty = ccx.icx(&ty_predicates).to_ty(&selfty);
|
||||
tcx.item_types.borrow_mut().insert(def_id, selfty);
|
||||
|
||||
let trait_ref = opt_trait_ref.as_ref().map(|ast_trait_ref| {
|
||||
AstConv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates),
|
||||
&ExplicitRscope,
|
||||
ast_trait_ref,
|
||||
selfty)
|
||||
});
|
||||
|
@ -850,8 +847,7 @@ fn convert_trait_item(ccx: &CrateCtxt, trait_item: &hir::TraitItem) {
|
|||
hir::TraitItemKind::Const(ref ty, _) => {
|
||||
let const_def_id = ccx.tcx.hir.local_def_id(trait_item.id);
|
||||
generics_of_def_id(ccx, const_def_id);
|
||||
let ty = ccx.icx(&trait_predicates)
|
||||
.to_ty(&ExplicitRscope, &ty);
|
||||
let ty = ccx.icx(&trait_predicates).to_ty(&ty);
|
||||
tcx.item_types.borrow_mut().insert(const_def_id, ty);
|
||||
convert_associated_const(ccx, TraitContainer(trait_def_id),
|
||||
trait_item.id, ty);
|
||||
|
@ -862,7 +858,7 @@ fn convert_trait_item(ccx: &CrateCtxt, trait_item: &hir::TraitItem) {
|
|||
generics_of_def_id(ccx, type_def_id);
|
||||
|
||||
let typ = opt_ty.as_ref().map({
|
||||
|ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty)
|
||||
|ty| ccx.icx(&trait_predicates).to_ty(&ty)
|
||||
});
|
||||
|
||||
convert_associated_type(ccx, TraitContainer(trait_def_id), trait_item.id, typ);
|
||||
|
@ -887,8 +883,7 @@ fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) {
|
|||
hir::ImplItemKind::Const(ref ty, _) => {
|
||||
let const_def_id = ccx.tcx.hir.local_def_id(impl_item.id);
|
||||
generics_of_def_id(ccx, const_def_id);
|
||||
let ty = ccx.icx(&impl_predicates)
|
||||
.to_ty(&ExplicitRscope, &ty);
|
||||
let ty = ccx.icx(&impl_predicates).to_ty(&ty);
|
||||
tcx.item_types.borrow_mut().insert(const_def_id, ty);
|
||||
convert_associated_const(ccx, ImplContainer(impl_def_id),
|
||||
impl_item.id, ty);
|
||||
|
@ -903,7 +898,7 @@ fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) {
|
|||
"associated types are not allowed in inherent impls");
|
||||
}
|
||||
|
||||
let typ = ccx.icx(&impl_predicates).to_ty(&ExplicitRscope, ty);
|
||||
let typ = ccx.icx(&impl_predicates).to_ty(ty);
|
||||
|
||||
convert_associated_type(ccx, ImplContainer(impl_def_id), impl_item.id, Some(typ));
|
||||
}
|
||||
|
@ -1410,7 +1405,6 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
def_id: tcx.hir.local_def_id(param_id),
|
||||
default_def_id: tcx.hir.local_def_id(parent),
|
||||
default: None,
|
||||
object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault,
|
||||
pure_wrt_drop: false,
|
||||
};
|
||||
tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone());
|
||||
|
@ -1463,7 +1457,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
let type_start = own_start + regions.len() as u32;
|
||||
let types = ast_generics.ty_params.iter().enumerate().map(|(i, p)| {
|
||||
let i = type_start + i as u32;
|
||||
get_or_create_type_parameter_def(ccx, ast_generics, i, p, allow_defaults)
|
||||
get_or_create_type_parameter_def(ccx, i, p, allow_defaults)
|
||||
});
|
||||
let mut types: Vec<_> = opt_self.into_iter().chain(types).collect();
|
||||
|
||||
|
@ -1478,24 +1472,11 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
def_id: def_id,
|
||||
default_def_id: parent_def_id.unwrap(),
|
||||
default: None,
|
||||
object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault,
|
||||
pure_wrt_drop: false,
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
// Debugging aid.
|
||||
if tcx.has_attr(def_id, "rustc_object_lifetime_default") {
|
||||
let object_lifetime_default_reprs: String =
|
||||
types.iter().map(|t| {
|
||||
match t.object_lifetime_default {
|
||||
ty::ObjectLifetimeDefault::Specific(r) => r.to_string(),
|
||||
d => format!("{:?}", d),
|
||||
}
|
||||
}).collect::<Vec<String>>().join(",");
|
||||
tcx.sess.span_err(tcx.hir.span(node_id), &object_lifetime_default_reprs);
|
||||
}
|
||||
|
||||
tcx.alloc_generics(ty::Generics {
|
||||
parent: parent_def_id,
|
||||
parent_regions: parent_regions,
|
||||
|
@ -1526,7 +1507,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
NodeItem(item) => {
|
||||
match item.node {
|
||||
ItemStatic(ref t, ..) | ItemConst(ref t, _) => {
|
||||
ccx.icx(&()).to_ty(&ExplicitRscope, &t)
|
||||
ccx.icx(&()).to_ty(&t)
|
||||
}
|
||||
ItemFn(ref decl, unsafety, _, abi, ref generics, _) => {
|
||||
let tofd = AstConv::ty_of_fn(&ccx.icx(generics), unsafety, abi, &decl);
|
||||
|
@ -1534,7 +1515,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
ccx.tcx.mk_fn_def(def_id, substs, tofd)
|
||||
}
|
||||
ItemTy(ref t, ref generics) => {
|
||||
ccx.icx(generics).to_ty(&ExplicitRscope, &t)
|
||||
ccx.icx(generics).to_ty(&t)
|
||||
}
|
||||
ItemEnum(ref ei, ref generics) => {
|
||||
let def = convert_enum_def(ccx, item, ei);
|
||||
|
@ -1575,7 +1556,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
fn_decl, generics, abi)
|
||||
}
|
||||
ForeignItemStatic(ref t, _) => {
|
||||
ccx.icx(&()).to_ty(&ExplicitRscope, t)
|
||||
ccx.icx(&()).to_ty(t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1771,7 +1752,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
|||
match predicate {
|
||||
&hir::WherePredicate::BoundPredicate(ref bound_pred) => {
|
||||
let ty = AstConv::ast_ty_to_ty(&ccx.icx(&(base_predicates, ast_generics)),
|
||||
&ExplicitRscope,
|
||||
&bound_pred.bounded_ty);
|
||||
|
||||
for bound in bound_pred.bounds.iter() {
|
||||
|
@ -1782,7 +1762,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
|||
let trait_ref =
|
||||
AstConv::instantiate_poly_trait_ref(&ccx.icx(&(base_predicates,
|
||||
ast_generics)),
|
||||
&ExplicitRscope,
|
||||
poly_trait_ref,
|
||||
ty,
|
||||
&mut projections);
|
||||
|
@ -1827,7 +1806,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
|||
}
|
||||
|
||||
fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
||||
ast_generics: &hir::Generics,
|
||||
index: u32,
|
||||
param: &hir::TyParam,
|
||||
allow_defaults: bool)
|
||||
|
@ -1840,11 +1818,7 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
|||
}
|
||||
|
||||
let default =
|
||||
param.default.as_ref().map(|def| ccx.icx(&()).to_ty(&ExplicitRscope, def));
|
||||
|
||||
let object_lifetime_default =
|
||||
compute_object_lifetime_default(ccx, param.id,
|
||||
¶m.bounds, &ast_generics.where_clause);
|
||||
param.default.as_ref().map(|def| ccx.icx(&()).to_ty(def));
|
||||
|
||||
let parent = tcx.hir.get_parent(param.id);
|
||||
|
||||
|
@ -1865,7 +1839,6 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
|||
def_id: ccx.tcx.hir.local_def_id(param.id),
|
||||
default_def_id: ccx.tcx.hir.local_def_id(parent),
|
||||
default: default,
|
||||
object_lifetime_default: object_lifetime_default,
|
||||
pure_wrt_drop: param.pure_wrt_drop,
|
||||
};
|
||||
|
||||
|
@ -1880,75 +1853,6 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
|||
def
|
||||
}
|
||||
|
||||
/// Scan the bounds and where-clauses on a parameter to extract bounds
|
||||
/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault`.
|
||||
/// This runs as part of computing the minimal type scheme, so we
|
||||
/// intentionally avoid just asking astconv to convert all the where
|
||||
/// clauses into a `ty::Predicate`. This is because that could induce
|
||||
/// artificial cycles.
|
||||
fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
||||
param_id: ast::NodeId,
|
||||
param_bounds: &[hir::TyParamBound],
|
||||
where_clause: &hir::WhereClause)
|
||||
-> ty::ObjectLifetimeDefault<'tcx>
|
||||
{
|
||||
let inline_bounds = from_bounds(ccx, param_bounds);
|
||||
let where_bounds = from_predicates(ccx, param_id, &where_clause.predicates);
|
||||
let all_bounds: FxHashSet<_> = inline_bounds.into_iter()
|
||||
.chain(where_bounds)
|
||||
.collect();
|
||||
return if all_bounds.len() > 1 {
|
||||
ty::ObjectLifetimeDefault::Ambiguous
|
||||
} else if all_bounds.len() == 0 {
|
||||
ty::ObjectLifetimeDefault::BaseDefault
|
||||
} else {
|
||||
ty::ObjectLifetimeDefault::Specific(
|
||||
all_bounds.into_iter().next().unwrap())
|
||||
};
|
||||
|
||||
fn from_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
||||
bounds: &[hir::TyParamBound])
|
||||
-> Vec<&'tcx ty::Region>
|
||||
{
|
||||
bounds.iter()
|
||||
.filter_map(|bound| {
|
||||
match *bound {
|
||||
hir::TraitTyParamBound(..) =>
|
||||
None,
|
||||
hir::RegionTyParamBound(ref lifetime) =>
|
||||
Some(AstConv::ast_region_to_region(&ccx.icx(&()), lifetime, None)),
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn from_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
||||
param_id: ast::NodeId,
|
||||
predicates: &[hir::WherePredicate])
|
||||
-> Vec<&'tcx ty::Region>
|
||||
{
|
||||
predicates.iter()
|
||||
.flat_map(|predicate| {
|
||||
match *predicate {
|
||||
hir::WherePredicate::BoundPredicate(ref data) => {
|
||||
if data.bound_lifetimes.is_empty() &&
|
||||
is_param(ccx.tcx, &data.bounded_ty, param_id)
|
||||
{
|
||||
from_bounds(ccx, &data.bounds).into_iter()
|
||||
} else {
|
||||
Vec::new().into_iter()
|
||||
}
|
||||
}
|
||||
hir::WherePredicate::RegionPredicate(..) |
|
||||
hir::WherePredicate::EqPredicate(..) => {
|
||||
Vec::new().into_iter()
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub enum SizedByDefault { Yes, No, }
|
||||
|
||||
/// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or
|
||||
|
@ -1978,8 +1882,7 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
|
|||
let mut projection_bounds = vec![];
|
||||
|
||||
let mut trait_bounds: Vec<_> = trait_bounds.iter().map(|&bound| {
|
||||
astconv.instantiate_poly_trait_ref(&ExplicitRscope,
|
||||
bound,
|
||||
astconv.instantiate_poly_trait_ref(bound,
|
||||
param_ty,
|
||||
&mut projection_bounds)
|
||||
}).collect();
|
||||
|
@ -2017,8 +1920,7 @@ fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>,
|
|||
match *bound {
|
||||
hir::TraitTyParamBound(ref tr, hir::TraitBoundModifier::None) => {
|
||||
let mut projections = Vec::new();
|
||||
let pred = astconv.instantiate_poly_trait_ref(&ExplicitRscope,
|
||||
tr,
|
||||
let pred = astconv.instantiate_poly_trait_ref(tr,
|
||||
param_ty,
|
||||
&mut projections);
|
||||
projections.into_iter()
|
||||
|
|
|
@ -127,7 +127,6 @@ pub mod diagnostics;
|
|||
|
||||
pub mod check;
|
||||
pub mod check_unused;
|
||||
mod rscope;
|
||||
mod astconv;
|
||||
pub mod collect;
|
||||
mod constrained_type_params;
|
||||
|
|
|
@ -1,113 +0,0 @@
|
|||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use rustc::ty;
|
||||
|
||||
use syntax_pos::Span;
|
||||
|
||||
/// Defines strategies for handling regions that are omitted. For
|
||||
/// example, if one writes the type `&Foo`, then the lifetime of
|
||||
/// this reference has been omitted. When converting this
|
||||
/// type, the generic functions in astconv will invoke `anon_region`
|
||||
/// on the provided region-scope to decide how to translate this
|
||||
/// omitted region.
|
||||
///
|
||||
/// It is not always legal to omit regions, therefore `anon_region`
|
||||
/// can return `Err(())` to indicate that this is not a scope in which
|
||||
/// regions can legally be omitted.
|
||||
pub trait RegionScope {
|
||||
/// If an object omits any explicit lifetime bound, and none can
|
||||
/// be derived from the object traits, what should we use? If
|
||||
/// `None` is returned, an explicit annotation is required.
|
||||
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region>;
|
||||
|
||||
/// The "base" default is the initial default for a scope. This is
|
||||
/// 'static except for in fn bodies, where it is a fresh inference
|
||||
/// variable. You shouldn't call this except for as part of
|
||||
/// computing `object_lifetime_default` (in particular, in legacy
|
||||
/// modes, it may not be relevant).
|
||||
fn base_object_lifetime_default(&self, span: Span) -> ty::Region;
|
||||
}
|
||||
|
||||
// A scope in which all regions must be explicitly named. This is used
|
||||
// for types that appear in structs and so on.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ExplicitRscope;
|
||||
|
||||
impl RegionScope for ExplicitRscope {
|
||||
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
|
||||
Some(self.base_object_lifetime_default(span))
|
||||
}
|
||||
|
||||
fn base_object_lifetime_default(&self, _span: Span) -> ty::Region {
|
||||
ty::ReStatic
|
||||
}
|
||||
}
|
||||
|
||||
/// A scope which overrides the default object lifetime but has no other effect.
|
||||
pub struct ObjectLifetimeDefaultRscope<'r> {
|
||||
base_scope: &'r (RegionScope+'r),
|
||||
default: ty::ObjectLifetimeDefault<'r>,
|
||||
}
|
||||
|
||||
impl<'r> ObjectLifetimeDefaultRscope<'r> {
|
||||
pub fn new(base_scope: &'r (RegionScope+'r),
|
||||
default: ty::ObjectLifetimeDefault<'r>)
|
||||
-> ObjectLifetimeDefaultRscope<'r>
|
||||
{
|
||||
ObjectLifetimeDefaultRscope {
|
||||
base_scope: base_scope,
|
||||
default: default,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'r> RegionScope for ObjectLifetimeDefaultRscope<'r> {
|
||||
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
|
||||
match self.default {
|
||||
ty::ObjectLifetimeDefault::Ambiguous =>
|
||||
None,
|
||||
|
||||
ty::ObjectLifetimeDefault::BaseDefault =>
|
||||
// NB: This behavior changed in Rust 1.3.
|
||||
Some(self.base_object_lifetime_default(span)),
|
||||
|
||||
ty::ObjectLifetimeDefault::Specific(r) =>
|
||||
Some(*r),
|
||||
}
|
||||
}
|
||||
|
||||
fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
|
||||
self.base_scope.base_object_lifetime_default(span)
|
||||
}
|
||||
}
|
||||
|
||||
/// A scope which simply shifts the Debruijn index of other scopes
|
||||
/// to account for binding levels.
|
||||
pub struct ShiftedRscope<'r> {
|
||||
base_scope: &'r (RegionScope+'r)
|
||||
}
|
||||
|
||||
impl<'r> ShiftedRscope<'r> {
|
||||
pub fn new(base_scope: &'r (RegionScope+'r)) -> ShiftedRscope<'r> {
|
||||
ShiftedRscope { base_scope: base_scope }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'r> RegionScope for ShiftedRscope<'r> {
|
||||
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
|
||||
self.base_scope.object_lifetime_default(span)
|
||||
.map(|r| ty::fold::shift_region(r, 1))
|
||||
}
|
||||
|
||||
fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
|
||||
ty::fold::shift_region(self.base_scope.base_object_lifetime_default(span), 1)
|
||||
}
|
||||
}
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
trait Test {
|
||||
fn foo(&self) { }
|
||||
}
|
||||
|
@ -23,6 +25,11 @@ struct Ref<'a,T:'a+?Sized> {
|
|||
r: &'a T
|
||||
}
|
||||
|
||||
struct Ref2<'a,'b,T:'a+'b+?Sized> {
|
||||
a: &'a T,
|
||||
b: &'b T
|
||||
}
|
||||
|
||||
struct SomeStruct<'a> {
|
||||
t: Ref<'a,Test>,
|
||||
u: Ref<'a,Test+'a>,
|
||||
|
@ -44,6 +51,17 @@ fn d<'a>(t: Ref<'a,Test+'a>, mut ss: SomeStruct<'a>) {
|
|||
ss.u = t;
|
||||
}
|
||||
|
||||
fn e<'a>(_: Ref<'a, Display+'static>) {}
|
||||
fn g<'a, 'b>(_: Ref2<'a, 'b, Display+'static>) {}
|
||||
|
||||
|
||||
fn main() {
|
||||
// Inside a function body, we can just infer all
|
||||
// lifetimes, to allow Ref<'tmp, Display+'static>
|
||||
// and Ref2<'tmp, 'tmp, Display+'static>.
|
||||
let x = &0 as &(Display+'static);
|
||||
let r: Ref<Display> = Ref { r: x };
|
||||
let r2: Ref2<Display> = Ref2 { a: x, b: x };
|
||||
e(r);
|
||||
g(r2);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
trait Test {
|
||||
fn foo(&self) { }
|
||||
}
|
||||
|
@ -40,6 +42,10 @@ fn d<'a>(t: &'a (Test+'a), mut ss: SomeStruct<'a>) {
|
|||
ss.u = t;
|
||||
}
|
||||
|
||||
fn e<'a>(_: &'a (Display+'static)) {}
|
||||
|
||||
fn main() {
|
||||
// Inside a function body, we can just infer both
|
||||
// lifetimes, to allow &'tmp (Display+'static).
|
||||
e(&0 as &Display);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue