about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs112
-rw-r--r--compiler/rustc_borrowck/src/lib.rs6
-rw-r--r--compiler/rustc_borrowck/src/nll.rs8
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs4
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs66
-rw-r--r--compiler/rustc_borrowck/src/type_check/canonical.rs9
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/input_output.rs8
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs275
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs42
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs14
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs19
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs8
-rw-r--r--compiler/rustc_data_structures/src/vec_map.rs16
-rw-r--r--compiler/rustc_infer/src/infer/at.rs21
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs72
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs26
-rw-r--r--compiler/rustc_infer/src/infer/equate.rs26
-rw-r--r--compiler/rustc_infer/src/infer/glb.rs10
-rw-r--r--compiler/rustc_infer/src/infer/lattice.rs25
-rw-r--r--compiler/rustc_infer/src/infer/lub.rs10
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs63
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs43
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs490
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/table.rs80
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs3
-rw-r--r--compiler/rustc_infer/src/infer/sub.rs37
-rw-r--r--compiler/rustc_infer/src/infer/undo_log.rs4
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs6
-rw-r--r--compiler/rustc_middle/src/mir/query.rs4
-rw-r--r--compiler/rustc_middle/src/ty/_match.rs4
-rw-r--r--compiler/rustc_middle/src/ty/context.rs11
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs14
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs45
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs25
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs7
-rw-r--r--compiler/rustc_mir_build/src/build/block.rs6
-rw-r--r--compiler/rustc_query_system/src/dep_graph/serialized.rs2
-rw-r--r--compiler/rustc_trait_selection/src/opaque_types.rs31
-rw-r--r--compiler/rustc_trait_selection/src/traits/codegen.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs19
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs32
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs37
-rw-r--r--compiler/rustc_traits/src/chalk/mod.rs2
-rw-r--r--compiler/rustc_type_ir/src/lib.rs8
-rw-r--r--compiler/rustc_typeck/src/check/_match.rs20
-rw-r--r--compiler/rustc_typeck/src/check/callee.rs2
-rw-r--r--compiler/rustc_typeck/src/check/check.rs61
-rw-r--r--compiler/rustc_typeck/src/check/closure.rs78
-rw-r--r--compiler/rustc_typeck/src/check/coercion.rs2
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs3
-rw-r--r--compiler/rustc_typeck/src/check/fallback.rs65
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs45
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/mod.rs3
-rw-r--r--compiler/rustc_typeck/src/check/inherited.rs9
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs3
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs1
-rw-r--r--compiler/rustc_typeck/src/check/upvar.rs5
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs2
-rw-r--r--compiler/rustc_typeck/src/check/writeback.rs91
-rw-r--r--compiler/rustc_typeck/src/collect/type_of.rs92
-rw-r--r--src/bootstrap/bin/rustc.rs6
-rw-r--r--src/test/incremental/hashes/function_interfaces.rs2
-rw-r--r--src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs2
-rw-r--r--src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr8
-rw-r--r--src/test/ui/associated-types/impl-trait-return-missing-constraint.rs3
-rw-r--r--src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr35
-rw-r--r--src/test/ui/async-await/async-borrowck-escaping-block-error.stderr6
-rw-r--r--src/test/ui/async-await/issue-70818.rs2
-rw-r--r--src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr14
-rw-r--r--src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr29
-rw-r--r--src/test/ui/async-await/no-const-async.rs1
-rw-r--r--src/test/ui/async-await/no-const-async.stderr33
-rw-r--r--src/test/ui/async-await/recursive-async-impl-trait-type.rs3
-rw-r--r--src/test/ui/async-await/suggest-missing-await.rs2
-rw-r--r--src/test/ui/chalkify/bugs/async.stderr9
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr6
-rw-r--r--src/test/ui/conservative_impl_trait.rs1
-rw-r--r--src/test/ui/conservative_impl_trait.stderr14
-rw-r--r--src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs3
-rw-r--r--src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr50
-rw-r--r--src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.rs2
-rw-r--r--src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr25
-rw-r--r--src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.rs11
-rw-r--r--src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr73
-rw-r--r--src/test/ui/generator/issue-88653.rs10
-rw-r--r--src/test/ui/generator/issue-88653.stderr18
-rw-r--r--src/test/ui/generator/type-mismatch-signature-deduction.rs4
-rw-r--r--src/test/ui/generator/type-mismatch-signature-deduction.stderr30
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-86218.stderr12
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-89008.stderr26
-rw-r--r--src/test/ui/generic-associated-types/issue-87258_a.rs3
-rw-r--r--src/test/ui/generic-associated-types/issue-87258_a.stderr11
-rw-r--r--src/test/ui/generic-associated-types/issue-87258_b.rs3
-rw-r--r--src/test/ui/generic-associated-types/issue-87258_b.stderr11
-rw-r--r--src/test/ui/generic-associated-types/issue-88595.rs1
-rw-r--r--src/test/ui/generic-associated-types/issue-88595.stderr12
-rw-r--r--src/test/ui/impl-trait/async_scope_creep.rs28
-rw-r--r--src/test/ui/impl-trait/auto-trait-leak.rs1
-rw-r--r--src/test/ui/impl-trait/auto-trait-leak.stderr112
-rw-r--r--src/test/ui/impl-trait/auto-trait.rs2
-rw-r--r--src/test/ui/impl-trait/auto-trait.stderr4
-rw-r--r--src/test/ui/impl-trait/autoderef.rs19
-rw-r--r--src/test/ui/impl-trait/bound-normalization-fail.rs6
-rw-r--r--src/test/ui/impl-trait/bound-normalization-fail.stderr65
-rw-r--r--src/test/ui/impl-trait/cross-return-site-inference.rs45
-rw-r--r--src/test/ui/impl-trait/cross-return-site-inference.stderr26
-rw-r--r--src/test/ui/impl-trait/divergence.rs13
-rw-r--r--src/test/ui/impl-trait/does-not-live-long-enough.stderr6
-rw-r--r--src/test/ui/impl-trait/equality.stderr13
-rw-r--r--src/test/ui/impl-trait/fallback.rs9
-rw-r--r--src/test/ui/impl-trait/hidden-lifetimes.rs4
-rw-r--r--src/test/ui/impl-trait/hidden-lifetimes.stderr16
-rw-r--r--src/test/ui/impl-trait/hidden-type-is-opaque-2.rs45
-rw-r--r--src/test/ui/impl-trait/hidden-type-is-opaque-2.stderr19
-rw-r--r--src/test/ui/impl-trait/hidden-type-is-opaque.rs42
-rw-r--r--src/test/ui/impl-trait/issue-55872-1.rs7
-rw-r--r--src/test/ui/impl-trait/issue-55872-1.stderr27
-rw-r--r--src/test/ui/impl-trait/issue-55872-2.rs7
-rw-r--r--src/test/ui/impl-trait/issue-55872-2.stderr20
-rw-r--r--src/test/ui/impl-trait/issue-55872-3.rs20
-rw-r--r--src/test/ui/impl-trait/issue-55872-3.stderr9
-rw-r--r--src/test/ui/impl-trait/issue-55872.rs2
-rw-r--r--src/test/ui/impl-trait/issue-55872.stderr10
-rw-r--r--src/test/ui/impl-trait/issue-72911.rs2
-rw-r--r--src/test/ui/impl-trait/issue-72911.stderr22
-rw-r--r--src/test/ui/impl-trait/issue-86465.rs2
-rw-r--r--src/test/ui/impl-trait/issue-86465.stderr15
-rw-r--r--src/test/ui/impl-trait/issues/issue-54895.rs23
-rw-r--r--src/test/ui/impl-trait/issues/issue-62742.rs32
-rw-r--r--src/test/ui/impl-trait/issues/issue-62742.stderr54
-rw-r--r--src/test/ui/impl-trait/issues/issue-67830.nll.stderr20
-rw-r--r--src/test/ui/impl-trait/issues/issue-67830.rs26
-rw-r--r--src/test/ui/impl-trait/issues/issue-67830.stderr15
-rw-r--r--src/test/ui/impl-trait/issues/issue-70877.rs6
-rw-r--r--src/test/ui/impl-trait/issues/issue-70877.stderr40
-rw-r--r--src/test/ui/impl-trait/issues/issue-74282.rs11
-rw-r--r--src/test/ui/impl-trait/issues/issue-74282.stderr33
-rw-r--r--src/test/ui/impl-trait/issues/issue-77987.rs21
-rw-r--r--src/test/ui/impl-trait/issues/issue-78722.rs5
-rw-r--r--src/test/ui/impl-trait/issues/issue-78722.stderr35
-rw-r--r--src/test/ui/impl-trait/issues/issue-82139.rs19
-rw-r--r--src/test/ui/impl-trait/issues/issue-82139.stderr9
-rw-r--r--src/test/ui/impl-trait/issues/issue-83919.rs31
-rw-r--r--src/test/ui/impl-trait/issues/issue-83919.stderr17
-rw-r--r--src/test/ui/impl-trait/issues/issue-84073.rs33
-rw-r--r--src/test/ui/impl-trait/issues/issue-84073.stderr9
-rw-r--r--src/test/ui/impl-trait/issues/issue-86201.rs4
-rw-r--r--src/test/ui/impl-trait/issues/issue-86201.stderr21
-rw-r--r--src/test/ui/impl-trait/issues/issue-86719.rs12
-rw-r--r--src/test/ui/impl-trait/issues/issue-86719.stderr24
-rw-r--r--src/test/ui/impl-trait/issues/issue-86800.rs48
-rw-r--r--src/test/ui/impl-trait/issues/issue-86800.stderr10
-rw-r--r--src/test/ui/impl-trait/issues/issue-87340.rs14
-rw-r--r--src/test/ui/impl-trait/issues/issue-87340.stderr9
-rw-r--r--src/test/ui/impl-trait/issues/issue-88236-2.nll.stderr51
-rw-r--r--src/test/ui/impl-trait/issues/issue-88236-2.rs23
-rw-r--r--src/test/ui/impl-trait/issues/issue-88236-2.stderr23
-rw-r--r--src/test/ui/impl-trait/issues/issue-88236.rs19
-rw-r--r--src/test/ui/impl-trait/issues/issue-89312.rs24
-rw-r--r--src/test/ui/impl-trait/issues/issue-93788.rs27
-rw-r--r--src/test/ui/impl-trait/lifetimes2.rs10
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs2
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr9
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs2
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr9
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs2
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr9
-rw-r--r--src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr22
-rw-r--r--src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs3
-rw-r--r--src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr31
-rw-r--r--src/test/ui/impl-trait/negative-reasoning.rs2
-rw-r--r--src/test/ui/impl-trait/negative-reasoning.stderr6
-rw-r--r--src/test/ui/impl-trait/nested-return-type2-tait.rs32
-rw-r--r--src/test/ui/impl-trait/nested-return-type2-tait.stderr32
-rw-r--r--src/test/ui/impl-trait/nested-return-type2-tait2.rs32
-rw-r--r--src/test/ui/impl-trait/nested-return-type2-tait2.stderr15
-rw-r--r--src/test/ui/impl-trait/nested-return-type2-tait3.rs31
-rw-r--r--src/test/ui/impl-trait/nested-return-type2-tait3.stderr15
-rw-r--r--src/test/ui/impl-trait/nested-return-type2.rs30
-rw-r--r--src/test/ui/impl-trait/nested-return-type3-tait.rs24
-rw-r--r--src/test/ui/impl-trait/nested-return-type3-tait2.rs25
-rw-r--r--src/test/ui/impl-trait/nested-return-type3-tait3.rs24
-rw-r--r--src/test/ui/impl-trait/nested-return-type3.rs20
-rw-r--r--src/test/ui/impl-trait/nested_impl_trait.rs2
-rw-r--r--src/test/ui/impl-trait/nested_impl_trait.stderr32
-rw-r--r--src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr35
-rw-r--r--src/test/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr159
-rw-r--r--src/test/ui/impl-trait/projection-mismatch-in-impl-where-clause.stderr2
-rw-r--r--src/test/ui/impl-trait/projection.rs29
-rw-r--r--src/test/ui/impl-trait/question_mark.rs30
-rw-r--r--src/test/ui/impl-trait/recursive-impl-trait-type-direct.rs3
-rw-r--r--src/test/ui/impl-trait/recursive-impl-trait-type-direct.stderr12
-rw-r--r--src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs2
-rw-r--r--src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs17
-rw-r--r--src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr11
-rw-r--r--src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs30
-rw-r--r--src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr25
-rw-r--r--src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration.rs19
-rw-r--r--src/test/ui/impl-trait/region-escape-via-bound.rs2
-rw-r--r--src/test/ui/impl-trait/region-escape-via-bound.stderr9
-rw-r--r--src/test/ui/impl-trait/static-return-lifetime-infered.rs4
-rw-r--r--src/test/ui/impl-trait/static-return-lifetime-infered.stderr32
-rw-r--r--src/test/ui/impl-trait/trait_resolution.rs30
-rw-r--r--src/test/ui/impl-trait/two_tait_defining_each_other.rs19
-rw-r--r--src/test/ui/impl-trait/two_tait_defining_each_other.stderr19
-rw-r--r--src/test/ui/impl-trait/two_tait_defining_each_other2.rs16
-rw-r--r--src/test/ui/impl-trait/two_tait_defining_each_other2.stderr27
-rw-r--r--src/test/ui/impl-trait/two_tait_defining_each_other3.rs19
-rw-r--r--src/test/ui/impl-trait/two_tait_defining_each_other3.stderr19
-rw-r--r--src/test/ui/impl-trait/type_parameters_captured.nll.stderr6
-rw-r--r--src/test/ui/impl-trait/type_parameters_captured.rs1
-rw-r--r--src/test/ui/impl-trait/type_parameters_captured.stderr15
-rw-r--r--src/test/ui/impl-trait/where-allowed-2.rs7
-rw-r--r--src/test/ui/impl-trait/where-allowed-2.stderr13
-rw-r--r--src/test/ui/issues-71798.rs4
-rw-r--r--src/test/ui/issues-71798.stderr18
-rw-r--r--src/test/ui/lazy-type-alias-impl-trait/branches.rs14
-rw-r--r--src/test/ui/lazy-type-alias-impl-trait/branches.stderr16
-rw-r--r--src/test/ui/lazy-type-alias-impl-trait/branches2.rs28
-rw-r--r--src/test/ui/lazy-type-alias-impl-trait/freeze_cycle.rs46
-rw-r--r--src/test/ui/lazy-type-alias-impl-trait/infer_cross_function.rs27
-rw-r--r--src/test/ui/lazy-type-alias-impl-trait/lifetime_inference.rs7
-rw-r--r--src/test/ui/lazy-type-alias-impl-trait/nested.rs23
-rw-r--r--src/test/ui/lazy-type-alias-impl-trait/opaque_vs_opaque.rs10
-rw-r--r--src/test/ui/lazy-type-alias-impl-trait/recursion.rs23
-rw-r--r--src/test/ui/lazy-type-alias-impl-trait/recursion2.rs21
-rw-r--r--src/test/ui/lazy-type-alias-impl-trait/recursion2.stderr16
-rw-r--r--src/test/ui/lazy-type-alias-impl-trait/recursion3.rs21
-rw-r--r--src/test/ui/lazy-type-alias-impl-trait/recursion3.stderr19
-rw-r--r--src/test/ui/lazy-type-alias-impl-trait/recursion4.rs23
-rw-r--r--src/test/ui/lazy-type-alias-impl-trait/recursion4.stderr29
-rw-r--r--src/test/ui/lazy-type-alias-impl-trait/unsized_sized_opaque.rs16
-rw-r--r--src/test/ui/lifetimes/lifetime-elision-return-type-trait.rs3
-rw-r--r--src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr13
-rw-r--r--src/test/ui/lint/inline-trait-and-foreign-items.rs2
-rw-r--r--src/test/ui/lint/inline-trait-and-foreign-items.stderr4
-rw-r--r--src/test/ui/lint/lint-ctypes-73249-2.rs2
-rw-r--r--src/test/ui/lint/lint-ctypes-73249-2.stderr2
-rw-r--r--src/test/ui/lint/lint-ctypes-73249-3.rs2
-rw-r--r--src/test/ui/lint/lint-ctypes-73249-3.stderr2
-rw-r--r--src/test/ui/lint/lint-ctypes-73249-5.rs2
-rw-r--r--src/test/ui/lint/lint-ctypes-73249-5.stderr2
-rw-r--r--src/test/ui/lint/lint-ctypes-73251-1.rs2
-rw-r--r--src/test/ui/lint/lint-ctypes-73251-1.stderr2
-rw-r--r--src/test/ui/lint/lint-ctypes-73251-2.rs2
-rw-r--r--src/test/ui/lint/lint-ctypes-73251-2.stderr2
-rw-r--r--src/test/ui/lint/opaque-ty-ffi-unsafe.rs2
-rw-r--r--src/test/ui/lint/opaque-ty-ffi-unsafe.stderr2
-rw-r--r--src/test/ui/never_type/feature-gate-never_type_fallback.rs7
-rw-r--r--src/test/ui/never_type/feature-gate-never_type_fallback.stderr12
-rw-r--r--src/test/ui/never_type/impl_trait_fallback.rs10
-rw-r--r--src/test/ui/never_type/impl_trait_fallback2.rs21
-rw-r--r--src/test/ui/never_type/impl_trait_fallback2.stderr9
-rw-r--r--src/test/ui/never_type/impl_trait_fallback3.rs15
-rw-r--r--src/test/ui/never_type/impl_trait_fallback3.stderr10
-rw-r--r--src/test/ui/never_type/impl_trait_fallback4.rs24
-rw-r--r--src/test/ui/never_type/impl_trait_fallback4.stderr9
-rw-r--r--src/test/ui/nll/issue-52113.rs4
-rw-r--r--src/test/ui/nll/issue-52113.stderr6
-rw-r--r--src/test/ui/nll/issue-73159-rpit-static.rs2
-rw-r--r--src/test/ui/nll/issue-73159-rpit-static.stderr5
-rw-r--r--src/test/ui/nll/relate_tys/opaque-hrtb.rs16
-rw-r--r--src/test/ui/nll/relate_tys/opaque-hrtb.stderr11
-rw-r--r--src/test/ui/nll/ty-outlives/impl-trait-captures.rs2
-rw-r--r--src/test/ui/nll/ty-outlives/impl-trait-captures.stderr8
-rw-r--r--src/test/ui/nll/ty-outlives/impl-trait-outlives.rs4
-rw-r--r--src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr12
-rw-r--r--src/test/ui/parser/fn-header-semantic-fail.rs9
-rw-r--r--src/test/ui/parser/fn-header-semantic-fail.stderr182
-rw-r--r--src/test/ui/polymorphization/generators.rs2
-rw-r--r--src/test/ui/polymorphization/generators.stderr20
-rw-r--r--src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs2
-rw-r--r--src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr23
-rw-r--r--src/test/ui/save-analysis/issue-68621.rs2
-rw-r--r--src/test/ui/save-analysis/issue-68621.stderr4
-rw-r--r--src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr4
-rw-r--r--src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr4
-rw-r--r--src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs1
-rw-r--r--src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr12
-rw-r--r--src/test/ui/suggestions/issue-81098.rs2
-rw-r--r--src/test/ui/suggestions/issue-81098.stderr31
-rw-r--r--src/test/ui/traits/alias/issue-83613.rs2
-rw-r--r--src/test/ui/traits/alias/issue-83613.stderr4
-rw-r--r--src/test/ui/traits/pointee-tail-is-generic-errors.rs2
-rw-r--r--src/test/ui/traits/pointee-tail-is-generic-errors.stderr6
-rw-r--r--src/test/ui/type-alias-impl-trait/argument-types.rs4
-rw-r--r--src/test/ui/type-alias-impl-trait/argument-types.stderr17
-rw-r--r--src/test/ui/type-alias-impl-trait/auto-trait-leakage2.stderr6
-rw-r--r--src/test/ui/type-alias-impl-trait/auto-trait-leakage3.rs1
-rw-r--r--src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr27
-rw-r--r--src/test/ui/type-alias-impl-trait/bound_reduction2.rs3
-rw-r--r--src/test/ui/type-alias-impl-trait/bound_reduction2.stderr14
-rw-r--r--src/test/ui/type-alias-impl-trait/bounds-are-checked.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr21
-rw-r--r--src/test/ui/type-alias-impl-trait/closures_in_branches.rs31
-rw-r--r--src/test/ui/type-alias-impl-trait/closures_in_branches.stderr11
-rw-r--r--src/test/ui/type-alias-impl-trait/declared_but_never_defined.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/declared_but_never_defined.stderr4
-rw-r--r--src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr8
-rw-r--r--src/test/ui/type-alias-impl-trait/different_defining_uses.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/different_defining_uses.stderr12
-rw-r--r--src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.rs4
-rw-r--r--src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr26
-rw-r--r--src/test/ui/type-alias-impl-trait/different_lifetimes_defining_uses.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/different_lifetimes_defining_uses.stderr12
-rw-r--r--src/test/ui/type-alias-impl-trait/fallback.rs4
-rw-r--r--src/test/ui/type-alias-impl-trait/field-types.rs4
-rw-r--r--src/test/ui/type-alias-impl-trait/field-types.stderr21
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_different_defining_uses.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_different_defining_uses.stderr12
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.rs4
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.stderr14
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs12
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr38
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs5
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr14
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs7
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr26
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.rs5
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr14
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_param_use5.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_param_use5.stderr12
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr12
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_param_use8.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_param_use8.stderr12
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr12
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_nondefining_use.rs12
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr38
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_not_used.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_not_used.stderr10
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr36
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs5
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr29
-rw-r--r--src/test/ui/type-alias-impl-trait/inference-cycle.rs4
-rw-r--r--src/test/ui/type-alias-impl-trait/inference-cycle.stderr36
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr8
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-53598.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-53598.stderr10
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr34
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr6
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-57700.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-57700.stderr10
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-58951-2.rs18
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-60371.rs1
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-60371.stderr13
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-60564.rs3
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-60564.stderr14
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-63279.rs5
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-63279.stderr37
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-63355.rs5
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-63355.stderr19
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr12
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr12
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-74280.stderr9
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-77179.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-93411.rs19
-rw-r--r--src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-infer.rs13
-rw-r--r--src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-infer.stderr11
-rw-r--r--src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.rs9
-rw-r--r--src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.stderr11
-rw-r--r--src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-pass.rs9
-rw-r--r--src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr6
-rw-r--r--src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.stderr15
-rw-r--r--src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr7
-rw-r--r--src/test/ui/type-alias-impl-trait/nested-tait-inference.rs5
-rw-r--r--src/test/ui/type-alias-impl-trait/nested-tait-inference.stderr27
-rw-r--r--src/test/ui/type-alias-impl-trait/nested-tait-inference2.rs4
-rw-r--r--src/test/ui/type-alias-impl-trait/nested-tait-inference2.stderr23
-rw-r--r--src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs17
-rw-r--r--src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr10
-rw-r--r--src/test/ui/type-alias-impl-trait/nested.rs17
-rw-r--r--src/test/ui/type-alias-impl-trait/nested.stderr12
-rw-r--r--src/test/ui/type-alias-impl-trait/nested_type_alias_impl_trait.rs4
-rw-r--r--src/test/ui/type-alias-impl-trait/nested_type_alias_impl_trait.stderr19
-rw-r--r--src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.rs7
-rw-r--r--src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr24
-rw-r--r--src/test/ui/type-alias-impl-trait/no_inferrable_concrete_type.rs4
-rw-r--r--src/test/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr4
-rw-r--r--src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr6
-rw-r--r--src/test/ui/type-alias-impl-trait/not_a_defining_use.rs7
-rw-r--r--src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr26
-rw-r--r--src/test/ui/type-alias-impl-trait/reveal_local.rs26
-rw-r--r--src/test/ui/type-alias-impl-trait/reveal_local.stderr51
-rw-r--r--src/test/ui/type-alias-impl-trait/self-referential-2.rs10
-rw-r--r--src/test/ui/type-alias-impl-trait/self-referential-2.stderr11
-rw-r--r--src/test/ui/type-alias-impl-trait/self-referential-3.rs14
-rw-r--r--src/test/ui/type-alias-impl-trait/self-referential-4.rs25
-rw-r--r--src/test/ui/type-alias-impl-trait/self-referential-4.stderr27
-rw-r--r--src/test/ui/type-alias-impl-trait/self-referential.rs25
-rw-r--r--src/test/ui/type-alias-impl-trait/self-referential.stderr27
-rw-r--r--src/test/ui/type-alias-impl-trait/static-const-types.rs8
-rw-r--r--src/test/ui/type-alias-impl-trait/static-const-types.stderr33
-rw-r--r--src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs4
-rw-r--r--src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/structural-match.rs4
-rw-r--r--src/test/ui/type-alias-impl-trait/structural-match.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs4
-rw-r--r--src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.stderr21
-rw-r--r--src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.stderr4
-rw-r--r--src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.stderr4
-rw-r--r--src/test/ui/type-alias-impl-trait/type-alias-impl-trait.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/type-alias-impl-trait2.rs84
-rw-r--r--src/test/ui/type-alias-impl-trait/type_of_a_let.rs11
-rw-r--r--src/test/ui/type-alias-impl-trait/type_of_a_let.stderr76
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
419 files changed, 5204 insertions, 2486 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index 7507ea76ed0..8601fbe27f3 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -2,9 +2,13 @@ use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
 use rustc_infer::infer::canonical::Canonical;
 use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError;
 use rustc_infer::infer::region_constraints::Constraint;
+use rustc_infer::infer::region_constraints::RegionConstraintData;
+use rustc_infer::infer::RegionVariableOrigin;
 use rustc_infer::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _};
 use rustc_infer::traits::{Normalized, ObligationCause, TraitEngine, TraitEngineExt};
 use rustc_middle::ty::error::TypeError;
+use rustc_middle::ty::RegionVid;
+use rustc_middle::ty::UniverseIndex;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc_span::Span;
 use rustc_trait_selection::traits::query::type_op;
@@ -76,6 +80,15 @@ crate trait ToUniverseInfo<'tcx> {
     fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>;
 }
 
+impl<'tcx> ToUniverseInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
+    fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
+        UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(crate::type_check::InstantiateOpaqueType {
+            base_universe: Some(base_universe),
+            ..self
+        })))
+    }
+}
+
 impl<'tcx> ToUniverseInfo<'tcx>
     for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>
 {
@@ -116,6 +129,12 @@ impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::Custo
     }
 }
 
+impl<'tcx> ToUniverseInfo<'tcx> for ! {
+    fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
+        self
+    }
+}
+
 #[allow(unused_lifetimes)]
 trait TypeOpInfo<'tcx> {
     /// Returns an error to be reported if rerunning the type op fails to
@@ -130,7 +149,7 @@ trait TypeOpInfo<'tcx> {
 
     fn nice_error(
         &self,
-        tcx: TyCtxt<'tcx>,
+        mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
         cause: ObligationCause<'tcx>,
         placeholder_region: ty::Region<'tcx>,
         error_region: Option<ty::Region<'tcx>>,
@@ -175,7 +194,7 @@ trait TypeOpInfo<'tcx> {
         debug!(?placeholder_region);
 
         let span = cause.span;
-        let nice_error = self.nice_error(tcx, cause, placeholder_region, error_region);
+        let nice_error = self.nice_error(mbcx, cause, placeholder_region, error_region);
 
         if let Some(nice_error) = nice_error {
             mbcx.buffer_error(nice_error);
@@ -208,16 +227,16 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
 
     fn nice_error(
         &self,
-        tcx: TyCtxt<'tcx>,
+        mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
         cause: ObligationCause<'tcx>,
         placeholder_region: ty::Region<'tcx>,
         error_region: Option<ty::Region<'tcx>>,
     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
-        tcx.infer_ctxt().enter_with_canonical(
+        mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
             cause.span,
             &self.canonical_query,
             |ref infcx, key, _| {
-                let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
+                let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
                 type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause);
                 try_extract_error_from_fulfill_cx(
                     fulfill_cx,
@@ -255,16 +274,16 @@ where
 
     fn nice_error(
         &self,
-        tcx: TyCtxt<'tcx>,
+        mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
         cause: ObligationCause<'tcx>,
         placeholder_region: ty::Region<'tcx>,
         error_region: Option<ty::Region<'tcx>>,
     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
-        tcx.infer_ctxt().enter_with_canonical(
+        mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
             cause.span,
             &self.canonical_query,
             |ref infcx, key, _| {
-                let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
+                let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
 
                 let mut selcx = SelectionContext::new(infcx);
 
@@ -316,16 +335,16 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
 
     fn nice_error(
         &self,
-        tcx: TyCtxt<'tcx>,
+        mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
         cause: ObligationCause<'tcx>,
         placeholder_region: ty::Region<'tcx>,
         error_region: Option<ty::Region<'tcx>>,
     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
-        tcx.infer_ctxt().enter_with_canonical(
+        mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
             cause.span,
             &self.canonical_query,
             |ref infcx, key, _| {
-                let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
+                let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
                 type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span))
                     .ok()?;
                 try_extract_error_from_fulfill_cx(
@@ -339,6 +358,43 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
     }
 }
 
+impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
+    fn fallback_error(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        span: Span,
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+        // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
+        // and is only the fallback when the nice error fails. Consider improving this some more.
+        tcx.sess.struct_span_err(span, "higher-ranked lifetime error for opaque type!")
+    }
+
+    fn base_universe(&self) -> ty::UniverseIndex {
+        self.base_universe.unwrap()
+    }
+
+    fn nice_error(
+        &self,
+        mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
+        _cause: ObligationCause<'tcx>,
+        placeholder_region: ty::Region<'tcx>,
+        error_region: Option<ty::Region<'tcx>>,
+    ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
+        try_extract_error_from_region_constraints(
+            mbcx.infcx,
+            placeholder_region,
+            error_region,
+            self.region_constraints.as_ref().unwrap(),
+            // We're using the original `InferCtxt` that we
+            // started MIR borrowchecking with, so the region
+            // constraints have already been taken. Use the data from
+            // our `mbcx` instead.
+            |vid| mbcx.regioncx.var_infos[vid].origin,
+            |vid| mbcx.regioncx.var_infos[vid].universe,
+        )
+    }
+}
+
 #[instrument(skip(fulfill_cx, infcx), level = "debug")]
 fn try_extract_error_from_fulfill_cx<'tcx>(
     mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
@@ -346,15 +402,30 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
     placeholder_region: ty::Region<'tcx>,
     error_region: Option<ty::Region<'tcx>>,
 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
-    let tcx = infcx.tcx;
-
     // We generally shouldn't have errors here because the query was
     // already run, but there's no point using `delay_span_bug`
     // when we're going to emit an error here anyway.
     let _errors = fulfill_cx.select_all_or_error(infcx);
+    let region_constraints = infcx.with_region_constraints(|r| r.clone());
+    try_extract_error_from_region_constraints(
+        infcx,
+        placeholder_region,
+        error_region,
+        &region_constraints,
+        |vid| infcx.region_var_origin(vid),
+        |vid| infcx.universe_of_region(infcx.tcx.mk_region(ty::ReVar(vid))),
+    )
+}
 
-    let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| {
-        debug!("{:#?}", region_constraints);
+fn try_extract_error_from_region_constraints<'tcx>(
+    infcx: &InferCtxt<'_, 'tcx>,
+    placeholder_region: ty::Region<'tcx>,
+    error_region: Option<ty::Region<'tcx>>,
+    region_constraints: &RegionConstraintData<'tcx>,
+    mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin,
+    mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex,
+) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
+    let (sub_region, cause) =
         region_constraints.constraints.iter().find_map(|(constraint, cause)| {
             match *constraint {
                 Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => {
@@ -362,12 +433,11 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
                 }
                 // FIXME: Should this check the universe of the var?
                 Constraint::VarSubReg(vid, sup) if sup == placeholder_region => {
-                    Some((tcx.mk_region(ty::ReVar(vid)), cause.clone()))
+                    Some((infcx.tcx.mk_region(ty::ReVar(vid)), cause.clone()))
                 }
                 _ => None,
             }
-        })
-    })?;
+        })?;
 
     debug!(?sub_region, "cause = {:#?}", cause);
     let nice_error = match (error_region, *sub_region) {
@@ -375,7 +445,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
             infcx,
             RegionResolutionError::SubSupConflict(
                 vid,
-                infcx.region_var_origin(vid),
+                region_var_origin(vid),
                 cause.clone(),
                 error_region,
                 cause.clone(),
@@ -392,8 +462,8 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
             infcx,
             RegionResolutionError::UpperBoundUniverseConflict(
                 vid,
-                infcx.region_var_origin(vid),
-                infcx.universe_of_region(sub_region),
+                region_var_origin(vid),
+                universe_of_region(vid),
                 cause.clone(),
                 placeholder_region,
             ),
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 6f78c816093..58b246ec873 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -7,6 +7,7 @@
 #![feature(let_chains)]
 #![feature(let_else)]
 #![feature(min_specialization)]
+#![feature(never_type)]
 #![feature(stmt_expr_attributes)]
 #![feature(trusted_step)]
 #![feature(try_blocks)]
@@ -125,8 +126,9 @@ fn mir_borrowck<'tcx>(
 ) -> &'tcx BorrowCheckResult<'tcx> {
     let (input_body, promoted) = tcx.mir_promoted(def);
     debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
+    let hir_owner = tcx.hir().local_def_id_to_hir_id(def.did).owner;
 
-    let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(def.did).enter(|infcx| {
+    let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(hir_owner).enter(|infcx| {
         let input_body: &Body<'_> = &input_body.borrow();
         let promoted: &IndexVec<_, _> = &promoted.borrow();
         do_mir_borrowck(&infcx, input_body, promoted, false).0
@@ -141,7 +143,7 @@ fn mir_borrowck<'tcx>(
 /// If `return_body_with_facts` is true, then return the body with non-erased
 /// region ids on which the borrow checking was performed together with Polonius
 /// facts.
-#[instrument(skip(infcx, input_body, input_promoted), level = "debug")]
+#[instrument(skip(infcx, input_body, input_promoted), fields(id=?input_body.source.with_opt_param().as_local().unwrap()), level = "debug")]
 fn do_mir_borrowck<'a, 'tcx>(
     infcx: &InferCtxt<'a, 'tcx>,
     input_body: &Body<'tcx>,
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 03b4a6ea983..9242c6aeb8b 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -8,7 +8,7 @@ use rustc_middle::mir::{
     BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location,
     Promoted,
 };
-use rustc_middle::ty::{self, OpaqueTypeKey, Region, RegionVid, Ty};
+use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Region, RegionVid};
 use rustc_span::symbol::sym;
 use std::env;
 use std::fmt::Debug;
@@ -43,7 +43,7 @@ pub type PoloniusOutput = Output<RustcFacts>;
 /// closure requirements to propagate, and any generated errors.
 crate struct NllOutput<'tcx> {
     pub regioncx: RegionInferenceContext<'tcx>,
-    pub opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
+    pub opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
     pub polonius_input: Option<Box<AllFacts>>,
     pub polonius_output: Option<Rc<PoloniusOutput>>,
     pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
@@ -305,7 +305,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
         infcx.set_tainted_by_errors();
     }
 
-    let remapped_opaque_tys = regioncx.infer_opaque_types(&infcx, opaque_type_values, body.span);
+    let remapped_opaque_tys = regioncx.infer_opaque_types(&infcx, opaque_type_values);
 
     NllOutput {
         regioncx,
@@ -372,7 +372,7 @@ pub(super) fn dump_annotation<'a, 'tcx>(
     body: &Body<'tcx>,
     regioncx: &RegionInferenceContext<'tcx>,
     closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
-    opaque_type_values: &VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
+    opaque_type_values: &VecMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
     errors: &mut crate::error::BorrowckErrors<'tcx>,
 ) {
     let tcx = infcx.tcx;
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 20f54d04777..1f81f7dda13 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -45,6 +45,7 @@ mod reverse_sccs;
 pub mod values;
 
 pub struct RegionInferenceContext<'tcx> {
+    pub var_infos: VarInfos,
     /// Contains the definition for every region variable. Region
     /// variables are identified by their index (`RegionVid`). The
     /// definition contains information about where the region came
@@ -267,7 +268,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     ) -> Self {
         // Create a RegionDefinition for each inference variable.
         let definitions: IndexVec<_, _> = var_infos
-            .into_iter()
+            .iter()
             .map(|info| RegionDefinition::new(info.universe, info.origin))
             .collect();
 
@@ -292,6 +293,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             Rc::new(member_constraints_in.into_mapped(|r| constraint_sccs.scc(r)));
 
         let mut result = Self {
+            var_infos,
             definitions,
             liveness_constraints,
             constraints,
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 60c48d8a764..f454141dc52 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -1,10 +1,9 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::vec_map::VecMap;
 use rustc_hir::OpaqueTyOrigin;
-use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, TyCtxt, TypeFoldable};
 use rustc_span::Span;
 use rustc_trait_selection::opaque_types::InferCtxtExt;
 
@@ -54,27 +53,41 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     pub(crate) fn infer_opaque_types(
         &self,
         infcx: &InferCtxt<'_, 'tcx>,
-        opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>,
-        span: Span,
-    ) -> VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>> {
+        opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
+    ) -> VecMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>> {
         opaque_ty_decls
             .into_iter()
-            .filter_map(|(opaque_type_key, decl)| {
+            .map(|(opaque_type_key, (concrete_type, origin))| {
                 let substs = opaque_type_key.substs;
-                let concrete_type = decl.concrete_ty;
                 debug!(?concrete_type, ?substs);
 
                 let mut subst_regions = vec![self.universal_regions.fr_static];
                 let universal_substs = infcx.tcx.fold_regions(substs, &mut false, |region, _| {
-                    let vid = self.universal_regions.to_region_vid(region);
-                    subst_regions.push(vid);
-                    self.definitions[vid].external_name.unwrap_or_else(|| {
-                        infcx
-                            .tcx
-                            .sess
-                            .delay_span_bug(span, "opaque type with non-universal region substs");
-                        infcx.tcx.lifetimes.re_static
-                    })
+                    if let ty::RePlaceholder(..) = region.kind() {
+                        // Higher kinded regions don't need remapping, they don't refer to anything outside of this the substs.
+                        return region;
+                    }
+                    let vid = self.to_region_vid(region);
+                    trace!(?vid);
+                    let scc = self.constraint_sccs.scc(vid);
+                    trace!(?scc);
+                    match self.scc_values.universal_regions_outlived_by(scc).find_map(|lb| {
+                        self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?)
+                    }) {
+                        Some(region) => {
+                            let vid = self.universal_regions.to_region_vid(region);
+                            subst_regions.push(vid);
+                            region
+                        }
+                        None => {
+                            subst_regions.push(vid);
+                            infcx.tcx.sess.delay_span_bug(
+                                concrete_type.span,
+                                "opaque type with non-universal region substs",
+                            );
+                            infcx.tcx.lifetimes.re_static
+                        }
+                    }
                 });
 
                 subst_regions.sort();
@@ -97,15 +110,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 let remapped_type = infcx.infer_opaque_definition_from_instantiation(
                     opaque_type_key,
                     universal_concrete_type,
-                    span,
                 );
-
-                check_opaque_type_parameter_valid(
+                let ty = if check_opaque_type_parameter_valid(
                     infcx.tcx,
                     opaque_type_key,
-                    OpaqueTypeDecl { concrete_ty: remapped_type, ..decl },
-                )
-                .then_some((opaque_type_key, remapped_type))
+                    origin,
+                    concrete_type.span,
+                ) {
+                    remapped_type
+                } else {
+                    infcx.tcx.ty_error()
+                };
+                (opaque_type_key, OpaqueHiddenType { ty, span: concrete_type.span })
             })
             .collect()
     }
@@ -149,9 +165,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 fn check_opaque_type_parameter_valid(
     tcx: TyCtxt<'_>,
     opaque_type_key: OpaqueTypeKey<'_>,
-    decl: OpaqueTypeDecl<'_>,
+    origin: OpaqueTyOrigin,
+    span: Span,
 ) -> bool {
-    match decl.origin {
+    match origin {
         // No need to check return position impl trait (RPIT)
         // because for type and const parameters they are correct
         // by construction: we convert
@@ -177,7 +194,6 @@ fn check_opaque_type_parameter_valid(
         // Check these
         OpaqueTyOrigin::TyAlias => {}
     }
-    let span = decl.definition_span;
     let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
     let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
     for (i, arg) in opaque_type_key.substs.iter().enumerate() {
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index 0fa72ed8241..3856b7f4a4b 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -33,12 +33,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     ) -> Fallible<R>
     where
         Op: type_op::TypeOp<'tcx, Output = R>,
-        Canonical<'tcx, Op>: ToUniverseInfo<'tcx>,
+        Op::ErrorInfo: ToUniverseInfo<'tcx>,
     {
         let old_universe = self.infcx.universe();
 
-        let TypeOpOutput { output, constraints, canonicalized_query } =
-            op.fully_perform(self.infcx)?;
+        let TypeOpOutput { output, constraints, error_info } = op.fully_perform(self.infcx)?;
 
         if let Some(data) = &constraints {
             self.push_region_constraints(locations, category, data);
@@ -47,8 +46,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         let universe = self.infcx.universe();
 
         if old_universe != universe {
-            let universe_info = match canonicalized_query {
-                Some(canonicalized_query) => canonicalized_query.to_universe_info(old_universe),
+            let universe_info = match error_info {
+                Some(error_info) => error_info.to_universe_info(old_universe),
                 None => UniverseInfo::other(),
             };
             for u in old_universe..universe {
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index 2e7798beb64..0b9d0a0e922 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -267,7 +267,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
                         TypeOpOutput {
                             output: self.infcx.tcx.ty_error(),
                             constraints: None,
-                            canonicalized_query: None,
+                            error_info: None,
                         }
                     });
                 // Note: we need this in examples like
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index bc740de5150..83c8ecba1f1 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -147,9 +147,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         // Return types are a bit more complex. They may contain opaque `impl Trait` types.
         let mir_output_ty = body.local_decls[RETURN_PLACE].ty;
         let output_span = body.local_decls[RETURN_PLACE].source_info.span;
-        if let Err(terr) = self.eq_opaque_type_and_type(
-            mir_output_ty,
+        if let Err(terr) = self.eq_types(
             normalized_output_ty,
+            mir_output_ty,
             Locations::All(output_span),
             ConstraintCategory::BoringNoLocation,
         ) {
@@ -169,9 +169,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             let user_provided_output_ty = user_provided_sig.output();
             let user_provided_output_ty =
                 self.normalize(user_provided_output_ty, Locations::All(output_span));
-            if let Err(err) = self.eq_opaque_type_and_type(
-                mir_output_ty,
+            if let Err(err) = self.eq_types(
                 user_provided_output_ty,
+                mir_output_ty,
                 Locations::All(output_span),
                 ConstraintCategory::BoringNoLocation,
             ) {
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index a7cf25d43d2..9d7dcc5379c 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -5,6 +5,7 @@ use std::{fmt, iter, mem};
 
 use either::Either;
 
+use hir::OpaqueTyOrigin;
 use rustc_data_structures::frozen::Frozen;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::vec_map::VecMap;
@@ -15,8 +16,8 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_infer::infer::canonical::QueryRegionConstraints;
-use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
 use rustc_infer::infer::outlives::env::RegionBoundPairs;
+use rustc_infer::infer::region_constraints::RegionConstraintData;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{
     InferCtxt, InferOk, LateBoundRegionConversionTime, NllRegionVariableOrigin,
@@ -30,8 +31,8 @@ use rustc_middle::ty::cast::CastTy;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts};
 use rustc_middle::ty::{
-    self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid,
-    ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
+    self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueHiddenType,
+    OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
 };
 use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::{Span, DUMMY_SP};
@@ -39,9 +40,11 @@ use rustc_target::abi::VariantIdx;
 use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::type_op;
+use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
 use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
+use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
 use rustc_trait_selection::traits::query::Fallible;
-use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations};
+use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation};
 
 use rustc_const_eval::transform::{
     check_consts::ConstCx, promote_consts::is_const_fn_in_array_repeat_expression,
@@ -75,7 +78,7 @@ macro_rules! span_mirbug {
             $context.last_span,
             &format!(
                 "broken MIR in {:?} ({:?}): {}",
-                $context.body.source.def_id(),
+                $context.body().source.def_id(),
                 $elem,
                 format_args!($($message)*),
             ),
@@ -199,59 +202,44 @@ pub(crate) fn type_check<'mir, 'tcx>(
             );
 
             translate_outlives_facts(&mut cx);
-            let opaque_type_values = mem::take(&mut infcx.inner.borrow_mut().opaque_types);
+            let opaque_type_values =
+                infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
 
             opaque_type_values
                 .into_iter()
-                .filter_map(|(opaque_type_key, mut decl)| {
-                    decl.concrete_ty = infcx.resolve_vars_if_possible(decl.concrete_ty);
+                .map(|(opaque_type_key, decl)| {
+                    cx.fully_perform_op(
+                        Locations::All(body.span),
+                        ConstraintCategory::OpaqueType,
+                        CustomTypeOp::new(
+                            |infcx| {
+                                infcx.register_member_constraints(
+                                    param_env,
+                                    opaque_type_key,
+                                    decl.hidden_type.ty,
+                                    decl.hidden_type.span,
+                                );
+                                Ok(InferOk { value: (), obligations: vec![] })
+                            },
+                            || "opaque_type_map".to_string(),
+                        ),
+                    )
+                    .unwrap();
+                    let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
                     trace!(
                         "finalized opaque type {:?} to {:#?}",
                         opaque_type_key,
-                        decl.concrete_ty.kind()
+                        hidden_type.ty.kind()
                     );
-                    if decl.concrete_ty.has_infer_types_or_consts() {
+                    if hidden_type.has_infer_types_or_consts() {
                         infcx.tcx.sess.delay_span_bug(
-                            body.span,
-                            &format!("could not resolve {:#?}", decl.concrete_ty.kind()),
+                            decl.hidden_type.span,
+                            &format!("could not resolve {:#?}", hidden_type.ty.kind()),
                         );
-                        decl.concrete_ty = infcx.tcx.ty_error();
+                        hidden_type.ty = infcx.tcx.ty_error();
                     }
-                    let concrete_is_opaque = if let ty::Opaque(def_id, _) = decl.concrete_ty.kind()
-                    {
-                        *def_id == opaque_type_key.def_id
-                    } else {
-                        false
-                    };
 
-                    if concrete_is_opaque {
-                        // We're using an opaque `impl Trait` type without
-                        // 'revealing' it. For example, code like this:
-                        //
-                        // type Foo = impl Debug;
-                        // fn foo1() -> Foo { ... }
-                        // fn foo2() -> Foo { foo1() }
-                        //
-                        // In `foo2`, we're not revealing the type of `Foo` - we're
-                        // just treating it as the opaque type.
-                        //
-                        // When this occurs, we do *not* want to try to equate
-                        // the concrete type with the underlying defining type
-                        // of the opaque type - this will always fail, since
-                        // the defining type of an opaque type is always
-                        // some other type (e.g. not itself)
-                        // Essentially, none of the normal obligations apply here -
-                        // we're just passing around some unknown opaque type,
-                        // without actually looking at the underlying type it
-                        // gets 'revealed' into
-                        debug!(
-                            "eq_opaque_type_and_type: non-defining use of {:?}",
-                            opaque_type_key.def_id,
-                        );
-                        None
-                    } else {
-                        Some((opaque_type_key, decl))
-                    }
+                    (opaque_type_key, (hidden_type, decl.origin))
                 })
                 .collect()
         },
@@ -283,7 +271,7 @@ fn type_check_internal<'a, 'tcx, R>(
         borrowck_context,
     );
     let errors_reported = {
-        let mut verifier = TypeVerifier::new(&mut checker, body, promoted);
+        let mut verifier = TypeVerifier::new(&mut checker, promoted);
         verifier.visit_body(&body);
         verifier.errors_reported
     };
@@ -340,7 +328,6 @@ enum FieldAccessError {
 /// is a problem.
 struct TypeVerifier<'a, 'b, 'tcx> {
     cx: &'a mut TypeChecker<'b, 'tcx>,
-    body: &'b Body<'tcx>,
     promoted: &'b IndexVec<Promoted, Body<'tcx>>,
     last_span: Span,
     errors_reported: bool,
@@ -476,7 +463,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
 
     fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
         self.super_rvalue(rvalue, location);
-        let rval_ty = rvalue.ty(self.body, self.tcx());
+        let rval_ty = rvalue.ty(self.body(), self.tcx());
         self.sanitize_type(rvalue, rval_ty);
     }
 
@@ -535,10 +522,13 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
 impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
     fn new(
         cx: &'a mut TypeChecker<'b, 'tcx>,
-        body: &'b Body<'tcx>,
         promoted: &'b IndexVec<Promoted, Body<'tcx>>,
     ) -> Self {
-        TypeVerifier { body, promoted, cx, last_span: body.span, errors_reported: false }
+        TypeVerifier { promoted, last_span: cx.body.span, cx, errors_reported: false }
+    }
+
+    fn body(&self) -> &Body<'tcx> {
+        self.cx.body
     }
 
     fn tcx(&self) -> TyCtxt<'tcx> {
@@ -563,7 +553,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
     ) -> PlaceTy<'tcx> {
         debug!("sanitize_place: {:?}", place);
 
-        let mut place_ty = PlaceTy::from_ty(self.body.local_decls[place.local].ty);
+        let mut place_ty = PlaceTy::from_ty(self.body().local_decls[place.local].ty);
 
         for elem in place.projection.iter() {
             if place_ty.variant_index.is_none() {
@@ -608,7 +598,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
         // checker on the promoted MIR, then transfer the constraints back to
         // the main MIR, changing the locations to the provided location.
 
-        let parent_body = mem::replace(&mut self.body, promoted_body);
+        let parent_body = mem::replace(&mut self.cx.body, promoted_body);
 
         // Use new sets of constraints and closure bounds so that we can
         // modify their locations.
@@ -644,7 +634,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
             self.cx.typeck_mir(promoted_body);
         }
 
-        self.body = parent_body;
+        self.cx.body = parent_body;
         // Merge the outlives constraints back in, at the given location.
         swap_constraints(self);
 
@@ -706,7 +696,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
                 }))
             }
             ProjectionElem::Index(i) => {
-                let index_ty = Place::from(i).ty(self.body, tcx).ty;
+                let index_ty = Place::from(i).ty(self.body(), tcx).ty;
                 if index_ty != tcx.types.usize {
                     PlaceTy::from_ty(span_mirbug_and_err!(self, i, "index by non-usize {:?}", i))
                 } else {
@@ -915,7 +905,7 @@ struct BorrowCheckContext<'a, 'tcx> {
 crate struct MirTypeckResults<'tcx> {
     crate constraints: MirTypeckRegionConstraints<'tcx>,
     crate universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
-    crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>,
+    crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
 }
 
 /// A collection of region constraints that must be satisfied for the
@@ -1065,17 +1055,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         checker
     }
 
+    fn body(&self) -> &Body<'tcx> {
+        self.body
+    }
+
     fn unsized_feature_enabled(&self) -> bool {
         let features = self.tcx().features();
         features.unsized_locals || features.unsized_fn_params
     }
 
     /// Equate the inferred type and the annotated type for user type annotations
+    #[instrument(skip(self), level = "debug")]
     fn check_user_type_annotations(&mut self) {
-        debug!(
-            "check_user_type_annotations: user_type_annotations={:?}",
-            self.user_type_annotations
-        );
+        debug!(?self.user_type_annotations);
         for user_annotation in self.user_type_annotations {
             let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
             let inferred_ty = self.normalize(inferred_ty, Locations::All(span));
@@ -1216,131 +1208,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         Ok(())
     }
 
-    /// Equates a type `anon_ty` that may contain opaque types whose
-    /// values are to be inferred by the MIR.
-    ///
-    /// The type `revealed_ty` contains the same type as `anon_ty`, but with the
-    /// hidden types for impl traits revealed.
-    ///
-    /// # Example
-    ///
-    /// Consider a piece of code like
-    ///
-    /// ```rust
-    /// type Foo<U> = impl Debug;
-    ///
-    /// fn foo<T: Debug>(t: T) -> Box<Foo<T>> {
-    ///      Box::new((t, 22_u32))
-    /// }
-    /// ```
-    ///
-    /// Here, the function signature would be something like
-    /// `fn(T) -> Box<impl Debug>`. The MIR return slot would have
-    /// the type with the opaque type revealed, so `Box<(T, u32)>`.
-    ///
-    /// In terms of our function parameters:
-    ///
-    /// * `anon_ty` would be `Box<Foo<T>>` where `Foo<T>` is an opaque type
-    ///   scoped to this function (note that it is parameterized by the
-    ///   generics of `foo`). Note that `anon_ty` is not just the opaque type,
-    ///   but the entire return type (which may contain opaque types within it).
-    /// * `revealed_ty` would be `Box<(T, u32)>`
-    #[instrument(skip(self), level = "debug")]
-    fn eq_opaque_type_and_type(
-        &mut self,
-        revealed_ty: Ty<'tcx>,
-        anon_ty: Ty<'tcx>,
-        locations: Locations,
-        category: ConstraintCategory,
-    ) -> Fallible<()> {
-        // Fast path for the common case.
-        if !anon_ty.has_opaque_types() {
-            if let Err(terr) = self.eq_types(anon_ty, revealed_ty, locations, category) {
-                span_mirbug!(
-                    self,
-                    locations,
-                    "eq_opaque_type_and_type: `{:?}=={:?}` failed with `{:?}`",
-                    revealed_ty,
-                    anon_ty,
-                    terr
-                );
-            }
-            return Ok(());
-        }
-
-        let param_env = self.param_env;
-        let body = self.body;
-        let mir_def_id = body.source.def_id().expect_local();
-
-        debug!(?mir_def_id);
-        self.fully_perform_op(
-            locations,
-            category,
-            CustomTypeOp::new(
-                |infcx| {
-                    let mut obligations = ObligationAccumulator::default();
-
-                    let dummy_body_id = hir::CRATE_HIR_ID;
-
-                    // Replace the opaque types defined by this function with
-                    // inference variables, creating a map. In our example above,
-                    // this would transform the type `Box<Foo<T>>` (where `Foo` is an opaque type)
-                    // to `Box<?T>`, returning an `opaque_type_map` mapping `{Foo<T> -> ?T}`.
-                    // (Note that the key of the map is both the def-id of `Foo` along with
-                    // any generic parameters.)
-                    let output_ty = obligations.add(infcx.instantiate_opaque_types(
-                        dummy_body_id,
-                        param_env,
-                        anon_ty,
-                        locations.span(body),
-                    ));
-                    debug!(?output_ty, ?revealed_ty);
-
-                    // Make sure that the inferred types are well-formed. I'm
-                    // not entirely sure this is needed (the HIR type check
-                    // didn't do this) but it seems sensible to prevent opaque
-                    // types hiding ill-formed types.
-                    obligations.obligations.push(traits::Obligation::new(
-                        ObligationCause::dummy(),
-                        param_env,
-                        ty::Binder::dummy(ty::PredicateKind::WellFormed(revealed_ty.into()))
-                            .to_predicate(infcx.tcx),
-                    ));
-                    obligations.add(
-                        infcx
-                            .at(&ObligationCause::dummy(), param_env)
-                            .eq(output_ty, revealed_ty)?,
-                    );
-
-                    debug!("equated");
-
-                    Ok(InferOk { value: (), obligations: obligations.into_vec() })
-                },
-                || "input_output".to_string(),
-            ),
-        )?;
-
-        // Finally, if we instantiated the anon types successfully, we
-        // have to solve any bounds (e.g., `-> impl Iterator` needs to
-        // prove that `T: Iterator` where `T` is the type we
-        // instantiated it with).
-        let opaque_type_map = self.infcx.inner.borrow().opaque_types.clone();
-        for (opaque_type_key, opaque_decl) in opaque_type_map {
-            self.fully_perform_op(
-                locations,
-                ConstraintCategory::OpaqueType,
-                CustomTypeOp::new(
-                    |infcx| {
-                        infcx.constrain_opaque_type(opaque_type_key, &opaque_decl);
-                        Ok(InferOk { value: (), obligations: vec![] })
-                    },
-                    || "opaque_type_map".to_string(),
-                ),
-            )?;
-        }
-        Ok(())
-    }
-
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
@@ -2772,19 +2639,31 @@ impl NormalizeLocation for Location {
     }
 }
 
-#[derive(Debug, Default)]
-struct ObligationAccumulator<'tcx> {
-    obligations: PredicateObligations<'tcx>,
+/// Runs `infcx.instantiate_opaque_types`. Unlike other `TypeOp`s,
+/// this is not canonicalized - it directly affects the main `InferCtxt`
+/// that we use during MIR borrowchecking.
+#[derive(Debug)]
+pub(super) struct InstantiateOpaqueType<'tcx> {
+    pub base_universe: Option<ty::UniverseIndex>,
+    pub region_constraints: Option<RegionConstraintData<'tcx>>,
+    pub obligations: Vec<PredicateObligation<'tcx>>,
 }
 
-impl<'tcx> ObligationAccumulator<'tcx> {
-    fn add<T>(&mut self, value: InferOk<'tcx, T>) -> T {
-        let InferOk { value, obligations } = value;
-        self.obligations.extend(obligations);
-        value
-    }
-
-    fn into_vec(self) -> PredicateObligations<'tcx> {
-        self.obligations
+impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> {
+    type Output = ();
+    /// We use this type itself to store the information used
+    /// when reporting errors. Since this is not a query, we don't
+    /// re-run anything during error reporting - we just use the information
+    /// we saved to help extract an error from the already-existing region
+    /// constraints in our `InferCtxt`
+    type ErrorInfo = InstantiateOpaqueType<'tcx>;
+
+    fn fully_perform(mut self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
+        let (mut output, region_constraints) = scrape_region_constraints(infcx, || {
+            Ok(InferOk { value: (), obligations: self.obligations.clone() })
+        })?;
+        self.region_constraints = Some(region_constraints);
+        output.error_info = Some(self);
+        Ok(output)
     }
 }
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index 590a7a91641..8a757636087 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -1,13 +1,16 @@
 use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
 use rustc_infer::infer::NllRegionVariableOrigin;
+use rustc_infer::traits::ObligationCause;
 use rustc_middle::mir::ConstraintCategory;
+use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::{self, Const, Ty};
+use rustc_span::Span;
 use rustc_trait_selection::traits::query::Fallible;
 
 use crate::constraints::OutlivesConstraint;
 use crate::diagnostics::UniverseInfo;
-use crate::type_check::{Locations, TypeChecker};
+use crate::type_check::{InstantiateOpaqueType, Locations, TypeChecker};
 
 impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     /// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`:
@@ -63,6 +66,10 @@ impl<'me, 'bccx, 'tcx> NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
 }
 
 impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
+    fn span(&self) -> Span {
+        self.locations.span(self.type_checker.body)
+    }
+
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
         self.type_checker.param_env
     }
@@ -117,6 +124,9 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
 
     // We don't have to worry about the equality of consts during borrow checking
     // as consts always have a static lifetime.
+    // FIXME(oli-obk): is this really true? We can at least have HKL and with
+    // inline consts we may have further lifetimes that may be unsound to treat as
+    // 'static.
     fn const_equate(&mut self, _a: Const<'tcx>, _b: Const<'tcx>) {}
 
     fn normalization() -> NormalizationStrategy {
@@ -126,4 +136,34 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
     fn forbid_inference_vars() -> bool {
         true
     }
+
+    fn register_opaque_type(
+        &mut self,
+        a: Ty<'tcx>,
+        b: Ty<'tcx>,
+        a_is_expected: bool,
+    ) -> Result<(), TypeError<'tcx>> {
+        let param_env = self.param_env();
+        let span = self.span();
+        let def_id = self.type_checker.body.source.def_id().expect_local();
+        let body_id = self.type_checker.tcx().hir().local_def_id_to_hir_id(def_id);
+        let cause = ObligationCause::misc(span, body_id);
+        self.type_checker
+            .fully_perform_op(
+                self.locations,
+                self.category,
+                InstantiateOpaqueType {
+                    obligations: self
+                        .type_checker
+                        .infcx
+                        .handle_opaque_type(a, b, a_is_expected, &cause, param_env)?
+                        .obligations,
+                    // These fields are filled in during exectuion of the operation
+                    base_universe: None,
+                    region_constraints: None,
+                },
+            )
+            .unwrap();
+        Ok(())
+    }
 }
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 478dbe31fba..e9c64049817 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -725,6 +725,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
         self.tcx.fold_regions(value, &mut false, |_region, _depth| self.next_nll_region_var(origin))
     }
 
+    #[instrument(level = "debug", skip(self, indices))]
     fn replace_bound_regions_with_nll_infer_vars<T>(
         &self,
         origin: NllRegionVariableOrigin,
@@ -735,22 +736,15 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
     where
         T: TypeFoldable<'tcx>,
     {
-        debug!(
-            "replace_bound_regions_with_nll_infer_vars(value={:?}, all_outlive_scope={:?})",
-            value, all_outlive_scope,
-        );
         let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| {
-            debug!("replace_bound_regions_with_nll_infer_vars: br={:?}", br);
+            debug!(?br);
             let liberated_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
                 scope: all_outlive_scope.to_def_id(),
                 bound_region: br.kind,
             }));
             let region_vid = self.next_nll_region_var(origin);
             indices.insert_late_bound_region(liberated_region, region_vid.to_region_vid());
-            debug!(
-                "replace_bound_regions_with_nll_infer_vars: liberated_region={:?} => {:?}",
-                liberated_region, region_vid
-            );
+            debug!(?liberated_region, ?region_vid);
             region_vid
         });
         value
@@ -765,6 +759,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
     /// entries for them and store them in the indices map. This code iterates over the complete
     /// set of late-bound regions and checks for any that we have not yet seen, adding them to the
     /// inputs vector.
+    #[instrument(skip(self, indices))]
     fn replace_late_bound_regions_with_nll_infer_vars(
         &self,
         mir_def_id: LocalDefId,
@@ -776,6 +771,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
             debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
             if !indices.indices.contains_key(&r) {
                 let region_vid = self.next_nll_region_var(FR);
+                debug!(?region_vid);
                 indices.insert_late_bound_region(r, region_vid.to_region_vid());
             }
         });
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 223b3ad0cf9..8790baa010c 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -11,7 +11,7 @@ use rustc_middle::mir::*;
 use rustc_middle::ty::cast::CastTy;
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
 use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt};
-use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
+use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeFoldable};
 use rustc_mir_dataflow::{self, Analysis};
 use rustc_span::{sym, Span, Symbol};
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
@@ -47,7 +47,10 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
         location: Location,
     ) -> bool {
         let ty = ccx.body.local_decls[local].ty;
-        if !NeedsDrop::in_any_value_of_ty(ccx, ty) {
+        // Peeking into opaque types causes cycles if the current function declares said opaque
+        // type. Thus we avoid short circuiting on the type and instead run the more expensive
+        // analysis that looks at the actual usage within this function
+        if !ty.has_opaque_types() && !NeedsDrop::in_any_value_of_ty(ccx, ty) {
             return false;
         }
 
@@ -101,7 +104,10 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
         location: Location,
     ) -> bool {
         let ty = ccx.body.local_decls[local].ty;
-        if !HasMutInterior::in_any_value_of_ty(ccx, ty) {
+        // Peeking into opaque types causes cycles if the current function declares said opaque
+        // type. Thus we avoid short circuiting on the type and instead run the more expensive
+        // analysis that looks at the actual usage within this function
+        if !ty.has_opaque_types() && !HasMutInterior::in_any_value_of_ty(ccx, ty) {
             return false;
         }
 
@@ -148,7 +154,12 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
 
             // If we know that all values of the return type are structurally matchable, there's no
             // need to run dataflow.
-            _ if !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) => false,
+            // Opaque types do not participate in const generics or pattern matching, so we can safely count them out.
+            _ if ccx.body.return_ty().has_opaque_types()
+                || !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) =>
+            {
+                false
+            }
 
             hir::ConstContext::Const | hir::ConstContext::Static(_) => {
                 let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx)
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index deeca78b75d..263959f3cb3 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -79,7 +79,6 @@ pub fn equal_up_to_regions<'tcx>(
     }
 
     // Normalize lifetimes away on both sides, then compare.
-    let param_env = param_env.with_reveal_all_normalized(tcx);
     let normalize = |ty: Ty<'tcx>| {
         tcx.normalize_erasing_regions(
             param_env,
@@ -170,9 +169,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             // Equal types, all is good.
             return true;
         }
+        // Normalization reveals opaque types, but we may be validating MIR while computing
+        // said opaque types, causing cycles.
+        if (src, dest).has_opaque_types() {
+            return true;
+        }
         // Normalize projections and things like that.
-        // FIXME: We need to reveal_all, as some optimizations change types in ways
-        // that require unfolding opaque types.
         let param_env = self.param_env.with_reveal_all_normalized(self.tcx);
         let src = self.tcx.normalize_erasing_regions(param_env, src);
         let dest = self.tcx.normalize_erasing_regions(param_env, dest);
diff --git a/compiler/rustc_data_structures/src/vec_map.rs b/compiler/rustc_data_structures/src/vec_map.rs
index cc7ec9432fa..2f4b3844430 100644
--- a/compiler/rustc_data_structures/src/vec_map.rs
+++ b/compiler/rustc_data_structures/src/vec_map.rs
@@ -30,6 +30,11 @@ where
         }
     }
 
+    /// Removes the entry from the map and returns the removed value
+    pub fn remove(&mut self, k: &K) -> Option<V> {
+        self.0.iter().position(|(k2, _)| k2 == k).map(|pos| self.0.remove(pos).1)
+    }
+
     /// Gets a reference to the value in the entry.
     pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
     where
@@ -39,6 +44,15 @@ where
         self.0.iter().find(|(key, _)| k == key.borrow()).map(|elem| &elem.1)
     }
 
+    /// Gets a mutable reference to the value in the entry.
+    pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
+    where
+        K: Borrow<Q>,
+        Q: Eq,
+    {
+        self.0.iter_mut().find(|(key, _)| k == key.borrow()).map(|elem| &mut elem.1)
+    }
+
     /// Returns the any value corresponding to the supplied predicate filter.
     ///
     /// The supplied predicate will be applied to each (key, value) pair and it will return a
@@ -58,7 +72,7 @@ where
         // This should return just one element, otherwise it's a bug
         assert!(
             filter.next().is_none(),
-            "Collection {:?} should have just one matching element",
+            "Collection {:#?} should have just one matching element",
             self
         );
         Some(value)
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index ff8082840e1..71ee4f1e76d 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -34,6 +34,12 @@ pub struct At<'a, 'tcx> {
     pub infcx: &'a InferCtxt<'a, 'tcx>,
     pub cause: &'a ObligationCause<'tcx>,
     pub param_env: ty::ParamEnv<'tcx>,
+    /// Whether we should define opaque types
+    /// or just treat them opaquely.
+    /// Currently only used to prevent predicate
+    /// matching from matching anything against opaque
+    /// types.
+    pub define_opaque_types: bool,
 }
 
 pub struct Trace<'a, 'tcx> {
@@ -49,7 +55,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         cause: &'a ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> At<'a, 'tcx> {
-        At { infcx: self, cause, param_env }
+        At { infcx: self, cause, param_env, define_opaque_types: true }
     }
 
     /// Forks the inference context, creating a new inference context with the same inference
@@ -59,6 +65,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         Self {
             tcx: self.tcx.clone(),
             defining_use_anchor: self.defining_use_anchor.clone(),
+            reveal_defining_opaque_types: self.reveal_defining_opaque_types.clone(),
             in_progress_typeck_results: self.in_progress_typeck_results.clone(),
             inner: self.inner.clone(),
             skip_leak_check: self.skip_leak_check.clone(),
@@ -86,6 +93,10 @@ pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
 }
 
 impl<'a, 'tcx> At<'a, 'tcx> {
+    pub fn define_opaque_types(self, define_opaque_types: bool) -> Self {
+        Self { define_opaque_types, ..self }
+    }
+
     /// Hacky routine for equating two impl headers in coherence.
     pub fn eq_impl_headers(
         self,
@@ -216,7 +227,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
     {
         let Trace { at, trace, a_is_expected } = self;
         at.infcx.commit_if_ok(|_| {
-            let mut fields = at.infcx.combine_fields(trace, at.param_env);
+            let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
             fields
                 .sub(a_is_expected)
                 .relate(a, b)
@@ -233,7 +244,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
     {
         let Trace { at, trace, a_is_expected } = self;
         at.infcx.commit_if_ok(|_| {
-            let mut fields = at.infcx.combine_fields(trace, at.param_env);
+            let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
             fields
                 .equate(a_is_expected)
                 .relate(a, b)
@@ -248,7 +259,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
     {
         let Trace { at, trace, a_is_expected } = self;
         at.infcx.commit_if_ok(|_| {
-            let mut fields = at.infcx.combine_fields(trace, at.param_env);
+            let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
             fields
                 .lub(a_is_expected)
                 .relate(a, b)
@@ -263,7 +274,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
     {
         let Trace { at, trace, a_is_expected } = self;
         at.infcx.commit_if_ok(|_| {
-            let mut fields = at.infcx.combine_fields(trace, at.param_env);
+            let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
             fields
                 .glb(a_is_expected)
                 .relate(a, b)
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 48d5c21f9eb..750643acdda 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -22,10 +22,12 @@ use rustc_data_structures::captures::Captures;
 use rustc_index::vec::Idx;
 use rustc_index::vec::IndexVec;
 use rustc_middle::arena::ArenaAllocatable;
+use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
 use rustc_middle::ty::{self, BoundVar, Const, ToPredicate, Ty, TyCtxt};
+use rustc_span::Span;
 use std::fmt::Debug;
 use std::iter;
 
@@ -89,6 +91,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
             var_values: inference_vars,
             region_constraints: QueryRegionConstraints::default(),
             certainty: Certainty::Proven, // Ambiguities are OK!
+            opaque_types: vec![],
             value: answer,
         })
     }
@@ -133,14 +136,27 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
         let certainty =
             if ambig_errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous };
 
+        let opaque_types = self.take_opaque_types_for_query_response();
+
         Ok(QueryResponse {
             var_values: inference_vars,
             region_constraints,
             certainty,
             value: answer,
+            opaque_types,
         })
     }
 
+    fn take_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> {
+        self.inner
+            .borrow_mut()
+            .opaque_type_storage
+            .take_opaque_types()
+            .into_iter()
+            .map(|(k, v)| (self.tcx.mk_opaque(k.def_id, k.substs), v.hidden_type.ty))
+            .collect()
+    }
+
     /// Given the (canonicalized) result to a canonical query,
     /// instantiates the result so it can be used, plugging in the
     /// values from the canonical query. (Note that the result may
@@ -223,13 +239,12 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
     where
         R: Debug + TypeFoldable<'tcx>,
     {
-        let result_subst =
-            self.query_response_substitution_guess(cause, original_values, query_response);
+        let InferOk { value: result_subst, mut obligations } = self
+            .query_response_substitution_guess(cause, param_env, original_values, query_response)?;
 
         // Compute `QueryOutlivesConstraint` values that unify each of
         // the original values `v_o` that was canonicalized into a
         // variable...
-        let mut obligations = vec![];
 
         for (index, original_value) in original_values.var_values.iter().enumerate() {
             // ...with the value `v_r` of that variable from the query.
@@ -343,20 +358,25 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
             original_values, query_response,
         );
 
-        let result_subst =
-            self.query_response_substitution_guess(cause, original_values, query_response);
+        let mut value = self.query_response_substitution_guess(
+            cause,
+            param_env,
+            original_values,
+            query_response,
+        )?;
 
-        let obligations = self
-            .unify_query_response_substitution_guess(
+        value.obligations.extend(
+            self.unify_query_response_substitution_guess(
                 cause,
                 param_env,
                 original_values,
-                &result_subst,
+                &value.value,
                 query_response,
             )?
-            .into_obligations();
+            .into_obligations(),
+        );
 
-        Ok(InferOk { value: result_subst, obligations })
+        Ok(value)
     }
 
     /// Given the original values and the (canonicalized) result from
@@ -371,9 +391,10 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
     fn query_response_substitution_guess<R>(
         &self,
         cause: &ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
         original_values: &OriginalQueryValues<'tcx>,
         query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
-    ) -> CanonicalVarValues<'tcx>
+    ) -> InferResult<'tcx, CanonicalVarValues<'tcx>>
     where
         R: Debug + TypeFoldable<'tcx>,
     {
@@ -473,7 +494,16 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
                 .collect(),
         };
 
-        result_subst
+        let mut obligations = vec![];
+
+        // Carry all newly resolved opaque types to the caller's scope
+        for &(a, b) in &query_response.value.opaque_types {
+            let a = substitute_value(self.tcx, &result_subst, a);
+            let b = substitute_value(self.tcx, &result_subst, b);
+            obligations.extend(self.handle_opaque_type(a, b, true, cause, param_env)?.obligations);
+        }
+
+        Ok(InferOk { value: result_subst, obligations })
     }
 
     /// Given a "guess" at the values for the canonical variables in
@@ -629,6 +659,10 @@ struct QueryTypeRelatingDelegate<'a, 'tcx> {
 }
 
 impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
+    fn span(&self) -> Span {
+        self.cause.span
+    }
+
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
         self.param_env
     }
@@ -684,4 +718,18 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
     fn forbid_inference_vars() -> bool {
         true
     }
+
+    fn register_opaque_type(
+        &mut self,
+        a: Ty<'tcx>,
+        b: Ty<'tcx>,
+        a_is_expected: bool,
+    ) -> Result<(), TypeError<'tcx>> {
+        self.obligations.extend(
+            self.infcx
+                .handle_opaque_type(a, b, a_is_expected, &self.cause, self.param_env)?
+                .obligations,
+        );
+        Ok(())
+    }
 }
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index e1b5d04ccfb..41995ca509e 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -51,6 +51,12 @@ pub struct CombineFields<'infcx, 'tcx> {
     pub cause: Option<ty::relate::Cause>,
     pub param_env: ty::ParamEnv<'tcx>,
     pub obligations: PredicateObligations<'tcx>,
+    /// Whether we should define opaque types
+    /// or just treat them opaquely.
+    /// Currently only used to prevent predicate
+    /// matching from matching anything against opaque
+    /// types.
+    pub define_opaque_types: bool,
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -322,6 +328,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
     /// will first instantiate `b_vid` with a *generalized* version
     /// of `a_ty`. Generalization introduces other inference
     /// variables wherever subtyping could occur.
+    #[instrument(skip(self), level = "debug")]
     pub fn instantiate(
         &mut self,
         a_ty: Ty<'tcx>,
@@ -334,8 +341,6 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
         // Get the actual variable that b_vid has been inferred to
         debug_assert!(self.infcx.inner.borrow_mut().type_variables().probe(b_vid).is_unknown());
 
-        debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", a_ty, dir, b_vid);
-
         // Generalize type of `a_ty` appropriately depending on the
         // direction.  As an example, assume:
         //
@@ -348,10 +353,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
         // variables. (Down below, we will relate `a_ty <: b_ty`,
         // adding constraints like `'x: '?2` and `?1 <: ?3`.)
         let Generalization { ty: b_ty, needs_wf } = self.generalize(a_ty, b_vid, dir)?;
-        debug!(
-            "instantiate(a_ty={:?}, dir={:?}, b_vid={:?}, generalized b_ty={:?})",
-            a_ty, dir, b_vid, b_ty
-        );
+        debug!(?b_ty);
         self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty);
 
         if needs_wf {
@@ -392,13 +394,13 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
     /// Preconditions:
     ///
     /// - `for_vid` is a "root vid"
+    #[instrument(skip(self), level = "trace")]
     fn generalize(
         &self,
         ty: Ty<'tcx>,
         for_vid: ty::TyVid,
         dir: RelationDir,
     ) -> RelateResult<'tcx, Generalization<'tcx>> {
-        debug!("generalize(ty={:?}, for_vid={:?}, dir={:?}", ty, for_vid, dir);
         // Determine the ambient variance within which `ty` appears.
         // The surrounding equation is:
         //
@@ -412,7 +414,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
             RelationDir::SupertypeOf => ty::Contravariant,
         };
 
-        debug!("generalize: ambient_variance = {:?}", ambient_variance);
+        trace!(?ambient_variance);
 
         let for_universe = match self.infcx.inner.borrow_mut().type_variables().probe(for_vid) {
             v @ TypeVariableValue::Known { .. } => {
@@ -421,8 +423,8 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
             TypeVariableValue::Unknown { universe } => universe,
         };
 
-        debug!("generalize: for_universe = {:?}", for_universe);
-        debug!("generalize: trace = {:?}", self.trace);
+        trace!(?for_universe);
+        trace!(?self.trace);
 
         let mut generalize = Generalizer {
             infcx: self.infcx,
@@ -439,12 +441,12 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
         let ty = match generalize.relate(ty, ty) {
             Ok(ty) => ty,
             Err(e) => {
-                debug!("generalize: failure {:?}", e);
+                debug!(?e, "failure");
                 return Err(e);
             }
         };
         let needs_wf = generalize.needs_wf;
-        debug!("generalize: success {{ {:?}, {:?} }}", ty, needs_wf);
+        trace!(?ty, ?needs_wf, "success");
         Ok(Generalization { ty, needs_wf })
     }
 
diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs
index 5ac9ad6850c..65c0eba4b3d 100644
--- a/compiler/rustc_infer/src/infer/equate.rs
+++ b/compiler/rustc_infer/src/infer/equate.rs
@@ -66,18 +66,19 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
         self.relate(a, b)
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-        debug!("{}.tys({:?}, {:?})", self.tag(), a, b);
         if a == b {
             return Ok(a);
         }
 
+        trace!(a = ?a.kind(), b = ?b.kind());
+
         let infcx = self.fields.infcx;
+
         let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
         let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
 
-        debug!("{}.tys: replacements ({:?}, {:?})", self.tag(), a, b);
-
         match (a.kind(), b.kind()) {
             (&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => {
                 infcx.inner.borrow_mut().type_variables().equate(a_id, b_id);
@@ -91,6 +92,25 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
                 self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?;
             }
 
+            (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
+                self.fields.infcx.super_combine_tys(self, a, b)?;
+            }
+            (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
+                if self.fields.define_opaque_types && did.is_local() =>
+            {
+                self.fields.obligations.extend(
+                    infcx
+                        .handle_opaque_type(
+                            a,
+                            b,
+                            self.a_is_expected(),
+                            &self.fields.trace.cause,
+                            self.param_env(),
+                        )?
+                        .obligations,
+                );
+            }
+
             _ => {
                 self.fields.infcx.super_combine_tys(self, a, b)?;
             }
diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs
index e98f33ea86e..0d38b94965a 100644
--- a/compiler/rustc_infer/src/infer/glb.rs
+++ b/compiler/rustc_infer/src/infer/glb.rs
@@ -6,7 +6,7 @@ use super::InferCtxt;
 use super::Subtype;
 
 use crate::infer::combine::ConstEquateRelation;
-use crate::traits::ObligationCause;
+use crate::traits::{ObligationCause, PredicateObligation};
 use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
@@ -113,12 +113,20 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
         &self.fields.trace.cause
     }
 
+    fn add_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>) {
+        self.fields.obligations.extend(obligations)
+    }
+
     fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
         let mut sub = self.fields.sub(self.a_is_expected);
         sub.relate(v, a)?;
         sub.relate(v, b)?;
         Ok(())
     }
+
+    fn define_opaque_types(&self) -> bool {
+        self.fields.define_opaque_types
+    }
 }
 
 impl<'tcx> ConstEquateRelation<'tcx> for Glb<'_, '_, 'tcx> {
diff --git a/compiler/rustc_infer/src/infer/lattice.rs b/compiler/rustc_infer/src/infer/lattice.rs
index 32affd6a14e..b77245c2592 100644
--- a/compiler/rustc_infer/src/infer/lattice.rs
+++ b/compiler/rustc_infer/src/infer/lattice.rs
@@ -20,7 +20,7 @@
 use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use super::InferCtxt;
 
-use crate::traits::ObligationCause;
+use crate::traits::{ObligationCause, PredicateObligation};
 use rustc_middle::ty::relate::{RelateResult, TypeRelation};
 use rustc_middle::ty::TyVar;
 use rustc_middle::ty::{self, Ty};
@@ -35,6 +35,10 @@ pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> {
 
     fn cause(&self) -> &ObligationCause<'tcx>;
 
+    fn add_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>);
+
+    fn define_opaque_types(&self) -> bool;
+
     // Relates the type `v` to `a` and `b` such that `v` represents
     // the LUB/GLB of `a` and `b` as appropriate.
     //
@@ -45,6 +49,7 @@ pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> {
 }
 
 /// Relates two types using a given lattice.
+#[instrument(skip(this), level = "debug")]
 pub fn super_lattice_tys<'a, 'tcx: 'a, L>(
     this: &mut L,
     a: Ty<'tcx>,
@@ -53,15 +58,17 @@ pub fn super_lattice_tys<'a, 'tcx: 'a, L>(
 where
     L: LatticeDir<'a, 'tcx>,
 {
-    debug!("{}.lattice_tys({:?}, {:?})", this.tag(), a, b);
+    debug!("{}", this.tag());
 
     if a == b {
         return Ok(a);
     }
 
     let infcx = this.infcx();
+
     let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
     let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
+
     match (a.kind(), b.kind()) {
         // If one side is known to be a variable and one is not,
         // create a variable (`v`) to represent the LUB. Make sure to
@@ -98,6 +105,20 @@ where
             Ok(v)
         }
 
+        (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
+            infcx.super_combine_tys(this, a, b)
+        }
+        (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
+            if this.define_opaque_types() && did.is_local() =>
+        {
+            this.add_obligations(
+                infcx
+                    .handle_opaque_type(a, b, this.a_is_expected(), this.cause(), this.param_env())?
+                    .obligations,
+            );
+            Ok(a)
+        }
+
         _ => infcx.super_combine_tys(this, a, b),
     }
 }
diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs
index bc85a4ac609..498c1e907c4 100644
--- a/compiler/rustc_infer/src/infer/lub.rs
+++ b/compiler/rustc_infer/src/infer/lub.rs
@@ -6,7 +6,7 @@ use super::InferCtxt;
 use super::Subtype;
 
 use crate::infer::combine::ConstEquateRelation;
-use crate::traits::ObligationCause;
+use crate::traits::{ObligationCause, PredicateObligation};
 use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
@@ -119,10 +119,18 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx,
         &self.fields.trace.cause
     }
 
+    fn add_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>) {
+        self.fields.obligations.extend(obligations)
+    }
+
     fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
         let mut sub = self.fields.sub(self.a_is_expected);
         sub.relate(a, v)?;
         sub.relate(b, v)?;
         Ok(())
     }
+
+    fn define_opaque_types(&self) -> bool {
+        self.fields.define_opaque_types
+    }
 }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 83ba9c96978..63ffb5bde38 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -5,7 +5,7 @@ pub use self::RegionVariableOrigin::*;
 pub use self::SubregionOrigin::*;
 pub use self::ValuePairs::*;
 
-use self::opaque_types::OpaqueTypeMap;
+use self::opaque_types::OpaqueTypeStorage;
 pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog};
 
 use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine};
@@ -191,18 +191,8 @@ pub struct InferCtxtInner<'tcx> {
 
     undo_log: InferCtxtUndoLogs<'tcx>,
 
-    // Opaque types found in explicit return types and their
-    // associated fresh inference variable. Writeback resolves these
-    // variables to get the concrete type, which can be used to
-    // 'de-opaque' OpaqueTypeDecl outside of type inference.
-    pub opaque_types: OpaqueTypeMap<'tcx>,
-
-    /// A map from inference variables created from opaque
-    /// type instantiations (`ty::Infer`) to the actual opaque
-    /// type (`ty::Opaque`). Used during fallback to map unconstrained
-    /// opaque type inference variables to their corresponding
-    /// opaque type.
-    pub opaque_types_vars: FxHashMap<Ty<'tcx>, Ty<'tcx>>,
+    /// Caches for opaque type inference.
+    pub opaque_type_storage: OpaqueTypeStorage<'tcx>,
 }
 
 impl<'tcx> InferCtxtInner<'tcx> {
@@ -216,8 +206,7 @@ impl<'tcx> InferCtxtInner<'tcx> {
             float_unification_storage: ut::UnificationTableStorage::new(),
             region_constraint_storage: Some(RegionConstraintStorage::new()),
             region_obligations: vec![],
-            opaque_types: Default::default(),
-            opaque_types_vars: Default::default(),
+            opaque_type_storage: Default::default(),
         }
     }
 
@@ -237,6 +226,11 @@ impl<'tcx> InferCtxtInner<'tcx> {
     }
 
     #[inline]
+    pub fn opaque_types(&mut self) -> opaque_types::OpaqueTypeTable<'_, 'tcx> {
+        self.opaque_type_storage.with_log(&mut self.undo_log)
+    }
+
+    #[inline]
     fn int_unification_table(
         &mut self,
     ) -> ut::UnificationTable<
@@ -296,6 +290,10 @@ pub struct InferCtxt<'a, 'tcx> {
     /// to the outside until the end up in an `InferCtxt` for typeck or borrowck.
     pub defining_use_anchor: Option<LocalDefId>,
 
+    /// Used by WF-checking to not have to figure out hidden types itself, but
+    /// to just invoke type_of to get the already computed hidden type from typeck.
+    pub reveal_defining_opaque_types: bool,
+
     /// During type-checking/inference of a body, `in_progress_typeck_results`
     /// contains a reference to the typeck results being built up, which are
     /// used for reading closure kinds/signatures as they are inferred,
@@ -571,6 +569,7 @@ pub struct InferCtxtBuilder<'tcx> {
     tcx: TyCtxt<'tcx>,
     fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
     defining_use_anchor: Option<LocalDefId>,
+    reveal_defining_opaque_types: bool,
 }
 
 pub trait TyCtxtInferExt<'tcx> {
@@ -579,7 +578,12 @@ pub trait TyCtxtInferExt<'tcx> {
 
 impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
     fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
-        InferCtxtBuilder { tcx: self, defining_use_anchor: None, fresh_typeck_results: None }
+        InferCtxtBuilder {
+            tcx: self,
+            defining_use_anchor: None,
+            fresh_typeck_results: None,
+            reveal_defining_opaque_types: false,
+        }
     }
 }
 
@@ -603,6 +607,13 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
         self
     }
 
+    /// WF-checking doesn't need to recompute opaque types and can instead use
+    /// the type_of query to get them from typeck.
+    pub fn reveal_defining_opaque_types(mut self) -> Self {
+        self.reveal_defining_opaque_types = true;
+        self
+    }
+
     /// Given a canonical value `C` as a starting point, create an
     /// inference context that contains each of the bound values
     /// within instantiated as a fresh variable. The `f` closure is
@@ -627,11 +638,17 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
     }
 
     pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R {
-        let InferCtxtBuilder { tcx, defining_use_anchor, ref fresh_typeck_results } = *self;
+        let InferCtxtBuilder {
+            tcx,
+            defining_use_anchor,
+            reveal_defining_opaque_types,
+            ref fresh_typeck_results,
+        } = *self;
         let in_progress_typeck_results = fresh_typeck_results.as_ref();
         f(InferCtxt {
             tcx,
             defining_use_anchor,
+            reveal_defining_opaque_types,
             in_progress_typeck_results,
             inner: RefCell::new(InferCtxtInner::new()),
             lexical_region_resolutions: RefCell::new(None),
@@ -766,6 +783,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         &'a self,
         trace: TypeTrace<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
+        define_opaque_types: bool,
     ) -> CombineFields<'a, 'tcx> {
         CombineFields {
             infcx: self,
@@ -773,6 +791,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             cause: None,
             param_env,
             obligations: PredicateObligations::new(),
+            define_opaque_types,
         }
     }
 
@@ -1088,12 +1107,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         self.tcx.mk_ty_var(self.next_ty_var_id(origin))
     }
 
+    pub fn next_ty_var_id_in_universe(
+        &self,
+        origin: TypeVariableOrigin,
+        universe: ty::UniverseIndex,
+    ) -> TyVid {
+        self.inner.borrow_mut().type_variables().new_var(universe, origin)
+    }
+
     pub fn next_ty_var_in_universe(
         &self,
         origin: TypeVariableOrigin,
         universe: ty::UniverseIndex,
     ) -> Ty<'tcx> {
-        let vid = self.inner.borrow_mut().type_variables().new_var(universe, origin);
+        let vid = self.next_ty_var_id_in_universe(origin, universe);
         self.tcx.mk_ty_var(vid)
     }
 
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 69db6509b79..cc0114d7538 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -24,11 +24,13 @@
 use crate::infer::combine::ConstEquateRelation;
 use crate::infer::InferCtxt;
 use crate::infer::{ConstVarValue, ConstVariableValue};
+use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::fold::{TypeFoldable, TypeVisitor};
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::{self, InferConst, Ty, TyCtxt};
+use rustc_span::Span;
 use std::fmt::Debug;
 use std::ops::ControlFlow;
 
@@ -75,6 +77,7 @@ where
 
 pub trait TypeRelatingDelegate<'tcx> {
     fn param_env(&self) -> ty::ParamEnv<'tcx>;
+    fn span(&self) -> Span;
 
     /// Push a constraint `sup: sub` -- this constraint must be
     /// satisfied for the two types to be related. `sub` and `sup` may
@@ -88,6 +91,12 @@ pub trait TypeRelatingDelegate<'tcx> {
     );
 
     fn const_equate(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>);
+    fn register_opaque_type(
+        &mut self,
+        a: Ty<'tcx>,
+        b: Ty<'tcx>,
+        a_is_expected: bool,
+    ) -> Result<(), TypeError<'tcx>>;
 
     /// Creates a new universe index. Used when instantiating placeholders.
     fn create_next_universe(&mut self) -> ty::UniverseIndex;
@@ -277,7 +286,6 @@ where
         projection_ty: ty::ProjectionTy<'tcx>,
         value_ty: Ty<'tcx>,
     ) -> Ty<'tcx> {
-        use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
         use rustc_span::DUMMY_SP;
 
         match *value_ty.kind() {
@@ -286,6 +294,8 @@ where
                     kind: TypeVariableOriginKind::MiscVariable,
                     span: DUMMY_SP,
                 });
+                // FIXME(lazy-normalization): This will always ICE, because the recursive
+                // call will end up in the _ arm below.
                 self.relate_projection_ty(projection_ty, var);
                 self.relate_projection_ty(other_projection_ty, var);
                 var
@@ -531,6 +541,8 @@ where
 
     #[instrument(skip(self), level = "debug")]
     fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+        let infcx = self.infcx;
+
         let a = self.infcx.shallow_resolve(a);
 
         if !D::forbid_inference_vars() {
@@ -559,6 +571,35 @@ where
 
             (&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var((vid, b)),
 
+            (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
+                self.infcx.super_combine_tys(self, a, b)
+            }
+            (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..)) if did.is_local() => {
+                let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
+                let mut generalize = |ty, ty_is_expected| {
+                    let var = infcx.next_ty_var_id_in_universe(
+                        TypeVariableOrigin {
+                            kind: TypeVariableOriginKind::MiscVariable,
+                            span: self.delegate.span(),
+                        },
+                        ty::UniverseIndex::ROOT,
+                    );
+                    if ty_is_expected {
+                        self.relate_ty_var((ty, var))
+                    } else {
+                        self.relate_ty_var((var, ty))
+                    }
+                };
+                let (a, b) = match (a.kind(), b.kind()) {
+                    (&ty::Opaque(..), _) => (a, generalize(b, false)?),
+                    (_, &ty::Opaque(..)) => (generalize(a, true)?, b),
+                    _ => unreachable!(),
+                };
+                self.delegate.register_opaque_type(a, b, true)?;
+                trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated");
+                Ok(a)
+            }
+
             (&ty::Projection(projection_ty), _)
                 if D::normalization() == NormalizationStrategy::Lazy =>
             {
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index e7dca94806c..e8cd5988b96 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -1,102 +1,196 @@
-use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use crate::infer::{InferCtxt, InferOk};
 use crate::traits;
+use hir::def_id::{DefId, LocalDefId};
+use hir::{HirId, OpaqueTyOrigin};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::vec_map::VecMap;
 use rustc_hir as hir;
-use rustc_hir::def_id::LocalDefId;
+use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::subst::{GenericArgKind, Subst};
-use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::{
+    self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitor,
+};
 use rustc_span::Span;
 
 use std::ops::ControlFlow;
 
 pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
 
+mod table;
+
+pub use table::{OpaqueTypeStorage, OpaqueTypeTable};
+
+use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use super::InferResult;
+
 /// Information about the opaque types whose values we
 /// are inferring in this function (these are the `impl Trait` that
 /// appear in the return type).
-#[derive(Copy, Clone, Debug)]
+#[derive(Clone, Debug)]
 pub struct OpaqueTypeDecl<'tcx> {
-    /// The opaque type (`ty::Opaque`) for this declaration.
-    pub opaque_type: Ty<'tcx>,
-
-    /// The span of this particular definition of the opaque type. So
-    /// for example:
-    ///
-    /// ```ignore (incomplete snippet)
-    /// type Foo = impl Baz;
-    /// fn bar() -> Foo {
-    /// //          ^^^ This is the span we are looking for!
-    /// }
-    /// ```
-    ///
-    /// In cases where the fn returns `(impl Trait, impl Trait)` or
-    /// other such combinations, the result is currently
-    /// over-approximated, but better than nothing.
-    pub definition_span: Span,
-
-    /// The type variable that represents the value of the opaque type
-    /// that we require. In other words, after we compile this function,
-    /// we will be created a constraint like:
-    ///
-    ///     Foo<'a, T> = ?C
-    ///
-    /// where `?C` is the value of this type variable. =) It may
-    /// naturally refer to the type and lifetime parameters in scope
-    /// in this function, though ultimately it should only reference
-    /// those that are arguments to `Foo` in the constraint above. (In
-    /// other words, `?C` should not include `'b`, even though it's a
-    /// lifetime parameter on `foo`.)
-    pub concrete_ty: Ty<'tcx>,
+    /// The hidden types that have been inferred for this opaque type.
+    /// There can be multiple, but they are all `lub`ed together at the end
+    /// to obtain the canonical hidden type.
+    pub hidden_type: OpaqueHiddenType<'tcx>,
 
     /// The origin of the opaque type.
     pub origin: hir::OpaqueTyOrigin,
 }
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
-    /// Replaces all opaque types in `value` with fresh inference variables
-    /// and creates appropriate obligations. For example, given the input:
-    ///
-    ///     impl Iterator<Item = impl Debug>
-    ///
-    /// this method would create two type variables, `?0` and `?1`. It would
-    /// return the type `?0` but also the obligations:
-    ///
-    ///     ?0: Iterator<Item = ?1>
-    ///     ?1: Debug
-    ///
-    /// Moreover, it returns an `OpaqueTypeMap` that would map `?0` to
-    /// info about the `impl Iterator<..>` type and `?1` to info about
-    /// the `impl Debug` type.
-    ///
-    /// # Parameters
-    ///
-    /// - `parent_def_id` -- the `DefId` of the function in which the opaque type
-    ///   is defined
-    /// - `body_id` -- the body-id with which the resulting obligations should
-    ///   be associated
-    /// - `param_env` -- the in-scope parameter environment to be used for
-    ///   obligations
-    /// - `value` -- the value within which we are instantiating opaque types
-    /// - `value_span` -- the span where the value came from, used in error reporting
-    pub fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
+    /// This is a backwards compatibility hack to prevent breaking changes from
+    /// lazy TAIT around RPIT handling.
+    pub fn replace_opaque_types_with_inference_vars<T: TypeFoldable<'tcx>>(
         &self,
-        body_id: hir::HirId,
-        param_env: ty::ParamEnv<'tcx>,
         value: T,
-        value_span: Span,
+        body_id: HirId,
+        span: Span,
+        param_env: ty::ParamEnv<'tcx>,
     ) -> InferOk<'tcx, T> {
-        debug!(
-            "instantiate_opaque_types(value={:?}, body_id={:?}, \
-             param_env={:?}, value_span={:?})",
-            value, body_id, param_env, value_span,
-        );
-        let mut instantiator =
-            Instantiator { infcx: self, body_id, param_env, value_span, obligations: vec![] };
-        let value = instantiator.instantiate_opaque_types_in_map(value);
-        InferOk { value, obligations: instantiator.obligations }
+        if !value.has_opaque_types() {
+            return InferOk { value, obligations: vec![] };
+        }
+        let mut obligations = vec![];
+        let value = value.fold_with(&mut ty::fold::BottomUpFolder {
+            tcx: self.tcx,
+            lt_op: |lt| lt,
+            ct_op: |ct| ct,
+            ty_op: |ty| match *ty.kind() {
+                // Closures can't create hidden types for opaque types of their parent, as they
+                // do not have all the outlives information available. Also `type_of` looks for
+                // hidden types in the owner (so the closure's parent), so it would not find these
+                // definitions.
+                ty::Opaque(def_id, _substs)
+                    if matches!(
+                        self.opaque_type_origin(def_id, span),
+                        Some(OpaqueTyOrigin::FnReturn(..))
+                    ) =>
+                {
+                    let span = if span.is_dummy() { self.tcx.def_span(def_id) } else { span };
+                    let cause = ObligationCause::misc(span, body_id);
+                    let ty_var = self.next_ty_var(TypeVariableOrigin {
+                        kind: TypeVariableOriginKind::TypeInference,
+                        span: cause.span,
+                    });
+                    obligations.extend(
+                        self.handle_opaque_type(ty, ty_var, true, &cause, param_env)
+                            .unwrap()
+                            .obligations,
+                    );
+                    ty_var
+                }
+                _ => ty,
+            },
+        });
+        InferOk { value, obligations }
+    }
+
+    pub fn handle_opaque_type(
+        &self,
+        a: Ty<'tcx>,
+        b: Ty<'tcx>,
+        a_is_expected: bool,
+        cause: &ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> InferResult<'tcx, ()> {
+        if a.references_error() || b.references_error() {
+            return Ok(InferOk { value: (), obligations: vec![] });
+        }
+        let (a, b) = if a_is_expected { (a, b) } else { (b, a) };
+        let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
+            ty::Opaque(def_id, substs) => {
+                let origin = if self.defining_use_anchor.is_some() {
+                    // Check that this is `impl Trait` type is
+                    // declared by `parent_def_id` -- i.e., one whose
+                    // value we are inferring.  At present, this is
+                    // always true during the first phase of
+                    // type-check, but not always true later on during
+                    // NLL. Once we support named opaque types more fully,
+                    // this same scenario will be able to arise during all phases.
+                    //
+                    // Here is an example using type alias `impl Trait`
+                    // that indicates the distinction we are checking for:
+                    //
+                    // ```rust
+                    // mod a {
+                    //   pub type Foo = impl Iterator;
+                    //   pub fn make_foo() -> Foo { .. }
+                    // }
+                    //
+                    // mod b {
+                    //   fn foo() -> a::Foo { a::make_foo() }
+                    // }
+                    // ```
+                    //
+                    // Here, the return type of `foo` references an
+                    // `Opaque` indeed, but not one whose value is
+                    // presently being inferred. You can get into a
+                    // similar situation with closure return types
+                    // today:
+                    //
+                    // ```rust
+                    // fn foo() -> impl Iterator { .. }
+                    // fn bar() {
+                    //     let x = || foo(); // returns the Opaque assoc with `foo`
+                    // }
+                    // ```
+                    self.opaque_type_origin(def_id, cause.span)?
+                } else {
+                    self.opaque_ty_origin_unchecked(def_id, cause.span)
+                };
+                if let ty::Opaque(did2, _) = *b.kind() {
+                    // We could accept this, but there are various ways to handle this situation, and we don't
+                    // want to make a decision on it right now. Likely this case is so super rare anyway, that
+                    // no one encounters it in practice.
+                    // It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`,
+                    // where it is of no concern, so we only check for TAITs.
+                    if let Some(OpaqueTyOrigin::TyAlias) = self.opaque_type_origin(did2, cause.span)
+                    {
+                        self.tcx
+                                .sess
+                                .struct_span_err(
+                                    cause.span,
+                                    "opaque type's hidden type cannot be another opaque type from the same scope",
+                                )
+                                .span_label(cause.span, "one of the two opaque types used here has to be outside its defining scope")
+                                .span_note(
+                                    self.tcx.def_span(def_id),
+                                    "opaque type whose hidden type is being assigned",
+                                )
+                                .span_note(
+                                    self.tcx.def_span(did2),
+                                    "opaque type being used as hidden type",
+                                )
+                                .emit();
+                    }
+                }
+                Some(self.register_hidden_type(
+                    OpaqueTypeKey { def_id, substs },
+                    cause.clone(),
+                    param_env,
+                    b,
+                    origin,
+                ))
+            }
+            _ => None,
+        };
+        if let Some(res) = process(a, b) {
+            res
+        } else if let Some(res) = process(b, a) {
+            res
+        } else {
+            // Rerun equality check, but this time error out due to
+            // different types.
+            match self.at(cause, param_env).define_opaque_types(false).eq(a, b) {
+                Ok(_) => span_bug!(
+                    cause.span,
+                    "opaque types are never equal to anything but themselves: {:#?}",
+                    (a.kind(), b.kind())
+                ),
+                Err(e) => Err(e),
+            }
+        }
     }
 
     /// Given the map `opaque_types` containing the opaque
@@ -231,51 +325,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     /// but this is not necessary, because the opaque type we
     /// create will be allowed to reference `T`. So we only generate a
     /// constraint that `'0: 'a`.
-    ///
-    /// # The `free_region_relations` parameter
-    ///
-    /// The `free_region_relations` argument is used to find the
-    /// "minimum" of the regions supplied to a given opaque type.
-    /// It must be a relation that can answer whether `'a <= 'b`,
-    /// where `'a` and `'b` are regions that appear in the "substs"
-    /// for the opaque type references (the `<'a>` in `Foo1<'a>`).
-    ///
-    /// Note that we do not impose the constraints based on the
-    /// generic regions from the `Foo1` definition (e.g., `'x`). This
-    /// is because the constraints we are imposing here is basically
-    /// the concern of the one generating the constraining type C1,
-    /// which is the current function. It also means that we can
-    /// take "implied bounds" into account in some cases:
-    ///
-    /// ```text
-    /// trait SomeTrait<'a, 'b> { }
-    /// fn foo<'a, 'b>(_: &'a &'b u32) -> impl SomeTrait<'a, 'b> { .. }
-    /// ```
-    ///
-    /// Here, the fact that `'b: 'a` is known only because of the
-    /// implied bounds from the `&'a &'b u32` parameter, and is not
-    /// "inherent" to the opaque type definition.
-    ///
-    /// # Parameters
-    ///
-    /// - `opaque_types` -- the map produced by `instantiate_opaque_types`
-    /// - `free_region_relations` -- something that can be used to relate
-    ///   the free regions (`'a`) that appear in the impl trait.
     #[instrument(level = "debug", skip(self))]
-    pub fn constrain_opaque_type(
+    pub fn register_member_constraints(
         &self,
+        param_env: ty::ParamEnv<'tcx>,
         opaque_type_key: OpaqueTypeKey<'tcx>,
-        opaque_defn: &OpaqueTypeDecl<'tcx>,
+        concrete_ty: Ty<'tcx>,
+        span: Span,
     ) {
         let def_id = opaque_type_key.def_id;
 
         let tcx = self.tcx;
 
-        let concrete_ty = self.resolve_vars_if_possible(opaque_defn.concrete_ty);
+        let concrete_ty = self.resolve_vars_if_possible(concrete_ty);
 
         debug!(?concrete_ty);
 
-        let first_own_region = match opaque_defn.origin {
+        let first_own_region = match self.opaque_ty_origin_unchecked(def_id, span) {
             hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {
                 // We lower
                 //
@@ -319,7 +385,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             op: |r| {
                 self.member_constraint(
                     opaque_type_key.def_id,
-                    opaque_defn.definition_span,
+                    span,
                     concrete_ty,
                     r,
                     &choice_regions,
@@ -328,15 +394,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         });
     }
 
-    fn opaque_type_origin(&self, def_id: LocalDefId) -> Option<hir::OpaqueTyOrigin> {
-        let tcx = self.tcx;
-        let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+    #[instrument(skip(self), level = "trace")]
+    pub fn opaque_type_origin(&self, opaque_def_id: DefId, span: Span) -> Option<OpaqueTyOrigin> {
+        let def_id = opaque_def_id.as_local()?;
+        let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
         let parent_def_id = self.defining_use_anchor?;
-        let item_kind = &tcx.hir().expect_item(def_id).kind;
+        let item_kind = &self.tcx.hir().expect_item(def_id).kind;
+
         let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, ..  }) = item_kind else {
             span_bug!(
-                tcx.def_span(def_id),
-                "weird opaque type: {:#?}",
+                span,
+                "weird opaque type: {:#?}, {:#?}",
+                opaque_def_id,
                 item_kind
             )
         };
@@ -347,11 +416,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
             // Named `type Foo = impl Bar;`
             hir::OpaqueTyOrigin::TyAlias => {
-                may_define_opaque_type(tcx, parent_def_id, opaque_hir_id)
+                may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id)
             }
         };
+        trace!(?origin);
         in_definition_scope.then_some(*origin)
     }
+
+    #[instrument(skip(self), level = "trace")]
+    fn opaque_ty_origin_unchecked(&self, opaque_def_id: DefId, span: Span) -> OpaqueTyOrigin {
+        let def_id = opaque_def_id.as_local().unwrap();
+        let origin = match self.tcx.hir().expect_item(def_id).kind {
+            hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => origin,
+            ref itemkind => {
+                span_bug!(span, "weird opaque type: {:?}, {:#?}", opaque_def_id, itemkind)
+            }
+        };
+        trace!(?origin);
+        origin
+    }
 }
 
 // Visitor that requires that (almost) all regions in the type visited outlive
@@ -426,180 +509,93 @@ where
     }
 }
 
-struct Instantiator<'a, 'tcx> {
-    infcx: &'a InferCtxt<'a, 'tcx>,
-    body_id: hir::HirId,
-    param_env: ty::ParamEnv<'tcx>,
-    value_span: Span,
-    obligations: Vec<traits::PredicateObligation<'tcx>>,
+pub enum UseKind {
+    DefiningUse,
+    OpaqueUse,
 }
 
-impl<'a, 'tcx> Instantiator<'a, 'tcx> {
-    fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
-        let tcx = self.infcx.tcx;
-        value.fold_with(&mut BottomUpFolder {
-            tcx,
-            ty_op: |ty| {
-                if ty.references_error() {
-                    return tcx.ty_error();
-                } else if let ty::Opaque(def_id, substs) = ty.kind() {
-                    // Check that this is `impl Trait` type is
-                    // declared by `parent_def_id` -- i.e., one whose
-                    // value we are inferring.  At present, this is
-                    // always true during the first phase of
-                    // type-check, but not always true later on during
-                    // NLL. Once we support named opaque types more fully,
-                    // this same scenario will be able to arise during all phases.
-                    //
-                    // Here is an example using type alias `impl Trait`
-                    // that indicates the distinction we are checking for:
-                    //
-                    // ```rust
-                    // mod a {
-                    //   pub type Foo = impl Iterator;
-                    //   pub fn make_foo() -> Foo { .. }
-                    // }
-                    //
-                    // mod b {
-                    //   fn foo() -> a::Foo { a::make_foo() }
-                    // }
-                    // ```
-                    //
-                    // Here, the return type of `foo` references an
-                    // `Opaque` indeed, but not one whose value is
-                    // presently being inferred. You can get into a
-                    // similar situation with closure return types
-                    // today:
-                    //
-                    // ```rust
-                    // fn foo() -> impl Iterator { .. }
-                    // fn bar() {
-                    //     let x = || foo(); // returns the Opaque assoc with `foo`
-                    // }
-                    // ```
-                    if let Some(def_id) = def_id.as_local() {
-                        if let Some(origin) = self.infcx.opaque_type_origin(def_id) {
-                            let opaque_type_key =
-                                OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
-                            return self.fold_opaque_ty(ty, opaque_type_key, origin);
-                        }
-
-                        debug!(
-                            "instantiate_opaque_types_in_map: \
-                             encountered opaque outside its definition scope \
-                             def_id={:?}",
-                            def_id,
-                        );
-                    }
-                }
-
-                ty
-            },
-            lt_op: |lt| lt,
-            ct_op: |ct| ct,
-        })
+impl UseKind {
+    pub fn is_defining(self) -> bool {
+        match self {
+            UseKind::DefiningUse => true,
+            UseKind::OpaqueUse => false,
+        }
     }
+}
 
+impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     #[instrument(skip(self), level = "debug")]
-    fn fold_opaque_ty(
-        &mut self,
-        ty: Ty<'tcx>,
+    pub fn register_hidden_type(
+        &self,
         opaque_type_key: OpaqueTypeKey<'tcx>,
+        cause: ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        hidden_ty: Ty<'tcx>,
         origin: hir::OpaqueTyOrigin,
-    ) -> Ty<'tcx> {
-        let infcx = self.infcx;
-        let tcx = infcx.tcx;
+    ) -> InferResult<'tcx, ()> {
+        let tcx = self.tcx;
         let OpaqueTypeKey { def_id, substs } = opaque_type_key;
 
-        // Use the same type variable if the exact same opaque type appears more
-        // than once in the return type (e.g., if it's passed to a type alias).
-        if let Some(opaque_defn) = infcx.inner.borrow().opaque_types.get(&opaque_type_key) {
-            debug!("re-using cached concrete type {:?}", opaque_defn.concrete_ty.kind());
-            return opaque_defn.concrete_ty;
-        }
-
-        let ty_var = infcx.next_ty_var(TypeVariableOrigin {
-            kind: TypeVariableOriginKind::TypeInference,
-            span: self.value_span,
-        });
-
         // Ideally, we'd get the span where *this specific `ty` came
         // from*, but right now we just use the span from the overall
         // value being folded. In simple cases like `-> impl Foo`,
         // these are the same span, but not in cases like `-> (impl
         // Foo, impl Bar)`.
-        let definition_span = self.value_span;
-
-        {
-            let mut infcx = self.infcx.inner.borrow_mut();
-            infcx.opaque_types.insert(
-                OpaqueTypeKey { def_id, substs },
-                OpaqueTypeDecl { opaque_type: ty, definition_span, concrete_ty: ty_var, origin },
-            );
-            infcx.opaque_types_vars.insert(ty_var, ty);
-        }
+        let span = cause.span;
 
-        debug!("generated new type inference var {:?}", ty_var.kind());
+        let mut obligations = vec![];
+        let prev = self.inner.borrow_mut().opaque_types().register(
+            OpaqueTypeKey { def_id, substs },
+            OpaqueHiddenType { ty: hidden_ty, span },
+            origin,
+        );
+        if let Some(prev) = prev {
+            obligations = self.at(&cause, param_env).eq(prev, hidden_ty)?.obligations;
+        }
 
         let item_bounds = tcx.explicit_item_bounds(def_id);
 
-        self.obligations.reserve(item_bounds.len());
         for (predicate, _) in item_bounds {
             debug!(?predicate);
             let predicate = predicate.subst(tcx, substs);
-            debug!(?predicate);
 
             let predicate = predicate.fold_with(&mut BottomUpFolder {
                 tcx,
                 ty_op: |ty| match *ty.kind() {
-                    // Replace all other mentions of the same opaque type with the hidden type,
-                    // as the bounds must hold on the hidden type after all.
-                    ty::Opaque(def_id2, substs2) if def_id == def_id2 && substs == substs2 => {
-                        ty_var
-                    }
-                    // Instantiate nested instances of `impl Trait`.
-                    ty::Opaque(..) => self.instantiate_opaque_types_in_map(ty),
-                    _ => ty,
-                },
-                lt_op: |lt| lt,
-                ct_op: |ct| ct,
-            });
-
-            // We can't normalize associated types from `rustc_infer`, but we can eagerly register inference variables for them.
-            let predicate = predicate.fold_with(&mut BottomUpFolder {
-                tcx,
-                ty_op: |ty| match ty.kind() {
+                    // We can't normalize associated types from `rustc_infer`,
+                    // but we can eagerly register inference variables for them.
                     ty::Projection(projection_ty) if !projection_ty.has_escaping_bound_vars() => {
-                        infcx.infer_projection(
-                            self.param_env,
-                            *projection_ty,
-                            traits::ObligationCause::misc(self.value_span, self.body_id),
+                        self.infer_projection(
+                            param_env,
+                            projection_ty,
+                            cause.clone(),
                             0,
-                            &mut self.obligations,
+                            &mut obligations,
                         )
                     }
+                    // Replace all other mentions of the same opaque type with the hidden type,
+                    // as the bounds must hold on the hidden type after all.
+                    ty::Opaque(def_id2, substs2) if def_id == def_id2 && substs == substs2 => {
+                        hidden_ty
+                    }
                     _ => ty,
                 },
                 lt_op: |lt| lt,
                 ct_op: |ct| ct,
             });
-            debug!(?predicate);
 
             if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
                 if projection.term.references_error() {
-                    return tcx.ty_error();
+                    // No point on adding these obligations since there's a type error involved.
+                    return Ok(InferOk { value: (), obligations: vec![] });
                 }
+                trace!("{:#?}", projection.term);
             }
-
-            let cause =
-                traits::ObligationCause::new(self.value_span, self.body_id, traits::OpaqueType);
-
             // Require that the predicate holds for the concrete type.
             debug!(?predicate);
-            self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate));
+            obligations.push(traits::Obligation::new(cause.clone(), param_env, predicate));
         }
-
-        ty_var
+        Ok(InferOk { value: (), obligations })
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs
new file mode 100644
index 00000000000..fb12da0cc13
--- /dev/null
+++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs
@@ -0,0 +1,80 @@
+use rustc_data_structures::undo_log::UndoLogs;
+use rustc_hir::OpaqueTyOrigin;
+use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty};
+use rustc_span::DUMMY_SP;
+
+use crate::infer::{InferCtxtUndoLogs, UndoLog};
+
+use super::{OpaqueTypeDecl, OpaqueTypeMap};
+
+#[derive(Default, Debug, Clone)]
+pub struct OpaqueTypeStorage<'tcx> {
+    // Opaque types found in explicit return types and their
+    // associated fresh inference variable. Writeback resolves these
+    // variables to get the concrete type, which can be used to
+    // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions.
+    pub opaque_types: OpaqueTypeMap<'tcx>,
+}
+
+impl<'tcx> OpaqueTypeStorage<'tcx> {
+    #[instrument(level = "debug")]
+    pub(crate) fn remove(&mut self, key: OpaqueTypeKey<'tcx>, idx: Option<OpaqueHiddenType<'tcx>>) {
+        if let Some(idx) = idx {
+            self.opaque_types.get_mut(&key).unwrap().hidden_type = idx;
+        } else {
+            match self.opaque_types.remove(&key) {
+                None => bug!("reverted opaque type inference that was never registered: {:?}", key),
+                Some(_) => {}
+            }
+        }
+    }
+
+    #[instrument(level = "debug")]
+    pub fn take_opaque_types(&mut self) -> OpaqueTypeMap<'tcx> {
+        std::mem::take(&mut self.opaque_types)
+    }
+
+    #[inline]
+    pub(crate) fn with_log<'a>(
+        &'a mut self,
+        undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
+    ) -> OpaqueTypeTable<'a, 'tcx> {
+        OpaqueTypeTable { storage: self, undo_log }
+    }
+}
+
+impl<'tcx> Drop for OpaqueTypeStorage<'tcx> {
+    fn drop(&mut self) {
+        if !self.opaque_types.is_empty() {
+            ty::tls::with(|tcx| {
+                tcx.sess.delay_span_bug(DUMMY_SP, &format!("{:?}", self.opaque_types))
+            });
+        }
+    }
+}
+
+pub struct OpaqueTypeTable<'a, 'tcx> {
+    storage: &'a mut OpaqueTypeStorage<'tcx>,
+
+    undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
+}
+
+impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> {
+    #[instrument(skip(self), level = "debug")]
+    pub(crate) fn register(
+        &mut self,
+        key: OpaqueTypeKey<'tcx>,
+        hidden_type: OpaqueHiddenType<'tcx>,
+        origin: OpaqueTyOrigin,
+    ) -> Option<Ty<'tcx>> {
+        if let Some(decl) = self.storage.opaque_types.get_mut(&key) {
+            let prev = std::mem::replace(&mut decl.hidden_type, hidden_type);
+            self.undo_log.push(UndoLog::OpaqueTypes(key, Some(prev)));
+            return Some(prev.ty);
+        }
+        let decl = OpaqueTypeDecl { hidden_type, origin };
+        self.storage.opaque_types.insert(key, decl);
+        self.undo_log.push(UndoLog::OpaqueTypes(key, None));
+        None
+    }
+}
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index 5d8cc94e05c..45aa2bcba86 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -153,6 +153,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
     /// This function may have to perform normalizations, and hence it
     /// returns an `InferOk` with subobligations that must be
     /// processed.
+    #[instrument(level = "debug", skip(self, region_bound_pairs_map))]
     pub fn process_registered_region_obligations(
         &self,
         region_bound_pairs_map: &FxHashMap<hir::HirId, RegionBoundPairs<'tcx>>,
@@ -164,8 +165,6 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
             "cannot process registered region obligations in a snapshot"
         );
 
-        debug!(?param_env, "process_registered_region_obligations()");
-
         let my_region_obligations = self.take_registered_region_obligations();
 
         for (body_id, RegionObligation { sup_type, sub_region, origin }) in my_region_obligations {
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index 9ec1b3390d0..3600b54a271 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -2,6 +2,7 @@ use super::combine::{CombineFields, RelationDir};
 use super::SubregionOrigin;
 
 use crate::infer::combine::ConstEquateRelation;
+use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
 use crate::traits::Obligation;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
@@ -74,9 +75,8 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
         }
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-        debug!("{}.tys({:?}, {:?})", self.tag(), a, b);
-
         if a == b {
             return Ok(a);
         }
@@ -84,6 +84,7 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
         let infcx = self.fields.infcx;
         let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
         let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
+
         match (a.kind(), b.kind()) {
             (&ty::Infer(TyVar(_)), &ty::Infer(TyVar(_))) => {
                 // Shouldn't have any LBR here, so we can safely put
@@ -121,6 +122,38 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
                 Ok(self.tcx().ty_error())
             }
 
+            (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
+                self.fields.infcx.super_combine_tys(self, a, b)?;
+                Ok(a)
+            }
+            (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
+                if self.fields.define_opaque_types && did.is_local() =>
+            {
+                let mut generalize = |ty, ty_is_expected| {
+                    let var = infcx.next_ty_var_id_in_universe(
+                        TypeVariableOrigin {
+                            kind: TypeVariableOriginKind::MiscVariable,
+                            span: self.fields.trace.cause.span,
+                        },
+                        ty::UniverseIndex::ROOT,
+                    );
+                    self.fields.instantiate(ty, RelationDir::SubtypeOf, var, ty_is_expected)?;
+                    Ok(infcx.tcx.mk_ty_var(var))
+                };
+                let (a, b) = if self.a_is_expected { (a, b) } else { (b, a) };
+                let (a, b) = match (a.kind(), b.kind()) {
+                    (&ty::Opaque(..), _) => (a, generalize(b, true)?),
+                    (_, &ty::Opaque(..)) => (generalize(a, false)?, b),
+                    _ => unreachable!(),
+                };
+                self.fields.obligations.extend(
+                    infcx
+                        .handle_opaque_type(a, b, true, &self.fields.trace.cause, self.param_env())?
+                        .obligations,
+                );
+                Ok(a)
+            }
+
             _ => {
                 self.fields.infcx.super_combine_tys(self, a, b)?;
                 Ok(a)
diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs
index ecd886b5478..1b696f21cbc 100644
--- a/compiler/rustc_infer/src/infer/undo_log.rs
+++ b/compiler/rustc_infer/src/infer/undo_log.rs
@@ -4,7 +4,7 @@ use rustc_data_structures::snapshot_vec as sv;
 use rustc_data_structures::undo_log::{Rollback, UndoLogs};
 use rustc_data_structures::unify as ut;
 use rustc_middle::infer::unify_key::RegionVidKey;
-use rustc_middle::ty;
+use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey};
 
 use crate::{
     infer::{region_constraints, type_variable, InferCtxtInner},
@@ -19,6 +19,7 @@ pub struct Snapshot<'tcx> {
 /// Records the "undo" data for a single operation that affects some form of inference variable.
 #[derive(Clone)]
 pub(crate) enum UndoLog<'tcx> {
+    OpaqueTypes(OpaqueTypeKey<'tcx>, Option<OpaqueHiddenType<'tcx>>),
     TypeVariables(type_variable::UndoLog<'tcx>),
     ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
     IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
@@ -65,6 +66,7 @@ impl_from! {
 impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> {
     fn reverse(&mut self, undo: UndoLog<'tcx>) {
         match undo {
+            UndoLog::OpaqueTypes(key, idx) => self.opaque_type_storage.remove(key, idx),
             UndoLog::TypeVariables(undo) => self.type_variable_storage.reverse(undo),
             UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo),
             UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo),
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index 419ed429246..f3ea83a32b5 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -178,6 +178,12 @@ pub struct QueryResponse<'tcx, R> {
     pub var_values: CanonicalVarValues<'tcx>,
     pub region_constraints: QueryRegionConstraints<'tcx>,
     pub certainty: Certainty,
+    /// List of opaque types which we tried to compare to another type.
+    /// Inside the query we don't know yet whether the opaque type actually
+    /// should get its hidden type inferred. So we bubble the opaque type
+    /// and the type it was compared against upwards and let the query caller
+    /// handle it.
+    pub opaque_types: Vec<(Ty<'tcx>, Ty<'tcx>)>,
     pub value: R,
 }
 
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 00d1370625f..811b9da3740 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -1,7 +1,7 @@
 //! Values computed by queries that use MIR.
 
 use crate::mir::{Body, Promoted};
-use crate::ty::{self, Ty, TyCtxt};
+use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt};
 use rustc_data_structures::stable_map::FxHashMap;
 use rustc_data_structures::vec_map::VecMap;
 use rustc_errors::ErrorGuaranteed;
@@ -242,7 +242,7 @@ pub struct BorrowCheckResult<'tcx> {
     /// All the opaque types that are restricted to concrete types
     /// by this function. Unlike the value in `TypeckResults`, this has
     /// unerased regions.
-    pub concrete_opaque_types: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
+    pub concrete_opaque_types: VecMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
     pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
     pub used_mut_upvars: SmallVec<[Field; 8]>,
     pub tainted_by_errors: Option<ErrorGuaranteed>,
diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs
index 738c48dbb5c..3243ef28ff0 100644
--- a/compiler/rustc_middle/src/ty/_match.rs
+++ b/compiler/rustc_middle/src/ty/_match.rs
@@ -53,17 +53,17 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
         self.relate(a, b)
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn regions(
         &mut self,
         a: ty::Region<'tcx>,
         b: ty::Region<'tcx>,
     ) -> RelateResult<'tcx, ty::Region<'tcx>> {
-        debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
         Ok(a)
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-        debug!("{}.tys({:?}, {:?})", self.tag(), a, b);
         if a == b {
             return Ok(a);
         }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index f51e6c2bc1f..ac9f04ee055 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -33,6 +33,7 @@ use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal};
+use rustc_data_structures::vec_map::VecMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
@@ -485,9 +486,13 @@ pub struct TypeckResults<'tcx> {
     /// this field will be set to `Some(ErrorGuaranteed)`.
     pub tainted_by_errors: Option<ErrorGuaranteed>,
 
-    /// All the opaque types that are restricted to concrete types
-    /// by this function.
-    pub concrete_opaque_types: FxHashSet<DefId>,
+    /// All the opaque types that have hidden types set
+    /// by this function. For return-position-impl-trait we also store the
+    /// type here, so that mir-borrowck can figure out hidden types,
+    /// even if they are only set in dead code (which doesn't show up in MIR).
+    /// For type-alias-impl-trait, this map is only used to prevent query cycles,
+    /// so the hidden types are all `None`.
+    pub concrete_opaque_types: VecMap<DefId, Option<Ty<'tcx>>>,
 
     /// Tracks the minimum captures required for a closure;
     /// see `MinCaptureInformationMap` for more details.
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index 780d380da36..388109e6512 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -1243,15 +1243,11 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
     type BreakTy = FoundFlags;
 
     #[inline]
-    #[instrument(level = "trace")]
-    fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<Self::BreakTy> {
-        debug!(
-            "HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}",
-            t,
-            t.flags(),
-            self.flags
-        );
-        if t.flags().intersects(self.flags) {
+    #[instrument(skip(self), level = "trace")]
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+        let flags = t.flags();
+        trace!(t.flags=?t.flags());
+        if flags.intersects(self.flags) {
             ControlFlow::Break(FoundFlags)
         } else {
             ControlFlow::CONTINUE
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 31db66dc242..44c190e459c 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1057,12 +1057,55 @@ impl<'tcx> InstantiatedPredicates<'tcx> {
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable, TypeFoldable)]
+#[derive(
+    Copy,
+    Clone,
+    Debug,
+    PartialEq,
+    Eq,
+    HashStable,
+    TyEncodable,
+    TyDecodable,
+    TypeFoldable,
+    Lift
+)]
 pub struct OpaqueTypeKey<'tcx> {
     pub def_id: DefId,
     pub substs: SubstsRef<'tcx>,
 }
 
+#[derive(Copy, Clone, Debug, TypeFoldable, HashStable, TyEncodable, TyDecodable)]
+pub struct OpaqueHiddenType<'tcx> {
+    /// The span of this particular definition of the opaque type. So
+    /// for example:
+    ///
+    /// ```ignore (incomplete snippet)
+    /// type Foo = impl Baz;
+    /// fn bar() -> Foo {
+    /// //          ^^^ This is the span we are looking for!
+    /// }
+    /// ```
+    ///
+    /// In cases where the fn returns `(impl Trait, impl Trait)` or
+    /// other such combinations, the result is currently
+    /// over-approximated, but better than nothing.
+    pub span: Span,
+
+    /// The type variable that represents the value of the opaque type
+    /// that we require. In other words, after we compile this function,
+    /// we will be created a constraint like:
+    ///
+    ///     Foo<'a, T> = ?C
+    ///
+    /// where `?C` is the value of this type variable. =) It may
+    /// naturally refer to the type and lifetime parameters in scope
+    /// in this function, though ultimately it should only reference
+    /// those that are arguments to `Foo` in the constraint above. (In
+    /// other words, `?C` should not include `'b`, even though it's a
+    /// lifetime parameter on `foo`.)
+    pub ty: Ty<'tcx>,
+}
+
 rustc_index::newtype_index! {
     /// "Universes" are used during type- and trait-checking in the
     /// presence of `for<..>` binders to control what sets of names are
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 5cfd9a5edfb..fecc5d805fc 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -647,20 +647,23 @@ pub trait PrettyPrinter<'tcx>:
                     return Ok(self);
                 }
 
-                return with_no_queries!({
-                    let def_key = self.tcx().def_key(def_id);
-                    if let Some(name) = def_key.disambiguated_data.data.get_opt_name() {
-                        p!(write("{}", name));
-                        // FIXME(eddyb) print this with `print_def_path`.
-                        if !substs.is_empty() {
-                            p!("::");
-                            p!(generic_delimiters(|cx| cx.comma_sep(substs.iter())));
+                let parent = self.tcx().parent(def_id).expect("opaque types always have a parent");
+                match self.tcx().def_kind(parent) {
+                    DefKind::TyAlias | DefKind::AssocTy => {
+                        if let ty::Opaque(d, _) = *self.tcx().type_of(parent).kind() {
+                            if d == def_id {
+                                // If the type alias directly starts with the `impl` of the
+                                // opaque type we're printing, then skip the `::{opaque#1}`.
+                                p!(print_def_path(parent, substs));
+                                return Ok(self);
+                            }
                         }
+                        // Complex opaque type, e.g. `type Foo = (i32, impl Debug);`
+                        p!(print_def_path(def_id, substs));
                         return Ok(self);
                     }
-
-                    self.pretty_print_opaque_impl_type(def_id, substs)
-                });
+                    _ => return self.pretty_print_opaque_impl_type(def_id, substs),
+                }
             }
             ty::Str => p!("str"),
             ty::Generator(did, substs, movability) => {
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index dc16460ca43..335ddeb66db 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1925,6 +1925,13 @@ impl<'tcx> Ty<'tcx> {
         }
     }
 
+    pub fn expect_opaque_type(self) -> ty::OpaqueTypeKey<'tcx> {
+        match *self.kind() {
+            Opaque(def_id, substs) => ty::OpaqueTypeKey { def_id, substs },
+            _ => bug!("`expect_opaque_type` called on non-opaque type: {}", self),
+        }
+    }
+
     pub fn simd_size_and_type(self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
         match self.kind() {
             Adt(def, substs) => {
diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs
index f98025f7953..679043bdc30 100644
--- a/compiler/rustc_mir_build/src/build/block.rs
+++ b/compiler/rustc_mir_build/src/build/block.rs
@@ -1,8 +1,8 @@
 use crate::build::matches::ArmHasGuard;
 use crate::build::ForGuard::OutsideGuard;
 use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
-use rustc_middle::mir::*;
 use rustc_middle::thir::*;
+use rustc_middle::{mir::*, ty};
 use rustc_span::Span;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
@@ -190,7 +190,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             // This return type is usually `()`, unless the block is diverging, in which case the
             // return type is `!`. For the unit type, we need to actually return the unit, but in
             // the case of `!`, no return value is required, as the block will never return.
-            if destination_ty.is_unit() {
+            // Opaque types of empty bodies also need this unit assignment, in order to infer that their
+            // type is actually unit. Otherwise there will be no defining use found in the MIR.
+            if destination_ty.is_unit() || matches!(destination_ty.kind(), ty::Opaque(..)) {
                 // We only want to assign an implicit `()` as the return value of the block if the
                 // block does not diverge. (Otherwise, we may try to assign a unit to a `!`-type.)
                 this.cfg.push_assign_unit(block, source_info, destination, this.tcx);
diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs
index 9778f77384c..7fd20b45e77 100644
--- a/compiler/rustc_query_system/src/dep_graph/serialized.rs
+++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs
@@ -181,7 +181,6 @@ impl<K: DepKind> EncoderState<K> {
         }
     }
 
-    #[instrument(level = "debug", skip(self, record_graph))]
     fn encode_node(
         &mut self,
         node: &NodeInfo<K>,
@@ -208,7 +207,6 @@ impl<K: DepKind> EncoderState<K> {
             stat.edge_counter += edge_count as u64;
         }
 
-        debug!(?index, ?node);
         let encoder = &mut self.encoder;
         if self.result.is_ok() {
             self.result = node.encode(encoder);
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index c93ff0aa6e2..06287f00fad 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -5,15 +5,14 @@ use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
-use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt};
+use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt};
 use rustc_span::Span;
 
 pub trait InferCtxtExt<'tcx> {
     fn infer_opaque_definition_from_instantiation(
         &self,
         opaque_type_key: OpaqueTypeKey<'tcx>,
-        instantiated_ty: Ty<'tcx>,
-        span: Span,
+        instantiated_ty: OpaqueHiddenType<'tcx>,
     ) -> Ty<'tcx>;
 }
 
@@ -33,7 +32,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
     /// purpose of this function is to do that translation.
     ///
     /// (*) C1 and C2 were introduced in the comments on
-    /// `constrain_opaque_type`. Read that comment for more context.
+    /// `register_member_constraints`. Read that comment for more context.
     ///
     /// # Parameters
     ///
@@ -45,9 +44,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
     fn infer_opaque_definition_from_instantiation(
         &self,
         opaque_type_key: OpaqueTypeKey<'tcx>,
-        instantiated_ty: Ty<'tcx>,
-        span: Span,
+        instantiated_ty: OpaqueHiddenType<'tcx>,
     ) -> Ty<'tcx> {
+        if self.is_tainted_by_errors() {
+            return self.tcx.ty_error();
+        }
+
         let OpaqueTypeKey { def_id, substs } = opaque_type_key;
 
         // Use substs to build up a reverse map from regions to their
@@ -65,13 +67,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         // Convert the type from the function into a type valid outside
         // the function, by replacing invalid regions with 'static,
         // after producing an error for each of them.
-        let definition_ty = instantiated_ty.fold_with(&mut ReverseMapper::new(
+        let definition_ty = instantiated_ty.ty.fold_with(&mut ReverseMapper::new(
             self.tcx,
-            self.is_tainted_by_errors(),
             def_id,
             map,
-            instantiated_ty,
-            span,
+            instantiated_ty.ty,
+            instantiated_ty.span,
         ));
         debug!(?definition_ty);
 
@@ -82,10 +83,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
 struct ReverseMapper<'tcx> {
     tcx: TyCtxt<'tcx>,
 
-    /// If errors have already been reported in this fn, we suppress
-    /// our own errors because they are sometimes derivative.
-    tainted_by_errors: bool,
-
     opaque_type_def_id: DefId,
     map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
     map_missing_regions_to_empty: bool,
@@ -100,7 +97,6 @@ struct ReverseMapper<'tcx> {
 impl<'tcx> ReverseMapper<'tcx> {
     fn new(
         tcx: TyCtxt<'tcx>,
-        tainted_by_errors: bool,
         opaque_type_def_id: DefId,
         map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
         hidden_ty: Ty<'tcx>,
@@ -108,7 +104,6 @@ impl<'tcx> ReverseMapper<'tcx> {
     ) -> Self {
         Self {
             tcx,
-            tainted_by_errors,
             opaque_type_def_id,
             map,
             map_missing_regions_to_empty: false,
@@ -167,9 +162,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
         match self.map.get(&r.into()).map(|k| k.unpack()) {
             Some(GenericArgKind::Lifetime(r1)) => r1,
             Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
-            None if self.map_missing_regions_to_empty || self.tainted_by_errors => {
-                self.tcx.lifetimes.re_root_empty
-            }
+            None if self.map_missing_regions_to_empty => self.tcx.lifetimes.re_root_empty,
             None if generics.parent.is_some() => {
                 if let Some(hidden_ty) = self.hidden_ty.take() {
                     unexpected_hidden_region_diagnostic(
diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs
index a607fb6c1b8..4b6784aee97 100644
--- a/compiler/rustc_trait_selection/src/traits/codegen.rs
+++ b/compiler/rustc_trait_selection/src/traits/codegen.rs
@@ -92,6 +92,12 @@ pub fn codegen_fulfill_obligation<'tcx>(
         });
         let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source);
 
+        // There should be no opaque types during codegen, they all get revealed.
+        let opaque_types = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+        if !opaque_types.is_empty() {
+            bug!("{:#?}", opaque_types);
+        }
+
         debug!("Cache miss: {:?} => {:?}", trait_ref, impl_source);
         Ok(&*tcx.arena.alloc(impl_source))
     })
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 d65b390af34..39da99ac252 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1294,6 +1294,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             ty::Generator(..) => "generator",
             _ => "function",
         };
+        let span = self.tcx.sess.source_map().guess_head_span(span);
         let mut err = struct_span_err!(
             self.tcx.sess,
             span,
@@ -1673,6 +1674,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             ));
 
             let original_span = err.span.primary_span().unwrap();
+            let original_span = self.tcx.sess.source_map().guess_head_span(original_span);
             let mut span = MultiSpan::from_span(original_span);
 
             let message = outer_generator
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index b61e6873571..d4ec677a0b1 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -214,10 +214,21 @@ fn project_and_unify_type<'cx, 'tcx>(
         Err(InProgress) => return Ok(Err(InProgress)),
     };
     debug!(?normalized, ?obligations, "project_and_unify_type result");
-    match infcx
-        .at(&obligation.cause, obligation.param_env)
-        .eq(normalized, obligation.predicate.term)
-    {
+    let actual = obligation.predicate.term;
+    // HACK: lazy TAIT would regress src/test/ui/impl-trait/nested-return-type2.rs, so we add
+    // a back-compat hack hat converts the RPITs into inference vars, just like they were before
+    // lazy TAIT.
+    // This does not affect TAITs in general, as tested in the nested-return-type-tait* tests.
+    let InferOk { value: actual, obligations: new } =
+        selcx.infcx().replace_opaque_types_with_inference_vars(
+            actual,
+            obligation.cause.body_id,
+            obligation.cause.span,
+            obligation.param_env,
+        );
+    obligations.extend(new);
+
+    match infcx.at(&obligation.cause, obligation.param_env).eq(normalized, actual) {
         Ok(InferOk { obligations: inferred_obligations, value: () }) => {
             obligations.extend(inferred_obligations);
             Ok(Ok(Some(obligations)))
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
index 0a85676f431..605c9ace5ed 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -3,7 +3,8 @@ use crate::infer::{InferCtxt, InferOk};
 use crate::traits::engine::TraitEngineExt as _;
 use crate::traits::query::type_op::TypeOpOutput;
 use crate::traits::query::Fallible;
-use crate::traits::{ObligationCause, TraitEngine};
+use crate::traits::TraitEngine;
+use rustc_infer::infer::region_constraints::RegionConstraintData;
 use rustc_infer::traits::TraitEngineExt as _;
 use rustc_span::source_map::DUMMY_SP;
 
@@ -31,6 +32,9 @@ where
     G: Fn() -> String,
 {
     type Output = R;
+    /// We can't do any custom error reporting for `CustomTypeOp`, so
+    /// we can use `!` to enforce that the implementation never provides it.
+    type ErrorInfo = !;
 
     /// Processes the operation and all resulting obligations,
     /// returning the final result along with any region constraints
@@ -40,7 +44,7 @@ where
             info!("fully_perform({:?})", self);
         }
 
-        scrape_region_constraints(infcx, || (self.closure)(infcx))
+        Ok(scrape_region_constraints(infcx, || (self.closure)(infcx))?.0)
     }
 }
 
@@ -55,12 +59,11 @@ where
 
 /// Executes `op` and then scrapes out all the "old style" region
 /// constraints that result, creating query-region-constraints.
-fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
+pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
     infcx: &InferCtxt<'_, 'tcx>,
     op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
-) -> Fallible<TypeOpOutput<'tcx, Op>> {
+) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> {
     let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-    let dummy_body_id = ObligationCause::dummy().body_id;
 
     // During NLL, we expect that nobody will register region
     // obligations **except** as part of a custom type op (and, at the
@@ -75,7 +78,6 @@ fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
     );
 
     let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
-    debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id));
     fulfill_cx.register_predicate_obligations(infcx, obligations);
     let errors = fulfill_cx.select_all_or_error(infcx);
     if !errors.is_empty() {
@@ -99,12 +101,18 @@ fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
     );
 
     if region_constraints.is_empty() {
-        Ok(TypeOpOutput { output: value, constraints: None, canonicalized_query: None })
+        Ok((
+            TypeOpOutput { output: value, constraints: None, error_info: None },
+            region_constraint_data,
+        ))
     } else {
-        Ok(TypeOpOutput {
-            output: value,
-            constraints: Some(Rc::new(region_constraints)),
-            canonicalized_query: None,
-        })
+        Ok((
+            TypeOpOutput {
+                output: value,
+                constraints: Some(Rc::new(region_constraints)),
+                error_info: None,
+            },
+            region_constraint_data,
+        ))
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
index d662f61e2cf..1e72dd69339 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
@@ -28,6 +28,7 @@ pub use rustc_middle::traits::query::type_op::*;
 /// cannot be completed).
 pub trait TypeOp<'tcx>: Sized + fmt::Debug {
     type Output;
+    type ErrorInfo;
 
     /// Processes the operation and all resulting obligations,
     /// returning the final result along with any region constraints
@@ -41,9 +42,8 @@ pub struct TypeOpOutput<'tcx, Op: TypeOp<'tcx>> {
     pub output: Op::Output,
     /// Any region constraints from performing the type op.
     pub constraints: Option<Rc<QueryRegionConstraints<'tcx>>>,
-    /// The canonicalized form of the query.
-    /// This for error reporting to be able to rerun the query.
-    pub canonicalized_query: Option<Canonical<'tcx, Op>>,
+    /// Used for error reporting to be able to rerun the query
+    pub error_info: Option<Op::ErrorInfo>,
 }
 
 /// "Query type ops" are type ops that are implemented using a
@@ -119,10 +119,11 @@ where
     Q: QueryTypeOp<'tcx>,
 {
     type Output = Q::QueryResponse;
+    type ErrorInfo = Canonical<'tcx, ParamEnvAnd<'tcx, Q>>;
 
     fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
         let mut region_constraints = QueryRegionConstraints::default();
-        let (output, canonicalized_query, mut obligations, _) =
+        let (output, error_info, mut obligations, _) =
             Q::fully_perform_into(self, infcx, &mut region_constraints)?;
 
         // Typically, instantiating NLL query results does not
@@ -160,6 +161,6 @@ where
         let region_constraints =
             if region_constraints.is_empty() { None } else { Some(Rc::new(region_constraints)) };
 
-        Ok(TypeOpOutput { output, constraints: region_constraints, canonicalized_query })
+        Ok(TypeOpOutput { output, constraints: region_constraints, error_info })
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 3e7a2252318..cf472813e9e 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -256,6 +256,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         };
 
         if obligation.predicate.skip_binder().self_ty().is_ty_var() {
+            debug!(ty = ?obligation.predicate.skip_binder().self_ty(), "ambiguous inference var or opaque type");
             // Self is a type variable (e.g., `_: AsRef<str>`).
             //
             // This is somewhat problematic, as the current scheme can't really
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 72d156067a1..42f17721f9b 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -33,6 +33,7 @@ use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::thir::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::fast_reject::{self, TreatParams};
+use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
@@ -1313,6 +1314,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
     }
 
+    #[instrument(skip(self, param_env, cache_fresh_trait_pred, dep_node), level = "debug")]
     fn insert_candidate_cache(
         &mut self,
         mut param_env: ty::ParamEnv<'tcx>,
@@ -1353,6 +1355,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     /// a projection, look at the bounds of `T::Bar`, see if we can find a
     /// `Baz` bound. We return indexes into the list returned by
     /// `tcx.item_bounds` for any applicable bounds.
+    #[instrument(level = "debug", skip(self))]
     fn match_projection_obligation_against_definition_bounds(
         &mut self,
         obligation: &TraitObligation<'tcx>,
@@ -1360,10 +1363,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let poly_trait_predicate = self.infcx().resolve_vars_if_possible(obligation.predicate);
         let placeholder_trait_predicate =
             self.infcx().replace_bound_vars_with_placeholders(poly_trait_predicate);
-        debug!(
-            ?placeholder_trait_predicate,
-            "match_projection_obligation_against_definition_bounds"
-        );
+        debug!(?placeholder_trait_predicate);
 
         let tcx = self.infcx.tcx;
         let (def_id, substs) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() {
@@ -1414,7 +1414,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             })
             .collect();
 
-        debug!(?matching_bounds, "match_projection_obligation_against_definition_bounds");
+        debug!(?matching_bounds);
         matching_bounds
     }
 
@@ -1444,6 +1444,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         });
         self.infcx
             .at(&obligation.cause, obligation.param_env)
+            .define_opaque_types(false)
             .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
             .map(|InferOk { obligations: _, value: () }| {
                 // This method is called within a probe, so we can't have
@@ -1506,6 +1507,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let is_match = self
             .infcx
             .at(&obligation.cause, obligation.param_env)
+            .define_opaque_types(false)
             .sup(obligation.predicate, infer_projection)
             .map_or(false, |InferOk { obligations, value: () }| {
                 self.evaluate_predicates_recursively(
@@ -2081,11 +2083,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         match self.match_impl(impl_def_id, obligation) {
             Ok(substs) => substs,
             Err(()) => {
-                bug!(
-                    "Impl {:?} was matchable against {:?} but now is not",
-                    impl_def_id,
-                    obligation
+                self.infcx.tcx.sess.delay_span_bug(
+                    obligation.cause.span,
+                    &format!(
+                        "Impl {:?} was matchable against {:?} but now is not",
+                        impl_def_id, obligation
+                    ),
                 );
+                let value = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id);
+                let err = self.tcx().ty_error();
+                let value = value.fold_with(&mut BottomUpFolder {
+                    tcx: self.tcx(),
+                    ty_op: |_| err,
+                    lt_op: |l| l,
+                    ct_op: |c| c,
+                });
+                Normalized { value, obligations: vec![] }
             }
         }
     }
@@ -2137,6 +2150,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let InferOk { obligations, .. } = self
             .infcx
             .at(&cause, obligation.param_env)
+            .define_opaque_types(false)
             .eq(placeholder_obligation_trait_ref, impl_trait_ref)
             .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?;
         nested_obligations.extend(obligations);
@@ -2220,6 +2234,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
         self.infcx
             .at(&obligation.cause, obligation.param_env)
+            // We don't want predicates for opaque types to just match all other types,
+            // if there is an obligation on the opaque type, then that obligation must be met
+            // opaquely. Otherwise we'd match any obligation to the opaque type and then error
+            // out later.
+            .define_opaque_types(false)
             .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
             .map(|InferOk { obligations, .. }| obligations)
             .map_err(|_| ())
diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs
index 3c2a266dab9..4e19479da87 100644
--- a/compiler/rustc_traits/src/chalk/mod.rs
+++ b/compiler/rustc_traits/src/chalk/mod.rs
@@ -134,6 +134,7 @@ crate fn evaluate_goal<'tcx>(
                 var_values: CanonicalVarValues { var_values },
                 region_constraints: QueryRegionConstraints::default(),
                 certainty: Certainty::Proven,
+                opaque_types: vec![],
                 value: (),
             },
         };
@@ -162,6 +163,7 @@ crate fn evaluate_goal<'tcx>(
                                     .make_identity(tcx),
                                 region_constraints: QueryRegionConstraints::default(),
                                 certainty: Certainty::Ambiguous,
+                                opaque_types: vec![],
                                 value: (),
                             },
                         };
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index e26f0033156..b015e40b683 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -61,6 +61,14 @@ bitflags! {
                                           | TypeFlags::HAS_CT_INFER.bits
                                           | TypeFlags::HAS_TY_PLACEHOLDER.bits
                                           | TypeFlags::HAS_CT_PLACEHOLDER.bits
+                                          // The `evaluate_obligation` query does not return further
+                                          // obligations. If it evaluates an obligation with an opaque
+                                          // type, that opaque type may get compared to another type,
+                                          // constraining it. We would lose this information.
+                                          // FIXME: differentiate between crate-local opaque types
+                                          // and opaque types from other crates, as only opaque types
+                                          // from the local crate can possibly be a local name
+                                          | TypeFlags::HAS_TY_OPAQUE.bits
                                           // We consider 'freshened' types and constants
                                           // to depend on a particular fn.
                                           // The freshening process throws away information,
diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs
index 9529e1528a8..79be8bde55a 100644
--- a/compiler/rustc_typeck/src/check/_match.rs
+++ b/compiler/rustc_typeck/src/check/_match.rs
@@ -4,7 +4,7 @@ use rustc_errors::{Applicability, Diagnostic};
 use rustc_hir::{self as hir, ExprKind};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::traits::Obligation;
-use rustc_middle::ty::{self, ToPredicate, Ty};
+use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable};
 use rustc_span::{MultiSpan, Span};
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::{
@@ -98,8 +98,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
             all_arms_diverge &= self.diverges.get();
 
-            let opt_suggest_box_span =
-                self.opt_suggest_box_span(arm.body.span, arm_ty, orig_expected);
+            let opt_suggest_box_span = self.opt_suggest_box_span(arm_ty, orig_expected);
 
             let (arm_span, semi_span) =
                 self.get_appropriate_arm_semicolon_removal_span(&arms, i, prior_arm_ty, arm_ty);
@@ -504,20 +503,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     // provide a structured suggestion in that case.
     pub(crate) fn opt_suggest_box_span(
         &self,
-        span: Span,
         outer_ty: Ty<'tcx>,
         orig_expected: Expectation<'tcx>,
     ) -> Option<Span> {
-        match (orig_expected, self.ret_coercion_impl_trait.map(|ty| (self.body_id.owner, ty))) {
-            (Expectation::ExpectHasType(expected), Some((_id, ty)))
-                if self.in_tail_expr && self.can_coerce(outer_ty, expected) =>
+        match orig_expected {
+            Expectation::ExpectHasType(expected)
+                if self.in_tail_expr
+                    && self.ret_coercion.as_ref()?.borrow().merged_ty().has_opaque_types()
+                    && self.can_coerce(outer_ty, expected) =>
             {
-                let impl_trait_ret_ty =
-                    self.infcx.instantiate_opaque_types(self.body_id, self.param_env, ty, span);
-                assert!(
-                    impl_trait_ret_ty.obligations.is_empty(),
-                    "we should never get new obligations here"
-                );
                 let obligations = self.fulfillment_cx.borrow().pending_obligations();
                 let mut suggest_box = !obligations.is_empty();
                 for o in obligations {
diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs
index d5187c109e3..2a5cf03e9d0 100644
--- a/compiler/rustc_typeck/src/check/callee.rs
+++ b/compiler/rustc_typeck/src/check/callee.rs
@@ -538,7 +538,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected: Expectation<'tcx>,
         fn_sig: ty::FnSig<'tcx>,
     ) -> Ty<'tcx> {
-        // `fn_sig` is the *signature* of the cosure being called. We
+        // `fn_sig` is the *signature* of the closure being called. We
         // don't know the full details yet (`Fn` vs `FnMut` etc), but we
         // do know the types expected for each argument and the return
         // type.
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index e57d55fdc23..5362ca8d719 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -17,7 +17,7 @@ use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::util::{Discr, IntTypeExt};
-use rustc_middle::ty::{self, OpaqueTypeKey, ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
 use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
 use rustc_span::symbol::sym;
 use rustc_span::{self, MultiSpan, Span};
@@ -83,8 +83,6 @@ pub(super) fn check_fn<'a, 'tcx>(
     can_be_generator: Option<hir::Movability>,
     return_type_pre_known: bool,
 ) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
-    let mut fn_sig = fn_sig;
-
     // Create the function context. This is either derived from scratch or,
     // in the case of closures, based on the outer context.
     let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
@@ -97,21 +95,15 @@ pub(super) fn check_fn<'a, 'tcx>(
 
     let declared_ret_ty = fn_sig.output();
 
-    let revealed_ret_ty =
-        fcx.instantiate_opaque_types_from_value(declared_ret_ty, decl.output.span());
-    debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty);
-    fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty)));
+    let ret_ty =
+        fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(
+            declared_ret_ty,
+            body.value.hir_id,
+            DUMMY_SP,
+            param_env,
+        ));
+    fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
     fcx.ret_type_span = Some(decl.output.span());
-    if let ty::Opaque(..) = declared_ret_ty.kind() {
-        fcx.ret_coercion_impl_trait = Some(declared_ret_ty);
-    }
-    fn_sig = tcx.mk_fn_sig(
-        fn_sig.inputs().iter().cloned(),
-        revealed_ret_ty,
-        fn_sig.c_variadic,
-        fn_sig.unsafety,
-        fn_sig.abi,
-    );
 
     let span = body.value.span;
 
@@ -253,7 +245,7 @@ pub(super) fn check_fn<'a, 'tcx>(
             fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
         debug!("actual_return_ty replaced with {:?}", actual_return_ty);
     }
-    fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty);
+    fcx.demand_suptype(span, declared_ret_ty, actual_return_ty);
 
     // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
     if let Some(panic_impl_did) = tcx.lang_items().panic_impl() {
@@ -656,6 +648,8 @@ fn check_opaque_meets_bounds<'tcx>(
     span: Span,
     origin: &hir::OpaqueTyOrigin,
 ) {
+    let hidden_type = tcx.type_of(def_id).subst(tcx, substs);
+
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
     let defining_use_anchor = match *origin {
         hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
@@ -670,25 +664,13 @@ fn check_opaque_meets_bounds<'tcx>(
 
         let misc_cause = traits::ObligationCause::misc(span, hir_id);
 
-        let _ = inh.register_infer_ok_obligations(
-            infcx.instantiate_opaque_types(hir_id, param_env, opaque_ty, span),
-        );
-
-        let opaque_type_map = infcx.inner.borrow().opaque_types.clone();
-        for (OpaqueTypeKey { def_id, substs }, opaque_defn) in opaque_type_map {
-            let hidden_type = tcx.type_of(def_id).subst(tcx, substs);
-            trace!(?hidden_type);
-            match infcx.at(&misc_cause, param_env).eq(opaque_defn.concrete_ty, hidden_type) {
-                Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok),
-                Err(ty_err) => {
-                    tcx.sess.delay_span_bug(
-                        span,
-                        &format!(
-                            "could not check bounds on revealed type `{}`:\n{}",
-                            hidden_type, ty_err,
-                        ),
-                    );
-                }
+        match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) {
+            Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok),
+            Err(ty_err) => {
+                tcx.sess.delay_span_bug(
+                    span,
+                    &format!("could not unify `{}` with revealed type:\n{}", hidden_type, ty_err,),
+                );
             }
         }
 
@@ -701,7 +683,7 @@ fn check_opaque_meets_bounds<'tcx>(
 
         match origin {
             // Checked when type checking the function containing them.
-            hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => return,
+            hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
             // Can have different predicates to their defining use
             hir::OpaqueTyOrigin::TyAlias => {
                 // Finally, resolve all regions. This catches wily misuses of
@@ -710,6 +692,9 @@ fn check_opaque_meets_bounds<'tcx>(
                 fcx.regionck_item(hir_id, span, FxHashSet::default());
             }
         }
+
+        // Clean up after ourselves
+        let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
     });
 }
 
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index 59c8febdc30..2f5f804c56f 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -3,6 +3,7 @@
 use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
 
 use crate::astconv::AstConv;
+use crate::rustc_middle::ty::subst::Subst;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
@@ -13,6 +14,7 @@ use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::source_map::Span;
+use rustc_span::DUMMY_SP;
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits::error_reporting::ArgKind;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
@@ -172,6 +174,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected_ty: Ty<'tcx>,
     ) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
         match *expected_ty.kind() {
+            ty::Opaque(def_id, substs) => {
+                let bounds = self.tcx.explicit_item_bounds(def_id);
+                let sig = bounds.iter().find_map(|(pred, span)| match pred.kind().skip_binder() {
+                    ty::PredicateKind::Projection(proj_predicate) => self
+                        .deduce_sig_from_projection(
+                            Some(*span),
+                            pred.kind().rebind(proj_predicate.subst(self.tcx, substs)),
+                        ),
+                    _ => None,
+                });
+
+                let kind = bounds
+                    .iter()
+                    .filter_map(|(pred, _)| match pred.kind().skip_binder() {
+                        ty::PredicateKind::Trait(tp) => {
+                            self.tcx.fn_trait_kind_from_lang_item(tp.def_id())
+                        }
+                        _ => None,
+                    })
+                    .fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
+                trace!(?sig, ?kind);
+                (sig, kind)
+            }
             ty::Dynamic(ref object_type, ..) => {
                 let sig = object_type.projection_bounds().find_map(|pb| {
                     let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self);
@@ -197,10 +222,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
         let expected_sig =
             self.obligations_for_self_ty(expected_vid).find_map(|(_, obligation)| {
-                debug!(
-                    "deduce_expectations_from_obligations: obligation.predicate={:?}",
-                    obligation.predicate
-                );
+                debug!(?obligation.predicate);
 
                 let bound_predicate = obligation.predicate.kind();
                 if let ty::PredicateKind::Projection(proj_predicate) =
@@ -235,6 +257,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// The `cause_span` should be the span that caused us to
     /// have this expected signature, or `None` if we can't readily
     /// know that.
+    #[instrument(level = "debug", skip(self, cause_span))]
     fn deduce_sig_from_projection(
         &self,
         cause_span: Option<Span>,
@@ -242,15 +265,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> Option<ExpectedSig<'tcx>> {
         let tcx = self.tcx;
 
-        debug!("deduce_sig_from_projection({:?})", projection);
-
         let trait_def_id = projection.trait_def_id(tcx);
 
         let is_fn = tcx.fn_trait_kind_from_lang_item(trait_def_id).is_some();
         let gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span);
         let is_gen = gen_trait == trait_def_id;
         if !is_fn && !is_gen {
-            debug!("deduce_sig_from_projection: not fn or generator");
+            debug!("not fn or generator");
             return None;
         }
 
@@ -259,7 +280,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // associated item and not yield.
             let return_assoc_item = self.tcx.associated_item_def_ids(gen_trait)[1];
             if return_assoc_item != projection.projection_def_id() {
-                debug!("deduce_sig_from_projection: not return assoc item of generator");
+                debug!("not return assoc item of generator");
                 return None;
             }
         }
@@ -267,7 +288,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let input_tys = if is_fn {
             let arg_param_ty = projection.skip_binder().projection_ty.substs.type_at(1);
             let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty);
-            debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty);
+            debug!(?arg_param_ty);
 
             match arg_param_ty.kind() {
                 &ty::Tuple(tys) => tys,
@@ -282,7 +303,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // Since this is a return parameter type it is safe to unwrap.
         let ret_param_ty = projection.skip_binder().term.ty().unwrap();
         let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty);
-        debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty);
+        debug!(?ret_param_ty);
 
         let sig = projection.rebind(self.tcx.mk_fn_sig(
             input_tys.iter(),
@@ -291,7 +312,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             hir::Unsafety::Normal,
             Abi::Rust,
         ));
-        debug!("deduce_sig_from_projection: sig={:?}", sig);
+        debug!(?sig);
 
         Some(ExpectedSig { cause_span, sig })
     }
@@ -401,9 +422,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // in this binder we are creating.
         assert!(!expected_sig.sig.skip_binder().has_vars_bound_above(ty::INNERMOST));
         let bound_sig = expected_sig.sig.map_bound(|sig| {
+            let output = self.hide_parent_opaque_types(
+                sig.output(),
+                expected_sig.cause_span.unwrap_or(DUMMY_SP),
+                body.id().hir_id,
+            );
             self.tcx.mk_fn_sig(
                 sig.inputs().iter().cloned(),
-                sig.output(),
+                output,
                 sig.c_variadic,
                 hir::Unsafety::Normal,
                 Abi::RustCall,
@@ -590,6 +616,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 _ => astconv.ty_infer(None, decl.output.span()),
             },
         };
+        let supplied_return =
+            self.hide_parent_opaque_types(supplied_return, decl.output.span(), body.id().hir_id);
 
         let result = ty::Binder::bind_with_vars(
             self.tcx.mk_fn_sig(
@@ -610,27 +638,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         result
     }
 
+    fn hide_parent_opaque_types(&self, ty: Ty<'tcx>, span: Span, body_id: hir::HirId) -> Ty<'tcx> {
+        let InferOk { value, obligations } =
+            self.replace_opaque_types_with_inference_vars(ty, body_id, span, self.param_env);
+        self.register_predicates(obligations);
+        value
+    }
+
     /// Invoked when we are translating the generator that results
     /// from desugaring an `async fn`. Returns the "sugared" return
     /// type of the `async fn` -- that is, the return type that the
     /// user specified. The "desugared" return type is an `impl
     /// Future<Output = T>`, so we do this by searching through the
     /// obligations to extract the `T`.
+    #[instrument(skip(self), level = "debug")]
     fn deduce_future_output_from_obligations(&self, expr_def_id: DefId) -> Option<Ty<'tcx>> {
-        debug!("deduce_future_output_from_obligations(expr_def_id={:?})", expr_def_id);
-
         let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| {
             span_bug!(self.tcx.def_span(expr_def_id), "async fn generator outside of a fn")
         });
 
-        // In practice, the return type of the surrounding function is
-        // always a (not yet resolved) inference variable, because it
-        // is the hidden type for an `impl Trait` that we are going to
-        // be inferring.
         let ret_ty = ret_coercion.borrow().expected_ty();
         let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
-        let ret_vid = match *ret_ty.kind() {
-            ty::Infer(ty::TyVar(ret_vid)) => ret_vid,
+        let (def_id, substs) = match *ret_ty.kind() {
+            ty::Opaque(def_id, substs) => (def_id, substs),
             ty::Error(_) => return None,
             _ => span_bug!(
                 self.tcx.def_span(expr_def_id),
@@ -638,17 +668,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ),
         };
 
+        let item_bounds = self.tcx.explicit_item_bounds(def_id);
+
         // Search for a pending obligation like
         //
         // `<R as Future>::Output = T`
         //
         // where R is the return type we are expecting. This type `T`
         // will be our output.
-        let output_ty = self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| {
-            let bound_predicate = obligation.predicate.kind();
+        let output_ty = item_bounds.iter().find_map(|&(predicate, span)| {
+            let bound_predicate = predicate.subst(self.tcx, substs).kind();
             if let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder() {
                 self.deduce_future_output_from_projection(
-                    obligation.cause.span,
+                    span,
                     bound_predicate.rebind(proj_predicate),
                 )
             } else {
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index c0eda02a999..2f973a54f88 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -1272,7 +1272,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
 
     /// Returns the current "merged type", representing our best-guess
     /// at the LUB of the expressions we've seen so far (if any). This
-    /// isn't *final* until you call `self.final()`, which will return
+    /// isn't *final* until you call `self.complete()`, which will return
     /// the merged type.
     pub fn merged_ty(&self) -> Ty<'tcx> {
         self.final_ty.unwrap_or(self.expected_ty)
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index e5784259ce8..81cebaef3aa 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -965,8 +965,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             };
             let else_diverges = self.diverges.get();
 
-            let opt_suggest_box_span =
-                self.opt_suggest_box_span(else_expr.span, else_ty, orig_expected);
+            let opt_suggest_box_span = self.opt_suggest_box_span(else_ty, orig_expected);
             let if_cause =
                 self.if_cause(sp, then_expr, else_expr, then_ty, else_ty, opt_suggest_box_span);
 
diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs
index 7214cdf3312..85132317824 100644
--- a/compiler/rustc_typeck/src/check/fallback.rs
+++ b/compiler/rustc_typeck/src/check/fallback.rs
@@ -24,7 +24,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
             self.fulfillment_cx.borrow_mut().pending_obligations()
         );
 
-        // Check if we have any unsolved varibales. If not, no need for fallback.
+        // Check if we have any unsolved variables. If not, no need for fallback.
         let unsolved_variables = self.unsolved_variables();
         if unsolved_variables.is_empty() {
             return false;
@@ -66,16 +66,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
         // refer to opaque types.
         self.select_obligations_where_possible(fallback_has_occurred, |_| {});
 
-        // We now run fallback again, but this time we allow it to replace
-        // unconstrained opaque type variables, in addition to performing
-        // other kinds of fallback.
-        for ty in &self.unsolved_variables() {
-            fallback_has_occurred |= self.fallback_opaque_type_vars(*ty);
-        }
-
-        // See if we can make any more progress.
-        self.select_obligations_where_possible(fallback_has_occurred, |_| {});
-
         fallback_has_occurred
     }
 
@@ -136,59 +126,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
         true
     }
 
-    /// Second round of fallback: Unconstrained type variables created
-    /// from the instantiation of an opaque type fall back to the
-    /// opaque type itself. This is a somewhat incomplete attempt to
-    /// manage "identity passthrough" for `impl Trait` types.
-    ///
-    /// For example, in this code:
-    ///
-    ///```
-    /// type MyType = impl Copy;
-    /// fn defining_use() -> MyType { true }
-    /// fn other_use() -> MyType { defining_use() }
-    /// ```
-    ///
-    /// `defining_use` will constrain the instantiated inference
-    /// variable to `bool`, while `other_use` will constrain
-    /// the instantiated inference variable to `MyType`.
-    ///
-    /// When we process opaque types during writeback, we
-    /// will handle cases like `other_use`, and not count
-    /// them as defining usages
-    ///
-    /// However, we also need to handle cases like this:
-    ///
-    /// ```rust
-    /// pub type Foo = impl Copy;
-    /// fn produce() -> Option<Foo> {
-    ///     None
-    ///  }
-    ///  ```
-    ///
-    /// In the above snippet, the inference variable created by
-    /// instantiating `Option<Foo>` will be completely unconstrained.
-    /// We treat this as a non-defining use by making the inference
-    /// variable fall back to the opaque type itself.
-    fn fallback_opaque_type_vars(&self, ty: Ty<'tcx>) -> bool {
-        let span = self
-            .infcx
-            .type_var_origin(ty)
-            .map(|origin| origin.span)
-            .unwrap_or(rustc_span::DUMMY_SP);
-        let oty = self.inner.borrow().opaque_types_vars.get(&ty).copied();
-        if let Some(opaque_ty) = oty {
-            debug!(
-                "fallback_opaque_type_vars(ty={:?}): falling back to opaque type {:?}",
-                ty, opaque_ty
-            );
-            self.demand_eqtype(span, ty, opaque_ty);
-            true
-        } else {
-            return false;
-        }
-    }
-
     /// The "diverging fallback" system is rather complicated. This is
     /// a result of our need to balance 'do the right thing' with
     /// backwards compatibility.
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index e3439a6f1d9..bb3bfbb7dd1 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -372,23 +372,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         (result, spans)
     }
 
-    /// Replaces the opaque types from the given value with type variables,
-    /// and records the `OpaqueTypeMap` for later use during writeback. See
-    /// `InferCtxt::instantiate_opaque_types` for more details.
-    #[instrument(skip(self, value_span), level = "debug")]
-    pub(in super::super) fn instantiate_opaque_types_from_value<T: TypeFoldable<'tcx>>(
-        &self,
-        value: T,
-        value_span: Span,
-    ) -> T {
-        self.register_infer_ok_obligations(self.instantiate_opaque_types(
-            self.body_id,
-            self.param_env,
-            value,
-            value_span,
-        ))
-    }
-
     /// Convenience method which tracks extra diagnostic information for normalization
     /// that occurs as a result of WF checking. The `hir_id` is the `HirId` of the hir item
     /// whose type is being wf-checked - this is used to construct a more precise span if
@@ -775,6 +758,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> Vec<Ty<'tcx>> {
         let formal_ret = self.resolve_vars_with_obligations(formal_ret);
         let Some(ret_ty) = expected_ret.only_has_type(self) else { return Vec::new() };
+
+        // HACK(oli-obk): This is a hack to keep RPIT and TAIT in sync wrt their behaviour.
+        // Without it, the inference
+        // variable will get instantiated with the opaque type. The inference variable often
+        // has various helpful obligations registered for it that help closures figure out their
+        // signature. If we infer the inference var to the opaque type, the closure won't be able
+        // to find those obligations anymore, and it can't necessarily find them from the opaque
+        // type itself. We could be more powerful with inference if we *combined* the obligations
+        // so that we got both the obligations from the opaque type and the ones from the inference
+        // variable. That will accept more code than we do right now, so we need to carefully consider
+        // the implications.
+        // Note: this check is pessimistic, as the inference type could be matched with something other
+        // than the opaque type, but then we need a new `TypeRelation` just for this specific case and
+        // can't re-use `sup` below.
+        // See src/test/ui/impl-trait/hidden-type-is-opaque.rs and
+        // src/test/ui/impl-trait/hidden-type-is-opaque-2.rs for examples that hit this path.
+        if formal_ret.has_infer_types() {
+            for ty in ret_ty.walk() {
+                if let ty::subst::GenericArgKind::Type(ty) = ty.unpack() {
+                    if let ty::Opaque(def_id, _) = *ty.kind() {
+                        if self.infcx.opaque_type_origin(def_id, DUMMY_SP).is_some() {
+                            return Vec::new();
+                        }
+                    }
+                }
+            }
+        }
+
         let expect_args = self
             .fudge_inference_if_ok(|| {
                 // Attempt to apply a subtyping relationship between the formal
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
index 222c14d0d47..6c55f821294 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
@@ -57,8 +57,6 @@ pub struct FnCtxt<'a, 'tcx> {
     /// any).
     pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
 
-    pub(super) ret_coercion_impl_trait: Option<Ty<'tcx>>,
-
     pub(super) ret_type_span: Option<Span>,
 
     /// Used exclusively to reduce cost of advanced evaluation used for
@@ -130,7 +128,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             param_env,
             err_count_on_creation: inh.tcx.sess.err_count(),
             ret_coercion: None,
-            ret_coercion_impl_trait: None,
             ret_type_span: None,
             in_tail_expr: false,
             ret_coercion_span: Cell::new(None),
diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs
index beb6b371b2b..b775f24f8ef 100644
--- a/compiler/rustc_typeck/src/check/inherited.rs
+++ b/compiler/rustc_typeck/src/check/inherited.rs
@@ -95,6 +95,13 @@ impl<'tcx> InheritedBuilder<'tcx> {
         let def_id = self.def_id;
         self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id)))
     }
+
+    /// WF-checking doesn't need to recompute opaque types and can instead use
+    /// the type_of query to get them from typeck.
+    pub fn reveal_defining_opaque_types(mut self) -> Self {
+        self.infcx = self.infcx.reveal_defining_opaque_types();
+        self
+    }
 }
 
 impl<'a, 'tcx> Inherited<'a, 'tcx> {
@@ -119,8 +126,8 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
     pub(super) fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) {
-        debug!("register_predicate({:?})", obligation);
         if obligation.has_escaping_bound_vars() {
             span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation);
         }
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index 704866c2cc2..abdce9f5866 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -1476,6 +1476,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             TraitCandidate(trait_ref) => self.probe(|_| {
                 let _ = self
                     .at(&ObligationCause::dummy(), self.param_env)
+                    .define_opaque_types(false)
                     .sup(candidate.xform_self_ty, self_ty);
                 match self.select_trait_candidate(trait_ref) {
                     Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => {
@@ -1505,6 +1506,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             // First check that the self type can be related.
             let sub_obligations = match self
                 .at(&ObligationCause::dummy(), self.param_env)
+                .define_opaque_types(false)
                 .sup(probe.xform_self_ty, self_ty)
             {
                 Ok(InferOk { obligations, value: () }) => obligations,
@@ -1655,6 +1657,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     );
                     if self
                         .at(&ObligationCause::dummy(), self.param_env)
+                        .define_opaque_types(false)
                         .sup(return_ty, xform_ret_ty)
                         .is_err()
                     {
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index 31cc3fa2ac6..b6111793678 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -343,6 +343,7 @@ fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::T
     typeck_with_fallback(tcx, def_id, fallback)
 }
 
+#[instrument(skip(tcx, fallback))]
 fn typeck_with_fallback<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: LocalDefId,
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index 7106f8f9d7a..70bc46c5123 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -335,11 +335,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     // Returns a list of `Ty`s for each upvar.
     fn final_upvar_tys(&self, closure_id: DefId) -> Vec<Ty<'tcx>> {
-        // Presently an unboxed closure type cannot "escape" out of a
-        // function, so we will only encounter ones that originated in the
-        // local crate or were inlined into it along with some function.
-        // This may change if abstract return types of some sort are
-        // implemented.
         self.typeck_results
             .borrow()
             .closure_min_captures_flattened(closure_id)
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index d6eeef3323c..250576bff04 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -968,7 +968,7 @@ fn for_item<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'_>) -> CheckWfFcxBuilder<
 
 fn for_id(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> CheckWfFcxBuilder<'_> {
     CheckWfFcxBuilder {
-        inherited: Inherited::build(tcx, def_id),
+        inherited: Inherited::build(tcx, def_id).reveal_defining_opaque_types(),
         id: hir::HirId::make_owner(def_id),
         span,
         param_env: tcx.param_env(def_id),
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index c1cb9a1a8d1..ecbd1e46349 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -18,9 +18,9 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
 use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
-use rustc_trait_selection::opaque_types::InferCtxtExt;
 
 use std::mem;
+use std::ops::ControlFlow;
 
 ///////////////////////////////////////////////////////////////////////////
 // Entry point
@@ -65,7 +65,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         wbcx.visit_closures();
         wbcx.visit_liberated_fn_sigs();
         wbcx.visit_fru_field_types();
-        wbcx.visit_opaque_types(body.value.span);
+        wbcx.visit_opaque_types();
         wbcx.visit_coercion_casts();
         wbcx.visit_user_provided_tys();
         wbcx.visit_user_provided_sigs();
@@ -497,64 +497,39 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
             fcx_typeck_results.generator_interior_types.clone();
     }
 
-    #[instrument(skip(self, span), level = "debug")]
-    fn visit_opaque_types(&mut self, span: Span) {
-        let opaque_types = self.fcx.infcx.inner.borrow().opaque_types.clone();
-        for (opaque_type_key, opaque_defn) in opaque_types {
-            let hir_id =
-                self.tcx().hir().local_def_id_to_hir_id(opaque_type_key.def_id.expect_local());
-            let instantiated_ty = self.resolve(opaque_defn.concrete_ty, &hir_id);
-
-            debug_assert!(!instantiated_ty.has_escaping_bound_vars());
-
-            let opaque_type_key = self.fcx.fully_resolve(opaque_type_key).unwrap();
-
-            // Prevent:
-            // * `fn foo<T>() -> Foo<T>`
-            // * `fn foo<T: Bound + Other>() -> Foo<T>`
-            // from being defining.
-
-            // Also replace all generic params with the ones from the opaque type
-            // definition so that
-            // ```rust
-            // type Foo<T> = impl Baz + 'static;
-            // fn foo<U>() -> Foo<U> { .. }
-            // ```
-            // figures out the concrete type with `U`, but the stored type is with `T`.
-
-            // FIXME: why are we calling this here? This seems too early, and duplicated.
-            let definition_ty = self.fcx.infer_opaque_definition_from_instantiation(
-                opaque_type_key,
-                instantiated_ty,
-                span,
-            );
-
-            let mut skip_add = false;
-
-            if let ty::Opaque(definition_ty_def_id, _substs) = *definition_ty.kind() {
-                if opaque_defn.origin == hir::OpaqueTyOrigin::TyAlias {
-                    if opaque_type_key.def_id == definition_ty_def_id {
-                        debug!(
-                            "skipping adding concrete definition for opaque type {:?} {:?}",
-                            opaque_defn, opaque_type_key.def_id
-                        );
-                        skip_add = true;
+    #[instrument(skip(self), level = "debug")]
+    fn visit_opaque_types(&mut self) {
+        let opaque_types =
+            self.fcx.infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+        for (opaque_type_key, decl) in opaque_types {
+            let hidden_type = match decl.origin {
+                hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => {
+                    let ty = self.resolve(decl.hidden_type.ty, &decl.hidden_type.span);
+                    struct RecursionChecker {
+                        def_id: DefId,
+                    }
+                    impl<'tcx> ty::TypeVisitor<'tcx> for RecursionChecker {
+                        type BreakTy = ();
+                        fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+                            if let ty::Opaque(def_id, _) = *t.kind() {
+                                if def_id == self.def_id {
+                                    return ControlFlow::Break(());
+                                }
+                            }
+                            t.super_visit_with(self)
+                        }
                     }
+                    if ty
+                        .visit_with(&mut RecursionChecker { def_id: opaque_type_key.def_id })
+                        .is_break()
+                    {
+                        return;
+                    }
+                    Some(ty)
                 }
-            }
-
-            if opaque_type_key.substs.needs_infer() {
-                span_bug!(span, "{:#?} has inference variables", opaque_type_key.substs)
-            }
-
-            // We only want to add an entry into `concrete_opaque_types`
-            // if we actually found a defining usage of this opaque type.
-            // Otherwise, we do nothing - we'll either find a defining usage
-            // in some other location, or we'll end up emitting an error due
-            // to the lack of defining usage
-            if !skip_add {
-                self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id);
-            }
+                hir::OpaqueTyOrigin::TyAlias => None,
+            };
+            self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type);
         }
     }
 
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index d422f355ad3..95d1b6a15f5 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -8,7 +8,7 @@ use rustc_hir::{HirId, Node};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::util::IntTypeExt;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder};
+use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder};
 use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
 
@@ -358,29 +358,24 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                         .concrete_opaque_types
                         .get_value_matching(|(key, _)| key.def_id == def_id.to_def_id())
                         .copied()
+                        .map(|concrete| concrete.ty)
                         .unwrap_or_else(|| {
-                            tcx.sess.delay_span_bug(
-                                DUMMY_SP,
-                                &format!(
-                                    "owner {:?} has no opaque type for {:?} in its typeck results",
-                                    owner, def_id,
-                                ),
-                            );
-                            if let Some(_) =
-                                tcx.typeck(owner).tainted_by_errors
-                            {
+                            let table = tcx.typeck(owner);
+                            if let Some(_) = table.tainted_by_errors {
                                 // Some error in the
                                 // owner fn prevented us from populating
                                 // the `concrete_opaque_types` table.
                                 tcx.ty_error()
                             } else {
-                                // We failed to resolve the opaque type or it
-                                // resolves to itself. Return the non-revealed
-                                // type, which should result in E0720.
-                                tcx.mk_opaque(
-                                    def_id.to_def_id(),
-                                    InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
-                                )
+                                table.concrete_opaque_types.get(&def_id.to_def_id()).copied().unwrap_or_else(|| {
+                                    // We failed to resolve the opaque type or it
+                                    // resolves to itself. We interpret this as the
+                                    // no values of the hidden type ever being constructed,
+                                    // so we can just make the hidden type be `!`.
+                                    // For backwards compatibility reasons, we fall back to
+                                    // `()` until we the diverging default is changed.
+                                    Some(tcx.mk_diverging_default())
+                                }).expect("RPIT always have a hidden type from typeck")
                             }
                         });
                     debug!("concrete_ty = {:?}", concrete_ty);
@@ -562,7 +557,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
         /// with the first type that we find, and then later types are
         /// checked against it (we also carry the span of that first
         /// type).
-        found: Option<(Span, Ty<'tcx>)>,
+        found: Option<ty::OpaqueHiddenType<'tcx>>,
     }
 
     impl ConstraintLocator<'_> {
@@ -575,14 +570,28 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
             }
             // Calling `mir_borrowck` can lead to cycle errors through
             // const-checking, avoid calling it if we don't have to.
-            if !self.tcx.typeck(def_id).concrete_opaque_types.contains(&self.def_id) {
+            // ```rust
+            // type Foo = impl Fn() -> usize; // when computing type for this
+            // const fn bar() -> Foo {
+            //     || 0usize
+            // }
+            // const BAZR: Foo = bar(); // we would mir-borrowck this, causing cycles
+            // // because we again need to reveal `Foo` so we can check whether the
+            // // constant does not contain interior mutability.
+            // ```
+            let tables = self.tcx.typeck(def_id);
+            if let Some(_) = tables.tainted_by_errors {
+                self.found = Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error() });
+                return;
+            }
+            if tables.concrete_opaque_types.get(&self.def_id).is_none() {
                 debug!("no constraints in typeck results");
                 return;
             }
             // Use borrowck to get the type with unerased regions.
             let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types;
             debug!(?concrete_opaque_types);
-            for (opaque_type_key, concrete_type) in concrete_opaque_types {
+            for &(opaque_type_key, concrete_type) in concrete_opaque_types {
                 if opaque_type_key.def_id != self.def_id {
                     // Ignore constraints for other opaque types.
                     continue;
@@ -590,26 +599,26 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
 
                 debug!(?concrete_type, ?opaque_type_key.substs, "found constraint");
 
-                // FIXME(oli-obk): trace the actual span from inference to improve errors.
-                let span = self.tcx.def_span(def_id);
-
-                if let Some((prev_span, prev_ty)) = self.found {
-                    if *concrete_type != prev_ty && !(*concrete_type, prev_ty).references_error() {
-                        debug!(?span);
+                if let Some(prev) = self.found {
+                    if concrete_type.ty != prev.ty && !(concrete_type, prev).references_error() {
                         // Found different concrete types for the opaque type.
                         let mut err = self.tcx.sess.struct_span_err(
-                            span,
+                            concrete_type.span,
                             "concrete type differs from previous defining opaque type use",
                         );
                         err.span_label(
-                            span,
-                            format!("expected `{}`, got `{}`", prev_ty, concrete_type),
+                            concrete_type.span,
+                            format!("expected `{}`, got `{}`", prev.ty, concrete_type.ty),
                         );
-                        err.span_note(prev_span, "previous use here");
+                        if prev.span == concrete_type.span {
+                            err.span_label(prev.span, "this expression supplies two conflicting concrete types for the same opaque type");
+                        } else {
+                            err.span_note(prev.span, "previous use here");
+                        }
                         err.emit();
                     }
                 } else {
-                    self.found = Some((span, *concrete_type));
+                    self.found = Some(concrete_type);
                 }
             }
         }
@@ -629,7 +638,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
             intravisit::walk_expr(self, ex);
         }
         fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
-            debug!("find_existential_constraints: visiting {:?}", it);
+            trace!(?it.def_id);
             // The opaque type itself or its children are not within its reveal scope.
             if it.def_id.to_def_id() != self.def_id {
                 self.check(it.def_id);
@@ -637,7 +646,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
             }
         }
         fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
-            debug!("find_existential_constraints: visiting {:?}", it);
+            trace!(?it.def_id);
             // The opaque type itself or its children are not within its reveal scope.
             if it.def_id.to_def_id() != self.def_id {
                 self.check(it.def_id);
@@ -645,7 +654,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
             }
         }
         fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
-            debug!("find_existential_constraints: visiting {:?}", it);
+            trace!(?it.def_id);
             self.check(it.def_id);
             intravisit::walk_trait_item(self, it);
         }
@@ -655,12 +664,12 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
     let scope = tcx.hir().get_defining_scope(hir_id);
     let mut locator = ConstraintLocator { def_id: def_id.to_def_id(), tcx, found: None };
 
-    debug!("find_opaque_ty_constraints: scope={:?}", scope);
+    debug!(?scope);
 
     if scope == hir::CRATE_HIR_ID {
         tcx.hir().walk_toplevel_module(&mut locator);
     } else {
-        debug!("find_opaque_ty_constraints: scope={:?}", tcx.hir().get(scope));
+        trace!("scope={:#?}", tcx.hir().get(scope));
         match tcx.hir().get(scope) {
             // We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods
             // This allows our visitor to process the defining item itself, causing
@@ -684,10 +693,15 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
     }
 
     match locator.found {
-        Some((_, ty)) => ty,
+        Some(hidden) => hidden.ty,
         None => {
             let span = tcx.def_span(def_id);
-            tcx.sess.span_err(span, "could not find defining uses");
+            let name = tcx.item_name(tcx.parent(def_id.to_def_id()).unwrap());
+            let label = format!(
+                "`{}` must be used in combination with a concrete type within the same module",
+                name
+            );
+            tcx.sess.struct_span_err(span, "unconstrained opaque type").note(&label).emit();
             tcx.ty_error()
         }
     }
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index 7105a2457e2..d9467e8fd6b 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -147,6 +147,12 @@ fn main() {
         cmd.arg("-Z").arg("force-unstable-if-unmarked");
     }
 
+    if let Ok(flags) = env::var("MAGIC_EXTRA_RUSTFLAGS") {
+        for flag in flags.split(' ') {
+            cmd.arg(flag);
+        }
+    }
+
     let is_test = args.iter().any(|a| a == "--test");
     if verbose > 2 {
         let rust_env_vars =
diff --git a/src/test/incremental/hashes/function_interfaces.rs b/src/test/incremental/hashes/function_interfaces.rs
index 4124eada188..31564a0cbd5 100644
--- a/src/test/incremental/hashes/function_interfaces.rs
+++ b/src/test/incremental/hashes/function_interfaces.rs
@@ -305,7 +305,7 @@ pub fn return_impl_trait() -> i32        {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, typeck, fn_sig")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, typeck, fn_sig, optimized_mir")]
 #[rustc_clean(cfg = "cfail3")]
 #[rustc_clean(cfg = "cfail5", except = "hir_owner, hir_owner_nodes, typeck, fn_sig, optimized_mir")]
 #[rustc_clean(cfg = "cfail6")]
diff --git a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs
index 4c36289f47b..67b97c21805 100644
--- a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs
+++ b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs
@@ -30,7 +30,7 @@ impl Thing for AssocNoCopy {
     type Out = Box<dyn Bar<Assoc: Copy>>;
 
     fn func() -> Self::Out {
-        //~^ ERROR the trait bound `String: Copy` is not satisfied
         Box::new(AssocNoCopy)
+        //~^ ERROR the trait bound `String: Copy` is not satisfied
     }
 }
diff --git a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr
index a32ab453152..f1dcd34066d 100644
--- a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr
+++ b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr
@@ -1,8 +1,10 @@
 error[E0277]: the trait bound `String: Copy` is not satisfied
-  --> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:32:18
+  --> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:33:9
    |
-LL |     fn func() -> Self::Out {
-   |                  ^^^^^^^^^ the trait `Copy` is not implemented for `String`
+LL |         Box::new(AssocNoCopy)
+   |         ^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
+   |
+   = note: required for the cast to the object type `dyn Bar<Assoc = <AssocNoCopy as Thing>::Out::{opaque#0}>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/impl-trait-return-missing-constraint.rs b/src/test/ui/associated-types/impl-trait-return-missing-constraint.rs
index 5f994f26534..ef0443034ec 100644
--- a/src/test/ui/associated-types/impl-trait-return-missing-constraint.rs
+++ b/src/test/ui/associated-types/impl-trait-return-missing-constraint.rs
@@ -23,7 +23,8 @@ fn bar() -> impl Bar {
 }
 
 fn baz() -> impl Bar<Item = i32> {
-//~^ ERROR type mismatch resolving `<impl Bar as Foo>::Item == i32`
+    //~^ ERROR type mismatch resolving `<impl Bar as Foo>::Item == i32`
+    //~| ERROR type mismatch resolving `<impl Bar as Foo>::Item == i32`
     bar()
 }
 
diff --git a/src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr b/src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr
index 283ecea735d..b7c49570ca4 100644
--- a/src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr
+++ b/src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr
@@ -2,18 +2,43 @@ error[E0271]: type mismatch resolving `<impl Bar as Foo>::Item == i32`
   --> $DIR/impl-trait-return-missing-constraint.rs:25:13
    |
 LL | fn bar() -> impl Bar {
-   |             -------- the found opaque type
+   |             -------- the expected opaque type
 ...
 LL | fn baz() -> impl Bar<Item = i32> {
-   |             ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found associated type
+   |             ^^^^^^^^^^^^^^^^^^^^ expected associated type, found `i32`
    |
-   = note:         expected type `i32`
-           found associated type `<impl Bar as Foo>::Item`
+   = note: expected associated type `<impl Bar as Foo>::Item`
+                         found type `i32`
+   = help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32` or calling a method that returns `<impl Bar as Foo>::Item`
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32`
    |
 LL | fn bar() -> impl Bar<Item = i32> {
    |                     ++++++++++++
 
-error: aborting due to previous error
+error[E0271]: type mismatch resolving `<impl Bar as Foo>::Item == i32`
+  --> $DIR/impl-trait-return-missing-constraint.rs:25:34
+   |
+LL |   fn bar() -> impl Bar {
+   |               -------- the expected opaque type
+...
+LL |   fn baz() -> impl Bar<Item = i32> {
+   |  __________________________________^
+LL | |
+LL | |
+LL | |     bar()
+LL | | }
+   | |_^ expected associated type, found `i32`
+   |
+   = note: expected associated type `<impl Bar as Foo>::Item`
+                         found type `i32`
+   = help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32` or calling a method that returns `<impl Bar as Foo>::Item`
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32`
+   |
+LL | fn bar() -> impl Bar<Item = i32> {
+   |                     ++++++++++++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr b/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr
index 44d60c1d80d..f21c8115124 100644
--- a/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr
+++ b/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr
@@ -8,10 +8,10 @@ LL |     Box::new(async { x } )
    |                    may outlive borrowed value `x`
    |
 note: async block is returned here
-  --> $DIR/async-borrowck-escaping-block-error.rs:4:20
+  --> $DIR/async-borrowck-escaping-block-error.rs:6:5
    |
-LL | fn test_boxed() -> Box<impl std::future::Future<Output = u32>> {
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     Box::new(async { x } )
+   |     ^^^^^^^^^^^^^^^^^^^^^^
 help: to force the async block to take ownership of `x` (and any other referenced variables), use the `move` keyword
    |
 LL |     Box::new(async move { x } )
diff --git a/src/test/ui/async-await/issue-70818.rs b/src/test/ui/async-await/issue-70818.rs
index 0609e4fc081..019c56eb2fa 100644
--- a/src/test/ui/async-await/issue-70818.rs
+++ b/src/test/ui/async-await/issue-70818.rs
@@ -2,7 +2,7 @@
 
 use std::future::Future;
 fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
-//~^ Error future cannot be sent between threads safely
+    //~^ Error future cannot be sent between threads safely
     async { (ty, ty1) }
 }
 
diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr
index 2722c72c20a..cdb141c0e3e 100644
--- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr
+++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr
@@ -14,12 +14,16 @@ LL | | }
    = help: consider adding the following bound: `'a: 'b`
 
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/ret-impl-trait-one.rs:16:65
+  --> $DIR/ret-impl-trait-one.rs:16:80
    |
-LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
-   |                                    --                           ^^^^^^^^^^^^^^
-   |                                    |
-   |                                    hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here
+LL |   async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
+   |  ____________________________________--__________________________________________^
+   | |                                    |
+   | |                                    hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here
+LL | |
+LL | |     (a, b)
+LL | | }
+   | |_^
    |
 help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
    |
diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
index 149692a2c69..2eb3a07059f 100644
--- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
+++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
@@ -1,19 +1,26 @@
 error[E0623]: lifetime mismatch
-  --> $DIR/ret-impl-trait-one.rs:10:65
+  --> $DIR/ret-impl-trait-one.rs:10:85
    |
-LL | async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
-   |                                                      ------     ^^^^^^^^^^^^^^^^^^^
-   |                                                      |          |
-   |                                                      |          ...but data from `a` is returned here
-   |                                                      this parameter and the return type are declared with different lifetimes...
+LL |   async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
+   |  ______________________________________________________------_____-------------------_^
+   | |                                                      |
+   | |                                                      this parameter and the return type are declared with different lifetimes...
+LL | |
+LL | |     (a, b)
+LL | | }
+   | |_^ ...but data from `a` is returned here
 
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/ret-impl-trait-one.rs:16:65
+  --> $DIR/ret-impl-trait-one.rs:16:80
    |
-LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
-   |                                    --                           ^^^^^^^^^^^^^^
-   |                                    |
-   |                                    hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here
+LL |   async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
+   |  ____________________________________--__________________________________________^
+   | |                                    |
+   | |                                    hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here
+LL | |
+LL | |     (a, b)
+LL | | }
+   | |_^
    |
 help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
    |
diff --git a/src/test/ui/async-await/no-const-async.rs b/src/test/ui/async-await/no-const-async.rs
index b3c59734e03..cfb0ef1b33a 100644
--- a/src/test/ui/async-await/no-const-async.rs
+++ b/src/test/ui/async-await/no-const-async.rs
@@ -3,3 +3,4 @@
 
 pub const async fn x() {}
 //~^ ERROR functions cannot be both `const` and `async`
+//~| ERROR cycle detected
diff --git a/src/test/ui/async-await/no-const-async.stderr b/src/test/ui/async-await/no-const-async.stderr
index 90ec646c8c0..fd76c282f96 100644
--- a/src/test/ui/async-await/no-const-async.stderr
+++ b/src/test/ui/async-await/no-const-async.stderr
@@ -7,5 +7,36 @@ LL | pub const async fn x() {}
    |     |     `async` because of this
    |     `const` because of this
 
-error: aborting due to previous error
+error[E0391]: cycle detected when computing type of `x::{opaque#0}`
+  --> $DIR/no-const-async.rs:4:24
+   |
+LL | pub const async fn x() {}
+   |                        ^
+   |
+note: ...which requires borrow-checking `x`...
+  --> $DIR/no-const-async.rs:4:1
+   |
+LL | pub const async fn x() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires processing `x`...
+  --> $DIR/no-const-async.rs:4:1
+   |
+LL | pub const async fn x() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires const checking `x`...
+  --> $DIR/no-const-async.rs:4:1
+   |
+LL | pub const async fn x() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^
+   = note: ...which requires computing whether `impl core::future::future::Future<Output = ()>` is freeze...
+   = note: ...which requires evaluating trait selection obligation `impl core::future::future::Future<Output = ()>: core::marker::Freeze`...
+   = note: ...which again requires computing type of `x::{opaque#0}`, completing the cycle
+note: cycle used when checking item types in top-level module
+  --> $DIR/no-const-async.rs:4:1
+   |
+LL | pub const async fn x() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/async-await/recursive-async-impl-trait-type.rs b/src/test/ui/async-await/recursive-async-impl-trait-type.rs
index aa773319458..edc4cb8ac5d 100644
--- a/src/test/ui/async-await/recursive-async-impl-trait-type.rs
+++ b/src/test/ui/async-await/recursive-async-impl-trait-type.rs
@@ -2,7 +2,8 @@
 // Test that impl trait does not allow creating recursive types that are
 // otherwise forbidden when using `async` and `await`.
 
-async fn recursive_async_function() -> () { //~ ERROR
+async fn recursive_async_function() -> () {
+    //~^ ERROR recursion in an `async fn` requires boxing
     recursive_async_function().await;
 }
 
diff --git a/src/test/ui/async-await/suggest-missing-await.rs b/src/test/ui/async-await/suggest-missing-await.rs
index c7c5b51e733..796f82e779c 100644
--- a/src/test/ui/async-await/suggest-missing-await.rs
+++ b/src/test/ui/async-await/suggest-missing-await.rs
@@ -21,8 +21,8 @@ async fn dummy() {}
 async fn suggest_await_in_async_fn_return() {
     dummy()
     //~^ ERROR mismatched types [E0308]
-    //~| HELP consider using a semicolon here
     //~| HELP consider `await`ing on the `Future`
+    //~| HELP consider using a semicolon here
     //~| SUGGESTION .await
 }
 
diff --git a/src/test/ui/chalkify/bugs/async.stderr b/src/test/ui/chalkify/bugs/async.stderr
index 3d62f059f37..78d78f57955 100644
--- a/src/test/ui/chalkify/bugs/async.stderr
+++ b/src/test/ui/chalkify/bugs/async.stderr
@@ -29,10 +29,13 @@ LL |     T: Generator<ResumeTy, Yield = ()>,
    |                            ^^^^^^^^^^ required by this bound in `from_generator`
 
 error[E0280]: the requirement `<impl Future as Future>::Output == u32` is not satisfied
-  --> $DIR/async.rs:7:25
+  --> $DIR/async.rs:7:29
    |
-LL | async fn foo(x: u32) -> u32 {
-   |                         ^^^
+LL |   async fn foo(x: u32) -> u32 {
+   |  _____________________________^
+LL | |     x
+LL | | }
+   | |_^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr
index bb00465758a..46379a3815a 100644
--- a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr
@@ -8,10 +8,10 @@ LL |        println!("{:?}", p);
    |                         - `p` is borrowed here
    |
 note: closure is returned here
-  --> $DIR/borrowck-4.rs:8:14
+  --> $DIR/borrowck-4.rs:15:5
    |
-LL | fn foo () -> impl FnMut()->() {
-   |              ^^^^^^^^^^^^^^^^
+LL |     c
+   |     ^
 help: to force the closure to take ownership of `p` (and any other referenced variables), use the `move` keyword
    |
 LL |     let mut c = move || {
diff --git a/src/test/ui/conservative_impl_trait.rs b/src/test/ui/conservative_impl_trait.rs
index b7f795eadb7..b8488d83998 100644
--- a/src/test/ui/conservative_impl_trait.rs
+++ b/src/test/ui/conservative_impl_trait.rs
@@ -2,6 +2,7 @@
 
 fn will_ice(something: &u32) -> impl Iterator<Item = &u32> {
     //~^ ERROR `()` is not an iterator
+    //~| ERROR `()` is not an iterator
 }
 
 fn main() {}
diff --git a/src/test/ui/conservative_impl_trait.stderr b/src/test/ui/conservative_impl_trait.stderr
index 63a4df242f8..2348f2f5297 100644
--- a/src/test/ui/conservative_impl_trait.stderr
+++ b/src/test/ui/conservative_impl_trait.stderr
@@ -6,6 +6,18 @@ LL | fn will_ice(something: &u32) -> impl Iterator<Item = &u32> {
    |
    = help: the trait `Iterator` is not implemented for `()`
 
-error: aborting due to previous error
+error[E0277]: `()` is not an iterator
+  --> $DIR/conservative_impl_trait.rs:3:60
+   |
+LL |   fn will_ice(something: &u32) -> impl Iterator<Item = &u32> {
+   |  ____________________________________________________________^
+LL | |
+LL | |
+LL | | }
+   | |_^ `()` is not an iterator
+   |
+   = help: the trait `Iterator` is not implemented for `()`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs
index 308c121a941..24031aa1e61 100644
--- a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs
+++ b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs
@@ -5,6 +5,7 @@ impl<const N: u32> Trait for Uwu<N> {}
 
 fn rawr() -> impl Trait {
     //~^ error: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
+    //~| error: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
     Uwu::<10, 12>
 }
 
@@ -16,11 +17,13 @@ impl Traitor<1, 2> for u64 {}
 
 fn uwu<const N: u8>() -> impl Traitor<N> {
     //~^ error: the trait bound `u32: Traitor<N, N>` is not satisfied
+    //~| error: the trait bound `u32: Traitor<N, N>` is not satisfied
     1_u32
 }
 
 fn owo() -> impl Traitor {
     //~^ error: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
+    //~| error: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
     1_u64
 }
 
diff --git a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr
index 19813a491c9..81cfcb35606 100644
--- a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr
+++ b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr
@@ -7,8 +7,22 @@ LL | fn rawr() -> impl Trait {
    = help: the following implementations were found:
              <Uwu<N> as Trait>
 
+error[E0277]: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
+  --> $DIR/rp_impl_trait_fail.rs:6:25
+   |
+LL |   fn rawr() -> impl Trait {
+   |  _________________________^
+LL | |
+LL | |
+LL | |     Uwu::<10, 12>
+LL | | }
+   | |_^ the trait `Trait` is not implemented for `Uwu<10_u32, 12_u32>`
+   |
+   = help: the following implementations were found:
+             <Uwu<N> as Trait>
+
 error[E0277]: the trait bound `u32: Traitor<N, N>` is not satisfied
-  --> $DIR/rp_impl_trait_fail.rs:17:26
+  --> $DIR/rp_impl_trait_fail.rs:18:26
    |
 LL | fn uwu<const N: u8>() -> impl Traitor<N> {
    |                          ^^^^^^^^^^^^^^^ the trait `Traitor<N, N>` is not implemented for `u32`
@@ -17,8 +31,23 @@ LL | fn uwu<const N: u8>() -> impl Traitor<N> {
              <u32 as Traitor<N, 2_u8>>
              <u64 as Traitor<1_u8, 2_u8>>
 
+error[E0277]: the trait bound `u32: Traitor<N, N>` is not satisfied
+  --> $DIR/rp_impl_trait_fail.rs:18:42
+   |
+LL |   fn uwu<const N: u8>() -> impl Traitor<N> {
+   |  __________________________________________^
+LL | |
+LL | |
+LL | |     1_u32
+LL | | }
+   | |_^ the trait `Traitor<N, N>` is not implemented for `u32`
+   |
+   = help: the following implementations were found:
+             <u32 as Traitor<N, 2_u8>>
+             <u64 as Traitor<1_u8, 2_u8>>
+
 error[E0277]: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
-  --> $DIR/rp_impl_trait_fail.rs:22:13
+  --> $DIR/rp_impl_trait_fail.rs:24:13
    |
 LL | fn owo() -> impl Traitor {
    |             ^^^^^^^^^^^^ the trait `Traitor<1_u8, 1_u8>` is not implemented for `u64`
@@ -27,6 +56,21 @@ LL | fn owo() -> impl Traitor {
              <u64 as Traitor<1_u8, 2_u8>>
              <u32 as Traitor<N, 2_u8>>
 
-error: aborting due to 3 previous errors
+error[E0277]: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
+  --> $DIR/rp_impl_trait_fail.rs:24:26
+   |
+LL |   fn owo() -> impl Traitor {
+   |  __________________________^
+LL | |
+LL | |
+LL | |     1_u64
+LL | | }
+   | |_^ the trait `Traitor<1_u8, 1_u8>` is not implemented for `u64`
+   |
+   = help: the following implementations were found:
+             <u64 as Traitor<1_u8, 2_u8>>
+             <u32 as Traitor<N, 2_u8>>
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.rs b/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.rs
index dab9c687e24..405d6e2a9f5 100644
--- a/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.rs
+++ b/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.rs
@@ -3,11 +3,9 @@
 #![allow(incomplete_features)]
 pub mod foo {
     type MainFn = impl Fn();
-    //~^ ERROR could not find defining uses
 
     fn bar() {}
     pub const BAR: MainFn = bar;
-    //~^ ERROR mismatched types [E0308]
 }
 
 use foo::BAR as main; //~ ERROR `main` function not found in crate
diff --git a/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr b/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr
index b9bc0262a56..fabb6ffb02f 100644
--- a/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr
+++ b/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr
@@ -1,30 +1,11 @@
 error[E0601]: `main` function not found in crate `imported_main_const_fn_item_type_forbidden`
-  --> $DIR/imported_main_const_fn_item_type_forbidden.rs:13:22
+  --> $DIR/imported_main_const_fn_item_type_forbidden.rs:11:22
    |
 LL | use foo::BAR as main;
    |     ---------------- ^ consider adding a `main` function to `$DIR/imported_main_const_fn_item_type_forbidden.rs`
    |     |
    |     non-function item at `crate::main` is found
 
-error[E0308]: mismatched types
-  --> $DIR/imported_main_const_fn_item_type_forbidden.rs:9:29
-   |
-LL |     type MainFn = impl Fn();
-   |                   --------- the expected opaque type
-...
-LL |     pub const BAR: MainFn = bar;
-   |                             ^^^ expected opaque type, found fn item
-   |
-   = note: expected opaque type `impl Fn()`
-                  found fn item `fn() {bar}`
-
-error: could not find defining uses
-  --> $DIR/imported_main_const_fn_item_type_forbidden.rs:5:19
-   |
-LL |     type MainFn = impl Fn();
-   |                   ^^^^^^^^^
-
-error: aborting due to 3 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0308, E0601.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.rs b/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.rs
index ea82837d4bf..6dfd7f6840f 100644
--- a/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.rs
+++ b/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.rs
@@ -1,13 +1,13 @@
 // ignore-compare-mode-chalk
+// check-pass
 #![feature(type_alias_impl_trait)]
 use std::fmt::Debug;
 
 type Foo = impl Debug;
-//~^ ERROR could not find defining uses
 
 struct Bar(Foo);
 fn define() -> Bar {
-    Bar(42) //~ ERROR mismatched types
+    Bar(42)
 }
 
 type Foo2 = impl Debug;
@@ -17,21 +17,18 @@ fn define2() {
 }
 
 type Foo3 = impl Debug;
-//~^ ERROR could not find defining uses
 
 fn define3(x: Foo3) {
-    let y: i32 = x; //~ ERROR mismatched types
+    let y: i32 = x;
 }
 fn define3_1() {
-    define3(42) //~ ERROR mismatched types
+    define3(42)
 }
 
 type Foo4 = impl Debug;
-//~^ ERROR could not find defining uses
 
 fn define4() {
     let y: Foo4 = 42;
-    //~^ ERROR mismatched types [E0308]
 }
 
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr b/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr
deleted file mode 100644
index da3ddb1c509..00000000000
--- a/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr
+++ /dev/null
@@ -1,73 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/feature-gate-type_alias_impl_trait.rs:10:9
-   |
-LL | type Foo = impl Debug;
-   |            ---------- the expected opaque type
-...
-LL |     Bar(42)
-   |         ^^ expected opaque type, found integer
-   |
-   = note: expected opaque type `impl Debug`
-                     found type `{integer}`
-
-error[E0308]: mismatched types
-  --> $DIR/feature-gate-type_alias_impl_trait.rs:23:18
-   |
-LL | type Foo3 = impl Debug;
-   |             ---------- the found opaque type
-...
-LL |     let y: i32 = x;
-   |            ---   ^ expected `i32`, found opaque type
-   |            |
-   |            expected due to this
-   |
-   = note:     expected type `i32`
-           found opaque type `impl Debug`
-
-error[E0308]: mismatched types
-  --> $DIR/feature-gate-type_alias_impl_trait.rs:26:13
-   |
-LL | type Foo3 = impl Debug;
-   |             ---------- the expected opaque type
-...
-LL |     define3(42)
-   |             ^^ expected opaque type, found integer
-   |
-   = note: expected opaque type `impl Debug`
-                     found type `{integer}`
-
-error[E0308]: mismatched types
-  --> $DIR/feature-gate-type_alias_impl_trait.rs:33:19
-   |
-LL | type Foo4 = impl Debug;
-   |             ---------- the expected opaque type
-...
-LL |     let y: Foo4 = 42;
-   |            ----   ^^ expected opaque type, found integer
-   |            |
-   |            expected due to this
-   |
-   = note: expected opaque type `impl Debug`
-                     found type `{integer}`
-
-error: could not find defining uses
-  --> $DIR/feature-gate-type_alias_impl_trait.rs:5:12
-   |
-LL | type Foo = impl Debug;
-   |            ^^^^^^^^^^
-
-error: could not find defining uses
-  --> $DIR/feature-gate-type_alias_impl_trait.rs:19:13
-   |
-LL | type Foo3 = impl Debug;
-   |             ^^^^^^^^^^
-
-error: could not find defining uses
-  --> $DIR/feature-gate-type_alias_impl_trait.rs:29:13
-   |
-LL | type Foo4 = impl Debug;
-   |             ^^^^^^^^^^
-
-error: aborting due to 7 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/generator/issue-88653.rs b/src/test/ui/generator/issue-88653.rs
index ce9159b53e0..f27956e4595 100644
--- a/src/test/ui/generator/issue-88653.rs
+++ b/src/test/ui/generator/issue-88653.rs
@@ -6,10 +6,14 @@
 use std::ops::Generator;
 
 fn foo(bar: bool) -> impl Generator<(bool,)> {
-//~^ ERROR: type mismatch in generator arguments [E0631]
-//~| NOTE: expected signature of `fn((bool,)) -> _`
+    //~^ ERROR: type mismatch in generator arguments [E0631]
+    //~| ERROR: type mismatch in generator arguments [E0631]
+    //~| NOTE: expected signature of `fn((bool,)) -> _`
+    //~| NOTE: expected signature of `fn((bool,)) -> _`
+    //~| NOTE: in this expansion of desugaring of `impl Trait`
     |bar| {
-    //~^ NOTE: found signature of `fn(bool) -> _`
+        //~^ NOTE: found signature of `fn(bool) -> _`
+        //~| NOTE: found signature of `fn(bool) -> _`
         if bar {
             yield bar;
         }
diff --git a/src/test/ui/generator/issue-88653.stderr b/src/test/ui/generator/issue-88653.stderr
index 5bd8ad129fe..25357411ce1 100644
--- a/src/test/ui/generator/issue-88653.stderr
+++ b/src/test/ui/generator/issue-88653.stderr
@@ -7,6 +7,22 @@ LL | fn foo(bar: bool) -> impl Generator<(bool,)> {
 LL |     |bar| {
    |     ----- found signature of `fn(bool) -> _`
 
-error: aborting due to previous error
+error[E0631]: type mismatch in generator arguments
+  --> $DIR/issue-88653.rs:8:46
+   |
+LL |   fn foo(bar: bool) -> impl Generator<(bool,)> {
+   |  ______________________________________________^
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     |bar| {
+   | |     ----- found signature of `fn(bool) -> _`
+...  |
+LL | |     }
+LL | | }
+   | |_^ expected signature of `fn((bool,)) -> _`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0631`.
diff --git a/src/test/ui/generator/type-mismatch-signature-deduction.rs b/src/test/ui/generator/type-mismatch-signature-deduction.rs
index 7774ff48f56..77b830783c3 100644
--- a/src/test/ui/generator/type-mismatch-signature-deduction.rs
+++ b/src/test/ui/generator/type-mismatch-signature-deduction.rs
@@ -2,7 +2,9 @@
 
 use std::ops::Generator;
 
-fn foo() -> impl Generator<Return = i32> { //~ ERROR type mismatch
+fn foo() -> impl Generator<Return = i32> {
+    //~^ ERROR type mismatch
+    //~| ERROR type mismatch
     || {
         if false {
             return Ok(6);
diff --git a/src/test/ui/generator/type-mismatch-signature-deduction.stderr b/src/test/ui/generator/type-mismatch-signature-deduction.stderr
index 3f1f33a3b12..6369e7ec4c7 100644
--- a/src/test/ui/generator/type-mismatch-signature-deduction.stderr
+++ b/src/test/ui/generator/type-mismatch-signature-deduction.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/type-mismatch-signature-deduction.rs:13:9
+  --> $DIR/type-mismatch-signature-deduction.rs:15:9
    |
 LL |         5
    |         ^ expected enum `Result`, found integer
@@ -7,21 +7,37 @@ LL |         5
    = note: expected type `Result<{integer}, _>`
               found type `{integer}`
 note: return type inferred to be `Result<{integer}, _>` here
-  --> $DIR/type-mismatch-signature-deduction.rs:8:20
+  --> $DIR/type-mismatch-signature-deduction.rs:10:20
    |
 LL |             return Ok(6);
    |                    ^^^^^
 
-error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:6:5: 14:6] as Generator>::Return == i32`
+error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:8:5: 16:6] as Generator>::Return == i32`
   --> $DIR/type-mismatch-signature-deduction.rs:5:13
    |
 LL | fn foo() -> impl Generator<Return = i32> {
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found enum `Result`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Result`, found `i32`
    |
-   = note: expected type `i32`
-              found enum `Result<{integer}, _>`
+   = note: expected enum `Result<{integer}, _>`
+              found type `i32`
 
-error: aborting due to 2 previous errors
+error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:8:5: 16:6] as Generator>::Return == i32`
+  --> $DIR/type-mismatch-signature-deduction.rs:5:42
+   |
+LL |   fn foo() -> impl Generator<Return = i32> {
+   |  __________________________________________^
+LL | |
+LL | |
+LL | |     || {
+...  |
+LL | |     }
+LL | | }
+   | |_^ expected enum `Result`, found `i32`
+   |
+   = note: expected enum `Result<{integer}, _>`
+              found type `i32`
+
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0271, E0308.
 For more information about an error, try `rustc --explain E0271`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-86218.stderr b/src/test/ui/generic-associated-types/bugs/issue-86218.stderr
index 98a5f4254bb..fbf1c8f95fe 100644
--- a/src/test/ui/generic-associated-types/bugs/issue-86218.stderr
+++ b/src/test/ui/generic-associated-types/bugs/issue-86218.stderr
@@ -1,4 +1,4 @@
-error[E0477]: the type `impl Stream<Item = i32>` does not fulfill the required lifetime
+error[E0477]: the type `<() as Yay<&'a ()>>::InnerStream<'s>` does not fulfill the required lifetime
   --> $DIR/issue-86218.rs:23:28
    |
 LL |     type InnerStream<'s> = impl Stream<Item = i32> + 's;
@@ -10,6 +10,14 @@ note: type must outlive the lifetime `'s` as defined here as required by this bi
 LL |     type InnerStream<'s> = impl Stream<Item = i32> + 's;
    |                      ^^
 
-error: aborting due to previous error
+error: unconstrained opaque type
+  --> $DIR/issue-86218.rs:23:28
+   |
+LL |     type InnerStream<'s> = impl Stream<Item = i32> + 's;
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `InnerStream` must be used in combination with a concrete type within the same module
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0477`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-89008.stderr b/src/test/ui/generic-associated-types/bugs/issue-89008.stderr
index 3e607d4004e..5cbadfacc1b 100644
--- a/src/test/ui/generic-associated-types/bugs/issue-89008.stderr
+++ b/src/test/ui/generic-associated-types/bugs/issue-89008.stderr
@@ -1,21 +1,19 @@
-error[E0271]: type mismatch resolving `<impl Future as Future>::Output == impl Stream<Item = Repr>`
-  --> $DIR/issue-89008.rs:39:43
+error[E0271]: type mismatch resolving `<Empty<_> as Stream>::Item == Repr`
+  --> $DIR/issue-89008.rs:40:9
    |
-LL |     type LineStream<'a, Repr> = impl Stream<Item = Repr>;
-   |                                 ------------------------ the expected opaque type
-...
 LL |     fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {
-   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found struct `Empty`
+   |                        ---- this type parameter
+LL |         async {empty()}
+   |         ^^^^^^^^^^^^^^^ type mismatch resolving `<Empty<_> as Stream>::Item == Repr`
    |
-   = note: expected opaque type `impl Stream<Item = Repr>`
-                   found struct `Empty<_>`
-
-error: could not find defining uses
-  --> $DIR/issue-89008.rs:35:33
+note: expected this to be `()`
+  --> $DIR/issue-89008.rs:18:17
    |
-LL |     type LineStream<'a, Repr> = impl Stream<Item = Repr>;
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     type Item = ();
+   |                 ^^
+   = note:   expected unit type `()`
+           found type parameter `Repr`
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/generic-associated-types/issue-87258_a.rs b/src/test/ui/generic-associated-types/issue-87258_a.rs
index d9d17751fa6..c65f3fb2aa0 100644
--- a/src/test/ui/generic-associated-types/issue-87258_a.rs
+++ b/src/test/ui/generic-associated-types/issue-87258_a.rs
@@ -16,7 +16,8 @@ pub trait Trait2 {
 
 impl<'c, S: Trait2> Trait2 for &'c mut S {
     type FooFuture<'a> = impl Trait1;
-    fn foo<'a>() -> Self::FooFuture<'a> { //~ ERROR
+    //~^ ERROR unconstrained opaque type
+    fn foo<'a>() -> Self::FooFuture<'a> {
         Struct(unimplemented!())
     }
 }
diff --git a/src/test/ui/generic-associated-types/issue-87258_a.stderr b/src/test/ui/generic-associated-types/issue-87258_a.stderr
index 93513a4563f..db3a5c819cb 100644
--- a/src/test/ui/generic-associated-types/issue-87258_a.stderr
+++ b/src/test/ui/generic-associated-types/issue-87258_a.stderr
@@ -1,11 +1,10 @@
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/issue-87258_a.rs:19:21
+error: unconstrained opaque type
+  --> $DIR/issue-87258_a.rs:18:26
    |
-LL |     fn foo<'a>() -> Self::FooFuture<'a> {
-   |                     ^^^^^^^^^^^^^^^^^^^
+LL |     type FooFuture<'a> = impl Trait1;
+   |                          ^^^^^^^^^^^
    |
-   = note: hidden type `Struct<'_>` captures lifetime '_#7r
+   = note: `FooFuture` must be used in combination with a concrete type within the same module
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0700`.
diff --git a/src/test/ui/generic-associated-types/issue-87258_b.rs b/src/test/ui/generic-associated-types/issue-87258_b.rs
index b29a978f517..f59e0d76659 100644
--- a/src/test/ui/generic-associated-types/issue-87258_b.rs
+++ b/src/test/ui/generic-associated-types/issue-87258_b.rs
@@ -15,10 +15,11 @@ pub trait Trait2 {
 }
 
 type Helper<'xenon, 'yttrium, KABOOM: Trait2> = impl Trait1;
+//~^ ERROR unconstrained opaque type
 
 impl<'c, S: Trait2> Trait2 for &'c mut S {
     type FooFuture<'a> = Helper<'c, 'a, S>;
-    fn foo<'a>() -> Self::FooFuture<'a> { //~ ERROR
+    fn foo<'a>() -> Self::FooFuture<'a> {
         Struct(unimplemented!())
     }
 }
diff --git a/src/test/ui/generic-associated-types/issue-87258_b.stderr b/src/test/ui/generic-associated-types/issue-87258_b.stderr
index e077a423400..9faccc96124 100644
--- a/src/test/ui/generic-associated-types/issue-87258_b.stderr
+++ b/src/test/ui/generic-associated-types/issue-87258_b.stderr
@@ -1,11 +1,10 @@
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/issue-87258_b.rs:21:21
+error: unconstrained opaque type
+  --> $DIR/issue-87258_b.rs:17:49
    |
-LL |     fn foo<'a>() -> Self::FooFuture<'a> {
-   |                     ^^^^^^^^^^^^^^^^^^^
+LL | type Helper<'xenon, 'yttrium, KABOOM: Trait2> = impl Trait1;
+   |                                                 ^^^^^^^^^^^
    |
-   = note: hidden type `Struct<'_>` captures lifetime '_#7r
+   = note: `Helper` must be used in combination with a concrete type within the same module
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0700`.
diff --git a/src/test/ui/generic-associated-types/issue-88595.rs b/src/test/ui/generic-associated-types/issue-88595.rs
index c97d17811ba..e0796dfecbb 100644
--- a/src/test/ui/generic-associated-types/issue-88595.rs
+++ b/src/test/ui/generic-associated-types/issue-88595.rs
@@ -17,7 +17,6 @@ struct C;
 
 impl<'a> A<'a> for C {
     type B<'b> = impl Clone;
-    //~^ ERROR: could not find defining uses
 
     fn a(&'a self) -> Self::B<'a> {} //~ ERROR: non-defining opaque type use in defining scope
 }
diff --git a/src/test/ui/generic-associated-types/issue-88595.stderr b/src/test/ui/generic-associated-types/issue-88595.stderr
index 4e4f86bbac8..79d3479af8c 100644
--- a/src/test/ui/generic-associated-types/issue-88595.stderr
+++ b/src/test/ui/generic-associated-types/issue-88595.stderr
@@ -1,8 +1,8 @@
 error: non-defining opaque type use in defining scope
-  --> $DIR/issue-88595.rs:22:23
+  --> $DIR/issue-88595.rs:21:35
    |
 LL |     fn a(&'a self) -> Self::B<'a> {}
-   |                       ^^^^^^^^^^^
+   |                                   ^^
    |
 note: lifetime used multiple times
   --> $DIR/issue-88595.rs:18:6
@@ -12,11 +12,5 @@ LL | impl<'a> A<'a> for C {
 LL |     type B<'b> = impl Clone;
    |            ^^
 
-error: could not find defining uses
-  --> $DIR/issue-88595.rs:19:18
-   |
-LL |     type B<'b> = impl Clone;
-   |                  ^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/impl-trait/async_scope_creep.rs b/src/test/ui/impl-trait/async_scope_creep.rs
new file mode 100644
index 00000000000..7a9d64d339f
--- /dev/null
+++ b/src/test/ui/impl-trait/async_scope_creep.rs
@@ -0,0 +1,28 @@
+#![feature(type_alias_impl_trait)]
+// edition:2021
+// check-pass
+
+struct Pending {}
+
+struct CantOpen {}
+
+trait AsyncRead {}
+
+impl AsyncRead for i32 {}
+
+type PendingReader<'a> = impl AsyncRead + 'a;
+
+type OpeningReadFuture<'a> =
+    impl std::future::Future<Output = Result<PendingReader<'a>, CantOpen>>;
+
+impl Pending {
+    async fn read(&mut self) -> Result<impl AsyncRead + '_, CantOpen> {
+        Ok(42)
+    }
+
+    fn read_fut(&mut self) -> OpeningReadFuture<'_> {
+        self.read()
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/auto-trait-leak.rs b/src/test/ui/impl-trait/auto-trait-leak.rs
index c2fbbf94fd6..d2452abab02 100644
--- a/src/test/ui/impl-trait/auto-trait-leak.rs
+++ b/src/test/ui/impl-trait/auto-trait-leak.rs
@@ -11,6 +11,7 @@ fn main() {
 // return type, which can't depend on the obligation.
 fn cycle1() -> impl Clone {
     //~^ ERROR cycle detected
+    //~| ERROR cycle detected
     send(cycle2().clone());
 
     Rc::new(Cell::new(5))
diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr
index 634ff14869e..14db864f1c2 100644
--- a/src/test/ui/impl-trait/auto-trait-leak.stderr
+++ b/src/test/ui/impl-trait/auto-trait-leak.stderr
@@ -30,47 +30,129 @@ note: ...which requires building MIR for `cycle1`...
 LL | fn cycle1() -> impl Clone {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires type-checking `cycle1`...
-  --> $DIR/auto-trait-leak.rs:14:5
+  --> $DIR/auto-trait-leak.rs:12:1
+   |
+LL | fn cycle1() -> impl Clone {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires computing type of `cycle2::{opaque#0}`...
+  --> $DIR/auto-trait-leak.rs:20:16
+   |
+LL | fn cycle2() -> impl Clone {
+   |                ^^^^^^^^^^
+note: ...which requires borrow-checking `cycle2`...
+  --> $DIR/auto-trait-leak.rs:20:1
+   |
+LL | fn cycle2() -> impl Clone {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires processing `cycle2`...
+  --> $DIR/auto-trait-leak.rs:20:1
+   |
+LL | fn cycle2() -> impl Clone {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires processing MIR for `cycle2`...
+  --> $DIR/auto-trait-leak.rs:20:1
+   |
+LL | fn cycle2() -> impl Clone {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires unsafety-checking `cycle2`...
+  --> $DIR/auto-trait-leak.rs:20:1
+   |
+LL | fn cycle2() -> impl Clone {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires building MIR for `cycle2`...
+  --> $DIR/auto-trait-leak.rs:20:1
+   |
+LL | fn cycle2() -> impl Clone {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires type-checking `cycle2`...
+  --> $DIR/auto-trait-leak.rs:20:1
+   |
+LL | fn cycle2() -> impl Clone {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle
+note: cycle used when checking item types in top-level module
+  --> $DIR/auto-trait-leak.rs:1:1
+   |
+LL | / use std::cell::Cell;
+LL | | use std::rc::Rc;
+LL | |
+LL | | fn send<T: Send>(_: T) {}
+...  |
+LL | |     Rc::new(String::from("foo"))
+LL | | }
+   | |_^
+
+error[E0391]: cycle detected when computing type of `cycle1::{opaque#0}`
+  --> $DIR/auto-trait-leak.rs:12:16
    |
-LL |     send(cycle2().clone());
-   |     ^^^^
-   = note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`...
+LL | fn cycle1() -> impl Clone {
+   |                ^^^^^^^^^^
+   |
+note: ...which requires borrow-checking `cycle1`...
+  --> $DIR/auto-trait-leak.rs:12:1
+   |
+LL | fn cycle1() -> impl Clone {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires processing `cycle1`...
+  --> $DIR/auto-trait-leak.rs:12:1
+   |
+LL | fn cycle1() -> impl Clone {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires processing MIR for `cycle1`...
+  --> $DIR/auto-trait-leak.rs:12:1
+   |
+LL | fn cycle1() -> impl Clone {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires unsafety-checking `cycle1`...
+  --> $DIR/auto-trait-leak.rs:12:1
+   |
+LL | fn cycle1() -> impl Clone {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires building MIR for `cycle1`...
+  --> $DIR/auto-trait-leak.rs:12:1
+   |
+LL | fn cycle1() -> impl Clone {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires type-checking `cycle1`...
+  --> $DIR/auto-trait-leak.rs:12:1
+   |
+LL | fn cycle1() -> impl Clone {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires computing type of `cycle2::{opaque#0}`...
-  --> $DIR/auto-trait-leak.rs:19:16
+  --> $DIR/auto-trait-leak.rs:20:16
    |
 LL | fn cycle2() -> impl Clone {
    |                ^^^^^^^^^^
 note: ...which requires borrow-checking `cycle2`...
-  --> $DIR/auto-trait-leak.rs:19:1
+  --> $DIR/auto-trait-leak.rs:20:1
    |
 LL | fn cycle2() -> impl Clone {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires processing `cycle2`...
-  --> $DIR/auto-trait-leak.rs:19:1
+  --> $DIR/auto-trait-leak.rs:20:1
    |
 LL | fn cycle2() -> impl Clone {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires processing MIR for `cycle2`...
-  --> $DIR/auto-trait-leak.rs:19:1
+  --> $DIR/auto-trait-leak.rs:20:1
    |
 LL | fn cycle2() -> impl Clone {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires unsafety-checking `cycle2`...
-  --> $DIR/auto-trait-leak.rs:19:1
+  --> $DIR/auto-trait-leak.rs:20:1
    |
 LL | fn cycle2() -> impl Clone {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires building MIR for `cycle2`...
-  --> $DIR/auto-trait-leak.rs:19:1
+  --> $DIR/auto-trait-leak.rs:20:1
    |
 LL | fn cycle2() -> impl Clone {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires type-checking `cycle2`...
-  --> $DIR/auto-trait-leak.rs:20:5
+  --> $DIR/auto-trait-leak.rs:20:1
    |
-LL |     send(cycle1().clone());
-   |     ^^^^
-   = note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`...
+LL | fn cycle2() -> impl Clone {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle
 note: cycle used when checking item types in top-level module
   --> $DIR/auto-trait-leak.rs:1:1
@@ -84,6 +166,6 @@ LL | |     Rc::new(String::from("foo"))
 LL | | }
    | |_^
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/impl-trait/auto-trait.rs b/src/test/ui/impl-trait/auto-trait.rs
index cf2773f4ef5..35994e4a5ba 100644
--- a/src/test/ui/impl-trait/auto-trait.rs
+++ b/src/test/ui/impl-trait/auto-trait.rs
@@ -19,7 +19,7 @@ impl<T: Send> AnotherTrait for T {}
 // (We treat opaque types as "foreign types" that could grow more impls
 // in the future.)
 impl AnotherTrait for D<OpaqueType> {
-    //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<impl OpaqueTrait>`
+    //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
 }
 
 fn main() {}
diff --git a/src/test/ui/impl-trait/auto-trait.stderr b/src/test/ui/impl-trait/auto-trait.stderr
index 26cd8fb6a9b..81009413c9a 100644
--- a/src/test/ui/impl-trait/auto-trait.stderr
+++ b/src/test/ui/impl-trait/auto-trait.stderr
@@ -1,11 +1,11 @@
-error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<impl OpaqueTrait>`
+error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
   --> $DIR/auto-trait.rs:21:1
    |
 LL | impl<T: Send> AnotherTrait for T {}
    | -------------------------------- first implementation here
 ...
 LL | impl AnotherTrait for D<OpaqueType> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<impl OpaqueTrait>`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/impl-trait/autoderef.rs b/src/test/ui/impl-trait/autoderef.rs
new file mode 100644
index 00000000000..5e4f4995447
--- /dev/null
+++ b/src/test/ui/impl-trait/autoderef.rs
@@ -0,0 +1,19 @@
+// check-pass
+
+use std::path::Path;
+use std::ffi::OsStr;
+use std::ops::Deref;
+
+fn frob(path: &str) -> impl Deref<Target = Path> + '_ {
+    OsStr::new(path).as_ref()
+}
+
+fn open_parent<'path>(_path: &'path Path) {
+    todo!()
+}
+
+fn main() {
+    let old_path = frob("hello");
+
+    open_parent(&old_path);
+}
diff --git a/src/test/ui/impl-trait/bound-normalization-fail.rs b/src/test/ui/impl-trait/bound-normalization-fail.rs
index 8ec06e534d1..9f962fa9bba 100644
--- a/src/test/ui/impl-trait/bound-normalization-fail.rs
+++ b/src/test/ui/impl-trait/bound-normalization-fail.rs
@@ -24,6 +24,7 @@ mod impl_trait {
     /// `T::Assoc` can't be normalized any further here.
     fn foo_fail<T: Trait>() -> impl FooLike<Output = T::Assoc> {
         //~^ ERROR: type mismatch
+        //~| ERROR: type mismatch
         Foo(())
     }
 }
@@ -39,8 +40,9 @@ mod lifetimes {
 
     /// Missing bound constraining `Assoc`, `T::Assoc` can't be normalized further.
     fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output = T::Assoc> {
-        //~^ ERROR: type mismatch
-        //~^^ ERROR `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
+        //~^ ERROR `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
+        //~| ERROR: type mismatch
+        //~| ERROR: type mismatch
         Foo(())
     }
 }
diff --git a/src/test/ui/impl-trait/bound-normalization-fail.stderr b/src/test/ui/impl-trait/bound-normalization-fail.stderr
index afa21c1a858..0344f416eb7 100644
--- a/src/test/ui/impl-trait/bound-normalization-fail.stderr
+++ b/src/test/ui/impl-trait/bound-normalization-fail.stderr
@@ -4,43 +4,90 @@ error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as imp
 LL |     fn foo_fail<T: Trait>() -> impl FooLike<Output = T::Assoc> {
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Foo<()> as FooLike>::Output == <T as impl_trait::Trait>::Assoc`
    |
-note: expected this to be `<T as impl_trait::Trait>::Assoc`
+note: expected this to be `()`
   --> $DIR/bound-normalization-fail.rs:14:19
    |
 LL |     type Output = T;
    |                   ^
-   = note: expected associated type `<T as impl_trait::Trait>::Assoc`
-                    found unit type `()`
+   = note:    expected unit type `()`
+           found associated type `<T as impl_trait::Trait>::Assoc`
+help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc` to `()`
+   |
+LL |     fn foo_fail<T: Trait<Assoc = ()>>() -> impl FooLike<Output = T::Assoc> {
+   |                         ++++++++++++
+
+error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as impl_trait::Trait>::Assoc`
+  --> $DIR/bound-normalization-fail.rs:25:64
+   |
+LL |       fn foo_fail<T: Trait>() -> impl FooLike<Output = T::Assoc> {
+   |  ________________________________________________________________^
+LL | |
+LL | |
+LL | |         Foo(())
+LL | |     }
+   | |_____^ type mismatch resolving `<Foo<()> as FooLike>::Output == <T as impl_trait::Trait>::Assoc`
+   |
+note: expected this to be `()`
+  --> $DIR/bound-normalization-fail.rs:14:19
+   |
+LL |     type Output = T;
+   |                   ^
+   = note:    expected unit type `()`
+           found associated type `<T as impl_trait::Trait>::Assoc`
 help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc` to `()`
    |
 LL |     fn foo_fail<T: Trait<Assoc = ()>>() -> impl FooLike<Output = T::Assoc> {
    |                         ++++++++++++
 
 error[E0760]: `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
-  --> $DIR/bound-normalization-fail.rs:41:41
+  --> $DIR/bound-normalization-fail.rs:42:41
    |
 LL |     fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output = T::Assoc> {
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lifetimes::Trait<'static>>::Assoc`
-  --> $DIR/bound-normalization-fail.rs:41:41
+  --> $DIR/bound-normalization-fail.rs:42:41
    |
 LL |     fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output = T::Assoc> {
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lifetimes::Trait<'static>>::Assoc`
    |
-note: expected this to be `<T as lifetimes::Trait<'static>>::Assoc`
+note: expected this to be `()`
+  --> $DIR/bound-normalization-fail.rs:14:19
+   |
+LL |     type Output = T;
+   |                   ^
+   = note:    expected unit type `()`
+           found associated type `<T as lifetimes::Trait<'static>>::Assoc`
+help: consider constraining the associated type `<T as lifetimes::Trait<'static>>::Assoc` to `()`
+   |
+LL |     fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike<Output = T::Assoc> {
+   |                                 ++++++++++++
+
+error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lifetimes::Trait<'static>>::Assoc`
+  --> $DIR/bound-normalization-fail.rs:42:73
+   |
+LL |       fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output = T::Assoc> {
+   |  _________________________________________________________________________^
+LL | |
+LL | |
+LL | |
+LL | |         Foo(())
+LL | |     }
+   | |_____^ type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lifetimes::Trait<'static>>::Assoc`
+   |
+note: expected this to be `()`
   --> $DIR/bound-normalization-fail.rs:14:19
    |
 LL |     type Output = T;
    |                   ^
-   = note: expected associated type `<T as lifetimes::Trait<'static>>::Assoc`
-                    found unit type `()`
+   = note:    expected unit type `()`
+           found associated type `<T as lifetimes::Trait<'static>>::Assoc`
 help: consider constraining the associated type `<T as lifetimes::Trait<'static>>::Assoc` to `()`
    |
 LL |     fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike<Output = T::Assoc> {
    |                                 ++++++++++++
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0271, E0760.
 For more information about an error, try `rustc --explain E0271`.
diff --git a/src/test/ui/impl-trait/cross-return-site-inference.rs b/src/test/ui/impl-trait/cross-return-site-inference.rs
new file mode 100644
index 00000000000..c27b5ca9f66
--- /dev/null
+++ b/src/test/ui/impl-trait/cross-return-site-inference.rs
@@ -0,0 +1,45 @@
+// edition:2021
+
+fn foo(b: bool) -> impl std::fmt::Debug {
+    if b {
+        return vec![42]
+    }
+    [].into_iter().collect()
+}
+
+fn bar(b: bool) -> impl std::fmt::Debug {
+    if b {
+        return [].into_iter().collect()
+    }
+    vec![42]
+}
+
+fn bak(b: bool) -> impl std::fmt::Debug {
+    if b {
+        return std::iter::empty().collect()
+    }
+    vec![42]
+}
+
+fn baa(b: bool) -> impl std::fmt::Debug {
+    if b {
+        return [42].into_iter().collect()
+    }
+    vec![]
+}
+
+fn muh() -> Result<(), impl std::fmt::Debug> {
+    Err("whoops")?; //~ ERROR `?` couldn't convert the error to `impl Debug`
+    Ok(())
+}
+
+fn muh2() -> Result<(), impl std::fmt::Debug> {
+    return Err(From::from("foo")); //~ ERROR the trait bound `impl Debug: From<&str>` is not satisfied
+    Ok(())
+}
+
+fn muh3() -> Result<(), impl std::fmt::Debug> {
+    Err(From::from("foo")) //~ ERROR the trait bound `impl Debug: From<&str>` is not satisfied
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/cross-return-site-inference.stderr b/src/test/ui/impl-trait/cross-return-site-inference.stderr
new file mode 100644
index 00000000000..06afb938c5f
--- /dev/null
+++ b/src/test/ui/impl-trait/cross-return-site-inference.stderr
@@ -0,0 +1,26 @@
+error[E0277]: `?` couldn't convert the error to `impl Debug`
+  --> $DIR/cross-return-site-inference.rs:32:18
+   |
+LL | fn muh() -> Result<(), impl std::fmt::Debug> {
+   |             -------------------------------- expected `impl Debug` because of this
+LL |     Err("whoops")?;
+   |                  ^ the trait `From<&str>` is not implemented for `impl Debug`
+   |
+   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
+   = note: required because of the requirements on the impl of `FromResidual<Result<Infallible, &str>>` for `Result<(), impl Debug>`
+
+error[E0277]: the trait bound `impl Debug: From<&str>` is not satisfied
+  --> $DIR/cross-return-site-inference.rs:37:16
+   |
+LL |     return Err(From::from("foo"));
+   |                ^^^^^^^^^^ the trait `From<&str>` is not implemented for `impl Debug`
+
+error[E0277]: the trait bound `impl Debug: From<&str>` is not satisfied
+  --> $DIR/cross-return-site-inference.rs:42:9
+   |
+LL |     Err(From::from("foo"))
+   |         ^^^^^^^^^^ the trait `From<&str>` is not implemented for `impl Debug`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/divergence.rs b/src/test/ui/impl-trait/divergence.rs
new file mode 100644
index 00000000000..211f7972dbc
--- /dev/null
+++ b/src/test/ui/impl-trait/divergence.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+fn foo() -> impl MyTrait {
+    panic!();
+    MyStruct
+}
+
+struct MyStruct;
+trait MyTrait {}
+
+impl MyTrait for MyStruct {}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/does-not-live-long-enough.stderr b/src/test/ui/impl-trait/does-not-live-long-enough.stderr
index f4bd0fde3b6..750687e2322 100644
--- a/src/test/ui/impl-trait/does-not-live-long-enough.stderr
+++ b/src/test/ui/impl-trait/does-not-live-long-enough.stderr
@@ -7,10 +7,10 @@ LL |         self.data.iter().filter(|s| s.starts_with(prefix)).map(|s| s.as_ref
    |                                 may outlive borrowed value `prefix`
    |
 note: closure is returned here
-  --> $DIR/does-not-live-long-enough.rs:5:55
+  --> $DIR/does-not-live-long-enough.rs:6:9
    |
-LL |     fn started_with<'a>(&'a self, prefix: &'a str) -> impl Iterator<Item=&'a str> {
-   |                                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         self.data.iter().filter(|s| s.starts_with(prefix)).map(|s| s.as_ref())
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: to force the closure to take ownership of `prefix` (and any other referenced variables), use the `move` keyword
    |
 LL |         self.data.iter().filter(move |s| s.starts_with(prefix)).map(|s| s.as_ref())
diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr
index 536a4726c6d..804ccbcc6c0 100644
--- a/src/test/ui/impl-trait/equality.stderr
+++ b/src/test/ui/impl-trait/equality.stderr
@@ -12,19 +12,10 @@ error[E0308]: mismatched types
   --> $DIR/equality.rs:15:5
    |
 LL | fn two(x: bool) -> impl Foo {
-   |                    -------- expected because this return type...
-LL |     if x {
-LL |         return 1_i32;
-   |                ----- ...is found to be `i32` here
-LL |     }
+   |                    -------- expected `_` because of return type
+...
 LL |     0_u32
    |     ^^^^^ expected `i32`, found `u32`
-   |
-   = note: to return `impl Trait`, all returned values must be of the same type
-   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = help: if the trait `Foo` were object safe, you could return a boxed trait object
-   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
-   = help: you could instead create a new `enum` with a variant for each returned type
 
 error[E0277]: cannot add `impl Foo` to `u32`
   --> $DIR/equality.rs:24:11
diff --git a/src/test/ui/impl-trait/fallback.rs b/src/test/ui/impl-trait/fallback.rs
new file mode 100644
index 00000000000..1e6eb5bb355
--- /dev/null
+++ b/src/test/ui/impl-trait/fallback.rs
@@ -0,0 +1,9 @@
+// check-pass
+
+fn take_edge_counters(
+    x: &mut Option<Vec<i32>>,
+) -> Option<impl Iterator<Item = i32>> {
+    x.take().map_or(None, |m| Some(m.into_iter()))
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/hidden-lifetimes.rs b/src/test/ui/impl-trait/hidden-lifetimes.rs
index 2ee004a37a6..ae07c892768 100644
--- a/src/test/ui/impl-trait/hidden-lifetimes.rs
+++ b/src/test/ui/impl-trait/hidden-lifetimes.rs
@@ -26,8 +26,8 @@ impl<T> Swap for Rc<RefCell<T>> {
 // Here we are hiding `'b` making the caller believe that `&'a mut &'s T` and
 // `&'a mut &'l T` are the same type.
 fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a {
-    //~^ ERROR hidden type
     x
+    //~^ ERROR hidden type
 }
 
 fn dangle_ref() -> &'static [i32; 3] {
@@ -43,8 +43,8 @@ fn dangle_ref() -> &'static [i32; 3] {
 // This is different to the previous example because the concrete return type
 // only has a single lifetime.
 fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a {
-    //~^ ERROR hidden type
     x
+    //~^ ERROR hidden type
 }
 
 fn dangle_rc_refcell() -> &'static [i32; 3] {
diff --git a/src/test/ui/impl-trait/hidden-lifetimes.stderr b/src/test/ui/impl-trait/hidden-lifetimes.stderr
index c6d11293eec..97652f5462e 100644
--- a/src/test/ui/impl-trait/hidden-lifetimes.stderr
+++ b/src/test/ui/impl-trait/hidden-lifetimes.stderr
@@ -1,10 +1,10 @@
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/hidden-lifetimes.rs:28:54
+  --> $DIR/hidden-lifetimes.rs:29:5
    |
 LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a {
-   |                 --                                   ^^^^^^^^^^^^^^
-   |                 |
-   |                 hidden type `&'a mut &'b T` captures the lifetime `'b` as defined here
+   |                 -- hidden type `&'a mut &'b T` captures the lifetime `'b` as defined here
+LL |     x
+   |     ^
    |
 help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
    |
@@ -12,12 +12,12 @@ LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a + 'b {
    |                                                                     ++++
 
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/hidden-lifetimes.rs:45:70
+  --> $DIR/hidden-lifetimes.rs:46:5
    |
 LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a {
-   |                        --                                            ^^^^^^^^^^^^^^
-   |                        |
-   |                        hidden type `Rc<RefCell<&'b T>>` captures the lifetime `'b` as defined here
+   |                        -- hidden type `Rc<RefCell<&'b T>>` captures the lifetime `'b` as defined here
+LL |     x
+   |     ^
    |
 help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
    |
diff --git a/src/test/ui/impl-trait/hidden-type-is-opaque-2.rs b/src/test/ui/impl-trait/hidden-type-is-opaque-2.rs
new file mode 100644
index 00000000000..7876add5aa6
--- /dev/null
+++ b/src/test/ui/impl-trait/hidden-type-is-opaque-2.rs
@@ -0,0 +1,45 @@
+// This doesn't work, because we don't flow information from opaque types
+// into function arguments via the function's generic parameters
+// FIXME(oli-obk): make `expected_inputs_for_expected_output` support this
+
+#![feature(type_alias_impl_trait)]
+
+fn reify_as() -> Thunk<impl FnOnce(Continuation) -> Continuation> {
+    Thunk::new(|mut cont| { //~ ERROR type annotations needed
+        cont.reify_as();
+        cont
+    })
+}
+
+type Tait = impl FnOnce(Continuation) -> Continuation;
+
+fn reify_as_tait() -> Thunk<Tait> {
+    Thunk::new(|mut cont| { //~ ERROR type annotations needed
+        cont.reify_as();
+        cont
+    })
+}
+
+#[must_use]
+struct Thunk<F>(F);
+
+impl<F> Thunk<F> {
+    fn new(f: F) -> Self
+    where
+        F: ContFn,
+    {
+        Thunk(f)
+    }
+}
+
+trait ContFn {}
+
+impl<F: FnOnce(Continuation) -> Continuation> ContFn for F {}
+
+struct Continuation;
+
+impl Continuation {
+    fn reify_as(&mut self) {}
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/hidden-type-is-opaque-2.stderr b/src/test/ui/impl-trait/hidden-type-is-opaque-2.stderr
new file mode 100644
index 00000000000..dcf1982312f
--- /dev/null
+++ b/src/test/ui/impl-trait/hidden-type-is-opaque-2.stderr
@@ -0,0 +1,19 @@
+error[E0282]: type annotations needed
+  --> $DIR/hidden-type-is-opaque-2.rs:8:17
+   |
+LL |     Thunk::new(|mut cont| {
+   |                 ^^^^^^^^ consider giving this closure parameter a type
+   |
+   = note: type must be known at this point
+
+error[E0282]: type annotations needed
+  --> $DIR/hidden-type-is-opaque-2.rs:17:17
+   |
+LL |     Thunk::new(|mut cont| {
+   |                 ^^^^^^^^ consider giving this closure parameter a type
+   |
+   = note: type must be known at this point
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/impl-trait/hidden-type-is-opaque.rs b/src/test/ui/impl-trait/hidden-type-is-opaque.rs
new file mode 100644
index 00000000000..72b4028d854
--- /dev/null
+++ b/src/test/ui/impl-trait/hidden-type-is-opaque.rs
@@ -0,0 +1,42 @@
+// check-pass
+#![feature(type_alias_impl_trait)]
+
+fn reify_as() -> Thunk<impl ContFn> {
+    Thunk::new(|mut cont| {
+        cont.reify_as();
+        cont
+    })
+}
+
+type Tait = impl ContFn;
+
+fn reify_as_tait() -> Thunk<Tait> {
+    Thunk::new(|mut cont| {
+        cont.reify_as();
+        cont
+    })
+}
+
+#[must_use]
+struct Thunk<F>(F);
+
+impl<F> Thunk<F> {
+    fn new(f: F) -> Self
+    where
+        F: FnOnce(Continuation) -> Continuation,
+    {
+        Thunk(f)
+    }
+}
+
+trait ContFn {}
+
+impl<F: FnOnce(Continuation) -> Continuation> ContFn for F {}
+
+struct Continuation;
+
+impl Continuation {
+    fn reify_as(&mut self) {}
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issue-55872-1.rs b/src/test/ui/impl-trait/issue-55872-1.rs
index 46188636475..a75b9b43b3e 100644
--- a/src/test/ui/impl-trait/issue-55872-1.rs
+++ b/src/test/ui/impl-trait/issue-55872-1.rs
@@ -10,11 +10,10 @@ impl<S: Default> Bar for S {
     type E = impl Copy;
 
     fn foo<T: Default>() -> Self::E {
-        //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-        //~| ERROR impl has stricter requirements than trait
-        //~| ERROR the trait bound `S: Copy` is not satisfied in `(S, T)` [E0277]
-        //~| ERROR the trait bound `T: Copy` is not satisfied in `(S, T)` [E0277]
+        //~^ ERROR impl has stricter requirements than trait
         (S::default(), T::default())
+        //~^ ERROR the trait bound `S: Copy` is not satisfied in `(S, T)` [E0277]
+        //~| ERROR the trait bound `T: Copy` is not satisfied in `(S, T)` [E0277]
     }
 }
 
diff --git a/src/test/ui/impl-trait/issue-55872-1.stderr b/src/test/ui/impl-trait/issue-55872-1.stderr
index 2d1142fd0c5..efc57da7461 100644
--- a/src/test/ui/impl-trait/issue-55872-1.stderr
+++ b/src/test/ui/impl-trait/issue-55872-1.stderr
@@ -8,10 +8,10 @@ LL |     fn foo<T: Default>() -> Self::E {
    |               ^^^^^^^ impl has extra requirement `T: Default`
 
 error[E0277]: the trait bound `S: Copy` is not satisfied in `(S, T)`
-  --> $DIR/issue-55872-1.rs:12:29
+  --> $DIR/issue-55872-1.rs:14:9
    |
-LL |     fn foo<T: Default>() -> Self::E {
-   |                             ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S`
+LL |         (S::default(), T::default())
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S`
    |
    = note: required because it appears within the type `(S, T)`
 help: consider further restricting this bound
@@ -20,10 +20,10 @@ LL | impl<S: Default + std::marker::Copy> Bar for S {
    |                 +++++++++++++++++++
 
 error[E0277]: the trait bound `T: Copy` is not satisfied in `(S, T)`
-  --> $DIR/issue-55872-1.rs:12:29
+  --> $DIR/issue-55872-1.rs:14:9
    |
-LL |     fn foo<T: Default>() -> Self::E {
-   |                             ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T`
+LL |         (S::default(), T::default())
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T`
    |
    = note: required because it appears within the type `(S, T)`
 help: consider further restricting this bound
@@ -31,20 +31,7 @@ help: consider further restricting this bound
 LL |     fn foo<T: Default + std::marker::Copy>() -> Self::E {
    |                       +++++++++++++++++++
 
-error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-  --> $DIR/issue-55872-1.rs:12:37
-   |
-LL |       fn foo<T: Default>() -> Self::E {
-   |  _____________________________________^
-LL | |
-LL | |
-LL | |
-LL | |
-LL | |         (S::default(), T::default())
-LL | |     }
-   | |_____^
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0276, E0277.
 For more information about an error, try `rustc --explain E0276`.
diff --git a/src/test/ui/impl-trait/issue-55872-2.rs b/src/test/ui/impl-trait/issue-55872-2.rs
index 1841d7b3d37..4443d3c4d0d 100644
--- a/src/test/ui/impl-trait/issue-55872-2.rs
+++ b/src/test/ui/impl-trait/issue-55872-2.rs
@@ -3,17 +3,16 @@
 #![feature(type_alias_impl_trait)]
 
 pub trait Bar {
-    type E: Copy;
+    type E: Send;
 
     fn foo<T>() -> Self::E;
 }
 
 impl<S> Bar for S {
-    type E = impl std::marker::Copy;
+    type E = impl std::marker::Send;
     fn foo<T>() -> Self::E {
-        //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-        //~| ERROR the trait bound `impl Future: Copy` is not satisfied
         async {}
+        //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
     }
 }
 
diff --git a/src/test/ui/impl-trait/issue-55872-2.stderr b/src/test/ui/impl-trait/issue-55872-2.stderr
index 76122e60c4c..11b8485c8bb 100644
--- a/src/test/ui/impl-trait/issue-55872-2.stderr
+++ b/src/test/ui/impl-trait/issue-55872-2.stderr
@@ -1,20 +1,8 @@
-error[E0277]: the trait bound `impl Future: Copy` is not satisfied
-  --> $DIR/issue-55872-2.rs:13:20
-   |
-LL |     fn foo<T>() -> Self::E {
-   |                    ^^^^^^^ the trait `Copy` is not implemented for `impl Future`
-
 error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-  --> $DIR/issue-55872-2.rs:13:28
+  --> $DIR/issue-55872-2.rs:14:9
    |
-LL |       fn foo<T>() -> Self::E {
-   |  ____________________________^
-LL | |
-LL | |
-LL | |         async {}
-LL | |     }
-   | |_____^
+LL |         async {}
+   |         ^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/issue-55872-3.rs b/src/test/ui/impl-trait/issue-55872-3.rs
new file mode 100644
index 00000000000..bc2d0b1d757
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-55872-3.rs
@@ -0,0 +1,20 @@
+// edition:2018
+// ignore-compare-mode-chalk
+
+#![feature(type_alias_impl_trait)]
+
+pub trait Bar {
+    type E: Copy;
+
+    fn foo<T>() -> Self::E;
+}
+
+impl<S> Bar for S {
+    type E = impl std::marker::Copy;
+    fn foo<T>() -> Self::E {
+        async {}
+        //~^ ERROR the trait bound `impl Future: Copy` is not satisfied [E0277]
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issue-55872-3.stderr b/src/test/ui/impl-trait/issue-55872-3.stderr
new file mode 100644
index 00000000000..69a5c8d6135
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-55872-3.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `impl Future: Copy` is not satisfied
+  --> $DIR/issue-55872-3.rs:15:9
+   |
+LL |         async {}
+   |         ^^^^^^^^ the trait `Copy` is not implemented for `impl Future`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/issue-55872.rs b/src/test/ui/impl-trait/issue-55872.rs
index 183728b0f7f..c4e6f643608 100644
--- a/src/test/ui/impl-trait/issue-55872.rs
+++ b/src/test/ui/impl-trait/issue-55872.rs
@@ -10,8 +10,8 @@ impl<S> Bar for S {
     type E = impl Copy;
 
     fn foo<T>() -> Self::E {
-        //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
         || ()
+        //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
     }
 }
 
diff --git a/src/test/ui/impl-trait/issue-55872.stderr b/src/test/ui/impl-trait/issue-55872.stderr
index 39d870dc003..cb370fbe1c4 100644
--- a/src/test/ui/impl-trait/issue-55872.stderr
+++ b/src/test/ui/impl-trait/issue-55872.stderr
@@ -1,12 +1,8 @@
 error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-  --> $DIR/issue-55872.rs:12:28
+  --> $DIR/issue-55872.rs:13:9
    |
-LL |       fn foo<T>() -> Self::E {
-   |  ____________________________^
-LL | |
-LL | |         || ()
-LL | |     }
-   | |_____^
+LL |         || ()
+   |         ^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/impl-trait/issue-72911.rs b/src/test/ui/impl-trait/issue-72911.rs
index dee5a41f6de..cf2c8b7e415 100644
--- a/src/test/ui/impl-trait/issue-72911.rs
+++ b/src/test/ui/impl-trait/issue-72911.rs
@@ -5,7 +5,7 @@ pub struct Lint {}
 impl Lint {}
 
 pub fn gather_all() -> impl Iterator<Item = Lint> {
-    //~^ ERROR: cannot resolve opaque type
+    //~^ ERROR `()` is not an iterator
     lint_files().flat_map(|f| gather_from_file(&f))
 }
 
diff --git a/src/test/ui/impl-trait/issue-72911.stderr b/src/test/ui/impl-trait/issue-72911.stderr
index e57fbf104dc..4a990286d96 100644
--- a/src/test/ui/impl-trait/issue-72911.stderr
+++ b/src/test/ui/impl-trait/issue-72911.stderr
@@ -10,25 +10,15 @@ error[E0433]: failed to resolve: use of undeclared crate or module `foo`
 LL | fn lint_files() -> impl Iterator<Item = foo::MissingItem> {
    |                                         ^^^ use of undeclared crate or module `foo`
 
-error[E0720]: cannot resolve opaque type
+error[E0277]: `()` is not an iterator
   --> $DIR/issue-72911.rs:7:24
    |
 LL | pub fn gather_all() -> impl Iterator<Item = Lint> {
-   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive opaque type
-LL |
-LL |     lint_files().flat_map(|f| gather_from_file(&f))
-   |     -----------------------------------------------
-   |     |
-   |     returning here with type `FlatMap<impl Iterator<Item = [type error]>, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
-   |     returning here with type `FlatMap<impl Iterator<Item = [type error]>, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
-...
-LL | fn gather_from_file(dir_entry: &foo::MissingItem) -> impl Iterator<Item = Lint> {
-   |                                                      -------------------------- returning this opaque type `FlatMap<impl Iterator<Item = [type error]>, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
-...
-LL | fn lint_files() -> impl Iterator<Item = foo::MissingItem> {
-   |                    -------------------------------------- returning this opaque type `FlatMap<impl Iterator<Item = [type error]>, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator
+   |
+   = help: the trait `Iterator` is not implemented for `()`
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0433, E0720.
-For more information about an error, try `rustc --explain E0433`.
+Some errors have detailed explanations: E0277, E0433.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/issue-86465.rs b/src/test/ui/impl-trait/issue-86465.rs
index a6976daff01..a79bb6474d8 100644
--- a/src/test/ui/impl-trait/issue-86465.rs
+++ b/src/test/ui/impl-trait/issue-86465.rs
@@ -3,8 +3,8 @@
 type X<'a, 'b> = impl std::fmt::Debug;
 
 fn f<'t, 'u>(a: &'t u32, b: &'u u32) -> (X<'t, 'u>, X<'u, 't>) {
-    //~^ ERROR concrete type differs from previous defining opaque type use
     (a, a)
+    //~^ ERROR concrete type differs from previous defining opaque type use
 }
 
 fn main() {}
diff --git a/src/test/ui/impl-trait/issue-86465.stderr b/src/test/ui/impl-trait/issue-86465.stderr
index 595b16aa685..90d6904ed61 100644
--- a/src/test/ui/impl-trait/issue-86465.stderr
+++ b/src/test/ui/impl-trait/issue-86465.stderr
@@ -1,14 +1,11 @@
 error: concrete type differs from previous defining opaque type use
-  --> $DIR/issue-86465.rs:5:1
+  --> $DIR/issue-86465.rs:6:5
    |
-LL | fn f<'t, 'u>(a: &'t u32, b: &'u u32) -> (X<'t, 'u>, X<'u, 't>) {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&'a u32`, got `&'b u32`
-   |
-note: previous use here
-  --> $DIR/issue-86465.rs:5:1
-   |
-LL | fn f<'t, 'u>(a: &'t u32, b: &'u u32) -> (X<'t, 'u>, X<'u, 't>) {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     (a, a)
+   |     ^^^^^^
+   |     |
+   |     expected `&'a u32`, got `&'b u32`
+   |     this expression supplies two conflicting concrete types for the same opaque type
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/impl-trait/issues/issue-54895.rs b/src/test/ui/impl-trait/issues/issue-54895.rs
new file mode 100644
index 00000000000..a70166e03a7
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-54895.rs
@@ -0,0 +1,23 @@
+// check-pass
+
+trait Trait<'a> {
+    type Out;
+    fn call(&'a self) -> Self::Out;
+}
+
+struct X(());
+
+impl<'a> Trait<'a> for X {
+    type Out = ();
+    fn call(&'a self) -> Self::Out {
+        ()
+    }
+}
+
+fn f() -> impl for<'a> Trait<'a, Out = impl Sized + 'a> {
+    X(())
+}
+
+fn main() {
+    let _ = f();
+}
diff --git a/src/test/ui/impl-trait/issues/issue-62742.rs b/src/test/ui/impl-trait/issues/issue-62742.rs
new file mode 100644
index 00000000000..041bd0e3855
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-62742.rs
@@ -0,0 +1,32 @@
+use std::marker::PhantomData;
+
+fn _alias_check() {
+    WrongImpl::foo(0i32);
+    //~^ ERROR the trait bound `RawImpl<_>: Raw<_>` is not satisfied
+    WrongImpl::<()>::foo(0i32);
+    //~^ ERROR the trait bound `RawImpl<()>: Raw<()>` is not satisfied
+    //~| ERROR trait bounds were not satisfied
+    CorrectImpl::foo(0i32);
+}
+
+pub trait Raw<T: ?Sized> {
+    type Value;
+}
+
+pub type WrongImpl<T> = SafeImpl<T, RawImpl<T>>;
+
+pub type CorrectImpl<T> = SafeImpl<[T], RawImpl<T>>;
+
+pub struct RawImpl<T>(PhantomData<T>);
+
+impl<T> Raw<[T]> for RawImpl<T> {
+    type Value = T;
+}
+
+pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
+
+impl<T: ?Sized, A: Raw<T>> SafeImpl<T, A> {
+    pub fn foo(value: A::Value) {}
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issues/issue-62742.stderr b/src/test/ui/impl-trait/issues/issue-62742.stderr
new file mode 100644
index 00000000000..28068b7548c
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-62742.stderr
@@ -0,0 +1,54 @@
+error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied
+  --> $DIR/issue-62742.rs:4:5
+   |
+LL |     WrongImpl::foo(0i32);
+   |     ^^^^^^^^^ the trait `Raw<_>` is not implemented for `RawImpl<_>`
+   |
+   = help: the following implementations were found:
+             <RawImpl<T> as Raw<[T]>>
+note: required by a bound in `SafeImpl`
+  --> $DIR/issue-62742.rs:26:35
+   |
+LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
+   |                                   ^^^^^^ required by this bound in `SafeImpl`
+
+error[E0599]: the function or associated item `foo` exists for struct `SafeImpl<(), RawImpl<()>>`, but its trait bounds were not satisfied
+  --> $DIR/issue-62742.rs:6:22
+   |
+LL |     WrongImpl::<()>::foo(0i32);
+   |                      ^^^ function or associated item cannot be called on `SafeImpl<(), RawImpl<()>>` due to unsatisfied trait bounds
+...
+LL | pub struct RawImpl<T>(PhantomData<T>);
+   | -------------------------------------- doesn't satisfy `RawImpl<()>: Raw<()>`
+...
+LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
+   | --------------------------------------------------------------- function or associated item `foo` not found for this
+   |
+   = note: the following trait bounds were not satisfied:
+           `RawImpl<()>: Raw<()>`
+note: the following trait must be implemented
+  --> $DIR/issue-62742.rs:12:1
+   |
+LL | / pub trait Raw<T: ?Sized> {
+LL | |     type Value;
+LL | | }
+   | |_^
+
+error[E0277]: the trait bound `RawImpl<()>: Raw<()>` is not satisfied
+  --> $DIR/issue-62742.rs:6:5
+   |
+LL |     WrongImpl::<()>::foo(0i32);
+   |     ^^^^^^^^^^^^^^^ the trait `Raw<()>` is not implemented for `RawImpl<()>`
+   |
+   = help: the following implementations were found:
+             <RawImpl<T> as Raw<[T]>>
+note: required by a bound in `SafeImpl`
+  --> $DIR/issue-62742.rs:26:35
+   |
+LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
+   |                                   ^^^^^^ required by this bound in `SafeImpl`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0277, E0599.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/issues/issue-67830.nll.stderr b/src/test/ui/impl-trait/issues/issue-67830.nll.stderr
new file mode 100644
index 00000000000..17fbe046e3a
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-67830.nll.stderr
@@ -0,0 +1,20 @@
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/issue-67830.rs:23:5
+   |
+LL |     Wrap(|a| Some(a).into_iter())
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'2 A) -> std::option::IntoIter<&A>` must implement `FnOnce<(&'1 A,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 A,)>`, for some specific lifetime `'2`
+
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/issue-67830.rs:23:5
+   |
+LL |     Wrap(|a| Some(a).into_iter())
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'2 A) -> std::option::IntoIter<&A>` must implement `FnOnce<(&'1 A,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 A,)>`, for some specific lifetime `'2`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/impl-trait/issues/issue-67830.rs b/src/test/ui/impl-trait/issues/issue-67830.rs
new file mode 100644
index 00000000000..a308d975b43
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-67830.rs
@@ -0,0 +1,26 @@
+trait MyFn<Arg> {
+    type Output;
+    fn call(&self, arg: Arg) -> Self::Output;
+}
+
+struct Wrap<F>(F);
+
+impl<A, B, F> MyFn<A> for Wrap<F>
+where
+    F: Fn(A) -> B
+{
+    type Output = B;
+
+    fn call(&self, arg: A) -> Self::Output {
+        (self.0)(arg)
+    }
+}
+
+
+struct A;
+fn test() -> impl for<'a> MyFn<&'a A, Output=impl Iterator + 'a> {
+    //~^ ERROR implementation of `FnOnce` is not general enough
+    Wrap(|a| Some(a).into_iter())
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issues/issue-67830.stderr b/src/test/ui/impl-trait/issues/issue-67830.stderr
new file mode 100644
index 00000000000..74e2f99cd33
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-67830.stderr
@@ -0,0 +1,15 @@
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/issue-67830.rs:21:66
+   |
+LL |   fn test() -> impl for<'a> MyFn<&'a A, Output=impl Iterator + 'a> {
+   |  __________________________________________________________________^
+LL | |
+LL | |     Wrap(|a| Some(a).into_iter())
+LL | | }
+   | |_^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'2 A) -> std::option::IntoIter<&A>` must implement `FnOnce<(&'1 A,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 A,)>`, for some specific lifetime `'2`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/impl-trait/issues/issue-70877.rs b/src/test/ui/impl-trait/issues/issue-70877.rs
index 853c2a82bed..1a86fa00ed1 100644
--- a/src/test/ui/impl-trait/issues/issue-70877.rs
+++ b/src/test/ui/impl-trait/issues/issue-70877.rs
@@ -4,7 +4,7 @@ type FooArg<'a> = &'a dyn ToString;
 type FooRet = impl std::fmt::Debug;
 
 type FooItem = Box<dyn Fn(FooArg) -> FooRet>;
-type Foo = impl Iterator<Item = FooItem>; //~ ERROR: type mismatch
+type Foo = impl Iterator<Item = FooItem>;
 
 #[repr(C)]
 struct Bar(u8);
@@ -13,7 +13,7 @@ impl Iterator for Bar {
     type Item = FooItem;
 
     fn next(&mut self) -> Option<Self::Item> {
-        Some(Box::new(quux))
+        Some(Box::new(quux)) //~ ERROR mismatched types
     }
 }
 
@@ -28,7 +28,7 @@ fn ham() -> Foo {
 fn oof() -> impl std::fmt::Debug {
     let mut bar = ham();
     let func = bar.next().unwrap();
-    return func(&"oof");
+    return func(&"oof"); //~ ERROR opaque type's hidden type cannot be another opaque type
 }
 
 fn main() {
diff --git a/src/test/ui/impl-trait/issues/issue-70877.stderr b/src/test/ui/impl-trait/issues/issue-70877.stderr
index fe48e92da5e..7cbd58bdabf 100644
--- a/src/test/ui/impl-trait/issues/issue-70877.stderr
+++ b/src/test/ui/impl-trait/issues/issue-70877.stderr
@@ -1,20 +1,34 @@
-error[E0271]: type mismatch resolving `<Bar as Iterator>::Item == Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>`
-  --> $DIR/issue-70877.rs:7:12
+error[E0308]: mismatched types
+  --> $DIR/issue-70877.rs:16:9
    |
 LL | type FooRet = impl std::fmt::Debug;
-   |               -------------------- the found opaque type
+   |               -------------------- the expected opaque type
 ...
-LL | type Foo = impl Iterator<Item = FooItem>;
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Bar as Iterator>::Item == Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>`
+LL |     fn next(&mut self) -> Option<Self::Item> {
+   |                           ------------------ expected `Option<Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> FooRet + 'static)>>` because of return type
+LL |         Some(Box::new(quux))
+   |         ^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found fn item
    |
-note: expected this to be `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>`
-  --> $DIR/issue-70877.rs:13:17
+   = note: expected enum `Option<Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> FooRet + 'static)>>`
+              found enum `Option<Box<for<'r> fn(&'r (dyn ToString + 'r)) -> FooRet {quux}>>`
+
+error: opaque type's hidden type cannot be another opaque type from the same scope
+  --> $DIR/issue-70877.rs:31:12
+   |
+LL |     return func(&"oof");
+   |            ^^^^^^^^^^^^ one of the two opaque types used here has to be outside its defining scope
+   |
+note: opaque type whose hidden type is being assigned
+  --> $DIR/issue-70877.rs:28:13
    |
-LL |     type Item = FooItem;
-   |                 ^^^^^^^
-   = note: expected struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>`
-              found struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> impl Debug + 'static)>`
+LL | fn oof() -> impl std::fmt::Debug {
+   |             ^^^^^^^^^^^^^^^^^^^^
+note: opaque type being used as hidden type
+  --> $DIR/issue-70877.rs:4:15
+   |
+LL | type FooRet = impl std::fmt::Debug;
+   |               ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/impl-trait/issues/issue-74282.rs b/src/test/ui/impl-trait/issues/issue-74282.rs
new file mode 100644
index 00000000000..654de0cd025
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-74282.rs
@@ -0,0 +1,11 @@
+#![feature(type_alias_impl_trait)]
+
+type Closure = impl Fn() -> u64;
+struct Anonymous(Closure);
+
+fn main() {
+    let y = || -> Closure { || 3 };
+    Anonymous(|| { //~ ERROR mismatched types
+        3 //~^ ERROR mismatched types
+    })
+}
diff --git a/src/test/ui/impl-trait/issues/issue-74282.stderr b/src/test/ui/impl-trait/issues/issue-74282.stderr
new file mode 100644
index 00000000000..6e02a6b2b87
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-74282.stderr
@@ -0,0 +1,33 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-74282.rs:8:15
+   |
+LL |   type Closure = impl Fn() -> u64;
+   |                  ---------------- the expected opaque type
+...
+LL |       Anonymous(|| {
+   |  _______________^
+LL | |         3
+LL | |     })
+   | |_____^ expected closure, found a different closure
+   |
+   = note: expected opaque type `Closure`
+                  found closure `[closure@$DIR/issue-74282.rs:8:15: 10:6]`
+   = note: no two closures, even if identical, have the same type
+   = help: consider boxing your closure and/or using it as a trait object
+
+error[E0308]: mismatched types
+  --> $DIR/issue-74282.rs:8:5
+   |
+LL |   fn main() {
+   |             - expected `()` because of default return type
+LL |       let y = || -> Closure { || 3 };
+LL | /     Anonymous(|| {
+LL | |         3
+LL | |     })
+   | |      ^- help: consider using a semicolon here: `;`
+   | |______|
+   |        expected `()`, found struct `Anonymous`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/impl-trait/issues/issue-77987.rs b/src/test/ui/impl-trait/issues/issue-77987.rs
new file mode 100644
index 00000000000..d29710b6f54
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-77987.rs
@@ -0,0 +1,21 @@
+#![feature(type_alias_impl_trait)]
+
+// check-pass
+
+trait Foo<T> {}
+impl<T, U> Foo<T> for U {}
+
+type Scope = impl Foo<()>;
+
+#[allow(unused)]
+fn infer_scope() -> Scope {
+    ()
+}
+
+#[allow(unused)]
+fn ice() -> impl Foo<Scope>
+{
+    loop {}
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issues/issue-78722.rs b/src/test/ui/impl-trait/issues/issue-78722.rs
index bdbd20f9d2b..5498793bc28 100644
--- a/src/test/ui/impl-trait/issues/issue-78722.rs
+++ b/src/test/ui/impl-trait/issues/issue-78722.rs
@@ -7,10 +7,11 @@ type F = impl core::future::Future<Output = u8>;
 struct Bug {
     V1: [(); {
         fn concrete_use() -> F {
-            async {}
+            async {} //~ ERROR type mismatch
         }
         let f: F = async { 1 };
-        //~^ ERROR mismatched types [E0308]
+        //~^ ERROR `async` blocks are not allowed in constants
+        //~| ERROR destructors cannot be evaluated at compile-time
         1
     }],
 }
diff --git a/src/test/ui/impl-trait/issues/issue-78722.stderr b/src/test/ui/impl-trait/issues/issue-78722.stderr
index 86bde9a0cdd..624d85570c7 100644
--- a/src/test/ui/impl-trait/issues/issue-78722.stderr
+++ b/src/test/ui/impl-trait/issues/issue-78722.stderr
@@ -1,23 +1,28 @@
-error[E0308]: mismatched types
+error[E0658]: `async` blocks are not allowed in constants
   --> $DIR/issue-78722.rs:12:20
    |
-LL | type F = impl core::future::Future<Output = u8>;
-   |          -------------------------------------- the expected opaque type
-...
 LL |         let f: F = async { 1 };
-   |                -   ^^^^^^^^^^^ expected opaque type, found a different opaque type
-   |                |
-   |                expected due to this
+   |                    ^^^^^^^^^^^
    |
-  ::: $SRC_DIR/core/src/future/mod.rs:LL:COL
+   = note: see issue #85368 <https://github.com/rust-lang/rust/issues/85368> for more information
+   = help: add `#![feature(const_async_blocks)]` to the crate attributes to enable
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/issue-78722.rs:12:13
    |
-LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
-   |                                           ------------------------------- the found opaque type
+LL |         let f: F = async { 1 };
+   |             ^ constants cannot evaluate destructors
+...
+LL |     }],
+   |     - value is dropped here
+
+error[E0271]: type mismatch resolving `<impl Future as Future>::Output == u8`
+  --> $DIR/issue-78722.rs:10:13
    |
-   = note: expected opaque type `impl Future<Output = u8>`
-              found opaque type `impl Future`
-   = note: distinct uses of `impl Trait` result in different opaque types
+LL |             async {}
+   |             ^^^^^^^^ expected `()`, found `u8`
 
-error: aborting due to previous error
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
+Some errors have detailed explanations: E0271, E0493, E0658.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/src/test/ui/impl-trait/issues/issue-82139.rs b/src/test/ui/impl-trait/issues/issue-82139.rs
new file mode 100644
index 00000000000..cc9167b340a
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-82139.rs
@@ -0,0 +1,19 @@
+#![feature(type_alias_impl_trait)]
+
+trait Trait {
+    type Associated;
+    fn func() -> Self::Associated;
+}
+
+trait Bound {}
+pub struct Struct;
+
+impl Trait for Struct {
+    type Associated = impl Bound;
+
+    fn func() -> Self::Associated {
+        Some(42).map(|_| j) //~ ERROR cannot find value `j` in this scope
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issues/issue-82139.stderr b/src/test/ui/impl-trait/issues/issue-82139.stderr
new file mode 100644
index 00000000000..0adcd4a7a2f
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-82139.stderr
@@ -0,0 +1,9 @@
+error[E0425]: cannot find value `j` in this scope
+  --> $DIR/issue-82139.rs:15:26
+   |
+LL |         Some(42).map(|_| j)
+   |                          ^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/impl-trait/issues/issue-83919.rs b/src/test/ui/impl-trait/issues/issue-83919.rs
new file mode 100644
index 00000000000..58aca77fdf1
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-83919.rs
@@ -0,0 +1,31 @@
+#![feature(type_alias_impl_trait)]
+
+// edition:2021
+
+use std::future::Future;
+
+trait Foo {
+    type T;
+    type Fut2: Future<Output=Self::T>; // ICE got triggered with traits other than Future here
+    type Fut: Future<Output=Self::Fut2>;
+    fn get_fut(&self) -> Self::Fut;
+}
+
+struct Implementor;
+
+impl Foo for Implementor {
+    type T = u64;
+    type Fut2 = impl Future<Output=u64>;
+    type Fut = impl Future<Output=Self::Fut2>;
+
+    fn get_fut(&self) -> Self::Fut {
+        async move {
+            42 //~^ ERROR `{integer}` is not a future
+            // 42 does not impl Future and rustc does actually point out the error,
+            // but rustc used to panic.
+            // Putting a valid Future here always worked fine.
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issues/issue-83919.stderr b/src/test/ui/impl-trait/issues/issue-83919.stderr
new file mode 100644
index 00000000000..ebd0130be8d
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-83919.stderr
@@ -0,0 +1,17 @@
+error[E0277]: `{integer}` is not a future
+  --> $DIR/issue-83919.rs:22:9
+   |
+LL | /         async move {
+LL | |             42
+LL | |             // 42 does not impl Future and rustc does actually point out the error,
+LL | |             // but rustc used to panic.
+LL | |             // Putting a valid Future here always worked fine.
+LL | |         }
+   | |_________^ `{integer}` is not a future
+   |
+   = help: the trait `Future` is not implemented for `{integer}`
+   = note: {integer} must be a future or must implement `IntoFuture` to be awaited
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/issues/issue-84073.rs b/src/test/ui/impl-trait/issues/issue-84073.rs
new file mode 100644
index 00000000000..49a34ccfa3b
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-84073.rs
@@ -0,0 +1,33 @@
+use std::marker::PhantomData;
+
+pub trait StatefulFuture<S> {}
+pub struct Never<T>(PhantomData<T>);
+impl<T> StatefulFuture<T> for Never<T> {}
+
+pub struct RaceBuilder<F, S> {
+    future: F,
+    _phantom: PhantomData<S>,
+}
+
+impl<T, F> RaceBuilder<T, F>
+where
+    F: StatefulFuture<Option<T>>,
+{
+    pub fn when(self) {}
+}
+
+pub struct Race<T, R> {
+    race: R,
+    _phantom: PhantomData<T>,
+}
+
+impl<T, R> Race<T, R>
+where
+    R: Fn(RaceBuilder<T, Never<T>>),
+{
+    pub fn new(race: R) {}
+}
+
+fn main() {
+    Race::new(|race| race.when()); //~ ERROR type annotations needed
+}
diff --git a/src/test/ui/impl-trait/issues/issue-84073.stderr b/src/test/ui/impl-trait/issues/issue-84073.stderr
new file mode 100644
index 00000000000..36047d23fed
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-84073.stderr
@@ -0,0 +1,9 @@
+error[E0282]: type annotations needed for `RaceBuilder<T, Never<T>>`
+  --> $DIR/issue-84073.rs:32:16
+   |
+LL |     Race::new(|race| race.when());
+   |                ^^^^ consider giving this closure parameter the explicit type `RaceBuilder<T, Never<T>>`, where the type parameter `T` is specified
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/impl-trait/issues/issue-86201.rs b/src/test/ui/impl-trait/issues/issue-86201.rs
index e3386d29def..0786e66ca8b 100644
--- a/src/test/ui/impl-trait/issues/issue-86201.rs
+++ b/src/test/ui/impl-trait/issues/issue-86201.rs
@@ -1,10 +1,10 @@
 #![feature(unboxed_closures)]
 #![feature(type_alias_impl_trait)]
 
+// check-pass
+
 type FunType = impl Fn<()>;
-//~^ ERROR could not find defining uses
 static STATIC_FN: FunType = some_fn;
-//~^ ERROR mismatched types
 
 fn some_fn() {}
 
diff --git a/src/test/ui/impl-trait/issues/issue-86201.stderr b/src/test/ui/impl-trait/issues/issue-86201.stderr
deleted file mode 100644
index b1460096ded..00000000000
--- a/src/test/ui/impl-trait/issues/issue-86201.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/issue-86201.rs:6:29
-   |
-LL | type FunType = impl Fn<()>;
-   |                ----------- the expected opaque type
-LL |
-LL | static STATIC_FN: FunType = some_fn;
-   |                             ^^^^^^^ expected opaque type, found fn item
-   |
-   = note: expected opaque type `impl Fn<()>`
-                  found fn item `fn() {some_fn}`
-
-error: could not find defining uses
-  --> $DIR/issue-86201.rs:4:16
-   |
-LL | type FunType = impl Fn<()>;
-   |                ^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/impl-trait/issues/issue-86719.rs b/src/test/ui/impl-trait/issues/issue-86719.rs
new file mode 100644
index 00000000000..f4b0b3f33fc
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-86719.rs
@@ -0,0 +1,12 @@
+#![feature(type_alias_impl_trait)]
+
+trait Bar {
+    type E;
+}
+impl<S> Bar for S {
+    type E = impl ; //~ ERROR at least one trait must be specified
+    fn foo() -> Self::E { //~ ERROR `foo` is not a member
+        |_| true //~ ERROR type annotations needed
+    }
+}
+fn main() {}
diff --git a/src/test/ui/impl-trait/issues/issue-86719.stderr b/src/test/ui/impl-trait/issues/issue-86719.stderr
new file mode 100644
index 00000000000..e2abf71c110
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-86719.stderr
@@ -0,0 +1,24 @@
+error: at least one trait must be specified
+  --> $DIR/issue-86719.rs:7:14
+   |
+LL |     type E = impl ;
+   |              ^^^^
+
+error[E0407]: method `foo` is not a member of trait `Bar`
+  --> $DIR/issue-86719.rs:8:5
+   |
+LL | /     fn foo() -> Self::E {
+LL | |         |_| true
+LL | |     }
+   | |_____^ not a member of trait `Bar`
+
+error[E0282]: type annotations needed
+  --> $DIR/issue-86719.rs:9:10
+   |
+LL |         |_| true
+   |          ^ consider giving this closure parameter a type
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0282, E0407.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/src/test/ui/impl-trait/issues/issue-86800.rs b/src/test/ui/impl-trait/issues/issue-86800.rs
new file mode 100644
index 00000000000..e8cef42f208
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-86800.rs
@@ -0,0 +1,48 @@
+#![feature(type_alias_impl_trait)]
+
+// edition:2021
+
+use std::future::Future;
+
+struct Connection {
+}
+
+trait Transaction {
+}
+
+struct TestTransaction<'conn> {
+    conn: &'conn Connection
+}
+
+impl<'conn> Transaction for TestTransaction<'conn> {
+}
+
+struct Context {
+}
+
+type TransactionResult<O> = Result<O, ()>;
+
+type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>;
+//~^ ERROR unconstrained opaque type
+
+fn execute_transaction_fut<'f, F, O>(
+    f: F,
+) -> impl FnOnce(&mut dyn Transaction) -> TransactionFuture<O>
+where
+    F: FnOnce(&mut dyn Transaction) -> TransactionFuture<O> + 'f
+{
+    f
+}
+
+impl Context {
+    async fn do_transaction<O>(
+        &self, f: impl FnOnce(&mut dyn Transaction) -> TransactionFuture<O>
+    ) -> TransactionResult<O>
+    {
+        let mut conn = Connection {};
+        let mut transaction = TestTransaction { conn: &mut conn };
+        f(&mut transaction).await
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issues/issue-86800.stderr b/src/test/ui/impl-trait/issues/issue-86800.stderr
new file mode 100644
index 00000000000..787aecc5b84
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-86800.stderr
@@ -0,0 +1,10 @@
+error: unconstrained opaque type
+  --> $DIR/issue-86800.rs:25:34
+   |
+LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>;
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `TransactionFuture` must be used in combination with a concrete type within the same module
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/impl-trait/issues/issue-87340.rs b/src/test/ui/impl-trait/issues/issue-87340.rs
new file mode 100644
index 00000000000..f0f6d2bb61c
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-87340.rs
@@ -0,0 +1,14 @@
+#![feature(type_alias_impl_trait)]
+
+trait X {
+    type I;
+    fn f() -> Self::I;
+}
+
+impl<T> X for () {
+//~^ ERROR `T` is not constrained by the impl trait, self type, or predicates
+    type I = impl Sized;
+    fn f() -> Self::I {}
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issues/issue-87340.stderr b/src/test/ui/impl-trait/issues/issue-87340.stderr
new file mode 100644
index 00000000000..2ab1e6a0312
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-87340.stderr
@@ -0,0 +1,9 @@
+error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/issue-87340.rs:8:6
+   |
+LL | impl<T> X for () {
+   |      ^ unconstrained type parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0207`.
diff --git a/src/test/ui/impl-trait/issues/issue-88236-2.nll.stderr b/src/test/ui/impl-trait/issues/issue-88236-2.nll.stderr
new file mode 100644
index 00000000000..9cf8ff76c87
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-88236-2.nll.stderr
@@ -0,0 +1,51 @@
+error: implementation of `Hrtb` is not general enough
+  --> $DIR/issue-88236-2.rs:17:5
+   |
+LL |     &()
+   |     ^^^ implementation of `Hrtb` is not general enough
+   |
+   = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`...
+   = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1`
+
+error: implementation of `Hrtb` is not general enough
+  --> $DIR/issue-88236-2.rs:17:5
+   |
+LL |     &()
+   |     ^^^ implementation of `Hrtb` is not general enough
+   |
+   = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`...
+   = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/issue-88236-2.rs:20:5
+   |
+LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {
+   |                  -- lifetime `'b` defined here
+LL |     x
+   |     ^ returning this value requires that `'b` must outlive `'static`
+   |
+help: to allow this `impl Trait` to capture borrowed data with lifetime `'b`, add `'b` as a bound
+   |
+LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> + 'b {
+   |                                                                                  ++++
+
+error: implementation of `Hrtb` is not general enough
+  --> $DIR/issue-88236-2.rs:20:5
+   |
+LL |     x
+   |     ^ implementation of `Hrtb` is not general enough
+   |
+   = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`...
+   = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1`
+
+error: implementation of `Hrtb` is not general enough
+  --> $DIR/issue-88236-2.rs:20:5
+   |
+LL |     x
+   |     ^ implementation of `Hrtb` is not general enough
+   |
+   = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`...
+   = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/impl-trait/issues/issue-88236-2.rs b/src/test/ui/impl-trait/issues/issue-88236-2.rs
new file mode 100644
index 00000000000..af26a1f54c4
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-88236-2.rs
@@ -0,0 +1,23 @@
+// this used to cause stack overflows
+
+trait Hrtb<'a> {
+    type Assoc;
+}
+
+impl<'a> Hrtb<'a> for () {
+    type Assoc = ();
+}
+
+impl<'a> Hrtb<'a> for &'a () {
+    type Assoc = ();
+}
+
+fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {}
+fn make_weird_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {
+    &() //~^ ERROR implementation of `Hrtb` is not general enough
+}
+fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {
+    x //~^ ERROR implementation of `Hrtb` is not general enough
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issues/issue-88236-2.stderr b/src/test/ui/impl-trait/issues/issue-88236-2.stderr
new file mode 100644
index 00000000000..45fadcab3f2
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-88236-2.stderr
@@ -0,0 +1,23 @@
+error: implementation of `Hrtb` is not general enough
+  --> $DIR/issue-88236-2.rs:16:38
+   |
+LL | fn make_weird_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Hrtb` is not general enough
+   |
+   = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`...
+   = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1`
+
+error: implementation of `Hrtb` is not general enough
+  --> $DIR/issue-88236-2.rs:19:82
+   |
+LL |   fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {
+   |  __________________________________________________________________________________^
+LL | |     x
+LL | | }
+   | |_^ implementation of `Hrtb` is not general enough
+   |
+   = note: `&()` must implement `Hrtb<'0>`, for any lifetime `'0`...
+   = note: ...but `Hrtb<'_>` is actually implemented for the type `&()`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/impl-trait/issues/issue-88236.rs b/src/test/ui/impl-trait/issues/issue-88236.rs
new file mode 100644
index 00000000000..2ea35270a7e
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-88236.rs
@@ -0,0 +1,19 @@
+// check-pass
+
+// this used to cause stack overflows
+
+trait Hrtb<'a> {
+    type Assoc;
+}
+
+impl<'a> Hrtb<'a> for () {
+    type Assoc = ();
+}
+
+impl<'a> Hrtb<'a> for &'a () {
+    type Assoc = ();
+}
+
+fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issues/issue-89312.rs b/src/test/ui/impl-trait/issues/issue-89312.rs
new file mode 100644
index 00000000000..d685a6f1201
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-89312.rs
@@ -0,0 +1,24 @@
+#![feature(type_alias_impl_trait)]
+
+// check-pass
+
+trait T { type Item; }
+
+type Alias<'a> = impl T<Item = &'a ()>;
+
+struct S;
+impl<'a> T for &'a S {
+    type Item = &'a ();
+}
+
+fn filter_positive<'a>() -> Alias<'a> {
+    &S
+}
+
+fn with_positive(fun: impl Fn(Alias<'_>)) {
+    fun(filter_positive());
+}
+
+fn main() {
+    with_positive(|_| ());
+}
diff --git a/src/test/ui/impl-trait/issues/issue-93788.rs b/src/test/ui/impl-trait/issues/issue-93788.rs
new file mode 100644
index 00000000000..6924931cda5
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-93788.rs
@@ -0,0 +1,27 @@
+// check-pass
+
+struct D;
+
+trait Tr {
+    type It;
+    fn foo(self) -> Option<Self::It>;
+}
+
+impl<'a> Tr for &'a D {
+    type It = ();
+    fn foo(self) -> Option<()> { None }
+}
+
+fn run<F>(f: F)
+    where for<'a> &'a D: Tr,
+          F: Fn(<&D as Tr>::It),
+{
+    let d = &D;
+    while let Some(i) = d.foo() {
+        f(i);
+    }
+}
+
+fn main() {
+    run(|_| {});
+}
diff --git a/src/test/ui/impl-trait/lifetimes2.rs b/src/test/ui/impl-trait/lifetimes2.rs
new file mode 100644
index 00000000000..834f2dc6cb5
--- /dev/null
+++ b/src/test/ui/impl-trait/lifetimes2.rs
@@ -0,0 +1,10 @@
+// check-pass
+
+pub fn keys<'a>(x: &'a Result<u32, u32>) -> impl std::fmt::Debug + 'a {
+    match x {
+        Ok(map) => Ok(map),
+        Err(map) => Err(map),
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs b/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs
index 72e9d96da36..f5aaf118521 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs
+++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs
@@ -8,7 +8,6 @@ impl<T: Copy> Copy for CopyIfEq<T, T> {}
 type E<'a, 'b> = impl Sized;
 
 fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
-    //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
     let v = CopyIfEq::<*mut _, *mut _>(&mut { x }, &mut y);
 
     // This assignment requires that `x` and `y` have the same type due to the
@@ -21,6 +20,7 @@ fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
         let _: &'b i32 = *u.0;
     }
     u.0
+    //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
 }
 
 fn main() {}
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr b/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr
index 40bec0da270..b837b641103 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr
+++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr
@@ -1,10 +1,11 @@
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/error-handling-2.rs:10:60
+  --> $DIR/error-handling-2.rs:22:5
    |
 LL | fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
-   |        --                                                  ^^^^^^^^^
-   |        |
-   |        hidden type `*mut &'a i32` captures the lifetime `'a` as defined here
+   |        -- hidden type `*mut &'a i32` captures the lifetime `'a` as defined here
+...
+LL |     u.0
+   |     ^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs
index 3a97624647e..47e05bce0f8 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs
@@ -14,7 +14,6 @@ struct Ordinary<'a>(&'a u8);
 // by both `'a` and `'b`.
 
 fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
-//~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
 where
     'a: 'e,
     'b: 'd,
@@ -27,6 +26,7 @@ where
     // 'a in ['d, 'e]
     // ```
     if condition() { a } else { b }
+    //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
 }
 
 fn condition() -> bool {
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
index 32829a0a1b2..15476c706a7 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
@@ -1,10 +1,11 @@
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/ordinary-bounds-unrelated.rs:16:74
+  --> $DIR/ordinary-bounds-unrelated.rs:28:33
    |
 LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
-   |                     --                                                   ^^^^^^^^^^^^^^^^^^
-   |                     |
-   |                     hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
+   |                     -- hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
+...
+LL |     if condition() { a } else { b }
+   |                                 ^
    |
 help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
    |
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs
index d4c60a4e892..321cb8c92a1 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs
@@ -16,7 +16,6 @@ struct Ordinary<'a>(&'a u8);
 // consider the loans for both `'a` and `'b` alive.
 
 fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
-//~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
 {
     // We return a value:
     //
@@ -30,6 +29,7 @@ fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
     //
     // We are forced to pick that '0 = 'e, because only 'e is outlived by *both* 'a and 'b.
     if condition() { a } else { b }
+    //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
 }
 
 fn condition() -> bool {
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
index 83ad23b253b..7315aa8e9d4 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
@@ -1,10 +1,11 @@
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/ordinary-bounds-unsuited.rs:18:62
+  --> $DIR/ordinary-bounds-unsuited.rs:31:33
    |
 LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
-   |                     --                                       ^^^^^^^^^^^^^^^^^^
-   |                     |
-   |                     hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
+   |                     -- hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
+...
+LL |     if condition() { a } else { b }
+   |                                 ^
    |
 help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
    |
diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
index 2f6bd8ff377..9589b69491e 100644
--- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
+++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
@@ -1,8 +1,8 @@
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/must_outlive_least_region_or_bound.rs:3:23
+  --> $DIR/must_outlive_least_region_or_bound.rs:3:35
    |
 LL | fn elided(x: &i32) -> impl Copy { x }
-   |              ----     ^^^^^^^^^
+   |              ----                 ^
    |              |
    |              hidden type `&i32` captures the anonymous lifetime defined here
    |
@@ -12,10 +12,10 @@ LL | fn elided(x: &i32) -> impl Copy + '_ { x }
    |                                 ++++
 
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/must_outlive_least_region_or_bound.rs:6:32
+  --> $DIR/must_outlive_least_region_or_bound.rs:6:44
    |
 LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
-   |             --                 ^^^^^^^^^
+   |             --                             ^
    |             |
    |             hidden type `&'a i32` captures the lifetime `'a` as defined here
    |
@@ -67,12 +67,12 @@ LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
    = help: consider replacing `'a` with `'static`
 
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/must_outlive_least_region_or_bound.rs:33:61
+  --> $DIR/must_outlive_least_region_or_bound.rs:34:5
    |
 LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
-   |                              --                             ^^^^^^^^^^^^^^^^
-   |                              |
-   |                              hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:35:5: 35:31]` captures the lifetime `'b` as defined here
+   |                              -- hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:34:5: 34:31]` captures the lifetime `'b` as defined here
+LL |     move |_| println!("{}", y)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
    |
@@ -80,10 +80,10 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32
    |                                                                              ++++
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:38:51
+  --> $DIR/must_outlive_least_region_or_bound.rs:41:5
    |
-LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
-   |                                                   ^^^^^^^^^^^^^^^^^^^^
+LL |     x
+   |     ^
    |
    = help: consider adding an explicit lifetime bound `T: 'static`...
 
diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs
index 69d2843ff3f..baa42da6446 100644
--- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs
+++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs
@@ -31,12 +31,13 @@ fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } //~ ERRO
 // Tests that a closure type containing 'b cannot be returned from a type where
 // only 'a was expected.
 fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
-    //~^ ERROR: captures lifetime that does not appear in bounds
     move |_| println!("{}", y)
+    //~^ ERROR: captures lifetime that does not appear in bounds
 }
 
 fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
     //~^ ERROR the parameter type `T` may not live long enough
+    //~| ERROR the parameter type `T` may not live long enough
     x
 }
 
diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
index 07ac0a8db35..1272adb35e9 100644
--- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
+++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
@@ -1,8 +1,8 @@
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/must_outlive_least_region_or_bound.rs:3:23
+  --> $DIR/must_outlive_least_region_or_bound.rs:3:35
    |
 LL | fn elided(x: &i32) -> impl Copy { x }
-   |              ----     ^^^^^^^^^
+   |              ----                 ^
    |              |
    |              hidden type `&i32` captures the anonymous lifetime defined here
    |
@@ -12,10 +12,10 @@ LL | fn elided(x: &i32) -> impl Copy + '_ { x }
    |                                 ++++
 
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/must_outlive_least_region_or_bound.rs:6:32
+  --> $DIR/must_outlive_least_region_or_bound.rs:6:44
    |
 LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
-   |             --                 ^^^^^^^^^
+   |             --                             ^
    |             |
    |             hidden type `&'a i32` captures the lifetime `'a` as defined here
    |
@@ -112,12 +112,12 @@ LL | fn with_bound<'a>(x: &'static i32) -> impl LifetimeTrait<'a> + 'static { x
    |                      ~~~~~~~~~~~~
 
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/must_outlive_least_region_or_bound.rs:33:61
+  --> $DIR/must_outlive_least_region_or_bound.rs:34:5
    |
 LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
-   |                              --                             ^^^^^^^^^^^^^^^^
-   |                              |
-   |                              hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:35:5: 35:31]` captures the lifetime `'b` as defined here
+   |                              -- hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:34:5: 34:31]` captures the lifetime `'b` as defined here
+LL |     move |_| println!("{}", y)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
    |
@@ -132,6 +132,19 @@ LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
    |                                 |
    |                                 help: consider adding an explicit lifetime bound...: `T: 'static +`
 
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/must_outlive_least_region_or_bound.rs:38:72
+   |
+LL |   fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
+   |  _________________________________--_____________________________________^
+   | |                                 |
+   | |                                 help: consider adding an explicit lifetime bound...: `T: 'static +`
+LL | |
+LL | |
+LL | |     x
+LL | | }
+   | |_^ ...so that the type `T` will meet its required lifetime bounds
+
 error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/must_outlive_least_region_or_bound.rs:16:50
    |
@@ -218,7 +231,7 @@ help: alternatively, add an explicit `'static` bound to this reference
 LL | fn explicit4<'a>(x: &'static i32) -> Box<dyn Debug + 'static> { Box::new(x) }
    |                     ~~~~~~~~~~~~
 
-error: aborting due to 13 previous errors
+error: aborting due to 14 previous errors
 
 Some errors have detailed explanations: E0310, E0621, E0700, E0759.
 For more information about an error, try `rustc --explain E0310`.
diff --git a/src/test/ui/impl-trait/negative-reasoning.rs b/src/test/ui/impl-trait/negative-reasoning.rs
index d173fe83fb7..70e24a3a9d0 100644
--- a/src/test/ui/impl-trait/negative-reasoning.rs
+++ b/src/test/ui/impl-trait/negative-reasoning.rs
@@ -17,7 +17,7 @@ impl<T: std::fmt::Debug> AnotherTrait for T {}
 
 // This is in error, because we cannot assume that `OpaqueType: !Debug`
 impl AnotherTrait for D<OpaqueType> {
-    //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<impl OpaqueTrait>`
+    //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
 }
 
 fn main() {}
diff --git a/src/test/ui/impl-trait/negative-reasoning.stderr b/src/test/ui/impl-trait/negative-reasoning.stderr
index e39a8e53f79..6b8cc9e7374 100644
--- a/src/test/ui/impl-trait/negative-reasoning.stderr
+++ b/src/test/ui/impl-trait/negative-reasoning.stderr
@@ -1,13 +1,13 @@
-error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<impl OpaqueTrait>`
+error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
   --> $DIR/negative-reasoning.rs:19:1
    |
 LL | impl<T: std::fmt::Debug> AnotherTrait for T {}
    | ------------------------------------------- first implementation here
 ...
 LL | impl AnotherTrait for D<OpaqueType> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<impl OpaqueTrait>`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>`
    |
-   = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `impl OpaqueTrait` in future versions
+   = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/impl-trait/nested-return-type2-tait.rs b/src/test/ui/impl-trait/nested-return-type2-tait.rs
new file mode 100644
index 00000000000..f2217f699fb
--- /dev/null
+++ b/src/test/ui/impl-trait/nested-return-type2-tait.rs
@@ -0,0 +1,32 @@
+#![feature(type_alias_impl_trait)]
+
+trait Duh {}
+
+impl Duh for i32 {}
+
+trait Trait {
+    type Assoc: Duh;
+}
+
+// the fact that `R` is the `::Output` projection on `F` causes
+// an intermediate inference var to be generated which is then later
+// compared against the actually found `Assoc` type.
+impl<R: Duh, F: FnMut() -> R> Trait for F {
+    type Assoc = R;
+}
+
+type Sendable = impl Send;
+
+// The `Sendable` here is then later compared against the inference var
+// created, causing the inference var to be set to `Sendable` instead of
+// the hidden type. We already have obligations registered on the inference
+// var to make it uphold the `: Duh` bound on `Trait::Assoc`. The opaque
+// type does not implement `Duh`, even if its hidden type does. So we error out.
+fn foo() -> impl Trait<Assoc = Sendable> {
+    //~^ ERROR `Sendable: Duh` is not satisfied
+    //~| ERROR `Sendable: Duh` is not satisfied
+    || 42
+}
+
+fn main() {
+}
diff --git a/src/test/ui/impl-trait/nested-return-type2-tait.stderr b/src/test/ui/impl-trait/nested-return-type2-tait.stderr
new file mode 100644
index 00000000000..776c06b20df
--- /dev/null
+++ b/src/test/ui/impl-trait/nested-return-type2-tait.stderr
@@ -0,0 +1,32 @@
+error[E0277]: the trait bound `Sendable: Duh` is not satisfied
+  --> $DIR/nested-return-type2-tait.rs:25:13
+   |
+LL | fn foo() -> impl Trait<Assoc = Sendable> {
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Duh` is not implemented for `Sendable`
+   |
+note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2-tait.rs:28:5: 28:10]`
+  --> $DIR/nested-return-type2-tait.rs:14:31
+   |
+LL | impl<R: Duh, F: FnMut() -> R> Trait for F {
+   |                               ^^^^^     ^
+
+error[E0277]: the trait bound `Sendable: Duh` is not satisfied
+  --> $DIR/nested-return-type2-tait.rs:25:42
+   |
+LL |   fn foo() -> impl Trait<Assoc = Sendable> {
+   |  __________________________________________^
+LL | |
+LL | |
+LL | |     || 42
+LL | | }
+   | |_^ the trait `Duh` is not implemented for `Sendable`
+   |
+note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2-tait.rs:28:5: 28:10]`
+  --> $DIR/nested-return-type2-tait.rs:14:31
+   |
+LL | impl<R: Duh, F: FnMut() -> R> Trait for F {
+   |                               ^^^^^     ^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/nested-return-type2-tait2.rs b/src/test/ui/impl-trait/nested-return-type2-tait2.rs
new file mode 100644
index 00000000000..af8e0663054
--- /dev/null
+++ b/src/test/ui/impl-trait/nested-return-type2-tait2.rs
@@ -0,0 +1,32 @@
+#![feature(type_alias_impl_trait)]
+
+trait Duh {}
+
+impl Duh for i32 {}
+
+trait Trait {
+    type Assoc: Duh;
+}
+
+// the fact that `R` is the `::Output` projection on `F` causes
+// an intermediate inference var to be generated which is then later
+// compared against the actually found `Assoc` type.
+impl<R: Duh, F: FnMut() -> R> Trait for F {
+    type Assoc = R;
+}
+
+type Sendable = impl Send;
+type Traitable = impl Trait<Assoc = Sendable>;
+
+// The `impl Send` here is then later compared against the inference var
+// created, causing the inference var to be set to `impl Send` instead of
+// the hidden type. We already have obligations registered on the inference
+// var to make it uphold the `: Duh` bound on `Trait::Assoc`. The opaque
+// type does not implement `Duh`, even if its hidden type does. So we error out.
+fn foo() -> Traitable {
+    || 42
+    //~^ ERROR `Sendable: Duh` is not satisfied
+}
+
+fn main() {
+}
diff --git a/src/test/ui/impl-trait/nested-return-type2-tait2.stderr b/src/test/ui/impl-trait/nested-return-type2-tait2.stderr
new file mode 100644
index 00000000000..4993202e253
--- /dev/null
+++ b/src/test/ui/impl-trait/nested-return-type2-tait2.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `Sendable: Duh` is not satisfied
+  --> $DIR/nested-return-type2-tait2.rs:27:5
+   |
+LL |     || 42
+   |     ^^^^^ the trait `Duh` is not implemented for `Sendable`
+   |
+note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2-tait2.rs:27:5: 27:10]`
+  --> $DIR/nested-return-type2-tait2.rs:14:31
+   |
+LL | impl<R: Duh, F: FnMut() -> R> Trait for F {
+   |                               ^^^^^     ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/nested-return-type2-tait3.rs b/src/test/ui/impl-trait/nested-return-type2-tait3.rs
new file mode 100644
index 00000000000..74fd8a9dda0
--- /dev/null
+++ b/src/test/ui/impl-trait/nested-return-type2-tait3.rs
@@ -0,0 +1,31 @@
+#![feature(type_alias_impl_trait)]
+
+trait Duh {}
+
+impl Duh for i32 {}
+
+trait Trait {
+    type Assoc: Duh;
+}
+
+// the fact that `R` is the `::Output` projection on `F` causes
+// an intermediate inference var to be generated which is then later
+// compared against the actually found `Assoc` type.
+impl<R: Duh, F: FnMut() -> R> Trait for F {
+    type Assoc = R;
+}
+
+type Traitable = impl Trait<Assoc = impl Send>;
+
+// The `impl Send` here is then later compared against the inference var
+// created, causing the inference var to be set to `impl Send` instead of
+// the hidden type. We already have obligations registered on the inference
+// var to make it uphold the `: Duh` bound on `Trait::Assoc`. The opaque
+// type does not implement `Duh`, even if its hidden type does. So we error out.
+fn foo() -> Traitable {
+    || 42
+    //~^ ERROR `impl Send: Duh` is not satisfied
+}
+
+fn main() {
+}
diff --git a/src/test/ui/impl-trait/nested-return-type2-tait3.stderr b/src/test/ui/impl-trait/nested-return-type2-tait3.stderr
new file mode 100644
index 00000000000..efeaf059a3b
--- /dev/null
+++ b/src/test/ui/impl-trait/nested-return-type2-tait3.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `impl Send: Duh` is not satisfied
+  --> $DIR/nested-return-type2-tait3.rs:26:5
+   |
+LL |     || 42
+   |     ^^^^^ the trait `Duh` is not implemented for `impl Send`
+   |
+note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2-tait3.rs:26:5: 26:10]`
+  --> $DIR/nested-return-type2-tait3.rs:14:31
+   |
+LL | impl<R: Duh, F: FnMut() -> R> Trait for F {
+   |                               ^^^^^     ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/nested-return-type2.rs b/src/test/ui/impl-trait/nested-return-type2.rs
new file mode 100644
index 00000000000..39928d543e1
--- /dev/null
+++ b/src/test/ui/impl-trait/nested-return-type2.rs
@@ -0,0 +1,30 @@
+// check-pass
+
+trait Duh {}
+
+impl Duh for i32 {}
+
+trait Trait {
+    type Assoc: Duh;
+}
+
+// the fact that `R` is the `::Output` projection on `F` causes
+// an intermediate inference var to be generated which is then later
+// compared against the actually found `Assoc` type.
+impl<R: Duh, F: FnMut() -> R> Trait for F {
+    type Assoc = R;
+}
+
+// The `impl Send` here is then later compared against the inference var
+// created, causing the inference var to be set to `impl Send` instead of
+// the hidden type. We already have obligations registered on the inference
+// var to make it uphold the `: Duh` bound on `Trait::Assoc`. The opaque
+// type does not implement `Duh`, even if its hidden type does.
+// Lazy TAIT would error out, but we inserted a hack to make it work again,
+// keeping backwards compatibility.
+fn foo() -> impl Trait<Assoc = impl Send> {
+    || 42
+}
+
+fn main() {
+}
diff --git a/src/test/ui/impl-trait/nested-return-type3-tait.rs b/src/test/ui/impl-trait/nested-return-type3-tait.rs
new file mode 100644
index 00000000000..3936f4dbbb4
--- /dev/null
+++ b/src/test/ui/impl-trait/nested-return-type3-tait.rs
@@ -0,0 +1,24 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+
+trait Duh {}
+
+impl Duh for i32 {}
+
+trait Trait {
+    type Assoc: Duh;
+}
+
+impl<F: Duh> Trait for F {
+    type Assoc = F;
+}
+
+type Sendable = impl Send;
+
+fn foo() -> impl Trait<Assoc = Sendable> {
+    42
+}
+
+fn main() {
+}
diff --git a/src/test/ui/impl-trait/nested-return-type3-tait2.rs b/src/test/ui/impl-trait/nested-return-type3-tait2.rs
new file mode 100644
index 00000000000..56778ed90dc
--- /dev/null
+++ b/src/test/ui/impl-trait/nested-return-type3-tait2.rs
@@ -0,0 +1,25 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+
+trait Duh {}
+
+impl Duh for i32 {}
+
+trait Trait {
+    type Assoc: Duh;
+}
+
+impl<F: Duh> Trait for F {
+    type Assoc = F;
+}
+
+type Sendable = impl Send;
+type Traitable = impl Trait<Assoc = Sendable>;
+
+fn foo() -> Traitable {
+    42
+}
+
+fn main() {
+}
diff --git a/src/test/ui/impl-trait/nested-return-type3-tait3.rs b/src/test/ui/impl-trait/nested-return-type3-tait3.rs
new file mode 100644
index 00000000000..04c6c92b1a3
--- /dev/null
+++ b/src/test/ui/impl-trait/nested-return-type3-tait3.rs
@@ -0,0 +1,24 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+
+trait Duh {}
+
+impl Duh for i32 {}
+
+trait Trait {
+    type Assoc: Duh;
+}
+
+impl<F: Duh> Trait for F {
+    type Assoc = F;
+}
+
+type Traitable = impl Trait<Assoc = impl Send>;
+
+fn foo() -> Traitable {
+    42
+}
+
+fn main() {
+}
diff --git a/src/test/ui/impl-trait/nested-return-type3.rs b/src/test/ui/impl-trait/nested-return-type3.rs
new file mode 100644
index 00000000000..74b4dae22eb
--- /dev/null
+++ b/src/test/ui/impl-trait/nested-return-type3.rs
@@ -0,0 +1,20 @@
+// check-pass
+
+trait Duh {}
+
+impl Duh for i32 {}
+
+trait Trait {
+    type Assoc: Duh;
+}
+
+impl<F: Duh> Trait for F {
+    type Assoc = F;
+}
+
+fn foo() -> impl Trait<Assoc = impl Send> {
+    42
+}
+
+fn main() {
+}
diff --git a/src/test/ui/impl-trait/nested_impl_trait.rs b/src/test/ui/impl-trait/nested_impl_trait.rs
index 06a2191a017..85c6f8c462c 100644
--- a/src/test/ui/impl-trait/nested_impl_trait.rs
+++ b/src/test/ui/impl-trait/nested_impl_trait.rs
@@ -4,6 +4,7 @@ fn fine(x: impl Into<u32>) -> impl Into<u32> { x }
 
 fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
 //~^ ERROR nested `impl Trait` is not allowed
+//~| ERROR the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
 
 fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
 //~^ ERROR nested `impl Trait` is not allowed
@@ -16,6 +17,7 @@ struct X;
 impl X {
     fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
     //~^ ERROR nested `impl Trait` is not allowed
+    //~| ERROR the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
 }
 
 fn allowed_in_assoc_type() -> impl Iterator<Item=impl Fn()> {
diff --git a/src/test/ui/impl-trait/nested_impl_trait.stderr b/src/test/ui/impl-trait/nested_impl_trait.stderr
index 4444e6a454f..26b48c7cdf7 100644
--- a/src/test/ui/impl-trait/nested_impl_trait.stderr
+++ b/src/test/ui/impl-trait/nested_impl_trait.stderr
@@ -8,7 +8,7 @@ LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
    |                                              outer `impl Trait`
 
 error[E0666]: nested `impl Trait` is not allowed
-  --> $DIR/nested_impl_trait.rs:8:42
+  --> $DIR/nested_impl_trait.rs:9:42
    |
 LL | fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
    |                                ----------^^^^^^^^^^-
@@ -17,7 +17,7 @@ LL | fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
    |                                outer `impl Trait`
 
 error[E0666]: nested `impl Trait` is not allowed
-  --> $DIR/nested_impl_trait.rs:12:37
+  --> $DIR/nested_impl_trait.rs:13:37
    |
 LL | fn bad_in_arg_position(_: impl Into<impl Debug>) { }
    |                           ----------^^^^^^^^^^-
@@ -26,7 +26,7 @@ LL | fn bad_in_arg_position(_: impl Into<impl Debug>) { }
    |                           outer `impl Trait`
 
 error[E0666]: nested `impl Trait` is not allowed
-  --> $DIR/nested_impl_trait.rs:17:44
+  --> $DIR/nested_impl_trait.rs:18:44
    |
 LL |     fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
    |                                  ----------^^^^^^^^^^-
@@ -35,18 +35,34 @@ LL |     fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
    |                                  outer `impl Trait`
 
 error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return
-  --> $DIR/nested_impl_trait.rs:8:32
+  --> $DIR/nested_impl_trait.rs:9:32
    |
 LL | fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
    |                                ^^^^^^^^^^^^^^^^^^^^^
 
 error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
-  --> $DIR/nested_impl_trait.rs:25:42
+  --> $DIR/nested_impl_trait.rs:27:42
    |
 LL | fn allowed_in_ret_type() -> impl Fn() -> impl Into<u32> {
    |                                          ^^^^^^^^^^^^^^
 
-error: aborting due to 6 previous errors
+error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
+  --> $DIR/nested_impl_trait.rs:5:46
+   |
+LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
+   |                                              ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug`
+   |
+   = note: required because of the requirements on the impl of `Into<impl Debug>` for `impl Into<u32>`
+
+error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
+  --> $DIR/nested_impl_trait.rs:18:34
+   |
+LL |     fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
+   |                                  ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug`
+   |
+   = note: required because of the requirements on the impl of `Into<impl Debug>` for `impl Into<u32>`
+
+error: aborting due to 8 previous errors
 
-Some errors have detailed explanations: E0562, E0666.
-For more information about an error, try `rustc --explain E0562`.
+Some errors have detailed explanations: E0277, E0562, E0666.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr
index 357166d1123..5ca01a59376 100644
--- a/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr
+++ b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr
@@ -2,46 +2,19 @@ error[E0308]: mismatched types
   --> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:36:5
    |
 LL | fn can() -> impl NotObjectSafe {
-   |             ------------------ expected because this return type...
-LL |     if true {
-LL |         return A;
-   |                - ...is found to be `A` here
-LL |     }
+   |             ------------------ expected `_` because of return type
+...
 LL |     B
    |     ^ expected struct `A`, found struct `B`
-   |
-   = note: to return `impl Trait`, all returned values must be of the same type
-   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = help: if the trait `NotObjectSafe` were object safe, you could return a boxed trait object
-   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
-   = help: you could instead create a new `enum` with a variant for each returned type
 
 error[E0308]: mismatched types
   --> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:43:5
    |
 LL | fn cat() -> impl ObjectSafe {
-   |             --------------- expected because this return type...
-LL |     if true {
-LL |         return A;
-   |                - ...is found to be `A` here
-LL |     }
+   |             --------------- expected `_` because of return type
+...
 LL |     B
    |     ^ expected struct `A`, found struct `B`
-   |
-   = note: to return `impl Trait`, all returned values must be of the same type
-   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
-   = help: you could instead create a new `enum` with a variant for each returned type
-help: you could change the return type to be a boxed trait object
-   |
-LL | fn cat() -> Box<dyn ObjectSafe> {
-   |             ~~~~~~~           +
-help: if you change the return type to expect trait objects, box the returned expressions
-   |
-LL ~         return Box::new(A);
-LL |     }
-LL ~     Box::new(B)
-   |
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr b/src/test/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr
index 970abad5c72..0c595f441ba 100644
--- a/src/test/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr
+++ b/src/test/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr
@@ -2,82 +2,28 @@ error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:5:5
    |
 LL | fn foo() -> impl std::fmt::Display {
-   |             ---------------------- expected because this return type...
-LL |     if false {
-LL |         return 0i32;
-   |                ---- ...is found to be `i32` here
-LL |     }
+   |             ---------------------- expected `_` because of return type
+...
 LL |     1u32
    |     ^^^^ expected `i32`, found `u32`
-   |
-   = note: to return `impl Trait`, all returned values must be of the same type
-   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
-   = help: you could instead create a new `enum` with a variant for each returned type
-help: you could change the return type to be a boxed trait object
-   |
-LL | fn foo() -> Box<dyn std::fmt::Display> {
-   |             ~~~~~~~                  +
-help: if you change the return type to expect trait objects, box the returned expressions
-   |
-LL ~         return Box::new(0i32);
-LL |     }
-LL ~     Box::new(1u32)
-   |
 
 error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:12:16
    |
 LL | fn bar() -> impl std::fmt::Display {
-   |             ---------------------- expected because this return type...
-LL |     if false {
-LL |         return 0i32;
-   |                ---- ...is found to be `i32` here
-LL |     } else {
+   |             ---------------------- expected `_` because of return type
+...
 LL |         return 1u32;
    |                ^^^^ expected `i32`, found `u32`
-   |
-   = note: to return `impl Trait`, all returned values must be of the same type
-   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
-   = help: you could instead create a new `enum` with a variant for each returned type
-help: you could change the return type to be a boxed trait object
-   |
-LL | fn bar() -> Box<dyn std::fmt::Display> {
-   |             ~~~~~~~                  +
-help: if you change the return type to expect trait objects, box the returned expressions
-   |
-LL ~         return Box::new(0i32);
-LL |     } else {
-LL ~         return Box::new(1u32);
-   |
 
 error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:20:9
    |
 LL | fn baz() -> impl std::fmt::Display {
-   |             ---------------------- expected because this return type...
-LL |     if false {
-LL |         return 0i32;
-   |                ---- ...is found to be `i32` here
-LL |     } else {
+   |             ---------------------- expected `_` because of return type
+...
 LL |         1u32
    |         ^^^^ expected `i32`, found `u32`
-   |
-   = note: to return `impl Trait`, all returned values must be of the same type
-   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
-   = help: you could instead create a new `enum` with a variant for each returned type
-help: you could change the return type to be a boxed trait object
-   |
-LL | fn baz() -> Box<dyn std::fmt::Display> {
-   |             ~~~~~~~                  +
-help: if you change the return type to expect trait objects, box the returned expressions
-   |
-LL ~         return Box::new(0i32);
-LL |     } else {
-LL ~         Box::new(1u32)
-   |
 
 error[E0308]: `if` and `else` have incompatible types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:28:9
@@ -90,100 +36,36 @@ LL | |         1u32
    | |         ^^^^ expected `i32`, found `u32`
 LL | |     }
    | |_____- `if` and `else` have incompatible types
-   |
-help: you could change the return type to be a boxed trait object
-   |
-LL | fn qux() -> Box<dyn std::fmt::Display> {
-   |             ~~~~~~~                  +
-help: if you change the return type to expect trait objects, box the returned expressions
-   |
-LL ~         Box::new(0i32)
-LL |     } else {
-LL ~         Box::new(1u32)
-   |
 
 error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:35:14
    |
 LL | fn bat() -> impl std::fmt::Display {
-   |             ---------------------- expected because this return type...
-LL |     match 13 {
-LL |         0 => return 0i32,
-   |                     ---- ...is found to be `i32` here
+   |             ---------------------- expected `_` because of return type
+...
 LL |         _ => 1u32,
    |              ^^^^ expected `i32`, found `u32`
-   |
-   = note: to return `impl Trait`, all returned values must be of the same type
-   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
-   = help: you could instead create a new `enum` with a variant for each returned type
-help: you could change the return type to be a boxed trait object
-   |
-LL | fn bat() -> Box<dyn std::fmt::Display> {
-   |             ~~~~~~~                  +
-help: if you change the return type to expect trait objects, box the returned expressions
-   |
-LL ~         0 => return Box::new(0i32),
-LL ~         _ => Box::new(1u32),
-   |
 
 error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:40:5
    |
 LL |   fn can() -> impl std::fmt::Display {
-   |               ---------------------- expected because this return type...
+   |               ---------------------- expected `_` because of return type
 LL | /     match 13 {
 LL | |         0 => return 0i32,
-   | |                     ---- ...is found to be `i32` here
 LL | |         1 => 1u32,
 LL | |         _ => 2u32,
 LL | |     }
    | |_____^ expected `i32`, found `u32`
-   |
-   = note: to return `impl Trait`, all returned values must be of the same type
-   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
-   = help: you could instead create a new `enum` with a variant for each returned type
-help: you could change the return type to be a boxed trait object
-   |
-LL | fn can() -> Box<dyn std::fmt::Display> {
-   |             ~~~~~~~                  +
-help: if you change the return type to expect trait objects, box the returned expressions
-   |
-LL ~     Box::new(match 13 {
-LL ~         0 => return Box::new(0i32),
-LL |         1 => 1u32,
-LL |         _ => 2u32,
-LL ~     })
-   |
 
 error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:53:13
    |
 LL | fn cat() -> impl std::fmt::Display {
-   |             ---------------------- expected because this return type...
-...
-LL |             return 0i32;
-   |                    ---- ...is found to be `i32` here
+   |             ---------------------- expected `_` because of return type
 ...
 LL |             1u32
    |             ^^^^ expected `i32`, found `u32`
-   |
-   = note: to return `impl Trait`, all returned values must be of the same type
-   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
-   = help: you could instead create a new `enum` with a variant for each returned type
-help: you could change the return type to be a boxed trait object
-   |
-LL | fn cat() -> Box<dyn std::fmt::Display> {
-   |             ~~~~~~~                  +
-help: if you change the return type to expect trait objects, box the returned expressions
-   |
-LL ~             return Box::new(0i32);
-LL |         }
-LL |         _ => {
-LL ~             Box::new(1u32)
-   |
 
 error[E0308]: `match` arms have incompatible types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:61:14
@@ -196,16 +78,6 @@ LL | |         1 => 1u32,
 LL | |         _ => 2u32,
 LL | |     }
    | |_____- `match` arms have incompatible types
-   |
-help: you could change the return type to be a boxed trait object
-   |
-LL | fn dog() -> Box<dyn std::fmt::Display> {
-   |             ~~~~~~~                  +
-help: if you change the return type to expect trait objects, box the returned expressions
-   |
-LL ~         0 => Box::new(0i32),
-LL ~         1 => Box::new(1u32),
-   |
 
 error[E0308]: `if` and `else` have incompatible types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:97:9
@@ -218,17 +90,6 @@ LL | |         1u32
    | |         ^^^^ expected `i32`, found `u32`
 LL | |     }
    | |_____- `if` and `else` have incompatible types
-   |
-help: you could change the return type to be a boxed trait object
-   |
-LL | fn apt() -> Box<dyn std::fmt::Display> {
-   |             ~~~~~~~                  +
-help: if you change the return type to expect trait objects, box the returned expressions
-   |
-LL ~         Box::new(0i32)
-LL |     } else {
-LL ~         Box::new(1u32)
-   |
 
 error[E0746]: return type cannot have an unboxed trait object
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:66:13
diff --git a/src/test/ui/impl-trait/projection-mismatch-in-impl-where-clause.stderr b/src/test/ui/impl-trait/projection-mismatch-in-impl-where-clause.stderr
index 65daabe419d..ade0dfa1bb3 100644
--- a/src/test/ui/impl-trait/projection-mismatch-in-impl-where-clause.stderr
+++ b/src/test/ui/impl-trait/projection-mismatch-in-impl-where-clause.stderr
@@ -4,7 +4,7 @@ error[E0271]: type mismatch resolving `<() as Super>::Assoc == ()`
 LL | fn test() -> impl Test {
    |              ^^^^^^^^^ type mismatch resolving `<() as Super>::Assoc == ()`
    |
-note: expected this to be `()`
+note: expected this to be `u8`
   --> $DIR/projection-mismatch-in-impl-where-clause.rs:6:18
    |
 LL |     type Assoc = u8;
diff --git a/src/test/ui/impl-trait/projection.rs b/src/test/ui/impl-trait/projection.rs
new file mode 100644
index 00000000000..b33802e2bc8
--- /dev/null
+++ b/src/test/ui/impl-trait/projection.rs
@@ -0,0 +1,29 @@
+// build-pass
+// needs to be build-pass, because it is a regression test for a mir validation failure
+// that only happens during codegen.
+
+struct D;
+
+trait Tr {
+    type It;
+    fn foo(self) -> Option<Self::It>;
+}
+
+impl<'a> Tr for &'a D {
+    type It = ();
+    fn foo(self) -> Option<()> { None }
+}
+
+fn run<F>(f: F)
+    where for<'a> &'a D: Tr,
+          F: Fn(<&D as Tr>::It),
+{
+    let d = &D;
+    while let Some(i) = d.foo() {
+        f(i);
+    }
+}
+
+fn main() {
+    run(|_| {});
+}
diff --git a/src/test/ui/impl-trait/question_mark.rs b/src/test/ui/impl-trait/question_mark.rs
new file mode 100644
index 00000000000..7bd5cff31bb
--- /dev/null
+++ b/src/test/ui/impl-trait/question_mark.rs
@@ -0,0 +1,30 @@
+// check-pass
+
+use std::fmt::Debug;
+
+#[derive(Debug)]
+pub struct Target;
+
+#[derive(Debug)]
+pub struct Source;
+impl From<Source> for Target {
+    fn from(_: Source) -> Self {
+        Self
+    }
+}
+
+fn maybe_source() -> Result<(), Source> {
+    todo!()
+}
+
+pub fn typaram() -> Result<(), impl Debug> {
+    maybe_source()?;
+    Ok::<_, Target>(())
+}
+
+pub fn direct() -> Result<(), impl Debug> {
+    maybe_source()?;
+    Err(Target)
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-direct.rs b/src/test/ui/impl-trait/recursive-impl-trait-type-direct.rs
index 3cc53744097..540a280f0a3 100644
--- a/src/test/ui/impl-trait/recursive-impl-trait-type-direct.rs
+++ b/src/test/ui/impl-trait/recursive-impl-trait-type-direct.rs
@@ -1,9 +1,8 @@
-// Test that an `impl Trait` type that expands to itself is an error.
+// check-pass
 
 #![allow(unconditional_recursion)]
 
 fn test() -> impl Sized {
-    //~^ ERROR E0720
     test()
 }
 
diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-direct.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type-direct.stderr
deleted file mode 100644
index 5a3027ec751..00000000000
--- a/src/test/ui/impl-trait/recursive-impl-trait-type-direct.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0720]: cannot resolve opaque type
-  --> $DIR/recursive-impl-trait-type-direct.rs:5:14
-   |
-LL | fn test() -> impl Sized {
-   |              ^^^^^^^^^^ recursive opaque type
-LL |
-LL |     test()
-   |     ------ returning here with type `impl Sized`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0720`.
diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs
index e3c621f0c57..ffc0cd9d10c 100644
--- a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs
+++ b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs
@@ -5,7 +5,7 @@
 #![allow(unconditional_recursion)]
 
 fn option(i: i32) -> impl Sized {
-    //~^ ERROR
+    //~^ ERROR cannot resolve opaque type
     if i < 0 { None } else { Some((option(i - 1), i)) }
 }
 
diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs
new file mode 100644
index 00000000000..6b200d7e3a8
--- /dev/null
+++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs
@@ -0,0 +1,17 @@
+#![feature(type_alias_impl_trait)]
+
+type Foo = impl PartialEq<(Foo, i32)>;
+
+struct Bar;
+
+impl PartialEq<(Foo, i32)> for Bar {
+    fn eq(&self, _other: &(Foo, i32)) -> bool {
+        true
+    }
+}
+
+fn foo() -> Foo {
+    Bar //~ ERROR can't compare `Bar` with `(Bar, i32)`
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr
new file mode 100644
index 00000000000..5476bf9d277
--- /dev/null
+++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr
@@ -0,0 +1,11 @@
+error[E0277]: can't compare `Bar` with `(Bar, i32)`
+  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs:14:5
+   |
+LL |     Bar
+   |     ^^^ no implementation for `Bar == (Bar, i32)`
+   |
+   = help: the trait `PartialEq<(Bar, i32)>` is not implemented for `Bar`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs
new file mode 100644
index 00000000000..6aa832cde71
--- /dev/null
+++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs
@@ -0,0 +1,30 @@
+#![feature(type_alias_impl_trait)]
+
+mod a {
+    type Foo = impl PartialEq<(Foo, i32)>;
+    //~^ ERROR unconstrained opaque type
+
+    struct Bar;
+
+    impl PartialEq<(Bar, i32)> for Bar {
+        fn eq(&self, _other: &(Foo, i32)) -> bool {
+            true
+        }
+    }
+}
+
+mod b {
+    type Foo = impl PartialEq<(Foo, i32)>;
+    //~^ ERROR unconstrained opaque type
+
+    struct Bar;
+
+    impl PartialEq<(Foo, i32)> for Bar {
+        fn eq(&self, _other: &(Bar, i32)) -> bool {
+            //~^ ERROR impl has stricter requirements than trait
+            true
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr
new file mode 100644
index 00000000000..19d5cdb9d0a
--- /dev/null
+++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr
@@ -0,0 +1,25 @@
+error: unconstrained opaque type
+  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:4:16
+   |
+LL |     type Foo = impl PartialEq<(Foo, i32)>;
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Foo` must be used in combination with a concrete type within the same module
+
+error: unconstrained opaque type
+  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:17:16
+   |
+LL |     type Foo = impl PartialEq<(Foo, i32)>;
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Foo` must be used in combination with a concrete type within the same module
+
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:23:9
+   |
+LL |         fn eq(&self, _other: &(Bar, i32)) -> bool {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `b::Bar: PartialEq<(b::Bar, i32)>`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0276`.
diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration.rs b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration.rs
new file mode 100644
index 00000000000..ad0a003e879
--- /dev/null
+++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration.rs
@@ -0,0 +1,19 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+
+type Foo = impl PartialEq<(Foo, i32)>;
+
+struct Bar;
+
+impl PartialEq<(Bar, i32)> for Bar {
+    fn eq(&self, _other: &(Bar, i32)) -> bool {
+        true
+    }
+}
+
+fn foo() -> Foo {
+    Bar
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/region-escape-via-bound.rs b/src/test/ui/impl-trait/region-escape-via-bound.rs
index e834f96dbbe..a04cb1702b6 100644
--- a/src/test/ui/impl-trait/region-escape-via-bound.rs
+++ b/src/test/ui/impl-trait/region-escape-via-bound.rs
@@ -12,10 +12,10 @@ trait Trait<'a> { }
 impl<'a, 'b> Trait<'b> for Cell<&'a u32> { }
 
 fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y>
-    //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds [E0700]
 where 'x: 'y
 {
     x
+    //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds [E0700]
 }
 
 fn main() { }
diff --git a/src/test/ui/impl-trait/region-escape-via-bound.stderr b/src/test/ui/impl-trait/region-escape-via-bound.stderr
index ecec34e0115..bc02f7694d7 100644
--- a/src/test/ui/impl-trait/region-escape-via-bound.stderr
+++ b/src/test/ui/impl-trait/region-escape-via-bound.stderr
@@ -1,10 +1,11 @@
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/region-escape-via-bound.rs:14:37
+  --> $DIR/region-escape-via-bound.rs:17:5
    |
 LL | fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y>
-   |        --                           ^^^^^^^^^^^^^^
-   |        |
-   |        hidden type `Cell<&'x u32>` captures the lifetime `'x` as defined here
+   |        -- hidden type `Cell<&'x u32>` captures the lifetime `'x` as defined here
+...
+LL |     x
+   |     ^
    |
 help: to declare that the `impl Trait` captures `'x`, you can add an explicit `'x` lifetime bound
    |
diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.rs b/src/test/ui/impl-trait/static-return-lifetime-infered.rs
index d792c6eafb3..f940c1949d0 100644
--- a/src/test/ui/impl-trait/static-return-lifetime-infered.rs
+++ b/src/test/ui/impl-trait/static-return-lifetime-infered.rs
@@ -4,14 +4,14 @@ struct A {
 
 impl A {
     fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
+        self.x.iter().map(|a| a.0)
         //~^ ERROR: captures lifetime that does not appear in bounds
         //~| ERROR: captures lifetime that does not appear in bounds
-        self.x.iter().map(|a| a.0)
     }
     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
+        self.x.iter().map(|a| a.0)
         //~^ ERROR: captures lifetime that does not appear in bounds
         //~| ERROR: captures lifetime that does not appear in bounds
-        self.x.iter().map(|a| a.0)
     }
 }
 
diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr
index 7424da76182..bc8e39f9c50 100644
--- a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr
+++ b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr
@@ -1,10 +1,10 @@
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/static-return-lifetime-infered.rs:6:35
+  --> $DIR/static-return-lifetime-infered.rs:7:9
    |
 LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
-   |                         -----     ^^^^^^^^^^^^^^^^^^^^^^^
-   |                         |
-   |                         hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:9:27: 9:34]>` captures the anonymous lifetime defined here
+   |                         ----- hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:7:27: 7:34]>` captures the anonymous lifetime defined here
+LL |         self.x.iter().map(|a| a.0)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
    |
@@ -12,12 +12,12 @@ LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
    |                                                           ++++
 
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/static-return-lifetime-infered.rs:6:35
+  --> $DIR/static-return-lifetime-infered.rs:7:9
    |
 LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
-   |                         -----     ^^^^^^^^^^^^^^^^^^^^^^^
-   |                         |
-   |                         hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:9:27: 9:34]>` captures the anonymous lifetime defined here
+   |                         ----- hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:7:27: 7:34]>` captures the anonymous lifetime defined here
+LL |         self.x.iter().map(|a| a.0)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
    |
@@ -25,12 +25,12 @@ LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
    |                                                           ++++
 
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/static-return-lifetime-infered.rs:11:37
+  --> $DIR/static-return-lifetime-infered.rs:12:9
    |
 LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
-   |                    --               ^^^^^^^^^^^^^^^^^^^^^^^
-   |                    |
-   |                    hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:14:27: 14:34]>` captures the lifetime `'a` as defined here
+   |                    -- hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:12:27: 12:34]>` captures the lifetime `'a` as defined here
+LL |         self.x.iter().map(|a| a.0)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: to declare that the `impl Trait` captures `'a`, you can add an explicit `'a` lifetime bound
    |
@@ -38,12 +38,12 @@ LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
    |                                                             ++++
 
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/static-return-lifetime-infered.rs:11:37
+  --> $DIR/static-return-lifetime-infered.rs:12:9
    |
 LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
-   |                    --               ^^^^^^^^^^^^^^^^^^^^^^^
-   |                    |
-   |                    hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:14:27: 14:34]>` captures the lifetime `'a` as defined here
+   |                    -- hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:12:27: 12:34]>` captures the lifetime `'a` as defined here
+LL |         self.x.iter().map(|a| a.0)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: to declare that the `impl Trait` captures `'a`, you can add an explicit `'a` lifetime bound
    |
diff --git a/src/test/ui/impl-trait/trait_resolution.rs b/src/test/ui/impl-trait/trait_resolution.rs
new file mode 100644
index 00000000000..8dcbbfd6e64
--- /dev/null
+++ b/src/test/ui/impl-trait/trait_resolution.rs
@@ -0,0 +1,30 @@
+// check-pass
+
+use std::fmt::Debug;
+
+pub struct EventStream<S> {
+    stream: S,
+}
+
+impl<S: Debug> EventStream<S> {
+    fn into_stream(self) -> impl Debug {
+        unimplemented!()
+    }
+
+    pub fn into_reader(self) -> impl Debug {
+        ReaderStream::from(self.into_stream())
+    }
+}
+
+#[derive(Debug)]
+pub struct ReaderStream<S> {
+    stream: S,
+}
+
+impl<S> From<S> for ReaderStream<S> {
+    fn from(stream: S) -> Self {
+        ReaderStream { stream }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/two_tait_defining_each_other.rs b/src/test/ui/impl-trait/two_tait_defining_each_other.rs
new file mode 100644
index 00000000000..6eb2a11b22c
--- /dev/null
+++ b/src/test/ui/impl-trait/two_tait_defining_each_other.rs
@@ -0,0 +1,19 @@
+#![feature(type_alias_impl_trait)]
+
+type A = impl Foo;
+type B = impl Foo;
+
+trait Foo {}
+
+fn muh(x: A) -> B {
+    if false {
+        return Bar; // B's hidden type is Bar
+    }
+    x // A's hidden type is `Bar`, because all the hidden types of `B` are compared with each other
+    //~^ ERROR opaque type's hidden type cannot be another opaque type
+}
+
+struct Bar;
+impl Foo for Bar {}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/two_tait_defining_each_other.stderr b/src/test/ui/impl-trait/two_tait_defining_each_other.stderr
new file mode 100644
index 00000000000..1a42ac525a6
--- /dev/null
+++ b/src/test/ui/impl-trait/two_tait_defining_each_other.stderr
@@ -0,0 +1,19 @@
+error: opaque type's hidden type cannot be another opaque type from the same scope
+  --> $DIR/two_tait_defining_each_other.rs:12:5
+   |
+LL |     x // A's hidden type is `Bar`, because all the hidden types of `B` are compared with each other
+   |     ^ one of the two opaque types used here has to be outside its defining scope
+   |
+note: opaque type whose hidden type is being assigned
+  --> $DIR/two_tait_defining_each_other.rs:4:10
+   |
+LL | type B = impl Foo;
+   |          ^^^^^^^^
+note: opaque type being used as hidden type
+  --> $DIR/two_tait_defining_each_other.rs:3:10
+   |
+LL | type A = impl Foo;
+   |          ^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/impl-trait/two_tait_defining_each_other2.rs b/src/test/ui/impl-trait/two_tait_defining_each_other2.rs
new file mode 100644
index 00000000000..05b09668016
--- /dev/null
+++ b/src/test/ui/impl-trait/two_tait_defining_each_other2.rs
@@ -0,0 +1,16 @@
+#![feature(type_alias_impl_trait)]
+
+type A = impl Foo; //~ ERROR unconstrained opaque type
+type B = impl Foo;
+
+trait Foo {}
+
+fn muh(x: A) -> B {
+    x // B's hidden type is A (opaquely)
+    //~^ ERROR opaque type's hidden type cannot be another opaque type
+}
+
+struct Bar;
+impl Foo for Bar {}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/two_tait_defining_each_other2.stderr b/src/test/ui/impl-trait/two_tait_defining_each_other2.stderr
new file mode 100644
index 00000000000..4d8f96de162
--- /dev/null
+++ b/src/test/ui/impl-trait/two_tait_defining_each_other2.stderr
@@ -0,0 +1,27 @@
+error: unconstrained opaque type
+  --> $DIR/two_tait_defining_each_other2.rs:3:10
+   |
+LL | type A = impl Foo;
+   |          ^^^^^^^^
+   |
+   = note: `A` must be used in combination with a concrete type within the same module
+
+error: opaque type's hidden type cannot be another opaque type from the same scope
+  --> $DIR/two_tait_defining_each_other2.rs:9:5
+   |
+LL |     x // B's hidden type is A (opaquely)
+   |     ^ one of the two opaque types used here has to be outside its defining scope
+   |
+note: opaque type whose hidden type is being assigned
+  --> $DIR/two_tait_defining_each_other2.rs:4:10
+   |
+LL | type B = impl Foo;
+   |          ^^^^^^^^
+note: opaque type being used as hidden type
+  --> $DIR/two_tait_defining_each_other2.rs:3:10
+   |
+LL | type A = impl Foo;
+   |          ^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/impl-trait/two_tait_defining_each_other3.rs b/src/test/ui/impl-trait/two_tait_defining_each_other3.rs
new file mode 100644
index 00000000000..37f8ae1b84b
--- /dev/null
+++ b/src/test/ui/impl-trait/two_tait_defining_each_other3.rs
@@ -0,0 +1,19 @@
+#![feature(type_alias_impl_trait)]
+
+type A = impl Foo;
+type B = impl Foo;
+
+trait Foo {}
+
+fn muh(x: A) -> B {
+    if false {
+        return x;  // B's hidden type is A (opaquely)
+        //~^ ERROR opaque type's hidden type cannot be another opaque type
+    }
+    Bar // A's hidden type is `Bar`, because all the return types are compared with each other
+}
+
+struct Bar;
+impl Foo for Bar {}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/two_tait_defining_each_other3.stderr b/src/test/ui/impl-trait/two_tait_defining_each_other3.stderr
new file mode 100644
index 00000000000..b06dc16d5e7
--- /dev/null
+++ b/src/test/ui/impl-trait/two_tait_defining_each_other3.stderr
@@ -0,0 +1,19 @@
+error: opaque type's hidden type cannot be another opaque type from the same scope
+  --> $DIR/two_tait_defining_each_other3.rs:10:16
+   |
+LL |         return x;  // B's hidden type is A (opaquely)
+   |                ^ one of the two opaque types used here has to be outside its defining scope
+   |
+note: opaque type whose hidden type is being assigned
+  --> $DIR/two_tait_defining_each_other3.rs:4:10
+   |
+LL | type B = impl Foo;
+   |          ^^^^^^^^
+note: opaque type being used as hidden type
+  --> $DIR/two_tait_defining_each_other3.rs:3:10
+   |
+LL | type A = impl Foo;
+   |          ^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/impl-trait/type_parameters_captured.nll.stderr b/src/test/ui/impl-trait/type_parameters_captured.nll.stderr
index 039cb62f866..b1175a5952e 100644
--- a/src/test/ui/impl-trait/type_parameters_captured.nll.stderr
+++ b/src/test/ui/impl-trait/type_parameters_captured.nll.stderr
@@ -1,8 +1,8 @@
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/type_parameters_captured.rs:7:20
+  --> $DIR/type_parameters_captured.rs:10:5
    |
-LL | fn foo<T>(x: T) -> impl Any + 'static {
-   |                    ^^^^^^^^^^^^^^^^^^
+LL |     x
+   |     ^
    |
    = help: consider adding an explicit lifetime bound `T: 'static`...
 
diff --git a/src/test/ui/impl-trait/type_parameters_captured.rs b/src/test/ui/impl-trait/type_parameters_captured.rs
index 6c9c9d4a42a..bb9cab742a5 100644
--- a/src/test/ui/impl-trait/type_parameters_captured.rs
+++ b/src/test/ui/impl-trait/type_parameters_captured.rs
@@ -6,6 +6,7 @@ impl<T> Any for T {}
 // Check that type parameters are captured and not considered 'static
 fn foo<T>(x: T) -> impl Any + 'static {
     //~^ ERROR the parameter type `T` may not live long enough
+    //~| ERROR the parameter type `T` may not live long enough
     x
 }
 
diff --git a/src/test/ui/impl-trait/type_parameters_captured.stderr b/src/test/ui/impl-trait/type_parameters_captured.stderr
index 40e50b9922f..c4ca34a6ed3 100644
--- a/src/test/ui/impl-trait/type_parameters_captured.stderr
+++ b/src/test/ui/impl-trait/type_parameters_captured.stderr
@@ -6,6 +6,19 @@ LL | fn foo<T>(x: T) -> impl Any + 'static {
    |        |
    |        help: consider adding an explicit lifetime bound...: `T: 'static`
 
-error: aborting due to previous error
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/type_parameters_captured.rs:7:39
+   |
+LL |   fn foo<T>(x: T) -> impl Any + 'static {
+   |  ________-______________________________^
+   | |        |
+   | |        help: consider adding an explicit lifetime bound...: `T: 'static`
+LL | |
+LL | |
+LL | |     x
+LL | | }
+   | |_^ ...so that the type `T` will meet its required lifetime bounds
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0310`.
diff --git a/src/test/ui/impl-trait/where-allowed-2.rs b/src/test/ui/impl-trait/where-allowed-2.rs
index 462508f306e..d5a87b5d468 100644
--- a/src/test/ui/impl-trait/where-allowed-2.rs
+++ b/src/test/ui/impl-trait/where-allowed-2.rs
@@ -1,8 +1,7 @@
-//! Ideally, these tests would go in `where-allowed.rs`, but we bail out
-//! too early to display them.
 use std::fmt::Debug;
 
-// Disallowed
-fn in_adt_in_return() -> Vec<impl Debug> { panic!() } //~ ERROR cannot resolve opaque type
+// check-pass
+
+fn in_adt_in_return() -> Vec<impl Debug> { panic!() }
 
 fn main() {}
diff --git a/src/test/ui/impl-trait/where-allowed-2.stderr b/src/test/ui/impl-trait/where-allowed-2.stderr
deleted file mode 100644
index b8e06725cbc..00000000000
--- a/src/test/ui/impl-trait/where-allowed-2.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0720]: cannot resolve opaque type
-  --> $DIR/where-allowed-2.rs:6:30
-   |
-LL | fn in_adt_in_return() -> Vec<impl Debug> { panic!() }
-   |                              ^^^^^^^^^^    -------- this returned value is of `!` type
-   |                              |
-   |                              cannot resolve opaque type
-   |
-   = help: this error will resolve once the item's body returns a concrete type
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0720`.
diff --git a/src/test/ui/issues-71798.rs b/src/test/ui/issues-71798.rs
index fecba721ac9..fde59f39b1c 100644
--- a/src/test/ui/issues-71798.rs
+++ b/src/test/ui/issues-71798.rs
@@ -1,5 +1,7 @@
 fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
-    *x //~^ ERROR `u32` is not a future
+    //~^ ERROR `u32` is not a future
+    //~| ERROR `u32` is not a future
+    *x
 }
 
 fn main() {
diff --git a/src/test/ui/issues-71798.stderr b/src/test/ui/issues-71798.stderr
index bc4dc9ebf9e..63669c0513d 100644
--- a/src/test/ui/issues-71798.stderr
+++ b/src/test/ui/issues-71798.stderr
@@ -1,5 +1,5 @@
 error[E0425]: cannot find value `u` in this scope
-  --> $DIR/issues-71798.rs:6:24
+  --> $DIR/issues-71798.rs:8:24
    |
 LL |     let _ = test_ref & u;
    |                        ^ not found in this scope
@@ -13,7 +13,21 @@ LL | fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
    = help: the trait `Future` is not implemented for `u32`
    = note: u32 must be a future or must implement `IntoFuture` to be awaited
 
-error: aborting due to 2 previous errors
+error[E0277]: `u32` is not a future
+  --> $DIR/issues-71798.rs:1:69
+   |
+LL |   fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
+   |  _____________________________________________________________________^
+LL | |
+LL | |
+LL | |     *x
+LL | | }
+   | |_^ `u32` is not a future
+   |
+   = help: the trait `Future` is not implemented for `u32`
+   = note: u32 must be a future or must implement `IntoFuture` to be awaited
+
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0277, E0425.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/lazy-type-alias-impl-trait/branches.rs b/src/test/ui/lazy-type-alias-impl-trait/branches.rs
new file mode 100644
index 00000000000..aa172f3f19b
--- /dev/null
+++ b/src/test/ui/lazy-type-alias-impl-trait/branches.rs
@@ -0,0 +1,14 @@
+#![feature(type_alias_impl_trait)]
+
+type Foo = impl std::fmt::Debug;
+
+fn foo(b: bool) -> Foo {
+    if b {
+        vec![42_i32]
+    } else {
+        std::iter::empty().collect()
+        //~^ ERROR `Foo` cannot be built from an iterator over elements of type `_`
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/lazy-type-alias-impl-trait/branches.stderr b/src/test/ui/lazy-type-alias-impl-trait/branches.stderr
new file mode 100644
index 00000000000..c3902f34706
--- /dev/null
+++ b/src/test/ui/lazy-type-alias-impl-trait/branches.stderr
@@ -0,0 +1,16 @@
+error[E0277]: a value of type `Foo` cannot be built from an iterator over elements of type `_`
+  --> $DIR/branches.rs:9:28
+   |
+LL |         std::iter::empty().collect()
+   |                            ^^^^^^^ value of type `Foo` cannot be built from `std::iter::Iterator<Item=_>`
+   |
+   = help: the trait `FromIterator<_>` is not implemented for `Foo`
+note: required by a bound in `collect`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+   |
+LL |     fn collect<B: FromIterator<Self::Item>>(self) -> B
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/lazy-type-alias-impl-trait/branches2.rs b/src/test/ui/lazy-type-alias-impl-trait/branches2.rs
new file mode 100644
index 00000000000..af605e4d806
--- /dev/null
+++ b/src/test/ui/lazy-type-alias-impl-trait/branches2.rs
@@ -0,0 +1,28 @@
+#![feature(type_alias_impl_trait)]
+
+// run-pass
+
+type Foo = impl std::iter::FromIterator<i32> + PartialEq<Vec<i32>> + std::fmt::Debug;
+
+fn foo(b: bool) -> Foo {
+    if b {
+        vec![42_i32]
+    } else {
+        std::iter::empty().collect()
+    }
+}
+
+fn bar(b: bool) -> impl PartialEq<Vec<i32>> + std::fmt::Debug {
+    if b {
+        vec![42_i32]
+    } else {
+        std::iter::empty().collect()
+    }
+}
+
+fn main() {
+    assert_eq!(foo(true), vec![42]);
+    assert_eq!(foo(false), vec![]);
+    assert_eq!(bar(true), vec![42]);
+    assert_eq!(bar(false), vec![]);
+}
diff --git a/src/test/ui/lazy-type-alias-impl-trait/freeze_cycle.rs b/src/test/ui/lazy-type-alias-impl-trait/freeze_cycle.rs
new file mode 100644
index 00000000000..10f6bd74031
--- /dev/null
+++ b/src/test/ui/lazy-type-alias-impl-trait/freeze_cycle.rs
@@ -0,0 +1,46 @@
+// check-pass
+
+#![feature(gen_future, generator_trait, negative_impls)]
+
+use std::ops::{Generator, GeneratorState};
+use std::task::{Poll, Context};
+use std::future::{Future};
+use std::ptr::NonNull;
+use std::pin::Pin;
+
+fn main() {}
+
+#[derive(Debug, Copy, Clone)]
+pub struct ResumeTy(NonNull<Context<'static>>);
+
+unsafe impl Send for ResumeTy {}
+
+unsafe impl Sync for ResumeTy {}
+
+pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
+where
+    T: Generator<ResumeTy, Yield = ()>,
+{
+    struct GenFuture<T: Generator<ResumeTy, Yield = ()>>(T);
+
+    // We rely on the fact that async/await futures are immovable in order to create
+    // self-referential borrows in the underlying generator.
+    impl<T: Generator<ResumeTy, Yield = ()>> !Unpin for GenFuture<T> {}
+
+    impl<T: Generator<ResumeTy, Yield = ()>> Future for GenFuture<T> {
+        type Output = T::Return;
+        fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+            // SAFETY: Safe because we're !Unpin + !Drop, and this is just a field projection.
+            let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) };
+
+            // Resume the generator, turning the `&mut Context` into a `NonNull` raw pointer. The
+            // `.await` lowering will safely cast that back to a `&mut Context`.
+            match gen.resume(ResumeTy(NonNull::from(cx).cast::<Context<'static>>())) {
+                GeneratorState::Yielded(()) => Poll::Pending,
+                GeneratorState::Complete(x) => Poll::Ready(x),
+            }
+        }
+    }
+
+    GenFuture(gen)
+}
diff --git a/src/test/ui/lazy-type-alias-impl-trait/infer_cross_function.rs b/src/test/ui/lazy-type-alias-impl-trait/infer_cross_function.rs
new file mode 100644
index 00000000000..d07d732c785
--- /dev/null
+++ b/src/test/ui/lazy-type-alias-impl-trait/infer_cross_function.rs
@@ -0,0 +1,27 @@
+// check-pass
+
+fn main() {}
+
+trait Reader {}
+
+struct Unit<R>(R);
+struct ResDwarf<R>(R);
+
+struct Context<R: Reader> {
+    dwarf: ResDwarf<R>,
+}
+
+struct Range;
+
+struct ResUnit<R>(R);
+
+impl<R: Reader + 'static> Context<R> {
+    fn find_dwarf_unit(&self, probe: u64) -> Option<&Unit<R>> {
+        let x = self.find_units(probe);
+        None
+    }
+
+    fn find_units(&self, probe: u64) -> impl Iterator<Item = &ResUnit<R>> {
+        std::iter::empty()
+    }
+}
diff --git a/src/test/ui/lazy-type-alias-impl-trait/lifetime_inference.rs b/src/test/ui/lazy-type-alias-impl-trait/lifetime_inference.rs
new file mode 100644
index 00000000000..f75a88aa8f0
--- /dev/null
+++ b/src/test/ui/lazy-type-alias-impl-trait/lifetime_inference.rs
@@ -0,0 +1,7 @@
+// check-pass
+
+fn main() {}
+
+fn nth<I: Iterator>(iter: &mut I, step: usize) -> impl FnMut() -> Option<I::Item> + '_ {
+    move || iter.nth(step)
+}
diff --git a/src/test/ui/lazy-type-alias-impl-trait/nested.rs b/src/test/ui/lazy-type-alias-impl-trait/nested.rs
new file mode 100644
index 00000000000..f8291112739
--- /dev/null
+++ b/src/test/ui/lazy-type-alias-impl-trait/nested.rs
@@ -0,0 +1,23 @@
+// check-pass
+
+fn main() {}
+
+struct RawTableInner<A> {
+    alloc: A,
+}
+
+impl<A> RawTableInner<A> {
+    fn prepare_resize(
+        self,
+    ) -> ScopeGuard<Self, impl FnMut(&mut Self)> {
+        ScopeGuard { dropfn: move |self_| {}, value: self,  }
+    }
+}
+
+pub struct ScopeGuard<T, F>
+where
+    F: FnMut(&mut T),
+{
+    dropfn: F,
+    value: T,
+}
diff --git a/src/test/ui/lazy-type-alias-impl-trait/opaque_vs_opaque.rs b/src/test/ui/lazy-type-alias-impl-trait/opaque_vs_opaque.rs
new file mode 100644
index 00000000000..8d03b5158d6
--- /dev/null
+++ b/src/test/ui/lazy-type-alias-impl-trait/opaque_vs_opaque.rs
@@ -0,0 +1,10 @@
+// check-pass
+
+fn main() {}
+
+fn filter_fold<T, Acc, PRED: FnMut(&T) -> bool, FOLD: FnMut(Acc, T) -> Acc>(
+    mut predicate: PRED,
+    mut fold: FOLD,
+) -> impl FnMut(Acc, T) -> Acc {
+    move |acc, item| if predicate(&item) { fold(acc, item) } else { acc }
+}
diff --git a/src/test/ui/lazy-type-alias-impl-trait/recursion.rs b/src/test/ui/lazy-type-alias-impl-trait/recursion.rs
new file mode 100644
index 00000000000..cf7cd5d26ca
--- /dev/null
+++ b/src/test/ui/lazy-type-alias-impl-trait/recursion.rs
@@ -0,0 +1,23 @@
+#![feature(type_alias_impl_trait)]
+
+// check-pass
+
+type Foo = impl std::fmt::Debug;
+
+fn foo(b: bool) -> Foo {
+    if b {
+        return 42
+    }
+    let x: u32 = foo(false);
+    99
+}
+
+fn bar(b: bool) -> impl std::fmt::Debug {
+    if b {
+        return 42
+    }
+    let x: u32 = bar(false);
+    99
+}
+
+fn main() {}
diff --git a/src/test/ui/lazy-type-alias-impl-trait/recursion2.rs b/src/test/ui/lazy-type-alias-impl-trait/recursion2.rs
new file mode 100644
index 00000000000..1cc64ea17e7
--- /dev/null
+++ b/src/test/ui/lazy-type-alias-impl-trait/recursion2.rs
@@ -0,0 +1,21 @@
+#![feature(type_alias_impl_trait)]
+
+type Foo = impl std::fmt::Debug;
+
+fn foo(b: bool) -> Foo {
+    if b {
+        return vec![];
+    }
+    let x: Vec<i32> = foo(false);
+    std::iter::empty().collect() //~ ERROR `Foo` cannot be built from an iterator
+}
+
+fn bar(b: bool) -> impl std::fmt::Debug {
+    if b {
+        return vec![]
+    }
+    let x: Vec<i32> = bar(false);
+    std::iter::empty().collect()
+}
+
+fn main() {}
diff --git a/src/test/ui/lazy-type-alias-impl-trait/recursion2.stderr b/src/test/ui/lazy-type-alias-impl-trait/recursion2.stderr
new file mode 100644
index 00000000000..1f6201a8300
--- /dev/null
+++ b/src/test/ui/lazy-type-alias-impl-trait/recursion2.stderr
@@ -0,0 +1,16 @@
+error[E0277]: a value of type `Foo` cannot be built from an iterator over elements of type `_`
+  --> $DIR/recursion2.rs:10:24
+   |
+LL |     std::iter::empty().collect()
+   |                        ^^^^^^^ value of type `Foo` cannot be built from `std::iter::Iterator<Item=_>`
+   |
+   = help: the trait `FromIterator<_>` is not implemented for `Foo`
+note: required by a bound in `collect`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+   |
+LL |     fn collect<B: FromIterator<Self::Item>>(self) -> B
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/lazy-type-alias-impl-trait/recursion3.rs b/src/test/ui/lazy-type-alias-impl-trait/recursion3.rs
new file mode 100644
index 00000000000..7f1cedae068
--- /dev/null
+++ b/src/test/ui/lazy-type-alias-impl-trait/recursion3.rs
@@ -0,0 +1,21 @@
+#![feature(type_alias_impl_trait)]
+
+type Foo = impl std::fmt::Debug;
+
+fn foo(b: bool) -> Foo {
+    if b {
+        return 42
+    }
+    let x: u32 = foo(false) + 42; //~ ERROR cannot add
+    99
+}
+
+fn bar(b: bool) -> impl std::fmt::Debug {
+    if b {
+        return 42
+    }
+    let x: u32 = bar(false) + 42; //~ ERROR cannot add
+    99
+}
+
+fn main() {}
diff --git a/src/test/ui/lazy-type-alias-impl-trait/recursion3.stderr b/src/test/ui/lazy-type-alias-impl-trait/recursion3.stderr
new file mode 100644
index 00000000000..e1d5cafedc8
--- /dev/null
+++ b/src/test/ui/lazy-type-alias-impl-trait/recursion3.stderr
@@ -0,0 +1,19 @@
+error[E0369]: cannot add `{integer}` to `Foo`
+  --> $DIR/recursion3.rs:9:29
+   |
+LL |     let x: u32 = foo(false) + 42;
+   |                  ---------- ^ -- {integer}
+   |                  |
+   |                  Foo
+
+error[E0369]: cannot add `{integer}` to `impl Debug`
+  --> $DIR/recursion3.rs:17:29
+   |
+LL |     let x: u32 = bar(false) + 42;
+   |                  ---------- ^ -- {integer}
+   |                  |
+   |                  impl Debug
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0369`.
diff --git a/src/test/ui/lazy-type-alias-impl-trait/recursion4.rs b/src/test/ui/lazy-type-alias-impl-trait/recursion4.rs
new file mode 100644
index 00000000000..57dd7fb067c
--- /dev/null
+++ b/src/test/ui/lazy-type-alias-impl-trait/recursion4.rs
@@ -0,0 +1,23 @@
+#![feature(type_alias_impl_trait)]
+
+type Foo = impl std::fmt::Debug;
+
+fn foo(b: bool) -> Foo {
+    if b {
+        return vec![];
+    }
+    let mut x = foo(false);
+    x = std::iter::empty().collect(); //~ ERROR `Foo` cannot be built from an iterator
+    vec![]
+}
+
+fn bar(b: bool) -> impl std::fmt::Debug {
+    if b {
+        return vec![];
+    }
+    let mut x = bar(false);
+    x = std::iter::empty().collect(); //~ ERROR `impl Debug` cannot be built from an iterator
+    vec![]
+}
+
+fn main() {}
diff --git a/src/test/ui/lazy-type-alias-impl-trait/recursion4.stderr b/src/test/ui/lazy-type-alias-impl-trait/recursion4.stderr
new file mode 100644
index 00000000000..42a1f782d29
--- /dev/null
+++ b/src/test/ui/lazy-type-alias-impl-trait/recursion4.stderr
@@ -0,0 +1,29 @@
+error[E0277]: a value of type `Foo` cannot be built from an iterator over elements of type `_`
+  --> $DIR/recursion4.rs:10:28
+   |
+LL |     x = std::iter::empty().collect();
+   |                            ^^^^^^^ value of type `Foo` cannot be built from `std::iter::Iterator<Item=_>`
+   |
+   = help: the trait `FromIterator<_>` is not implemented for `Foo`
+note: required by a bound in `collect`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+   |
+LL |     fn collect<B: FromIterator<Self::Item>>(self) -> B
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect`
+
+error[E0277]: a value of type `impl Debug` cannot be built from an iterator over elements of type `_`
+  --> $DIR/recursion4.rs:19:28
+   |
+LL |     x = std::iter::empty().collect();
+   |                            ^^^^^^^ value of type `impl Debug` cannot be built from `std::iter::Iterator<Item=_>`
+   |
+   = help: the trait `FromIterator<_>` is not implemented for `impl Debug`
+note: required by a bound in `collect`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+   |
+LL |     fn collect<B: FromIterator<Self::Item>>(self) -> B
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/lazy-type-alias-impl-trait/unsized_sized_opaque.rs b/src/test/ui/lazy-type-alias-impl-trait/unsized_sized_opaque.rs
new file mode 100644
index 00000000000..00710149823
--- /dev/null
+++ b/src/test/ui/lazy-type-alias-impl-trait/unsized_sized_opaque.rs
@@ -0,0 +1,16 @@
+// check-pass
+
+fn main() {}
+
+pub struct PairSlices<'a, 'b, T> {
+    pub(crate) a0: &'a mut [T],
+    pub(crate) a1: &'a mut [T],
+    pub(crate) b0: &'b [T],
+    pub(crate) b1: &'b [T],
+}
+
+impl<'a, 'b, T> PairSlices<'a, 'b, T> {
+    pub fn remainder(self) -> impl Iterator<Item = &'b [T]> {
+        IntoIterator::into_iter([self.b0, self.b1])
+    }
+}
diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.rs b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.rs
index ea0d0ccbc55..133679f30f8 100644
--- a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.rs
+++ b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.rs
@@ -6,7 +6,8 @@ trait Future {
 use std::error::Error;
 
 fn foo() -> impl Future<Item=(), Error=Box<dyn Error>> {
-//~^ ERROR not satisfied
+    //~^ ERROR not satisfied
+    //~| ERROR not satisfied
     Ok(())
 }
 
diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr
index ef1127c59ac..a3badd7b25a 100644
--- a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr
+++ b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr
@@ -4,6 +4,17 @@ error[E0277]: the trait bound `Result<(), _>: Future` is not satisfied
 LL | fn foo() -> impl Future<Item=(), Error=Box<dyn Error>> {
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Future` is not implemented for `Result<(), _>`
 
-error: aborting due to previous error
+error[E0277]: the trait bound `Result<(), _>: Future` is not satisfied
+  --> $DIR/lifetime-elision-return-type-trait.rs:8:56
+   |
+LL |   fn foo() -> impl Future<Item=(), Error=Box<dyn Error>> {
+   |  ________________________________________________________^
+LL | |
+LL | |
+LL | |     Ok(())
+LL | | }
+   | |_^ the trait `Future` is not implemented for `Result<(), _>`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/lint/inline-trait-and-foreign-items.rs b/src/test/ui/lint/inline-trait-and-foreign-items.rs
index 6321b3c76e4..13dab7ed954 100644
--- a/src/test/ui/lint/inline-trait-and-foreign-items.rs
+++ b/src/test/ui/lint/inline-trait-and-foreign-items.rs
@@ -23,7 +23,7 @@ impl Trait for () {
     type T = Self;
 
     #[inline] //~ ERROR attribute should be applied to function or closure
-    type U = impl Trait; //~ ERROR could not find defining uses
+    type U = impl Trait; //~ ERROR unconstrained opaque type
 }
 
 extern "C" {
diff --git a/src/test/ui/lint/inline-trait-and-foreign-items.stderr b/src/test/ui/lint/inline-trait-and-foreign-items.stderr
index 6ac884c12ce..fc7e89e4f4c 100644
--- a/src/test/ui/lint/inline-trait-and-foreign-items.stderr
+++ b/src/test/ui/lint/inline-trait-and-foreign-items.stderr
@@ -61,11 +61,13 @@ LL |     #[inline]
 LL |     type T;
    |     ------- not a function or closure
 
-error: could not find defining uses
+error: unconstrained opaque type
   --> $DIR/inline-trait-and-foreign-items.rs:26:14
    |
 LL |     type U = impl Trait;
    |              ^^^^^^^^^^
+   |
+   = note: `U` must be used in combination with a concrete type within the same module
 
 error: aborting due to 6 previous errors; 2 warnings emitted
 
diff --git a/src/test/ui/lint/lint-ctypes-73249-2.rs b/src/test/ui/lint/lint-ctypes-73249-2.rs
index fe578f51b63..691047c8a40 100644
--- a/src/test/ui/lint/lint-ctypes-73249-2.rs
+++ b/src/test/ui/lint/lint-ctypes-73249-2.rs
@@ -23,7 +23,7 @@ pub struct A<T: Foo> {
 }
 
 extern "C" {
-    pub fn lint_me() -> A<()>; //~ ERROR: uses type `impl Baz`
+    pub fn lint_me() -> A<()>; //~ ERROR: uses type `Qux`
 }
 
 fn main() {}
diff --git a/src/test/ui/lint/lint-ctypes-73249-2.stderr b/src/test/ui/lint/lint-ctypes-73249-2.stderr
index 36dbe3217d7..7c85e9fa85c 100644
--- a/src/test/ui/lint/lint-ctypes-73249-2.stderr
+++ b/src/test/ui/lint/lint-ctypes-73249-2.stderr
@@ -1,4 +1,4 @@
-error: `extern` block uses type `impl Baz`, which is not FFI-safe
+error: `extern` block uses type `Qux`, which is not FFI-safe
   --> $DIR/lint-ctypes-73249-2.rs:26:25
    |
 LL |     pub fn lint_me() -> A<()>;
diff --git a/src/test/ui/lint/lint-ctypes-73249-3.rs b/src/test/ui/lint/lint-ctypes-73249-3.rs
index ec12de00739..ef8ab7e03d2 100644
--- a/src/test/ui/lint/lint-ctypes-73249-3.rs
+++ b/src/test/ui/lint/lint-ctypes-73249-3.rs
@@ -17,7 +17,7 @@ pub struct A {
 }
 
 extern "C" {
-    pub fn lint_me() -> A; //~ ERROR: uses type `impl Baz`
+    pub fn lint_me() -> A; //~ ERROR: uses type `Qux`
 }
 
 fn main() {}
diff --git a/src/test/ui/lint/lint-ctypes-73249-3.stderr b/src/test/ui/lint/lint-ctypes-73249-3.stderr
index e987ec90228..83e2a233c43 100644
--- a/src/test/ui/lint/lint-ctypes-73249-3.stderr
+++ b/src/test/ui/lint/lint-ctypes-73249-3.stderr
@@ -1,4 +1,4 @@
-error: `extern` block uses type `impl Baz`, which is not FFI-safe
+error: `extern` block uses type `Qux`, which is not FFI-safe
   --> $DIR/lint-ctypes-73249-3.rs:20:25
    |
 LL |     pub fn lint_me() -> A;
diff --git a/src/test/ui/lint/lint-ctypes-73249-5.rs b/src/test/ui/lint/lint-ctypes-73249-5.rs
index 58c2d7a501a..083fb6c5fb1 100644
--- a/src/test/ui/lint/lint-ctypes-73249-5.rs
+++ b/src/test/ui/lint/lint-ctypes-73249-5.rs
@@ -17,7 +17,7 @@ pub struct A {
 }
 
 extern "C" {
-    pub fn lint_me() -> A; //~ ERROR: uses type `impl Baz`
+    pub fn lint_me() -> A; //~ ERROR: uses type `Qux`
 }
 
 fn main() {}
diff --git a/src/test/ui/lint/lint-ctypes-73249-5.stderr b/src/test/ui/lint/lint-ctypes-73249-5.stderr
index 749714c7df8..37781d78cf2 100644
--- a/src/test/ui/lint/lint-ctypes-73249-5.stderr
+++ b/src/test/ui/lint/lint-ctypes-73249-5.stderr
@@ -1,4 +1,4 @@
-error: `extern` block uses type `impl Baz`, which is not FFI-safe
+error: `extern` block uses type `Qux`, which is not FFI-safe
   --> $DIR/lint-ctypes-73249-5.rs:20:25
    |
 LL |     pub fn lint_me() -> A;
diff --git a/src/test/ui/lint/lint-ctypes-73251-1.rs b/src/test/ui/lint/lint-ctypes-73251-1.rs
index dc4c7efd7ef..145ba784f7c 100644
--- a/src/test/ui/lint/lint-ctypes-73251-1.rs
+++ b/src/test/ui/lint/lint-ctypes-73251-1.rs
@@ -20,7 +20,7 @@ fn assign() -> Qux {
 }
 
 extern "C" {
-    pub fn lint_me() -> <u32 as Foo>::Assoc; //~ ERROR: uses type `impl Baz`
+    pub fn lint_me() -> <u32 as Foo>::Assoc; //~ ERROR: uses type `Qux`
 }
 
 fn main() {}
diff --git a/src/test/ui/lint/lint-ctypes-73251-1.stderr b/src/test/ui/lint/lint-ctypes-73251-1.stderr
index 505ccd5a930..76b19d37e21 100644
--- a/src/test/ui/lint/lint-ctypes-73251-1.stderr
+++ b/src/test/ui/lint/lint-ctypes-73251-1.stderr
@@ -1,4 +1,4 @@
-error: `extern` block uses type `impl Baz`, which is not FFI-safe
+error: `extern` block uses type `Qux`, which is not FFI-safe
   --> $DIR/lint-ctypes-73251-1.rs:23:25
    |
 LL |     pub fn lint_me() -> <u32 as Foo>::Assoc;
diff --git a/src/test/ui/lint/lint-ctypes-73251-2.rs b/src/test/ui/lint/lint-ctypes-73251-2.rs
index 717ca4986f7..df71a945796 100644
--- a/src/test/ui/lint/lint-ctypes-73251-2.rs
+++ b/src/test/ui/lint/lint-ctypes-73251-2.rs
@@ -33,7 +33,7 @@ fn use_of_b() -> AliasB {
 }
 
 extern "C" {
-    pub fn lint_me() -> <AliasB as TraitB>::Assoc; //~ ERROR: uses type `impl TraitA<Assoc = u32>`
+    pub fn lint_me() -> <AliasB as TraitB>::Assoc; //~ ERROR: uses type `AliasA`
 }
 
 fn main() {}
diff --git a/src/test/ui/lint/lint-ctypes-73251-2.stderr b/src/test/ui/lint/lint-ctypes-73251-2.stderr
index d7e10db441e..64f0fb2d892 100644
--- a/src/test/ui/lint/lint-ctypes-73251-2.stderr
+++ b/src/test/ui/lint/lint-ctypes-73251-2.stderr
@@ -1,4 +1,4 @@
-error: `extern` block uses type `impl TraitA<Assoc = u32>`, which is not FFI-safe
+error: `extern` block uses type `AliasA`, which is not FFI-safe
   --> $DIR/lint-ctypes-73251-2.rs:36:25
    |
 LL |     pub fn lint_me() -> <AliasB as TraitB>::Assoc;
diff --git a/src/test/ui/lint/opaque-ty-ffi-unsafe.rs b/src/test/ui/lint/opaque-ty-ffi-unsafe.rs
index 3a62b6a21a5..b7cc38e99fc 100644
--- a/src/test/ui/lint/opaque-ty-ffi-unsafe.rs
+++ b/src/test/ui/lint/opaque-ty-ffi-unsafe.rs
@@ -9,7 +9,7 @@ pub fn ret_closure() -> A {
 
 extern "C" {
     pub fn a(_: A);
-    //~^ ERROR `extern` block uses type `impl Fn()`, which is not FFI-safe [improper_ctypes]
+    //~^ ERROR `extern` block uses type `A`, which is not FFI-safe [improper_ctypes]
 }
 
 fn main() {}
diff --git a/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr b/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr
index 5afbef778b3..62d00fd6835 100644
--- a/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr
+++ b/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr
@@ -1,4 +1,4 @@
-error: `extern` block uses type `impl Fn()`, which is not FFI-safe
+error: `extern` block uses type `A`, which is not FFI-safe
   --> $DIR/opaque-ty-ffi-unsafe.rs:11:17
    |
 LL |     pub fn a(_: A);
diff --git a/src/test/ui/never_type/feature-gate-never_type_fallback.rs b/src/test/ui/never_type/feature-gate-never_type_fallback.rs
index 3b896ec9d70..7d020841180 100644
--- a/src/test/ui/never_type/feature-gate-never_type_fallback.rs
+++ b/src/test/ui/never_type/feature-gate-never_type_fallback.rs
@@ -6,7 +6,8 @@ fn main() {}
 
 trait T {}
 
-fn should_ret_unit() -> impl T {
-    //~^ ERROR the trait bound `(): T` is not satisfied
-    panic!()
+fn should_ret_unit() {
+    foo(panic!()) //~ ERROR
 }
+
+fn foo(_: impl T) {}
diff --git a/src/test/ui/never_type/feature-gate-never_type_fallback.stderr b/src/test/ui/never_type/feature-gate-never_type_fallback.stderr
index 670f76867ce..54abed38300 100644
--- a/src/test/ui/never_type/feature-gate-never_type_fallback.stderr
+++ b/src/test/ui/never_type/feature-gate-never_type_fallback.stderr
@@ -1,8 +1,14 @@
 error[E0277]: the trait bound `(): T` is not satisfied
-  --> $DIR/feature-gate-never_type_fallback.rs:9:25
+  --> $DIR/feature-gate-never_type_fallback.rs:10:5
    |
-LL | fn should_ret_unit() -> impl T {
-   |                         ^^^^^^ the trait `T` is not implemented for `()`
+LL |     foo(panic!())
+   |     ^^^ the trait `T` is not implemented for `()`
+   |
+note: required by a bound in `foo`
+  --> $DIR/feature-gate-never_type_fallback.rs:13:16
+   |
+LL | fn foo(_: impl T) {}
+   |                ^ required by this bound in `foo`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/never_type/impl_trait_fallback.rs b/src/test/ui/never_type/impl_trait_fallback.rs
new file mode 100644
index 00000000000..cc9520c1b24
--- /dev/null
+++ b/src/test/ui/never_type/impl_trait_fallback.rs
@@ -0,0 +1,10 @@
+// check-pass
+
+fn main() {}
+
+trait T {}
+impl T for () {}
+
+fn should_ret_unit() -> impl T {
+    panic!()
+}
diff --git a/src/test/ui/never_type/impl_trait_fallback2.rs b/src/test/ui/never_type/impl_trait_fallback2.rs
new file mode 100644
index 00000000000..f73d953bdbd
--- /dev/null
+++ b/src/test/ui/never_type/impl_trait_fallback2.rs
@@ -0,0 +1,21 @@
+#![feature(type_alias_impl_trait)]
+
+fn main() {}
+
+trait T {}
+impl T for i32 {}
+
+fn should_ret_unit() -> impl T {
+    //~^ ERROR `(): T` is not satisfied
+    panic!()
+}
+
+type Foo = impl T;
+
+fn a() -> Foo {
+    panic!()
+}
+
+fn b() -> Foo {
+    42
+}
diff --git a/src/test/ui/never_type/impl_trait_fallback2.stderr b/src/test/ui/never_type/impl_trait_fallback2.stderr
new file mode 100644
index 00000000000..2f50b9d2459
--- /dev/null
+++ b/src/test/ui/never_type/impl_trait_fallback2.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `(): T` is not satisfied
+  --> $DIR/impl_trait_fallback2.rs:8:25
+   |
+LL | fn should_ret_unit() -> impl T {
+   |                         ^^^^^^ the trait `T` is not implemented for `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/never_type/impl_trait_fallback3.rs b/src/test/ui/never_type/impl_trait_fallback3.rs
new file mode 100644
index 00000000000..26ce9b93105
--- /dev/null
+++ b/src/test/ui/never_type/impl_trait_fallback3.rs
@@ -0,0 +1,15 @@
+#![feature(type_alias_impl_trait)]
+
+fn main() {}
+
+trait T {
+    type Assoc;
+}
+
+type Foo = impl T;
+//~^ ERROR unconstrained opaque type
+
+fn a() -> Foo {
+    // This is not a defining use, it doesn't actually constrain the opaque type.
+    panic!()
+}
diff --git a/src/test/ui/never_type/impl_trait_fallback3.stderr b/src/test/ui/never_type/impl_trait_fallback3.stderr
new file mode 100644
index 00000000000..121019d5f69
--- /dev/null
+++ b/src/test/ui/never_type/impl_trait_fallback3.stderr
@@ -0,0 +1,10 @@
+error: unconstrained opaque type
+  --> $DIR/impl_trait_fallback3.rs:9:12
+   |
+LL | type Foo = impl T;
+   |            ^^^^^^
+   |
+   = note: `Foo` must be used in combination with a concrete type within the same module
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/never_type/impl_trait_fallback4.rs b/src/test/ui/never_type/impl_trait_fallback4.rs
new file mode 100644
index 00000000000..fe62773fa02
--- /dev/null
+++ b/src/test/ui/never_type/impl_trait_fallback4.rs
@@ -0,0 +1,24 @@
+#![feature(type_alias_impl_trait)]
+
+trait T {
+    type Assoc: Cake;
+}
+
+trait Cake: std::fmt::Display {
+    fn cake() -> Self;
+}
+
+type Foo = impl T;
+
+fn foo() -> impl T {
+    //~^ ERROR `(): T` is not satisfied
+    panic!()
+}
+
+fn a() -> Foo {
+    foo()
+}
+
+fn main() {
+    println!("{}", <Foo as T>::Assoc::cake());
+}
diff --git a/src/test/ui/never_type/impl_trait_fallback4.stderr b/src/test/ui/never_type/impl_trait_fallback4.stderr
new file mode 100644
index 00000000000..f2e216e9044
--- /dev/null
+++ b/src/test/ui/never_type/impl_trait_fallback4.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `(): T` is not satisfied
+  --> $DIR/impl_trait_fallback4.rs:13:13
+   |
+LL | fn foo() -> impl T {
+   |             ^^^^^^ the trait `T` is not implemented for `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/nll/issue-52113.rs b/src/test/ui/nll/issue-52113.rs
index 0d7ee037692..2f4cbf8322b 100644
--- a/src/test/ui/nll/issue-52113.rs
+++ b/src/test/ui/nll/issue-52113.rs
@@ -29,9 +29,9 @@ fn produce3<'a, 'b: 'a>(data: &'a mut Vec<&'a u32>, value: &'b u32) -> impl Bazi
 fn produce_err<'a, 'b: 'a>(data: &'b mut Vec<&'b u32>, value: &'a u32) -> impl Bazinga + 'b {
     let x = move || {
         let value: &'a u32 = value;
-        data.push(value);
+        data.push(value); //~ ERROR lifetime may not live long enough
     };
-    x //~ ERROR lifetime may not live long enough
+    x
 }
 
 fn main() {}
diff --git a/src/test/ui/nll/issue-52113.stderr b/src/test/ui/nll/issue-52113.stderr
index f70ae2edd7f..42ff1866893 100644
--- a/src/test/ui/nll/issue-52113.stderr
+++ b/src/test/ui/nll/issue-52113.stderr
@@ -1,13 +1,13 @@
 error: lifetime may not live long enough
-  --> $DIR/issue-52113.rs:34:5
+  --> $DIR/issue-52113.rs:32:9
    |
 LL | fn produce_err<'a, 'b: 'a>(data: &'b mut Vec<&'b u32>, value: &'a u32) -> impl Bazinga + 'b {
    |                --  -- lifetime `'b` defined here
    |                |
    |                lifetime `'a` defined here
 ...
-LL |     x
-   |     ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+LL |         data.push(value);
+   |         ^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
 
diff --git a/src/test/ui/nll/issue-73159-rpit-static.rs b/src/test/ui/nll/issue-73159-rpit-static.rs
index e29ba09b369..97dc016068b 100644
--- a/src/test/ui/nll/issue-73159-rpit-static.rs
+++ b/src/test/ui/nll/issue-73159-rpit-static.rs
@@ -7,8 +7,8 @@ struct Foo<'a>(&'a [u8]);
 
 impl<'a> Foo<'a> {
     fn make_it(&self) -> impl Iterator<Item = u8> {
-        //~^ ERROR: captures lifetime that does not appear in bounds
         self.0.iter().copied()
+        //~^ ERROR: captures lifetime that does not appear in bounds
     }
 }
 
diff --git a/src/test/ui/nll/issue-73159-rpit-static.stderr b/src/test/ui/nll/issue-73159-rpit-static.stderr
index 6c7cd0c8254..a3e9c0b44c2 100644
--- a/src/test/ui/nll/issue-73159-rpit-static.stderr
+++ b/src/test/ui/nll/issue-73159-rpit-static.stderr
@@ -1,10 +1,11 @@
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/issue-73159-rpit-static.rs:9:26
+  --> $DIR/issue-73159-rpit-static.rs:10:9
    |
 LL | impl<'a> Foo<'a> {
    |      -- hidden type `Copied<std::slice::Iter<'a, u8>>` captures the lifetime `'a` as defined here
 LL |     fn make_it(&self) -> impl Iterator<Item = u8> {
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         self.0.iter().copied()
+   |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/relate_tys/opaque-hrtb.rs b/src/test/ui/nll/relate_tys/opaque-hrtb.rs
new file mode 100644
index 00000000000..0fbe6a63c0b
--- /dev/null
+++ b/src/test/ui/nll/relate_tys/opaque-hrtb.rs
@@ -0,0 +1,16 @@
+#![feature(nll)]
+
+trait MyTrait<T> {}
+
+struct Foo;
+impl<T> MyTrait<T> for Foo {}
+
+fn bar<Input>() -> impl MyTrait<Input> {
+    Foo
+}
+
+fn foo() -> impl for<'a> MyTrait<&'a str> {
+    bar() //~ ERROR implementation of `MyTrait` is not general enough
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/relate_tys/opaque-hrtb.stderr b/src/test/ui/nll/relate_tys/opaque-hrtb.stderr
new file mode 100644
index 00000000000..4c8b66f21ab
--- /dev/null
+++ b/src/test/ui/nll/relate_tys/opaque-hrtb.stderr
@@ -0,0 +1,11 @@
+error: implementation of `MyTrait` is not general enough
+  --> $DIR/opaque-hrtb.rs:13:5
+   |
+LL |     bar()
+   |     ^^^^^ implementation of `MyTrait` is not general enough
+   |
+   = note: `impl MyTrait<&'2 str>` must implement `MyTrait<&'1 str>`, for any lifetime `'1`...
+   = note: ...but it actually implements `MyTrait<&'2 str>`, for some specific lifetime `'2`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/ty-outlives/impl-trait-captures.rs b/src/test/ui/nll/ty-outlives/impl-trait-captures.rs
index 8af23aad726..c04185d0814 100644
--- a/src/test/ui/nll/ty-outlives/impl-trait-captures.rs
+++ b/src/test/ui/nll/ty-outlives/impl-trait-captures.rs
@@ -8,8 +8,8 @@ trait Foo<'a> {
 impl<'a, T> Foo<'a> for T { }
 
 fn foo<'a, T>(x: &T) -> impl Foo<'a> {
-//~^ ERROR captures lifetime that does not appear in bounds
     x
+    //~^ ERROR captures lifetime that does not appear in bounds
 }
 
 fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
index 3e6fe789a8b..42d9f057aaa 100644
--- a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
+++ b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
@@ -1,10 +1,10 @@
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/impl-trait-captures.rs:10:25
+  --> $DIR/impl-trait-captures.rs:11:5
    |
 LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
-   |                  --     ^^^^^^^^^^^^
-   |                  |
-   |                  hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0)) T` captures the anonymous lifetime defined here
+   |                  -- hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0)) T` captures the anonymous lifetime defined here
+LL |     x
+   |     ^
    |
 help: to declare that the `impl Trait` captures `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0))` lifetime bound
    |
diff --git a/src/test/ui/nll/ty-outlives/impl-trait-outlives.rs b/src/test/ui/nll/ty-outlives/impl-trait-outlives.rs
index 0c7d8acb052..3548ad03a7d 100644
--- a/src/test/ui/nll/ty-outlives/impl-trait-outlives.rs
+++ b/src/test/ui/nll/ty-outlives/impl-trait-outlives.rs
@@ -5,11 +5,11 @@
 use std::fmt::Debug;
 
 fn no_region<'a, T>(x: Box<T>) -> impl Debug + 'a
-    //~^ ERROR the parameter type `T` may not live long enough [E0309]
 where
     T: Debug,
 {
     x
+    //~^ ERROR the parameter type `T` may not live long enough [E0309]
 }
 
 fn correct_region<'a, T>(x: Box<T>) -> impl Debug + 'a
@@ -20,11 +20,11 @@ where
 }
 
 fn wrong_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
-    //~^ ERROR the parameter type `T` may not live long enough [E0309]
 where
     T: 'b + Debug,
 {
     x
+    //~^ ERROR the parameter type `T` may not live long enough [E0309]
 }
 
 fn outlives_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
diff --git a/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr b/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr
index 053aef951f2..31ee540cce9 100644
--- a/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr
+++ b/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr
@@ -1,16 +1,16 @@
 error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/impl-trait-outlives.rs:7:35
+  --> $DIR/impl-trait-outlives.rs:11:5
    |
-LL | fn no_region<'a, T>(x: Box<T>) -> impl Debug + 'a
-   |                                   ^^^^^^^^^^^^^^^
+LL |     x
+   |     ^
    |
    = help: consider adding an explicit lifetime bound `T: 'a`...
 
 error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/impl-trait-outlives.rs:22:42
+  --> $DIR/impl-trait-outlives.rs:26:5
    |
-LL | fn wrong_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
-   |                                          ^^^^^^^^^^^^^^^
+LL |     x
+   |     ^
    |
    = help: consider adding an explicit lifetime bound `T: 'a`...
 
diff --git a/src/test/ui/parser/fn-header-semantic-fail.rs b/src/test/ui/parser/fn-header-semantic-fail.rs
index 91a63bafd99..c2954868f78 100644
--- a/src/test/ui/parser/fn-header-semantic-fail.rs
+++ b/src/test/ui/parser/fn-header-semantic-fail.rs
@@ -9,8 +9,9 @@ fn main() {
     unsafe fn ff2() {} // OK.
     const fn ff3() {} // OK.
     extern "C" fn ff4() {} // OK.
-    const async unsafe extern "C" fn ff5() {} // OK.
+    const async unsafe extern "C" fn ff5() {}
     //~^ ERROR functions cannot be both `const` and `async`
+    //~| ERROR cycle detected
 
     trait X {
         async fn ft1(); //~ ERROR functions in traits cannot be declared `async`
@@ -26,15 +27,16 @@ fn main() {
     struct Y;
     impl X for Y {
         async fn ft1() {} //~ ERROR functions in traits cannot be declared `async`
-        //~^ ERROR method `ft1` has an incompatible type for trait
+        //~^ ERROR impl has stricter requirements than trait
         unsafe fn ft2() {} // OK.
         const fn ft3() {} //~ ERROR functions in traits cannot be declared const
         extern "C" fn ft4() {}
         const async unsafe extern "C" fn ft5() {}
         //~^ ERROR functions in traits cannot be declared `async`
         //~| ERROR functions in traits cannot be declared const
-        //~| ERROR method `ft5` has an incompatible type for trait
         //~| ERROR functions cannot be both `const` and `async`
+        //~| ERROR cycle detected
+        //~| ERROR impl has stricter requirements than trait
     }
 
     impl Y {
@@ -44,6 +46,7 @@ fn main() {
         extern "C" fn fi4() {} // OK.
         const async unsafe extern "C" fn fi5() {}
         //~^ ERROR functions cannot be both `const` and `async`
+        //~| ERROR cycle detected
     }
 
     extern "C" {
diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr
index 8eaba559a62..bd3b9181123 100644
--- a/src/test/ui/parser/fn-header-semantic-fail.stderr
+++ b/src/test/ui/parser/fn-header-semantic-fail.stderr
@@ -1,14 +1,14 @@
 error: functions cannot be both `const` and `async`
   --> $DIR/fn-header-semantic-fail.rs:12:5
    |
-LL |     const async unsafe extern "C" fn ff5() {} // OK.
+LL |     const async unsafe extern "C" fn ff5() {}
    |     ^^^^^-^^^^^------------------------------
    |     |     |
    |     |     `async` because of this
    |     `const` because of this
 
 error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:16:9
+  --> $DIR/fn-header-semantic-fail.rs:17:9
    |
 LL |         async fn ft1();
    |         -----^^^^^^^^^^
@@ -19,19 +19,19 @@ LL |         async fn ft1();
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
 
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/fn-header-semantic-fail.rs:18:9
+  --> $DIR/fn-header-semantic-fail.rs:19:9
    |
 LL |         const fn ft3();
    |         ^^^^^ functions in traits cannot be const
 
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/fn-header-semantic-fail.rs:20:9
+  --> $DIR/fn-header-semantic-fail.rs:21:9
    |
 LL |         const async unsafe extern "C" fn ft5();
    |         ^^^^^ functions in traits cannot be const
 
 error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:20:9
+  --> $DIR/fn-header-semantic-fail.rs:21:9
    |
 LL |         const async unsafe extern "C" fn ft5();
    |         ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -42,7 +42,7 @@ LL |         const async unsafe extern "C" fn ft5();
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
 
 error: functions cannot be both `const` and `async`
-  --> $DIR/fn-header-semantic-fail.rs:20:9
+  --> $DIR/fn-header-semantic-fail.rs:21:9
    |
 LL |         const async unsafe extern "C" fn ft5();
    |         ^^^^^-^^^^^----------------------------
@@ -51,7 +51,7 @@ LL |         const async unsafe extern "C" fn ft5();
    |         `const` because of this
 
 error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:28:9
+  --> $DIR/fn-header-semantic-fail.rs:29:9
    |
 LL |         async fn ft1() {}
    |         -----^^^^^^^^^^^^
@@ -62,19 +62,19 @@ LL |         async fn ft1() {}
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
 
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/fn-header-semantic-fail.rs:31:9
+  --> $DIR/fn-header-semantic-fail.rs:32:9
    |
 LL |         const fn ft3() {}
    |         ^^^^^ functions in traits cannot be const
 
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/fn-header-semantic-fail.rs:33:9
+  --> $DIR/fn-header-semantic-fail.rs:34:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^ functions in traits cannot be const
 
 error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:33:9
+  --> $DIR/fn-header-semantic-fail.rs:34:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -85,7 +85,7 @@ LL |         const async unsafe extern "C" fn ft5() {}
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
 
 error: functions cannot be both `const` and `async`
-  --> $DIR/fn-header-semantic-fail.rs:33:9
+  --> $DIR/fn-header-semantic-fail.rs:34:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^-^^^^^------------------------------
@@ -94,7 +94,7 @@ LL |         const async unsafe extern "C" fn ft5() {}
    |         `const` because of this
 
 error: functions cannot be both `const` and `async`
-  --> $DIR/fn-header-semantic-fail.rs:45:9
+  --> $DIR/fn-header-semantic-fail.rs:47:9
    |
 LL |         const async unsafe extern "C" fn fi5() {}
    |         ^^^^^-^^^^^------------------------------
@@ -103,7 +103,7 @@ LL |         const async unsafe extern "C" fn fi5() {}
    |         `const` because of this
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:50:18
+  --> $DIR/fn-header-semantic-fail.rs:53:18
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
@@ -116,7 +116,7 @@ LL |         fn fe1();
    |         ~~
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:51:19
+  --> $DIR/fn-header-semantic-fail.rs:54:19
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
@@ -130,7 +130,7 @@ LL |         fn fe2();
    |         ~~
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:52:18
+  --> $DIR/fn-header-semantic-fail.rs:55:18
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
@@ -144,7 +144,7 @@ LL |         fn fe3();
    |         ~~
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:53:23
+  --> $DIR/fn-header-semantic-fail.rs:56:23
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
@@ -158,7 +158,7 @@ LL |         fn fe4();
    |         ~~
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:54:42
+  --> $DIR/fn-header-semantic-fail.rs:57:42
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
@@ -172,7 +172,7 @@ LL |         fn fe5();
    |         ~~
 
 error: functions cannot be both `const` and `async`
-  --> $DIR/fn-header-semantic-fail.rs:54:9
+  --> $DIR/fn-header-semantic-fail.rs:57:9
    |
 LL |         const async unsafe extern "C" fn fe5();
    |         ^^^^^-^^^^^----------------------------
@@ -180,43 +180,133 @@ LL |         const async unsafe extern "C" fn fe5();
    |         |     `async` because of this
    |         `const` because of this
 
-error[E0053]: method `ft1` has an incompatible type for trait
-  --> $DIR/fn-header-semantic-fail.rs:28:24
+error[E0391]: cycle detected when computing type of `main::ff5::{opaque#0}`
+  --> $DIR/fn-header-semantic-fail.rs:12:44
    |
-LL |         async fn ft1() {}
-   |                        ^
-   |                        |
-   |                        checked the `Output` of this `async fn`, found opaque type
-   |                        expected `()`, found opaque type
+LL |     const async unsafe extern "C" fn ff5() {}
+   |                                            ^
+   |
+note: ...which requires borrow-checking `main::ff5`...
+  --> $DIR/fn-header-semantic-fail.rs:12:5
+   |
+LL |     const async unsafe extern "C" fn ff5() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires processing `main::ff5`...
+  --> $DIR/fn-header-semantic-fail.rs:12:5
+   |
+LL |     const async unsafe extern "C" fn ff5() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires const checking `main::ff5`...
+  --> $DIR/fn-header-semantic-fail.rs:12:5
    |
-   = note: while checking the return type of the `async fn`
-note: type in trait
-  --> $DIR/fn-header-semantic-fail.rs:16:23
+LL |     const async unsafe extern "C" fn ff5() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: ...which requires computing whether `impl core::future::future::Future<Output = ()>` is freeze...
+   = note: ...which requires evaluating trait selection obligation `impl core::future::future::Future<Output = ()>: core::marker::Freeze`...
+   = note: ...which again requires computing type of `main::ff5::{opaque#0}`, completing the cycle
+note: cycle used when checking item types in top-level module
+  --> $DIR/fn-header-semantic-fail.rs:5:1
+   |
+LL | / #![feature(const_extern_fn)]
+LL | |
+LL | | fn main() {
+LL | |     async fn ff1() {} // OK.
+...  |
+LL | |     }
+LL | | }
+   | |_^
+
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/fn-header-semantic-fail.rs:29:9
    |
 LL |         async fn ft1();
-   |                       ^
-   = note: expected fn pointer `fn()`
-              found fn pointer `fn() -> impl Future<Output = ()>`
+   |         --------------- definition of `ft1` from trait
+...
+LL |         async fn ft1() {}
+   |         ^^^^^^^^^^^^^^ impl has extra requirement `(): Future`
+
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/fn-header-semantic-fail.rs:34:9
+   |
+LL |         const async unsafe extern "C" fn ft5();
+   |         --------------------------------------- definition of `ft5` from trait
+...
+LL |         const async unsafe extern "C" fn ft5() {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `(): Future`
 
-error[E0053]: method `ft5` has an incompatible type for trait
-  --> $DIR/fn-header-semantic-fail.rs:33:48
+error[E0391]: cycle detected when computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 40:6>::ft5::{opaque#0}`
+  --> $DIR/fn-header-semantic-fail.rs:34:48
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |                                                ^
-   |                                                |
-   |                                                checked the `Output` of this `async fn`, found opaque type
-   |                                                expected `()`, found opaque type
    |
-   = note: while checking the return type of the `async fn`
-note: type in trait
-  --> $DIR/fn-header-semantic-fail.rs:20:47
+note: ...which requires borrow-checking `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 40:6>::ft5`...
+  --> $DIR/fn-header-semantic-fail.rs:34:9
    |
-LL |         const async unsafe extern "C" fn ft5();
-   |                                               ^
-   = note: expected fn pointer `unsafe extern "C" fn()`
-              found fn pointer `unsafe extern "C" fn() -> impl Future<Output = ()>`
+LL |         const async unsafe extern "C" fn ft5() {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires processing `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 40:6>::ft5`...
+  --> $DIR/fn-header-semantic-fail.rs:34:9
+   |
+LL |         const async unsafe extern "C" fn ft5() {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires const checking `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 40:6>::ft5`...
+  --> $DIR/fn-header-semantic-fail.rs:34:9
+   |
+LL |         const async unsafe extern "C" fn ft5() {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: ...which requires computing whether `impl core::future::future::Future<Output = ()>` is freeze...
+   = note: ...which requires evaluating trait selection obligation `impl core::future::future::Future<Output = ()>: core::marker::Freeze`...
+   = note: ...which again requires computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 40:6>::ft5::{opaque#0}`, completing the cycle
+note: cycle used when checking item types in top-level module
+  --> $DIR/fn-header-semantic-fail.rs:5:1
+   |
+LL | / #![feature(const_extern_fn)]
+LL | |
+LL | | fn main() {
+LL | |     async fn ff1() {} // OK.
+...  |
+LL | |     }
+LL | | }
+   | |_^
+
+error[E0391]: cycle detected when computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:42:5: 50:6>::fi5::{opaque#0}`
+  --> $DIR/fn-header-semantic-fail.rs:47:48
+   |
+LL |         const async unsafe extern "C" fn fi5() {}
+   |                                                ^
+   |
+note: ...which requires borrow-checking `main::<impl at $DIR/fn-header-semantic-fail.rs:42:5: 50:6>::fi5`...
+  --> $DIR/fn-header-semantic-fail.rs:47:9
+   |
+LL |         const async unsafe extern "C" fn fi5() {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires processing `main::<impl at $DIR/fn-header-semantic-fail.rs:42:5: 50:6>::fi5`...
+  --> $DIR/fn-header-semantic-fail.rs:47:9
+   |
+LL |         const async unsafe extern "C" fn fi5() {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires const checking `main::<impl at $DIR/fn-header-semantic-fail.rs:42:5: 50:6>::fi5`...
+  --> $DIR/fn-header-semantic-fail.rs:47:9
+   |
+LL |         const async unsafe extern "C" fn fi5() {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: ...which requires computing whether `impl core::future::future::Future<Output = ()>` is freeze...
+   = note: ...which requires evaluating trait selection obligation `impl core::future::future::Future<Output = ()>: core::marker::Freeze`...
+   = note: ...which again requires computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:42:5: 50:6>::fi5::{opaque#0}`, completing the cycle
+note: cycle used when checking item types in top-level module
+  --> $DIR/fn-header-semantic-fail.rs:5:1
+   |
+LL | / #![feature(const_extern_fn)]
+LL | |
+LL | | fn main() {
+LL | |     async fn ff1() {} // OK.
+...  |
+LL | |     }
+LL | | }
+   | |_^
 
-error: aborting due to 20 previous errors
+error: aborting due to 23 previous errors
 
-Some errors have detailed explanations: E0053, E0379, E0706.
-For more information about an error, try `rustc --explain E0053`.
+Some errors have detailed explanations: E0276, E0379, E0391, E0706.
+For more information about an error, try `rustc --explain E0276`.
diff --git a/src/test/ui/polymorphization/generators.rs b/src/test/ui/polymorphization/generators.rs
index f295cf15d08..68ea4a026d7 100644
--- a/src/test/ui/polymorphization/generators.rs
+++ b/src/test/ui/polymorphization/generators.rs
@@ -32,7 +32,6 @@ where
 
 #[rustc_polymorphize_error]
 pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
-    //~^ ERROR item has unused generic parameters
     || {
         //~^ ERROR item has unused generic parameters
         yield 1;
@@ -58,7 +57,6 @@ pub fn used_type_in_return<R: Default>() -> impl Generator<(), Yield = u32, Retu
 
 #[rustc_polymorphize_error]
 pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
-    //~^ ERROR item has unused generic parameters
     || {
         //~^ ERROR item has unused generic parameters
         yield 1;
diff --git a/src/test/ui/polymorphization/generators.stderr b/src/test/ui/polymorphization/generators.stderr
index c4e566a42d0..1152bcb0734 100644
--- a/src/test/ui/polymorphization/generators.stderr
+++ b/src/test/ui/polymorphization/generators.stderr
@@ -8,11 +8,10 @@ LL | #![feature(generic_const_exprs, generators, generator_trait, rustc_attrs)]
    = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
 
 error: item has unused generic parameters
-  --> $DIR/generators.rs:36:5
+  --> $DIR/generators.rs:35:5
    |
 LL |   pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
    |                      - generic parameter `T` is unused
-LL |
 LL | /     || {
 LL | |
 LL | |         yield 1;
@@ -21,17 +20,10 @@ LL | |     }
    | |_____^
 
 error: item has unused generic parameters
-  --> $DIR/generators.rs:34:8
-   |
-LL | pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
-   |        ^^^^^^^^^^^ - generic parameter `T` is unused
-
-error: item has unused generic parameters
-  --> $DIR/generators.rs:62:5
+  --> $DIR/generators.rs:60:5
    |
 LL |   pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
    |                             - generic parameter `T` is unused
-LL |
 LL | /     || {
 LL | |
 LL | |         yield 1;
@@ -39,11 +31,5 @@ LL | |         2
 LL | |     }
    | |_____^
 
-error: item has unused generic parameters
-  --> $DIR/generators.rs:60:8
-   |
-LL | pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
-   |        ^^^^^^^^^^^^       - generic parameter `T` is unused
-
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs
index cc36f054bc3..6facc467f7a 100644
--- a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs
+++ b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs
@@ -14,7 +14,7 @@ trait B {
 impl B for A {
     async fn associated(); //~ ERROR without body
     //~^ ERROR cannot be declared `async`
-    //~| ERROR incompatible type for trait
+    //~| ERROR impl has stricter requirements than trait
 }
 
 fn main() {}
diff --git a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr
index d3214458eac..c144060a859 100644
--- a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr
+++ b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr
@@ -44,25 +44,16 @@ LL |     async fn associated();
    = note: `async` trait functions are not currently supported
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
 
-error[E0053]: method `associated` has an incompatible type for trait
-  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:26
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:5
    |
 LL |     async fn associated();
-   |                          ^
-   |                          |
-   |                          checked the `Output` of this `async fn`, found opaque type
-   |                          expected `()`, found opaque type
-   |
-   = note: while checking the return type of the `async fn`
-note: type in trait
-  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:11:26
-   |
+   |     ---------------------- definition of `associated` from trait
+...
 LL |     async fn associated();
-   |                          ^
-   = note: expected fn pointer `fn()`
-              found fn pointer `fn() -> impl Future<Output = ()>`
+   |     ^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `(): Future`
 
 error: aborting due to 6 previous errors
 
-Some errors have detailed explanations: E0053, E0706.
-For more information about an error, try `rustc --explain E0053`.
+Some errors have detailed explanations: E0276, E0706.
+For more information about an error, try `rustc --explain E0276`.
diff --git a/src/test/ui/save-analysis/issue-68621.rs b/src/test/ui/save-analysis/issue-68621.rs
index 96af085c5b6..30479580f11 100644
--- a/src/test/ui/save-analysis/issue-68621.rs
+++ b/src/test/ui/save-analysis/issue-68621.rs
@@ -11,7 +11,7 @@ trait Service {
 struct Struct;
 
 impl Service for Struct {
-    type Future = impl Trait; //~ ERROR: could not find defining uses
+    type Future = impl Trait; //~ ERROR: unconstrained opaque type
 }
 
 fn main() {}
diff --git a/src/test/ui/save-analysis/issue-68621.stderr b/src/test/ui/save-analysis/issue-68621.stderr
index 3af6d0a3e07..4a4bf9a6996 100644
--- a/src/test/ui/save-analysis/issue-68621.stderr
+++ b/src/test/ui/save-analysis/issue-68621.stderr
@@ -1,8 +1,10 @@
-error: could not find defining uses
+error: unconstrained opaque type
   --> $DIR/issue-68621.rs:14:19
    |
 LL |     type Future = impl Trait;
    |                   ^^^^^^^^^^
+   |
+   = note: `Future` must be used in combination with a concrete type within the same module
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
index 61ac7731777..570a08cb587 100644
--- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
@@ -1,8 +1,8 @@
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:37
+  --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:48
    |
 LL |     async fn f(self: Pin<&Self>) -> impl Clone { self }
-   |                          -          ^^^^^^^^^^
+   |                          -                     ^^^^^^^^
    |                          |
    |                          hidden type `Pin<&Foo>` captures the lifetime `'_` as defined here
    |
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr
index 6f8200739b9..abdc650c68e 100644
--- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr
@@ -1,8 +1,8 @@
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:31
+  --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:44
    |
 LL |     fn f(self: Pin<&Self>) -> impl Clone { self }
-   |                    -----      ^^^^^^^^^^
+   |                    -----                   ^^^^
    |                    |
    |                    hidden type `Pin<&Foo>` captures the anonymous lifetime defined here
    |
diff --git a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs
index e72a2d8ccc6..cad7d76c6ab 100644
--- a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs
+++ b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs
@@ -2,6 +2,7 @@ trait Bar {}
 impl Bar for u8 {}
 fn foo() -> impl Bar {
     5; //~^ ERROR the trait bound `(): Bar` is not satisfied
+    //~| ERROR the trait bound `(): Bar` is not satisfied
 }
 
 fn main() {}
diff --git a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr
index d826222a06a..ba6967e78e1 100644
--- a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr
+++ b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr
@@ -6,6 +6,16 @@ LL | fn foo() -> impl Bar {
 LL |     5;
    |      - consider removing this semicolon
 
-error: aborting due to previous error
+error[E0277]: the trait bound `(): Bar` is not satisfied
+  --> $DIR/impl-trait-return-trailing-semicolon.rs:3:22
+   |
+LL |   fn foo() -> impl Bar {
+   |  ______________________^
+LL | |     5;
+LL | |
+LL | | }
+   | |_^ the trait `Bar` is not implemented for `()`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/issue-81098.rs b/src/test/ui/suggestions/issue-81098.rs
index a601b5866f4..7ca7380a7be 100644
--- a/src/test/ui/suggestions/issue-81098.rs
+++ b/src/test/ui/suggestions/issue-81098.rs
@@ -1,12 +1,14 @@
 // Don't suggest removing a semicolon if the last statement isn't an expression with semicolon
 // (#81098)
 fn wat() -> impl core::fmt::Display { //~ ERROR: `()` doesn't implement `std::fmt::Display`
+    //~^ ERROR: `()` doesn't implement `std::fmt::Display`
     fn why() {}
 }
 
 // Do it if the last statement is an expression with semicolon
 // (#54771)
 fn ok() -> impl core::fmt::Display { //~ ERROR: `()` doesn't implement `std::fmt::Display`
+    //~^ ERROR: `()` doesn't implement `std::fmt::Display`
     1;
 }
 
diff --git a/src/test/ui/suggestions/issue-81098.stderr b/src/test/ui/suggestions/issue-81098.stderr
index 2a72159e577..d62526442e9 100644
--- a/src/test/ui/suggestions/issue-81098.stderr
+++ b/src/test/ui/suggestions/issue-81098.stderr
@@ -8,16 +8,43 @@ LL | fn wat() -> impl core::fmt::Display {
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
 
 error[E0277]: `()` doesn't implement `std::fmt::Display`
-  --> $DIR/issue-81098.rs:9:12
+  --> $DIR/issue-81098.rs:3:37
+   |
+LL |   fn wat() -> impl core::fmt::Display {
+   |  _____________________________________^
+LL | |
+LL | |     fn why() {}
+LL | | }
+   | |_^ `()` cannot be formatted with the default formatter
+   |
+   = help: the trait `std::fmt::Display` is not implemented for `()`
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+
+error[E0277]: `()` doesn't implement `std::fmt::Display`
+  --> $DIR/issue-81098.rs:10:12
    |
 LL | fn ok() -> impl core::fmt::Display {
    |            ^^^^^^^^^^^^^^^^^^^^^^^ `()` cannot be formatted with the default formatter
+LL |
 LL |     1;
    |      - consider removing this semicolon
    |
    = help: the trait `std::fmt::Display` is not implemented for `()`
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
 
-error: aborting due to 2 previous errors
+error[E0277]: `()` doesn't implement `std::fmt::Display`
+  --> $DIR/issue-81098.rs:10:36
+   |
+LL |   fn ok() -> impl core::fmt::Display {
+   |  ____________________________________^
+LL | |
+LL | |     1;
+LL | | }
+   | |_^ `()` cannot be formatted with the default formatter
+   |
+   = help: the trait `std::fmt::Display` is not implemented for `()`
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/traits/alias/issue-83613.rs b/src/test/ui/traits/alias/issue-83613.rs
index 0013d5d66f1..04320e72076 100644
--- a/src/test/ui/traits/alias/issue-83613.rs
+++ b/src/test/ui/traits/alias/issue-83613.rs
@@ -8,6 +8,6 @@ fn mk_opaque() -> OpaqueType {
 trait AnotherTrait {}
 impl<T: Send> AnotherTrait for T {}
 impl AnotherTrait for OpaqueType {}
-//~^ ERROR conflicting implementations of trait `AnotherTrait` for type `impl OpaqueTrait`
+//~^ ERROR conflicting implementations of trait `AnotherTrait` for type `OpaqueType`
 //~| ERROR cannot implement trait on type alias impl trait
 fn main() {}
diff --git a/src/test/ui/traits/alias/issue-83613.stderr b/src/test/ui/traits/alias/issue-83613.stderr
index 6a3498a3893..4f19e6607c8 100644
--- a/src/test/ui/traits/alias/issue-83613.stderr
+++ b/src/test/ui/traits/alias/issue-83613.stderr
@@ -10,13 +10,13 @@ note: type alias impl trait defined here
 LL | type OpaqueType = impl OpaqueTrait;
    |                   ^^^^^^^^^^^^^^^^
 
-error[E0119]: conflicting implementations of trait `AnotherTrait` for type `impl OpaqueTrait`
+error[E0119]: conflicting implementations of trait `AnotherTrait` for type `OpaqueType`
   --> $DIR/issue-83613.rs:10:1
    |
 LL | impl<T: Send> AnotherTrait for T {}
    | -------------------------------- first implementation here
 LL | impl AnotherTrait for OpaqueType {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `impl OpaqueTrait`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `OpaqueType`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/traits/pointee-tail-is-generic-errors.rs b/src/test/ui/traits/pointee-tail-is-generic-errors.rs
index d081721aca2..28bc1da964d 100644
--- a/src/test/ui/traits/pointee-tail-is-generic-errors.rs
+++ b/src/test/ui/traits/pointee-tail-is-generic-errors.rs
@@ -14,7 +14,7 @@ fn a<T: ?Sized>() {
     //~^ ERROR type mismatch resolving `<T as Pointee>::Metadata == ()`
 
     is_thin::<Opaque>();
-    //~^ ERROR type mismatch resolving `<impl Debug + ?Sized as Pointee>::Metadata == ()`
+    //~^ ERROR type mismatch resolving `<Opaque as Pointee>::Metadata == ()`
 }
 
 fn is_thin<T: std::ptr::Pointee<Metadata = ()> + ?Sized>() {}
diff --git a/src/test/ui/traits/pointee-tail-is-generic-errors.stderr b/src/test/ui/traits/pointee-tail-is-generic-errors.stderr
index fa5fe67e53c..8456f84562f 100644
--- a/src/test/ui/traits/pointee-tail-is-generic-errors.stderr
+++ b/src/test/ui/traits/pointee-tail-is-generic-errors.stderr
@@ -14,7 +14,7 @@ note: required by a bound in `is_thin`
 LL | fn is_thin<T: std::ptr::Pointee<Metadata = ()> + ?Sized>() {}
    |                                 ^^^^^^^^^^^^^ required by this bound in `is_thin`
 
-error[E0271]: type mismatch resolving `<impl Debug + ?Sized as Pointee>::Metadata == ()`
+error[E0271]: type mismatch resolving `<Opaque as Pointee>::Metadata == ()`
   --> $DIR/pointee-tail-is-generic-errors.rs:16:5
    |
 LL | type Opaque = impl std::fmt::Debug + ?Sized;
@@ -24,13 +24,13 @@ LL |     is_thin::<Opaque>();
    |     ^^^^^^^^^^^^^^^^^ expected `()`, found associated type
    |
    = note:    expected unit type `()`
-           found associated type `<impl Debug + ?Sized as Pointee>::Metadata`
+           found associated type `<Opaque as Pointee>::Metadata`
 note: required by a bound in `is_thin`
   --> $DIR/pointee-tail-is-generic-errors.rs:20:33
    |
 LL | fn is_thin<T: std::ptr::Pointee<Metadata = ()> + ?Sized>() {}
    |                                 ^^^^^^^^^^^^^ required by this bound in `is_thin`
-help: consider constraining the associated type `<impl Debug + ?Sized as Pointee>::Metadata` to `()`
+help: consider constraining the associated type `<Opaque as Pointee>::Metadata` to `()`
    |
 LL | type Opaque = impl std::fmt::Debug<Metadata = ()> + ?Sized;
    |                                   +++++++++++++++
diff --git a/src/test/ui/type-alias-impl-trait/argument-types.rs b/src/test/ui/type-alias-impl-trait/argument-types.rs
index 8427b5b1fe8..185207b9800 100644
--- a/src/test/ui/type-alias-impl-trait/argument-types.rs
+++ b/src/test/ui/type-alias-impl-trait/argument-types.rs
@@ -1,14 +1,12 @@
 #![feature(type_alias_impl_trait)]
 #![allow(dead_code)]
-
+// check-pass
 use std::fmt::Debug;
 
 type Foo = impl Debug;
 
-// FIXME: This should compile, but it currently doesn't
 fn foo1(mut x: Foo) {
     x = 22_u32;
-    //~^ ERROR: mismatched types [E0308]
 }
 
 fn foo2(mut x: Foo) {
diff --git a/src/test/ui/type-alias-impl-trait/argument-types.stderr b/src/test/ui/type-alias-impl-trait/argument-types.stderr
deleted file mode 100644
index a87e44a048b..00000000000
--- a/src/test/ui/type-alias-impl-trait/argument-types.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/argument-types.rs:10:9
-   |
-LL | type Foo = impl Debug;
-   |            ---------- the expected opaque type
-...
-LL | fn foo1(mut x: Foo) {
-   |                --- expected due to this parameter type
-LL |     x = 22_u32;
-   |         ^^^^^^ expected opaque type, found `u32`
-   |
-   = note: expected opaque type `impl Debug`
-                     found type `u32`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/type-alias-impl-trait/auto-trait-leakage2.stderr b/src/test/ui/type-alias-impl-trait/auto-trait-leakage2.stderr
index 4a49d6e4ab8..0664275b2ad 100644
--- a/src/test/ui/type-alias-impl-trait/auto-trait-leakage2.stderr
+++ b/src/test/ui/type-alias-impl-trait/auto-trait-leakage2.stderr
@@ -2,15 +2,15 @@ error[E0277]: `Rc<u32>` cannot be sent between threads safely
   --> $DIR/auto-trait-leakage2.rs:17:13
    |
 LL |     type Foo = impl std::fmt::Debug;
-   |                -------------------- within this `impl Debug`
+   |                -------------------- within this `Foo`
 ...
 LL |     is_send(m::foo());
    |     ------- ^^^^^^^^ `Rc<u32>` cannot be sent between threads safely
    |     |
    |     required by a bound introduced by this call
    |
-   = help: within `impl Debug`, the trait `Send` is not implemented for `Rc<u32>`
-   = note: required because it appears within the type `impl Debug`
+   = help: within `Foo`, the trait `Send` is not implemented for `Rc<u32>`
+   = note: required because it appears within the type `Foo`
 note: required by a bound in `is_send`
   --> $DIR/auto-trait-leakage2.rs:14:15
    |
diff --git a/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.rs b/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.rs
index 5fb7a9473d3..b456b1445e7 100644
--- a/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.rs
+++ b/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.rs
@@ -6,6 +6,7 @@
 mod m {
     type Foo = impl std::fmt::Debug;
     //~^ ERROR: cycle detected when computing type of `m::Foo::{opaque#0}` [E0391]
+    //~| ERROR: cycle detected when computing type of `m::Foo::{opaque#0}` [E0391]
 
     pub fn foo() -> Foo {
         22_u32
diff --git a/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr b/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr
index c0147e56c93..4c44875b4a5 100644
--- a/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr
+++ b/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr
@@ -5,11 +5,10 @@ LL |     type Foo = impl std::fmt::Debug;
    |                ^^^^^^^^^^^^^^^^^^^^
    |
 note: ...which requires type-checking `m::bar`...
-  --> $DIR/auto-trait-leakage3.rs:15:9
+  --> $DIR/auto-trait-leakage3.rs:15:5
    |
-LL |         is_send(foo());
-   |         ^^^^^^^
-   = note: ...which requires evaluating trait selection obligation `impl core::fmt::Debug: core::marker::Send`...
+LL |     pub fn bar() {
+   |     ^^^^^^^^^^^^
    = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle
 note: cycle used when checking item types in module `m`
   --> $DIR/auto-trait-leakage3.rs:6:1
@@ -17,6 +16,24 @@ note: cycle used when checking item types in module `m`
 LL | mod m {
    | ^^^^^
 
-error: aborting due to previous error
+error[E0391]: cycle detected when computing type of `m::Foo::{opaque#0}`
+  --> $DIR/auto-trait-leakage3.rs:7:16
+   |
+LL |     type Foo = impl std::fmt::Debug;
+   |                ^^^^^^^^^^^^^^^^^^^^
+   |
+note: ...which requires type-checking `m::bar`...
+  --> $DIR/auto-trait-leakage3.rs:15:5
+   |
+LL |     pub fn bar() {
+   |     ^^^^^^^^^^^^
+   = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle
+note: cycle used when checking item types in module `m`
+  --> $DIR/auto-trait-leakage3.rs:6:1
+   |
+LL | mod m {
+   | ^^^^^
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/type-alias-impl-trait/bound_reduction2.rs b/src/test/ui/type-alias-impl-trait/bound_reduction2.rs
index cee8186dd8f..4d2890b5de5 100644
--- a/src/test/ui/type-alias-impl-trait/bound_reduction2.rs
+++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.rs
@@ -7,13 +7,12 @@ trait TraitWithAssoc {
 }
 
 type Foo<V> = impl Trait<V>;
-//~^ ERROR could not find defining uses
 
 trait Trait<U> {}
 
 impl<W> Trait<W> for () {}
 
 fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
-    //~^ ERROR non-defining opaque type use in defining scope
     ()
+    //~^ ERROR non-defining opaque type use
 }
diff --git a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr
index 03e696fe898..c405b1f6af2 100644
--- a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr
+++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr
@@ -1,8 +1,8 @@
 error: non-defining opaque type use in defining scope
-  --> $DIR/bound_reduction2.rs:16:46
+  --> $DIR/bound_reduction2.rs:16:5
    |
-LL | fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
-   |                                              ^^^^^^^^^^^^^
+LL |     ()
+   |     ^^
    |
 note: used non-generic type `<T as TraitWithAssoc>::Assoc` for generic parameter
   --> $DIR/bound_reduction2.rs:9:10
@@ -10,11 +10,5 @@ note: used non-generic type `<T as TraitWithAssoc>::Assoc` for generic parameter
 LL | type Foo<V> = impl Trait<V>;
    |          ^
 
-error: could not find defining uses
-  --> $DIR/bound_reduction2.rs:9:15
-   |
-LL | type Foo<V> = impl Trait<V>;
-   |               ^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/bounds-are-checked.rs b/src/test/ui/type-alias-impl-trait/bounds-are-checked.rs
index eecef2338c1..83d22161e4e 100644
--- a/src/test/ui/type-alias-impl-trait/bounds-are-checked.rs
+++ b/src/test/ui/type-alias-impl-trait/bounds-are-checked.rs
@@ -4,11 +4,11 @@
 #![feature(type_alias_impl_trait)]
 
 type X<'a> = impl Into<&'static str> + From<&'a str>;
-//~^ ERROR mismatched types
 
 fn f<'a: 'static>(t: &'a str) -> X<'a> {
     //~^ WARNING unnecessary lifetime parameter
     t
+    //~^ ERROR non-defining opaque type use
 }
 
 fn extend_lt<'a>(o: &'a str) -> &'static str {
diff --git a/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr b/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr
index da9f81d6bd3..d87ef2ec79c 100644
--- a/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr
+++ b/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr
@@ -1,26 +1,19 @@
 warning: unnecessary lifetime parameter `'a`
-  --> $DIR/bounds-are-checked.rs:9:6
+  --> $DIR/bounds-are-checked.rs:8:6
    |
 LL | fn f<'a: 'static>(t: &'a str) -> X<'a> {
    |      ^^^^^^^^^^^
    |
    = help: you can use the `'static` lifetime directly, in place of `'a`
 
-error[E0308]: mismatched types
-  --> $DIR/bounds-are-checked.rs:6:14
+error: non-defining opaque type use in defining scope
+  --> $DIR/bounds-are-checked.rs:10:5
    |
 LL | type X<'a> = impl Into<&'static str> + From<&'a str>;
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
-   |
-   = note: expected trait `From<&'a str>`
-              found trait `From<&'static str>`
-note: the lifetime `'a` as defined here...
-  --> $DIR/bounds-are-checked.rs:6:8
-   |
-LL | type X<'a> = impl Into<&'static str> + From<&'a str>;
-   |        ^^
-   = note: ...does not necessarily outlive the static lifetime
+   |        -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
+...
+LL |     t
+   |     ^
 
 error: aborting due to previous error; 1 warning emitted
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/type-alias-impl-trait/closures_in_branches.rs b/src/test/ui/type-alias-impl-trait/closures_in_branches.rs
new file mode 100644
index 00000000000..a1a9401acc2
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/closures_in_branches.rs
@@ -0,0 +1,31 @@
+#![feature(type_alias_impl_trait)]
+
+type Foo = impl std::ops::FnOnce(String) -> usize;
+
+fn foo(b: bool) -> Foo {
+    if b {
+        |x| x.len()
+    } else {
+        panic!()
+    }
+}
+
+
+type Foo1 = impl std::ops::FnOnce(String) -> usize;
+fn foo1(b: bool) -> Foo1 {
+    |x| x.len()
+}
+
+fn bar(b: bool) -> impl std::ops::FnOnce(String) -> usize {
+    if b {
+        |x| x.len() //~ ERROR type annotations needed
+    } else {
+        panic!()
+    }
+}
+
+fn bar1(b: bool) -> impl std::ops::FnOnce(String) -> usize {
+    |x| x.len()
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/closures_in_branches.stderr b/src/test/ui/type-alias-impl-trait/closures_in_branches.stderr
new file mode 100644
index 00000000000..cfa4a4b9d20
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/closures_in_branches.stderr
@@ -0,0 +1,11 @@
+error[E0282]: type annotations needed
+  --> $DIR/closures_in_branches.rs:21:10
+   |
+LL |         |x| x.len()
+   |          ^ consider giving this closure parameter a type
+   |
+   = note: type must be known at this point
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/type-alias-impl-trait/declared_but_never_defined.rs b/src/test/ui/type-alias-impl-trait/declared_but_never_defined.rs
index c4bf56a9197..6febd07157a 100644
--- a/src/test/ui/type-alias-impl-trait/declared_but_never_defined.rs
+++ b/src/test/ui/type-alias-impl-trait/declared_but_never_defined.rs
@@ -3,4 +3,4 @@
 fn main() {}
 
 // declared but never defined
-type Bar = impl std::fmt::Debug; //~ ERROR could not find defining uses
+type Bar = impl std::fmt::Debug; //~ ERROR unconstrained opaque type
diff --git a/src/test/ui/type-alias-impl-trait/declared_but_never_defined.stderr b/src/test/ui/type-alias-impl-trait/declared_but_never_defined.stderr
index 21c2e8a9db6..60bc24320a3 100644
--- a/src/test/ui/type-alias-impl-trait/declared_but_never_defined.stderr
+++ b/src/test/ui/type-alias-impl-trait/declared_but_never_defined.stderr
@@ -1,8 +1,10 @@
-error: could not find defining uses
+error: unconstrained opaque type
   --> $DIR/declared_but_never_defined.rs:6:12
    |
 LL | type Bar = impl std::fmt::Debug;
    |            ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Bar` must be used in combination with a concrete type within the same module
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs b/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs
index 7ea517eb734..5bda5f0fcea 100644
--- a/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs
+++ b/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs
@@ -4,7 +4,7 @@ fn main() {}
 
 mod boo {
     // declared in module but not defined inside of it
-    pub type Boo = impl ::std::fmt::Debug; //~ ERROR could not find defining uses
+    pub type Boo = impl ::std::fmt::Debug; //~ ERROR unconstrained opaque type
 }
 
 fn bomp() -> boo::Boo {
diff --git a/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr b/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr
index 0b4c262bbb4..fbfa0ccf1e8 100644
--- a/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr
+++ b/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr
@@ -1,8 +1,10 @@
-error: could not find defining uses
+error: unconstrained opaque type
   --> $DIR/declared_but_not_defined_in_scope.rs:7:20
    |
 LL |     pub type Boo = impl ::std::fmt::Debug;
    |                    ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Boo` must be used in combination with a concrete type within the same module
 
 error[E0308]: mismatched types
   --> $DIR/declared_but_not_defined_in_scope.rs:11:5
@@ -11,11 +13,11 @@ LL |     pub type Boo = impl ::std::fmt::Debug;
    |                    ---------------------- the expected opaque type
 ...
 LL | fn bomp() -> boo::Boo {
-   |              -------- expected `impl Debug` because of return type
+   |              -------- expected `Boo` because of return type
 LL |     ""
    |     ^^ expected opaque type, found `&str`
    |
-   = note: expected opaque type `impl Debug`
+   = note: expected opaque type `Boo`
                 found reference `&'static str`
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/type-alias-impl-trait/different_defining_uses.rs b/src/test/ui/type-alias-impl-trait/different_defining_uses.rs
index 272af7a5204..4505c4d9524 100644
--- a/src/test/ui/type-alias-impl-trait/different_defining_uses.rs
+++ b/src/test/ui/type-alias-impl-trait/different_defining_uses.rs
@@ -10,6 +10,6 @@ fn foo() -> Foo {
 }
 
 fn bar() -> Foo {
-    //~^ ERROR concrete type differs from previous
     42i32
+    //~^ ERROR concrete type differs from previous
 }
diff --git a/src/test/ui/type-alias-impl-trait/different_defining_uses.stderr b/src/test/ui/type-alias-impl-trait/different_defining_uses.stderr
index eaa716bc71c..a8b4cd7afe8 100644
--- a/src/test/ui/type-alias-impl-trait/different_defining_uses.stderr
+++ b/src/test/ui/type-alias-impl-trait/different_defining_uses.stderr
@@ -1,14 +1,14 @@
 error: concrete type differs from previous defining opaque type use
-  --> $DIR/different_defining_uses.rs:12:1
+  --> $DIR/different_defining_uses.rs:13:5
    |
-LL | fn bar() -> Foo {
-   | ^^^^^^^^^^^^^^^ expected `&'static str`, got `i32`
+LL |     42i32
+   |     ^^^^^ expected `&'static str`, got `i32`
    |
 note: previous use here
-  --> $DIR/different_defining_uses.rs:8:1
+  --> $DIR/different_defining_uses.rs:9:5
    |
-LL | fn foo() -> Foo {
-   | ^^^^^^^^^^^^^^^
+LL |     ""
+   |     ^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.rs b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.rs
index 95cbcfec2dc..7740f774ebc 100644
--- a/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.rs
+++ b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.rs
@@ -1,5 +1,5 @@
 #![feature(type_alias_impl_trait)]
-
+// check-pass
 fn main() {}
 
 // two definitions with different types
@@ -10,11 +10,9 @@ fn foo() -> Foo {
 }
 
 fn bar() -> Foo {
-    //~^ ERROR concrete type differs from previous
     panic!()
 }
 
 fn boo() -> Foo {
-    //~^ ERROR concrete type differs from previous
     loop {}
 }
diff --git a/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr
deleted file mode 100644
index 6274029e4f5..00000000000
--- a/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr
+++ /dev/null
@@ -1,26 +0,0 @@
-error: concrete type differs from previous defining opaque type use
-  --> $DIR/different_defining_uses_never_type.rs:12:1
-   |
-LL | fn bar() -> Foo {
-   | ^^^^^^^^^^^^^^^ expected `&'static str`, got `()`
-   |
-note: previous use here
-  --> $DIR/different_defining_uses_never_type.rs:8:1
-   |
-LL | fn foo() -> Foo {
-   | ^^^^^^^^^^^^^^^
-
-error: concrete type differs from previous defining opaque type use
-  --> $DIR/different_defining_uses_never_type.rs:17:1
-   |
-LL | fn boo() -> Foo {
-   | ^^^^^^^^^^^^^^^ expected `&'static str`, got `()`
-   |
-note: previous use here
-  --> $DIR/different_defining_uses_never_type.rs:8:1
-   |
-LL | fn foo() -> Foo {
-   | ^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/type-alias-impl-trait/different_lifetimes_defining_uses.rs b/src/test/ui/type-alias-impl-trait/different_lifetimes_defining_uses.rs
index d0001976d65..4f424b8c665 100644
--- a/src/test/ui/type-alias-impl-trait/different_lifetimes_defining_uses.rs
+++ b/src/test/ui/type-alias-impl-trait/different_lifetimes_defining_uses.rs
@@ -8,8 +8,8 @@ fn foo<'a, 'b>(a: &'a u32, b: &'b u32) -> OneLifetime<'a, 'b> {
 }
 
 fn bar<'a, 'b>(a: &'a u32, b: &'b u32) -> OneLifetime<'a, 'b> {
-    //~^ ERROR: concrete type differs from previous defining opaque type use
     b
+    //~^ ERROR: concrete type differs from previous defining opaque type use
 }
 
 fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/different_lifetimes_defining_uses.stderr b/src/test/ui/type-alias-impl-trait/different_lifetimes_defining_uses.stderr
index 9493a59cf1e..0c50a84e894 100644
--- a/src/test/ui/type-alias-impl-trait/different_lifetimes_defining_uses.stderr
+++ b/src/test/ui/type-alias-impl-trait/different_lifetimes_defining_uses.stderr
@@ -1,14 +1,14 @@
 error: concrete type differs from previous defining opaque type use
-  --> $DIR/different_lifetimes_defining_uses.rs:10:1
+  --> $DIR/different_lifetimes_defining_uses.rs:11:5
    |
-LL | fn bar<'a, 'b>(a: &'a u32, b: &'b u32) -> OneLifetime<'a, 'b> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&'a u32`, got `&'b u32`
+LL |     b
+   |     ^ expected `&'a u32`, got `&'b u32`
    |
 note: previous use here
-  --> $DIR/different_lifetimes_defining_uses.rs:6:1
+  --> $DIR/different_lifetimes_defining_uses.rs:7:5
    |
-LL | fn foo<'a, 'b>(a: &'a u32, b: &'b u32) -> OneLifetime<'a, 'b> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     a
+   |     ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/fallback.rs b/src/test/ui/type-alias-impl-trait/fallback.rs
index fe1ca2230da..d7e93335f47 100644
--- a/src/test/ui/type-alias-impl-trait/fallback.rs
+++ b/src/test/ui/type-alias-impl-trait/fallback.rs
@@ -1,5 +1,5 @@
-// Tests that we correctly handle the instantiated
-// inference variable being completely unconstrained.
+// Tests that we correctly handle opaque types being used opaquely,
+// even within their defining scope.
 //
 // check-pass
 #![feature(type_alias_impl_trait)]
diff --git a/src/test/ui/type-alias-impl-trait/field-types.rs b/src/test/ui/type-alias-impl-trait/field-types.rs
index 91494a82d0f..d99ed58127b 100644
--- a/src/test/ui/type-alias-impl-trait/field-types.rs
+++ b/src/test/ui/type-alias-impl-trait/field-types.rs
@@ -1,12 +1,11 @@
 #![feature(type_alias_impl_trait)]
 #![allow(dead_code)]
 
-// FIXME This should compile, but it currently doesn't
+// check-pass
 
 use std::fmt::Debug;
 
 type Foo = impl Debug;
-//~^ ERROR: could not find defining uses
 
 struct Bar {
     foo: Foo,
@@ -14,7 +13,6 @@ struct Bar {
 
 fn bar() -> Bar {
     Bar { foo: "foo" }
-    //~^ ERROR: mismatched types [E0308]
 }
 
 fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/field-types.stderr b/src/test/ui/type-alias-impl-trait/field-types.stderr
deleted file mode 100644
index 18c2abbdf37..00000000000
--- a/src/test/ui/type-alias-impl-trait/field-types.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/field-types.rs:16:16
-   |
-LL | type Foo = impl Debug;
-   |            ---------- the expected opaque type
-...
-LL |     Bar { foo: "foo" }
-   |                ^^^^^ expected opaque type, found `&str`
-   |
-   = note: expected opaque type `impl Debug`
-                found reference `&'static str`
-
-error: could not find defining uses
-  --> $DIR/field-types.rs:8:12
-   |
-LL | type Foo = impl Debug;
-   |            ^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/type-alias-impl-trait/generic_different_defining_uses.rs b/src/test/ui/type-alias-impl-trait/generic_different_defining_uses.rs
index 07535130758..8b683ad2828 100644
--- a/src/test/ui/type-alias-impl-trait/generic_different_defining_uses.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_different_defining_uses.rs
@@ -9,6 +9,6 @@ fn my_iter<T>(t: T) -> MyIter<T> {
 }
 
 fn my_iter2<T>(t: T) -> MyIter<T> {
-    //~^ ERROR concrete type differs from previous
     Some(t).into_iter()
+    //~^ ERROR concrete type differs from previous
 }
diff --git a/src/test/ui/type-alias-impl-trait/generic_different_defining_uses.stderr b/src/test/ui/type-alias-impl-trait/generic_different_defining_uses.stderr
index f8a058170e3..47ac3346259 100644
--- a/src/test/ui/type-alias-impl-trait/generic_different_defining_uses.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_different_defining_uses.stderr
@@ -1,14 +1,14 @@
 error: concrete type differs from previous defining opaque type use
-  --> $DIR/generic_different_defining_uses.rs:11:1
+  --> $DIR/generic_different_defining_uses.rs:12:5
    |
-LL | fn my_iter2<T>(t: T) -> MyIter<T> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `std::iter::Once<T>`, got `std::option::IntoIter<T>`
+LL |     Some(t).into_iter()
+   |     ^^^^^^^^^^^^^^^^^^^ expected `std::iter::Once<T>`, got `std::option::IntoIter<T>`
    |
 note: previous use here
-  --> $DIR/generic_different_defining_uses.rs:7:1
+  --> $DIR/generic_different_defining_uses.rs:8:5
    |
-LL | fn my_iter<T>(t: T) -> MyIter<T> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     std::iter::once(t)
+   |     ^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.rs
index 885aae619d6..c9b9e128f88 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.rs
@@ -3,9 +3,9 @@
 fn main() {}
 
 type Two<'a, 'b> = impl std::fmt::Debug;
-//~^ ERROR could not find defining uses
+
 
 fn one<'a>(t: &'a ()) -> Two<'a, 'a> {
-    //~^ ERROR non-defining opaque type use
     t
+    //~^ ERROR non-defining opaque type use
 }
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.stderr
index b99c6a51f4b..222aaea78d9 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.stderr
@@ -1,8 +1,8 @@
 error: non-defining opaque type use in defining scope
-  --> $DIR/generic_duplicate_lifetime_param.rs:8:26
+  --> $DIR/generic_duplicate_lifetime_param.rs:9:5
    |
-LL | fn one<'a>(t: &'a ()) -> Two<'a, 'a> {
-   |                          ^^^^^^^^^^^
+LL |     t
+   |     ^
    |
 note: lifetime used multiple times
   --> $DIR/generic_duplicate_lifetime_param.rs:5:10
@@ -10,11 +10,5 @@ note: lifetime used multiple times
 LL | type Two<'a, 'b> = impl std::fmt::Debug;
    |          ^^  ^^
 
-error: could not find defining uses
-  --> $DIR/generic_duplicate_lifetime_param.rs:5:20
-   |
-LL | type Two<'a, 'b> = impl std::fmt::Debug;
-   |                    ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs
index 33cd2f6ba07..093c1c23186 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs
@@ -6,23 +6,23 @@ fn main() {}
 
 // test that unused generic parameters are ok
 type TwoTys<T, U> = impl Debug;
-//~^ ERROR could not find defining uses
+
 type TwoLifetimes<'a, 'b> = impl Debug;
-//~^ ERROR could not find defining uses
+
 type TwoConsts<const X: usize, const Y: usize> = impl Debug;
-//~^ ERROR could not find defining uses
+
 
 fn one_ty<T: Debug>(t: T) -> TwoTys<T, T> {
-    //~^ ERROR non-defining opaque type use in defining scope
     t
+    //~^ ERROR non-defining opaque type use in defining scope
 }
 
 fn one_lifetime<'a>(t: &'a u32) -> TwoLifetimes<'a, 'a> {
-    //~^ ERROR non-defining opaque type use in defining scope
     t
+    //~^ ERROR non-defining opaque type use in defining scope
 }
 
 fn one_const<const N: usize>(t: *mut [u8; N]) -> TwoConsts<N, N> {
-    //~^ ERROR non-defining opaque type use in defining scope
     t
+    //~^ ERROR non-defining opaque type use in defining scope
 }
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr
index 52c60d1777e..922e41e0f68 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr
@@ -1,8 +1,8 @@
 error: non-defining opaque type use in defining scope
-  --> $DIR/generic_duplicate_param_use.rs:15:30
+  --> $DIR/generic_duplicate_param_use.rs:16:5
    |
-LL | fn one_ty<T: Debug>(t: T) -> TwoTys<T, T> {
-   |                              ^^^^^^^^^^^^
+LL |     t
+   |     ^
    |
 note: type used multiple times
   --> $DIR/generic_duplicate_param_use.rs:8:13
@@ -10,17 +10,11 @@ note: type used multiple times
 LL | type TwoTys<T, U> = impl Debug;
    |             ^  ^
 
-error: could not find defining uses
-  --> $DIR/generic_duplicate_param_use.rs:8:21
-   |
-LL | type TwoTys<T, U> = impl Debug;
-   |                     ^^^^^^^^^^
-
 error: non-defining opaque type use in defining scope
-  --> $DIR/generic_duplicate_param_use.rs:20:36
+  --> $DIR/generic_duplicate_param_use.rs:21:5
    |
-LL | fn one_lifetime<'a>(t: &'a u32) -> TwoLifetimes<'a, 'a> {
-   |                                    ^^^^^^^^^^^^^^^^^^^^
+LL |     t
+   |     ^
    |
 note: lifetime used multiple times
   --> $DIR/generic_duplicate_param_use.rs:10:19
@@ -28,17 +22,11 @@ note: lifetime used multiple times
 LL | type TwoLifetimes<'a, 'b> = impl Debug;
    |                   ^^  ^^
 
-error: could not find defining uses
-  --> $DIR/generic_duplicate_param_use.rs:10:29
-   |
-LL | type TwoLifetimes<'a, 'b> = impl Debug;
-   |                             ^^^^^^^^^^
-
 error: non-defining opaque type use in defining scope
-  --> $DIR/generic_duplicate_param_use.rs:25:50
+  --> $DIR/generic_duplicate_param_use.rs:26:5
    |
-LL | fn one_const<const N: usize>(t: *mut [u8; N]) -> TwoConsts<N, N> {
-   |                                                  ^^^^^^^^^^^^^^^
+LL |     t
+   |     ^
    |
 note: constant used multiple times
   --> $DIR/generic_duplicate_param_use.rs:12:22
@@ -46,11 +34,5 @@ note: constant used multiple times
 LL | type TwoConsts<const X: usize, const Y: usize> = impl Debug;
    |                      ^               ^
 
-error: could not find defining uses
-  --> $DIR/generic_duplicate_param_use.rs:12:50
-   |
-LL | type TwoConsts<const X: usize, const Y: usize> = impl Debug;
-   |                                                  ^^^^^^^^^^
-
-error: aborting due to 6 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs
index 04fb57b39c0..81bf9770d02 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs
@@ -8,11 +8,6 @@ fn main() {}
 type Two<T, U> = impl Debug;
 //~^ ERROR `T` doesn't implement `Debug`
 
-fn one<T: Debug>(t: T) -> Two<T, T> {
-    //~^ ERROR non-defining opaque type use in defining scope
-    t
-}
-
 fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
     t
 }
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr
index fca9b70d184..84aa260b099 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr
@@ -1,15 +1,3 @@
-error: non-defining opaque type use in defining scope
-  --> $DIR/generic_duplicate_param_use2.rs:11:27
-   |
-LL | fn one<T: Debug>(t: T) -> Two<T, T> {
-   |                           ^^^^^^^^^
-   |
-note: type used multiple times
-  --> $DIR/generic_duplicate_param_use2.rs:8:10
-   |
-LL | type Two<T, U> = impl Debug;
-   |          ^  ^
-
 error[E0277]: `T` doesn't implement `Debug`
   --> $DIR/generic_duplicate_param_use2.rs:8:18
    |
@@ -21,6 +9,6 @@ help: consider restricting type parameter `T`
 LL | type Two<T: std::fmt::Debug, U> = impl Debug;
    |           +++++++++++++++++
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs
index 1a755d39026..7747626d96d 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs
@@ -8,16 +8,11 @@ fn main() {}
 type Two<T, U> = impl Debug;
 //~^ ERROR `T` doesn't implement `Debug`
 
-fn one<T: Debug>(t: T) -> Two<T, T> {
-    //~^ ERROR non-defining opaque type use in defining scope
-    t
-}
-
 fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
     t
 }
 
 fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
-    //~^ ERROR concrete type differs from previous defining opaque type use
     u
+    //~^ ERROR concrete type differs from previous defining opaque type use
 }
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr
index 90b04c043a0..88c450704bf 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr
@@ -1,26 +1,14 @@
-error: non-defining opaque type use in defining scope
-  --> $DIR/generic_duplicate_param_use3.rs:11:27
-   |
-LL | fn one<T: Debug>(t: T) -> Two<T, T> {
-   |                           ^^^^^^^^^
-   |
-note: type used multiple times
-  --> $DIR/generic_duplicate_param_use3.rs:8:10
-   |
-LL | type Two<T, U> = impl Debug;
-   |          ^  ^
-
 error: concrete type differs from previous defining opaque type use
-  --> $DIR/generic_duplicate_param_use3.rs:20:1
+  --> $DIR/generic_duplicate_param_use3.rs:16:5
    |
-LL | fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `T`, got `U`
+LL |     u
+   |     ^ expected `T`, got `U`
    |
 note: previous use here
-  --> $DIR/generic_duplicate_param_use3.rs:16:1
+  --> $DIR/generic_duplicate_param_use3.rs:12:5
    |
-LL | fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     t
+   |     ^
 
 error[E0277]: `T` doesn't implement `Debug`
   --> $DIR/generic_duplicate_param_use3.rs:8:18
@@ -33,6 +21,6 @@ help: consider restricting type parameter `T`
 LL | type Two<T: std::fmt::Debug, U> = impl Debug;
    |           +++++++++++++++++
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.rs
index 50d95c83d58..aee2550e907 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.rs
@@ -8,11 +8,6 @@ fn main() {}
 type Two<T, U> = impl Debug;
 //~^ ERROR `U` doesn't implement `Debug`
 
-fn one<T: Debug>(t: T) -> Two<T, T> {
-    //~^ ERROR non-defining opaque type use in defining scope
-    t
-}
-
 fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
     u
 }
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr
index c4be2fa83f1..0491d61030e 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr
@@ -1,15 +1,3 @@
-error: non-defining opaque type use in defining scope
-  --> $DIR/generic_duplicate_param_use4.rs:11:27
-   |
-LL | fn one<T: Debug>(t: T) -> Two<T, T> {
-   |                           ^^^^^^^^^
-   |
-note: type used multiple times
-  --> $DIR/generic_duplicate_param_use4.rs:8:10
-   |
-LL | type Two<T, U> = impl Debug;
-   |          ^  ^
-
 error[E0277]: `U` doesn't implement `Debug`
   --> $DIR/generic_duplicate_param_use4.rs:8:18
    |
@@ -21,6 +9,6 @@ help: consider restricting type parameter `U`
 LL | type Two<T, U: std::fmt::Debug> = impl Debug;
    |              +++++++++++++++++
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use5.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use5.rs
index dd2f202cf5d..03bd00a039d 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use5.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use5.rs
@@ -14,6 +14,6 @@ fn two<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
 }
 
 fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
-    //~^ concrete type differs from previous
     (u, t)
+    //~^ concrete type differs from previous
 }
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use5.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use5.stderr
index 6cc6b35668c..d46a3ebe175 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use5.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use5.stderr
@@ -1,14 +1,14 @@
 error: concrete type differs from previous defining opaque type use
-  --> $DIR/generic_duplicate_param_use5.rs:16:1
+  --> $DIR/generic_duplicate_param_use5.rs:17:5
    |
-LL | fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(T, U)`, got `(U, T)`
+LL |     (u, t)
+   |     ^^^^^^ expected `(T, U)`, got `(U, T)`
    |
 note: previous use here
-  --> $DIR/generic_duplicate_param_use5.rs:12:1
+  --> $DIR/generic_duplicate_param_use5.rs:13:5
    |
-LL | fn two<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     (t, u)
+   |     ^^^^^^
 
 error[E0277]: `T` doesn't implement `Debug`
   --> $DIR/generic_duplicate_param_use5.rs:8:18
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.rs
index d54d3cd62e0..a8c801dc887 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.rs
@@ -13,6 +13,6 @@ fn two<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
 }
 
 fn three<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
-    //~^ ERROR concrete type differs from previous
     (u, t)
+    //~^ ERROR concrete type differs from previous
 }
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr
index e7520988e34..7e89b574b5c 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr
@@ -1,14 +1,14 @@
 error: concrete type differs from previous defining opaque type use
-  --> $DIR/generic_duplicate_param_use6.rs:15:1
+  --> $DIR/generic_duplicate_param_use6.rs:16:5
    |
-LL | fn three<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(T, T)`, got `(U, T)`
+LL |     (u, t)
+   |     ^^^^^^ expected `(T, T)`, got `(U, T)`
    |
 note: previous use here
-  --> $DIR/generic_duplicate_param_use6.rs:11:1
+  --> $DIR/generic_duplicate_param_use6.rs:12:5
    |
-LL | fn two<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     (t, t)
+   |     ^^^^^^
 
 error[E0277]: `T` doesn't implement `Debug`
   --> $DIR/generic_duplicate_param_use6.rs:8:18
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use8.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use8.rs
index 4a723b64cdc..57527e758db 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use8.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use8.rs
@@ -12,6 +12,6 @@ fn two<T: Debug, U: Debug>(t: T, _: U) -> Two<T, U> {
 }
 
 fn three<T: Debug, U: Debug>(_: T, u: U) -> Two<T, U> {
-    //~^ concrete type differs from previous
     (u, 4u32)
+    //~^ concrete type differs from previous
 }
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use8.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use8.stderr
index 44bdbdc95cc..1a6ec3aec14 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use8.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use8.stderr
@@ -1,14 +1,14 @@
 error: concrete type differs from previous defining opaque type use
-  --> $DIR/generic_duplicate_param_use8.rs:14:1
+  --> $DIR/generic_duplicate_param_use8.rs:15:5
    |
-LL | fn three<T: Debug, U: Debug>(_: T, u: U) -> Two<T, U> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(T, u32)`, got `(U, u32)`
+LL |     (u, 4u32)
+   |     ^^^^^^^^^ expected `(T, u32)`, got `(U, u32)`
    |
 note: previous use here
-  --> $DIR/generic_duplicate_param_use8.rs:10:1
+  --> $DIR/generic_duplicate_param_use8.rs:11:5
    |
-LL | fn two<T: Debug, U: Debug>(t: T, _: U) -> Two<T, U> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     (t, 4u32)
+   |     ^^^^^^^^^
 
 error[E0277]: `T` doesn't implement `Debug`
   --> $DIR/generic_duplicate_param_use8.rs:7:18
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.rs
index 4baf198b12f..5878ad92698 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.rs
@@ -19,5 +19,5 @@ fn two<T: Debug + Foo, U: Debug>(t: T, u: U) -> Two<T, U> {
 }
 
 fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
-    (t, u, 42) //~^ ERROR concrete type differs from previous
+    (t, u, 42) //~ ERROR concrete type differs from previous
 }
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr
index 43471f980b2..ef7573246af 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr
@@ -1,14 +1,14 @@
 error: concrete type differs from previous defining opaque type use
-  --> $DIR/generic_duplicate_param_use9.rs:21:1
+  --> $DIR/generic_duplicate_param_use9.rs:22:5
    |
-LL | fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(A, B, <A as Foo>::Bar)`, got `(A, B, i32)`
+LL |     (t, u, 42)
+   |     ^^^^^^^^^^ expected `(A, B, <A as Foo>::Bar)`, got `(A, B, i32)`
    |
 note: previous use here
-  --> $DIR/generic_duplicate_param_use9.rs:17:1
+  --> $DIR/generic_duplicate_param_use9.rs:18:5
    |
-LL | fn two<T: Debug + Foo, U: Debug>(t: T, u: U) -> Two<T, U> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     (t, u, T::BAR)
+   |     ^^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `A: Foo` is not satisfied
   --> $DIR/generic_duplicate_param_use9.rs:7:18
diff --git a/src/test/ui/type-alias-impl-trait/generic_nondefining_use.rs b/src/test/ui/type-alias-impl-trait/generic_nondefining_use.rs
index cf43085877f..f39741a6a62 100644
--- a/src/test/ui/type-alias-impl-trait/generic_nondefining_use.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_nondefining_use.rs
@@ -5,25 +5,25 @@ use std::fmt::Debug;
 fn main() {}
 
 type OneTy<T> = impl Debug;
-//~^ ERROR could not find defining uses
+
 type OneLifetime<'a> = impl Debug;
-//~^ ERROR could not find defining uses
+
 type OneConst<const X: usize> = impl Debug;
-//~^ ERROR could not find defining uses
+
 
 // Not defining uses, because they doesn't define *all* possible generics.
 
 fn concrete_ty() -> OneTy<u32> {
-    //~^ ERROR non-defining opaque type use in defining scope
     5u32
+    //~^ ERROR non-defining opaque type use in defining scope
 }
 
 fn concrete_lifetime() -> OneLifetime<'static> {
-    //~^ ERROR non-defining opaque type use in defining scope
     6u32
+    //~^ ERROR non-defining opaque type use in defining scope
 }
 
 fn concrete_const() -> OneConst<{ 123 }> {
-    //~^ ERROR non-defining opaque type use in defining scope
     7u32
+    //~^ ERROR non-defining opaque type use in defining scope
 }
diff --git a/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr b/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr
index 3aa42a25484..36694900c17 100644
--- a/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr
@@ -1,8 +1,8 @@
 error: non-defining opaque type use in defining scope
-  --> $DIR/generic_nondefining_use.rs:16:21
+  --> $DIR/generic_nondefining_use.rs:17:5
    |
-LL | fn concrete_ty() -> OneTy<u32> {
-   |                     ^^^^^^^^^^
+LL |     5u32
+   |     ^^^^
    |
 note: used non-generic type `u32` for generic parameter
   --> $DIR/generic_nondefining_use.rs:7:12
@@ -10,32 +10,20 @@ note: used non-generic type `u32` for generic parameter
 LL | type OneTy<T> = impl Debug;
    |            ^
 
-error: could not find defining uses
-  --> $DIR/generic_nondefining_use.rs:7:17
-   |
-LL | type OneTy<T> = impl Debug;
-   |                 ^^^^^^^^^^
-
 error: non-defining opaque type use in defining scope
-  --> $DIR/generic_nondefining_use.rs:21:27
+  --> $DIR/generic_nondefining_use.rs:22:5
    |
 LL | type OneLifetime<'a> = impl Debug;
    |                  -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
 ...
-LL | fn concrete_lifetime() -> OneLifetime<'static> {
-   |                           ^^^^^^^^^^^^^^^^^^^^
-
-error: could not find defining uses
-  --> $DIR/generic_nondefining_use.rs:9:24
-   |
-LL | type OneLifetime<'a> = impl Debug;
-   |                        ^^^^^^^^^^
+LL |     6u32
+   |     ^^^^
 
 error: non-defining opaque type use in defining scope
-  --> $DIR/generic_nondefining_use.rs:26:24
+  --> $DIR/generic_nondefining_use.rs:27:5
    |
-LL | fn concrete_const() -> OneConst<{ 123 }> {
-   |                        ^^^^^^^^^^^^^^^^^
+LL |     7u32
+   |     ^^^^
    |
 note: used non-generic constant `123_usize` for generic parameter
   --> $DIR/generic_nondefining_use.rs:11:21
@@ -43,11 +31,5 @@ note: used non-generic constant `123_usize` for generic parameter
 LL | type OneConst<const X: usize> = impl Debug;
    |                     ^
 
-error: could not find defining uses
-  --> $DIR/generic_nondefining_use.rs:11:33
-   |
-LL | type OneConst<const X: usize> = impl Debug;
-   |                                 ^^^^^^^^^^
-
-error: aborting due to 6 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/type-alias-impl-trait/generic_not_used.rs b/src/test/ui/type-alias-impl-trait/generic_not_used.rs
index dd6300a64f4..c70f473cff5 100644
--- a/src/test/ui/type-alias-impl-trait/generic_not_used.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_not_used.rs
@@ -6,6 +6,6 @@ type WrongGeneric<T: 'static> = impl 'static;
 //~^ ERROR: at least one trait must be specified
 
 fn wrong_generic<U: 'static, V: 'static>(_: U, v: V) -> WrongGeneric<U> {
-    //~^ ERROR type parameter `V` is part of concrete type but not used in parameter list
     v
+    //~^ ERROR type parameter `V` is part of concrete type but not used in parameter list
 }
diff --git a/src/test/ui/type-alias-impl-trait/generic_not_used.stderr b/src/test/ui/type-alias-impl-trait/generic_not_used.stderr
index 8015ff7eded..fd720239a52 100644
--- a/src/test/ui/type-alias-impl-trait/generic_not_used.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_not_used.stderr
@@ -5,14 +5,10 @@ LL | type WrongGeneric<T: 'static> = impl 'static;
    |                                 ^^^^^^^^^^^^
 
 error: type parameter `V` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-  --> $DIR/generic_not_used.rs:8:73
+  --> $DIR/generic_not_used.rs:9:5
    |
-LL |   fn wrong_generic<U: 'static, V: 'static>(_: U, v: V) -> WrongGeneric<U> {
-   |  _________________________________________________________________________^
-LL | |
-LL | |     v
-LL | | }
-   | |_^
+LL |     v
+   |     ^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr
index f4e1de8e50f..dc85db66d32 100644
--- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr
@@ -1,41 +1,29 @@
 error: at least one trait must be specified
-  --> $DIR/generic_type_does_not_live_long_enough.rs:9:24
+  --> $DIR/generic_type_does_not_live_long_enough.rs:10:24
    |
 LL | type WrongGeneric<T> = impl 'static;
    |                        ^^^^^^^^^^^^
 
-error[E0308]: mismatched types
+error: non-defining opaque type use in defining scope
   --> $DIR/generic_type_does_not_live_long_enough.rs:6:18
    |
 LL |     let z: i32 = x;
-   |            ---   ^ expected `i32`, found opaque type
-   |            |
-   |            expected due to this
-...
-LL | type WrongGeneric<T> = impl 'static;
-   |                        ------------ the found opaque type
-   |
-   = note:     expected type `i32`
-           found opaque type `impl Sized`
-
-error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/generic_type_does_not_live_long_enough.rs:12:30
+   |                  ^
    |
-LL | fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
-   |                              ^^^^^^^^^^^^^^^
+note: used non-generic type `&'static i32` for generic parameter
+  --> $DIR/generic_type_does_not_live_long_enough.rs:10:19
    |
-   = help: consider adding an explicit lifetime bound `T: 'static`...
+LL | type WrongGeneric<T> = impl 'static;
+   |                   ^
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/generic_type_does_not_live_long_enough.rs:9:24
+  --> $DIR/generic_type_does_not_live_long_enough.rs:14:5
    |
-LL | type WrongGeneric<T> = impl 'static;
-   |                        ^^^^^^^^^^^^
+LL |     t
+   |     ^
    |
    = help: consider adding an explicit lifetime bound `T: 'static`...
-   = note: ...so that the type `T` will meet its required lifetime bounds
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0308, E0310.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0310`.
diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs
index 78d25e30e03..cb90776472b 100644
--- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs
@@ -3,13 +3,14 @@
 fn main() {
     let y = 42;
     let x = wrong_generic(&y);
-    let z: i32 = x; //~ ERROR mismatched types
+    let z: i32 = x;
+    //~^ ERROR non-defining opaque type use
 }
 
 type WrongGeneric<T> = impl 'static;
 //~^ ERROR: at least one trait must be specified
 
 fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
-    //~^ ERROR the parameter type `T` may not live long enough
     t
+    //~^ ERROR the parameter type `T` may not live long enough
 }
diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr
index 568784372e5..15ec2eed3da 100644
--- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr
@@ -1,32 +1,29 @@
 error: at least one trait must be specified
-  --> $DIR/generic_type_does_not_live_long_enough.rs:9:24
+  --> $DIR/generic_type_does_not_live_long_enough.rs:10:24
    |
 LL | type WrongGeneric<T> = impl 'static;
    |                        ^^^^^^^^^^^^
 
-error[E0308]: mismatched types
+error: non-defining opaque type use in defining scope
   --> $DIR/generic_type_does_not_live_long_enough.rs:6:18
    |
 LL |     let z: i32 = x;
-   |            ---   ^ expected `i32`, found opaque type
-   |            |
-   |            expected due to this
-...
-LL | type WrongGeneric<T> = impl 'static;
-   |                        ------------ the found opaque type
+   |                  ^
+   |
+note: used non-generic type `&'static i32` for generic parameter
+  --> $DIR/generic_type_does_not_live_long_enough.rs:10:19
    |
-   = note:     expected type `i32`
-           found opaque type `impl Sized`
+LL | type WrongGeneric<T> = impl 'static;
+   |                   ^
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/generic_type_does_not_live_long_enough.rs:12:30
+  --> $DIR/generic_type_does_not_live_long_enough.rs:14:5
    |
 LL | fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
-   |                  -           ^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
-   |                  |
-   |                  help: consider adding an explicit lifetime bound...: `T: 'static`
+   |                  - help: consider adding an explicit lifetime bound...: `T: 'static`
+LL |     t
+   |     ^ ...so that the type `T` will meet its required lifetime bounds
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0308, E0310.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0310`.
diff --git a/src/test/ui/type-alias-impl-trait/inference-cycle.rs b/src/test/ui/type-alias-impl-trait/inference-cycle.rs
index c781e200bf8..608572978a3 100644
--- a/src/test/ui/type-alias-impl-trait/inference-cycle.rs
+++ b/src/test/ui/type-alias-impl-trait/inference-cycle.rs
@@ -3,7 +3,8 @@
 
 mod m {
     type Foo = impl std::fmt::Debug;
-    //~^ ERROR: cycle detected when computing type of `m::Foo::{opaque#0}` [E0391]
+    //~^ ERROR cycle detected
+    //~| ERROR cycle detected
 
     // Cycle: error today, but it'd be nice if it eventually worked
 
@@ -17,7 +18,6 @@ mod m {
 
     fn baz() {
         let f: Foo = 22_u32;
-        //~^ ERROR: mismatched types [E0308]
     }
 
     fn is_send<T: Send>(_: T) {}
diff --git a/src/test/ui/type-alias-impl-trait/inference-cycle.stderr b/src/test/ui/type-alias-impl-trait/inference-cycle.stderr
index e1212466477..3ed86fae8a1 100644
--- a/src/test/ui/type-alias-impl-trait/inference-cycle.stderr
+++ b/src/test/ui/type-alias-impl-trait/inference-cycle.stderr
@@ -5,11 +5,10 @@ LL |     type Foo = impl std::fmt::Debug;
    |                ^^^^^^^^^^^^^^^^^^^^
    |
 note: ...which requires type-checking `m::bar`...
-  --> $DIR/inference-cycle.rs:15:9
+  --> $DIR/inference-cycle.rs:15:5
    |
-LL |         is_send(foo()); // Today: error
-   |         ^^^^^^^
-   = note: ...which requires evaluating trait selection obligation `impl core::fmt::Debug: core::marker::Send`...
+LL |     pub fn bar() {
+   |     ^^^^^^^^^^^^
    = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle
 note: cycle used when checking item types in module `m`
   --> $DIR/inference-cycle.rs:4:1
@@ -17,21 +16,24 @@ note: cycle used when checking item types in module `m`
 LL | mod m {
    | ^^^^^
 
-error[E0308]: mismatched types
-  --> $DIR/inference-cycle.rs:19:22
+error[E0391]: cycle detected when computing type of `m::Foo::{opaque#0}`
+  --> $DIR/inference-cycle.rs:5:16
    |
 LL |     type Foo = impl std::fmt::Debug;
-   |                -------------------- the expected opaque type
-...
-LL |         let f: Foo = 22_u32;
-   |                ---   ^^^^^^ expected opaque type, found `u32`
-   |                |
-   |                expected due to this
-   |
-   = note: expected opaque type `impl Debug`
-                     found type `u32`
+   |                ^^^^^^^^^^^^^^^^^^^^
+   |
+note: ...which requires type-checking `m::bar`...
+  --> $DIR/inference-cycle.rs:15:5
+   |
+LL |     pub fn bar() {
+   |     ^^^^^^^^^^^^
+   = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle
+note: cycle used when checking item types in module `m`
+  --> $DIR/inference-cycle.rs:4:1
+   |
+LL | mod m {
+   | ^^^^^
 
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0308, E0391.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr b/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr
index d82050e263e..4c5fd22556a 100644
--- a/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr
@@ -1,14 +1,14 @@
 error: concrete type differs from previous defining opaque type use
-  --> $DIR/issue-52843-closure-constrain.rs:10:16
+  --> $DIR/issue-52843-closure-constrain.rs:10:31
    |
 LL |     let null = || -> Opaque { 0 };
-   |                ^^^^^^^^^^^^^^^^^^ expected `String`, got `i32`
+   |                               ^ expected `String`, got `i32`
    |
 note: previous use here
-  --> $DIR/issue-52843-closure-constrain.rs:9:5
+  --> $DIR/issue-52843-closure-constrain.rs:9:30
    |
 LL |     fn _unused() -> Opaque { String::new() }
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |                              ^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-53598.rs b/src/test/ui/type-alias-impl-trait/issue-53598.rs
index f936dc42f13..9c1cbf926f5 100644
--- a/src/test/ui/type-alias-impl-trait/issue-53598.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-53598.rs
@@ -17,8 +17,8 @@ impl Foo for S2 {
     type Item = impl Debug;
 
     fn foo<T: Debug>(_: T) -> Self::Item {
-        //~^ Error type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
         S::<T>(Default::default())
+        //~^ Error type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
     }
 }
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-53598.stderr b/src/test/ui/type-alias-impl-trait/issue-53598.stderr
index 9971c7e0e20..f8b8201e2eb 100644
--- a/src/test/ui/type-alias-impl-trait/issue-53598.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-53598.stderr
@@ -1,12 +1,8 @@
 error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-  --> $DIR/issue-53598.rs:19:42
+  --> $DIR/issue-53598.rs:20:9
    |
-LL |       fn foo<T: Debug>(_: T) -> Self::Item {
-   |  __________________________________________^
-LL | |
-LL | |         S::<T>(Default::default())
-LL | |     }
-   | |_____^
+LL |         S::<T>(Default::default())
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr
index a4ccae4eb7e..91daa65d656 100644
--- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr
@@ -1,38 +1,26 @@
-error: higher-ranked subtype error
-  --> $DIR/issue-57611-trait-alias.rs:21:9
-   |
-LL |         |x| x
-   |         ^^^^^
-
-error: higher-ranked subtype error
-  --> $DIR/issue-57611-trait-alias.rs:21:9
-   |
-LL |         |x| x
-   |         ^^^^^
-
 error[E0308]: mismatched types
-  --> $DIR/issue-57611-trait-alias.rs:17:16
+  --> $DIR/issue-57611-trait-alias.rs:20:9
    |
-LL |     type Bar = impl Baz<Self, Self>;
-   |                ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+LL |         |x| x
+   |         ^^^^^ one type is more general than the other
    |
    = note: expected type `for<'r> Fn<(&'r X,)>`
-              found type `Fn<(&'static X,)>`
+              found type `Fn<(&X,)>`
 note: this closure does not fulfill the lifetime requirements
-  --> $DIR/issue-57611-trait-alias.rs:21:9
+  --> $DIR/issue-57611-trait-alias.rs:20:9
    |
 LL |         |x| x
    |         ^^^^^
 
 error: implementation of `FnOnce` is not general enough
-  --> $DIR/issue-57611-trait-alias.rs:17:16
+  --> $DIR/issue-57611-trait-alias.rs:20:9
    |
-LL |     type Bar = impl Baz<Self, Self>;
-   |                ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+LL |         |x| x
+   |         ^^^^^ implementation of `FnOnce` is not general enough
    |
-   = note: closure with signature `fn(&'static X) -> &'static X` must implement `FnOnce<(&'0 X,)>`, for any lifetime `'0`...
-   = note: ...but it actually implements `FnOnce<(&'static X,)>`
+   = note: closure with signature `fn(&'2 X) -> &X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2`
 
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs
index 625e46b6bc0..7c6e7642484 100644
--- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs
@@ -17,8 +17,8 @@ impl Foo for X {
     type Bar = impl Baz<Self, Self>;
 
     fn bar(&self) -> Self::Bar {
-        //~^ ERROR implementation of `FnOnce` is not general enough
         |x| x
+        //~^ ERROR implementation of `FnOnce` is not general enough
     }
 }
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
index 54d237159d8..45329ea292d 100644
--- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
@@ -1,8 +1,8 @@
 error: implementation of `FnOnce` is not general enough
-  --> $DIR/issue-57611-trait-alias.rs:19:22
+  --> $DIR/issue-57611-trait-alias.rs:20:9
    |
-LL |     fn bar(&self) -> Self::Bar {
-   |                      ^^^^^^^^^ implementation of `FnOnce` is not general enough
+LL |         |x| x
+   |         ^^^^^ implementation of `FnOnce` is not general enough
    |
    = note: closure with signature `fn(&'2 X) -> &X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`...
    = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2`
diff --git a/src/test/ui/type-alias-impl-trait/issue-57700.rs b/src/test/ui/type-alias-impl-trait/issue-57700.rs
index 13a6b7c2f7c..48458938702 100644
--- a/src/test/ui/type-alias-impl-trait/issue-57700.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-57700.rs
@@ -13,8 +13,8 @@ impl<C> Foo for C {
     type Bar = impl Foo;
 
     fn foo(self: impl Deref<Target = Self>) -> Self::Bar {
-        //~^ Error type parameter `impl Deref<Target = Self>` is part of concrete type but not used in parameter list for the `impl Trait` type alias
         self
+        //~^ Error type parameter `impl Deref<Target = Self>` is part of concrete type but not used in parameter list for the `impl Trait` type alias
     }
 }
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-57700.stderr b/src/test/ui/type-alias-impl-trait/issue-57700.stderr
index b2e3f46f1f5..31b6df5d4c3 100644
--- a/src/test/ui/type-alias-impl-trait/issue-57700.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-57700.stderr
@@ -1,12 +1,8 @@
 error: type parameter `impl Deref<Target = Self>` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-  --> $DIR/issue-57700.rs:15:58
+  --> $DIR/issue-57700.rs:16:9
    |
-LL |       fn foo(self: impl Deref<Target = Self>) -> Self::Bar {
-   |  __________________________________________________________^
-LL | |
-LL | |         self
-LL | |     }
-   | |_____^
+LL |         self
+   |         ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-58951-2.rs b/src/test/ui/type-alias-impl-trait/issue-58951-2.rs
new file mode 100644
index 00000000000..e4ba7f8e2a6
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-58951-2.rs
@@ -0,0 +1,18 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+
+mod defining_use_scope {
+    pub type A = impl Iterator;
+
+    pub fn def_a() -> A {
+        0..1
+    }
+}
+use defining_use_scope::*;
+
+pub fn use_a() {
+    def_a().map(|x| x);
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/issue-60371.rs b/src/test/ui/type-alias-impl-trait/issue-60371.rs
index badf35484f3..9a40f3d9b64 100644
--- a/src/test/ui/type-alias-impl-trait/issue-60371.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-60371.rs
@@ -9,7 +9,6 @@ impl Bug for &() {
 
     const FUN: fn() -> Self::Item = || ();
     //~^ ERROR the trait bound `(): Bug` is not satisfied
-    //~| ERROR non-defining opaque type use in defining scope
 }
 
 fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/issue-60371.stderr b/src/test/ui/type-alias-impl-trait/issue-60371.stderr
index dc8a381aece..5fec078956b 100644
--- a/src/test/ui/type-alias-impl-trait/issue-60371.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-60371.stderr
@@ -11,21 +11,12 @@ error[E0277]: the trait bound `(): Bug` is not satisfied
   --> $DIR/issue-60371.rs:10:40
    |
 LL |     const FUN: fn() -> Self::Item = || ();
-   |                                        ^ the trait `Bug` is not implemented for `()`
+   |                                        ^^ the trait `Bug` is not implemented for `()`
    |
    = help: the following implementations were found:
              <&() as Bug>
 
-error: non-defining opaque type use in defining scope
-  --> $DIR/issue-60371.rs:10:37
-   |
-LL | impl Bug for &() {
-   |              - cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
-...
-LL |     const FUN: fn() -> Self::Item = || ();
-   |                                     ^^^^^
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0277, E0658.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-60564.rs b/src/test/ui/type-alias-impl-trait/issue-60564.rs
index 44dcec2c3da..4fc7679311a 100644
--- a/src/test/ui/type-alias-impl-trait/issue-60564.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-60564.rs
@@ -6,7 +6,6 @@ trait IterBits {
 }
 
 type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
-//~^ ERROR could not find defining uses
 
 impl<T: Copy, E> IterBits for T
 where
@@ -18,8 +17,8 @@ where
 {
     type BitsIter = IterBitsIter<T, E, u8>;
     fn iter_bits(self, n: u8) -> Self::BitsIter {
-        //~^ ERROR non-defining opaque type use in defining scope
         (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
+        //~^ ERROR non-defining opaque type use in defining scope
     }
 }
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-60564.stderr b/src/test/ui/type-alias-impl-trait/issue-60564.stderr
index 6b73fbef011..bbc93657be3 100644
--- a/src/test/ui/type-alias-impl-trait/issue-60564.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-60564.stderr
@@ -1,8 +1,8 @@
 error: non-defining opaque type use in defining scope
-  --> $DIR/issue-60564.rs:20:34
+  --> $DIR/issue-60564.rs:20:9
    |
-LL |     fn iter_bits(self, n: u8) -> Self::BitsIter {
-   |                                  ^^^^^^^^^^^^^^
+LL |         (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: used non-generic type `u8` for generic parameter
   --> $DIR/issue-60564.rs:8:25
@@ -10,11 +10,5 @@ note: used non-generic type `u8` for generic parameter
 LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
    |                         ^
 
-error: could not find defining uses
-  --> $DIR/issue-60564.rs:8:30
-   |
-LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-63279.rs b/src/test/ui/type-alias-impl-trait/issue-63279.rs
index 875cce4df23..057a908bbee 100644
--- a/src/test/ui/type-alias-impl-trait/issue-63279.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-63279.rs
@@ -5,7 +5,10 @@
 type Closure = impl FnOnce();
 
 fn c() -> Closure {
-    || -> Closure { || () } //~ ERROR: mismatched types
+    || -> Closure { || () }
+    //~^ ERROR: mismatched types
+    //~| ERROR: mismatched types
+    //~| ERROR: expected a `FnOnce<()>` closure, found `()`
 }
 
 fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/issue-63279.stderr b/src/test/ui/type-alias-impl-trait/issue-63279.stderr
index 5fde8c2ef1e..bcc9c57f91c 100644
--- a/src/test/ui/type-alias-impl-trait/issue-63279.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-63279.stderr
@@ -1,17 +1,36 @@
+error[E0277]: expected a `FnOnce<()>` closure, found `()`
+  --> $DIR/issue-63279.rs:8:11
+   |
+LL |     || -> Closure { || () }
+   |           ^^^^^^^ expected an `FnOnce<()>` closure, found `()`
+   |
+   = help: the trait `FnOnce<()>` is not implemented for `()`
+   = note: wrap the `()` in a closure with no arguments: `|| { /* code */ }`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-63279.rs:8:21
+   |
+LL |     || -> Closure { || () }
+   |                     ^^^^^ expected `()`, found closure
+   |
+   = note: expected unit type `()`
+                found closure `[closure@$DIR/issue-63279.rs:8:21: 8:26]`
+
 error[E0308]: mismatched types
   --> $DIR/issue-63279.rs:8:5
    |
 LL | type Closure = impl FnOnce();
-   |                ------------- the found opaque type
-...
+   |                ------------- the expected opaque type
+LL | 
+LL | fn c() -> Closure {
+   |           ------- expected `Closure` because of return type
 LL |     || -> Closure { || () }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found closure
    |
-   = note: expected type `[closure@$DIR/issue-63279.rs:8:21: 8:26]`
-           found closure `[closure@$DIR/issue-63279.rs:8:5: 8:28]`
-   = note: no two closures, even if identical, have the same type
-   = help: consider boxing your closure and/or using it as a trait object
+   = note: expected opaque type `Closure`
+                  found closure `[closure@$DIR/issue-63279.rs:8:5: 8:28]`
 
-error: aborting due to previous error
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
+Some errors have detailed explanations: E0277, E0308.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-63355.rs b/src/test/ui/type-alias-impl-trait/issue-63355.rs
index 9f617153e3f..7066a0535e1 100644
--- a/src/test/ui/type-alias-impl-trait/issue-63355.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-63355.rs
@@ -1,5 +1,5 @@
 #![feature(type_alias_impl_trait)]
-#![allow(incomplete_features)]
+// check-pass
 
 pub trait Foo {}
 
@@ -27,11 +27,8 @@ impl Bar for () {
     }
 }
 
-// FIXME(#86731): The below is illegal use of `type_alias_impl_trait`
-// but the compiler doesn't report it, we should fix it.
 pub type FooImpl = impl Foo;
 pub type BarImpl = impl Bar<Foo = FooImpl>;
-//~^ ERROR: type mismatch resolving `<() as Bar>::Foo == ()`
 
 impl Baz for () {
     type Foo = FooImpl;
diff --git a/src/test/ui/type-alias-impl-trait/issue-63355.stderr b/src/test/ui/type-alias-impl-trait/issue-63355.stderr
deleted file mode 100644
index 2dbd5a55a62..00000000000
--- a/src/test/ui/type-alias-impl-trait/issue-63355.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0271]: type mismatch resolving `<() as Bar>::Foo == ()`
-  --> $DIR/issue-63355.rs:33:20
-   |
-LL | pub type FooImpl = impl Foo;
-   |                    -------- the found opaque type
-LL | pub type BarImpl = impl Bar<Foo = FooImpl>;
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<() as Bar>::Foo == ()`
-   |
-note: expected this to be `()`
-  --> $DIR/issue-63355.rs:23:16
-   |
-LL |     type Foo = FooImpl;
-   |                ^^^^^^^
-   = note: expected unit type `()`
-            found opaque type `impl Foo`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs
index 2e6354088ac..5223fb1c702 100644
--- a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs
@@ -5,7 +5,7 @@
 #![feature(type_alias_impl_trait)]
 trait Trait<T> {}
 type Alias<'a, U> = impl Trait<U>;
-//~^ ERROR could not find defining uses
+
 fn f<'a>() -> Alias<'a, ()> {}
 //~^ ERROR non-defining opaque type use in defining scope
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr
index 721f99a3f0d..7fb9a0c410e 100644
--- a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr
@@ -1,8 +1,8 @@
 error: non-defining opaque type use in defining scope
-  --> $DIR/issue-68368-non-defining-use-2.rs:9:15
+  --> $DIR/issue-68368-non-defining-use-2.rs:9:29
    |
 LL | fn f<'a>() -> Alias<'a, ()> {}
-   |               ^^^^^^^^^^^^^
+   |                             ^^
    |
 note: used non-generic type `()` for generic parameter
   --> $DIR/issue-68368-non-defining-use-2.rs:7:16
@@ -10,11 +10,5 @@ note: used non-generic type `()` for generic parameter
 LL | type Alias<'a, U> = impl Trait<U>;
    |                ^
 
-error: could not find defining uses
-  --> $DIR/issue-68368-non-defining-use-2.rs:7:21
-   |
-LL | type Alias<'a, U> = impl Trait<U>;
-   |                     ^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs
index 3addd8dcc4f..b50462bf237 100644
--- a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs
@@ -5,7 +5,7 @@
 #![feature(type_alias_impl_trait)]
 trait Trait<T> {}
 type Alias<'a, U> = impl Trait<U>;
-//~^ ERROR could not find defining uses
+
 fn f<'a>() -> Alias<'a, ()> {}
 //~^ ERROR non-defining opaque type use in defining scope
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr
index f5b8fccf65d..8059621b61a 100644
--- a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr
@@ -1,8 +1,8 @@
 error: non-defining opaque type use in defining scope
-  --> $DIR/issue-68368-non-defining-use.rs:9:15
+  --> $DIR/issue-68368-non-defining-use.rs:9:29
    |
 LL | fn f<'a>() -> Alias<'a, ()> {}
-   |               ^^^^^^^^^^^^^
+   |                             ^^
    |
 note: used non-generic type `()` for generic parameter
   --> $DIR/issue-68368-non-defining-use.rs:7:16
@@ -10,11 +10,5 @@ note: used non-generic type `()` for generic parameter
 LL | type Alias<'a, U> = impl Trait<U>;
    |                ^
 
-error: could not find defining uses
-  --> $DIR/issue-68368-non-defining-use.rs:7:21
-   |
-LL | type Alias<'a, U> = impl Trait<U>;
-   |                     ^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-74280.stderr b/src/test/ui/type-alias-impl-trait/issue-74280.stderr
index f6b369dd8d5..7a22b360a31 100644
--- a/src/test/ui/type-alias-impl-trait/issue-74280.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-74280.stderr
@@ -1,8 +1,17 @@
 error[E0308]: mismatched types
   --> $DIR/issue-74280.rs:9:5
    |
+LL | type Test = impl Copy;
+   |             --------- the expected opaque type
+LL | 
+LL | fn test() -> Test {
+   |              ---- expected `Test` because of return type
+LL |     let y = || -> Test { () };
 LL |     7
    |     ^ expected `()`, found integer
+   |
+   = note: expected opaque type `Test`
+                     found type `{integer}`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-77179.stderr b/src/test/ui/type-alias-impl-trait/issue-77179.stderr
index 15205ba9b41..053546e4b92 100644
--- a/src/test/ui/type-alias-impl-trait/issue-77179.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-77179.stderr
@@ -5,7 +5,7 @@ LL | fn test() -> Pointer<_> {
    |              --------^-
    |              |       |
    |              |       not allowed in type signatures
-   |              help: replace with the correct return type: `Box<i32>`
+   |              help: replace with the correct return type: `Pointer<i32>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-93411.rs b/src/test/ui/type-alias-impl-trait/issue-93411.rs
new file mode 100644
index 00000000000..1f8c789267d
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-93411.rs
@@ -0,0 +1,19 @@
+#![feature(type_alias_impl_trait)]
+
+// this test used to stack overflow due to infinite recursion.
+// check-pass
+// compile-flags: --edition=2018
+
+use std::future::Future;
+
+fn main() {
+    let _ = move || async move {
+        let value = 0u8;
+        blah(&value).await;
+    };
+}
+
+type BlahFut<'a> = impl Future<Output = ()> + Send + 'a;
+fn blah<'a>(_value: &'a u8) -> BlahFut<'a> {
+    async {}
+}
diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-infer.rs b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-infer.rs
new file mode 100644
index 00000000000..b887fcf3083
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-infer.rs
@@ -0,0 +1,13 @@
+// https://github.com/rust-lang/rust/issues/73481
+// This test used to cause unsoundness, since one of the two possible
+// resolutions was chosen at random instead of erroring due to conflicts.
+
+#![feature(type_alias_impl_trait)]
+
+type Y<A, B> = impl std::fmt::Debug;
+
+fn g<A, B>() -> (Y<A, B>, Y<B, A>) {
+    (42_i64, 60) //~ ERROR concrete type differs from previous defining opaque type use
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-infer.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-infer.stderr
new file mode 100644
index 00000000000..27811700912
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-infer.stderr
@@ -0,0 +1,11 @@
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/multiple-def-uses-in-one-fn-infer.rs:10:5
+   |
+LL |     (42_i64, 60)
+   |     ^^^^^^^^^^^^
+   |     |
+   |     expected `i64`, got `i32`
+   |     this expression supplies two conflicting concrete types for the same opaque type
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.rs b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.rs
new file mode 100644
index 00000000000..3f122f10609
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.rs
@@ -0,0 +1,9 @@
+#![feature(type_alias_impl_trait)]
+
+type Foo<'a, 'b> = impl std::fmt::Debug;
+
+fn foo<'x, 'y>(i: &'x i32, j: &'y i32) -> (Foo<'x, 'y>, Foo<'y, 'x>) {
+    (i, i) //~ ERROR concrete type differs from previous
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.stderr
new file mode 100644
index 00000000000..81e603e2355
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.stderr
@@ -0,0 +1,11 @@
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5
+   |
+LL |     (i, i)
+   |     ^^^^^^
+   |     |
+   |     expected `&'a i32`, got `&'b i32`
+   |     this expression supplies two conflicting concrete types for the same opaque type
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-pass.rs b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-pass.rs
index f412b2d0e7d..83fd9a1da45 100644
--- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-pass.rs
+++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-pass.rs
@@ -7,6 +7,15 @@ fn f<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<A, B>)
     (a.clone(), a)
 }
 
+type Foo<'a, 'b> = impl std::fmt::Debug;
+
+fn foo<'x, 'y>(i: &'x i32, j: &'y i32) -> (Foo<'x, 'y>, Foo<'y, 'x>) {
+    (i, j)
+}
+
 fn main() {
     println!("{}", <X<_, _> as ToString>::to_string(&f(42_i32, String::new()).1));
+    let meh = 42;
+    let muh = 69;
+    println!("{:?}", foo(&meh, &muh));
 }
diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs
index da845e86147..46bac5a34f5 100644
--- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs
+++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs
@@ -7,8 +7,8 @@
 type X<A, B> = impl Into<&'static A>;
 
 fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) {
-    //~^ ERROR the trait bound `&'static B: From<&A>` is not satisfied
     (a, a)
+    //~^ ERROR the trait bound `&'static B: From<&A>` is not satisfied
 }
 
 fn main() {
diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr
index 4df2f52a9e4..f4d8b4509d4 100644
--- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr
+++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `&'static B: From<&A>` is not satisfied
-  --> $DIR/multiple-def-uses-in-one-fn.rs:9:45
+  --> $DIR/multiple-def-uses-in-one-fn.rs:10:9
    |
-LL | fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) {
-   |                                             ^^^^^^^^^^^^^^^^^^ the trait `From<&A>` is not implemented for `&'static B`
+LL |     (a, a)
+   |         ^ the trait `From<&A>` is not implemented for `&'static B`
    |
    = note: required because of the requirements on the impl of `Into<&'static B>` for `&A`
 help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.rs b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.rs
index 06e1990fd7f..14510a5294e 100644
--- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.rs
+++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.rs
@@ -7,8 +7,8 @@
 type X<A: ToString + Clone, B: ToString + Clone> = impl ToString;
 
 fn f<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<B, A>) {
-    //~^ ERROR concrete type differs from previous defining opaque type
     (a.clone(), a)
+    //~^ ERROR concrete type differs from previous defining opaque type
 }
 
 fn main() {
diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.stderr
index 52b0462de98..0f752212ac9 100644
--- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.stderr
+++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.stderr
@@ -1,14 +1,11 @@
 error: concrete type differs from previous defining opaque type use
-  --> $DIR/multiple-def-uses-in-one-fn2.rs:9:1
+  --> $DIR/multiple-def-uses-in-one-fn2.rs:10:5
    |
-LL | fn f<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<B, A>) {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `A`, got `B`
-   |
-note: previous use here
-  --> $DIR/multiple-def-uses-in-one-fn2.rs:9:1
-   |
-LL | fn f<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<B, A>) {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     (a.clone(), a)
+   |     ^^^^^^^^^^^^^^
+   |     |
+   |     expected `A`, got `B`
+   |     this expression supplies two conflicting concrete types for the same opaque type
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr
index bbe709dccab..db4b60461ef 100644
--- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr
+++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr
@@ -1,6 +1,9 @@
 error[E0308]: mismatched types
   --> $DIR/multiple-def-uses-in-one-fn3.rs:14:9
    |
+LL | type X<A: ToString + Clone, B: ToString + Clone> = impl ToString;
+   |                                                    ------------- the expected opaque type
+...
 LL | fn g<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<A, B>) {
    |      -                    - found type parameter
    |      |
@@ -8,8 +11,8 @@ LL | fn g<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<A
 LL |     (a, b)
    |         ^ expected type parameter `A`, found type parameter `B`
    |
-   = note: expected type parameter `A`
-              found type parameter `B`
+   = note: expected opaque type `X<A, B>`
+           found type parameter `B`
    = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
    = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
diff --git a/src/test/ui/type-alias-impl-trait/nested-tait-inference.rs b/src/test/ui/type-alias-impl-trait/nested-tait-inference.rs
index efb88dabf34..314e5362a8f 100644
--- a/src/test/ui/type-alias-impl-trait/nested-tait-inference.rs
+++ b/src/test/ui/type-alias-impl-trait/nested-tait-inference.rs
@@ -1,5 +1,3 @@
-// check-pass
-
 #![feature(type_alias_impl_trait)]
 #![allow(dead_code)]
 
@@ -12,6 +10,9 @@ trait Foo<A> { }
 impl Foo<()> for () { }
 
 fn foo() -> impl Foo<FooX> {
+    //~^ ERROR: the trait bound `(): Foo<FooX>` is not satisfied
+    //~| ERROR: the trait bound `(): Foo<FooX>` is not satisfied
+    // FIXME(type-alias-impl-trait): We could probably make this work.
     ()
 }
 
diff --git a/src/test/ui/type-alias-impl-trait/nested-tait-inference.stderr b/src/test/ui/type-alias-impl-trait/nested-tait-inference.stderr
new file mode 100644
index 00000000000..eb72e887691
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/nested-tait-inference.stderr
@@ -0,0 +1,27 @@
+error[E0277]: the trait bound `(): Foo<FooX>` is not satisfied
+  --> $DIR/nested-tait-inference.rs:12:13
+   |
+LL | fn foo() -> impl Foo<FooX> {
+   |             ^^^^^^^^^^^^^^ the trait `Foo<FooX>` is not implemented for `()`
+   |
+   = help: the following implementations were found:
+             <() as Foo<()>>
+
+error[E0277]: the trait bound `(): Foo<FooX>` is not satisfied
+  --> $DIR/nested-tait-inference.rs:12:28
+   |
+LL |   fn foo() -> impl Foo<FooX> {
+   |  ____________________________^
+LL | |
+LL | |
+LL | |     // FIXME(type-alias-impl-trait): We could probably make this work.
+LL | |     ()
+LL | | }
+   | |_^ the trait `Foo<FooX>` is not implemented for `()`
+   |
+   = help: the following implementations were found:
+             <() as Foo<()>>
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/nested-tait-inference2.rs b/src/test/ui/type-alias-impl-trait/nested-tait-inference2.rs
index 9b26a652978..4dc30d9257b 100644
--- a/src/test/ui/type-alias-impl-trait/nested-tait-inference2.rs
+++ b/src/test/ui/type-alias-impl-trait/nested-tait-inference2.rs
@@ -4,7 +4,6 @@
 use std::fmt::Debug;
 
 type FooX = impl Debug;
-//~^ ERROR: could not find defining uses
 
 trait Foo<A> {}
 
@@ -12,7 +11,8 @@ impl Foo<()> for () {}
 impl Foo<u32> for () {}
 
 fn foo() -> impl Foo<FooX> {
-    //~^ ERROR: the trait bound `(): Foo<impl Debug>` is not satisfied [E0277]
+    //~^ ERROR: the trait bound `(): Foo<FooX>` is not satisfied
+    //~| ERROR: the trait bound `(): Foo<FooX>` is not satisfied
     ()
 }
 
diff --git a/src/test/ui/type-alias-impl-trait/nested-tait-inference2.stderr b/src/test/ui/type-alias-impl-trait/nested-tait-inference2.stderr
index 7e24ee644b1..1372a018667 100644
--- a/src/test/ui/type-alias-impl-trait/nested-tait-inference2.stderr
+++ b/src/test/ui/type-alias-impl-trait/nested-tait-inference2.stderr
@@ -1,18 +1,27 @@
-error[E0277]: the trait bound `(): Foo<impl Debug>` is not satisfied
-  --> $DIR/nested-tait-inference2.rs:14:13
+error[E0277]: the trait bound `(): Foo<FooX>` is not satisfied
+  --> $DIR/nested-tait-inference2.rs:13:13
    |
 LL | fn foo() -> impl Foo<FooX> {
-   |             ^^^^^^^^^^^^^^ the trait `Foo<impl Debug>` is not implemented for `()`
+   |             ^^^^^^^^^^^^^^ the trait `Foo<FooX>` is not implemented for `()`
    |
    = help: the following implementations were found:
              <() as Foo<()>>
              <() as Foo<u32>>
 
-error: could not find defining uses
-  --> $DIR/nested-tait-inference2.rs:6:13
+error[E0277]: the trait bound `(): Foo<FooX>` is not satisfied
+  --> $DIR/nested-tait-inference2.rs:13:28
    |
-LL | type FooX = impl Debug;
-   |             ^^^^^^^^^^
+LL |   fn foo() -> impl Foo<FooX> {
+   |  ____________________________^
+LL | |
+LL | |
+LL | |     ()
+LL | | }
+   | |_^ the trait `Foo<FooX>` is not implemented for `()`
+   |
+   = help: the following implementations were found:
+             <() as Foo<()>>
+             <() as Foo<u32>>
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs
new file mode 100644
index 00000000000..fbab5470b4f
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs
@@ -0,0 +1,17 @@
+#![feature(type_alias_impl_trait)]
+#![allow(dead_code)]
+
+use std::fmt::Debug;
+
+type FooX = impl Debug;
+//~^ unconstrained opaque type
+
+trait Foo<A> { }
+
+impl Foo<FooX> for () { }
+
+fn foo() -> impl Foo<FooX> {
+    ()
+}
+
+fn main() { }
diff --git a/src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr
new file mode 100644
index 00000000000..b1d947a9ccf
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr
@@ -0,0 +1,10 @@
+error: unconstrained opaque type
+  --> $DIR/nested-tait-inference3.rs:6:13
+   |
+LL | type FooX = impl Debug;
+   |             ^^^^^^^^^^
+   |
+   = note: `FooX` must be used in combination with a concrete type within the same module
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/type-alias-impl-trait/nested.rs b/src/test/ui/type-alias-impl-trait/nested.rs
new file mode 100644
index 00000000000..6b866be7d17
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/nested.rs
@@ -0,0 +1,17 @@
+#![feature(type_alias_impl_trait)]
+
+type Foo = impl std::fmt::Debug;
+type Bar = impl Trait<Foo>;
+
+trait Trait<T> {}
+
+impl<T, U> Trait<T> for U {}
+
+fn bar() -> Bar {
+    42
+}
+
+fn main() {
+    println!("{:?}", bar());
+    //~^ ERROR `Bar` doesn't implement `Debug`
+}
diff --git a/src/test/ui/type-alias-impl-trait/nested.stderr b/src/test/ui/type-alias-impl-trait/nested.stderr
new file mode 100644
index 00000000000..cf4d23656e0
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/nested.stderr
@@ -0,0 +1,12 @@
+error[E0277]: `Bar` doesn't implement `Debug`
+  --> $DIR/nested.rs:15:22
+   |
+LL |     println!("{:?}", bar());
+   |                      ^^^^^ `Bar` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+   |
+   = help: the trait `Debug` is not implemented for `Bar`
+   = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/nested_type_alias_impl_trait.rs b/src/test/ui/type-alias-impl-trait/nested_type_alias_impl_trait.rs
index 6282264d8fe..60b6e1aac62 100644
--- a/src/test/ui/type-alias-impl-trait/nested_type_alias_impl_trait.rs
+++ b/src/test/ui/type-alias-impl-trait/nested_type_alias_impl_trait.rs
@@ -1,5 +1,5 @@
 #![feature(type_alias_impl_trait)]
-// build-pass (FIXME(62277): could be check-pass?)
+
 mod my_mod {
     use std::fmt::Debug;
 
@@ -11,7 +11,7 @@ mod my_mod {
     }
 
     pub fn get_foot() -> Foot {
-        get_foo()
+        get_foo() //~ ERROR opaque type's hidden type cannot be another opaque type
     }
 }
 
diff --git a/src/test/ui/type-alias-impl-trait/nested_type_alias_impl_trait.stderr b/src/test/ui/type-alias-impl-trait/nested_type_alias_impl_trait.stderr
new file mode 100644
index 00000000000..fa6ecf68d28
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/nested_type_alias_impl_trait.stderr
@@ -0,0 +1,19 @@
+error: opaque type's hidden type cannot be another opaque type from the same scope
+  --> $DIR/nested_type_alias_impl_trait.rs:14:9
+   |
+LL |         get_foo()
+   |         ^^^^^^^^^ one of the two opaque types used here has to be outside its defining scope
+   |
+note: opaque type whose hidden type is being assigned
+  --> $DIR/nested_type_alias_impl_trait.rs:7:21
+   |
+LL |     pub type Foot = impl Debug;
+   |                     ^^^^^^^^^^
+note: opaque type being used as hidden type
+  --> $DIR/nested_type_alias_impl_trait.rs:6:20
+   |
+LL |     pub type Foo = impl Debug;
+   |                    ^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.rs b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.rs
index 8787c023eb0..fed5ac07c90 100644
--- a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.rs
+++ b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.rs
@@ -1,8 +1,7 @@
 #![feature(type_alias_impl_trait)]
-
+// check-pass
 fn main() {}
 
-// don't reveal the concrete type
 type NoReveal = impl std::fmt::Debug;
 
 fn define_no_reveal() -> NoReveal {
@@ -10,6 +9,6 @@ fn define_no_reveal() -> NoReveal {
 }
 
 fn no_reveal(x: NoReveal) {
-    let _: &'static str = x; //~ mismatched types
-    let _ = x as &'static str; //~ non-primitive cast
+    let _: &'static str = x;
+    let _ = x as &'static str;
 }
diff --git a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr
deleted file mode 100644
index b438f844516..00000000000
--- a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr
+++ /dev/null
@@ -1,24 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/never_reveal_concrete_type.rs:13:27
-   |
-LL | type NoReveal = impl std::fmt::Debug;
-   |                 -------------------- the found opaque type
-...
-LL |     let _: &'static str = x;
-   |            ------------   ^ expected `&str`, found opaque type
-   |            |
-   |            expected due to this
-   |
-   = note: expected reference `&'static str`
-            found opaque type `impl Debug`
-
-error[E0605]: non-primitive cast: `impl Debug` as `&'static str`
-  --> $DIR/never_reveal_concrete_type.rs:14:13
-   |
-LL |     let _ = x as &'static str;
-   |             ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0308, E0605.
-For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/type-alias-impl-trait/no_inferrable_concrete_type.rs b/src/test/ui/type-alias-impl-trait/no_inferrable_concrete_type.rs
index 1197c7bc58e..fa578eced5f 100644
--- a/src/test/ui/type-alias-impl-trait/no_inferrable_concrete_type.rs
+++ b/src/test/ui/type-alias-impl-trait/no_inferrable_concrete_type.rs
@@ -1,9 +1,9 @@
 // Issue 52985: user code provides no use case that allows a type alias `impl Trait`
-// We now emit a 'could not find defining uses' error
+// We now emit a 'unconstrained opaque type' error
 
 #![feature(type_alias_impl_trait)]
 
-type Foo = impl Copy; //~ could not find defining uses
+type Foo = impl Copy; //~ unconstrained opaque type
 
 // make compiler happy about using 'Foo'
 fn bar(x: Foo) -> Foo {
diff --git a/src/test/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr b/src/test/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr
index 61025e84692..009935347e6 100644
--- a/src/test/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr
+++ b/src/test/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr
@@ -1,8 +1,10 @@
-error: could not find defining uses
+error: unconstrained opaque type
   --> $DIR/no_inferrable_concrete_type.rs:6:12
    |
 LL | type Foo = impl Copy;
    |            ^^^^^^^^^
+   |
+   = note: `Foo` must be used in combination with a concrete type within the same module
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr b/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr
index 67752acb8c9..ae03a5b3e37 100644
--- a/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr
+++ b/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr
@@ -10,7 +10,7 @@ LL |     let _: &str = bomp();
    |            expected due to this
    |
    = note: expected reference `&str`
-            found opaque type `impl Debug`
+            found opaque type `Boo`
 
 error[E0308]: mismatched types
   --> $DIR/no_revealing_outside_defining_module.rs:19:5
@@ -19,11 +19,11 @@ LL |     pub type Boo = impl ::std::fmt::Debug;
    |                    ---------------------- the expected opaque type
 ...
 LL | fn bomp() -> boo::Boo {
-   |              -------- expected `impl Debug` because of return type
+   |              -------- expected `Boo` because of return type
 LL |     ""
    |     ^^ expected opaque type, found `&str`
    |
-   = note: expected opaque type `impl Debug`
+   = note: expected opaque type `Boo`
                 found reference `&'static str`
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs b/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs
index 107cd394579..289784ce747 100644
--- a/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs
+++ b/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs
@@ -7,11 +7,6 @@ fn main() {}
 type Two<T, U> = impl Debug;
 //~^ ERROR `T` doesn't implement `Debug`
 
-fn two<T: Debug>(t: T) -> Two<T, u32> {
-    //~^ ERROR non-defining opaque type use in defining scope
-    (t, 4i8)
-}
-
 fn three<T: Debug, U>(t: T) -> Two<T, U> {
     (t, 5i8)
 }
@@ -27,8 +22,8 @@ impl Bar for u32 {
 }
 
 fn four<T: Debug, U: Bar>(t: T) -> Two<T, U> {
-    //~^ ERROR concrete type differs from previous
     (t, <U as Bar>::FOO)
+    //~^ ERROR concrete type differs from previous
 }
 
 fn is_sync<T: Sync>() {}
diff --git a/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr b/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr
index 08e49845521..6068cfeb51e 100644
--- a/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr
+++ b/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr
@@ -1,26 +1,14 @@
-error: non-defining opaque type use in defining scope
-  --> $DIR/not_a_defining_use.rs:10:27
-   |
-LL | fn two<T: Debug>(t: T) -> Two<T, u32> {
-   |                           ^^^^^^^^^^^
-   |
-note: used non-generic type `u32` for generic parameter
-  --> $DIR/not_a_defining_use.rs:7:13
-   |
-LL | type Two<T, U> = impl Debug;
-   |             ^
-
 error: concrete type differs from previous defining opaque type use
-  --> $DIR/not_a_defining_use.rs:29:1
+  --> $DIR/not_a_defining_use.rs:25:5
    |
-LL | fn four<T: Debug, U: Bar>(t: T) -> Two<T, U> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(T, i8)`, got `(T, <U as Bar>::Blub)`
+LL |     (t, <U as Bar>::FOO)
+   |     ^^^^^^^^^^^^^^^^^^^^ expected `(T, i8)`, got `(T, <U as Bar>::Blub)`
    |
 note: previous use here
-  --> $DIR/not_a_defining_use.rs:15:1
+  --> $DIR/not_a_defining_use.rs:11:5
    |
-LL | fn three<T: Debug, U>(t: T) -> Two<T, U> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     (t, 5i8)
+   |     ^^^^^^^^
 
 error[E0277]: `T` doesn't implement `Debug`
   --> $DIR/not_a_defining_use.rs:7:18
@@ -34,6 +22,6 @@ help: consider restricting type parameter `T`
 LL | type Two<T: std::fmt::Debug, U> = impl Debug;
    |           +++++++++++++++++
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/reveal_local.rs b/src/test/ui/type-alias-impl-trait/reveal_local.rs
new file mode 100644
index 00000000000..145186baa1f
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/reveal_local.rs
@@ -0,0 +1,26 @@
+#![feature(type_alias_impl_trait)]
+
+use std::fmt::Debug;
+
+type Foo = impl Debug;
+//~^ ERROR cycle detected
+//~| ERROR cycle detected
+
+fn is_send<T: Send>() { }
+
+fn not_good() {
+    // Error: this function does not constrain `Foo` to any particular
+    // hidden type, so it cannot rely on `Send` being true.
+    is_send::<Foo>();
+}
+
+fn not_gooder() {
+    // Constrain `Foo = u32`
+    let x: Foo = 22_u32;
+
+    // while we could know this from the hidden type, it would
+    // need extra roundabout logic to support it.
+    is_send::<Foo>();
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/reveal_local.stderr b/src/test/ui/type-alias-impl-trait/reveal_local.stderr
new file mode 100644
index 00000000000..5d48dd5b2bf
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/reveal_local.stderr
@@ -0,0 +1,51 @@
+error[E0391]: cycle detected when computing type of `Foo::{opaque#0}`
+  --> $DIR/reveal_local.rs:5:12
+   |
+LL | type Foo = impl Debug;
+   |            ^^^^^^^^^^
+   |
+note: ...which requires type-checking `not_good`...
+  --> $DIR/reveal_local.rs:11:1
+   |
+LL | fn not_good() {
+   | ^^^^^^^^^^^^^
+   = note: ...which again requires computing type of `Foo::{opaque#0}`, completing the cycle
+note: cycle used when checking item types in top-level module
+  --> $DIR/reveal_local.rs:1:1
+   |
+LL | / #![feature(type_alias_impl_trait)]
+LL | |
+LL | | use std::fmt::Debug;
+LL | |
+...  |
+LL | |
+LL | | fn main() {}
+   | |____________^
+
+error[E0391]: cycle detected when computing type of `Foo::{opaque#0}`
+  --> $DIR/reveal_local.rs:5:12
+   |
+LL | type Foo = impl Debug;
+   |            ^^^^^^^^^^
+   |
+note: ...which requires type-checking `not_gooder`...
+  --> $DIR/reveal_local.rs:17:1
+   |
+LL | fn not_gooder() {
+   | ^^^^^^^^^^^^^^^
+   = note: ...which again requires computing type of `Foo::{opaque#0}`, completing the cycle
+note: cycle used when checking item types in top-level module
+  --> $DIR/reveal_local.rs:1:1
+   |
+LL | / #![feature(type_alias_impl_trait)]
+LL | |
+LL | | use std::fmt::Debug;
+LL | |
+...  |
+LL | |
+LL | | fn main() {}
+   | |____________^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/type-alias-impl-trait/self-referential-2.rs b/src/test/ui/type-alias-impl-trait/self-referential-2.rs
new file mode 100644
index 00000000000..dc7054da5ec
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/self-referential-2.rs
@@ -0,0 +1,10 @@
+#![feature(type_alias_impl_trait)]
+
+type Foo = impl std::fmt::Debug;
+type Bar = impl PartialEq<Foo>;
+
+fn bar() -> Bar {
+    42_i32 //~ ERROR can't compare `i32` with `Foo`
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/self-referential-2.stderr b/src/test/ui/type-alias-impl-trait/self-referential-2.stderr
new file mode 100644
index 00000000000..6997676260d
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/self-referential-2.stderr
@@ -0,0 +1,11 @@
+error[E0277]: can't compare `i32` with `Foo`
+  --> $DIR/self-referential-2.rs:7:5
+   |
+LL |     42_i32
+   |     ^^^^^^ no implementation for `i32 == Foo`
+   |
+   = help: the trait `PartialEq<Foo>` is not implemented for `i32`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/self-referential-3.rs b/src/test/ui/type-alias-impl-trait/self-referential-3.rs
new file mode 100644
index 00000000000..d40715717d4
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/self-referential-3.rs
@@ -0,0 +1,14 @@
+// run-pass
+#![feature(type_alias_impl_trait)]
+
+type Bar<'a, 'b> = impl PartialEq<Bar<'a, 'b>> + std::fmt::Debug;
+
+fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> {
+    i
+}
+
+fn main() {
+    let meh = 42;
+    let muh = 42;
+    assert_eq!(bar(&meh), bar(&muh));
+}
diff --git a/src/test/ui/type-alias-impl-trait/self-referential-4.rs b/src/test/ui/type-alias-impl-trait/self-referential-4.rs
new file mode 100644
index 00000000000..697ec56825a
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/self-referential-4.rs
@@ -0,0 +1,25 @@
+#![feature(type_alias_impl_trait)]
+
+type Bar<'a, 'b> = impl PartialEq<Bar<'b, 'static>> + std::fmt::Debug;
+
+fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> {
+    i //~ ERROR can't compare `&i32` with `Bar<'b, 'static>`
+}
+
+type Foo<'a, 'b> = impl PartialEq<Foo<'static, 'b>> + std::fmt::Debug;
+
+fn foo<'a, 'b>(i: &'a i32) -> Foo<'a, 'b> {
+    i //~ ERROR can't compare `&i32` with `Foo<'static, 'b>`
+}
+
+type Moo<'a, 'b> = impl PartialEq<Moo<'static, 'a>> + std::fmt::Debug;
+
+fn moo<'a, 'b>(i: &'a i32) -> Moo<'a, 'b> {
+    i //~ ERROR can't compare `&i32` with `Moo<'static, 'a>`
+}
+
+fn main() {
+    let meh = 42;
+    let muh = 69;
+    assert_eq!(bar(&meh), bar(&meh));
+}
diff --git a/src/test/ui/type-alias-impl-trait/self-referential-4.stderr b/src/test/ui/type-alias-impl-trait/self-referential-4.stderr
new file mode 100644
index 00000000000..4a6ee2f9279
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/self-referential-4.stderr
@@ -0,0 +1,27 @@
+error[E0277]: can't compare `&i32` with `Bar<'b, 'static>`
+  --> $DIR/self-referential-4.rs:6:5
+   |
+LL |     i
+   |     ^ no implementation for `&i32 == Bar<'b, 'static>`
+   |
+   = help: the trait `PartialEq<Bar<'b, 'static>>` is not implemented for `&i32`
+
+error[E0277]: can't compare `&i32` with `Foo<'static, 'b>`
+  --> $DIR/self-referential-4.rs:12:5
+   |
+LL |     i
+   |     ^ no implementation for `&i32 == Foo<'static, 'b>`
+   |
+   = help: the trait `PartialEq<Foo<'static, 'b>>` is not implemented for `&i32`
+
+error[E0277]: can't compare `&i32` with `Moo<'static, 'a>`
+  --> $DIR/self-referential-4.rs:18:5
+   |
+LL |     i
+   |     ^ no implementation for `&i32 == Moo<'static, 'a>`
+   |
+   = help: the trait `PartialEq<Moo<'static, 'a>>` is not implemented for `&i32`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/self-referential.rs b/src/test/ui/type-alias-impl-trait/self-referential.rs
new file mode 100644
index 00000000000..4974ac72dad
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/self-referential.rs
@@ -0,0 +1,25 @@
+#![feature(type_alias_impl_trait)]
+
+type Bar<'a, 'b> = impl PartialEq<Bar<'b, 'a>> + std::fmt::Debug;
+
+fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> {
+    i //~ ERROR can't compare `&i32` with `Bar<'b, 'a>`
+}
+
+type Foo<'a, 'b> = (i32, impl PartialEq<Foo<'a, 'b>> + std::fmt::Debug);
+
+fn foo<'a, 'b>(i: &'a i32) -> Foo<'a, 'b> {
+    (42, i) //~ ERROR can't compare `&i32` with `(i32, &i32)`
+}
+
+type Moo<'a, 'b> = (i32, impl PartialEq<Moo<'b, 'a>> + std::fmt::Debug);
+
+fn moo<'a, 'b>(i: &'a i32) -> Moo<'a, 'b> {
+    (42, i) //~ ERROR can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0})`
+}
+
+fn main() {
+    let meh = 42;
+    let muh = 69;
+    assert_eq!(bar(&meh), bar(&meh));
+}
diff --git a/src/test/ui/type-alias-impl-trait/self-referential.stderr b/src/test/ui/type-alias-impl-trait/self-referential.stderr
new file mode 100644
index 00000000000..0626e6be0d5
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/self-referential.stderr
@@ -0,0 +1,27 @@
+error[E0277]: can't compare `&i32` with `Bar<'b, 'a>`
+  --> $DIR/self-referential.rs:6:5
+   |
+LL |     i
+   |     ^ no implementation for `&i32 == Bar<'b, 'a>`
+   |
+   = help: the trait `PartialEq<Bar<'b, 'a>>` is not implemented for `&i32`
+
+error[E0277]: can't compare `&i32` with `(i32, &i32)`
+  --> $DIR/self-referential.rs:12:10
+   |
+LL |     (42, i)
+   |          ^ no implementation for `&i32 == (i32, &i32)`
+   |
+   = help: the trait `PartialEq<(i32, &i32)>` is not implemented for `&i32`
+
+error[E0277]: can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0})`
+  --> $DIR/self-referential.rs:18:10
+   |
+LL |     (42, i)
+   |          ^ no implementation for `&i32 == (i32, Moo<'b, 'a>::{opaque#0})`
+   |
+   = help: the trait `PartialEq<(i32, Moo<'b, 'a>::{opaque#0})>` is not implemented for `&i32`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/static-const-types.rs b/src/test/ui/type-alias-impl-trait/static-const-types.rs
index 86b685022b2..748a279e439 100644
--- a/src/test/ui/type-alias-impl-trait/static-const-types.rs
+++ b/src/test/ui/type-alias-impl-trait/static-const-types.rs
@@ -1,13 +1,13 @@
 #![feature(type_alias_impl_trait)]
 #![allow(dead_code)]
 
-// FIXME: This should compile, but it currently doesn't
+// check-pass
 
 use std::fmt::Debug;
 
-type Foo = impl Debug; //~ ERROR could not find defining uses
+type Foo = impl Debug;
 
-static FOO1: Foo = 22_u32; //~ ERROR mismatched types
-const FOO2: Foo = 22_u32; //~ ERROR mismatched types
+static FOO1: Foo = 22_u32;
+const FOO2: Foo = 22_u32;
 
 fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/static-const-types.stderr b/src/test/ui/type-alias-impl-trait/static-const-types.stderr
deleted file mode 100644
index 6f4c2944f72..00000000000
--- a/src/test/ui/type-alias-impl-trait/static-const-types.stderr
+++ /dev/null
@@ -1,33 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/static-const-types.rs:10:20
-   |
-LL | type Foo = impl Debug;
-   |            ---------- the expected opaque type
-LL | 
-LL | static FOO1: Foo = 22_u32;
-   |                    ^^^^^^ expected opaque type, found `u32`
-   |
-   = note: expected opaque type `impl Debug`
-                     found type `u32`
-
-error[E0308]: mismatched types
-  --> $DIR/static-const-types.rs:11:19
-   |
-LL | type Foo = impl Debug;
-   |            ---------- the expected opaque type
-...
-LL | const FOO2: Foo = 22_u32;
-   |                   ^^^^^^ expected opaque type, found `u32`
-   |
-   = note: expected opaque type `impl Debug`
-                     found type `u32`
-
-error: could not find defining uses
-  --> $DIR/static-const-types.rs:8:12
-   |
-LL | type Foo = impl Debug;
-   |            ^^^^^^^^^^
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs
index 219837aa04b..c2ab6a9d10a 100644
--- a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs
+++ b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs
@@ -10,9 +10,9 @@ const fn leak_free() -> Bar {
 const LEAK_FREE: Bar = leak_free();
 
 fn leak_free_test() {
-    match todo!() {
+    match LEAK_FREE {
         LEAK_FREE => (),
-        //~^ `impl Send` cannot be used in patterns
+        //~^ `Bar` cannot be used in patterns
         _ => (),
     }
 }
diff --git a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr
index 889c4fd4b04..dbc183f54f4 100644
--- a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr
+++ b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr
@@ -1,4 +1,4 @@
-error: `impl Send` cannot be used in patterns
+error: `Bar` cannot be used in patterns
   --> $DIR/structural-match-no-leak.rs:14:9
    |
 LL |         LEAK_FREE => (),
diff --git a/src/test/ui/type-alias-impl-trait/structural-match.rs b/src/test/ui/type-alias-impl-trait/structural-match.rs
index c9e669cad60..7cc9ccaabdc 100644
--- a/src/test/ui/type-alias-impl-trait/structural-match.rs
+++ b/src/test/ui/type-alias-impl-trait/structural-match.rs
@@ -11,9 +11,9 @@ const fn value() -> Foo {
 const VALUE: Foo = value();
 
 fn test() {
-    match todo!() {
+    match VALUE {
         VALUE => (),
-        //~^ `impl Send` cannot be used in patterns
+        //~^ `Foo` cannot be used in patterns
         _ => (),
     }
 }
diff --git a/src/test/ui/type-alias-impl-trait/structural-match.stderr b/src/test/ui/type-alias-impl-trait/structural-match.stderr
index 262fd072613..61287f26806 100644
--- a/src/test/ui/type-alias-impl-trait/structural-match.stderr
+++ b/src/test/ui/type-alias-impl-trait/structural-match.stderr
@@ -1,4 +1,4 @@
-error: `impl Send` cannot be used in patterns
+error: `Foo` cannot be used in patterns
   --> $DIR/structural-match.rs:15:9
    |
 LL |         VALUE => (),
diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs
index 1a8113848f9..5630e036be3 100644
--- a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs
+++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs
@@ -1,13 +1,11 @@
 #![feature(type_alias_impl_trait)]
-
+// check-pass
 // Ensures that `const` items can constrain an opaque `impl Trait`.
 
 use std::fmt::Debug;
 
 pub type Foo = impl Debug;
-//~^ ERROR could not find defining uses
 
 const _FOO: Foo = 5;
-//~^ ERROR mismatched types [E0308]
 
 fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.stderr b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.stderr
deleted file mode 100644
index e2567e87ac6..00000000000
--- a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/type-alias-impl-trait-const.rs:10:19
-   |
-LL | pub type Foo = impl Debug;
-   |                ---------- the expected opaque type
-...
-LL | const _FOO: Foo = 5;
-   |                   ^ expected opaque type, found integer
-   |
-   = note: expected opaque type `impl Debug`
-                     found type `{integer}`
-
-error: could not find defining uses
-  --> $DIR/type-alias-impl-trait-const.rs:7:16
-   |
-LL | pub type Foo = impl Debug;
-   |                ^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.rs b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.rs
index c009952eab7..e5e7fb677ed 100644
--- a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.rs
+++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.rs
@@ -1,7 +1,7 @@
 #![feature(type_alias_impl_trait)]
 
 type Foo = impl Fn() -> Foo;
-//~^ ERROR: could not find defining uses
+//~^ ERROR: unconstrained opaque type
 
 fn crash(x: Foo) -> Foo {
     x
diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.stderr b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.stderr
index 726f4ea6e00..a770eeac39b 100644
--- a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.stderr
+++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.stderr
@@ -1,8 +1,10 @@
-error: could not find defining uses
+error: unconstrained opaque type
   --> $DIR/type-alias-impl-trait-with-cycle-error.rs:3:12
    |
 LL | type Foo = impl Fn() -> Foo;
    |            ^^^^^^^^^^^^^^^^
+   |
+   = note: `Foo` must be used in combination with a concrete type within the same module
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.rs b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.rs
index f3898bca64b..7c7a1b405bc 100644
--- a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.rs
+++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.rs
@@ -5,7 +5,7 @@ pub trait Bar<T> {
 }
 
 type Foo = impl Bar<Foo, Item = Foo>;
-//~^ ERROR: could not find defining uses
+//~^ ERROR: unconstrained opaque type
 
 fn crash(x: Foo) -> Foo {
     x
diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.stderr b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.stderr
index 3947cc4d270..3f3699ce532 100644
--- a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.stderr
+++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.stderr
@@ -1,8 +1,10 @@
-error: could not find defining uses
+error: unconstrained opaque type
   --> $DIR/type-alias-impl-trait-with-cycle-error2.rs:7:12
    |
 LL | type Foo = impl Bar<Foo, Item = Foo>;
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Foo` must be used in combination with a concrete type within the same module
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait.rs b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait.rs
index d2c8c1f63df..70c2ee4278c 100644
--- a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait.rs
+++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 #![allow(dead_code)]
 #![allow(unused_assignments)]
diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait2.rs b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait2.rs
new file mode 100644
index 00000000000..67f56bcde93
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait2.rs
@@ -0,0 +1,84 @@
+// check-pass
+
+#![allow(dead_code)]
+#![allow(unused_assignments)]
+#![allow(unused_variables)]
+#![feature(type_alias_impl_trait)]
+
+fn main() {
+    assert_eq!(foo().to_string(), "foo");
+    assert_eq!(bar1().to_string(), "bar1");
+    assert_eq!(bar2().to_string(), "bar2");
+    let mut x = bar1();
+    x = bar2();
+    assert_eq!(my_iter(42u8).collect::<Vec<u8>>(), vec![42u8]);
+}
+
+use defining_use_scope::*;
+
+mod defining_use_scope {
+    // single definition
+    pub type Foo = impl std::fmt::Display;
+
+    pub fn foo() -> Foo {
+        "foo"
+    }
+
+    // two definitions
+    pub type Bar = impl std::fmt::Display;
+
+    pub fn bar1() -> Bar {
+        "bar1"
+    }
+
+    pub fn bar2() -> Bar {
+        "bar2"
+    }
+
+    pub type MyIter<T> = impl Iterator<Item = T>;
+
+    pub fn my_iter<T>(t: T) -> MyIter<T> {
+        std::iter::once(t)
+    }
+
+    fn my_iter2<T>(t: T) -> MyIter<T> {
+        std::iter::once(t)
+    }
+
+    // param names should not have an effect!
+    fn my_iter3<U>(u: U) -> MyIter<U> {
+        std::iter::once(u)
+    }
+
+    // param position should not have an effect!
+    fn my_iter4<U, V>(_: U, v: V) -> MyIter<V> {
+        std::iter::once(v)
+    }
+
+    // param names should not have an effect!
+    type MyOtherIter<T> = impl Iterator<Item = T>;
+
+    fn my_other_iter<U>(u: U) -> MyOtherIter<U> {
+        std::iter::once(u)
+    }
+
+    trait Trait {}
+    type GenericBound<'a, T: Trait + 'a> = impl Sized + 'a;
+
+    fn generic_bound<'a, T: Trait + 'a>(t: T) -> GenericBound<'a, T> {
+        t
+    }
+
+    mod pass_through {
+        pub type Passthrough<T: 'static> = impl Sized + 'static;
+
+        fn define_passthrough<T: 'static>(t: T) -> Passthrough<T> {
+            t
+        }
+    }
+
+    fn use_passthrough(x: pass_through::Passthrough<u32>) -> pass_through::Passthrough<u32> {
+        x
+    }
+
+}
diff --git a/src/test/ui/type-alias-impl-trait/type_of_a_let.rs b/src/test/ui/type-alias-impl-trait/type_of_a_let.rs
index 7f8e6127cca..4e9d1788b94 100644
--- a/src/test/ui/type-alias-impl-trait/type_of_a_let.rs
+++ b/src/test/ui/type-alias-impl-trait/type_of_a_let.rs
@@ -1,27 +1,20 @@
 #![feature(type_alias_impl_trait)]
 #![allow(dead_code)]
 
-// FIXME This should compile, but it currently doesn't
-
 use std::fmt::Debug;
 
 type Foo = impl Debug;
-//~^ ERROR: could not find defining uses
 
 fn foo1() -> u32 {
     let x: Foo = 22_u32;
-    //~^ ERROR: mismatched types [E0308]
     x
-    //~^ ERROR: mismatched types [E0308]
 }
 
 fn foo2() -> u32 {
     let x: Foo = 22_u32;
-    //~^ ERROR: mismatched types [E0308]
     let y: Foo = x;
-    same_type((x, y));
-    y
-    //~^ ERROR: mismatched types [E0308]
+    same_type((x, y)); //~ ERROR use of moved value
+    y //~ ERROR use of moved value
 }
 
 fn same_type<T>(x: (T, T)) {}
diff --git a/src/test/ui/type-alias-impl-trait/type_of_a_let.stderr b/src/test/ui/type-alias-impl-trait/type_of_a_let.stderr
index cac8d6841af..1dabe4586c5 100644
--- a/src/test/ui/type-alias-impl-trait/type_of_a_let.stderr
+++ b/src/test/ui/type-alias-impl-trait/type_of_a_let.stderr
@@ -1,67 +1,23 @@
-error[E0308]: mismatched types
-  --> $DIR/type_of_a_let.rs:12:18
+error[E0382]: use of moved value: `x`
+  --> $DIR/type_of_a_let.rs:16:16
    |
-LL | type Foo = impl Debug;
-   |            ---------- the expected opaque type
-...
 LL |     let x: Foo = 22_u32;
-   |            ---   ^^^^^^ expected opaque type, found `u32`
-   |            |
-   |            expected due to this
-   |
-   = note: expected opaque type `impl Debug`
-                     found type `u32`
-
-error[E0308]: mismatched types
-  --> $DIR/type_of_a_let.rs:14:5
-   |
-LL | type Foo = impl Debug;
-   |            ---------- the found opaque type
-...
-LL | fn foo1() -> u32 {
-   |              --- expected `u32` because of return type
-...
-LL |     x
-   |     ^ expected `u32`, found opaque type
-   |
-   = note:     expected type `u32`
-           found opaque type `impl Debug`
+   |         - move occurs because `x` has type `Foo`, which does not implement the `Copy` trait
+LL |     let y: Foo = x;
+   |                  - value moved here
+LL |     same_type((x, y));
+   |                ^ value used here after move
 
-error[E0308]: mismatched types
-  --> $DIR/type_of_a_let.rs:19:18
-   |
-LL | type Foo = impl Debug;
-   |            ---------- the expected opaque type
-...
-LL |     let x: Foo = 22_u32;
-   |            ---   ^^^^^^ expected opaque type, found `u32`
-   |            |
-   |            expected due to this
+error[E0382]: use of moved value: `y`
+  --> $DIR/type_of_a_let.rs:17:5
    |
-   = note: expected opaque type `impl Debug`
-                     found type `u32`
-
-error[E0308]: mismatched types
-  --> $DIR/type_of_a_let.rs:23:5
-   |
-LL | type Foo = impl Debug;
-   |            ---------- the found opaque type
-...
-LL | fn foo2() -> u32 {
-   |              --- expected `u32` because of return type
-...
+LL |     let y: Foo = x;
+   |         - move occurs because `y` has type `Foo`, which does not implement the `Copy` trait
+LL |     same_type((x, y));
+   |                   - value moved here
 LL |     y
-   |     ^ expected `u32`, found opaque type
-   |
-   = note:     expected type `u32`
-           found opaque type `impl Debug`
-
-error: could not find defining uses
-  --> $DIR/type_of_a_let.rs:8:12
-   |
-LL | type Foo = impl Debug;
-   |            ^^^^^^^^^^
+   |     ^ value used here after move
 
-error: aborting due to 5 previous errors
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 0e5e0c2616e..63a8909c662 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -7,7 +7,7 @@ use std::path::Path;
 
 const ENTRY_LIMIT: usize = 1000;
 // FIXME: The following limits should be reduced eventually.
-const ROOT_ENTRY_LIMIT: usize = 985;
+const ROOT_ENTRY_LIMIT: usize = 986;
 const ISSUES_ENTRY_LIMIT: usize = 2310;
 
 fn check_entries(path: &Path, bad: &mut bool) {