Skip to content
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
14 changes: 13 additions & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,11 +464,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}

pub(crate) fn normalize<T>(&self, span: Span, value: Unnormalized<'tcx, T>) -> T
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
self.normalize_with_cause(span, value, ObligationCauseCode::Misc)
}

pub(crate) fn normalize_with_cause<T>(
&self,
span: Span,
value: Unnormalized<'tcx, T>,
code: ObligationCauseCode<'tcx>,
) -> T
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
self.register_infer_ok_obligations(
self.at(&self.misc(span), self.param_env).normalize(value),
self.at(&self.cause(span, code), self.param_env).normalize(value),
)
}

Expand Down
15 changes: 12 additions & 3 deletions compiler/rustc_hir_typeck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,15 @@ fn typeck_with_inspect<'tcx>(

fn_sig.inputs_and_output = tcx.mk_type_list_from_iter(
fn_sig
.inputs_and_output
.inputs()
.iter()
.enumerate()
.map(|(idx, ty)| fcx.normalize(arg_span(idx), Unnormalized::new_wip(ty))),
.map(|(idx, ty)| fcx.normalize(arg_span(idx), Unnormalized::new_wip(*ty)))
.chain([fcx.normalize_with_cause(
decl.output.span(),
Unnormalized::new_wip(fn_sig.output()),
ObligationCauseCode::ReturnType,
)]),
);

