From dd906ef7ec33240af1a17dee4ac933f363c987b0 Mon Sep 17 00:00:00 2001 From: alexey zabelin Date: Tue, 25 Apr 2017 18:28:08 -0400 Subject: [PATCH] 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 --- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/coercion.rs | 17 ++++++++-------- src/librustc_typeck/check/mod.rs | 10 ++++++---- .../ui/coercion-missing-tail-expected-type.rs | 20 +++++++++++++++++++ ...coercion-missing-tail-expected-type.stderr | 19 ++++++++++++++++++ 5 files changed, 54 insertions(+), 14 deletions(-) create mode 100644 src/test/ui/coercion-missing-tail-expected-type.rs create mode 100644 src/test/ui/coercion-missing-tail-expected-type.stderr diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 1086773041c93..ac10dfd36e25d 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -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, diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index d21b5f739bd7b..5baa8fdb9a0c2 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -1001,7 +1001,7 @@ 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 +1019,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 +1040,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 @@ -1119,11 +1122,7 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> } } Err(err) => { - let (expected, found) = if expression.is_none() { - // 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()); + let (expected, found) = if label_expression_as_expected { (expression_ty, self.final_ty.unwrap_or(self.expected_ty)) } else { // Otherwise, the "expected" type for error diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 098e8c53a52c1..c64e27692be8d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2785,7 +2785,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); @@ -3502,7 +3502,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 @@ -3537,7 +3537,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 } @@ -4077,6 +4077,8 @@ 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) { @@ -4084,7 +4086,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expected_ty, err); } - }); + }, false); } } }); diff --git a/src/test/ui/coercion-missing-tail-expected-type.rs b/src/test/ui/coercion-missing-tail-expected-type.rs new file mode 100644 index 0000000000000..489ad817ea8b1 --- /dev/null +++ b/src/test/ui/coercion-missing-tail-expected-type.rs @@ -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 or the MIT license +// , 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); +} diff --git a/src/test/ui/coercion-missing-tail-expected-type.stderr b/src/test/ui/coercion-missing-tail-expected-type.stderr new file mode 100644 index 0000000000000..43222e36ec57e --- /dev/null +++ b/src/test/ui/coercion-missing-tail-expected-type.stderr @@ -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 (), found i32 + | + = 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 +