about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs106
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/variance/constraints.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs4
-rw-r--r--compiler/rustc_infer/src/infer/glb.rs3
-rw-r--r--compiler/rustc_infer/src/infer/lub.rs3
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs8
-rw-r--r--compiler/rustc_infer/src/infer/sub.rs3
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs14
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs22
-rw-r--r--compiler/rustc_parse/src/parser/path.rs48
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly.rs25
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs44
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs4
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs30
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs43
-rw-r--r--library/core/src/option.rs16
-rw-r--r--tests/codegen/debug-vtable.rs8
-rw-r--r--tests/codegen/option-nonzero-eq.rs10
-rw-r--r--tests/ui/const-generics/bad-const-generic-exprs.rs34
-rw-r--r--tests/ui/const-generics/bad-const-generic-exprs.stderr106
-rw-r--r--tests/ui/error-codes/E0208.rs2
-rw-r--r--tests/ui/error-codes/E0208.stderr2
-rw-r--r--tests/ui/suggestions/late-bound-in-borrow-closure-sugg.rs28
-rw-r--r--tests/ui/suggestions/late-bound-in-borrow-closure-sugg.stderr26
-rw-r--r--tests/ui/typeck/issue-107087.rs18
-rw-r--r--tests/ui/typeck/issue-107087.stderr9
-rw-r--r--tests/ui/variance/variance-associated-types.rs2
-rw-r--r--tests/ui/variance/variance-associated-types.stderr2
-rw-r--r--tests/ui/variance/variance-regions-direct.rs12
-rw-r--r--tests/ui/variance/variance-regions-direct.stderr12
-rw-r--r--tests/ui/variance/variance-regions-indirect.rs8
-rw-r--r--tests/ui/variance/variance-regions-indirect.stderr8
-rw-r--r--tests/ui/variance/variance-trait-object-bound.rs2
-rw-r--r--tests/ui/variance/variance-trait-object-bound.stderr2
-rw-r--r--tests/ui/variance/variance-types.rs2
-rw-r--r--tests/ui/variance/variance-types.stderr2
39 files changed, 531 insertions, 160 deletions
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index b6eb5ee183f..f73bbf3d22b 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -1499,6 +1499,11 @@ pub fn create_vtable_di_node<'ll, 'tcx>(
         return;
     }
 
+    // When full debuginfo is enabled, we want to try and prevent vtables from being
+    // merged. Otherwise debuggers will have a hard time mapping from dyn pointer
+    // to concrete type.
+    llvm::SetUnnamedAddress(vtable, llvm::UnnamedAddr::No);
+
     let vtable_name =
         compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::GlobalVariable);
     let vtable_type_di_node = build_vtable_type_di_node(cx, ty, poly_trait_ref);
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 27284f8b983..caf26a75d3c 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -27,7 +27,7 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{walk_generics, Visitor as _};
 use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
-use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_middle::middle::stability::AllowUnstable;
 use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
 use rustc_middle::ty::GenericParamDefKind;
@@ -37,7 +37,7 @@ use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECT
 use rustc_span::edition::Edition;
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::symbol::{kw, Ident, Symbol};
-use rustc_span::{sym, Span};
+use rustc_span::{sym, Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::astconv_object_safety_violations;
@@ -54,7 +54,7 @@ use std::slice;
 pub struct PathSeg(pub DefId, pub usize);
 
 pub trait AstConv<'tcx> {
-    fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
+    fn tcx(&self) -> TyCtxt<'tcx>;
 
     fn item_def_id(&self) -> DefId;
 
@@ -131,6 +131,8 @@ pub trait AstConv<'tcx> {
     {
         self
     }
+
+    fn infcx(&self) -> Option<&InferCtxt<'tcx>>;
 }
 
 #[derive(Debug)]
@@ -2132,48 +2134,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     )
                     .emit() // Already reported in an earlier stage.
                 } else {
-                    // Find all the `impl`s that `qself_ty` has for any trait that has the
-                    // associated type, so that we suggest the right one.
-                    let infcx = tcx.infer_ctxt().build();
-                    // We create a fresh `ty::ParamEnv` instead of the one for `self.item_def_id()`
-                    // to avoid a cycle error in `src/test/ui/resolve/issue-102946.rs`.
-                    let param_env = ty::ParamEnv::empty();
-                    let traits: Vec<_> = self
-                        .tcx()
-                        .all_traits()
-                        .filter(|trait_def_id| {
-                            // Consider only traits with the associated type
-                            tcx.associated_items(*trait_def_id)
-                                .in_definition_order()
-                                .any(|i| {
-                                    i.kind.namespace() == Namespace::TypeNS
-                                        && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
-                                        && matches!(i.kind, ty::AssocKind::Type)
-                                })
-                            // Consider only accessible traits
-                            && tcx.visibility(*trait_def_id)
-                                .is_accessible_from(self.item_def_id(), tcx)
-                            && tcx.all_impls(*trait_def_id)
-                                .any(|impl_def_id| {
-                                    let trait_ref = tcx.impl_trait_ref(impl_def_id);
-                                    trait_ref.map_or(false, |trait_ref| {
-                                        let impl_ = trait_ref.subst(
-                                            tcx,
-                                            infcx.fresh_substs_for_item(span, impl_def_id),
-                                        );
-                                        infcx
-                                            .can_eq(
-                                                param_env,
-                                                tcx.erase_regions(impl_.self_ty()),
-                                                tcx.erase_regions(qself_ty),
-                                            )
-                                            .is_ok()
-                                    })
-                                    && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
-                                })
-                        })
-                        .map(|trait_def_id| tcx.def_path_str(trait_def_id))
-                        .collect();
+                    let traits: Vec<_> =
+                        self.probe_traits_that_match_assoc_ty(qself_ty, assoc_ident);
 
                     // Don't print `TyErr` to the user.
                     self.report_ambiguous_associated_type(
@@ -2232,6 +2194,60 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         Ok((ty, DefKind::AssocTy, assoc_ty_did))
     }
 
+    fn probe_traits_that_match_assoc_ty(
+        &self,
+        qself_ty: Ty<'tcx>,
+        assoc_ident: Ident,
+    ) -> Vec<String> {
+        let tcx = self.tcx();
+
+        // In contexts that have no inference context, just make a new one.
+        // We do need a local variable to store it, though.
+        let infcx_;
+        let infcx = if let Some(infcx) = self.infcx() {
+            infcx
+        } else {
+            assert!(!qself_ty.needs_infer());
+            infcx_ = tcx.infer_ctxt().build();
+            &infcx_
+        };
+
+        tcx.all_traits()
+            .filter(|trait_def_id| {
+                // Consider only traits with the associated type
+                tcx.associated_items(*trait_def_id)
+                        .in_definition_order()
+                        .any(|i| {
+                            i.kind.namespace() == Namespace::TypeNS
+                                && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
+                                && matches!(i.kind, ty::AssocKind::Type)
+                        })
+                    // Consider only accessible traits
+                    && tcx.visibility(*trait_def_id)
+                        .is_accessible_from(self.item_def_id(), tcx)
+                    && tcx.all_impls(*trait_def_id)
+                        .any(|impl_def_id| {
+                            let trait_ref = tcx.impl_trait_ref(impl_def_id);
+                            trait_ref.map_or(false, |trait_ref| {
+                                let impl_ = trait_ref.subst(
+                                    tcx,
+                                    infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id),
+                                );
+                                infcx
+                                    .can_eq(
+                                        ty::ParamEnv::empty(),
+                                        tcx.erase_regions(impl_.self_ty()),
+                                        tcx.erase_regions(qself_ty),
+                                    )
+                                    .is_ok()
+                            })
+                            && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
+                        })
+            })
+            .map(|trait_def_id| tcx.def_path_str(trait_def_id))
+            .collect()
+    }
+
     fn lookup_assoc_ty(
         &self,
         ident: Ident,
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index b73a05ff398..f5a1e51c07b 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -25,7 +25,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{GenericParamKind, Node};
-use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::query::Providers;
@@ -517,6 +517,10 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
     fn record_ty(&self, _hir_id: hir::HirId, _ty: Ty<'tcx>, _span: Span) {
         // There's no place to record types from signatures?
     }
+
+    fn infcx(&self) -> Option<&InferCtxt<'tcx>> {
+        None
+    }
 }
 
 /// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present.
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index a1872822d36..165782f209a 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -225,8 +225,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
             }
 
             ty::Ref(region, ty, mutbl) => {
-                let contra = self.contravariant(variance);
-                self.add_constraints_from_region(current, region, contra);
+                self.add_constraints_from_region(current, region, variance);
                 self.add_constraints_from_mt(current, &ty::TypeAndMut { ty, mutbl }, variance);
             }
 
