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:
parent
ed45f9cbf4
commit
003c4ffa83
5 changed files with 83 additions and 29 deletions
|
@ -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(¶m.attrs, "may_dangle"),
|
pure_wrt_drop: attr::contains_name(¶m.attrs, "may_dangle"),
|
||||||
attrs: self.lower_attrs(¶m.attrs),
|
attrs: self.lower_attrs(¶m.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;
|
||||||
|
|
|
@ -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>>,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue