about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-12-14 10:22:43 +0000
committerbors <bors@rust-lang.org>2024-12-14 10:22:43 +0000
commitf5079d00e63718235f95353df38ebb0891bab5b4 (patch)
treea6900feb1a5792511b8ec4573d8e391b122410ee
parented141926048597e3649bb238ca3dc417904cd56c (diff)
parentd714a22e7bc38b158d09ee6294d1716acd1a727d (diff)
downloadrust-f5079d00e63718235f95353df38ebb0891bab5b4.tar.gz
rust-f5079d00e63718235f95353df38ebb0891bab5b4.zip
Auto merge of #134185 - compiler-errors:impl-trait-in-bindings, r=oli-obk
(Re-)Implement `impl_trait_in_bindings`

This reimplements the `impl_trait_in_bindings` feature for local bindings.

"`impl Trait` in bindings" serve as a form of *trait* ascription, where the type basically functions as an infer var but additionally registering the `impl Trait`'s trait bounds for the infer type. These trait bounds can be used to enforce that predicates hold, and can guide inference (e.g. for closure signature inference):

```rust
let _: impl Fn(&u8) -> &u8 = |x| x;
```

They are implemented as an additional set of bounds that are registered when the type is lowered during typeck, and then these bounds are tied to a given `CanonicalUserTypeAscription` for borrowck. We enforce these `CanonicalUserTypeAscription` bounds during borrowck to make sure that the `impl Trait` types are sensitive to lifetimes:

```rust
trait Static: 'static {}
impl<T> Static for T where T: 'static {}

let local = 1;
let x: impl Static = &local;
//~^ ERROR `local` does not live long enough
```

r? oli-obk

cc #63065

---

Why can't we just use TAIT inference or something? Well, TAITs in bodies have the problem that they cannot reference lifetimes local to a body. For example:

```rust
type TAIT = impl Display;
let local = 0;
let x: TAIT = &local;
//~^ ERROR `local` does not live long enough
```

That's because TAITs requires us to do *opaque type inference* which is pretty strict, since we need to remap all of the lifetimes of the hidden type to universal regions. This is simply not possible here.

---

I consider this part of the "impl trait everywhere" experiment. I'm not certain if this needs yet another lang team experiment.
-rw-r--r--compiler/rustc_ast_lowering/src/block.rs19
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs10
-rw-r--r--compiler/rustc_borrowck/src/type_check/canonical.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/input_output.rs4
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs10
-rw-r--r--compiler/rustc_feature/src/removed.rs3
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs2
-rw-r--r--compiler/rustc_hir/src/intravisit.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs11
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs15
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs26
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs45
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs34
-rw-r--r--compiler/rustc_hir_typeck/src/gather_locals.rs9
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs2
-rw-r--r--compiler/rustc_middle/src/query/plumbing.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs43
-rw-r--r--compiler/rustc_mir_build/src/build/matches/match_pair.rs5
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs5
-rw-r--r--compiler/rustc_mir_build/src/thir/util.rs4
-rw-r--r--compiler/rustc_passes/src/input_stats.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs14
-rw-r--r--src/librustdoc/clean/mod.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs3
-rw-r--r--tests/ui/feature-gates/feature-gate-impl-trait-in-bindings.rs4
-rw-r--r--tests/ui/feature-gates/feature-gate-impl-trait-in-bindings.stderr14
-rw-r--r--tests/ui/impl-trait/in-bindings/bad-nesting.rs10
-rw-r--r--tests/ui/impl-trait/in-bindings/bad-nesting.stderr12
-rw-r--r--tests/ui/impl-trait/in-bindings/escaping-bound-var.rs14
-rw-r--r--tests/ui/impl-trait/in-bindings/escaping-bound-var.stderr8
-rw-r--r--tests/ui/impl-trait/in-bindings/lifetime-failure.rs12
-rw-r--r--tests/ui/impl-trait/in-bindings/lifetime-failure.stderr16
-rw-r--r--tests/ui/impl-trait/in-bindings/nesting-lifetime-failure.rs10
-rw-r--r--tests/ui/impl-trait/in-bindings/nesting-lifetime-failure.stderr16
-rw-r--r--tests/ui/impl-trait/in-bindings/nesting.rs7
-rw-r--r--tests/ui/impl-trait/in-bindings/simple.rs10
-rw-r--r--tests/ui/impl-trait/in-bindings/trait-failure.rs13
-rw-r--r--tests/ui/impl-trait/in-bindings/trait-failure.stderr24
-rw-r--r--tests/ui/impl-trait/issues/issue-54600.stderr3
-rw-r--r--tests/ui/impl-trait/issues/issue-54840.stderr3
-rw-r--r--tests/ui/impl-trait/issues/issue-58504.stderr3
-rw-r--r--tests/ui/impl-trait/issues/issue-58956.stderr3
-rw-r--r--tests/ui/impl-trait/issues/issue-70971.stderr3
-rw-r--r--tests/ui/impl-trait/issues/issue-79099.stderr3
-rw-r--r--tests/ui/impl-trait/issues/issue-84919.stderr3
-rw-r--r--tests/ui/impl-trait/issues/issue-87295.stderr3
-rw-r--r--tests/ui/impl-trait/where-allowed.stderr3
-rw-r--r--tests/ui/typeck/issue-104513-ice.stderr3
53 files changed, 442 insertions, 52 deletions
diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs
index 20d3ce65fac..88ce6f80e10 100644
--- a/compiler/rustc_ast_lowering/src/block.rs
+++ b/compiler/rustc_ast_lowering/src/block.rs
@@ -1,5 +1,6 @@
 use rustc_ast::{Block, BlockCheckMode, Local, LocalKind, Stmt, StmtKind};
 use rustc_hir as hir;
+use rustc_span::sym;
 use smallvec::SmallVec;
 
 use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext};
@@ -82,11 +83,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         (self.arena.alloc_from_iter(stmts), expr)
     }
 
