1
Fork 0

Point at return expression for RPIT-related error

This commit is contained in:
Michael Goulet 2022-06-06 23:20:13 -07:00
parent dc80ca78b6
commit 52409c4c90
14 changed files with 97 additions and 5 deletions

View file

@ -5,7 +5,7 @@ use hir::{HirId, OpaqueTyOrigin};
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use rustc_data_structures::vec_map::VecMap; use rustc_data_structures::vec_map::VecMap;
use rustc_hir as hir; 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::fold::BottomUpFolder;
use rustc_middle::ty::subst::{GenericArgKind, Subst}; use rustc_middle::ty::subst::{GenericArgKind, Subst};
use rustc_middle::ty::{ use rustc_middle::ty::{
@ -46,6 +46,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
value: T, value: T,
body_id: HirId, body_id: HirId,
span: Span, span: Span,
code: ObligationCauseCode<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
) -> InferOk<'tcx, T> { ) -> InferOk<'tcx, T> {
if !value.has_opaque_types() { 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 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 { let ty_var = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeInference, kind: TypeVariableOriginKind::TypeInference,
span: cause.span, span,
}); });
obligations.extend( obligations.extend(
self.handle_opaque_type(ty, ty_var, true, &cause, param_env) self.handle_opaque_type(ty, ty_var, true, &cause, param_env)

View file

@ -387,6 +387,9 @@ pub enum ObligationCauseCode<'tcx> {
/// Return type of this function /// Return type of this function
ReturnType, ReturnType,
/// Opaque return type of this function
OpaqueReturnType(Option<(Ty<'tcx>, Span)>),
/// Block implicit return /// Block implicit return
BlockTailExpression(hir::HirId), BlockTailExpression(hir::HirId),

View file

@ -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"); 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"),
);
}
}
} }
} }

View file

@ -28,6 +28,7 @@ use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_infer::traits::ObligationCauseCode;
use rustc_middle::traits::select::OverflowError; use rustc_middle::traits::select::OverflowError;
use rustc_middle::ty::fold::{MaxUniverse, TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::fold::{MaxUniverse, TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::subst::Subst; use rustc_middle::ty::subst::Subst;
@ -261,6 +262,7 @@ fn project_and_unify_type<'cx, 'tcx>(
actual, actual,
obligation.cause.body_id, obligation.cause.body_id,
obligation.cause.span, obligation.cause.span,
ObligationCauseCode::MiscObligation,
obligation.param_env, obligation.param_env,
); );
obligations.extend(new); obligations.extend(new);

View file

@ -101,8 +101,13 @@ pub(super) fn check_fn<'a, 'tcx>(
declared_ret_ty, declared_ret_ty,
body.value.hir_id, body.value.hir_id,
DUMMY_SP, DUMMY_SP,
traits::ObligationCauseCode::OpaqueReturnType(None),
param_env, 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_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
fcx.ret_type_span = Some(decl.output.span()); fcx.ret_type_span = Some(decl.output.span());

View file

@ -10,6 +10,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_infer::infer::{InferOk, InferResult}; use rustc_infer::infer::{InferOk, InferResult};
use rustc_infer::traits::ObligationCauseCode;
use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{self, Ty}; 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> { fn hide_parent_opaque_types(&self, ty: Ty<'tcx>, span: Span, body_id: hir::HirId) -> Ty<'tcx> {
let InferOk { value, obligations } = let InferOk { value, obligations } = self.replace_opaque_types_with_inference_vars(
self.replace_opaque_types_with_inference_vars(ty, body_id, span, self.param_env); ty,
body_id,
span,
ObligationCauseCode::MiscObligation,
self.param_env,
);
self.register_predicates(obligations); self.register_predicates(obligations);
value value
} }

View file

@ -39,6 +39,7 @@ use rustc_hir::{ExprKind, HirId, QPath};
use rustc_infer::infer; use rustc_infer::infer;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::InferOk; use rustc_infer::infer::InferOk;
use rustc_infer::traits::ObligationCause;
use rustc_middle::middle::stability; use rustc_middle::middle::stability;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
use rustc_middle::ty::error::TypeError::FieldMisMatch; use rustc_middle::ty::error::TypeError::FieldMisMatch;
@ -839,6 +840,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return_expr, return_expr,
return_expr_ty, 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( pub(crate) fn check_lhs_assignable(

View file

@ -115,6 +115,9 @@ pub struct FnCtxt<'a, 'tcx> {
/// either given explicitly or inferred from, say, an `Fn*` trait /// either given explicitly or inferred from, say, an `Fn*` trait
/// bound. Used for diagnostic purposes only. /// bound. Used for diagnostic purposes only.
pub(super) return_type_pre_known: bool, 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> { impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@ -141,6 +144,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}), }),
inh, inh,
return_type_pre_known: true, return_type_pre_known: true,
return_type_has_opaque: false,
} }
} }

