1
Fork 0

Allow both explicit and elided lifetimes in the same impl header

(While still prohibiting explicit and in-band in the same header.)
This commit is contained in:
Scott McMurray 2018-09-22 01:45:42 -07:00
parent ed45f9cbf4
commit 003c4ffa83
5 changed files with 83 additions and 29 deletions

View file

@ -683,9 +683,15 @@ impl<'a> LoweringContext<'a> {
// Get the name we'll use to make the def-path. Note // Get the name we'll use to make the def-path. Note
// that collisions are ok here and this shouldn't // that collisions are ok here and this shouldn't
// really show up for end-user. // really show up for end-user.
let str_name = match hir_name { let (str_name, kind) = match hir_name {
ParamName::Plain(ident) => ident.as_interned_str(), ParamName::Plain(ident) => (
ParamName::Fresh(_) => keywords::UnderscoreLifetime.name().as_interned_str(), ident.as_interned_str(),
hir::LifetimeParamKind::InBand,
),
ParamName::Fresh(_) => (
keywords::UnderscoreLifetime.name().as_interned_str(),
hir::LifetimeParamKind::Elided,
),
}; };
// Add a definition for the in-band lifetime def // Add a definition for the in-band lifetime def
@ -705,7 +711,7 @@ impl<'a> LoweringContext<'a> {
bounds: hir_vec![], bounds: hir_vec![],
span, span,
pure_wrt_drop: false, pure_wrt_drop: false,
kind: hir::GenericParamKind::Lifetime { in_band: true } kind: hir::GenericParamKind::Lifetime { kind }
} }
}) })
.chain(in_band_ty_params.into_iter()) .chain(in_band_ty_params.into_iter())
@ -1452,11 +1458,15 @@ impl<'a> LoweringContext<'a> {
lifetime.span, lifetime.span,
); );
let name = match name { let (name, kind) = match name {
hir::LifetimeName::Underscore => { hir::LifetimeName::Underscore => (
hir::ParamName::Plain(keywords::UnderscoreLifetime.ident()) hir::ParamName::Plain(keywords::UnderscoreLifetime.ident()),
} hir::LifetimeParamKind::Elided,
hir::LifetimeName::Param(param_name) => param_name, ),
hir::LifetimeName::Param(param_name) => (
param_name,
hir::LifetimeParamKind::Explicit,
),
_ => bug!("expected LifetimeName::Param or ParamName::Plain"), _ => bug!("expected LifetimeName::Param or ParamName::Plain"),
}; };
@ -1467,9 +1477,7 @@ impl<'a> LoweringContext<'a> {
pure_wrt_drop: false, pure_wrt_drop: false,
attrs: hir_vec![], attrs: hir_vec![],
bounds: hir_vec![], bounds: hir_vec![],
kind: hir::GenericParamKind::Lifetime { kind: hir::GenericParamKind::Lifetime { kind }
in_band: false,
}
}); });
} }
} }
@ -2283,7 +2291,9 @@ impl<'a> LoweringContext<'a> {
pure_wrt_drop: attr::contains_name(&param.attrs, "may_dangle"), pure_wrt_drop: attr::contains_name(&param.attrs, "may_dangle"),
attrs: self.lower_attrs(&param.attrs), attrs: self.lower_attrs(&param.attrs),
bounds, bounds,
kind: hir::GenericParamKind::Lifetime { in_band: false } kind: hir::GenericParamKind::Lifetime {
kind: hir::LifetimeParamKind::Explicit,
}
}; };
self.is_collecting_in_band_lifetimes = was_collecting_in_band; self.is_collecting_in_band_lifetimes = was_collecting_in_band;

View file