+    /// Return an `ImplTraitContext` that allows impl trait in bindings if
+    /// the feature gate is enabled, or issues a feature error if it is not.
+    fn impl_trait_in_bindings_ctxt(&self, position: ImplTraitPosition) -> ImplTraitContext {
+        if self.tcx.features().impl_trait_in_bindings() {
+            ImplTraitContext::InBinding
+        } else {
+            ImplTraitContext::FeatureGated(position, sym::impl_trait_in_bindings)
+        }
+    }
+
     fn lower_local(&mut self, l: &Local) -> &'hir hir::LetStmt<'hir> {
-        let ty = l
-            .ty
-            .as_ref()
-            .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable)));
+        // Let statements are allowed to have impl trait in bindings.
+        let ty = l.ty.as_ref().map(|t| {
+            self.lower_ty(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable))
+        });
         let init = l.kind.init().map(|init| self.lower_expr(init));
         let hir_id = self.lower_node_id(l.id);
         let pat = self.lower_pat(&l.pat);
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 3cbd3e1b637..e4600b0f636 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -260,6 +260,13 @@ enum ImplTraitContext {
     /// equivalent to a new opaque type like `type T = impl Debug; fn foo() -> T`.
     ///
     OpaqueTy { origin: hir::OpaqueTyOrigin<LocalDefId> },
+
+    /// Treat `impl Trait` as a "trait ascription", which is like a type
+    /// variable but that also enforces that a set of trait goals hold.
+    ///
+    /// This is useful to guide inference for unnameable types.
+    InBinding,
+
     /// `impl Trait` is unstably accepted in this position.
     FeatureGated(ImplTraitPosition, Symbol),
     /// `impl Trait` is not accepted in this position.
@@ -1327,6 +1334,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         }
                         path
                     }
+                    ImplTraitContext::InBinding => {
+                        hir::TyKind::TraitAscription(self.lower_param_bounds(bounds, itctx))
+                    }
                     ImplTraitContext::FeatureGated(position, feature) => {
                         let guar = self
                             .tcx
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index 585d0eabf5b..3903c45fda5 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -275,7 +275,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         user_ty: ty::UserType<'tcx>,
         span: Span,
     ) {
-        let ty::UserType::Ty(user_ty) = user_ty else { bug!() };
+        let ty::UserTypeKind::Ty(user_ty) = user_ty.kind else { bug!() };
 
         // A fast path for a common case with closure input/output types.
         if let ty::Infer(_) = user_ty.kind() {
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index bbe2b55d8c4..1f2ec168f03 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -110,7 +110,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         ) {
             self.ascribe_user_type_skip_wf(
                 arg_decl.ty,
-                ty::UserType::Ty(user_ty),
+                ty::UserType::new(ty::UserTypeKind::Ty(user_ty)),
                 arg_decl.source_info.span,
             );
         }
@@ -119,7 +119,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         let output_decl = &body.local_decls[RETURN_PLACE];
         self.ascribe_user_type_skip_wf(
             output_decl.ty,
-            ty::UserType::Ty(user_provided_sig.output()),
+            ty::UserType::new(ty::UserTypeKind::Ty(user_provided_sig.output())),
             output_decl.source_info.span,
         );
     }
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 89e683b8ae3..90d327b0ad2 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -31,7 +31,7 @@ use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{
     self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CoroutineArgsExt,
     Dynamic, GenericArgsRef, OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserArgs,
-    UserType, UserTypeAnnotationIndex,
+    UserTypeAnnotationIndex,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_mir_dataflow::ResultsCursor;
@@ -370,7 +370,10 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
                 } else {
                     self.cx.ascribe_user_type(
                         constant.const_.ty(),
-                        UserType::TypeOf(uv.def, UserArgs { args: uv.args, user_self_ty: None }),
+                        ty::UserType::new(ty::UserTypeKind::TypeOf(uv.def, UserArgs {
+                            args: uv.args,
+                            user_self_ty: None,
+                        })),
                         locations.span(self.cx.body),
                     );
                 }
