about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-08-19 22:48:54 +0200
committerGitHub <noreply@github.com>2019-08-19 22:48:54 +0200
commitbece1177c07bc528df16bf313eb07a762c0853f7 (patch)
treee3ae8dfed8e5e84a52cca92fa5cdd053e17c92b5 /src
parent4486c02695ae3a3074f7039bc30cb44827940e92 (diff)
parent7ee1af51ccc521779300eba0819bcb08c07632cf (diff)
downloadrust-bece1177c07bc528df16bf313eb07a762c0853f7.tar.gz
rust-bece1177c07bc528df16bf313eb07a762c0853f7.zip
Rollup merge of #63376 - nikomatsakis:async-await-issue-62517, r=cramertj
use different lifetime name for object-lifetime-default elision

Introduce a distinct value for `LifetimeName` to use when this is a object-lifetime-default elision. This allows us to avoid creating incorrect lifetime parameters for the opaque types that result. We really need to overhaul this setup at some point! It's getting increasingly byzantine. But this seems like a relatively... surgical fix.

r? @cramertj

Fixes #62517
Diffstat (limited to 'src')
-rw-r--r--src/librustc/hir/intravisit.rs1
-rw-r--r--src/librustc/hir/lowering.rs61
-rw-r--r--src/librustc/hir/mod.rs21
-rw-r--r--src/librustc/infer/opaque_types/mod.rs1
-rw-r--r--src/librustc/middle/resolve_lifetime.rs93
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs3
-rw-r--r--src/test/ui/async-await/issues/issue-62517-1.rs23
-rw-r--r--src/test/ui/async-await/issues/issue-62517-2.rs18
-rw-r--r--src/test/ui/impl-trait/dyn-trait-elided-two-inputs-assoc.rs16
-rw-r--r--src/test/ui/impl-trait/dyn-trait-elided-two-inputs-param.rs11
-rw-r--r--src/test/ui/impl-trait/dyn-trait-elided-two-inputs-ref-assoc.rs27
-rw-r--r--src/test/ui/impl-trait/dyn-trait-elided-two-inputs-ref-param.rs23
-rw-r--r--src/test/ui/lifetimes/lifetime-elision-return-type-trait.rs2
-rw-r--r--src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr10
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic1.rs27
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic1.stderr8
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic2.rs30
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic2.stderr8
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.rs23
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.stderr8
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-static.rs28
21 files changed, 429 insertions, 13 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 cc2e6137df3..e04e45e5fbc 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -322,7 +322,7 @@ enum ParenthesizedGenericArgs {
 /// `resolve_lifetime` module. Often we "fallthrough" to that code by generating
 /// an "elided" or "underscore" lifetime name. In the future, we probably want to move
 /// everything into HIR lowering.
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 enum AnonymousLifetimeMode {
     /// For **Modern** cases, create a new anonymous region parameter
     /// and reference that.
@@ -715,10 +715,16 @@ impl<'a> LoweringContext<'a> {
         anonymous_lifetime_mode: AnonymousLifetimeMode,
         op: impl FnOnce(&mut Self) -> R,
     ) -> R {
+        debug!(
+            "with_anonymous_lifetime_mode(anonymous_lifetime_mode={:?})",
+            anonymous_lifetime_mode,
+        );
         let old_anonymous_lifetime_mode = self.anonymous_lifetime_mode;
         self.anonymous_lifetime_mode = anonymous_lifetime_mode;
         let result = op(self);
         self.anonymous_lifetime_mode = old_anonymous_lifetime_mode;
+        debug!("with_anonymous_lifetime_mode: restoring anonymous_lifetime_mode={:?}",
+               old_anonymous_lifetime_mode);
         result
     }
 
@@ -1355,6 +1361,13 @@ impl<'a> LoweringContext<'a> {
         opaque_ty_node_id: NodeId,
         lower_bounds: impl FnOnce(&mut LoweringContext<'_>) -> hir::GenericBounds,
     ) -> hir::TyKind {
+        debug!(
+            "lower_opaque_impl_trait(fn_def_id={:?}, opaque_ty_node_id={:?}, span={:?})",
+            fn_def_id,
+            opaque_ty_node_id,
+            span,
+        );
+
         // Make sure we know that some funky desugaring has been going on here.
         // This is a first: there is code in other places like for loop
         // desugaring that explicitly states that we don't want to track that.
@@ -1382,6 +1395,14 @@ impl<'a> LoweringContext<'a> {
             &hir_bounds,
         );
 
+        debug!(
+            "lower_opaque_impl_trait: lifetimes={:#?}", lifetimes,
+        );
+
+        debug!(
+            "lower_opaque_impl_trait: lifetime_defs={:#?}", lifetime_defs,
+        );
+
         self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
             let opaque_ty_item = hir::OpaqueTy {
                 generics: hir::Generics {
@@ -1397,7 +1418,7 @@ impl<'a> LoweringContext<'a> {
                 origin: hir::OpaqueTyOrigin::FnReturn,
             };
 
-            trace!("exist ty from impl trait def-index: {:#?}", opaque_ty_def_index);
+            trace!("lower_opaque_impl_trait: {:#?}", opaque_ty_def_index);
             let opaque_ty_id = lctx.generate_opaque_type(
                 opaque_ty_node_id,
                 opaque_ty_item,
@@ -1445,6 +1466,13 @@ impl<'a> LoweringContext<'a> {
         parent_index: DefIndex,
         bounds: &hir::GenericBounds,
     ) -> (HirVec<hir::GenericArg>, HirVec<hir::GenericParam>) {
+        debug!(
+            "lifetimes_from_impl_trait_bounds(opaque_ty_id={:?}, \
+             parent_index={:?}, \
+             bounds={:#?})",
+            opaque_ty_id, parent_index, bounds,
+        );
+
         // This visitor walks over `impl Trait` bounds and creates defs for all lifetimes that
         // appear in the bounds, excluding lifetimes that are created within the bounds.
         // E.g., `'a`, `'b`, but not `'c` in `impl for<'c> SomeTrait<'a, 'b, 'c>`.
@@ -1532,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,
                 };
 
@@ -2182,6 +2215,14 @@ impl<'a> LoweringContext<'a> {
         fn_def_id: DefId,
         opaque_ty_node_id: NodeId,
     ) -> hir::FunctionRetTy {
+        debug!(
+            "lower_async_fn_ret_ty(\
+             output={:?}, \
+             fn_def_id={:?}, \
+             opaque_ty_node_id={:?})",
+            output, fn_def_id, opaque_ty_node_id,
+        );
+
         let span = output.span();
 
         let opaque_ty_span = self.mark_span_with_reason(
@@ -2264,6 +2305,8 @@ impl<'a> LoweringContext<'a> {
                 ),
             );
 
+            debug!("lower_async_fn_ret_ty: future_bound={:#?}", future_bound);
+
             // Calculate all the lifetimes that should be captured
             // by the opaque type. This should include all in-scope
             // lifetime parameters, including those defined in-band.
@@ -2512,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,
                 };
 
@@ -3255,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/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs
index 5c62f76e3bb..fd4f2c99659 100644
--- a/src/librustc/infer/opaque_types/mod.rs
+++ b/src/librustc/infer/opaque_types/mod.rs
@@ -1108,6 +1108,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
         // Use the same type variable if the exact same opaque type appears more
         // than once in the return type (e.g., if it's passed to a type alias).
         if let Some(opaque_defn) = self.opaque_types.get(&def_id) {
+            debug!("instantiate_opaque_types: returning concrete ty {:?}", opaque_defn.concrete_ty);
             return opaque_defn.concrete_ty;
         }
         let span = tcx.def_span(def_id);
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index f8f01f79e1d..f5b0af61693 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;
@@ -556,6 +558,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
 
     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
         debug!("visit_ty: id={:?} ty={:?}", ty.hir_id, ty);
+        debug!("visit_ty: ty.node={:?}", ty.node);
         match ty.node {
             hir::TyKind::BareFn(ref c) => {
                 let next_early_index = self.next_early_index();
@@ -585,11 +588,20 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 self.is_in_fn_syntax = was_in_fn_syntax;
             }
             hir::TyKind::TraitObject(ref bounds, ref lifetime) => {
+                debug!("visit_ty: TraitObject(bounds={:?}, lifetime={:?})", bounds, lifetime);
                 for bound in bounds {
                     self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
                 }
                 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
@@ -897,6 +909,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     }
 
     fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
+        debug!("visit_lifetime(lifetime_ref={:?})", lifetime_ref);
         if lifetime_ref.is_elided() {
             self.resolve_elided_lifetimes(vec![lifetime_ref]);
             return;
@@ -1911,6 +1924,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
     }
 
     fn visit_segment_args(&mut self, res: Res, depth: usize, generic_args: &'tcx hir::GenericArgs) {
+        debug!(
+            "visit_segment_args(res={:?}, depth={:?}, generic_args={:?})",
+            res,
+            depth,
+            generic_args,
+        );
+
         if generic_args.parenthesized {
             let was_in_fn_syntax = self.is_in_fn_syntax;
             self.is_in_fn_syntax = true;
@@ -1964,6 +1984,23 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             _ => None,
         };
 
+        debug!("visit_segment_args: type_def_id={:?}", type_def_id);
+
+        // Compute a vector of defaults, one for each type parameter,
+        // per the rules given in RFCs 599 and 1156. Example:
+        //
+        // ```rust
+        // struct Foo<'a, T: 'a, U> { }
+        // ```
+        //
+        // If you have `Foo<'x, dyn Bar, dyn Baz>`, we want to default
+        // `dyn Bar` to `dyn Bar + 'x` (because of the `T: 'a` bound)
+        // and `dyn Baz` to `dyn Baz + 'static` (because there is no
+        // such bound).
+        //
+        // Therefore, we would compute `object_lifetime_defaults` to a
+        // vector like `['x, 'static]`. Note that the vector only
+        // includes type parameters.
         let object_lifetime_defaults = type_def_id.map_or(vec![], |def_id| {
             let in_body = {
                 let mut scope = self.scope;
@@ -2003,6 +2040,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                             .collect()
                     })
             };
+            debug!("visit_segment_args: unsubst={:?}", unsubst);
             unsubst
                 .iter()
                 .map(|set| match *set {
@@ -2023,6 +2061,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                 .collect()
         });
 
+        debug!("visit_segment_args: object_lifetime_defaults={:?}", object_lifetime_defaults);
+
         let mut i = 0;
         for arg in &generic_args.args {
             match arg {
@@ -2045,8 +2085,49 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             }
         }
 
+        // Hack: when resolving the type `XX` in binding like `dyn
+        // Foo<'b, Item = XX>`, the current object-lifetime default
+        // would be to examine the trait `Foo` to check whether it has
+        // a lifetime bound declared on `Item`. e.g., if `Foo` is
+        // declared like so, then the default object lifetime bound in
+        // `XX` should be `'b`:
+        //
+        // ```rust
+        // trait Foo<'a> {
+        //   type Item: 'a;
+        // }
+        // ```
+        //
+        // but if we just have `type Item;`, then it would be
+        // `'static`. However, we don't get all of this logic correct.
+        //
+        // Instead, we do something hacky: if there are no lifetime parameters
+        // to the trait, then we simply use a default object lifetime
+        // bound of `'static`, because there is no other possibility. On the other hand,
+        // if there ARE lifetime parameters, then we require the user to give an
+        // explicit bound for now.
+        //
+        // This is intended to leave room for us to implement the
+        // correct behavior in the future.
+        let has_lifetime_parameter = generic_args
+            .args
+            .iter()
+            .any(|arg| match arg {
+                GenericArg::Lifetime(_) => true,
+                _ => false,
+            });
+
+        // Resolve lifetimes found in the type `XX` from `Item = XX` bindings.
         for b in &generic_args.bindings {
-            self.visit_assoc_type_binding(b);
+            let scope = Scope::ObjectLifetimeDefault {
+                lifetime: if has_lifetime_parameter {
+                    None
+                } else {
+                    Some(Region::Static)
+                },
+                s: self.scope,
+            };
+            self.with(scope, |_, this| this.visit_assoc_type_binding(b));
         }
     }
 
@@ -2347,6 +2428,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
     }
 
     fn resolve_elided_lifetimes(&mut self, lifetime_refs: Vec<&'tcx hir::Lifetime>) {
+        debug!("resolve_elided_lifetimes(lifetime_refs={:?})", lifetime_refs);
+
         if lifetime_refs.is_empty() {
             return;
         }
@@ -2539,6 +2622,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
     }
 
     fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
+        debug!("resolve_object_lifetime_default(lifetime_ref={:?})", lifetime_ref);
         let mut late_depth = 0;
         let mut scope = self.scope;
         let lifetime = loop {
@@ -2638,6 +2722,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..17fac408151
--- /dev/null
+++ b/src/test/ui/async-await/issues/issue-62517-2.rs
@@ -0,0 +1,18 @@
+// 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 Object {}
+
+trait Alpha<Param: ?Sized> {}
+
+async fn foo<'a>(_: &'a ()) -> impl Alpha<dyn Object> {}
+
+impl<T> Alpha<dyn Object> for T { }
+
+fn main() { }
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-assoc.rs b/src/test/ui/impl-trait/dyn-trait-elided-two-inputs-ref-assoc.rs
new file mode 100644
index 00000000000..aad9d89fe24
--- /dev/null
+++ b/src/test/ui/impl-trait/dyn-trait-elided-two-inputs-ref-assoc.rs
@@ -0,0 +1,27 @@
+// 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;
+
+    fn item(&self) -> Box<Self::Item> { panic!() }
+}
+
+trait Bar { }
+
+impl<T> Foo for T {
+    type Item = dyn Bar;
+}
+
+fn is_static<T>(_: T) where T: 'static { }
+
+fn bar(x: &str) -> &impl Foo<Item = dyn Bar> { &() }
+
+fn main() {
+    let s = format!("foo");
+    let r = bar(&s);
+    is_static(r.item());
+}
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`.
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic1.rs b/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic1.rs
new file mode 100644
index 00000000000..7337383e297
--- /dev/null
+++ b/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic1.rs
@@ -0,0 +1,27 @@
+// Test that `dyn Bar<Item = XX>` uses `'static` as the default object
+// lifetime bound for the type `XX`.
+
+trait Foo<'a> {
+    type Item: ?Sized;
+
+    fn item(&self) -> Box<Self::Item> { panic!() }
+}
+
+trait Bar { }
+
+impl<T> Foo<'_> for T {
+    type Item = dyn Bar;
+}
+
+fn is_static<T>(_: T) where T: 'static { }
+
+// Here, we should default to `dyn Bar + 'static`, but the current
+// code forces us into a conservative, hacky path.
+fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar> { &() }
+//~^ ERROR please supply an explicit bound
+
+fn main() {
+    let s = format!("foo");
+    let r = bar(&s);
+    is_static(r.item());
+}
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic1.stderr b/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic1.stderr
new file mode 100644
index 00000000000..9dbf7a78ed7
--- /dev/null
+++ b/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic1.stderr
@@ -0,0 +1,8 @@
+error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
+  --> $DIR/object-lifetime-default-dyn-binding-nonstatic1.rs:20:50
+   |
+LL | fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar> { &() }
+   |                                                  ^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic2.rs b/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic2.rs
new file mode 100644
index 00000000000..2a7415174f8
--- /dev/null
+++ b/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic2.rs
@@ -0,0 +1,30 @@
+// Test that `dyn Bar<Item = XX>` uses `'static` as the default object
+// lifetime bound for the type `XX`.
+
+trait Foo<'a> {
+    type Item: 'a + ?Sized;
+
+    fn item(&self) -> Box<Self::Item> { panic!() }
+}
+
+trait Bar { }
+
+impl<T> Foo<'_> for T {
+    type Item = dyn Bar;
+}
+
+fn is_static<T>(_: T) where T: 'static { }
+
+// Here, we default to `dyn Bar + 'a`.  Or, we *should*, but the
+// current code forces us into a conservative, hacky path.
+fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar> { &() }
+//~^ ERROR please supply an explicit bound
+
+fn main() {
+    let s = format!("foo");
+    let r = bar(&s);
+
+    // If it weren't for the conservative path above, we'd expect an
+    // error here.
+    is_static(r.item());
+}
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic2.stderr b/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic2.stderr
new file mode 100644
index 00000000000..d069f52ce47
--- /dev/null
+++ b/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic2.stderr
@@ -0,0 +1,8 @@
+error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
+  --> $DIR/object-lifetime-default-dyn-binding-nonstatic2.rs:20:50
+   |
+LL | fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar> { &() }
+   |                                                  ^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.rs b/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.rs
new file mode 100644
index 00000000000..51be999a632
--- /dev/null
+++ b/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.rs
@@ -0,0 +1,23 @@
+// Test that `dyn Bar<Item = XX>` uses `'static` as the default object
+// lifetime bound for the type `XX`.
+
+trait Foo<'a> {
+    type Item: ?Sized;
+
+    fn item(&self) -> Box<Self::Item> { panic!() }
+}
+
+trait Bar { }
+
+fn is_static<T>(_: T) where T: 'static { }
+
+// Here, we should default to `dyn Bar + 'static`, but the current
+// code forces us into a conservative, hacky path.
+fn bar(x: &str) -> &dyn Foo<Item = dyn Bar> { &() }
+//~^ ERROR please supply an explicit bound
+
+fn main() {
+    let s = format!("foo");
+    let r = bar(&s);
+    is_static(r.item());
+}
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.stderr b/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.stderr
new file mode 100644
index 00000000000..9c7b6b98f2e
--- /dev/null
+++ b/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.stderr
@@ -0,0 +1,8 @@
+error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
+  --> $DIR/object-lifetime-default-dyn-binding-nonstatic3.rs:16:36
+   |
+LL | fn bar(x: &str) -> &dyn Foo<Item = dyn Bar> { &() }
+   |                                    ^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-static.rs b/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-static.rs
new file mode 100644
index 00000000000..339f3356bd7
--- /dev/null
+++ b/src/test/ui/object-lifetime/object-lifetime-default-dyn-binding-static.rs
@@ -0,0 +1,28 @@
+// Test that `dyn Bar<Item = XX>` uses `'static` as the default object
+// lifetime bound for the type `XX`.
+//
+// check-pass
+
+trait Foo {
+    type Item: ?Sized;
+
+    fn item(&self) -> Box<Self::Item> { panic!() }
+}
+
+trait Bar { }
+
+impl<T> Foo for T {
+    type Item = dyn Bar;
+}
+
+fn is_static<T>(_: T) where T: 'static { }
+
+// Here, we default to `dyn Bar + 'static`, and not `&'x dyn Foo<Item
+// = dyn Bar + 'x>`.
+fn bar(x: &str) -> &dyn Foo<Item = dyn Bar> { &() }
+
+fn main() {
+    let s = format!("foo");
+    let r = bar(&s);
+    is_static(r.item());
+}