about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs10
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs2
-rw-r--r--compiler/rustc_typeck/src/check/check.rs5
-rw-r--r--compiler/rustc_typeck/src/check/closure.rs10
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs32
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/mod.rs4
-rw-r--r--src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr3
-rw-r--r--src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr9
-rw-r--r--src/test/ui/impl-trait/bound-normalization-fail.stderr6
-rw-r--r--src/test/ui/issues-71798.stderr3
-rw-r--r--src/test/ui/type-alias-impl-trait/nested-tait-inference.stderr3
-rw-r--r--src/test/ui/type-alias-impl-trait/nested-tait-inference2.stderr3
14 files changed, 97 insertions, 5 deletions
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 80f6abbab34..7684d861f3c 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -5,7 +5,7 @@ use hir::{HirId, OpaqueTyOrigin};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::vec_map::VecMap;
 use rustc_hir as hir;
-use rustc_middle::traits::ObligationCause;
+use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::subst::{GenericArgKind, Subst};
 use rustc_middle::ty::{
@@ -46,6 +46,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         value: T,
         body_id: HirId,
         span: Span,
+        code: ObligationCauseCode<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> InferOk<'tcx, T> {
         if !value.has_opaque_types() {
@@ -68,10 +69,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     ) =>
                 {
                     let span = if span.is_dummy() { self.tcx.def_span(def_id) } else { span };
-                    let cause = ObligationCause::misc(span, body_id);
+                    let cause = ObligationCause::new(span, body_id, code.clone());
+                    // FIXME(compiler-errors): We probably should add a new TypeVariableOriginKind
+                    // for opaque types, and then use that kind to fix the spans for type errors
+                    // that we see later on.
                     let ty_var = self.next_ty_var(TypeVariableOrigin {
                         kind: TypeVariableOriginKind::TypeInference,
-                        span: cause.span,
+                        span,
                     });
                     obligations.extend(
                         self.handle_opaque_type(ty, ty_var, true, &cause, param_env)
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 912b09eeca8..5258d37a14c 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -387,6 +387,9 @@ pub enum ObligationCauseCode<'tcx> {
     /// Return type of this function
     ReturnType,
 
+    /// Opaque return type of this function
+    OpaqueReturnType(Option<(Ty<'tcx>, Span)>),
+
     /// Block implicit return
     BlockTailExpression(hir::HirId),
 
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 d8003efba87..0485cac9e9f 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -2661,6 +2661,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     err.help("add `#![feature(trivial_bounds)]` to the crate attributes to enable");
                 }
             }
+            ObligationCauseCode::OpaqueReturnType(expr_info) => {
+                if let Some((expr_ty, expr_span)) = expr_info {
+                    let expr_ty = self.resolve_vars_if_possible(expr_ty);
+                    err.span_label(
+                        expr_span,
+                        format!("return type was inferred to be `{expr_ty}` here"),
+                    );
+                }
+            }
         }
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index a72f90746ed..82c54291a5d 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -28,6 +28,7 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
+use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::ty::fold::{MaxUniverse, TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::subst::Subst;
@@ -261,6 +262,7 @@ fn project_and_unify_type<'cx, 'tcx>(
             actual,
             obligation.cause.body_id,
             obligation.cause.span,
+            ObligationCauseCode::MiscObligation,
             obligation.param_env,
         );
     obligations.extend(new);
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 0425e7b074f..45c011b78e3 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -101,8 +101,13 @@ pub(super) fn check_fn<'a, 'tcx>(
             declared_ret_ty,
             body.value.hir_id,
             DUMMY_SP,
+            traits::ObligationCauseCode::OpaqueReturnType(None),
             param_env,
         ));
+    // If we replaced declared_ret_ty with infer vars, then we must be infering
+    // an opaque type, so set a flag so we can improve diagnostics.
+    fcx.return_type_has_opaque = ret_ty != declared_ret_ty;
+
     fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
     fcx.ret_type_span = Some(decl.output.span());
 
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index 05b22e174b8..cce11305119 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -10,6 +10,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_infer::infer::{InferOk, InferResult};
+use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::{self, Ty};
@@ -645,8 +646,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     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);
+        let InferOk { value, obligations } = self.replace_opaque_types_with_inference_vars(
+            ty,
+            body_id,
+            span,
+            ObligationCauseCode::MiscObligation,
+            self.param_env,
+        );
         self.register_predicates(obligations);
         value
     }
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 37d12b4ed5d..77d6495f38c 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -39,6 +39,7 @@ use rustc_hir::{ExprKind, HirId, QPath};
 use rustc_infer::infer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::InferOk;
+use rustc_infer::traits::ObligationCause;
 use rustc_middle::middle::stability;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
 use rustc_middle::ty::error::TypeError::FieldMisMatch;
@@ -839,6 +840,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return_expr,
             return_expr_ty,
         );
