Skip to content

Commit

Permalink
Auto merge of rust-lang#41547 - alexeyzab:41425-fix-mismatched-types-…
Browse files Browse the repository at this point in the history
…error-message, r=arielb1

Fix error message for mismatched types

This addresses rust-lang#41425 by implementing the changes mentioned in the
following comment:
rust-lang#41425 (comment)
  • Loading branch information
bors committed May 2, 2017
2 parents 50517d5 + c741bc8 commit 96e2c34
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 12 deletions.
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if is_if_let_fallback {
let cause = self.cause(expr.span, ObligationCauseCode::IfExpressionWithNoElse);
assert!(arm_ty.is_nil());
coercion.coerce_forced_unit(self, &cause, &mut |_| ());
coercion.coerce_forced_unit(self, &cause, &mut |_| (), true);
} else {
let cause = self.cause(expr.span, ObligationCauseCode::MatchExpressionArm {
arm_span: arm.body.span,
Expand Down
22 changes: 15 additions & 7 deletions src/librustc_typeck/check/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1001,7 +1001,12 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
expression_ty: Ty<'tcx>,
expression_diverges: Diverges)
{
self.coerce_inner(fcx, cause, Some(expression), expression_ty, expression_diverges, None)
self.coerce_inner(fcx,
cause,
Some(expression),
expression_ty,
expression_diverges,
None, false)
}

/// Indicates that one of the inputs is a "forced unit". This
Expand All @@ -1019,14 +1024,16 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
pub fn coerce_forced_unit<'a>(&mut self,
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
cause: &ObligationCause<'tcx>,
augment_error: &mut FnMut(&mut DiagnosticBuilder))
augment_error: &mut FnMut(&mut DiagnosticBuilder),
label_unit_as_expected: bool)
{
self.coerce_inner(fcx,
cause,
None,
fcx.tcx.mk_nil(),
Diverges::Maybe,
Some(augment_error))
Some(augment_error),
label_unit_as_expected)
}

/// The inner coercion "engine". If `expression` is `None`, this
Expand All @@ -1038,7 +1045,8 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
expression: Option<&'gcx hir::Expr>,
mut expression_ty: Ty<'tcx>,
expression_diverges: Diverges,
augment_error: Option<&mut FnMut(&mut DiagnosticBuilder)>)
augment_error: Option<&mut FnMut(&mut DiagnosticBuilder)>,
label_expression_as_expected: bool)
{
// Incorporate whatever type inference information we have
// until now; in principle we might also want to process
Expand Down Expand Up @@ -1096,7 +1104,7 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
// Another example is `break` with no argument expression.
assert!(expression_ty.is_nil());
assert!(expression_ty.is_nil(), "if let hack without unit type");
fcx.eq_types(true, cause, expression_ty, self.merged_ty())
fcx.eq_types(label_expression_as_expected, cause, expression_ty, self.merged_ty())
.map(|infer_ok| {
fcx.register_infer_ok_obligations(infer_ok);
expression_ty
Expand All @@ -1119,11 +1127,11 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
}
}
Err(err) => {
let (expected, found) = if expression.is_none() {
let (expected, found) = if label_expression_as_expected {
// In the case where this is a "forced unit", like
// `break`, we want to call the `()` "expected"
// since it is implied by the syntax.
assert!(expression_ty.is_nil());
// (Note: not all force-units work this way.)"
(expression_ty, self.final_ty.unwrap_or(self.expected_ty))
} else {
// Otherwise, the "expected" type for error
Expand Down
11 changes: 7 additions & 4 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2864,7 +2864,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.diverges.set(cond_diverges | then_diverges & else_diverges);
} else {
let else_cause = self.cause(sp, ObligationCauseCode::IfExpressionWithNoElse);
coerce.coerce_forced_unit(self, &else_cause, &mut |_| ());
coerce.coerce_forced_unit(self, &else_cause, &mut |_| (), true);

// If the condition is false we can't diverge.
self.diverges.set(cond_diverges);
Expand Down Expand Up @@ -3581,7 +3581,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
coerce.coerce(self, &cause, e, e_ty, e_diverges);
} else {
assert!(e_ty.is_nil());
coerce.coerce_forced_unit(self, &cause, &mut |_| ());
coerce.coerce_forced_unit(self, &cause, &mut |_| (), true);
}
} else {
// If `ctxt.coerce` is `None`, we can just ignore
Expand Down Expand Up @@ -3616,7 +3616,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
} else {
let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut();
let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression);
coercion.coerce_forced_unit(self, &cause, &mut |_| ());
coercion.coerce_forced_unit(self, &cause, &mut |_| (), true);
}
tcx.types.never
}
Expand Down Expand Up @@ -4154,14 +4154,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// expression (assuming there are no other breaks,
// this implies that the type of the block will be
// `!`).
//
// #41425 -- label the implicit `()` as being the
// "found type" here, rather than the "expected type".
if !self.diverges.get().always() {
coerce.coerce_forced_unit(self, &self.misc(blk.span), &mut |err| {
if let Some(expected_ty) = expected.only_has_type(self) {
self.consider_hint_about_removing_semicolon(blk,
expected_ty,
err);
}
});
}, false);
}
}
});
Expand Down
20 changes: 20 additions & 0 deletions src/test/ui/coercion-missing-tail-expected-type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// #41425 -- error message "mismatched types" has wrong types

fn plus_one(x: i32) -> i32 {
x + 1;
}

fn main() {
let x = plus_one(5);
println!("X = {}", x);
}
19 changes: 19 additions & 0 deletions src/test/ui/coercion-missing-tail-expected-type.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
error[E0308]: mismatched types
--> $DIR/coercion-missing-tail-expected-type.rs:13:28
|
13 | fn plus_one(x: i32) -> i32 {
| ____________________________^
14 | | x + 1;
15 | | }
| |_^ expected i32, found ()
|
= note: expected type `i32`
found type `()`
help: consider removing this semicolon:
--> $DIR/coercion-missing-tail-expected-type.rs:14:10
|
14 | x + 1;
| ^

error: aborting due to previous error

0 comments on commit 96e2c34

Please sign in to comment.