about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-05-02 12:11:54 +0000
committerbors <bors@rust-lang.org>2017-05-02 12:11:54 +0000
commit96e2c34286099eea4f51daaadbb82a8fbe99e0f6 (patch)
tree11b9c36039988c5b30c4ff443659e7f4e6c76ce6
parent50517d58a2f43779c27478baf77f938c0b3ebba0 (diff)
parentc741bc80320e18093a328fd36955a2d1bfae689b (diff)
downloadrust-96e2c34286099eea4f51daaadbb82a8fbe99e0f6.tar.gz
rust-96e2c34286099eea4f51daaadbb82a8fbe99e0f6.zip
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
-rw-r--r--src/librustc_typeck/check/_match.rs2
-rw-r--r--src/librustc_typeck/check/coercion.rs22
-rw-r--r--src/librustc_typeck/check/mod.rs11
-rw-r--r--src/test/ui/coercion-missing-tail-expected-type.rs20
-rw-r--r--src/test/ui/coercion-missing-tail-expected-type.stderr19
5 files changed, 62 insertions, 12 deletions
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 1086773041c..ac10dfd36e2 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 d21b5f739bd..57415021976 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -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
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 5a581788a21..9185b6ec7b1 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -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);
                 }
             }
         });
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 00000000000..489ad817ea8
--- /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 <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);
+}
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 00000000000..8f08ff34637
--- /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 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
+