提交 4eac052a 编写于 作者: E Eduard-Mihai Burtescu

rustc: move object default lifetimes to resolve_lifetimes.

上级 c5befdc6
......@@ -28,6 +28,7 @@
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 @@ fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
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 @@ fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> 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 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 @@ fn from_depth(self, depth: u32) -> 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 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
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 @@ fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
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 @@ fn visit_poly_trait_ref(&mut self,
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 check_if_label_shadows_lifetime<'a>(sess: &'a Session,
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 check_if_label_shadows_lifetime<'a>(sess: &'a Session,
}
}
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, &param.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 @@ fn with<F>(&mut self, wrap_scope: Scope, f: F) where
{
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 @@ fn with<F>(&mut self, wrap_scope: Scope, f: F) where
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 @@ fn resolve_lifetime_ref(&mut self, lifetime_ref: &hir::Lifetime) {
}
}
Scope::Elision { s, .. } => {
Scope::Elision { s, .. } |
Scope::ObjectLifetimeDefault { s, .. } => {
scope = s;
}
}
......@@ -763,6 +922,109 @@ fn resolve_lifetime_ref(&mut self, lifetime_ref: &hir::Lifetime) {
}
}
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(&lt) = 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 @@ fn visit_ty(&mut self, ty: &hir::Ty) {
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 @@ fn resolve_elided_lifetimes(&mut self, lifetime_refs: &[hir::Lifetime]) {
}
return;
}
Scope::ObjectLifetimeDefault { s, .. } => {
scope = s;
}
}
};
......@@ -1134,6 +1412,28 @@ fn report_elision_failure(&mut self,
}
}
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 @@ fn check_lifetime_def_for_shadowing(&self,
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 @@ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
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 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
}
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::{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 @@ fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize) {
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::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 @@ pub fn generics_own_param_counts(&self, item_id: DefIndex) -> (usize, usize) {
(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 @@ fn encode_generics(&mut self, def_id: DefId) -> Lazy<Generics<'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 @@ fn encode_generics(&mut self, def_id: DefId) -> Lazy<Generics<'tcx>> {
regions: regions,
types: types,
has_self: g.has_self,
object_lifetime_defaults: object_lifetime_defaults,
})
}
......
......@@ -16,6 +16,7 @@
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)]
......
此差异已折叠。
......@@ -97,7 +97,6 @@
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 @@ fn get_type_parameter_bounds(&self,
}
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 @@ fn set_tainted_by_errors(&self) {
}
}
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 @@ pub fn register_infer_ok_obligations<T>(&self, infer_ok: InferOk<'tcx, T>) -> T
}
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 @@ fn finish_resolving_struct_path(&self,
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 @@ pub fn instantiate_value_path(&self,
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::{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 @@ fn ensure_super_predicates(&self, span: Span, trait_def_id: DefId)
}
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 @@ fn get_free_substs(&self) -> Option<&Substs<'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,
&param.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 check;
pub mod check_unused;
mod rscope;
mod astconv;
pub mod collect;
mod constrained_type_params;
......
// 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);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册