diff options
| -rw-r--r-- | src/librustc/hir/intravisit.rs | 1 | ||||
| -rw-r--r-- | src/librustc/hir/lowering.rs | 19 | ||||
| -rw-r--r-- | src/librustc/hir/mod.rs | 21 | ||||
| -rw-r--r-- | src/librustc/middle/resolve_lifetime.rs | 17 | ||||
| -rw-r--r-- | src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs | 3 | ||||
| -rw-r--r-- | src/test/ui/async-await/issues/issue-62517-1.rs | 23 | ||||
| -rw-r--r-- | src/test/ui/async-await/issues/issue-62517-2.rs | 16 | ||||
| -rw-r--r-- | src/test/ui/async-await/issues/issue-62517-2.stderr | 11 | ||||
| -rw-r--r-- | src/test/ui/impl-trait/dyn-trait-elided-two-inputs-assoc.rs | 16 | ||||
| -rw-r--r-- | src/test/ui/impl-trait/dyn-trait-elided-two-inputs-param.rs | 11 | ||||
| -rw-r--r-- | src/test/ui/impl-trait/dyn-trait-elided-two-inputs-ref-param.rs | 23 | ||||
| -rw-r--r-- | src/test/ui/lifetimes/lifetime-elision-return-type-trait.rs | 2 | ||||
| -rw-r--r-- | src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr | 10 |
13 files changed, 163 insertions, 10 deletions
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 2c6373bdfa4..fa274f831b7 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -433,6 +433,7 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime LifetimeName::Static | LifetimeName::Error | LifetimeName::Implicit | + LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Underscore => {} } } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index cd127177e9f..e04e45e5fbc 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1560,6 +1560,11 @@ impl<'a> LoweringContext<'a> { } } hir::LifetimeName::Param(_) => lifetime.name, + + // Refers to some other lifetime that is "in + // scope" within the type. + hir::LifetimeName::ImplicitObjectLifetimeDefault => return, + hir::LifetimeName::Error | hir::LifetimeName::Static => return, }; @@ -2550,6 +2555,12 @@ impl<'a> LoweringContext<'a> { hir::LifetimeName::Implicit | hir::LifetimeName::Underscore | hir::LifetimeName::Static => hir::ParamName::Plain(lt.name.ident()), + hir::LifetimeName::ImplicitObjectLifetimeDefault => { + span_bug!( + param.ident.span, + "object-lifetime-default should not occur here", + ); + } hir::LifetimeName::Error => ParamName::Error, }; @@ -3293,7 +3304,13 @@ impl<'a> LoweringContext<'a> { AnonymousLifetimeMode::PassThrough => {} } - self.new_implicit_lifetime(span) + let r = hir::Lifetime { + hir_id: self.next_id(), + span, + name: hir::LifetimeName::ImplicitObjectLifetimeDefault, + }; + debug!("elided_dyn_bound: r={:?}", r); + r } fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime { diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index b469b7016be..98304818852 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -221,6 +221,19 @@ pub enum LifetimeName { /// User wrote nothing (e.g., the lifetime in `&u32`). Implicit, + /// Implicit lifetime in a context like `dyn Foo`. This is + /// distinguished from implicit lifetimes elsewhere because the + /// lifetime that they default to must appear elsewhere within the + /// enclosing type. This means that, in an `impl Trait` context, we + /// don't have to create a parameter for them. That is, `impl + /// Trait<Item = &u32>` expands to an opaque type like `type + /// Foo<'a> = impl Trait<Item = &'a u32>`, but `impl Trait<item = + /// dyn Bar>` expands to `type Foo = impl Trait<Item = dyn Bar + + /// 'static>`. The latter uses `ImplicitObjectLifetimeDefault` so + /// that surrounding code knows not to create a lifetime + /// parameter. + ImplicitObjectLifetimeDefault, + /// Indicates an error during lowering (usually `'_` in wrong place) /// that was already reported. Error, @@ -235,7 +248,9 @@ pub enum LifetimeName { impl LifetimeName { pub fn ident(&self) -> Ident { match *self { - LifetimeName::Implicit | LifetimeName::Error => Ident::invalid(), + LifetimeName::ImplicitObjectLifetimeDefault + | LifetimeName::Implicit + | LifetimeName::Error => Ident::invalid(), LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime), LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime), LifetimeName::Param(param_name) => param_name.ident(), @@ -244,7 +259,9 @@ impl LifetimeName { pub fn is_elided(&self) -> bool { match self { - LifetimeName::Implicit | LifetimeName::Underscore => true, + LifetimeName::ImplicitObjectLifetimeDefault + | LifetimeName::Implicit + | LifetimeName::Underscore => true, // It might seem surprising that `Fresh(_)` counts as // *not* elided -- but this is because, as far as the code diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 74031541f56..3b604bef78e 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -5,6 +5,8 @@ //! used between functions, and they operate in a purely top-down //! way. Therefore, we break lifetime name resolution into a separate pass. +// ignore-tidy-filelength + use crate::hir::def::{Res, DefKind}; use crate::hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use crate::hir::map::Map; @@ -591,6 +593,14 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } match lifetime.name { LifetimeName::Implicit => { + // For types like `dyn Foo`, we should + // generate a special form of elided. + span_bug!( + ty.span, + "object-lifetime-default expected, not implict", + ); + } + LifetimeName::ImplicitObjectLifetimeDefault => { // If the user does not write *anything*, we // use the object lifetime defaulting // rules. So e.g., `Box<dyn Debug>` becomes @@ -2643,6 +2653,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => { self.resolve_lifetime_ref(lt); } + hir::LifetimeName::ImplicitObjectLifetimeDefault => { + self.tcx.sess.delay_span_bug( + lt.span, + "lowering generated `ImplicitObjectLifetimeDefault` \ + outside of an object type", + ) + } hir::LifetimeName::Error => { // No need to do anything, error already reported. } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs index 3f5b2f4bce7..ca68b9e31b6 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs @@ -578,7 +578,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { }) } - hir::LifetimeName::Implicit => { + hir::LifetimeName::ImplicitObjectLifetimeDefault + | hir::LifetimeName::Implicit => { // In this case, the user left off the lifetime; so // they wrote something like: // diff --git a/src/test/ui/async-await/issues/issue-62517-1.rs b/src/test/ui/async-await/issues/issue-62517-1.rs new file mode 100644 index 00000000000..5955d9751af --- /dev/null +++ b/src/test/ui/async-await/issues/issue-62517-1.rs @@ -0,0 +1,23 @@ +// Regression test for #62517. We used to ICE when you had an `async +// fn` with an `impl Trait` return that mentioned a `dyn Bar` with no +// explicit lifetime bound. +// +// edition:2018 +// check-pass + +#![feature(async_await)] + +trait FirstTrait {} +trait SecondTrait { + type Item: ?Sized; +} + +async fn foo(x: &str) -> impl SecondTrait<Item = dyn FirstTrait> { +} + + +impl<T> SecondTrait for T { + type Item = dyn FirstTrait; +} + +fn main() { } diff --git a/src/test/ui/async-await/issues/issue-62517-2.rs b/src/test/ui/async-await/issues/issue-62517-2.rs new file mode 100644 index 00000000000..72dae58e516 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-62517-2.rs @@ -0,0 +1,16 @@ +// Regression test for #62517. We used to ICE when you had an `async +// fn` with an `impl Trait` return that mentioned a `dyn Bar` with no +// explicit lifetime bound. +// +// edition:2018 + +#![feature(async_await)] + +trait Object {} + +trait Alpha<Param> {} + +async fn foo<'a>(_: &'a ()) -> impl Alpha<dyn Object> {} +//~^ ERROR not satisfied + +fn main() { } diff --git a/src/test/ui/async-await/issues/issue-62517-2.stderr b/src/test/ui/async-await/issues/issue-62517-2.stderr new file mode 100644 index 00000000000..4f9b3047bfe --- /dev/null +++ b/src/test/ui/async-await/issues/issue-62517-2.stderr @@ -0,0 +1,11 @@ +error[E0277]: the trait bound `(): Alpha<(dyn Object + 'static)>` is not satisfied + --> $DIR/issue-62517-2.rs:13:32 + | +LL | async fn foo<'a>(_: &'a ()) -> impl Alpha<dyn Object> {} + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Alpha<(dyn Object + 'static)>` is not implemented for `()` + | + = note: the return type of a function must have a statically known size + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/impl-trait/dyn-trait-elided-two-inputs-assoc.rs b/src/test/ui/impl-trait/dyn-trait-elided-two-inputs-assoc.rs new file mode 100644 index 00000000000..3b714157384 --- /dev/null +++ b/src/test/ui/impl-trait/dyn-trait-elided-two-inputs-assoc.rs @@ -0,0 +1,16 @@ +// Test that we don't get an error with `dyn Bar` in an impl Trait +// when there are multiple inputs. The `dyn Bar` should default to `+ +// 'static`. This used to erroneously generate an error (cc #62517). +// +// check-pass + +trait Foo { type Item: ?Sized; } +trait Bar { } + +impl<T> Foo for T { + type Item = dyn Bar; +} + +fn foo(x: &str, y: &str) -> impl Foo<Item = dyn Bar> { () } + +fn main() { } diff --git a/src/test/ui/impl-trait/dyn-trait-elided-two-inputs-param.rs b/src/test/ui/impl-trait/dyn-trait-elided-two-inputs-param.rs new file mode 100644 index 00000000000..e8da52aad0e --- /dev/null +++ b/src/test/ui/impl-trait/dyn-trait-elided-two-inputs-param.rs @@ -0,0 +1,11 @@ +// Test that we don't get an error with `dyn Object` in an impl Trait +// when there are multiple inputs. The `dyn Object` should default to `+ +// 'static`. This used to erroneously generate an error (cc #62517). +// +// check-pass + +trait Alpha<Item: ?Sized> {} +trait Object {} +impl<T> Alpha<dyn Object> for T {} +fn alpha(x: &str, y: &str) -> impl Alpha<dyn Object> { () } +fn main() { } diff --git a/src/test/ui/impl-trait/dyn-trait-elided-two-inputs-ref-param.rs b/src/test/ui/impl-trait/dyn-trait-elided-two-inputs-ref-param.rs new file mode 100644 index 00000000000..8d34c1b6c2a --- /dev/null +++ b/src/test/ui/impl-trait/dyn-trait-elided-two-inputs-ref-param.rs @@ -0,0 +1,23 @@ +// Test that `impl Alpha<dyn Object>` resets the object-lifetime +// default to `'static`. +// +// check-pass + +trait Alpha<Item: ?Sized> { + fn item(&self) -> Box<Item> { + panic!() + } +} + +trait Object {} +impl<T> Alpha<dyn Object> for T {} +fn alpha(x: &str, y: &str) -> impl Alpha<dyn Object> { () } +fn is_static<T>(_: T) where T: 'static { } + +fn bar(x: &str) -> &impl Alpha<dyn Object> { &() } + +fn main() { + let s = format!("foo"); + let r = bar(&s); + is_static(r.item()); +} diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.rs b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.rs index 2370084b072..ea0d0ccbc55 100644 --- a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.rs +++ b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.rs @@ -6,7 +6,7 @@ trait Future { use std::error::Error; fn foo() -> impl Future<Item=(), Error=Box<dyn Error>> { -//~^ ERROR missing lifetime +//~^ ERROR not satisfied Ok(()) } diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr index 06b317ce952..228582d0001 100644 --- a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr +++ b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr @@ -1,11 +1,11 @@ -error[E0106]: missing lifetime specifier - --> $DIR/lifetime-elision-return-type-trait.rs:8:44 +error[E0277]: the trait bound `std::result::Result<(), _>: Future` is not satisfied + --> $DIR/lifetime-elision-return-type-trait.rs:8:13 | LL | fn foo() -> impl Future<Item=(), Error=Box<dyn Error>> { - | ^^^^^^^^^ help: consider giving it a 'static lifetime: `dyn Error + 'static` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Future` is not implemented for `std::result::Result<(), _>` | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from + = note: the return type of a function must have a statically known size error: aborting due to previous error -For more information about this error, try `rustc --explain E0106`. +For more information about this error, try `rustc --explain E0277`. |