@@ -258,9 +257,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
             }
 
             ty::Dynamic(data, r, _) => {
-                // The type `Foo<T+'a>` is contravariant w/r/t `'a`:
-                let contra = self.contravariant(variance);
-                self.add_constraints_from_region(current, r, contra);
+                // The type `dyn Trait<T> +'a` is covariant w/r/t `'a`:
+                self.add_constraints_from_region(current, r, variance);
 
                 if let Some(poly_trait_ref) = data.principal() {
                     self.add_constraints_from_invariant_substs(
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 8724e69cc51..4940015ddd5 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -324,6 +324,10 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
         let ty = if !ty.has_escaping_bound_vars() { self.normalize(span, ty) } else { ty };
         self.write_ty(hir_id, ty)
     }
+
+    fn infcx(&self) -> Option<&infer::InferCtxt<'tcx>> {
+        Some(&self.infcx)
+    }
 }
 
 /// Represents a user-provided type in the raw form (never normalized).
diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs
index 21b68ce9989..b92b162a978 100644
--- a/compiler/rustc_infer/src/infer/glb.rs
+++ b/compiler/rustc_infer/src/infer/glb.rs
@@ -79,7 +79,8 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
         debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
 
         let origin = Subtype(Box::new(self.fields.trace.clone()));
-        Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().glb_regions(
+        // GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8
+        Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().lub_regions(
             self.tcx(),
             origin,
             a,
diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs
index c07ac1d3ace..f6e0554fd1f 100644
--- a/compiler/rustc_infer/src/infer/lub.rs
+++ b/compiler/rustc_infer/src/infer/lub.rs
@@ -79,7 +79,8 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
         debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
 
         let origin = Subtype(Box::new(self.fields.trace.clone()));
-        Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().lub_regions(
+        // LUB(&'static u8, &'a u8) == &RegionGLB('static, 'a) u8 == &'a u8
+        Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().glb_regions(
             self.tcx(),
             origin,
             a,
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index f235cb5ab45..f83219b8ee2 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -663,13 +663,13 @@ where
         debug!(?v_b);
 
         if self.ambient_covariance() {
-            // Covariance: a <= b. Hence, `b: a`.
-            self.push_outlives(v_b, v_a, self.ambient_variance_info);
+            // Covariant: &'a u8 <: &'b u8. Hence, `'a: 'b`.
+            self.push_outlives(v_a, v_b, self.ambient_variance_info);
         }
 
         if self.ambient_contravariance() {
-            // Contravariant: b <= a. Hence, `a: b`.
-            self.push_outlives(v_a, v_b, self.ambient_variance_info);
+            // Contravariant: &'b u8 <: &'a u8. Hence, `'b: 'a`.
+            self.push_outlives(v_b, v_a, self.ambient_variance_info);
         }
 
         Ok(a)
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index bd38b52ba34..51c34f0d55f 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -191,12 +191,13 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
         // from the "cause" field, we could perhaps give more tailored
         // error messages.
         let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone()));
+        // Subtype(&'a u8, &'b u8) => Outlives('a: 'b) => SubRegion('b, 'a)
         self.fields
             .infcx
             .inner
             .borrow_mut()
             .unwrap_region_constraints()
-            .make_subregion(origin, a, b);
+            .make_subregion(origin, b, a);
 
         Ok(a)
     }
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 7122e864cf2..fa87301df7e 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -443,12 +443,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             if a_repr == b_repr =>
         {
             let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| {
-                relation.relate_with_variance(
-                    ty::Contravariant,
-                    ty::VarianceDiagInfo::default(),
-                    a_region,
-                    b_region,
-                )
+                relation.relate(a_region, b_region)
             })?;
             Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound, a_repr))
         }
@@ -497,12 +492,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
         }
 
         (&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => {
-            let r = relation.relate_with_variance(
-                ty::Contravariant,
-                ty::VarianceDiagInfo::default(),
-                a_r,
-                b_r,
-            )?;
+            let r = relation.relate(a_r, b_r)?;
             let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl };
             let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl };
             let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?;
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index eda7046c748..f4c08031bcc 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -2353,6 +2353,28 @@ impl<'a> Parser<'a> {
         Err(err)
     }
 