@ -499,14 +499,27 @@ impl GenericBound {
pub type GenericBounds = HirVec<GenericBound>; pub type GenericBounds = HirVec<GenericBound>;
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
pub enum LifetimeParamKind {
// Indicates that the lifetime definition was explicitly declared, like:
// `fn foo<'a>(x: &'a u8) -> &'a u8 { x }`
Explicit,
// Indicates that the lifetime definition was synthetically added
// as a result of an in-band lifetime usage like:
// `fn foo(x: &'a u8) -> &'a u8 { x }`
InBand,
// Indication that the lifetime was elided like both cases here:
// `fn foo(x: &u8) -> &'_ u8 { x }`
Elided,
}
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub enum GenericParamKind { pub enum GenericParamKind {
/// A lifetime definition, eg `'a: 'b + 'c + 'd`. /// A lifetime definition, eg `'a: 'b + 'c + 'd`.
Lifetime { Lifetime {
// Indicates that the lifetime definition was synthetically added kind: LifetimeParamKind,
// as a result of an in-band lifetime usage like:
// `fn foo(x: &'a u8) -> &'a u8 { x }`
in_band: bool,
}, },
Type { Type {
default: Option<P<Ty>>, default: Option<P<Ty>>,

View file

@ -207,14 +207,20 @@ impl_stable_hash_for!(struct hir::GenericParam {
kind kind
}); });
impl_stable_hash_for!(enum hir::LifetimeParamKind {
Explicit,
InBand,
Elided
});
impl<'a> HashStable<StableHashingContext<'a>> for hir::GenericParamKind { impl<'a> HashStable<StableHashingContext<'a>> for hir::GenericParamKind {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
match self { match self {
hir::GenericParamKind::Lifetime { in_band } => { hir::GenericParamKind::Lifetime { kind } => {
in_band.hash_stable(hcx, hasher); kind.hash_stable(hcx, hasher);
} }
hir::GenericParamKind::Type { ref default, synthetic } => { hir::GenericParamKind::Type { ref default, synthetic } => {
default.hash_stable(hcx, hasher); default.hash_stable(hcx, hasher);

View file

@ -35,7 +35,7 @@ use syntax_pos::Span;
use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap, NodeSet}; use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap, NodeSet};
use hir::intravisit::{self, NestedVisitorMap, Visitor}; use hir::intravisit::{self, NestedVisitorMap, Visitor};
use hir::{self, GenericParamKind}; use hir::{self, GenericParamKind, LifetimeParamKind};
/// The origin of a named lifetime definition. /// The origin of a named lifetime definition.
/// ///
@ -51,8 +51,8 @@ pub enum LifetimeDefOrigin {
impl LifetimeDefOrigin { impl LifetimeDefOrigin {
fn from_param(param: &GenericParam) -> Self { fn from_param(param: &GenericParam) -> Self {
match param.kind { match param.kind {
GenericParamKind::Lifetime { in_band } => { GenericParamKind::Lifetime { kind } => {
if in_band { if kind == LifetimeParamKind::InBand {
LifetimeDefOrigin::InBand LifetimeDefOrigin::InBand
} else { } else {
LifetimeDefOrigin::Explicit LifetimeDefOrigin::Explicit
@ -1087,15 +1087,15 @@ fn check_mixed_explicit_and_in_band_defs(
tcx: TyCtxt<'_, '_, '_>, tcx: TyCtxt<'_, '_, '_>,
params: &P<[hir::GenericParam]>, params: &P<[hir::GenericParam]>,
) { ) {
let in_bands: Vec<_> = params.iter().filter_map(|param| match param.kind { let lifetime_params: Vec<_> = params.iter().filter_map(|param| match param.kind {
GenericParamKind::Lifetime { in_band, .. } => Some((in_band, param.span)), GenericParamKind::Lifetime { kind, .. } => Some((kind, param.span)),
_ => None, _ => None,
}).collect(); }).collect();
let out_of_band = in_bands.iter().find(|(in_band, _)| !in_band); let explicit = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::Explicit);
let in_band = in_bands.iter().find(|(in_band, _)| *in_band); let in_band = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::InBand);
if let (Some((_, out_of_band_span)), Some((_, in_band_span))) if let (Some((_, explicit_span)), Some((_, in_band_span)))
= (out_of_band, in_band) { = (explicit, in_band) {
struct_span_err!( struct_span_err!(
tcx.sess, tcx.sess,
*in_band_span, *in_band_span,
@ -1104,7 +1104,7 @@ fn check_mixed_explicit_and_in_band_defs(
).span_label( ).span_label(
*in_band_span, *in_band_span,
"in-band lifetime definition here", "in-band lifetime definition here",
).span_label(*out_of_band_span, "explicit lifetime definition here") ).span_label(*explicit_span, "explicit lifetime definition here")
.emit(); .emit();
} }
} }

View file

@ -0,0 +1,25 @@
// Copyright 2018 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.
// run-pass
#![allow(warnings)]
#![feature(impl_header_lifetime_elision)]
// This works for functions...
fn foo<'a>(x: &str, y: &'a str) {}
// ...so this should work for impls
impl<'a> Foo<&str> for &'a str {}
trait Foo<T> {}
fn main() {
}