diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index bd8770abb135c..d237632cf36a4 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -683,9 +683,15 @@ impl<'a> LoweringContext<'a> { // Get the name we'll use to make the def-path. Note // that collisions are ok here and this shouldn't // really show up for end-user. - let str_name = match hir_name { - ParamName::Plain(ident) => ident.as_interned_str(), - ParamName::Fresh(_) => keywords::UnderscoreLifetime.name().as_interned_str(), + let (str_name, kind) = match hir_name { + ParamName::Plain(ident) => ( + 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 @@ -705,7 +711,7 @@ impl<'a> LoweringContext<'a> { bounds: hir_vec![], span, pure_wrt_drop: false, - kind: hir::GenericParamKind::Lifetime { in_band: true } + kind: hir::GenericParamKind::Lifetime { kind } } }) .chain(in_band_ty_params.into_iter()) @@ -1452,11 +1458,15 @@ impl<'a> LoweringContext<'a> { lifetime.span, ); - let name = match name { - hir::LifetimeName::Underscore => { - hir::ParamName::Plain(keywords::UnderscoreLifetime.ident()) - } - hir::LifetimeName::Param(param_name) => param_name, + let (name, kind) = match name { + hir::LifetimeName::Underscore => ( + hir::ParamName::Plain(keywords::UnderscoreLifetime.ident()), + hir::LifetimeParamKind::Elided, + ), + hir::LifetimeName::Param(param_name) => ( + param_name, + hir::LifetimeParamKind::Explicit, + ), _ => bug!("expected LifetimeName::Param or ParamName::Plain"), }; @@ -1467,9 +1477,7 @@ impl<'a> LoweringContext<'a> { pure_wrt_drop: false, attrs: hir_vec![], bounds: hir_vec![], - kind: hir::GenericParamKind::Lifetime { - in_band: false, - } + kind: hir::GenericParamKind::Lifetime { kind } }); } } @@ -2283,7 +2291,9 @@ impl<'a> LoweringContext<'a> { pure_wrt_drop: attr::contains_name(¶m.attrs, "may_dangle"), attrs: self.lower_attrs(¶m.attrs), 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; diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index de9808ffe7001..ee8e64b2e206f 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -499,14 +499,27 @@ impl GenericBound { pub type GenericBounds = HirVec; +#[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)] pub enum GenericParamKind { /// A lifetime definition, eg `'a: 'b + 'c + 'd`. Lifetime { - // 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 }` - in_band: bool, + kind: LifetimeParamKind, }, Type { default: Option>, diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index bc2eb5f442b47..676c24a8d3dff 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -207,14 +207,20 @@ impl_stable_hash_for!(struct hir::GenericParam { kind }); +impl_stable_hash_for!(enum hir::LifetimeParamKind { + Explicit, + InBand, + Elided +}); + impl<'a> HashStable> for hir::GenericParamKind { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match self { - hir::GenericParamKind::Lifetime { in_band } => { - in_band.hash_stable(hcx, hasher); + hir::GenericParamKind::Lifetime { kind } => { + kind.hash_stable(hcx, hasher); } hir::GenericParamKind::Type { ref default, synthetic } => { default.hash_stable(hcx, hasher); diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index db931d0a739ff..fb1cd4ce06419 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -35,7 +35,7 @@ use syntax_pos::Span; use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap, NodeSet}; use hir::intravisit::{self, NestedVisitorMap, Visitor}; -use hir::{self, GenericParamKind}; +use hir::{self, GenericParamKind, LifetimeParamKind}; /// The origin of a named lifetime definition. /// @@ -51,8 +51,8 @@ pub enum LifetimeDefOrigin { impl LifetimeDefOrigin { fn from_param(param: &GenericParam) -> Self { match param.kind { - GenericParamKind::Lifetime { in_band } => { - if in_band { + GenericParamKind::Lifetime { kind } => { + if kind == LifetimeParamKind::InBand { LifetimeDefOrigin::InBand } else { LifetimeDefOrigin::Explicit @@ -1087,15 +1087,15 @@ fn check_mixed_explicit_and_in_band_defs( tcx: TyCtxt<'_, '_, '_>, params: &P<[hir::GenericParam]>, ) { - let in_bands: Vec<_> = params.iter().filter_map(|param| match param.kind { - GenericParamKind::Lifetime { in_band, .. } => Some((in_band, param.span)), + let lifetime_params: Vec<_> = params.iter().filter_map(|param| match param.kind { + GenericParamKind::Lifetime { kind, .. } => Some((kind, param.span)), _ => None, }).collect(); - let out_of_band = in_bands.iter().find(|(in_band, _)| !in_band); - let in_band = in_bands.iter().find(|(in_band, _)| *in_band); + let explicit = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::Explicit); + let in_band = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::InBand); - if let (Some((_, out_of_band_span)), Some((_, in_band_span))) - = (out_of_band, in_band) { + if let (Some((_, explicit_span)), Some((_, in_band_span))) + = (explicit, in_band) { struct_span_err!( tcx.sess, *in_band_span, @@ -1104,7 +1104,7 @@ fn check_mixed_explicit_and_in_band_defs( ).span_label( *in_band_span, "in-band lifetime definition here", - ).span_label(*out_of_band_span, "explicit lifetime definition here") + ).span_label(*explicit_span, "explicit lifetime definition here") .emit(); } } diff --git a/src/test/ui/impl-header-lifetime-elision/explicit-and-elided-same-header.rs b/src/test/ui/impl-header-lifetime-elision/explicit-and-elided-same-header.rs new file mode 100644 index 0000000000000..56dd6691abbe5 --- /dev/null +++ b/src/test/ui/impl-header-lifetime-elision/explicit-and-elided-same-header.rs @@ -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 or the MIT license +// , 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 {} + +fn main() { +}