@@ -991,9 +994,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         for user_annotation in self.user_type_annotations {
             let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
             let annotation = self.instantiate_canonical(span, user_ty);
-            if let ty::UserType::TypeOf(def, args) = annotation
+            if let ty::UserTypeKind::TypeOf(def, args) = annotation.kind
                 && let DefKind::InlineConst = tcx.def_kind(def)
             {
+                assert!(annotation.bounds.is_empty());
                 self.check_inline_const(inferred_ty, def.expect_local(), args, span);
             } else {
                 self.ascribe_user_type(inferred_ty, annotation, span);
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 8b4f441dafe..e25840ba5fc 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -126,9 +126,6 @@ declare_features! (
             better implied higher-ranked implied bounds support"
         )
     ),
-    /// Allows `impl Trait` in bindings (`let`, `const`, `static`).
-    (removed, impl_trait_in_bindings, "1.55.0", Some(63065),
-     Some("the implementation was not maintainable, the feature may get reintroduced once the current refactorings are done")),
     (removed, import_shadowing, "1.0.0", None, None),
     /// Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`).
     (removed, in_band_lifetimes, "1.23.0", Some(44524),
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 8fa75eac9db..45c63b03fe9 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -517,6 +517,8 @@ declare_features! (
     (unstable, if_let_guard, "1.47.0", Some(51114)),
     /// Allows `impl Trait` to be used inside associated types (RFC 2515).
     (unstable, impl_trait_in_assoc_type, "1.70.0", Some(63063)),
+    /// Allows `impl Trait` in bindings (`let`).
+    (unstable, impl_trait_in_bindings, "1.64.0", Some(63065)),
     /// Allows `impl Trait` as output type in `Fn` traits in return position of functions.
     (unstable, impl_trait_in_fn_trait_return, "1.64.0", Some(99697)),
     /// Allows associated types in inherent impls.
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index c7d83760b78..357033a9e18 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2906,6 +2906,8 @@ pub enum TyKind<'hir> {
     Path(QPath<'hir>),
     /// An opaque type definition itself. This is only used for `impl Trait`.
     OpaqueDef(&'hir OpaqueTy<'hir>),
+    /// A trait ascription type, which is `impl Trait` within a local binding.
+    TraitAscription(GenericBounds<'hir>),
     /// A trait object type `Bound1 + Bound2 + Bound3`
     /// where `Bound` is a trait or a lifetime.
     TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax),
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 482940eb5ca..6d481f7536a 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -900,6 +900,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul
         TyKind::OpaqueDef(opaque) => {
             try_visit!(visitor.visit_opaque_ty(opaque));
         }
+        TyKind::TraitAscription(bounds) => {
+            walk_list!(visitor, visit_param_bound, bounds);
+        }
         TyKind::Array(ref ty, ref length) => {
             try_visit!(visitor.visit_ty(ty));
             try_visit!(visitor.visit_const_arg(length));
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index cb5086c9a65..7fb024cce5a 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -29,7 +29,7 @@ use rustc_errors::{
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor, walk_generics};
-use rustc_hir::{self as hir, GenericParamKind, Node};
+use rustc_hir::{self as hir, GenericParamKind, HirId, Node};
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::hir::nested_filter;
@@ -437,6 +437,15 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
         ty::Const::new_error_with_message(self.tcx(), span, "bad placeholder constant")
     }
 
+    fn register_trait_ascription_bounds(
+        &self,
+        _: Vec<(ty::Clause<'tcx>, Span)>,
+        _: HirId,
+        span: Span,
+    ) {
+        self.dcx().span_delayed_bug(span, "trait ascription type not allowed here");
+    }
+
     fn probe_ty_param_bounds(
         &self,
         span: Span,
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 923d2b1fe67..0f797bcdae4 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -852,6 +852,21 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                 };
                 self.with(scope, |this| this.visit_ty(mt.ty));
             }
+            hir::TyKind::TraitAscription(bounds) => {
+                let scope = Scope::TraitRefBoundary { s: self.scope };
+                self.with(scope, |this| {
+                    let scope = Scope::LateBoundary {
+                        s: this.scope,
+                        what: "`impl Trait` in binding",
+                        deny_late_regions: true,
+                    };
+                    this.with(scope, |this| {
+                        for bound in bounds {
+                            this.visit_param_bound(bound);
+                        }
+                    })
+                });
+            }
             _ => intravisit::walk_ty(self, ty),
         }
     }
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 1bdbde30037..a357ade0294 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -123,6 +123,13 @@ pub trait HirTyLowerer<'tcx> {
     /// Returns the const to use when a const is omitted.
     fn ct_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx>;
 
+    fn register_trait_ascription_bounds(
+        &self,
+        bounds: Vec<(ty::Clause<'tcx>, Span)>,
+        hir_id: HirId,
+        span: Span,
+    );
+
     /// Probe bounds in scope where the bounded type coincides with the given type parameter.
     ///
     /// Rephrased, this returns bounds of the form `T: Trait`, where `T` is a type parameter
@@ -2375,6 +2382,25 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
                 self.lower_opaque_ty(opaque_ty.def_id, in_trait)
             }
+            hir::TyKind::TraitAscription(hir_bounds) => {
+                // Impl trait in bindings lower as an infer var with additional
+                // set of type bounds.
+                let self_ty = self.ty_infer(None, hir_ty.span);
+                let mut bounds = Bounds::default();
+                self.lower_bounds(
+                    self_ty,
+                    hir_bounds.iter(),
+                    &mut bounds,
+                    ty::List::empty(),
+                    PredicateFilter::All,
+                );
+                self.register_trait_ascription_bounds(
+                    bounds.clauses().collect(),
+                    hir_ty.hir_id,
+                    hir_ty.span,
+                );
+                self_ty
+            }
             // If we encounter a type relative path with RTN generics, then it must have
             // *not* gone through `lower_ty_maybe_return_type_notation`, and therefore
             // it's certainly in an illegal position.
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index a17b6321ce8..8dd8a5c98ef 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -292,6 +292,9 @@ impl<'a> State<'a> {
                 self.print_unsafe_binder(unsafe_binder);
             }
             hir::TyKind::OpaqueDef(..) => self.word("/*impl Trait*/"),
+            hir::TyKind::TraitAscription(bounds) => {
+                self.print_bounds("impl", bounds);
+            }
             hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false),
             hir::TyKind::TraitObject(bounds, lifetime, syntax) => {
                 if syntax == ast::TraitObjectSyntax::Dyn {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 863be3bdcb2..0dacfc9b7bf 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -4,11 +4,11 @@ use std::slice;
 use rustc_abi::FieldIdx;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey};
-use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{ExprKind, GenericArg, HirId, Node, QPath};
+use rustc_hir::{self as hir, ExprKind, GenericArg, HirId, Node, QPath, intravisit};
 use rustc_hir_analysis::hir_ty_lowering::errors::GenericsArgsErrExtend;
 use rustc_hir_analysis::hir_ty_lowering::generics::{
     check_generic_arg_count_for_call, lower_generic_args,
@@ -25,7 +25,7 @@ use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
 use rustc_middle::ty::{
     self, AdtKind, CanonicalUserType, GenericArgKind, GenericArgsRef, GenericParamDefKind,
-    IsIdentity, Ty, TyCtxt, UserArgs, UserSelfTy, UserType,
+    IsIdentity, Ty, TyCtxt, UserArgs, UserSelfTy,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
@@ -216,11 +216,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         debug!("fcx {}", self.tag());
 
         if Self::can_contain_user_lifetime_bounds((args, user_self_ty)) {
-            let canonicalized =
-                self.canonicalize_user_type_annotation(UserType::TypeOf(def_id, UserArgs {
-                    args,
-                    user_self_ty,
-                }));
+            let canonicalized = self.canonicalize_user_type_annotation(ty::UserType::new(
+                ty::UserTypeKind::TypeOf(def_id, UserArgs { args, user_self_ty }),
+            ));
             debug!(?canonicalized);
             self.write_user_type_annotation(hir_id, canonicalized);
         }
@@ -462,13 +460,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         LoweredTy::from_raw(self, hir_ty.span, ty)
     }
 
+    /// Walk a `hir_ty` and collect any clauses that may have come from a type
+    /// within the `hir_ty`. These clauses will be canonicalized with a user type
+    /// annotation so that we can enforce these bounds in borrowck, too.
+    pub(crate) fn collect_impl_trait_clauses_from_hir_ty(
+        &self,
+        hir_ty: &'tcx hir::Ty<'tcx>,
+    ) -> ty::Clauses<'tcx> {
+        struct CollectClauses<'a, 'tcx> {
+            clauses: Vec<ty::Clause<'tcx>>,
+            fcx: &'a FnCtxt<'a, 'tcx>,
+        }
+
+        impl<'tcx> intravisit::Visitor<'tcx> for CollectClauses<'_, 'tcx> {
+            fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
+                if let Some(clauses) = self.fcx.trait_ascriptions.borrow().get(&ty.hir_id.local_id)
+                {
+                    self.clauses.extend(clauses.iter().cloned());
+                }
+                intravisit::walk_ty(self, ty)
+            }
+        }
+
+        let mut clauses = CollectClauses { clauses: vec![], fcx: self };
+        clauses.visit_ty(hir_ty);
+        self.tcx.mk_clauses(&clauses.clauses)
+    }
+
     #[instrument(level = "debug", skip_all)]
-    pub(crate) fn lower_ty_saving_user_provided_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
+    pub(crate) fn lower_ty_saving_user_provided_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> Ty<'tcx> {
         let ty = self.lower_ty(hir_ty);
         debug!(?ty);
 
         if Self::can_contain_user_lifetime_bounds(ty.raw) {
-            let c_ty = self.canonicalize_response(UserType::Ty(ty.raw));
+            let c_ty = self.canonicalize_response(ty::UserType::new(ty::UserTypeKind::Ty(ty.raw)));
             debug!(?c_ty);
             self.typeck_results.borrow_mut().user_provided_types_mut().insert(hir_ty.hir_id, c_ty);
         }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index aacdcf027b6..b9011e89f04 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -10,10 +10,11 @@ use std::ops::Deref;
 
 use hir::def_id::CRATE_DEF_ID;
 use rustc_errors::DiagCtxtHandle;
-use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::{self as hir, HirId, ItemLocalMap};
 use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, RegionInferReason};
 use rustc_infer::infer;
