From 4eac052a33f38688d582d3bb5242728f543a3c8f Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 25 Jan 2017 17:32:44 +0200 Subject: [PATCH] rustc: move object default lifetimes to resolve_lifetimes. --- src/librustc/middle/cstore.rs | 6 + src/librustc/middle/resolve_lifetime.rs | 343 ++++++++++++++++-- src/librustc/ty/mod.rs | 19 - src/librustc/ty/structural_impls.rs | 26 +- src/librustc/util/ppaux.rs | 10 - src/librustc_metadata/cstore_impl.rs | 7 + src/librustc_metadata/decoder.rs | 7 + src/librustc_metadata/encoder.rs | 7 + src/librustc_metadata/schema.rs | 2 + src/librustc_typeck/astconv.rs | 175 +++------ src/librustc_typeck/check/mod.rs | 28 +- src/librustc_typeck/collect.rs | 136 +------ src/librustc_typeck/lib.rs | 1 - src/librustc_typeck/rscope.rs | 113 ------ ...object-lifetime-default-from-ref-struct.rs | 18 + .../object-lifetime-default-from-rptr.rs | 6 + 16 files changed, 445 insertions(+), 459 deletions(-) delete mode 100644 src/librustc_typeck/rscope.rs diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 8cf13cddc8c7f..d11e6e3fc72bd 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -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; fn item_attrs(&self, def_id: DefId) -> Vec; 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 + { bug!("item_generics_object_lifetime_defaults") } fn item_attrs(&self, def_id: DefId) -> Vec { bug!("item_attrs") } fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef { bug!("trait_def") } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 88da47c2f0c44..88ef2c69a04dc 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -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 { + 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 { + Empty, + One(T), + Many +} + +impl Set1 { + 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; + // 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, + + // For each type and trait definition, maps type parameters + // to the trait object lifetime defaults computed from them. + pub object_lifetime_defaults: NodeMap>, } 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>, } #[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, + 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> { + 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::>().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 { + fn add_bounds(set: &mut Set1, 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(&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], output: Option<&'tcx P>) { 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; } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 36fc5149b40d8..6ea083b314fef 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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>, - 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 diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 0f0478bc8cdb0..56f5dbc735de4 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -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>(&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>(&self, visitor: &mut V) -> bool { - match *self { - ty::ObjectLifetimeDefault::Specific(r) => r.visit_with(visitor), - _ => false, - } + self.default.visit_with(visitor) } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index e90e1a94be951..0522ea90522c1 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -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() { diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 03b2b0114f19c..39581a4696088 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -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 { + 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 { self.dep_graph.read(DepNode::MetaData(def_id)); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index bfc4257bda013..dd44ef202dc27 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -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 { + 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)) } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index c407c27b096e1..028555d1df848 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -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, }) } diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 4f9f2d23f5d3e..91375d42823fb 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -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>, pub types: LazySeq>, pub has_self: bool, + pub object_lifetime_defaults: LazySeq, } #[derive(RustcEncodable, RustcDecodable)] diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 5c71947c2077e..56de539cbfe99 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -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` /// 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>) @@ -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>, 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>, 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> @@ -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 = - 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!(), }; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4d1b2cec32e5f..c2f32c2b52bbe 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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 { - 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; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 90e2f821b10b5..6f0825a25f947 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -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(&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::>().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() diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 90ce77cc5f4bc..4ed116b88f6d9 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -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; diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs deleted file mode 100644 index d982c91e388d1..0000000000000 --- a/src/librustc_typeck/rscope.rs +++ /dev/null @@ -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 or the MIT license -// , 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; - - /// 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 { - 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 { - 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 { - 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) - } -} diff --git a/src/test/run-pass/object-lifetime-default-from-ref-struct.rs b/src/test/run-pass/object-lifetime-default-from-ref-struct.rs index 910d933d46f08..6aaf892097136 100644 --- a/src/test/run-pass/object-lifetime-default-from-ref-struct.rs +++ b/src/test/run-pass/object-lifetime-default-from-ref-struct.rs @@ -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 = Ref { r: x }; + let r2: Ref2 = Ref2 { a: x, b: x }; + e(r); + g(r2); } diff --git a/src/test/run-pass/object-lifetime-default-from-rptr.rs b/src/test/run-pass/object-lifetime-default-from-rptr.rs index d9e0b22fbfa4b..cbff0d4dbaa3c 100644 --- a/src/test/run-pass/object-lifetime-default-from-rptr.rs +++ b/src/test/run-pass/object-lifetime-default-from-rptr.rs @@ -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); }