+
+        if self.return_type_has_opaque {
+            // Point any obligations that were registered due to opaque type
+            // inference at the return expression.
+            self.select_obligations_where_possible(false, |errors| {
+                self.point_at_return_for_opaque_ty_error(errors, span, return_expr_ty);
+            });
+        }
+    }
+
+    fn point_at_return_for_opaque_ty_error(
+        &self,
+        errors: &mut Vec<traits::FulfillmentError<'tcx>>,
+        span: Span,
+        return_expr_ty: Ty<'tcx>,
+    ) {
+        // Don't point at the whole block if it's empty
+        if span == self.tcx.hir().span(self.body_id) {
+            return;
+        }
+        for err in errors {
+            let cause = &mut err.obligation.cause;
+            if let ObligationCauseCode::OpaqueReturnType(None) = cause.code() {
+                let new_cause = ObligationCause::new(
+                    cause.span,
+                    cause.body_id,
+                    ObligationCauseCode::OpaqueReturnType(Some((return_expr_ty, span))),
+                );
+                *cause = new_cause;
+            }
+        }
     }
 
     pub(crate) fn check_lhs_assignable(
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
index fa2416d56de..8b680a3d042 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
@@ -115,6 +115,9 @@ pub struct FnCtxt<'a, 'tcx> {
     /// either given explicitly or inferred from, say, an `Fn*` trait
     /// bound. Used for diagnostic purposes only.
     pub(super) return_type_pre_known: bool,
+
+    /// True if the return type has an Opaque type
+    pub(super) return_type_has_opaque: bool,
 }
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -141,6 +144,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }),
             inh,
             return_type_pre_known: true,
+            return_type_has_opaque: false,
         }
     }
 
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 bd8c8a4414c..fbd76a64c1e 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
@@ -6,6 +6,9 @@ LL | fn bar() -> impl Bar {
 ...
 LL | fn baz() -> impl Bar<Item = i32> {
    |             ^^^^^^^^^^^^^^^^^^^^ expected associated type, found `i32`
+LL |
+LL |     bar()
+   |     ----- return type was inferred to be `impl Bar` here
    |
    = note: expected associated type `<impl Bar as Foo>::Item`
                          found type `i32`
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 cbe4a4ac0d6..cbc7b93f3a9 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
@@ -3,6 +3,9 @@ error[E0277]: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
    |
 LL | fn rawr() -> impl Trait {
    |              ^^^^^^^^^^ the trait `Trait` is not implemented for `Uwu<10_u32, 12_u32>`
+LL |
+LL |     Uwu::<10, 12>
+   |     ------------- return type was inferred to be `Uwu<10_u32, 12_u32>` here
    |
    = help: the trait `Trait` is implemented for `Uwu<N>`
 
@@ -11,6 +14,9 @@ error[E0277]: the trait bound `u32: Traitor<N>` is not satisfied
    |
 LL | fn uwu<const N: u8>() -> impl Traitor<N> {
    |                          ^^^^^^^^^^^^^^^ the trait `Traitor<N>` is not implemented for `u32`
+LL |
+LL |     1_u32
+   |     ----- return type was inferred to be `u32` here
    |
    = help: the following other types implement trait `Traitor<N, M>`:
              <u32 as Traitor<N, 2_u8>>
@@ -21,6 +27,9 @@ error[E0277]: the trait bound `u64: Traitor` is not satisfied
    |
 LL | fn owo() -> impl Traitor {
    |             ^^^^^^^^^^^^ the trait `Traitor` is not implemented for `u64`
+LL |
+LL |     1_u64
+   |     ----- return type was inferred to be `u64` here
    |
    = help: the following other types implement trait `Traitor<N, M>`:
              <u32 as Traitor<N, 2_u8>>
diff --git a/src/test/ui/impl-trait/bound-normalization-fail.stderr b/src/test/ui/impl-trait/bound-normalization-fail.stderr
index eac7e6b315e..bd8d3d3d24e 100644
--- a/src/test/ui/impl-trait/bound-normalization-fail.stderr
+++ b/src/test/ui/impl-trait/bound-normalization-fail.stderr
@@ -3,6 +3,9 @@ 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`
+LL |
+LL |         Foo(())
+   |         ------- return type was inferred to be `Foo<()>` here
    |
 note: expected this to be `()`
   --> $DIR/bound-normalization-fail.rs:14:19
@@ -27,6 +30,9 @@ error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lif
    |
 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`
+...
+LL |         Foo(())
+   |         ------- return type was inferred to be `Foo<()>` here
    |
 note: expected this to be `()`
   --> $DIR/bound-normalization-fail.rs:14:19
diff --git a/src/test/ui/issues-71798.stderr b/src/test/ui/issues-71798.stderr
index ab72c3e41af..829d0a02ec9 100644
--- a/src/test/ui/issues-71798.stderr
+++ b/src/test/ui/issues-71798.stderr
@@ -9,6 +9,9 @@ error[E0277]: `u32` is not a future
    |
 LL | fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `u32` is not a future
+LL |
+LL |     *x
+   |     -- return type was inferred to be `u32` here
    |
    = help: the trait `Future` is not implemented for `u32`
    = note: u32 must be a future or must implement `IntoFuture` to be awaited
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
index f98da9f7f92..62db019ed6a 100644
--- a/src/test/ui/type-alias-impl-trait/nested-tait-inference.stderr
+++ b/src/test/ui/type-alias-impl-trait/nested-tait-inference.stderr
@@ -3,6 +3,9 @@ error[E0277]: the trait bound `(): Foo<FooX>` is not satisfied
    |
 LL | fn foo() -> impl Foo<FooX> {
    |             ^^^^^^^^^^^^^^ the trait `Foo<FooX>` is not implemented for `()`
+...
+LL |     ()
+   |     -- return type was inferred to be `()` here
    |
    = help: the trait `Foo<()>` is implemented for `()`
 
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 54f571ad3e3..f4d96038d91 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
@@ -3,6 +3,9 @@ error[E0277]: the trait bound `(): Foo<FooX>` is not satisfied
    |
 LL | fn foo() -> impl Foo<FooX> {
    |             ^^^^^^^^^^^^^^ the trait `Foo<FooX>` is not implemented for `()`
+LL |
+LL |     ()
+   |     -- return type was inferred to be `()` here
    |
    = help: the following other types implement trait `Foo<A>`:
              <() as Foo<()>>