+    /// Try to recover from an unbraced const argument whose first token [could begin a type][ty].
+    ///
+    /// [ty]: token::Token::can_begin_type
+    pub(crate) fn recover_unbraced_const_arg_that_can_begin_ty(
+        &mut self,
+        mut snapshot: SnapshotParser<'a>,
+    ) -> Option<P<ast::Expr>> {
+        match snapshot.parse_expr_res(Restrictions::CONST_EXPR, None) {
+            // Since we don't know the exact reason why we failed to parse the type or the
+            // expression, employ a simple heuristic to weed out some pathological cases.
+            Ok(expr) if let token::Comma | token::Gt = snapshot.token.kind => {
+                self.restore_snapshot(snapshot);
+                Some(expr)
+            }
+            Ok(_) => None,
+            Err(err) => {
+                err.cancel();
+                None
+            }
+        }
+    }
+
     /// Creates a dummy const argument, and reports that the expression must be enclosed in braces
     pub fn dummy_const_arg_needs_braces(
         &self,
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 5333d3b8587..2e706a00cf7 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -675,22 +675,42 @@ impl<'a> Parser<'a> {
             GenericArg::Const(self.parse_const_arg()?)
         } else if self.check_type() {
             // Parse type argument.
-            let is_const_fn =
-                self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Parenthesis));
-            let mut snapshot = self.create_snapshot_for_diagnostic();
+
+            // Proactively create a parser snapshot enabling us to rewind and try to reparse the
+            // input as a const expression in case we fail to parse a type. If we successfully
+            // do so, we will report an error that it needs to be wrapped in braces.
+            let mut snapshot = None;
+            if self.may_recover() && self.token.can_begin_expr() {
+                snapshot = Some(self.create_snapshot_for_diagnostic());
+            }
+
             match self.parse_ty() {
-                Ok(ty) => GenericArg::Type(ty),
+                Ok(ty) => {
+                    // Since the type parser recovers from some malformed slice and array types and
+                    // successfully returns a type, we need to look for `TyKind::Err`s in the
+                    // type to determine if error recovery has occurred and if the input is not a
+                    // syntactically valid type after all.
+                    if let ast::TyKind::Slice(inner_ty) | ast::TyKind::Array(inner_ty, _) = &ty.kind
+                        && let ast::TyKind::Err = inner_ty.kind
+                        && let Some(snapshot) = snapshot
+                        && let Some(expr) = self.recover_unbraced_const_arg_that_can_begin_ty(snapshot)
+                    {
+                        return Ok(Some(self.dummy_const_arg_needs_braces(
+                            self.struct_span_err(expr.span, "invalid const generic expression"),
+                            expr.span,
+                        )));
+                    }
+
+                    GenericArg::Type(ty)
+                }
                 Err(err) => {
-                    if is_const_fn {
-                        match (*snapshot).parse_expr_res(Restrictions::CONST_EXPR, None) {
-                            Ok(expr) => {
-                                self.restore_snapshot(snapshot);
-                                return Ok(Some(self.dummy_const_arg_needs_braces(err, expr.span)));
-                            }
-                            Err(err) => {
-                                err.cancel();
-                            }
-                        }
+                    if let Some(snapshot) = snapshot
+                        && let Some(expr) = self.recover_unbraced_const_arg_that_can_begin_ty(snapshot)
+                    {
+                        return Ok(Some(self.dummy_const_arg_needs_braces(
+                            err,
+                            expr.span,
+                        )));
                     }
                     // Try to recover from possible `const` arg without braces.
                     return self.recover_const_arg(start, err).map(Some);
diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs
index 0c18fc355e9..f7cf81da497 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly.rs
@@ -1,6 +1,8 @@
 //! Code shared by trait and projection goals for candidate assembly.
 
 use super::infcx_ext::InferCtxtExt;
+#[cfg(doc)]
+use super::trait_goals::structural_traits::*;
 use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult};
 use rustc_hir::def_id::DefId;
 use rustc_infer::traits::query::NoSolution;
@@ -98,52 +100,75 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq {
         assumption: ty::Predicate<'tcx>,
     ) -> QueryResult<'tcx>;
 
+    // A type implements an `auto trait` if its components do as well. These components
+    // are given by built-in rules from [`instantiate_constituent_tys_for_auto_trait`].
     fn consider_auto_trait_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
+    // A trait alias holds if the RHS traits and `where` clauses hold.
     fn consider_trait_alias_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
+    // A type is `Copy` or `Clone` if its components are `Sized`. These components
+    // are given by built-in rules from [`instantiate_constituent_tys_for_sized_trait`].
     fn consider_builtin_sized_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
+    // A type is `Copy` or `Clone` if its components are `Copy` or `Clone`. These
+    // components are given by built-in rules from [`instantiate_constituent_tys_for_copy_clone_trait`].
     fn consider_builtin_copy_clone_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
+    // A type is `PointerSized` if we can compute its layout, and that layout
+    // matches the layout of `usize`.
     fn consider_builtin_pointer_sized_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
+    // A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn<A>`
+    // family of traits where `A` is given by the signature of the type.
     fn consider_builtin_fn_trait_candidates(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
         kind: ty::ClosureKind,
     ) -> QueryResult<'tcx>;
 
+    // `Tuple` is implemented if the `Self` type is a tuple.
     fn consider_builtin_tuple_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
+    // `Pointee` is always implemented.
+    //
+    // See the projection implementation for the `Metadata` types for all of
+    // the built-in types. For structs, the metadata type is given by the struct
+    // tail.
     fn consider_builtin_pointee_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
+    // A generator (that comes from an `async` desugaring) is known to implement
+    // `Future<Output = O>`, where `O` is given by the generator's return type
+    // that was computed during type-checking.
     fn consider_builtin_future_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
+    // A generator (that doesn't come from an `async` desugaring) is known to
+    // implement `Generator<R, Yield = Y, Return = O>`, given the resume, yield,
+    // and return types of the generator computed during type-checking.
     fn consider_builtin_generator_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 7880cbad5fe..e240dd5a225 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -335,15 +335,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
             // That won't actually reflect in the query response, so it seems moot.
             self.make_canonical_response(Certainty::AMBIGUOUS)
         } else {
-            self.infcx.probe(|_| {
-                let InferOk { value: (), obligations } = self
-                    .infcx
-                    .at(&ObligationCause::dummy(), goal.param_env)
-                    .sub(goal.predicate.a, goal.predicate.b)?;
-                self.evaluate_all_and_make_canonical_response(
-                    obligations.into_iter().map(|pred| pred.into()).collect(),
-                )
-            })
+            let InferOk { value: (), obligations } = self
+                .infcx
+                .at(&ObligationCause::dummy(), goal.param_env)
+                .sub(goal.predicate.a, goal.predicate.b)?;
+            self.evaluate_all_and_make_canonical_response(
+                obligations.into_iter().map(|pred| pred.into()).collect(),
+            )
         }
     }
 
