Skip to content

Implement underscore lifetimes #44691

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 22, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/librustc/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -2086,4 +2086,5 @@ register_diagnostics! {
E0566, // conflicting representation hints
E0623, // lifetime mismatch where both parameters are anonymous regions
E0628, // generators cannot have explicit arguments
E0637, // "'_" is not a valid lifetime bound
}
7 changes: 6 additions & 1 deletion src/librustc/hir/intravisit.rs
Original file line number Diff line number Diff line change
@@ -422,7 +422,12 @@ pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {

pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
visitor.visit_id(lifetime.id);
visitor.visit_name(lifetime.span, lifetime.name);
match lifetime.name {
LifetimeName::Name(name) => {
visitor.visit_name(lifetime.span, name);
}
LifetimeName::Static | LifetimeName::Implicit | LifetimeName::Underscore => {}
}
}

pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, lifetime_def: &'v LifetimeDef) {
8 changes: 6 additions & 2 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
@@ -1121,7 +1121,11 @@ impl<'a> LoweringContext<'a> {
fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
hir::Lifetime {
id: self.lower_node_id(l.id).node_id,
name: self.lower_ident(l.ident),
name: match self.lower_ident(l.ident) {
x if x == "'_" => hir::LifetimeName::Underscore,
x if x == "'static" => hir::LifetimeName::Static,
name => hir::LifetimeName::Name(name),
},
span: l.span,
}
}
@@ -3005,7 +3009,7 @@ impl<'a> LoweringContext<'a> {
hir::Lifetime {
id: self.next_id().node_id,
span,
name: keywords::Invalid.name()
name: hir::LifetimeName::Implicit,
}
}
}
2 changes: 1 addition & 1 deletion src/librustc/hir/map/mod.rs
Original file line number Diff line number Diff line change
@@ -805,7 +805,7 @@ impl<'hir> Map<'hir> {
NodeTraitItem(ti) => ti.name,
NodeVariant(v) => v.node.name,
NodeField(f) => f.name,
NodeLifetime(lt) => lt.name,
NodeLifetime(lt) => lt.name.name(),
NodeTyParam(tp) => tp.name,
NodeBinding(&Pat { node: PatKind::Binding(_,_,l,_), .. }) => l.node,
NodeStructCtor(_) => self.name(self.get_parent(id)),
30 changes: 27 additions & 3 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
@@ -145,7 +145,27 @@ pub struct Lifetime {
/// HIR lowering inserts these placeholders in type paths that
/// refer to type definitions needing lifetime parameters,
/// `&T` and `&mut T`, and trait objects without `... + 'a`.
pub name: Name,
pub name: LifetimeName,
}

#[derive(Debug, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
pub enum LifetimeName {
Implicit,
Underscore,
Static,
Name(Name),
}

impl LifetimeName {
pub fn name(&self) -> Name {
use self::LifetimeName::*;
match *self {
Implicit => keywords::Invalid.name(),
Underscore => Symbol::intern("'_"),
Static => keywords::StaticLifetime.name(),
Name(name) => name,
}
}
}

impl fmt::Debug for Lifetime {
@@ -159,11 +179,15 @@ impl fmt::Debug for Lifetime {

impl Lifetime {
pub fn is_elided(&self) -> bool {
self.name == keywords::Invalid.name()
use self::LifetimeName::*;
match self.name {
Implicit | Underscore => true,
Static | Name(_) => false,
}
}

pub fn is_static(&self) -> bool {
self.name == "'static"
self.name == LifetimeName::Static
}
}

2 changes: 1 addition & 1 deletion src/librustc/hir/print.rs
Original file line number Diff line number Diff line change
@@ -1975,7 +1975,7 @@ impl<'a> State<'a> {
}

pub fn print_lifetime(&mut self, lifetime: &hir::Lifetime) -> io::Result<()> {
self.print_name(lifetime.name)
self.print_name(lifetime.name.name())
}

pub fn print_lifetime_def(&mut self, lifetime: &hir::LifetimeDef) -> io::Result<()> {
7 changes: 7 additions & 0 deletions src/librustc/ich/impls_hir.rs
Original file line number Diff line number Diff line change
@@ -123,6 +123,13 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::ImplItemId {
}
}

impl_stable_hash_for!(enum hir::LifetimeName {
Implicit,
Underscore,
Static,
Name(name)
});

impl_stable_hash_for!(struct hir::Lifetime {
id,
span,
78 changes: 48 additions & 30 deletions src/librustc/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
@@ -46,14 +46,16 @@ pub enum Region {
}

impl Region {
fn early(hir_map: &Map, index: &mut u32, def: &hir::LifetimeDef) -> (ast::Name, Region) {
fn early(hir_map: &Map, index: &mut u32, def: &hir::LifetimeDef)
-> (hir::LifetimeName, Region)
{
let i = *index;
*index += 1;
let def_id = hir_map.local_def_id(def.lifetime.id);
(def.lifetime.name, Region::EarlyBound(i, def_id))
}

fn late(hir_map: &Map, def: &hir::LifetimeDef) -> (ast::Name, Region) {
fn late(hir_map: &Map, def: &hir::LifetimeDef) -> (hir::LifetimeName, Region) {
let depth = ty::DebruijnIndex::new(1);
let def_id = hir_map.local_def_id(def.lifetime.id);
(def.lifetime.name, Region::LateBound(depth, def_id))
@@ -198,7 +200,7 @@ enum Scope<'a> {
/// it should be shifted by the number of `Binder`s in between the
/// declaration `Binder` and the location it's referenced from.
Binder {
lifetimes: FxHashMap<ast::Name, Region>,
lifetimes: FxHashMap<hir::LifetimeName, Region>,
s: ScopeRef<'a>
},

@@ -654,7 +656,7 @@ fn extract_labels(ctxt: &mut LifetimeContext, body: &hir::Body) {

Scope::Binder { ref lifetimes, s } => {
// FIXME (#24278): non-hygienic comparison
if let Some(def) = lifetimes.get(&label) {
if let Some(def) = lifetimes.get(&hir::LifetimeName::Name(label)) {
let node_id = hir_map.as_local_node_id(def.id().unwrap())
.unwrap();

@@ -692,7 +694,7 @@ fn compute_object_lifetime_defaults(sess: &Session, hir_map: &Map)
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()
generics.lifetimes[i as usize].lifetime.name.name().to_string()
}
Set1::One(_) => bug!(),
Set1::Many => "Ambiguous".to_string(),
@@ -714,7 +716,7 @@ fn compute_object_lifetime_defaults(sess: &Session, hir_map: &Map)
/// 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]) {
fn add_bounds(set: &mut Set1<hir::LifetimeName>, bounds: &[hir::TyParamBound]) {
for bound in bounds {
if let hir::RegionTyParamBound(ref lifetime) = *bound {
set.insert(lifetime.name);
@@ -754,7 +756,7 @@ fn object_lifetime_defaults_for_item(hir_map: &Map, generics: &hir::Generics)
match set {
Set1::Empty => Set1::Empty,
Set1::One(name) => {
if name == "'static" {
if name == hir::LifetimeName::Static {
Set1::One(Region::Static)
} else {
generics.lifetimes.iter().enumerate().find(|&(_, def)| {
@@ -922,7 +924,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
self.insert_lifetime(lifetime_ref, def);
} else {
struct_span_err!(self.sess, lifetime_ref.span, E0261,
"use of undeclared lifetime name `{}`", lifetime_ref.name)
"use of undeclared lifetime name `{}`", lifetime_ref.name.name())
.span_label(lifetime_ref.span, "undeclared lifetime")
.emit();
}
@@ -1422,13 +1424,17 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
let lifetime_i = &lifetimes[i];

for lifetime in lifetimes {
if lifetime.lifetime.is_static() {
let lifetime = lifetime.lifetime;
let mut err = struct_span_err!(self.sess, lifetime.span, E0262,
"invalid lifetime parameter name: `{}`", lifetime.name);
err.span_label(lifetime.span,
format!("{} is a reserved lifetime name", lifetime.name));
err.emit();
match lifetime.lifetime.name {
hir::LifetimeName::Static | hir::LifetimeName::Underscore => {
let lifetime = lifetime.lifetime;
let name = lifetime.name.name();
let mut err = struct_span_err!(self.sess, lifetime.span, E0262,
"invalid lifetime parameter name: `{}`", name);
err.span_label(lifetime.span,
format!("{} is a reserved lifetime name", name));
err.emit();
}
hir::LifetimeName::Implicit | hir::LifetimeName::Name(_) => {}
}
}

@@ -1439,7 +1445,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
if lifetime_i.lifetime.name == lifetime_j.lifetime.name {
struct_span_err!(self.sess, lifetime_j.lifetime.span, E0263,
"lifetime name `{}` declared twice in the same scope",
lifetime_j.lifetime.name)
lifetime_j.lifetime.name.name())
.span_label(lifetime_j.lifetime.span,
"declared twice")
.span_label(lifetime_i.lifetime.span,
@@ -1452,15 +1458,27 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
self.check_lifetime_def_for_shadowing(old_scope, &lifetime_i.lifetime);

for bound in &lifetime_i.bounds {
if !bound.is_static() {
self.resolve_lifetime_ref(bound);
} else {
self.insert_lifetime(bound, Region::Static);
self.sess.struct_span_warn(lifetime_i.lifetime.span.to(bound.span),
&format!("unnecessary lifetime parameter `{}`", lifetime_i.lifetime.name))
.help(&format!("you can use the `'static` lifetime directly, in place \
of `{}`", lifetime_i.lifetime.name))
.emit();
match bound.name {
hir::LifetimeName::Underscore => {
let mut err = struct_span_err!(self.sess, bound.span, E0637,
"invalid lifetime bound name: `'_`");
err.span_label(bound.span, "`'_` is a reserved lifetime name");
err.emit();
}
hir::LifetimeName::Static => {
self.insert_lifetime(bound, Region::Static);
self.sess.struct_span_warn(lifetime_i.lifetime.span.to(bound.span),
&format!("unnecessary lifetime parameter `{}`",
lifetime_i.lifetime.name.name()))
.help(&format!(
"you can use the `'static` lifetime directly, in place \
of `{}`", lifetime_i.lifetime.name.name()))
.emit();
}
hir::LifetimeName::Implicit |
hir::LifetimeName::Name(_) => {
self.resolve_lifetime_ref(bound);
}
}
}
}
@@ -1472,9 +1490,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
{
for &(label, label_span) in &self.labels_in_fn {
// FIXME (#24278): non-hygienic comparison
if lifetime.name == label {
if lifetime.name.name() == label {
signal_shadowing_problem(self.sess,
lifetime.name,
label,
original_label(label_span),
shadower_lifetime(&lifetime));
return;
@@ -1501,7 +1519,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {

signal_shadowing_problem(
self.sess,
lifetime.name,
lifetime.name.name(),
original_lifetime(self.hir_map.span(node_id)),
shadower_lifetime(&lifetime));
return;
@@ -1617,7 +1635,7 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
return;

struct ConstrainedCollector {
regions: FxHashSet<ast::Name>,
regions: FxHashSet<hir::LifetimeName>,
}

impl<'v> Visitor<'v> for ConstrainedCollector {
@@ -1657,7 +1675,7 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
}

struct AllCollector {
regions: FxHashSet<ast::Name>,
regions: FxHashSet<hir::LifetimeName>,
impl_trait: bool
}

2 changes: 1 addition & 1 deletion src/librustc_lint/bad_style.rs
Original file line number Diff line number Diff line change
@@ -278,7 +278,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase {
fn check_lifetime_def(&mut self, cx: &LateContext, t: &hir::LifetimeDef) {
self.check_snake_case(cx,
"lifetime",
&t.lifetime.name.as_str(),
&t.lifetime.name.name().as_str(),
Some(t.lifetime.span));
}

8 changes: 0 additions & 8 deletions src/librustc_passes/ast_validation.rs
Original file line number Diff line number Diff line change
@@ -122,14 +122,6 @@ impl<'a> AstValidator<'a> {
}

impl<'a> Visitor<'a> for AstValidator<'a> {
fn visit_lifetime(&mut self, lt: &'a Lifetime) {
if lt.ident.name == "'_" {
self.err_handler().span_err(lt.span, &format!("invalid lifetime name `{}`", lt.ident));
}

visit::walk_lifetime(self, lt)
}

fn visit_expr(&mut self, expr: &'a Expr) {
match expr.node {
ExprKind::While(.., Some(ident)) |
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/wfcheck.rs
Original file line number Diff line number Diff line change
@@ -523,7 +523,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {

let (span, name) = if index < ast_generics.lifetimes.len() {
(ast_generics.lifetimes[index].lifetime.span,
ast_generics.lifetimes[index].lifetime.name)
ast_generics.lifetimes[index].lifetime.name.name())
} else {
let index = index - ast_generics.lifetimes.len();
(ast_generics.ty_params[index].span,
4 changes: 2 additions & 2 deletions src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
@@ -953,7 +953,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics);
let regions = early_lifetimes.enumerate().map(|(i, l)| {
ty::RegionParameterDef {
name: l.lifetime.name,
name: l.lifetime.name.name(),
index: own_start + i as u32,
def_id: tcx.hir.local_def_id(l.lifetime.id),
pure_wrt_drop: l.pure_wrt_drop,
@@ -1423,7 +1423,7 @@ fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let region = tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
def_id: tcx.hir.local_def_id(param.lifetime.id),
index,
name: param.lifetime.name
name: param.lifetime.name.name(),
}));
index += 1;

2 changes: 1 addition & 1 deletion src/librustc_typeck/impl_wf_check.rs
Original file line number Diff line number Diff line change
@@ -132,7 +132,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
!input_parameters.contains(&param)
{
report_unused_parameter(tcx, lifetime.lifetime.span,
"lifetime", &lifetime.lifetime.name.to_string());
"lifetime", &lifetime.lifetime.name.name().to_string());
}
}

10 changes: 5 additions & 5 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
@@ -876,22 +876,22 @@ impl Clean<Lifetime> for hir::Lifetime {
}
_ => {}
}
Lifetime(self.name.to_string())
Lifetime(self.name.name().to_string())
}
}

impl Clean<Lifetime> for hir::LifetimeDef {
fn clean(&self, _: &DocContext) -> Lifetime {
if self.bounds.len() > 0 {
let mut s = format!("{}: {}",
self.lifetime.name.to_string(),
self.bounds[0].name.to_string());
self.lifetime.name.name(),
self.bounds[0].name.name());
for bound in self.bounds.iter().skip(1) {
s.push_str(&format!(" + {}", bound.name.to_string()));
s.push_str(&format!(" + {}", bound.name.name()));
}
Lifetime(s)
} else {
Lifetime(self.lifetime.name.to_string())
Lifetime(self.lifetime.name.name().to_string())
}
}
}
Loading