if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NAKED) {
Expand All @@ -191,7 +196,11 @@ fn typeck_with_inspect<'tcx>(

loops::check(tcx, def_id, body);

let expected_type = fcx.normalize(body.value.span, Unnormalized::new_wip(expected_type));
let expected_type = fcx.normalize_with_cause(
body.value.span,
Unnormalized::new_wip(expected_type),
ObligationCauseCode::BlockTailExpression(body.value.hir_id, hir::MatchSource::Normal),
);

let wf_code = ObligationCauseCode::WellFormed(WellFormedLoc::Ty(def_id));
fcx.register_wf_obligation(expected_type.into(), body.value.span, wf_code);
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,8 @@ pub enum ObligationCauseCode<'tcx> {
/// Opaque return type of this function
OpaqueReturnType(Option<(Ty<'tcx>, HirId)>),

ReturnType,

/// Block implicit return
BlockTailExpression(HirId, hir::MatchSource),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ use crate::diagnostics::{
use crate::error_reporting::TypeErrCtxt;
use crate::error_reporting::infer::TyCategory;
use crate::error_reporting::traits::report_dyn_incompatibility;
use crate::error_reporting::traits::suggestions::ReturnsVisitor;
use crate::infer::{self, InferCtxt, InferCtxtExt as _};
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use crate::traits::{
Expand Down Expand Up @@ -1960,6 +1961,52 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
});

// Account for errors caused on a return type.
if let ObligationCauseCode::ReturnType = obligation.cause.code() {
let body = self.tcx.hir_body_owned_by(obligation.cause.body_def_id);
let mut visitor = ReturnsVisitor::default();
visitor.visit_body(&body);
if visitor.returns.is_empty()
&& let hir::ExprKind::Block(block, _) = body.value.kind
{
// We likely have an attempt to unify `<Something as Trait>Assoc == ()`, but we
// have no returned expression.
let span = match block.stmts {
[] => body.value.span,
[.., stmt] => stmt.span,
};
if let Some(clause) = predicate.as_clause()
&& let ty::ClauseKind::Projection(projection) = clause.kind().skip_binder()
&& let Some(ty) = projection.term.as_type()
&& ty == self.tcx.types.unit
{
diag.span_label(span, "`()` returned here");
}
} else if let Some(typeck) = &self.typeck_results {
for expr in visitor.returns {
let span = match expr.kind {
hir::ExprKind::Closure(closure) => closure.fn_decl_span,
_ => expr.span,
};
let msg = match typeck.expr_ty_adjusted_opt(expr) {
Some(ty) => {
let ty = self.tcx.short_string(ty, diag.long_ty_path());
format!("`{ty}` returned here")
}
None => "value returned here".to_string(),
};
diag.span_label(span, msg);
self.point_at_chain_in_return_position(
obligation.cause.body_def_id,
expr,
typeck,
obligation.param_env,
&mut diag,
);
}
}
}

self.note_type_err(
&mut diag,
&obligation.cause,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3921,6 +3921,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
| ObligationCauseCode::AlwaysApplicableImpl
| ObligationCauseCode::ConstParam(_)
| ObligationCauseCode::ConstItemTy(_)
| ObligationCauseCode::ReturnType
| ObligationCauseCode::ReferenceOutlivesReferent(..)
| ObligationCauseCode::ObjectTypeBound(..) => {}
ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id, .. } => {
Expand Down Expand Up @@ -5972,7 +5973,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
/// | | `Iterator::Item` is `&mut Vec<u8>` here
/// | this expression has type `Vec<Vec<u8>>`
/// ```
fn point_at_chain_in_return_position(
pub fn point_at_chain_in_return_position(
&self,
body_def_id: LocalDefId,
expr: &hir::Expr<'_>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ error[E0271]: type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()`
--> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:29:43
|
LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- `()` returned here
| |
| type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()`
|
note: types differ
--> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:28:36
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0271]: expected `foo` to return `i32`, but it returns `()`
--> $DIR/issue-106991.rs:5:13
--> $DIR/issue-106991.rs:8:13
|
LL | fn bar() -> impl Iterator<Item = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `()`
Expand All @@ -9,7 +9,7 @@ LL | x.iter_mut().map(foo)
|
= note: required for `Map<std::slice::IterMut<'_, Vec<u8>>, for<'a> fn(&'a mut Vec<u8>) {foo}>` to implement `Iterator`
note: the method call chain might not have had the expected associated types
--> $DIR/issue-106991.rs:8:18
--> $DIR/issue-106991.rs:12:18
|
LL | let mut x: Vec<Vec<u8>> = vec![vec![0, 2, 1], vec![5, 4, 3]];
| ---------------------------------- this expression has type `Vec<Vec<u8>>`
Expand All @@ -18,6 +18,15 @@ LL | x.iter_mut().map(foo)
| |
| `Iterator::Item` is `&mut Vec<u8>` here

error: aborting due to 1 previous error
error[E0271]: expected `IterMut<'_, Vec<u8>>` to be an iterator that yields `i32`, but it yields `&mut Vec<u8>`
--> $DIR/issue-106991.rs:15:13
|
LL | fn baz() -> impl Iterator<Item = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `&mut Vec<u8>`
|
= note: expected type `i32`
found mutable reference `&mut Vec<u8>`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0271`.
45 changes: 45 additions & 0 deletions tests/ui/lint/issue-106991.next.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
error[E0271]: expected `Map<IterMut<'_, Vec<u8>>, fn(&mut Vec<u8>) {foo}>` to be an iterator that yields `i32`, but it yields `()`
--> $DIR/issue-106991.rs:8:13
|
LL | fn bar() -> impl Iterator<Item = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `()`
...
LL | x.iter_mut().map(foo)
| --------------------- `Map<std::slice::IterMut<'_, Vec<u8>>, for<'a> fn(&'a mut Vec<u8>) {foo}>` returned here
|
note: the method call chain might not have had the expected associated types
--> $DIR/issue-106991.rs:12:18
|
LL | let mut x: Vec<Vec<u8>> = vec![vec![0, 2, 1], vec![5, 4, 3]];
| ---------------------------------- this expression has type `Vec<Vec<u8>>`
LL | x.iter_mut().map(foo)
| ---------- ^^^^^^^^ `Iterator::Item` changed to `()` here
| |
| `Iterator::Item` is `&mut Vec<u8>` here

error[E0271]: expected `IterMut<'_, Vec<u8>>` to be an iterator that yields `i32`, but it yields `&mut Vec<u8>`
--> $DIR/issue-106991.rs:15:13
|
LL | fn baz() -> impl Iterator<Item = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `&mut Vec<u8>`
...
LL | return x.iter_mut();
| ------------ `std::slice::IterMut<'_, Vec<u8>>` returned here
LL | }
LL | x.iter_mut()
| ------------ value returned here
|
note: the method call chain might not have had the expected associated types
--> $DIR/issue-106991.rs:20:18
|
LL | let mut x: Vec<Vec<u8>> = vec![vec![0, 2, 1], vec![5, 4, 3]];
| ---------------------------------- this expression has type `Vec<Vec<u8>>`
LL | if true {
LL | return x.iter_mut();
| ^^^^^^^^^^ `Iterator::Item` is `&mut Vec<u8>` here
= note: expected type `i32`
found mutable reference `&mut Vec<u8>`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0271`.
16 changes: 15 additions & 1 deletion tests/ui/lint/issue-106991.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
//@revisions: current next
//@[next] compile-flags: -Znext-solver=globally

fn foo(items: &mut Vec<u8>) {
items.sort();
}

fn bar() -> impl Iterator<Item = i32> {
//~^ ERROR expected `foo` to return `i32`, but it returns `()` [E0271]
//[current]~^ ERROR: expected `foo` to return `i32`, but it returns `()` [E0271]
//[next]~^^ ERROR: expected `Map<IterMut<'_, Vec<u8>>, fn(&mut Vec<u8>) {foo}>` to be an iterator that yields `i32`, but it yields `()`
let mut x: Vec<Vec<u8>> = vec![vec![0, 2, 1], vec![5, 4, 3]];
x.iter_mut().map(foo)
}

fn baz() -> impl Iterator<Item = i32> {
//[current]~^ ERROR: expected `IterMut<'_, Vec<u8>>` to be an iterator that yields `i32`, but it yields `&mut Vec<u8>`
//[next]~^^ ERROR: expected `IterMut<'_, Vec<u8>>` to be an iterator that yields `i32`, but it yields `&mut Vec<u8>`
let mut x: Vec<Vec<u8>> = vec![vec![0, 2, 1], vec![5, 4, 3]];
if true {
return x.iter_mut();
}
x.iter_mut()
}

fn main() {
bar();
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ LL | fn build<'a>(&mut self, commands: impl Iterator + 'a) -> impl Iterator
| ------------------ ^^^^^^^^^^^^^^^^^^ expected `&mut Self`, found type parameter `impl Iterator + 'a`
| |
| found this type parameter
...
LL | self.build(further_commands)
| ---------------------------- `impl Iterator + '_` returned here
|
= note: expected associated type `impl Iterator + '_`
found associated type `impl Iterator + 'a`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ LL | type Foo<V> = impl std::fmt::Debug;
= note: `Foo` must be used in combination with a concrete type within the same crate

error[E0277]: the trait bound `(): Identity<Q>` is not satisfied
--> $DIR/orphanck-tait-with-projection-arg.rs:11:14
--> $DIR/orphanck-tait-with-projection-arg.rs:11:24
|
LL | fn clone(&self) -> Self {
| ^^^^^ the trait `Identity<Q>` is not implemented for `()`
| ^^^^ the trait `Identity<Q>` is not implemented for `()`
|
help: this trait has no implementations, consider adding one
--> $DIR/orphanck-tait-with-projection-arg.rs:5:1
Expand Down
Loading