@@ -376,22 +374,22 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         &mut self,
         goal: Goal<'tcx, ty::GenericArg<'tcx>>,
     ) -> QueryResult<'tcx> {
-        self.infcx.probe(|_| {
-            match crate::traits::wf::unnormalized_obligations(
-                self.infcx,
-                goal.param_env,
-                goal.predicate,
-            ) {
-                Some(obligations) => self.evaluate_all_and_make_canonical_response(
-                    obligations.into_iter().map(|o| o.into()).collect(),
-                ),
-                None => self.make_canonical_response(Certainty::AMBIGUOUS),
-            }
-        })
+        match crate::traits::wf::unnormalized_obligations(
+            self.infcx,
+            goal.param_env,
+            goal.predicate,
+        ) {
+            Some(obligations) => self.evaluate_all_and_make_canonical_response(
+                obligations.into_iter().map(|o| o.into()).collect(),
+            ),
+            None => self.make_canonical_response(Certainty::AMBIGUOUS),
+        }
     }
 }
 
 impl<'tcx> EvalCtxt<'_, 'tcx> {
+    // Recursively evaluates a list of goals to completion, returning the certainty
+    // of all of the goals.
     fn evaluate_all(
         &mut self,
         mut goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
@@ -428,6 +426,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         })
     }
 
+    // Recursively evaluates a list of goals to completion, making a query response.
+    //
+    // This is just a convenient way of calling [`EvalCtxt::evaluate_all`],
+    // then [`EvalCtxt::make_canonical_response`].
     fn evaluate_all_and_make_canonical_response(
         &mut self,
         goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index 518d6fff938..638efaa2ba5 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -296,7 +296,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
         goal: Goal<'tcx, Self>,
         assumption: ty::Predicate<'tcx>,
     ) -> QueryResult<'tcx> {