+use rustc_infer::traits::Obligation;
 use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
 use rustc_session::Session;
 use rustc_span::symbol::Ident;
@@ -114,6 +115,12 @@ pub(crate) struct FnCtxt<'a, 'tcx> {
 
     pub(super) diverging_fallback_behavior: DivergingFallbackBehavior,
     pub(super) diverging_block_behavior: DivergingBlockBehavior,
+
+    /// Clauses that we lowered as part of the `impl_trait_in_bindings` feature.
+    ///
+    /// These are stored here so we may collect them when canonicalizing user
+    /// type ascriptions later.
+    pub(super) trait_ascriptions: RefCell<ItemLocalMap<Vec<ty::Clause<'tcx>>>>,
 }
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -141,6 +148,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             fallback_has_occurred: Cell::new(false),
             diverging_fallback_behavior,
             diverging_block_behavior,
+            trait_ascriptions: Default::default(),
         }
     }
 
@@ -252,6 +260,30 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
         }
     }
 
+    fn register_trait_ascription_bounds(
+        &self,
+        bounds: Vec<(ty::Clause<'tcx>, Span)>,
+        hir_id: HirId,
+        _span: Span,
+    ) {
+        for (clause, span) in bounds {
+            if clause.has_escaping_bound_vars() {
+                self.dcx().span_delayed_bug(span, "clause should have no escaping bound vars");
+                continue;
+            }
+
+            self.trait_ascriptions.borrow_mut().entry(hir_id.local_id).or_default().push(clause);
+
+            let clause = self.normalize(span, clause);
+            self.register_predicate(Obligation::new(
+                self.tcx,
+                self.misc(span),
+                self.param_env,
+                clause,
+            ));
+        }
+    }
+
     fn probe_ty_param_bounds(
         &self,
         _: Span,
diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs
index f427b0b805e..48fd5f1f982 100644
--- a/compiler/rustc_hir_typeck/src/gather_locals.rs
+++ b/compiler/rustc_hir_typeck/src/gather_locals.rs
@@ -2,7 +2,7 @@ use rustc_hir as hir;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{HirId, PatKind};
 use rustc_infer::traits::ObligationCauseCode;
-use rustc_middle::ty::{Ty, UserType};
+use rustc_middle::ty::{self, Ty};
 use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
 use tracing::debug;
@@ -92,7 +92,12 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
             Some(ref ty) => {
                 let o_ty = self.fcx.lower_ty(ty);
 
-                let c_ty = self.fcx.infcx.canonicalize_user_type_annotation(UserType::Ty(o_ty.raw));
+                let c_ty = self.fcx.infcx.canonicalize_user_type_annotation(
+                    ty::UserType::new_with_bounds(
+                        ty::UserTypeKind::Ty(o_ty.raw),
+                        self.fcx.collect_impl_trait_clauses_from_hir_ty(ty),
+                    ),
+                );
                 debug!("visit_local: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, c_ty);
                 self.fcx
                     .typeck_results
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index b31ee1a55d6..ef431c852e9 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -17,7 +17,6 @@ use rustc_middle::ty::adjustment::{
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{
     self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, UserArgs,
-    UserType,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_span::{DUMMY_SP, Span};
@@ -491,9 +490,8 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
                     user_self_ty: None, // not relevant here
                 };
 
-                self.fcx.canonicalize_user_type_annotation(UserType::TypeOf(
-                    pick.item.def_id,
-                    user_args,
+                self.fcx.canonicalize_user_type_annotation(ty::UserType::new(
+                    ty::UserTypeKind::TypeOf(pick.item.def_id, user_args),
                 ))
             });
 
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index e17a68c8692..6f1e3a0cf8c 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -476,7 +476,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
             for (local_id, c_ty) in sorted_user_provided_types {
                 let hir_id = HirId { owner: common_hir_owner, local_id };
 
-                if let ty::UserType::TypeOf(_, user_args) = c_ty.value {
+                if let ty::UserTypeKind::TypeOf(_, user_args) = c_ty.value.kind {
                     // This is a unit-testing mechanism.
                     let span = self.tcx().hir().span(hir_id);
                     // We need to buffer the errors in order to guarantee a consistent
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index f4135d8dbc6..3337f7ceee7 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -323,7 +323,7 @@ macro_rules! define_callbacks {
                 // Increase this limit if necessary, but do try to keep the size low if possible
                 #[cfg(target_pointer_width = "64")]
                 const _: () = {
-                    if mem::size_of::<Key<'static>>() > 80 {
+                    if mem::size_of::<Key<'static>>() > 88 {
                         panic!("{}", concat!(
                             "the query `",
                             stringify!($name),
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 8051aa01715..e47b0cf0b3b 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -95,7 +95,7 @@ pub use self::sty::{
 pub use self::trait_def::TraitDef;
 pub use self::typeck_results::{
     CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, IsIdentity,
-    TypeckResults, UserType, UserTypeAnnotationIndex,
+    TypeckResults, UserType, UserTypeAnnotationIndex, UserTypeKind,
 };
 pub use self::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
 use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason};
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index 8cba5f33278..551c113aa59 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -700,12 +700,31 @@ pub struct CanonicalUserTypeAnnotation<'tcx> {
 /// Canonical user type annotation.
 pub type CanonicalUserType<'tcx> = Canonical<'tcx, UserType<'tcx>>;
 
+#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
+#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)]
+pub struct UserType<'tcx> {
+    pub kind: UserTypeKind<'tcx>,
+    pub bounds: ty::Clauses<'tcx>,
+}
+
+impl<'tcx> UserType<'tcx> {
+    pub fn new(kind: UserTypeKind<'tcx>) -> UserType<'tcx> {
+        UserType { kind, bounds: ty::ListWithCachedTypeInfo::empty() }
+    }
+
+    /// A user type annotation with additional bounds that need to be enforced.
+    /// These bounds are lowered from `impl Trait` in bindings.
+    pub fn new_with_bounds(kind: UserTypeKind<'tcx>, bounds: ty::Clauses<'tcx>) -> UserType<'tcx> {
+        UserType { kind, bounds }
+    }
+}
+
 /// A user-given type annotation attached to a constant. These arise
 /// from constants that are named via paths, like `Foo::<A>::new` and
 /// so forth.
 #[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
 #[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)]
-pub enum UserType<'tcx> {
+pub enum UserTypeKind<'tcx> {
     Ty(Ty<'tcx>),
 
     /// The canonical type is the result of `type_of(def_id)` with the
@@ -721,9 +740,13 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> {
     /// Returns `true` if this represents the generic parameters of the form `[?0, ?1, ?2]`,
     /// i.e., each thing is mapped to a canonical variable with the same index.
     fn is_identity(&self) -> bool {
-        match self.value {
-            UserType::Ty(_) => false,
-            UserType::TypeOf(_, user_args) => {
+        if !self.value.bounds.is_empty() {
+            return false;
+        }
+
+        match self.value.kind {
+            UserTypeKind::Ty(_) => false,
+            UserTypeKind::TypeOf(_, user_args) => {
                 if user_args.user_self_ty.is_some() {
                     return false;
                 }
@@ -765,6 +788,18 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> {
 
 impl<'tcx> std::fmt::Display for UserType<'tcx> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        if self.bounds.is_empty() {
+            self.kind.fmt(f)
+        } else {
+            self.kind.fmt(f)?;
+            write!(f, " + ")?;
+            std::fmt::Debug::fmt(&self.bounds, f)
+        }
+    }
+}
+
+impl<'tcx> std::fmt::Display for UserTypeKind<'tcx> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match self {
             Self::Ty(arg0) => {
                 ty::print::with_no_trimmed_paths!(write!(f, "Ty({})", arg0))
diff --git a/compiler/rustc_mir_build/src/build/matches/match_pair.rs b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
index 2815b390375..33fbd7b1a3f 100644
--- a/compiler/rustc_mir_build/src/build/matches/match_pair.rs
+++ b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
@@ -176,9 +176,8 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
                         ty: cx.infcx.next_ty_var(span),
                     })
                     .args;
-                    let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
-                        def_id,
-                        ty::UserArgs { args, user_self_ty: None },
+                    let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::new(
+                        ty::UserTypeKind::TypeOf(def_id, ty::UserArgs { args, user_self_ty: None }),
                     ));
                     let annotation = ty::CanonicalUserTypeAnnotation {
                         inferred_ty: pattern.ty,
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 3cbf1e2055c..6770e562d50 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -15,7 +15,6 @@ use rustc_middle::ty::adjustment::{
 };
 use rustc_middle::ty::{
     self, AdtKind, GenericArgs, InlineConstArgs, InlineConstArgsParts, ScalarInt, Ty, UpvarArgs,
-    UserType,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_span::{Span, sym};
@@ -443,7 +442,9 @@ impl<'tcx> Cx<'tcx> {
                         let user_provided_types = self.typeck_results().user_provided_types();
                         let user_ty =
                             user_provided_types.get(fun.hir_id).copied().map(|mut u_ty| {
-                                if let UserType::TypeOf(ref mut did, _) = &mut u_ty.value {
+                                if let ty::UserTypeKind::TypeOf(ref mut did, _) =
+                                    &mut u_ty.value.kind
+                                {
                                     *did = adt_def.did();
                                 }
                                 Box::new(u_ty)
diff --git a/compiler/rustc_mir_build/src/thir/util.rs b/compiler/rustc_mir_build/src/thir/util.rs
index 53a2a0852eb..ed7c7e40993 100644
--- a/compiler/rustc_mir_build/src/thir/util.rs
+++ b/compiler/rustc_mir_build/src/thir/util.rs
@@ -1,6 +1,6 @@
 use rustc_hir as hir;
 use rustc_middle::bug;
-use rustc_middle::ty::{self, CanonicalUserType, TyCtxt, UserType};
+use rustc_middle::ty::{self, CanonicalUserType, TyCtxt};
 use tracing::debug;
 
 pub(crate) trait UserAnnotatedTyHelpers<'tcx> {
@@ -21,7 +21,7 @@ pub(crate) trait UserAnnotatedTyHelpers<'tcx> {
         let ty = self.typeck_results().node_type(hir_id);
         match ty.kind() {
             ty::Adt(adt_def, ..) => {
-                if let UserType::TypeOf(ref mut did, _) = &mut user_ty.value {
+                if let ty::UserTypeKind::TypeOf(ref mut did, _) = &mut user_ty.value.kind {
                     *did = adt_def.did();
                 }
                 Some(user_ty)
diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs
index 164cbc69595..7ccbc7bdc57 100644
--- a/compiler/rustc_passes/src/input_stats.rs
+++ b/compiler/rustc_passes/src/input_stats.rs
@@ -371,6 +371,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
             Tup,
             Path,
             OpaqueDef,
+            TraitAscription,
             TraitObject,
             Typeof,
             Infer,
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
index dc3f5544613..254dee794f1 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
@@ -3,7 +3,7 @@ use rustc_infer::traits::Obligation;
 use rustc_middle::traits::query::NoSolution;
 pub use rustc_middle::traits::query::type_op::AscribeUserType;
 use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
-use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, UserArgs, UserSelfTy, UserType};
+use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, UserArgs, UserSelfTy, UserTypeKind};
 use rustc_span::{DUMMY_SP, Span};
 use tracing::{debug, instrument};
 
@@ -46,12 +46,18 @@ pub fn type_op_ascribe_user_type_with_span<'tcx>(
     let (param_env, AscribeUserType { mir_ty, user_ty }) = key.into_parts();
     debug!("type_op_ascribe_user_type: mir_ty={:?} user_ty={:?}", mir_ty, user_ty);
     let span = span.unwrap_or(DUMMY_SP);
-    match user_ty {
-        UserType::Ty(user_ty) => relate_mir_and_user_ty(ocx, param_env, span, mir_ty, user_ty)?,
-        UserType::TypeOf(def_id, user_args) => {
+    match user_ty.kind {
+        UserTypeKind::Ty(user_ty) => relate_mir_and_user_ty(ocx, param_env, span, mir_ty, user_ty)?,
+        UserTypeKind::TypeOf(def_id, user_args) => {
             relate_mir_and_user_args(ocx, param_env, span, mir_ty, def_id, user_args)?
         }
     };
+
+    // Enforce any bounds that come from impl trait in bindings.
+    ocx.register_obligations(user_ty.bounds.iter().map(|clause| {
+        Obligation::new(ocx.infcx.tcx, ObligationCause::dummy_with_span(span), param_env, clause)
+    }));
+
     Ok(())
 }
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index a201a9bbfed..25f88c8797f 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1839,11 +1839,15 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
             DynTrait(bounds, lifetime)
         }
         TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),
-        // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
-        TyKind::Infer | TyKind::Err(_) | TyKind::Typeof(..) | TyKind::InferDelegation(..) => Infer,
         TyKind::UnsafeBinder(..) => {
             unimplemented!("unsafe binders are not supported yet")
         }
+        // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
+        TyKind::Infer
+        | TyKind::Err(_)
+        | TyKind::Typeof(..)
+        | TyKind::InferDelegation(..)
+        | TyKind::TraitAscription(_) => Infer,
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index bd4ce7ab922..e3959903fdd 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -814,6 +814,7 @@ impl TyCoercionStability {
                 | TyKind::Tup(_)
                 | TyKind::Path(_) => Self::Deref,
                 TyKind::OpaqueDef(..)
+                | TyKind::TraitAscription(..)
                 | TyKind::Infer
                 | TyKind::Typeof(..)
                 | TyKind::TraitObject(..)
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 279025b9bf9..4b604f658b8 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -1260,7 +1260,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             | TyKind::Infer
             | TyKind::Never
             | TyKind::InferDelegation(..)
-            | TyKind::OpaqueDef(_) => {},
+            | TyKind::OpaqueDef(_)
+            | TyKind::TraitAscription(_) => {},
         }
     }
 
diff --git a/tests/ui/feature-gates/feature-gate-impl-trait-in-bindings.rs b/tests/ui/feature-gates/feature-gate-impl-trait-in-bindings.rs
new file mode 100644
index 00000000000..f6574b48120
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-impl-trait-in-bindings.rs
@@ -0,0 +1,4 @@
+fn main() {
+    let x: impl Sized = ();
+    //~^ ERROR `impl Trait` is not allowed in the type of variable bindings
+}
diff --git a/tests/ui/feature-gates/feature-gate-impl-trait-in-bindings.stderr b/tests/ui/feature-gates/feature-gate-impl-trait-in-bindings.stderr
new file mode 100644
index 00000000000..58f058fb564
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-impl-trait-in-bindings.stderr
@@ -0,0 +1,14 @@
+error[E0562]: `impl Trait` is not allowed in the type of variable bindings
+  --> $DIR/feature-gate-impl-trait-in-bindings.rs:2:12
+   |
+LL |     let x: impl Sized = ();
+   |            ^^^^^^^^^^
+   |
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
+   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
+   = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0562`.
diff --git a/tests/ui/impl-trait/in-bindings/bad-nesting.rs b/tests/ui/impl-trait/in-bindings/bad-nesting.rs
new file mode 100644
index 00000000000..7f4b44cc691
--- /dev/null
+++ b/tests/ui/impl-trait/in-bindings/bad-nesting.rs
@@ -0,0 +1,10 @@
+#![feature(impl_trait_in_bindings)]
+
+trait Foo<T> {}
+
+impl Foo<()> for () {}
+
+fn main() {
+    let x: impl Foo<impl Sized> = ();
+    //~^ ERROR nested `impl Trait` is not allowed
+}
diff --git a/tests/ui/impl-trait/in-bindings/bad-nesting.stderr b/tests/ui/impl-trait/in-bindings/bad-nesting.stderr
new file mode 100644
index 00000000000..d82ce733254
--- /dev/null
+++ b/tests/ui/impl-trait/in-bindings/bad-nesting.stderr
@@ -0,0 +1,12 @@
+error[E0666]: nested `impl Trait` is not allowed
+  --> $DIR/bad-nesting.rs:8:21
+   |
+LL |     let x: impl Foo<impl Sized> = ();
+   |            ---------^^^^^^^^^^-
+   |            |        |
+   |            |        nested `impl Trait` here
+   |            outer `impl Trait`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0666`.
diff --git a/tests/ui/impl-trait/in-bindings/escaping-bound-var.rs b/tests/ui/impl-trait/in-bindings/escaping-bound-var.rs
new file mode 100644
index 00000000000..b57fef9be21
--- /dev/null
+++ b/tests/ui/impl-trait/in-bindings/escaping-bound-var.rs
@@ -0,0 +1,14 @@
+#![feature(impl_trait_in_bindings)]
+
+trait Foo<'a> {
+    type Out;
+}
+
+impl<'a> Foo<'a> for () {
+    type Out = ();
+}
+
+fn main() {
+    let x: &dyn for<'a> Foo<'a, Out = impl Sized + 'a> = &();
+    //~^ ERROR cannot capture late-bound lifetime in `impl Trait` in binding
+}
diff --git a/tests/ui/impl-trait/in-bindings/escaping-bound-var.stderr b/tests/ui/impl-trait/in-bindings/escaping-bound-var.stderr
new file mode 100644
index 00000000000..640f6f36927
--- /dev/null
+++ b/tests/ui/impl-trait/in-bindings/escaping-bound-var.stderr
@@ -0,0 +1,8 @@
+error: cannot capture late-bound lifetime in `impl Trait` in binding
+  --> $DIR/escaping-bound-var.rs:12:52
+   |
+LL |     let x: &dyn for<'a> Foo<'a, Out = impl Sized + 'a> = &();
+   |                     -- lifetime defined here       ^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/impl-trait/in-bindings/lifetime-failure.rs b/tests/ui/impl-trait/in-bindings/lifetime-failure.rs
new file mode 100644
index 00000000000..df685c36c43
--- /dev/null
+++ b/tests/ui/impl-trait/in-bindings/lifetime-failure.rs
@@ -0,0 +1,12 @@
+#![feature(impl_trait_in_bindings)]
+
+trait Static: 'static {}
+impl<T: 'static> Static for T {}
+
+struct W<T>(T);
+
+fn main() {
+    let local = 0;
+    let _: W<impl Static> = W(&local);
+    //~^ ERROR `local` does not live long enough
+}
diff --git a/tests/ui/impl-trait/in-bindings/lifetime-failure.stderr b/tests/ui/impl-trait/in-bindings/lifetime-failure.stderr
new file mode 100644
index 00000000000..189efcbca87
--- /dev/null
+++ b/tests/ui/impl-trait/in-bindings/lifetime-failure.stderr
@@ -0,0 +1,16 @@
+error[E0597]: `local` does not live long enough
+  --> $DIR/lifetime-failure.rs:10:31
+   |
+LL |     let local = 0;
+   |         ----- binding `local` declared here
+LL |     let _: W<impl Static> = W(&local);
+   |            --------------     ^^^^^^ borrowed value does not live long enough
+   |            |
+   |            type annotation requires that `local` is borrowed for `'static`
+LL |
+LL | }
+   | - `local` dropped here while still borrowed
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/impl-trait/in-bindings/nesting-lifetime-failure.rs b/tests/ui/impl-trait/in-bindings/nesting-lifetime-failure.rs
new file mode 100644
index 00000000000..7e5d2cf18bd
--- /dev/null
+++ b/tests/ui/impl-trait/in-bindings/nesting-lifetime-failure.rs
@@ -0,0 +1,10 @@
+#![feature(impl_trait_in_bindings)]
+
+trait Static {}
+impl<T: 'static> Static for T {}
+
+fn main() {
+    let local = 0;
+    let _: impl IntoIterator<Item = impl Static> = [&local];
+    //~^ ERROR `local` does not live long enough
+}
diff --git a/tests/ui/impl-trait/in-bindings/nesting-lifetime-failure.stderr b/tests/ui/impl-trait/in-bindings/nesting-lifetime-failure.stderr
new file mode 100644
index 00000000000..c0326b37949
--- /dev/null
+++ b/tests/ui/impl-trait/in-bindings/nesting-lifetime-failure.stderr
@@ -0,0 +1,16 @@
+error[E0597]: `local` does not live long enough
+  --> $DIR/nesting-lifetime-failure.rs:8:53
+   |
+LL |     let local = 0;
+   |         ----- binding `local` declared here
+LL |     let _: impl IntoIterator<Item = impl Static> = [&local];
+   |            -------------------------------------    ^^^^^^ borrowed value does not live long enough
+   |            |
+   |            type annotation requires that `local` is borrowed for `'static`
+LL |
+LL | }
+   | - `local` dropped here while still borrowed
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/impl-trait/in-bindings/nesting.rs b/tests/ui/impl-trait/in-bindings/nesting.rs
new file mode 100644
index 00000000000..51ff42bcafe
--- /dev/null
+++ b/tests/ui/impl-trait/in-bindings/nesting.rs
@@ -0,0 +1,7 @@
+//@ check-pass
+
+#![feature(impl_trait_in_bindings)]
+
+fn main() {
+    let _: impl IntoIterator<Item = impl Sized> = ["hello", " world"];
+}
diff --git a/tests/ui/impl-trait/in-bindings/simple.rs b/tests/ui/impl-trait/in-bindings/simple.rs
new file mode 100644
index 00000000000..8052f5a1880
--- /dev/null
+++ b/tests/ui/impl-trait/in-bindings/simple.rs
@@ -0,0 +1,10 @@
+//@ check-pass
+
+#![feature(impl_trait_in_bindings)]
+
+trait Foo {}
+impl Foo for () {}
+
+fn main() {
+    let x: impl Foo = ();
+}
diff --git a/tests/ui/impl-trait/in-bindings/trait-failure.rs b/tests/ui/impl-trait/in-bindings/trait-failure.rs
new file mode 100644
index 00000000000..e4052437f2f
--- /dev/null
+++ b/tests/ui/impl-trait/in-bindings/trait-failure.rs
@@ -0,0 +1,13 @@
+#![feature(impl_trait_in_bindings)]
+
+trait Foo {}
+
+struct W<T>(T);
+impl<T> Foo for W<T> where T: Foo {}
+
+fn main() {
+    let x: impl Foo = W(());
+    //~^ ERROR the trait bound `(): Foo` is not satisfied
+    let x: W<impl Foo> = W(());
+    //~^ ERROR the trait bound `(): Foo` is not satisfied
+}
diff --git a/tests/ui/impl-trait/in-bindings/trait-failure.stderr b/tests/ui/impl-trait/in-bindings/trait-failure.stderr
new file mode 100644
index 00000000000..332cefd796d
--- /dev/null
+++ b/tests/ui/impl-trait/in-bindings/trait-failure.stderr
@@ -0,0 +1,24 @@
+error[E0277]: the trait bound `(): Foo` is not satisfied
+  --> $DIR/trait-failure.rs:9:17
+   |
+LL |     let x: impl Foo = W(());
+   |                 ^^^ the trait `Foo` is not implemented for `()`
+   |
+   = help: the trait `Foo` is implemented for `W<T>`
+note: required for `W<()>` to implement `Foo`
+  --> $DIR/trait-failure.rs:6:9
+   |
+LL | impl<T> Foo for W<T> where T: Foo {}
+   |         ^^^     ^^^^          --- unsatisfied trait bound introduced here
+
+error[E0277]: the trait bound `(): Foo` is not satisfied
+  --> $DIR/trait-failure.rs:11:19
+   |
+LL |     let x: W<impl Foo> = W(());
+   |                   ^^^ the trait `Foo` is not implemented for `()`
+   |
+   = help: the trait `Foo` is implemented for `W<T>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/impl-trait/issues/issue-54600.stderr b/tests/ui/impl-trait/issues/issue-54600.stderr
index c75c0fa0f05..02d60960233 100644
--- a/tests/ui/impl-trait/issues/issue-54600.stderr
+++ b/tests/ui/impl-trait/issues/issue-54600.stderr
@@ -5,6 +5,9 @@ LL |     let x: Option<impl Debug> = Some(44_u32);
    |                   ^^^^^^^^^^
    |
    = note: `impl Trait` is only allowed in arguments and return types of functions and methods
+   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
+   = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/impl-trait/issues/issue-54840.stderr b/tests/ui/impl-trait/issues/issue-54840.stderr
index de75256d5a9..805ea04f0bc 100644
--- a/tests/ui/impl-trait/issues/issue-54840.stderr
+++ b/tests/ui/impl-trait/issues/issue-54840.stderr
@@ -5,6 +5,9 @@ LL |     let j: &impl Add = &i;
    |             ^^^^^^^^
    |
    = note: `impl Trait` is only allowed in arguments and return types of functions and methods
+   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
+   = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/impl-trait/issues/issue-58504.stderr b/tests/ui/impl-trait/issues/issue-58504.stderr
index 8231732bba1..bc921d5cd2c 100644
--- a/tests/ui/impl-trait/issues/issue-58504.stderr
+++ b/tests/ui/impl-trait/issues/issue-58504.stderr
@@ -5,6 +5,9 @@ LL |     let gens: [impl Coroutine<Return=!, Yield=()>;2] = [ mk_gen(), mk_gen()
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `impl Trait` is only allowed in arguments and return types of functions and methods
+   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
+   = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/impl-trait/issues/issue-58956.stderr b/tests/ui/impl-trait/issues/issue-58956.stderr
index 0c81c69def3..825777e4923 100644
--- a/tests/ui/impl-trait/issues/issue-58956.stderr
+++ b/tests/ui/impl-trait/issues/issue-58956.stderr
@@ -13,6 +13,9 @@ LL |     let x: Wrap<impl Lam> = Wrap(B);
    |                 ^^^^^^^^
    |
    = note: `impl Trait` is only allowed in arguments and return types of functions and methods
+   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
+   = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/impl-trait/issues/issue-70971.stderr b/tests/ui/impl-trait/issues/issue-70971.stderr
index 28c463cea85..10e5fffa430 100644
--- a/tests/ui/impl-trait/issues/issue-70971.stderr
+++ b/tests/ui/impl-trait/issues/issue-70971.stderr
@@ -5,6 +5,9 @@ LL |     let x : (impl Copy,) = (true,);
    |              ^^^^^^^^^
    |
    = note: `impl Trait` is only allowed in arguments and return types of functions and methods
+   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
+   = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/impl-trait/issues/issue-79099.stderr b/tests/ui/impl-trait/issues/issue-79099.stderr
index 96825eabec7..d7c0c494454 100644
--- a/tests/ui/impl-trait/issues/issue-79099.stderr
+++ b/tests/ui/impl-trait/issues/issue-79099.stderr
@@ -16,6 +16,9 @@ LL |         let f: impl core::future::Future<Output = u8> = async { 1 };
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `impl Trait` is only allowed in arguments and return types of functions and methods
+   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
+   = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/impl-trait/issues/issue-84919.stderr b/tests/ui/impl-trait/issues/issue-84919.stderr
index 02d2ce28fb3..21dd355065d 100644
--- a/tests/ui/impl-trait/issues/issue-84919.stderr
+++ b/tests/ui/impl-trait/issues/issue-84919.stderr
@@ -5,6 +5,9 @@ LL |     let _x: impl Trait = ();
    |             ^^^^^^^^^^
    |
    = note: `impl Trait` is only allowed in arguments and return types of functions and methods
+   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
+   = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/impl-trait/issues/issue-87295.stderr b/tests/ui/impl-trait/issues/issue-87295.stderr
index 78274a056ec..31f3b2f5bf2 100644
--- a/tests/ui/impl-trait/issues/issue-87295.stderr
+++ b/tests/ui/impl-trait/issues/issue-87295.stderr
@@ -5,6 +5,9 @@ LL |     let _do_not_waste: Struct<impl Trait<Output = i32>> = Struct::new(());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `impl Trait` is only allowed in arguments and return types of functions and methods
+   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
+   = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr
index 13f50fcea7b..400df87ca3f 100644
--- a/tests/ui/impl-trait/where-allowed.stderr
+++ b/tests/ui/impl-trait/where-allowed.stderr
@@ -333,6 +333,9 @@ LL |     let _in_local_variable: impl Fn() = || {};
    |                             ^^^^^^^^^
    |
    = note: `impl Trait` is only allowed in arguments and return types of functions and methods
+   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
+   = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0562]: `impl Trait` is not allowed in closure return types
   --> $DIR/where-allowed.rs:253:46
diff --git a/tests/ui/typeck/issue-104513-ice.stderr b/tests/ui/typeck/issue-104513-ice.stderr
index 37d38a76a40..c3872ea8968 100644
--- a/tests/ui/typeck/issue-104513-ice.stderr
+++ b/tests/ui/typeck/issue-104513-ice.stderr
@@ -11,6 +11,9 @@ LL |     let _: S<impl Oops> = S;
    |              ^^^^^^^^^
    |
    = note: `impl Trait` is only allowed in arguments and return types of functions and methods
+   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
+   = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: aborting due to 2 previous errors