diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs new file mode 100644 index 000000000000..8e55e067513f --- /dev/null +++ b/src/librustc/middle/resolve_lifetime.rs @@ -0,0 +1,132 @@ +//! Name resolution for lifetimes. +//! +//! Name resolution for lifetimes follows *much* simpler rules than the +//! full resolve. For example, lifetime names are never exported or +//! used between functions, and they operate in a purely top-down +//! way. Therefore, we break lifetime name resolution into a separate pass. + +use crate::hir::def_id::{DefId, LocalDefId}; +use crate::hir::{GenericParam, ItemLocalId}; +use crate::hir::{GenericParamKind, LifetimeParamKind}; +use crate::ty; + +use crate::util::nodemap::{FxHashMap, FxHashSet, HirIdMap, HirIdSet}; +use rustc_macros::HashStable; + +/// The origin of a named lifetime definition. +/// +/// This is used to prevent the usage of in-band lifetimes in `Fn`/`fn` syntax. +#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, HashStable)] +pub enum LifetimeDefOrigin { + // Explicit binders like `fn foo<'a>(x: &'a u8)` or elided like `impl Foo<&u32>` + ExplicitOrElided, + // In-band declarations like `fn foo(x: &'a u8)` + InBand, + // Some kind of erroneous origin + Error, +} + +impl LifetimeDefOrigin { + pub fn from_param(param: &GenericParam<'_>) -> Self { + match param.kind { + GenericParamKind::Lifetime { kind } => match kind { + LifetimeParamKind::InBand => LifetimeDefOrigin::InBand, + LifetimeParamKind::Explicit => LifetimeDefOrigin::ExplicitOrElided, + LifetimeParamKind::Elided => LifetimeDefOrigin::ExplicitOrElided, + LifetimeParamKind::Error => LifetimeDefOrigin::Error, + }, + _ => bug!("expected a lifetime param"), + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, HashStable)] +pub enum Region { + Static, + EarlyBound(/* index */ u32, /* lifetime decl */ DefId, LifetimeDefOrigin), + LateBound(ty::DebruijnIndex, /* lifetime decl */ DefId, LifetimeDefOrigin), + LateBoundAnon(ty::DebruijnIndex, /* anon index */ u32), + Free(DefId, /* lifetime decl */ DefId), +} + +/// 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, HashStable)] +pub enum Set1 { + Empty, + One(T), + Many, +} + +impl Set1 { + pub fn insert(&mut self, value: T) { + *self = match self { + Set1::Empty => Set1::One(value), + Set1::One(old) if *old == value => return, + _ => Set1::Many, + }; + } +} + +pub type ObjectLifetimeDefault = Set1; + +/// Maps the id of each lifetime reference to the lifetime decl +/// that it corresponds to. +#[derive(HashStable)] +pub struct ResolveLifetimes { + defs: FxHashMap>, + late_bound: FxHashMap>, + object_lifetime_defaults: + FxHashMap>>, +} + +impl ResolveLifetimes { + pub fn new( + defs: HirIdMap, + late_bound: HirIdSet, + object_lifetime_defaults: HirIdMap>, + ) -> Self { + let defs = { + let mut map = FxHashMap::<_, FxHashMap<_, _>>::default(); + for (hir_id, v) in defs { + let map = map.entry(hir_id.owner_local_def_id()).or_default(); + map.insert(hir_id.local_id, v); + } + map + }; + let late_bound = { + let mut map = FxHashMap::<_, FxHashSet<_>>::default(); + for hir_id in late_bound { + let map = map.entry(hir_id.owner_local_def_id()).or_default(); + map.insert(hir_id.local_id); + } + map + }; + let object_lifetime_defaults = { + let mut map = FxHashMap::<_, FxHashMap<_, _>>::default(); + for (hir_id, v) in object_lifetime_defaults { + let map = map.entry(hir_id.owner_local_def_id()).or_default(); + map.insert(hir_id.local_id, v); + } + map + }; + + Self { defs, late_bound, object_lifetime_defaults } + } + + pub fn named_region_map(&self, id: &LocalDefId) -> Option<&FxHashMap> { + self.defs.get(id) + } + + pub fn is_late_bound_map(&self, id: &LocalDefId) -> Option<&FxHashSet> { + self.late_bound.get(id) + } + + pub fn object_lifetime_defaults_map( + &self, + id: &LocalDefId, + ) -> Option<&FxHashMap>> { + self.object_lifetime_defaults.get(id) + } +} diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 57fd2fb6d278..f519d5ab50a4 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -10,7 +10,7 @@ use rustc::hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc::hir::lowering::lower_crate; use rustc::lint; use rustc::middle::cstore::{CrateStore, MetadataLoader, MetadataLoaderDyn}; -use rustc::middle::{self, resolve_lifetime, stability}; +use rustc::middle::{self, stability}; use rustc::session::config::{self, CrateType, Input, OutputFilenames, OutputType}; use rustc::session::config::{PpMode, PpSourceMode}; use rustc::session::search_paths::PathKind; @@ -678,13 +678,13 @@ pub fn default_provide(providers: &mut ty::query::Providers<'_>) { plugin::build::provide(providers); hir::provide(providers); mir::provide(providers); - resolve_lifetime::provide(providers); rustc_privacy::provide(providers); typeck::provide(providers); ty::provide(providers); traits::provide(providers); stability::provide(providers); rustc_passes::provide(providers); + rustc_resolve::provide(providers); rustc_traits::provide(providers); middle::region::provide(providers); rustc_metadata::provide(providers); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 357176ae090c..4daf22d1b2bb 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -16,6 +16,13 @@ #![feature(nll)] #![recursion_limit = "256"] +#[macro_use] +extern crate rustc; +#[macro_use] +extern crate log; +#[macro_use] +extern crate syntax; + pub use rustc::hir::def::{Namespace, PerNS}; use Determinacy::*; @@ -30,6 +37,7 @@ use rustc::lint; use rustc::middle::cstore::{CrateStore, MetadataLoaderDyn}; use rustc::session::Session; use rustc::span_bug; +use rustc::ty::query::Providers; use rustc::ty::{self, DefIdTree, ResolverOutputs}; use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap, NodeSet}; @@ -74,6 +82,7 @@ mod def_collector; mod diagnostics; mod imports; mod late; +mod lifetimes; mod macros; enum Weak { @@ -3089,3 +3098,7 @@ impl CrateLint { } } } + +pub fn provide(providers: &mut Providers<'_>) { + lifetimes::provide(providers); +} diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs index 5f8a58636c08..3bcd104246d0 100644 --- a/src/librustc_resolve/lifetimes.rs +++ b/src/librustc_resolve/lifetimes.rs @@ -5,17 +5,16 @@ //! used between functions, and they operate in a purely top-down //! way. Therefore, we break lifetime name resolution into a separate pass. -use crate::hir::def::{DefKind, Res}; -use crate::hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; -use crate::hir::map::Map; -use crate::hir::{GenericArg, GenericParam, ItemLocalId, LifetimeName, Node, ParamName, QPath}; -use crate::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt}; +use rustc::hir::def::{DefKind, Res}; +use rustc::hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; +use rustc::hir::map::Map; +use rustc::hir::{GenericArg, GenericParam, LifetimeName, Node, ParamName, QPath}; +use rustc::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt}; -use crate::rustc::lint; -use crate::session::Session; -use crate::util::nodemap::{DefIdMap, FxHashMap, FxHashSet, HirIdMap, HirIdSet}; use errors::{pluralize, Applicability, DiagnosticBuilder}; -use rustc_macros::HashStable; +use rustc::lint; +use rustc::session::Session; +use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet, HirIdMap, HirIdSet}; use std::borrow::Cow; use std::cell::Cell; use std::mem::{replace, take}; @@ -24,38 +23,12 @@ use syntax::attr; use syntax::symbol::{kw, sym}; use syntax_pos::Span; -use crate::hir::intravisit::{self, NestedVisitorMap, Visitor}; -use crate::hir::{self, GenericParamKind, LifetimeParamKind}; +use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc::hir::{self, GenericParamKind, LifetimeParamKind}; +use rustc::middle::resolve_lifetime::*; use rustc_error_codes::*; -/// The origin of a named lifetime definition. -/// -/// This is used to prevent the usage of in-band lifetimes in `Fn`/`fn` syntax. -#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, HashStable)] -pub enum LifetimeDefOrigin { - // Explicit binders like `fn foo<'a>(x: &'a u8)` or elided like `impl Foo<&u32>` - ExplicitOrElided, - // In-band declarations like `fn foo(x: &'a u8)` - InBand, - // Some kind of erroneous origin - Error, -} - -impl LifetimeDefOrigin { - fn from_param(param: &GenericParam<'_>) -> Self { - match param.kind { - GenericParamKind::Lifetime { kind } => match kind { - LifetimeParamKind::InBand => LifetimeDefOrigin::InBand, - LifetimeParamKind::Explicit => LifetimeDefOrigin::ExplicitOrElided, - LifetimeParamKind::Elided => LifetimeDefOrigin::ExplicitOrElided, - LifetimeParamKind::Error => LifetimeDefOrigin::Error, - }, - _ => bug!("expected a lifetime param"), - } - } -} - // This counts the no of times a lifetime is used #[derive(Clone, Copy, Debug)] pub enum LifetimeUseSet<'tcx> { @@ -63,16 +36,25 @@ pub enum LifetimeUseSet<'tcx> { Many, } -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, HashStable)] -pub enum Region { - Static, - EarlyBound(/* index */ u32, /* lifetime decl */ DefId, LifetimeDefOrigin), - LateBound(ty::DebruijnIndex, /* lifetime decl */ DefId, LifetimeDefOrigin), - LateBoundAnon(ty::DebruijnIndex, /* anon index */ u32), - Free(DefId, /* lifetime decl */ DefId), +trait RegionExt { + fn early(hir_map: &Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region); + + fn late(hir_map: &Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region); + + fn late_anon(index: &Cell) -> Region; + + fn id(&self) -> Option; + + fn shifted(self, amount: u32) -> Region; + + fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region; + + fn subst<'a, L>(self, params: L, map: &NamedRegionMap) -> Option + where + L: Iterator; } -impl Region { +impl RegionExt for Region { fn early(hir_map: &Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region) { let i = *index; *index += 1; @@ -146,28 +128,6 @@ impl Region { } } -/// 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, HashStable)] -pub enum Set1 { - Empty, - One(T), - Many, -} - -impl Set1 { - pub fn insert(&mut self, value: T) { - *self = match self { - Set1::Empty => Set1::One(value), - Set1::One(old) if *old == value => return, - _ => Set1::Many, - }; - } -} - -pub type ObjectLifetimeDefault = Set1; - /// Maps the id of each lifetime reference to the lifetime decl /// that it corresponds to. /// @@ -178,25 +138,16 @@ pub type ObjectLifetimeDefault = Set1; struct NamedRegionMap { // maps from every use of a named (not anonymous) lifetime to a // `Region` describing how that region is bound - pub defs: HirIdMap, + defs: HirIdMap, // the set of lifetime def ids that are late-bound; a region can // be late-bound if (a) it does NOT appear in a where-clause and // (b) it DOES appear in the arguments. - pub late_bound: HirIdSet, + late_bound: HirIdSet, // For each type and trait definition, maps type parameters // to the trait object lifetime defaults computed from them. - pub object_lifetime_defaults: HirIdMap>, -} - -/// See [`NamedRegionMap`]. -#[derive(Default, HashStable)] -pub struct ResolveLifetimes { - defs: FxHashMap>, - late_bound: FxHashMap>, - object_lifetime_defaults: - FxHashMap>>, + object_lifetime_defaults: HirIdMap>, } struct LifetimeContext<'a, 'tcx> { @@ -323,17 +274,17 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { named_region_map: |tcx, id| { let id = LocalDefId::from_def_id(DefId::local(id)); // (*) - tcx.resolve_lifetimes(LOCAL_CRATE).defs.get(&id) + tcx.resolve_lifetimes(LOCAL_CRATE).named_region_map(&id) }, is_late_bound_map: |tcx, id| { let id = LocalDefId::from_def_id(DefId::local(id)); // (*) - tcx.resolve_lifetimes(LOCAL_CRATE).late_bound.get(&id) + tcx.resolve_lifetimes(LOCAL_CRATE).is_late_bound_map(&id) }, object_lifetime_defaults_map: |tcx, id| { let id = LocalDefId::from_def_id(DefId::local(id)); // (*) - tcx.resolve_lifetimes(LOCAL_CRATE).object_lifetime_defaults.get(&id) + tcx.resolve_lifetimes(LOCAL_CRATE).object_lifetime_defaults_map(&id) }, ..*providers @@ -351,21 +302,11 @@ fn resolve_lifetimes(tcx: TyCtxt<'_>, for_krate: CrateNum) -> &ResolveLifetimes let named_region_map = krate(tcx); - let mut rl = ResolveLifetimes::default(); - - for (hir_id, v) in named_region_map.defs { - let map = rl.defs.entry(hir_id.owner_local_def_id()).or_default(); - map.insert(hir_id.local_id, v); - } - for hir_id in named_region_map.late_bound { - let map = rl.late_bound.entry(hir_id.owner_local_def_id()).or_default(); - map.insert(hir_id.local_id); - } - for (hir_id, v) in named_region_map.object_lifetime_defaults { - let map = rl.object_lifetime_defaults.entry(hir_id.owner_local_def_id()).or_default(); - map.insert(hir_id.local_id, v); - } - + let rl = ResolveLifetimes::new( + named_region_map.defs, + named_region_map.late_bound, + named_region_map.object_lifetime_defaults, + ); tcx.arena.alloc(rl) } @@ -2899,7 +2840,7 @@ fn insert_late_bound_lifetimes( } } -pub fn report_missing_lifetime_specifiers( +fn report_missing_lifetime_specifiers( sess: &Session, span: Span, count: usize,