View file

@ -6,6 +6,9 @@ LL | fn bar() -> impl Bar {
... ...
LL | fn baz() -> impl Bar<Item = i32> { LL | fn baz() -> impl Bar<Item = i32> {
| ^^^^^^^^^^^^^^^^^^^^ expected associated type, found `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` = note: expected associated type `<impl Bar as Foo>::Item`
found type `i32` found type `i32`

View file

@ -3,6 +3,9 @@ error[E0277]: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
| |
LL | fn rawr() -> impl Trait { LL | fn rawr() -> impl Trait {
| ^^^^^^^^^^ the trait `Trait` is not implemented for `Uwu<10_u32, 12_u32>` | ^^^^^^^^^^ 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>` = 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> { LL | fn uwu<const N: u8>() -> impl Traitor<N> {
| ^^^^^^^^^^^^^^^ the trait `Traitor<N>` is not implemented for `u32` | ^^^^^^^^^^^^^^^ 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>`: = help: the following other types implement trait `Traitor<N, M>`:
<u32 as Traitor<N, 2_u8>> <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 { LL | fn owo() -> impl Traitor {
| ^^^^^^^^^^^^ the trait `Traitor` is not implemented for `u64` | ^^^^^^^^^^^^ 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>`: = help: the following other types implement trait `Traitor<N, M>`:
<u32 as Traitor<N, 2_u8>> <u32 as Traitor<N, 2_u8>>

View file

@ -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> { LL | fn foo_fail<T: Trait>() -> impl FooLike<Output = T::Assoc> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Foo<()> as FooLike>::Output == <T as impl_trait::Trait>::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 `()` note: expected this to be `()`
--> $DIR/bound-normalization-fail.rs:14:19 --> $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> { 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` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 `()` note: expected this to be `()`
--> $DIR/bound-normalization-fail.rs:14:19 --> $DIR/bound-normalization-fail.rs:14:19

View file

@ -9,6 +9,9 @@ error[E0277]: `u32` is not a future
| |
LL | fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ { LL | fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `u32` is not a 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` = help: the trait `Future` is not implemented for `u32`
= note: u32 must be a future or must implement `IntoFuture` to be awaited = note: u32 must be a future or must implement `IntoFuture` to be awaited

View file

@ -3,6 +3,9 @@ error[E0277]: the trait bound `(): Foo<FooX>` is not satisfied
| |
LL | fn foo() -> impl Foo<FooX> { LL | fn foo() -> impl Foo<FooX> {
| ^^^^^^^^^^^^^^ the trait `Foo<FooX>` is not implemented for `()` | ^^^^^^^^^^^^^^ the trait `Foo<FooX>` is not implemented for `()`
...
LL | ()
| -- return type was inferred to be `()` here
| |
= help: the trait `Foo<()>` is implemented for `()` = help: the trait `Foo<()>` is implemented for `()`

View file

@ -3,6 +3,9 @@ error[E0277]: the trait bound `(): Foo<FooX>` is not satisfied
| |
LL | fn foo() -> impl Foo<FooX> { LL | fn foo() -> impl Foo<FooX> {
| ^^^^^^^^^^^^^^ the trait `Foo<FooX>` is not implemented for `()` | ^^^^^^^^^^^^^^ 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>`: = help: the following other types implement trait `Foo<A>`:
<() as Foo<()>> <() as Foo<()>>