From 52409c4c90d122a73ece033aaac65ef254ea5470 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 6 Jun 2022 23:20:13 -0700 Subject: [PATCH] Point at return expression for RPIT-related error --- .../rustc_infer/src/infer/opaque_types.rs | 10 ++++-- compiler/rustc_middle/src/traits/mod.rs | 3 ++ .../src/traits/error_reporting/suggestions.rs | 9 ++++++ .../src/traits/project.rs | 2 ++ compiler/rustc_typeck/src/check/check.rs | 5 +++ compiler/rustc_typeck/src/check/closure.rs | 10 ++++-- compiler/rustc_typeck/src/check/expr.rs | 32 +++++++++++++++++++ .../rustc_typeck/src/check/fn_ctxt/mod.rs | 4 +++ ...mpl-trait-return-missing-constraint.stderr | 3 ++ .../defaults/rp_impl_trait_fail.stderr | 9 ++++++ .../bound-normalization-fail.stderr | 6 ++++ src/test/ui/issues-71798.stderr | 3 ++ .../nested-tait-inference.stderr | 3 ++ .../nested-tait-inference2.stderr | 3 ++ 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 80f6abbab3447..7684d861f3c93 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 912b09eeca861..5258d37a14c91 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 d8003efba872d..0485cac9e9f74 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 a72f90746edfa..82c54291a5d5e 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 0425e7b074fcf..45c011b78e388 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 05b22e174b845..cce1130511944 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 37d12b4ed5da4..77d6495f38c2f 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>, + 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 fa2416d56de14..8b680a3d042da 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 bd8c8a4414c4d..fbd76a64c1e92 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 { | ^^^^^^^^^^^^^^^^^^^^ expected associated type, found `i32` +LL | +LL | bar() + | ----- return type was inferred to be `impl Bar` here | = note: expected associated type `::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 cbe4a4ac0d659..cbc7b93f3a925 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` @@ -11,6 +14,9 @@ error[E0277]: the trait bound `u32: Traitor` is not satisfied | LL | fn uwu() -> impl Traitor { | ^^^^^^^^^^^^^^^ the trait `Traitor` 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`: > @@ -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`: > diff --git a/src/test/ui/impl-trait/bound-normalization-fail.stderr b/src/test/ui/impl-trait/bound-normalization-fail.stderr index eac7e6b315ec4..bd8d3d3d24ece 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 ` as FooLike>::Output == () -> impl FooLike { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving ` as FooLike>::Output == ::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 ` as FooLike>::Output == >() -> impl FooLike { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving ` as FooLike>::Output == >::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 ab72c3e41af97..829d0a02ec90b 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 + '_ { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `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 f98da9f7f920a..62db019ed6a91 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` is not satisfied | LL | fn foo() -> impl Foo { | ^^^^^^^^^^^^^^ the trait `Foo` 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 54f571ad3e37e..f4d96038d9109 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` is not satisfied | LL | fn foo() -> impl Foo { | ^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()` +LL | +LL | () + | -- return type was inferred to be `()` here | = help: the following other types implement trait `Foo`: <() as Foo<()>>