-        if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred() {
+        if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred()
+            && poly_projection_pred.projection_def_id() == goal.predicate.def_id()
+        {
             ecx.infcx.probe(|_| {
                 let assumption_projection_pred =
                     ecx.infcx.instantiate_bound_vars_with_infer(poly_projection_pred);
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index d74857dc4b4..45b6a5f4ec5 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -65,7 +65,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         goal: Goal<'tcx, Self>,
         assumption: ty::Predicate<'tcx>,
     ) -> QueryResult<'tcx> {
-        if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred() {
+        if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred()
+            && poly_trait_pred.def_id() == goal.predicate.def_id()
+        {
             // FIXME: Constness and polarity
             ecx.infcx.probe(|_| {
                 let assumption_trait_pred =
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index f7f787dea95..26c0b3beb37 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -3807,13 +3807,13 @@ fn hint_missing_borrow<'tcx>(
     err: &mut Diagnostic,
 ) {
     let found_args = match found.kind() {
-        ty::FnPtr(f) => f.inputs().skip_binder().iter(),
+        ty::FnPtr(f) => infcx.replace_bound_vars_with_placeholders(*f).inputs().iter(),
         kind => {
             span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind)
         }
     };
     let expected_args = match expected.kind() {
-        ty::FnPtr(f) => f.inputs().skip_binder().iter(),
+        ty::FnPtr(f) => infcx.replace_bound_vars_with_placeholders(*f).inputs().iter(),
         kind => {
             span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind)
         }
@@ -3824,12 +3824,12 @@ fn hint_missing_borrow<'tcx>(
 
     let args = fn_decl.inputs.iter().map(|ty| ty);
 
-    fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
-        let mut refs = 0;
+    fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) {
+        let mut refs = vec![];
 
-        while let ty::Ref(_, new_ty, _) = ty.kind() {
+        while let ty::Ref(_, new_ty, mutbl) = ty.kind() {
             ty = *new_ty;
-            refs += 1;
+            refs.push(*mutbl);
         }
 
         (ty, refs)
@@ -3843,11 +3843,21 @@ fn hint_missing_borrow<'tcx>(
         let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg);
 
         if infcx.can_eq(param_env, found_ty, expected_ty).is_ok() {
-            if found_refs < expected_refs {
-                to_borrow.push((arg.span.shrink_to_lo(), "&".repeat(expected_refs - found_refs)));
-            } else if found_refs > expected_refs {
+            // FIXME: This could handle more exotic cases like mutability mismatches too!
+            if found_refs.len() < expected_refs.len()
+                && found_refs[..] == expected_refs[expected_refs.len() - found_refs.len()..]
+            {
+                to_borrow.push((
+                    arg.span.shrink_to_lo(),
+                    expected_refs[..expected_refs.len() - found_refs.len()]
+                        .iter()
+                        .map(|mutbl| format!("&{}", mutbl.prefix_str()))
+                        .collect::<Vec<_>>()
+                        .join(""),
+                ));
+            } else if found_refs.len() > expected_refs.len() {
                 let mut span = arg.span.shrink_to_lo();
-                let mut left = found_refs - expected_refs;
+                let mut left = found_refs.len() - expected_refs.len();
                 let mut ty = arg;
                 while let hir::TyKind::Ref(_, mut_ty) = &ty.kind && left > 0 {
                     span = span.with_hi(mut_ty.ty.span.lo());
diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
index 09b58894d30..f183248f2d0 100644
--- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
@@ -1,7 +1,9 @@
 use rustc_middle::ty;
+use rustc_session::config::TraitSolver;
 
 use crate::infer::canonical::OriginalQueryValues;
 use crate::infer::InferCtxt;
+use crate::solve::{Certainty, Goal, InferCtxtEvalExt, MaybeCause};
 use crate::traits::{EvaluationResult, OverflowError, PredicateObligation, SelectionContext};
 
 pub trait InferCtxtExt<'tcx> {
@@ -77,12 +79,38 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
             _ => obligation.param_env.without_const(),
         };
 
-        let c_pred = self
-            .canonicalize_query_keep_static(param_env.and(obligation.predicate), &mut _orig_values);
-        // Run canonical query. If overflow occurs, rerun from scratch but this time
-        // in standard trait query mode so that overflow is handled appropriately
-        // within `SelectionContext`.
-        self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred)
+        if self.tcx.sess.opts.unstable_opts.trait_solver != TraitSolver::Next {
+            let c_pred = self.canonicalize_query_keep_static(
+                param_env.and(obligation.predicate),
+                &mut _orig_values,
+            );
+            self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred)
+        } else {
+            self.probe(|snapshot| {
+                if let Ok((_, certainty)) =
+                    self.evaluate_root_goal(Goal::new(self.tcx, param_env, obligation.predicate))
+                {
+                    match certainty {
+                        Certainty::Yes => {
+                            if self.opaque_types_added_in_snapshot(snapshot) {
+                                Ok(EvaluationResult::EvaluatedToOkModuloOpaqueTypes)
+                            } else if self.region_constraints_added_in_snapshot(snapshot).is_some()
+                            {
+                                Ok(EvaluationResult::EvaluatedToOkModuloRegions)
+                            } else {
+                                Ok(EvaluationResult::EvaluatedToOk)
+                            }
+                        }
+                        Certainty::Maybe(MaybeCause::Ambiguity) => {
+                            Ok(EvaluationResult::EvaluatedToAmbig)
+                        }
+                        Certainty::Maybe(MaybeCause::Overflow) => Err(OverflowError::Canonical),
+                    }
+                } else {
+                    Ok(EvaluationResult::EvaluatedToErr)
+                }
+            })
+        }
     }
 
     // Helper function that canonicalizes and runs the query. If an
@@ -92,6 +120,9 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
         &self,
         obligation: &PredicateObligation<'tcx>,
     ) -> EvaluationResult {
+        // Run canonical query. If overflow occurs, rerun from scratch but this time
+        // in standard trait query mode so that overflow is handled appropriately
+        // within `SelectionContext`.
         match self.evaluate_obligation(obligation) {
             Ok(result) => result,
             Err(OverflowError::Canonical) => {
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 7cc00e3f8d1..c43b728022d 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -551,7 +551,7 @@ use crate::marker::Destruct;
 use crate::panicking::{panic, panic_str};
 use crate::pin::Pin;
 use crate::{
-    convert, hint, mem,
+    cmp, convert, hint, mem,
     ops::{self, ControlFlow, Deref, DerefMut},
 };
 
@@ -2090,6 +2090,12 @@ impl<T: PartialEq> PartialEq for Option<T> {
     }
 }
 
+/// This specialization trait is a workaround for LLVM not currently (2023-01)
+/// being able to optimize this itself, even though Alive confirms that it would
+/// be legal to do so: <https://github.com/llvm/llvm-project/issues/52622>
+///
+/// Once that's fixed, `Option` should go back to deriving `PartialEq`, as
+/// it used to do before <https://github.com/rust-lang/rust/pull/103556>.
 #[unstable(feature = "spec_option_partial_eq", issue = "none", reason = "exposed only for rustc")]
 #[doc(hidden)]
 pub trait SpecOptionPartialEq: Sized {
@@ -2146,6 +2152,14 @@ impl<T> SpecOptionPartialEq for crate::ptr::NonNull<T> {
     }
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl SpecOptionPartialEq for cmp::Ordering {
+    #[inline]
+    fn eq(l: &Option<Self>, r: &Option<Self>) -> bool {
+        l.map_or(2, |x| x as i8) == r.map_or(2, |x| x as i8)
+    }
+}
+
 /////////////////////////////////////////////////////////////////////////////
 // The Option Iterators
 /////////////////////////////////////////////////////////////////////////////
diff --git a/tests/codegen/debug-vtable.rs b/tests/codegen/debug-vtable.rs
index bdd312878ec..d82b737de0b 100644
--- a/tests/codegen/debug-vtable.rs
+++ b/tests/codegen/debug-vtable.rs
@@ -9,6 +9,14 @@
 // compile-flags: -Cdebuginfo=2 -Copt-level=0 -Csymbol-mangling-version=v0
 // ignore-tidy-linelength
 
+// Make sure that vtables don't have the unnamed_addr attribute when debuginfo is enabled.
+// This helps debuggers more reliably map from dyn pointer to concrete type.
+// CHECK: @vtable.0 = private constant <{
+// CHECK: @vtable.1 = private constant <{
+// CHECK: @vtable.2 = private constant <{
+// CHECK: @vtable.3 = private constant <{
+// CHECK: @vtable.4 = private constant <{
+
 // NONMSVC: ![[USIZE:[0-9]+]] = !DIBasicType(name: "usize"
 // MSVC: ![[USIZE:[0-9]+]] = !DIDerivedType(tag: DW_TAG_typedef, name: "usize"
 // NONMSVC: ![[PTR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "*const ()"
diff --git a/tests/codegen/option-nonzero-eq.rs b/tests/codegen/option-nonzero-eq.rs
index 598dcc19b49..835decd3e5f 100644
--- a/tests/codegen/option-nonzero-eq.rs
+++ b/tests/codegen/option-nonzero-eq.rs
@@ -3,6 +3,7 @@
 #![crate_type = "lib"]
 
 extern crate core;
+use core::cmp::Ordering;
 use core::num::{NonZeroU32, NonZeroI64};
 use core::ptr::NonNull;
 
@@ -32,3 +33,12 @@ pub fn non_null_eq(l: Option<NonNull<u8>>, r: Option<NonNull<u8>>) -> bool {
     // CHECK-NEXT: ret i1
     l == r
 }
+
+// CHECK-lABEL: @ordering_eq
+#[no_mangle]
+pub fn ordering_eq(l: Option<Ordering>, r: Option<Ordering>) -> bool {
+    // CHECK: start:
+    // CHECK-NEXT: icmp eq i8
+    // CHECK-NEXT: ret i1
+    l == r
+}
diff --git a/tests/ui/const-generics/bad-const-generic-exprs.rs b/tests/ui/const-generics/bad-const-generic-exprs.rs
index ca91643edf7..423752ca25e 100644
--- a/tests/ui/const-generics/bad-const-generic-exprs.rs
+++ b/tests/ui/const-generics/bad-const-generic-exprs.rs
@@ -13,10 +13,34 @@ fn main() {
     let _: Wow<A.0>;
     //~^ ERROR expected one of
     //~| HELP expressions must be enclosed in braces to be used as const generic arguments
-
-    // FIXME(compiler-errors): This one is still unsatisfying,
-    // and probably a case I could see someone typing by accident..
+    let _: Wow<[]>;
+    //~^ ERROR expected type
+    //~| HELP expressions must be enclosed in braces to be used as const generic arguments
     let _: Wow<[12]>;
-    //~^ ERROR expected type, found
-    //~| ERROR type provided when a constant was expected
+    //~^ ERROR expected type
+    //~| ERROR invalid const generic expression
+    //~| HELP expressions must be enclosed in braces to be used as const generic arguments
+    let _: Wow<[0, 1, 3]>;
+    //~^ ERROR expected type
+    //~| HELP expressions must be enclosed in braces to be used as const generic arguments
+    let _: Wow<[0xff; 8]>;
+    //~^ ERROR expected type
+    //~| ERROR invalid const generic expression
+    //~| HELP expressions must be enclosed in braces to be used as const generic arguments
+    let _: Wow<[1, 2]>; // Regression test for issue #81698.
+    //~^ ERROR expected type
+    //~| HELP expressions must be enclosed in braces to be used as const generic arguments
+    let _: Wow<&0>;
+    //~^ ERROR expected type
+    //~| HELP expressions must be enclosed in braces to be used as const generic arguments
+    let _: Wow<("", 0)>;
+    //~^ ERROR expected type
+    //~| HELP expressions must be enclosed in braces to be used as const generic arguments
+    let _: Wow<(1 + 2) * 3>;
+    //~^ ERROR expected type
+    //~| HELP expressions must be enclosed in braces to be used as const generic arguments
+    // FIXME(fmease): This one is pretty bad.
+    let _: Wow<!0>;
+    //~^ ERROR expected one of
+    //~| HELP you might have meant to end the type parameters here
 }
diff --git a/tests/ui/const-generics/bad-const-generic-exprs.stderr b/tests/ui/const-generics/bad-const-generic-exprs.stderr
index 24668b08b8a..17a63a96fe4 100644
--- a/tests/ui/const-generics/bad-const-generic-exprs.stderr
+++ b/tests/ui/const-generics/bad-const-generic-exprs.stderr
@@ -42,18 +42,118 @@ help: expressions must be enclosed in braces to be used as const generic argumen
 LL |     let _: Wow<{ A.0 }>;
    |                +     +
 
+error: expected type, found `]`
+  --> $DIR/bad-const-generic-exprs.rs:16:17
+   |
+LL |     let _: Wow<[]>;
+   |                 ^ expected type
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     let _: Wow<{ [] }>;
+   |                +    +
+
 error: expected type, found `12`
   --> $DIR/bad-const-generic-exprs.rs:19:17
    |
 LL |     let _: Wow<[12]>;
    |                 ^^ expected type
 
-error[E0747]: type provided when a constant was expected
+error: invalid const generic expression
   --> $DIR/bad-const-generic-exprs.rs:19:16
    |
 LL |     let _: Wow<[12]>;
    |                ^^^^
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     let _: Wow<{ [12] }>;
+   |                +      +
+
+error: expected type, found `0`
+  --> $DIR/bad-const-generic-exprs.rs:23:17
+   |
+LL |     let _: Wow<[0, 1, 3]>;
+   |                 ^ expected type
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     let _: Wow<{ [0, 1, 3] }>;
+   |                +           +
+
+error: expected type, found `0xff`
+  --> $DIR/bad-const-generic-exprs.rs:26:17
+   |
+LL |     let _: Wow<[0xff; 8]>;
+   |                 ^^^^ expected type
+
+error: invalid const generic expression
+  --> $DIR/bad-const-generic-exprs.rs:26:16
+   |
+LL |     let _: Wow<[0xff; 8]>;
+   |                ^^^^^^^^^
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     let _: Wow<{ [0xff; 8] }>;
+   |                +           +
+
+error: expected type, found `1`
+  --> $DIR/bad-const-generic-exprs.rs:30:17
+   |
+LL |     let _: Wow<[1, 2]>; // Regression test for issue #81698.
+   |                 ^ expected type
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     let _: Wow<{ [1, 2] }>; // Regression test for issue #81698.
+   |                +        +
+
+error: expected type, found `0`
+  --> $DIR/bad-const-generic-exprs.rs:33:17
+   |
+LL |     let _: Wow<&0>;
+   |                 ^ expected type
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     let _: Wow<{ &0 }>;
+   |                +    +
+
+error: expected type, found `""`
+  --> $DIR/bad-const-generic-exprs.rs:36:17
+   |
+LL |     let _: Wow<("", 0)>;
+   |                 ^^ expected type
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     let _: Wow<{ ("", 0) }>;
+   |                +         +
+
+error: expected type, found `1`
+  --> $DIR/bad-const-generic-exprs.rs:39:17
+   |
+LL |     let _: Wow<(1 + 2) * 3>;
+   |                 ^ expected type
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     let _: Wow<{ (1 + 2) * 3 }>;
+   |                +             +
+
+error: expected one of `,` or `>`, found `0`
+  --> $DIR/bad-const-generic-exprs.rs:43:17
+   |
+LL |     let _: Wow<!0>;
+   |         -       ^ expected one of `,` or `>`
+   |         |
+   |         while parsing the type for `_`
+   |
+help: you might have meant to end the type parameters here
+   |
+LL |     let _: Wow<!>0>;
+   |                 +
 
-error: aborting due to 6 previous errors
+error: aborting due to 15 previous errors
 
-For more information about this error, try `rustc --explain E0747`.
diff --git a/tests/ui/error-codes/E0208.rs b/tests/ui/error-codes/E0208.rs
index c67d42889d6..74c138af483 100644
--- a/tests/ui/error-codes/E0208.rs
+++ b/tests/ui/error-codes/E0208.rs
@@ -1,7 +1,7 @@
 #![feature(rustc_attrs)]
 
 #[rustc_variance]
-struct Foo<'a, T> { //~ ERROR [-, o]
+struct Foo<'a, T> { //~ ERROR [+, o]
     t: &'a mut T,
 }
 
diff --git a/tests/ui/error-codes/E0208.stderr b/tests/ui/error-codes/E0208.stderr
index dbbb41e7950..2c7072a7e76 100644
--- a/tests/ui/error-codes/E0208.stderr
+++ b/tests/ui/error-codes/E0208.stderr
@@ -1,4 +1,4 @@
-error: [-, o]
+error: [+, o]
   --> $DIR/E0208.rs:4:1
    |
 LL | struct Foo<'a, T> {
diff --git a/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.rs b/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.rs
new file mode 100644
index 00000000000..3bf6b7bb9b1
--- /dev/null
+++ b/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.rs
@@ -0,0 +1,28 @@
+use std::cell::RefCell;
+use std::collections::HashMap;
+use std::rc::Rc;
+
+pub struct Trader<'a> {
+    closure: Box<dyn Fn(&mut Trader) + 'a>,
+}
+
+impl<'a> Trader<'a> {
+    pub fn new() -> Self {
+        Trader {
+            closure: Box::new(|_| {}),
+        }
+    }
+    pub fn set_closure(&mut self, function: impl Fn(&mut Trader) + 'a) {
+        //foo
+    }
+}
+
+fn main() {
+    let closure = |trader : Trader| {
+        println!("Woooosh!");
+    };
+
+    let mut trader = Trader::new();
+    trader.set_closure(closure);
+    //~^ ERROR type mismatch in closure arguments
+}
diff --git a/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.stderr b/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.stderr
new file mode 100644
index 00000000000..6820af1fd45
--- /dev/null
+++ b/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.stderr
@@ -0,0 +1,26 @@
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/late-bound-in-borrow-closure-sugg.rs:26:24
+   |
+LL |     let closure = |trader : Trader| {
+   |                   ----------------- found signature defined here
+...
+LL |     trader.set_closure(closure);
+   |            ----------- ^^^^^^^ expected due to this
+   |            |
+   |            required by a bound introduced by this call
+   |
+   = note: expected closure signature `for<'a, 'b> fn(&'a mut Trader<'b>) -> _`
+              found closure signature `for<'a> fn(Trader<'a>) -> _`
+note: required by a bound in `Trader::<'a>::set_closure`
+  --> $DIR/late-bound-in-borrow-closure-sugg.rs:15:50
+   |
+LL |     pub fn set_closure(&mut self, function: impl Fn(&mut Trader) + 'a) {
+   |                                                  ^^^^^^^^^^^^^^^ required by this bound in `Trader::<'a>::set_closure`
+help: consider borrowing the argument
+   |
+LL |     let closure = |trader : &mut Trader| {
+   |                             ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0631`.
diff --git a/tests/ui/typeck/issue-107087.rs b/tests/ui/typeck/issue-107087.rs
new file mode 100644
index 00000000000..135cdf19e3e
--- /dev/null
+++ b/tests/ui/typeck/issue-107087.rs
@@ -0,0 +1,18 @@
+struct A<T>(T);
+
+trait Foo {
+    type B;
+}
+
+impl Foo for A<u32> {
+    type B = i32;
+}
+
+impl Foo for A<i32> {
+    type B = i32;
+}
+
+fn main() {
+    A::B::<>::C
+    //~^ ERROR ambiguous associated type
+}
diff --git a/tests/ui/typeck/issue-107087.stderr b/tests/ui/typeck/issue-107087.stderr
new file mode 100644
index 00000000000..70f19320802
--- /dev/null
+++ b/tests/ui/typeck/issue-107087.stderr
@@ -0,0 +1,9 @@
+error[E0223]: ambiguous associated type
+  --> $DIR/issue-107087.rs:16:5
+   |
+LL |     A::B::<>::C
+   |     ^^^^^^^^ help: use the fully-qualified path: `<A<_> as Foo>::B`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0223`.
diff --git a/tests/ui/variance/variance-associated-types.rs b/tests/ui/variance/variance-associated-types.rs
index 1165fb53c73..ecb0821827d 100644
--- a/tests/ui/variance/variance-associated-types.rs
+++ b/tests/ui/variance/variance-associated-types.rs
@@ -10,7 +10,7 @@ trait Trait<'a> {
 }
 
 #[rustc_variance]
-struct Foo<'a, T : Trait<'a>> { //~ ERROR [-, +]
+struct Foo<'a, T : Trait<'a>> { //~ ERROR [+, +]
     field: (T, &'a ())
 }
 
diff --git a/tests/ui/variance/variance-associated-types.stderr b/tests/ui/variance/variance-associated-types.stderr
index 51f17c7c228..70cb246f6e9 100644
--- a/tests/ui/variance/variance-associated-types.stderr
+++ b/tests/ui/variance/variance-associated-types.stderr
@@ -1,4 +1,4 @@
-error: [-, +]
+error: [+, +]
   --> $DIR/variance-associated-types.rs:13:1
    |
 LL | struct Foo<'a, T : Trait<'a>> {
diff --git a/tests/ui/variance/variance-regions-direct.rs b/tests/ui/variance/variance-regions-direct.rs
index 3f34e7655f3..39ea77a8aa2 100644
--- a/tests/ui/variance/variance-regions-direct.rs
+++ b/tests/ui/variance/variance-regions-direct.rs
@@ -6,7 +6,7 @@
 // Regions that just appear in normal spots are contravariant:
 
 #[rustc_variance]
-struct Test2<'a, 'b, 'c> { //~ ERROR [-, -, -]
+struct Test2<'a, 'b, 'c> { //~ ERROR [+, +, +]
     x: &'a isize,
     y: &'b [isize],
     c: &'c str
@@ -15,7 +15,7 @@ struct Test2<'a, 'b, 'c> { //~ ERROR [-, -, -]
 // Those same annotations in function arguments become covariant:
 
 #[rustc_variance]
-struct Test3<'a, 'b, 'c> { //~ ERROR [+, +, +]
+struct Test3<'a, 'b, 'c> { //~ ERROR [-, -, -]
     x: extern "Rust" fn(&'a isize),
     y: extern "Rust" fn(&'b [isize]),
     c: extern "Rust" fn(&'c str),
@@ -24,7 +24,7 @@ struct Test3<'a, 'b, 'c> { //~ ERROR [+, +, +]
 // Mutability induces invariance:
 
 #[rustc_variance]
-struct Test4<'a, 'b:'a> { //~ ERROR [-, o]
+struct Test4<'a, 'b:'a> { //~ ERROR [+, o]
     x: &'a mut &'b isize,
 }
 
@@ -32,7 +32,7 @@ struct Test4<'a, 'b:'a> { //~ ERROR [-, o]
 // contravariant context:
 
 #[rustc_variance]
-struct Test5<'a, 'b:'a> { //~ ERROR [+, o]
+struct Test5<'a, 'b:'a> { //~ ERROR [-, o]
     x: extern "Rust" fn(&'a mut &'b isize),
 }
 
@@ -42,7 +42,7 @@ struct Test5<'a, 'b:'a> { //~ ERROR [+, o]
 // argument list occurs in an invariant context.
 
 #[rustc_variance]
-struct Test6<'a, 'b:'a> { //~ ERROR [-, o]
+struct Test6<'a, 'b:'a> { //~ ERROR [+, o]
     x: &'a mut extern "Rust" fn(&'b isize),
 }
 
@@ -56,7 +56,7 @@ struct Test7<'a> { //~ ERROR [*]
 // Try enums too.
 
 #[rustc_variance]
-enum Test8<'a, 'b, 'c:'b> { //~ ERROR [+, -, o]
+enum Test8<'a, 'b, 'c:'b> { //~ ERROR [-, +, o]
     Test8A(extern "Rust" fn(&'a isize)),
     Test8B(&'b [isize]),
     Test8C(&'b mut &'c str),
diff --git a/tests/ui/variance/variance-regions-direct.stderr b/tests/ui/variance/variance-regions-direct.stderr
index eda02e9b03b..c55730296f1 100644
--- a/tests/ui/variance/variance-regions-direct.stderr
+++ b/tests/ui/variance/variance-regions-direct.stderr
@@ -1,28 +1,28 @@
-error: [-, -, -]
+error: [+, +, +]
   --> $DIR/variance-regions-direct.rs:9:1
    |
 LL | struct Test2<'a, 'b, 'c> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [+, +, +]
+error: [-, -, -]
   --> $DIR/variance-regions-direct.rs:18:1
    |
 LL | struct Test3<'a, 'b, 'c> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [-, o]
+error: [+, o]
   --> $DIR/variance-regions-direct.rs:27:1
    |
 LL | struct Test4<'a, 'b:'a> {
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [+, o]
+error: [-, o]
   --> $DIR/variance-regions-direct.rs:35:1
    |
 LL | struct Test5<'a, 'b:'a> {
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [-, o]
+error: [+, o]
   --> $DIR/variance-regions-direct.rs:45:1
    |
 LL | struct Test6<'a, 'b:'a> {
@@ -34,7 +34,7 @@ error: [*]
 LL | struct Test7<'a> {
    | ^^^^^^^^^^^^^^^^
 
-error: [+, -, o]
+error: [-, +, o]
   --> $DIR/variance-regions-direct.rs:59:1
    |
 LL | enum Test8<'a, 'b, 'c:'b> {
diff --git a/tests/ui/variance/variance-regions-indirect.rs b/tests/ui/variance/variance-regions-indirect.rs
index f84f25ada14..0d00535fef1 100644
--- a/tests/ui/variance/variance-regions-indirect.rs
+++ b/tests/ui/variance/variance-regions-indirect.rs
@@ -5,14 +5,14 @@
 #![feature(rustc_attrs)]
 
 #[rustc_variance]
-enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [+, -, o, *]
+enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [-, +, o, *]
     Test8A(extern "Rust" fn(&'a isize)),
     Test8B(&'b [isize]),
     Test8C(&'b mut &'c str),
 }
 
 #[rustc_variance]
-struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR [*, o, -, +]
+struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR [*, o, +, -]
     f: Base<'z, 'y, 'x, 'w>
 }
 
@@ -22,12 +22,12 @@ struct Derived2<'a, 'b:'a, 'c> { //~ ERROR [o, o, *]
 }
 
 #[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here)
-struct Derived3<'a:'b, 'b, 'c> { //~ ERROR [o, -, *]
+struct Derived3<'a:'b, 'b, 'c> { //~ ERROR [o, +, *]
     f: Base<'a, 'b, 'a, 'c>
 }
 
 #[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here)
-struct Derived4<'a, 'b, 'c:'b> { //~ ERROR [+, -, o]
+struct Derived4<'a, 'b, 'c:'b> { //~ ERROR [-, +, o]
     f: Base<'a, 'b, 'c, 'a>
 }
 
diff --git a/tests/ui/variance/variance-regions-indirect.stderr b/tests/ui/variance/variance-regions-indirect.stderr
index fa2f4d507f3..edf2626d598 100644
--- a/tests/ui/variance/variance-regions-indirect.stderr
+++ b/tests/ui/variance/variance-regions-indirect.stderr
@@ -1,10 +1,10 @@
-error: [+, -, o, *]
+error: [-, +, o, *]
   --> $DIR/variance-regions-indirect.rs:8:1
    |
 LL | enum Base<'a, 'b, 'c:'b, 'd> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [*, o, -, +]
+error: [*, o, +, -]
   --> $DIR/variance-regions-indirect.rs:15:1
    |
 LL | struct Derived1<'w, 'x:'y, 'y, 'z> {
@@ -16,13 +16,13 @@ error: [o, o, *]
 LL | struct Derived2<'a, 'b:'a, 'c> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [o, -, *]
+error: [o, +, *]
   --> $DIR/variance-regions-indirect.rs:25:1
    |
 LL | struct Derived3<'a:'b, 'b, 'c> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [+, -, o]
+error: [-, +, o]
   --> $DIR/variance-regions-indirect.rs:30:1
    |
 LL | struct Derived4<'a, 'b, 'c:'b> {
diff --git a/tests/ui/variance/variance-trait-object-bound.rs b/tests/ui/variance/variance-trait-object-bound.rs
index ec3c973bc76..11303c46520 100644
--- a/tests/ui/variance/variance-trait-object-bound.rs
+++ b/tests/ui/variance/variance-trait-object-bound.rs
@@ -11,7 +11,7 @@ use std::mem;
 trait T { fn foo(&self); }
 
 #[rustc_variance]
-struct TOption<'a> { //~ ERROR [-]
+struct TOption<'a> { //~ ERROR [+]
     v: Option<Box<dyn T + 'a>>,
 }
 
diff --git a/tests/ui/variance/variance-trait-object-bound.stderr b/tests/ui/variance/variance-trait-object-bound.stderr
index 7c46b553f43..bfcc8d4a1d1 100644
--- a/tests/ui/variance/variance-trait-object-bound.stderr
+++ b/tests/ui/variance/variance-trait-object-bound.stderr
@@ -1,4 +1,4 @@
-error: [-]
+error: [+]
   --> $DIR/variance-trait-object-bound.rs:14:1
    |
 LL | struct TOption<'a> {
diff --git a/tests/ui/variance/variance-types.rs b/tests/ui/variance/variance-types.rs
index b9b6d9c9bb5..cfc03b75473 100644
--- a/tests/ui/variance/variance-types.rs
+++ b/tests/ui/variance/variance-types.rs
@@ -7,7 +7,7 @@ use std::cell::Cell;
 // not considered bivariant.
 
 #[rustc_variance]
-struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR [-, o, o]
+struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR [+, o, o]
     t: &'a mut (A,B)
 }
 
diff --git a/tests/ui/variance/variance-types.stderr b/tests/ui/variance/variance-types.stderr
index 9f7f1d9b0e3..0fda4b8036e 100644
--- a/tests/ui/variance/variance-types.stderr
+++ b/tests/ui/variance/variance-types.stderr
@@ -1,4 +1,4 @@
-error: [-, o, o]
+error: [+, o, o]
   --> $DIR/variance-types.rs:10:1
    |
 LL | struct InvariantMut<'a,A:'a,B:'a> {