Auto merge of #49251 - nikomatsakis:issue-15872-elision-impl-header, r=cramertj
support elision in impl headers You can now do things like: ``` impl MyTrait<'_> for &u32 { ... } ``` Each `'_` or elided lifetime is a fresh parameter. `'_` and elision are still not permitted in associated type values. (Plausibly we could support that if there is a single input lifetime.) The original lifetime elision RFC was a bit unclear on this point: [as documented here, I think this is the correct interpretation, both because it fits existing impls and it's most analogous to the behavior in fns](https://github.com/rust-lang/rust/issues/15872#issuecomment-338700138). We do not support elision with deprecated forms: ``` impl MyTrait for std::cell::Ref<u32> { } // ERROR ``` Builds on the in-band lifetime stuff. r? @cramertj Fixes #15872
This commit is contained in:
commit
b4aa80dd73
20 changed files with 2081 additions and 1107 deletions
|
@ -420,7 +420,10 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime
|
|||
LifetimeName::Name(name) => {
|
||||
visitor.visit_name(lifetime.span, name);
|
||||
}
|
||||
LifetimeName::Static | LifetimeName::Implicit | LifetimeName::Underscore => {}
|
||||
LifetimeName::Fresh(_) |
|
||||
LifetimeName::Static |
|
||||
LifetimeName::Implicit |
|
||||
LifetimeName::Underscore => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -203,9 +203,31 @@ pub struct Lifetime {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
|
||||
pub enum LifetimeName {
|
||||
/// User typed nothing. e.g. the lifetime in `&u32`.
|
||||
Implicit,
|
||||
|
||||
/// User typed `'_`.
|
||||
Underscore,
|
||||
|
||||
/// Synthetic name generated when user elided a lifetime in an impl header,
|
||||
/// e.g. the lifetimes in cases like these:
|
||||
///
|
||||
/// impl Foo for &u32
|
||||
/// impl Foo<'_> for u32
|
||||
///
|
||||
/// in that case, we rewrite to
|
||||
///
|
||||
/// impl<'f> Foo for &'f u32
|
||||
/// impl<'f> Foo<'f> for u32
|
||||
///
|
||||
/// where `'f` is something like `Fresh(0)`. The indices are
|
||||
/// unique per impl, but not necessarily continuous.
|
||||
Fresh(usize),
|
||||
|
||||
/// User wrote `'static`
|
||||
Static,
|
||||
|
||||
/// Some user-given name like `'x`
|
||||
Name(Name),
|
||||
}
|
||||
|
||||
|
@ -214,7 +236,7 @@ impl LifetimeName {
|
|||
use self::LifetimeName::*;
|
||||
match *self {
|
||||
Implicit => keywords::Invalid.name(),
|
||||
Underscore => keywords::UnderscoreLifetime.name(),
|
||||
Fresh(_) | Underscore => keywords::UnderscoreLifetime.name(),
|
||||
Static => keywords::StaticLifetime.name(),
|
||||
Name(name) => name,
|
||||
}
|
||||
|
@ -235,7 +257,13 @@ impl Lifetime {
|
|||
use self::LifetimeName::*;
|
||||
match self.name {
|
||||
Implicit | Underscore => true,
|
||||
Static | Name(_) => false,
|
||||
|
||||
// It might seem surprising that `Fresh(_)` counts as
|
||||
// *not* elided -- but this is because, as far as the code
|
||||
// in the compiler is concerned -- `Fresh(_)` variants act
|
||||
// equivalently to "some fresh name". They correspond to
|
||||
// early-bound regions on an impl, in other words.
|
||||
Fresh(_) | Static | Name(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -145,6 +145,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::ImplItemId {
|
|||
impl_stable_hash_for!(enum hir::LifetimeName {
|
||||
Implicit,
|
||||
Underscore,
|
||||
Fresh(index),
|
||||
Static,
|
||||
Name(name)
|
||||
});
|
||||
|
|
|
@ -31,6 +31,7 @@ use syntax::ptr::P;
|
|||
use syntax_pos::Span;
|
||||
use errors::DiagnosticBuilder;
|
||||
use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap, NodeSet};
|
||||
use session::Session;
|
||||
use std::slice;
|
||||
use rustc::lint;
|
||||
|
||||
|
@ -468,10 +469,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
fn visit_item(&mut self, item: &'tcx hir::Item) {
|
||||
match item.node {
|
||||
hir::ItemFn(ref decl, _, _, _, ref generics, _) => {
|
||||
self.visit_early_late(None,
|
||||
decl,
|
||||
generics,
|
||||
|this| {
|
||||
self.visit_early_late(None, decl, generics, |this| {
|
||||
intravisit::walk_item(this, item);
|
||||
});
|
||||
}
|
||||
|
@ -505,7 +503,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
} else {
|
||||
0
|
||||
};
|
||||
let lifetimes = generics.lifetimes()
|
||||
let lifetimes = generics
|
||||
.lifetimes()
|
||||
.map(|def| Region::early(&self.tcx.hir, &mut index, def))
|
||||
.collect();
|
||||
let next_early_index = index + generics.ty_params().count() as u32;
|
||||
|
@ -526,10 +525,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
|
||||
match item.node {
|
||||
hir::ForeignItemFn(ref decl, _, ref generics) => {
|
||||
self.visit_early_late(None,
|
||||
decl,
|
||||
generics,
|
||||
|this| {
|
||||
self.visit_early_late(None, decl, generics, |this| {
|
||||
intravisit::walk_foreign_item(this, item);
|
||||
})
|
||||
}
|
||||
|
@ -586,7 +582,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
// cc #48468
|
||||
self.resolve_elided_lifetimes(slice::from_ref(lifetime), false)
|
||||
}
|
||||
LifetimeName::Static | LifetimeName::Name(_) => {
|
||||
LifetimeName::Fresh(_) | LifetimeName::Static | LifetimeName::Name(_) => {
|
||||
// If the user wrote an explicit name, use that.
|
||||
self.visit_lifetime(lifetime);
|
||||
}
|
||||
|
@ -670,7 +666,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
if let Some(elision_region) = elision {
|
||||
let scope = Scope::Elision {
|
||||
elide: Elide::Exact(elision_region),
|
||||
s: self.scope
|
||||
s: self.scope,
|
||||
};
|
||||
self.with(scope, |_old_scope, this| {
|
||||
let scope = Scope::Binder {
|
||||
|
@ -716,12 +712,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
&trait_item.generics,
|
||||
|this| intravisit::walk_trait_item(this, trait_item),
|
||||
);
|
||||
},
|
||||
}
|
||||
Type(ref bounds, ref ty) => {
|
||||
let generics = &trait_item.generics;
|
||||
let mut index = self.next_early_index();
|
||||
debug!("visit_ty: index = {}", index);
|
||||
let lifetimes = generics.lifetimes()
|
||||
let lifetimes = generics
|
||||
.lifetimes()
|
||||
.map(|lt_def| Region::early(&self.tcx.hir, &mut index, lt_def))
|
||||
.collect();
|
||||
|
||||
|
@ -741,12 +738,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
this.visit_ty(ty);
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
Const(_, _) => {
|
||||
// Only methods and types support generics.
|
||||
assert!(trait_item.generics.params.is_empty());
|
||||
intravisit::walk_trait_item(self, trait_item);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -761,12 +758,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
&impl_item.generics,
|
||||
|this| intravisit::walk_impl_item(this, impl_item),
|
||||
)
|
||||
},
|
||||
}
|
||||
Type(ref ty) => {
|
||||
let generics = &impl_item.generics;
|
||||
let mut index = self.next_early_index();
|
||||
debug!("visit_ty: index = {}", index);
|
||||
let lifetimes = generics.lifetimes()
|
||||
let lifetimes = generics
|
||||
.lifetimes()
|
||||
.map(|lt_def| Region::early(&self.tcx.hir, &mut index, lt_def))
|
||||
.collect();
|
||||
|
||||
|
@ -781,12 +779,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
this.visit_generics(generics);
|
||||
this.visit_ty(ty);
|
||||
});
|
||||
},
|
||||
}
|
||||
Const(_, _) => {
|
||||
// Only methods and types support generics.
|
||||
assert!(impl_item.generics.params.is_empty());
|
||||
intravisit::walk_impl_item(self, impl_item);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -822,7 +820,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
|
||||
check_mixed_explicit_and_in_band_defs(
|
||||
self.tcx,
|
||||
&generics.lifetimes().cloned().collect::<Vec<_>>()
|
||||
&generics.lifetimes().cloned().collect::<Vec<_>>(),
|
||||
);
|
||||
for ty_param in generics.ty_params() {
|
||||
walk_list!(self, visit_ty_param_bound, &ty_param.bounds);
|
||||
|
@ -842,7 +840,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
self.trait_ref_hack = true;
|
||||
let next_early_index = self.next_early_index();
|
||||
let scope = Scope::Binder {
|
||||
lifetimes: bound_generic_params.lifetimes()
|
||||
lifetimes: bound_generic_params
|
||||
.lifetimes()
|
||||
.map(|def| Region::late(&self.tcx.hir, def))
|
||||
.collect(),
|
||||
s: self.scope,
|
||||
|
@ -890,8 +889,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
) {
|
||||
debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref);
|
||||
|
||||
if !self.trait_ref_hack ||
|
||||
trait_ref.bound_generic_params.iter().any(|p| p.is_lifetime_param())
|
||||
if !self.trait_ref_hack
|
||||
|| trait_ref
|
||||
.bound_generic_params
|
||||
.iter()
|
||||
.any(|p| p.is_lifetime_param())
|
||||
{
|
||||
if self.trait_ref_hack {
|
||||
span_err!(
|
||||
|
@ -903,7 +905,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
let next_early_index = self.next_early_index();
|
||||
let scope = Scope::Binder {
|
||||
lifetimes: trait_ref.bound_generic_params
|
||||
lifetimes: trait_ref
|
||||
.bound_generic_params
|
||||
.lifetimes()
|
||||
.map(|def| Region::late(&self.tcx.hir, def))
|
||||
.collect(),
|
||||
|
@ -1144,7 +1147,8 @@ fn compute_object_lifetime_defaults(
|
|||
.map(|set| match *set {
|
||||
Set1::Empty => "BaseDefault".to_string(),
|
||||
Set1::One(Region::Static) => "'static".to_string(),
|
||||
Set1::One(Region::EarlyBound(i, _, _)) => generics.lifetimes()
|
||||
Set1::One(Region::EarlyBound(i, _, _)) => generics
|
||||
.lifetimes()
|
||||
.nth(i as usize)
|
||||
.unwrap()
|
||||
.lifetime
|
||||
|
@ -1182,7 +1186,8 @@ fn object_lifetime_defaults_for_item(
|
|||
}
|
||||
}
|
||||
|
||||
generics.ty_params()
|
||||
generics
|
||||
.ty_params()
|
||||
.map(|param| {
|
||||
let mut set = Set1::Empty;
|
||||
|
||||
|
@ -1278,17 +1283,21 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
if let hir::map::NodeLifetime(hir_lifetime) = this.tcx.hir.get(node_id) {
|
||||
let span = hir_lifetime.span;
|
||||
let id = hir_lifetime.id;
|
||||
debug!("id ={:?} span = {:?} hir_lifetime = {:?}",
|
||||
node_id,
|
||||
span,
|
||||
hir_lifetime);
|
||||
debug!(
|
||||
"id ={:?} span = {:?} hir_lifetime = {:?}",
|
||||
node_id, span, hir_lifetime
|
||||
);
|
||||
|
||||
this.tcx
|
||||
.struct_span_lint_node(lint::builtin::SINGLE_USE_LIFETIME,
|
||||
.struct_span_lint_node(
|
||||
lint::builtin::SINGLE_USE_LIFETIME,
|
||||
id,
|
||||
span,
|
||||
&format!("lifetime name `{}` only used once",
|
||||
hir_lifetime.name.name()))
|
||||
&format!(
|
||||
"lifetime name `{}` only used once",
|
||||
hir_lifetime.name.name()
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
@ -1379,8 +1388,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
next_early_index,
|
||||
abstract_type_parent,
|
||||
..
|
||||
} if (!only_abstract_type_parent || abstract_type_parent)
|
||||
=> return next_early_index,
|
||||
} if (!only_abstract_type_parent || abstract_type_parent) =>
|
||||
{
|
||||
return next_early_index
|
||||
}
|
||||
|
||||
Scope::Binder { s, .. }
|
||||
| Scope::Body { s, .. }
|
||||
|
@ -1698,8 +1709,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
// Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds).
|
||||
hir::map::NodeForeignItem(_) | hir::map::NodeTy(_) | hir::map::NodeTraitRef(_) =>
|
||||
None,
|
||||
hir::map::NodeForeignItem(_) | hir::map::NodeTy(_) | hir::map::NodeTraitRef(_) => None,
|
||||
// Everything else (only closures?) doesn't
|
||||
// actually enjoy elision in return types.
|
||||
_ => {
|
||||
|
@ -1894,7 +1904,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
lint::builtin::ELIDED_LIFETIME_IN_PATH,
|
||||
id,
|
||||
span,
|
||||
&format!("hidden lifetime parameters are deprecated, try `Foo<'_>`"))
|
||||
&format!("hidden lifetime parameters are deprecated, try `Foo<'_>`"),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
let error = loop {
|
||||
|
@ -1933,25 +1944,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0106,
|
||||
"missing lifetime specifier{}",
|
||||
if lifetime_refs.len() > 1 { "s" } else { "" }
|
||||
);
|
||||
let msg = if lifetime_refs.len() > 1 {
|
||||
format!("expected {} lifetime parameters", lifetime_refs.len())
|
||||
} else {
|
||||
format!("expected lifetime parameter")
|
||||
};
|
||||
err.span_label(span, msg);
|
||||
let mut err = report_missing_lifetime_specifiers(self.tcx.sess, span, lifetime_refs.len());
|
||||
|
||||
if let Some(params) = error {
|
||||
if lifetime_refs.len() == 1 {
|
||||
self.report_elision_failure(&mut err, params);
|
||||
}
|
||||
}
|
||||
|
||||
err.emit();
|
||||
}
|
||||
|
||||
|
@ -2086,7 +2086,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
);
|
||||
err.emit();
|
||||
}
|
||||
hir::LifetimeName::Implicit | hir::LifetimeName::Name(_) => {}
|
||||
hir::LifetimeName::Fresh(_) | hir::LifetimeName::Implicit |
|
||||
hir::LifetimeName::Name(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2138,7 +2139,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
))
|
||||
.emit();
|
||||
}
|
||||
hir::LifetimeName::Implicit | hir::LifetimeName::Name(_) => {
|
||||
hir::LifetimeName::Fresh(_) | hir::LifetimeName::Implicit |
|
||||
hir::LifetimeName::Name(_) => {
|
||||
self.resolve_lifetime_ref(bound);
|
||||
}
|
||||
}
|
||||
|
@ -2146,9 +2148,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_lifetime_def_for_shadowing(&self,
|
||||
fn check_lifetime_def_for_shadowing(
|
||||
&self,
|
||||
mut old_scope: ScopeRef,
|
||||
lifetime: &'tcx hir::Lifetime) {
|
||||
lifetime: &'tcx hir::Lifetime,
|
||||
) {
|
||||
for &(label, label_span) in &self.labels_in_fn {
|
||||
// FIXME (#24278): non-hygienic comparison
|
||||
if lifetime.name.name() == label {
|
||||
|
@ -2216,14 +2220,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
self.map.defs.insert(lifetime_ref.id, def);
|
||||
|
||||
match def {
|
||||
Region::LateBoundAnon(..) |
|
||||
Region::Static => {
|
||||
Region::LateBoundAnon(..) | Region::Static => {
|
||||
// These are anonymous lifetimes or lifetimes that are not declared.
|
||||
}
|
||||
|
||||
Region::Free(_, def_id) |
|
||||
Region::LateBound(_, def_id, _) |
|
||||
Region::EarlyBound(_, def_id, _) => {
|
||||
Region::Free(_, def_id)
|
||||
| Region::LateBound(_, def_id, _)
|
||||
| Region::EarlyBound(_, def_id, _) => {
|
||||
// A lifetime declared by the user.
|
||||
if !self.lifetime_uses.contains_key(&def_id) {
|
||||
self.lifetime_uses
|
||||
|
@ -2255,8 +2258,7 @@ fn insert_late_bound_lifetimes(
|
|||
) {
|
||||
debug!(
|
||||
"insert_late_bound_lifetimes(decl={:?}, generics={:?})",
|
||||
decl,
|
||||
generics
|
||||
decl, generics
|
||||
);
|
||||
|
||||
let mut constrained_by_input = ConstrainedCollector {
|
||||
|
@ -2335,8 +2337,7 @@ fn insert_late_bound_lifetimes(
|
|||
debug!(
|
||||
"insert_late_bound_lifetimes: \
|
||||
lifetime {:?} with id {:?} is late-bound",
|
||||
lifetime.lifetime.name,
|
||||
lifetime.lifetime.id
|
||||
lifetime.lifetime.name, lifetime.lifetime.id
|
||||
);
|
||||
|
||||
let inserted = map.late_bound.insert(lifetime.lifetime.id);
|
||||
|
@ -2403,3 +2404,27 @@ fn insert_late_bound_lifetimes(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn report_missing_lifetime_specifiers(
|
||||
sess: &Session,
|
||||
span: Span,
|
||||
count: usize,
|
||||
) -> DiagnosticBuilder<'_> {
|
||||
let mut err = struct_span_err!(
|
||||
sess,
|
||||
span,
|
||||
E0106,
|
||||
"missing lifetime specifier{}",
|
||||
if count > 1 { "s" } else { "" }
|
||||
);
|
||||
|
||||
let msg = if count > 1 {
|
||||
format!("expected {} lifetime parameters", count)
|
||||
} else {
|
||||
format!("expected lifetime parameter")
|
||||
};
|
||||
|
||||
err.span_label(span, msg);
|
||||
|
||||
err
|
||||
}
|
||||
|
|
22
src/test/ui/feature-gate-in_band_lifetimes-impl.rs
Normal file
22
src/test/ui/feature-gate-in_band_lifetimes-impl.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2017 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.
|
||||
|
||||
#![allow(warnings)]
|
||||
#![feature(underscore_lifetimes)]
|
||||
|
||||
trait MyTrait<'a> { }
|
||||
|
||||
impl<'a> MyTrait<'a> for &u32 { }
|
||||
//~^ ERROR missing lifetime specifier
|
||||
|
||||
impl<'a> MyTrait<'_> for &'a f32 { }
|
||||
//~^ ERROR missing lifetime specifier
|
||||
|
||||
fn main() {}
|
15
src/test/ui/feature-gate-in_band_lifetimes-impl.stderr
Normal file
15
src/test/ui/feature-gate-in_band_lifetimes-impl.stderr
Normal file
|
@ -0,0 +1,15 @@
|
|||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/feature-gate-in_band_lifetimes-impl.rs:16:26
|
||||
|
|
||||
LL | impl<'a> MyTrait<'a> for &u32 { }
|
||||
| ^ expected lifetime parameter
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/feature-gate-in_band_lifetimes-impl.rs:19:18
|
||||
|
|
||||
LL | impl<'a> MyTrait<'_> for &'a f32 { }
|
||||
| ^^ expected lifetime parameter
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0106`.
|
38
src/test/ui/in-band-lifetimes/impl/assoc-type.rs
Normal file
38
src/test/ui/in-band-lifetimes/impl/assoc-type.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
// 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.
|
||||
|
||||
// Test that we do not yet support elision in associated types, even
|
||||
// when there is just one name we could take from the impl header.
|
||||
|
||||
#![allow(warnings)]
|
||||
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(underscore_lifetimes)]
|
||||
|
||||
trait MyTrait {
|
||||
type Output;
|
||||
}
|
||||
|
||||
impl MyTrait for &i32 {
|
||||
type Output = &i32;
|
||||
//~^ ERROR missing lifetime specifier
|
||||
}
|
||||
|
||||
impl MyTrait for &u32 {
|
||||
type Output = &'_ i32;
|
||||
//~^ ERROR missing lifetime specifier
|
||||
}
|
||||
|
||||
// This is what you have to do:
|
||||
impl MyTrait for &'a f32 {
|
||||
type Output = &'a f32;
|
||||
}
|
||||
|
||||
fn main() { }
|
15
src/test/ui/in-band-lifetimes/impl/assoc-type.stderr
Normal file
15
src/test/ui/in-band-lifetimes/impl/assoc-type.stderr
Normal file
|
@ -0,0 +1,15 @@
|
|||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/assoc-type.rs:24:19
|
||||
|
|
||||
LL | type Output = &i32;
|
||||
| ^ expected lifetime parameter
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/assoc-type.rs:29:20
|
||||
|
|
||||
LL | type Output = &'_ i32;
|
||||
| ^^ expected lifetime parameter
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0106`.
|
45
src/test/ui/in-band-lifetimes/impl/dyn-trait.rs
Normal file
45
src/test/ui/in-band-lifetimes/impl/dyn-trait.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
// 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.
|
||||
|
||||
// Test that `impl MyTrait<'_> for &i32` is equivalent to `impl<'a,
|
||||
// 'b> MyTrait<'a> for &'b i32`.
|
||||
|
||||
#![allow(warnings)]
|
||||
|
||||
#![feature(dyn_trait)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(underscore_lifetimes)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
// Equivalent to `Box<dyn Debug + 'static>`:
|
||||
trait StaticTrait { }
|
||||
impl StaticTrait for Box<dyn Debug> { }
|
||||
|
||||
// Equivalent to `Box<dyn Debug + 'static>`:
|
||||
trait NotStaticTrait { }
|
||||
impl NotStaticTrait for Box<dyn Debug + '_> { }
|
||||
|
||||
fn static_val<T: StaticTrait>(_: T) {
|
||||
}
|
||||
|
||||
fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
|
||||
static_val(x); //~ ERROR cannot infer
|
||||
}
|
||||
|
||||
fn not_static_val<T: NotStaticTrait>(_: T) {
|
||||
}
|
||||
|
||||
fn with_dyn_debug_not_static<'a>(x: Box<dyn Debug + 'a>) {
|
||||
not_static_val(x); // OK
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
22
src/test/ui/in-band-lifetimes/impl/dyn-trait.stderr
Normal file
22
src/test/ui/in-band-lifetimes/impl/dyn-trait.stderr
Normal file
|
@ -0,0 +1,22 @@
|
|||
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
|
||||
--> $DIR/dyn-trait.rs:34:16
|
||||
|
|
||||
LL | static_val(x); //~ ERROR cannot infer
|
||||
| ^
|
||||
|
|
||||
note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 33:1...
|
||||
--> $DIR/dyn-trait.rs:33:1
|
||||
|
|
||||
LL | fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: ...so that the expression is assignable:
|
||||
expected std::boxed::Box<std::fmt::Debug>
|
||||
found std::boxed::Box<std::fmt::Debug + 'a>
|
||||
= note: but, the lifetime must be valid for the static lifetime...
|
||||
= note: ...so that the types are compatible:
|
||||
expected StaticTrait
|
||||
found StaticTrait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0495`.
|
23
src/test/ui/in-band-lifetimes/impl/path-elided.rs
Normal file
23
src/test/ui/in-band-lifetimes/impl/path-elided.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
// 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.
|
||||
#![allow(warnings)]
|
||||
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(underscore_lifetimes)]
|
||||
|
||||
trait MyTrait { }
|
||||
|
||||
struct Foo<'a> { x: &'a u32 }
|
||||
|
||||
impl MyTrait for Foo {
|
||||
//~^ ERROR missing lifetime specifier
|
||||
}
|
||||
|
||||
fn main() {}
|
9
src/test/ui/in-band-lifetimes/impl/path-elided.stderr
Normal file
9
src/test/ui/in-band-lifetimes/impl/path-elided.stderr
Normal file
|
@ -0,0 +1,9 @@
|
|||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/path-elided.rs:19:18
|
||||
|
|
||||
LL | impl MyTrait for Foo {
|
||||
| ^^^ expected lifetime parameter
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0106`.
|
47
src/test/ui/in-band-lifetimes/impl/path-underscore.rs
Normal file
47
src/test/ui/in-band-lifetimes/impl/path-underscore.rs
Normal file
|
@ -0,0 +1,47 @@
|
|||
// 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.
|
||||
|
||||
// Test that `impl MyTrait for Foo<'_>` works.
|
||||
|
||||
// run-pass
|
||||
|
||||
#![allow(warnings)]
|
||||
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(underscore_lifetimes)]
|
||||
|
||||
trait MyTrait { }
|
||||
|
||||
struct Foo<'a> { x: &'a u32 }
|
||||
|
||||
impl MyTrait for Foo<'_> {
|
||||
}
|
||||
|
||||
fn impls_my_trait<T: MyTrait>() { }
|
||||
|
||||
fn impls_my_trait_val<T: MyTrait>(_: T) {
|
||||
impls_my_trait::<T>();
|
||||
}
|
||||
|
||||
fn random_where_clause()
|
||||
where for<'a> Foo<'a>: MyTrait { }
|
||||
|
||||
fn main() {
|
||||
let x = 22;
|
||||
let f = Foo { x: &x };
|
||||
|
||||
// This type is `Foo<'x>` for a local lifetime `'x`; so the impl
|
||||
// must apply to any lifetime to apply to this.
|
||||
impls_my_trait_val(f);
|
||||
|
||||
impls_my_trait::<Foo<'static>>();
|
||||
|
||||
random_where_clause();
|
||||
}
|
43
src/test/ui/in-band-lifetimes/impl/ref-underscore.rs
Normal file
43
src/test/ui/in-band-lifetimes/impl/ref-underscore.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
// 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.
|
||||
|
||||
// Test that `impl MyTrait for &i32` works and is equivalent to any lifetime.
|
||||
|
||||
// run-pass
|
||||
|
||||
#![allow(warnings)]
|
||||
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(underscore_lifetimes)]
|
||||
|
||||
trait MyTrait { }
|
||||
|
||||
impl MyTrait for &i32 {
|
||||
}
|
||||
|
||||
fn impls_my_trait<T: MyTrait>() { }
|
||||
|
||||
fn impls_my_trait_val<T: MyTrait>(_: T) {
|
||||
impls_my_trait::<T>();
|
||||
}
|
||||
|
||||
fn random_where_clause()
|
||||
where for<'a> &'a i32: MyTrait { }
|
||||
|
||||
fn main() {
|
||||
let x = 22;
|
||||
let f = &x;
|
||||
|
||||
impls_my_trait_val(f);
|
||||
|
||||
impls_my_trait::<&'static i32>();
|
||||
|
||||
random_where_clause();
|
||||
}
|
21
src/test/ui/in-band-lifetimes/impl/trait-elided.rs
Normal file
21
src/test/ui/in-band-lifetimes/impl/trait-elided.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
// 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.
|
||||
#![allow(warnings)]
|
||||
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(underscore_lifetimes)]
|
||||
|
||||
trait MyTrait<'a> { }
|
||||
|
||||
impl MyTrait for u32 {
|
||||
//~^ ERROR missing lifetime specifier
|
||||
}
|
||||
|
||||
fn main() {}
|
9
src/test/ui/in-band-lifetimes/impl/trait-elided.stderr
Normal file
9
src/test/ui/in-band-lifetimes/impl/trait-elided.stderr
Normal file
|
@ -0,0 +1,9 @@
|
|||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/trait-elided.rs:17:6
|
||||
|
|
||||
LL | impl MyTrait for u32 {
|
||||
| ^^^^^^^ expected lifetime parameter
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0106`.
|
48
src/test/ui/in-band-lifetimes/impl/trait-underscore.rs
Normal file
48
src/test/ui/in-band-lifetimes/impl/trait-underscore.rs
Normal file
|
@ -0,0 +1,48 @@
|
|||
// 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.
|
||||
|
||||
// Test that `impl MyTrait<'_> for &i32` is equivalent to `impl<'a,
|
||||
// 'b> MyTrait<'a> for &'b i32`.
|
||||
//
|
||||
// run-pass
|
||||
|
||||
#![allow(warnings)]
|
||||
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(underscore_lifetimes)]
|
||||
|
||||
trait MyTrait<'a> { }
|
||||
|
||||
// This is equivalent to `MyTrait<'a> for &'b i32`, which is proven by
|
||||
// the code below.
|
||||
impl MyTrait<'_> for &i32 {
|
||||
}
|
||||
|
||||
// When called, T will be `&'x i32` for some `'x`, so since we can
|
||||
// prove that `&'x i32: for<'a> MyTrait<'a>, then we know that the
|
||||
// lifetime parameter above is disconnected.
|
||||
fn impls_my_trait<T: for<'a> MyTrait<'a>>() { }
|
||||
|
||||
fn impls_my_trait_val<T: for<'a> MyTrait<'a>>(_: T) {
|
||||
impls_my_trait::<T>();
|
||||
}
|
||||
|
||||
fn random_where_clause()
|
||||
where for<'a, 'b> &'a i32: MyTrait<'b> { }
|
||||
|
||||
fn main() {
|
||||
let x = 22;
|
||||
let f = &x;
|
||||
impls_my_trait_val(f);
|
||||
|
||||
impls_my_trait::<&'static i32>();
|
||||
|
||||
random_where_clause();
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
// Check that the `'_` in `dyn Trait + '_` acts like ordinary elision,
|
||||
// and not like an object lifetime default.
|
||||
//
|
||||
// cc #48468
|
||||
|
||||
#![feature(dyn_trait)]
|
||||
#![feature(underscore_lifetimes)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
struct Foo {
|
||||
x: Box<dyn Debug + '_>, //~ ERROR missing lifetime specifier
|
||||
//~^ ERROR E0228
|
||||
}
|
||||
|
||||
fn main() { }
|
|
@ -0,0 +1,16 @@
|
|||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/dyn-trait-underscore-in-struct.rs:22:24
|
||||
|
|
||||
LL | x: Box<dyn Debug + '_>, //~ ERROR missing lifetime specifier
|
||||
| ^^ expected lifetime parameter
|
||||
|
||||
error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
|
||||
--> $DIR/dyn-trait-underscore-in-struct.rs:22:12
|
||||
|
|
||||
LL | x: Box<dyn Debug + '_>, //~ ERROR missing lifetime specifier
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors occurred: E0106, E0228.
|
||||
For more information about an error, try `rustc --explain E0106`.
|
Loading…
Add table
Add a link
Reference in a new issue