about summary refs log tree commit diff
diff options
context:
space:
mode:
authoralexey zabelin <zabelin.alex@gmail.com>2017-04-25 18:28:08 -0400
committeralexey zabelin <zabelin.alex@gmail.com>2017-04-25 18:28:08 -0400
commitdd906ef7ec33240af1a17dee4ac933f363c987b0 (patch)
treeda85ae6143684203b69ad1f41690d1f1e58ce14c
parent63c77214c1d38789652b465694b254205d1886e0 (diff)
downloadrust-dd906ef7ec33240af1a17dee4ac933f363c987b0.tar.gz
rust-dd906ef7ec33240af1a17dee4ac933f363c987b0.zip
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.rs17
-rw-r--r--src/librustc_typeck/check/mod.rs10
-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, 54 insertions, 14 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..5baa8fdb9a0 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 098e8c53a52..c64e27692be 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 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..43222e36ec5
--- /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
+