Auto merge of #41547 - alexeyzab:41425-fix-mismatched-types-error-message, r=arielb1

Fix error message for mismatched types

This addresses #41425 by implementing the changes mentioned in the
following comment:
https://github.com/rust-lang/rust/issues/41425#issuecomment-296754508
This commit is contained in:
bors 2017-05-02 12:11:54 +00:00
commit 96e2c34286
5 changed files with 62 additions and 12 deletions

View File

@ -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,

View File

@ -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
@ -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
@ -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
@ -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
@ -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

View File

@ -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);
@ -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
@ -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
}
@ -4154,6 +4154,9 @@ 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) {
@ -4161,7 +4164,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
expected_ty,
err);
}
});
}, false);
}
}
});

View File

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

View File

@ -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