Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Point at return expression for RPIT-related error #97818

Merged
merged 1 commit into from
Jun 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions compiler/rustc_infer/src/infer/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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() {
Expand All @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
);
}
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_typeck/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());

Expand Down
10 changes: 8 additions & 2 deletions compiler/rustc_typeck/src/check/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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
}
Expand Down
32 changes: 32 additions & 0 deletions compiler/rustc_typeck/src/check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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(
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand All @@ -141,6 +144,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}),
inh,
return_type_pre_known: true,
return_type_has_opaque: false,
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
9 changes: 9 additions & 0 deletions src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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>`

Expand All @@ -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>>
Expand All @@ -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>>
Expand Down
6 changes: 6 additions & 0 deletions src/test/ui/impl-trait/bound-normalization-fail.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
3 changes: 3 additions & 0 deletions src/test/ui/issues-71798.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 `()`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<()>>
Expand Down