]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #42850 - estebank:unwanted-return-rotj, r=nikomatsakis
authorbors <bors@rust-lang.org>
Wed, 28 Jun 2017 20:16:13 +0000 (20:16 +0000)
committerbors <bors@rust-lang.org>
Wed, 28 Jun 2017 20:16:13 +0000 (20:16 +0000)
Detect missing `;` on methods with return type `()`

 - Point out the origin of a type requirement when it is the return type
   of a method
 - Point out possibly missing semicolon when the return type is `()` and
   the implicit return makes sense as a statement
 - Suggest changing the return type of methods with default return type
 - Don't suggest changing the return type on `fn main()`
 - Don't suggest changing the return type on impl fn
 - Suggest removal of semicolon (instead of being help)

50 files changed:
src/librustc/hir/map/mod.rs
src/librustc/traits/error_reporting.rs
src/librustc/traits/mod.rs
src/librustc/traits/structural_impls.rs
src/librustc/ty/mod.rs
src/librustc_errors/emitter.rs
src/librustc_typeck/check/coercion.rs
src/librustc_typeck/check/demand.rs
src/librustc_typeck/check/mod.rs
src/test/compile-fail/block-must-not-have-result-do.rs [deleted file]
src/test/compile-fail/block-must-not-have-result-res.rs [deleted file]
src/test/compile-fail/block-must-not-have-result-while.rs [deleted file]
src/test/compile-fail/consider-removing-last-semi.rs [deleted file]
src/test/compile-fail/for-loop-has-unit-body.rs [deleted file]
src/test/compile-fail/issue-11714.rs [deleted file]
src/test/compile-fail/issue-13428.rs [deleted file]
src/test/compile-fail/issue-13624.rs [deleted file]
src/test/compile-fail/issue-20862.rs [deleted file]
src/test/compile-fail/issue-22645.rs [deleted file]
src/test/compile-fail/issue-3563.rs [deleted file]
src/test/compile-fail/issue-5500.rs [deleted file]
src/test/ui/block-result/block-must-not-have-result-do.rs [new file with mode: 0644]
src/test/ui/block-result/block-must-not-have-result-do.stderr [new file with mode: 0644]
src/test/ui/block-result/block-must-not-have-result-res.rs [new file with mode: 0644]
src/test/ui/block-result/block-must-not-have-result-res.stderr [new file with mode: 0644]
src/test/ui/block-result/block-must-not-have-result-while.rs [new file with mode: 0644]
src/test/ui/block-result/block-must-not-have-result-while.stderr [new file with mode: 0644]
src/test/ui/block-result/consider-removing-last-semi.rs [new file with mode: 0644]
src/test/ui/block-result/consider-removing-last-semi.stderr [new file with mode: 0644]
src/test/ui/block-result/issue-11714.rs [new file with mode: 0644]
src/test/ui/block-result/issue-11714.stderr [new file with mode: 0644]
src/test/ui/block-result/issue-13428.rs [new file with mode: 0644]
src/test/ui/block-result/issue-13428.stderr [new file with mode: 0644]
src/test/ui/block-result/issue-13624.rs [new file with mode: 0644]
src/test/ui/block-result/issue-13624.stderr [new file with mode: 0644]
src/test/ui/block-result/issue-20862.rs [new file with mode: 0644]
src/test/ui/block-result/issue-20862.stderr [new file with mode: 0644]
src/test/ui/block-result/issue-22645.rs [new file with mode: 0644]
src/test/ui/block-result/issue-22645.stderr [new file with mode: 0644]
src/test/ui/block-result/issue-3563.rs [new file with mode: 0644]
src/test/ui/block-result/issue-3563.stderr [new file with mode: 0644]
src/test/ui/block-result/issue-5500.rs [new file with mode: 0644]
src/test/ui/block-result/issue-5500.stderr [new file with mode: 0644]
src/test/ui/block-result/unexpected-return-on-unit.rs [new file with mode: 0644]
src/test/ui/block-result/unexpected-return-on-unit.stderr [new file with mode: 0644]
src/test/ui/coercion-missing-tail-expected-type.stderr
src/test/ui/mismatched_types/for-loop-has-unit-body.rs [new file with mode: 0644]
src/test/ui/mismatched_types/for-loop-has-unit-body.stderr [new file with mode: 0644]
src/test/ui/mismatched_types/issue-19109.stderr
src/test/ui/resolve/token-error-correct-3.stderr

index a1875cd46a0cb85932408b67796861d2c989d3bb..02a36a372d9ef3354aab83d9e93dcb9afa1039fc 100644 (file)
@@ -594,8 +594,12 @@ pub fn is_argument(&self, id: NodeId) -> bool {
     /// last good node id we found. Note that reaching the crate root (id == 0),
     /// is not an error, since items in the crate module have the crate root as
     /// parent.
-    fn walk_parent_nodes<F>(&self, start_id: NodeId, found: F) -> Result<NodeId, NodeId>
-        where F: Fn(&Node<'hir>) -> bool
+    fn walk_parent_nodes<F, F2>(&self,
+                                start_id: NodeId,
+                                found: F,
+                                bail_early: F2)
+        -> Result<NodeId, NodeId>
+        where F: Fn(&Node<'hir>) -> bool, F2: Fn(&Node<'hir>) -> bool
     {
         let mut id = start_id;
         loop {
@@ -616,6 +620,8 @@ fn walk_parent_nodes<F>(&self, start_id: NodeId, found: F) -> Result<NodeId, Nod
                 Some(ref node) => {
                     if found(node) {
                         return Ok(parent_node);
+                    } else if bail_early(node) {
+                        return Err(parent_node);
                     }
                 }
                 None => {
@@ -626,6 +632,56 @@ fn walk_parent_nodes<F>(&self, start_id: NodeId, found: F) -> Result<NodeId, Nod
         }
     }
 
+    /// Retrieve the NodeId for `id`'s enclosing method, unless there's a
+    /// `while` or `loop` before reacing it, as block tail returns are not
+    /// available in them.
+    ///
+    /// ```
+    /// fn foo(x: usize) -> bool {
+    ///     if x == 1 {
+    ///         true  // `get_return_block` gets passed the `id` corresponding
+    ///     } else {  // to this, it will return `foo`'s `NodeId`.
+    ///         false
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// ```
+    /// fn foo(x: usize) -> bool {
+    ///     loop {
+    ///         true  // `get_return_block` gets passed the `id` corresponding
+    ///     }         // to this, it will return `None`.
+    ///     false
+    /// }
+    /// ```
+    pub fn get_return_block(&self, id: NodeId) -> Option<NodeId> {
+        let match_fn = |node: &Node| {
+            match *node {
+                NodeItem(_) |
+                NodeForeignItem(_) |
+                NodeTraitItem(_) |
+                NodeImplItem(_) => true,
+                _ => false,
+            }
+        };
+        let match_non_returning_block = |node: &Node| {
+            match *node {
+                NodeExpr(ref expr) => {
+                    match expr.node {
+                        ExprWhile(..) | ExprLoop(..) => true,
+                        _ => false,
+                    }
+                }
+                _ => false,
+            }
+        };
+
+        match self.walk_parent_nodes(id, match_fn, match_non_returning_block) {
+            Ok(id) => Some(id),
+            Err(_) => None,
+        }
+    }
+
     /// Retrieve the NodeId for `id`'s parent item, or `id` itself if no
     /// parent item is in this map. The "parent item" is the closest parent node
     /// in the AST which is recorded by the map and is an item, either an item
@@ -637,7 +693,7 @@ pub fn get_parent(&self, id: NodeId) -> NodeId {
             NodeTraitItem(_) |
             NodeImplItem(_) => true,
             _ => false,
-        }) {
+        }, |_| false) {
             Ok(id) => id,
             Err(id) => id,
         }
@@ -649,7 +705,7 @@ pub fn get_module_parent(&self, id: NodeId) -> DefId {
         let id = match self.walk_parent_nodes(id, |node| match *node {
             NodeItem(&Item { node: Item_::ItemMod(_), .. }) => true,
             _ => false,
-        }) {
+        }, |_| false) {
             Ok(id) => id,
             Err(id) => id,
         };
@@ -668,7 +724,7 @@ pub fn get_enclosing_scope(&self, id: NodeId) -> Option<NodeId> {
             NodeImplItem(_) |
             NodeBlock(_) => true,
             _ => false,
-        }) {
+        }, |_| false) {
             Ok(id) => Some(id),
             Err(_) => None,
         }
index 247fb079fe7ee68d0d3ac4204d299cf81ea550dc..2f260b0b9ee1fca233a32f6a4c52a6a1441d645e 100644 (file)
@@ -1088,7 +1088,7 @@ fn note_obligation_cause_code<T>(&self,
             ObligationCauseCode::VariableType(_) => {
                 err.note("all local variables must have a statically known size");
             }
-            ObligationCauseCode::ReturnType => {
+            ObligationCauseCode::SizedReturnType => {
                 err.note("the return type of a function must have a \
                           statically known size");
             }
@@ -1133,6 +1133,8 @@ fn note_obligation_cause_code<T>(&self,
                               but not on the corresponding trait method",
                              predicate));
             }
+            ObligationCauseCode::ReturnType(_) |
+            ObligationCauseCode::BlockTailExpression(_) => (),
         }
     }
 
index e9196cd12431bc825b13e3ffde7bf5edd5a883f4..a98be90e3a0f11876b08199025ed00382c823d82 100644 (file)
@@ -118,27 +118,32 @@ pub enum ObligationCauseCode<'tcx> {
     /// Obligation incurred due to an object cast.
     ObjectCastObligation(/* Object type */ Ty<'tcx>),
 
-    /// Various cases where expressions must be sized/copy/etc:
-    AssignmentLhsSized,        // L = X implies that L is Sized
-    StructInitializerSized,    // S { ... } must be Sized
-    VariableType(ast::NodeId), // Type of each variable must be Sized
-    ReturnType,                // Return type must be Sized
-    RepeatVec,                 // [T,..n] --> T must be Copy
-
-    // Types of fields (other than the last) in a struct must be sized.
+    // Various cases where expressions must be sized/copy/etc:
+    /// L = X implies that L is Sized
+    AssignmentLhsSized,
+    /// S { ... } must be Sized
+    StructInitializerSized,
+    /// Type of each variable must be Sized
+    VariableType(ast::NodeId),
+    /// Return type must be Sized
+    SizedReturnType,
+    /// [T,..n] --> T must be Copy
+    RepeatVec,
+
+    /// Types of fields (other than the last) in a struct must be sized.
     FieldSized,
 
-    // Constant expressions must be sized.
+    /// Constant expressions must be sized.
     ConstSized,
 
-    // static items must have `Sync` type
+    /// static items must have `Sync` type
     SharedStatic,
 
     BuiltinDerivedObligation(DerivedObligationCause<'tcx>),
 
     ImplDerivedObligation(DerivedObligationCause<'tcx>),
 
-    // error derived when matching traits/impls; see ObligationCause for more details
+    /// error derived when matching traits/impls; see ObligationCause for more details
     CompareImplMethodObligation {
         item_name: ast::Name,
         impl_item_def_id: DefId,
@@ -146,37 +151,43 @@ pub enum ObligationCauseCode<'tcx> {
         lint_id: Option<ast::NodeId>,
     },
 
-    // Checking that this expression can be assigned where it needs to be
+    /// Checking that this expression can be assigned where it needs to be
     // FIXME(eddyb) #11161 is the original Expr required?
     ExprAssignable,
 
-    // Computing common supertype in the arms of a match expression
+    /// Computing common supertype in the arms of a match expression
     MatchExpressionArm { arm_span: Span,
                          source: hir::MatchSource },
 
-    // Computing common supertype in an if expression
+    /// Computing common supertype in an if expression
     IfExpression,
 
-    // Computing common supertype of an if expression with no else counter-part
+    /// Computing common supertype of an if expression with no else counter-part
     IfExpressionWithNoElse,
 
-    // `where a == b`
+    /// `where a == b`
     EquatePredicate,
 
-    // `main` has wrong type
+    /// `main` has wrong type
     MainFunctionType,
 
-    // `start` has wrong type
+    /// `start` has wrong type
     StartFunctionType,
 
-    // intrinsic has wrong type
+    /// intrinsic has wrong type
     IntrinsicType,
 
-    // method receiver
+    /// method receiver
     MethodReceiver,
 
-    // `return` with no expression
+    /// `return` with no expression
     ReturnNoExpression,
+
+    /// `return` with an expression
+    ReturnType(ast::NodeId),
+
+    /// Block implicit return
+    BlockTailExpression(ast::NodeId),
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
index 4abb0cb549db45add7ce5f917660a282bc030f72..0d6df78c2ac5b88a0b4dd62a74b5768226a157b7 100644 (file)
@@ -191,7 +191,8 @@ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lif
             super::AssignmentLhsSized => Some(super::AssignmentLhsSized),
             super::StructInitializerSized => Some(super::StructInitializerSized),
             super::VariableType(id) => Some(super::VariableType(id)),
-            super::ReturnType => Some(super::ReturnType),
+            super::ReturnType(id) => Some(super::ReturnType(id)),
+            super::SizedReturnType => Some(super::SizedReturnType),
             super::RepeatVec => Some(super::RepeatVec),
             super::FieldSized => Some(super::FieldSized),
             super::ConstSized => Some(super::ConstSized),
@@ -213,34 +214,19 @@ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lif
                     lint_id: lint_id,
                 })
             }
-            super::ExprAssignable => {
-                Some(super::ExprAssignable)
-            }
+            super::ExprAssignable => Some(super::ExprAssignable),
             super::MatchExpressionArm { arm_span, source } => {
                 Some(super::MatchExpressionArm { arm_span: arm_span,
                                                  source: source })
             }
-            super::IfExpression => {
-                Some(super::IfExpression)
-            }
-            super::IfExpressionWithNoElse => {
-                Some(super::IfExpressionWithNoElse)
-            }
-            super::EquatePredicate => {
-                Some(super::EquatePredicate)
-            }
-            super::MainFunctionType => {
-                Some(super::MainFunctionType)
-            }
-            super::StartFunctionType => {
-                Some(super::StartFunctionType)
-            }
-            super::IntrinsicType => {
-                Some(super::IntrinsicType)
-            }
-            super::MethodReceiver => {
-                Some(super::MethodReceiver)
-            }
+            super::IfExpression => Some(super::IfExpression),
+            super::IfExpressionWithNoElse => Some(super::IfExpressionWithNoElse),
+            super::EquatePredicate => Some(super::EquatePredicate),
+            super::MainFunctionType => Some(super::MainFunctionType),
+            super::StartFunctionType => Some(super::StartFunctionType),
+            super::IntrinsicType => Some(super::IntrinsicType),
+            super::MethodReceiver => Some(super::MethodReceiver),
+            super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)),
         }
     }
 }
@@ -492,12 +478,14 @@ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
             super::AssignmentLhsSized |
             super::StructInitializerSized |
             super::VariableType(_) |
-            super::ReturnType |
+            super::ReturnType(_) |
+            super::SizedReturnType |
             super::ReturnNoExpression |
             super::RepeatVec |
             super::FieldSized |
             super::ConstSized |
             super::SharedStatic |
+            super::BlockTailExpression(_) |
             super::CompareImplMethodObligation { .. } => self.clone(),
 
             super::ProjectionWf(proj) => super::ProjectionWf(proj.fold_with(folder)),
@@ -537,12 +525,14 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
             super::AssignmentLhsSized |
             super::StructInitializerSized |
             super::VariableType(_) |
-            super::ReturnType |
+            super::ReturnType(_) |
+            super::SizedReturnType |
             super::ReturnNoExpression |
             super::RepeatVec |
             super::FieldSized |
             super::ConstSized |
             super::SharedStatic |
+            super::BlockTailExpression(_) |
             super::CompareImplMethodObligation { .. } => false,
 
             super::ProjectionWf(proj) => proj.visit_with(visitor),
index f4d0867d130001846310f4bf0ce373ed5ad96ff1..548ee7bcbe503eb743630f388d4ec970fd177046 100644 (file)
@@ -481,6 +481,18 @@ pub fn is_primitive_ty(&self) -> bool {
             _ => false,
         }
     }
+
+    pub fn is_suggestable(&self) -> bool {
+        match self.sty {
+            TypeVariants::TyAnon(..) |
+            TypeVariants::TyFnDef(..) |
+            TypeVariants::TyFnPtr(..) |
+            TypeVariants::TyDynamic(..) |
+            TypeVariants::TyClosure(..) |
+            TypeVariants::TyProjection(..) => false,
+            _ => true,
+        }
+    }
 }
 
 impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::TyS<'tcx> {
index 2d25d12d3a96e437ffec77d1a8b655498207ab18..4b71aa6b85f1c91c24f8dd0ea3a19fed0da9bf70 100644 (file)
@@ -47,7 +47,12 @@ fn emit(&mut self, db: &DiagnosticBuilder) {
                // don't display multiline suggestions as labels
                sugg.substitution_parts[0].substitutions[0].find('\n').is_none() {
                 let substitution = &sugg.substitution_parts[0].substitutions[0];
-                let msg = format!("help: {} `{}`", sugg.msg, substitution);
+                let msg = if substitution.len() == 0 {
+                    // This substitution is only removal, don't show it
+                    format!("help: {}", sugg.msg)
+                } else {
+                    format!("help: {} `{}`", sugg.msg, substitution)
+                };
                 primary_span.push_span_label(sugg.substitution_spans().next().unwrap(), msg);
             } else {
                 // if there are multiple suggestions, print them all in full
index 17d02223716827e7fbf3530496abaabdf0fb648a..81aa59e956abf40cb8fca6dc9612caae4fb9ec95 100644 (file)
@@ -1168,6 +1168,18 @@ fn coerce_inner<'a>(&mut self,
                             "`return;` in a function whose return type is not `()`");
                         db.span_label(cause.span, "return type is not ()");
                     }
+                    ObligationCauseCode::BlockTailExpression(blk_id) => {
+                        db = fcx.report_mismatched_types(cause, expected, found, err);
+
+                        let expr = expression.unwrap_or_else(|| {
+                            span_bug!(cause.span,
+                                      "supposed to be part of a block tail expression, but the \
+                                       expression is empty");
+                        });
+                        fcx.suggest_mismatched_types_on_tail(&mut db, expr,
+                                                             expected, found,
+                                                             cause.span, blk_id);
+                    }
                     _ => {
                         db = fcx.report_mismatched_types(cause, expected, found, err);
                     }
index 287c591c1183d5e12f12fb9461b439b5995f6169..f54ad54187267fd6d96ee6f48a22c9de61ad573a 100644 (file)
@@ -73,15 +73,21 @@ pub fn demand_eqtype_with_origin(&self,
         }
     }
 
+    pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>) {
+        if let Some(mut err) = self.demand_coerce_diag(expr, checked_ty, expected) {
+            err.emit();
+        }
+    }
+
     // Checks that the type of `expr` can be coerced to `expected`.
     //
     // NB: This code relies on `self.diverges` to be accurate.  In
     // particular, assignments to `!` will be permitted if the
     // diverges flag is currently "always".
-    pub fn demand_coerce(&self,
-                         expr: &hir::Expr,
-                         checked_ty: Ty<'tcx>,
-                         expected: Ty<'tcx>) {
+    pub fn demand_coerce_diag(&self,
+                              expr: &hir::Expr,
+                              checked_ty: Ty<'tcx>,
+                              expected: Ty<'tcx>) -> Option<DiagnosticBuilder<'tcx>> {
         let expected = self.resolve_type_vars_with_obligations(expected);
 
         if let Err(e) = self.try_coerce(expr, checked_ty, self.diverges.get(), expected) {
@@ -105,8 +111,9 @@ pub fn demand_coerce(&self,
                                       self.get_best_match(&suggestions).join("\n")));
                 }
             }
-            err.emit();
+            return Some(err);
         }
+        None
     }
 
     fn format_method_suggestion(&self, method: &AssociatedItem) -> String {
index 701de029b2bd5362bf9941574246d416eb3ab70d..dd488f0c4fe93e4aec58ad387ad4cf27e00bbc40 100644 (file)
 
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
+use rustc::hir::map::Node;
 use rustc::hir::{self, PatKind};
 use rustc::middle::lang_items;
 use rustc_back::slice;
@@ -977,7 +978,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id);
 
     let ret_ty = fn_sig.output();
-    fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType);
+    fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::SizedReturnType);
     let ret_ty = fcx.instantiate_anon_types(&ret_ty);
     fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
     fn_sig = fcx.tcx.mk_fn_sig(
@@ -1900,7 +1901,7 @@ fn instantiate_anon_types<T: TypeFoldable<'tcx>>(&self, value: &T) -> T {
 
                     // Require that the predicate holds for the concrete type.
                     let cause = traits::ObligationCause::new(span, self.body_id,
-                                                             traits::ReturnType);
+                                                             traits::SizedReturnType);
                     self.register_predicate(traits::Obligation::new(cause,
                                                                     self.param_env,
                                                                     predicate));
@@ -2839,10 +2840,11 @@ fn check_return_expr(&self, return_expr: &'gcx hir::Expr) {
                                              "check_return_expr called outside fn body"));
 
         let ret_ty = ret_coercion.borrow().expected_ty();
-        let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty);
+        let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty.clone());
         ret_coercion.borrow_mut()
                     .coerce(self,
-                            &self.misc(return_expr.span),
+                            &self.cause(return_expr.span,
+                                        ObligationCauseCode::ReturnType(return_expr.id)),
                             return_expr,
                             return_expr_ty,
                             self.diverges.get());
@@ -4161,8 +4163,10 @@ fn check_block_with_expected(&self,
             let mut coerce = ctxt.coerce.as_mut().unwrap();
             if let Some(tail_expr_ty) = tail_expr_ty {
                 let tail_expr = tail_expr.unwrap();
+                let cause = self.cause(tail_expr.span,
+                                       ObligationCauseCode::BlockTailExpression(blk.id));
                 coerce.coerce(self,
-                              &self.misc(tail_expr.span),
+                              &cause,
                               tail_expr,
                               tail_expr_ty,
                               self.diverges.get());
@@ -4201,6 +4205,130 @@ fn check_block_with_expected(&self,
         ty
     }
 
+    /// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether it is
+    /// `fn main` if it is a method, `None` otherwise.
+    pub fn get_fn_decl(&self, blk_id: ast::NodeId) -> Option<(hir::FnDecl, bool)> {
+        // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
+        // `while` before reaching it, as block tail returns are not available in them.
+        if let Some(fn_id) = self.tcx.hir.get_return_block(blk_id) {
+            let parent = self.tcx.hir.get(fn_id);
+
+            if let Node::NodeItem(&hir::Item {
+                name, node: hir::ItemFn(ref decl, ..), ..
+            }) = parent {
+                decl.clone().and_then(|decl| {
+                    // This is less than ideal, it will not present the return type span on any
+                    // method called `main`, regardless of whether it is actually the entry point.
+                    Some((decl, name == Symbol::intern("main")))
+                })
+            } else if let Node::NodeTraitItem(&hir::TraitItem {
+                node: hir::TraitItemKind::Method(hir::MethodSig {
+                    ref decl, ..
+                }, ..), ..
+            }) = parent {
+                decl.clone().and_then(|decl| {
+                    Some((decl, false))
+                })
+            } else {
+                None
+            }
+        } else {
+            None
+        }
+    }
+
+    /// On implicit return expressions with mismatched types, provide the following suggestions:
+    ///
+    ///  - Point out the method's return type as the reason for the expected type
+    ///  - Possible missing semicolon
+    ///  - Possible missing return type if the return type is the default, and not `fn main()`
+    pub fn suggest_mismatched_types_on_tail(&self,
+                                            err: &mut DiagnosticBuilder<'tcx>,
+                                            expression: &'gcx hir::Expr,
+                                            expected: Ty<'tcx>,
+                                            found: Ty<'tcx>,
+                                            cause_span: Span,
+                                            blk_id: ast::NodeId) {
+        self.suggest_missing_semicolon(err, expression, expected, cause_span);
+
+        if let Some((fn_decl, is_main)) = self.get_fn_decl(blk_id) {
+            // `fn main()` must return `()`, do not suggest changing return type
+            if !is_main {
+                self.suggest_missing_return_type(err, &fn_decl, found);
+            }
+        }
+    }
+
+    /// A common error is to forget to add a semicolon at the end of a block:
+    ///
+    /// ```
+    /// fn foo() {
+    ///     bar_that_returns_u32()
+    /// }
+    /// ```
+    ///
+    /// This routine checks if the return expression in a block would make sense on its own as a
+    /// statement and the return type has been left as defaultor has been specified as `()`. If so,
+    /// it suggests adding a semicolon.
+    fn suggest_missing_semicolon(&self,
+                                     err: &mut DiagnosticBuilder<'tcx>,
+                                     expression: &'gcx hir::Expr,
+                                     expected: Ty<'tcx>,
+                                     cause_span: Span) {
+        if expected.is_nil() {
+            // `BlockTailExpression` only relevant if the tail expr would be
+            // useful on its own.
+            match expression.node {
+                hir::ExprCall(..) |
+                hir::ExprMethodCall(..) |
+                hir::ExprIf(..) |
+                hir::ExprWhile(..) |
+                hir::ExprLoop(..) |
+                hir::ExprMatch(..) |
+                hir::ExprBlock(..) => {
+                    let sp = cause_span.next_point();
+                    err.span_suggestion(sp,
+                                        "did you mean to add a semicolon here?",
+                                        ";".to_string());
+                }
+                _ => (),
+            }
+        }
+    }
+
+
+    /// A possible error is to forget to add a return type that is needed:
+    ///
+    /// ```
+    /// fn foo() {
+    ///     bar_that_returns_u32()
+    /// }
+    /// ```
+    ///
+    /// This routine checks if the return type is left as default, the method is not part of an
+    /// `impl` block and that it isn't the `main` method. If so, it suggests setting the return
+    /// type.
+    fn suggest_missing_return_type(&self,
+                                   err: &mut DiagnosticBuilder<'tcx>,
+                                   fn_decl: &hir::FnDecl,
+                                   ty: Ty<'tcx>) {
+
+        // Only recommend changing the return type for methods that
+        // haven't set a return type at all (and aren't `fn main()` or an impl).
+        if let &hir::FnDecl {
+            output: hir::FunctionRetTy::DefaultReturn(span), ..
+        } = fn_decl {
+            if ty.is_suggestable() {
+                err.span_suggestion(span,
+                                    "possibly return type missing here?",
+                                    format!("-> {} ", ty));
+            } else {
+                err.span_label(span, "possibly return type missing here?");
+            }
+        }
+    }
+
+
     /// A common error is to add an extra semicolon:
     ///
     /// ```
@@ -4236,7 +4364,7 @@ fn consider_hint_about_removing_semicolon(&self,
             hi: original_span.hi,
             ctxt: original_span.ctxt,
         };
-        err.span_help(span_semi, "consider removing this semicolon:");
+        err.span_suggestion(span_semi, "consider removing this semicolon", "".to_string());
     }
 
     // Instantiates the given path, which must refer to an item with the given
diff --git a/src/test/compile-fail/block-must-not-have-result-do.rs b/src/test/compile-fail/block-must-not-have-result-do.rs
deleted file mode 100644 (file)
index 2a6c71d..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2012 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.
-
-fn main() {
-    loop {
-        true //~  ERROR mismatched types
-    }
-}
diff --git a/src/test/compile-fail/block-must-not-have-result-res.rs b/src/test/compile-fail/block-must-not-have-result-res.rs
deleted file mode 100644 (file)
index 8728685..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2012 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.
-
-struct r;
-
-impl Drop for r {
-    fn drop(&mut self) {
-        true //~  ERROR mismatched types
-    }
-}
-
-fn main() {
-}
diff --git a/src/test/compile-fail/block-must-not-have-result-while.rs b/src/test/compile-fail/block-must-not-have-result-while.rs
deleted file mode 100644 (file)
index a0fb470..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2012 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.
-
-fn main() {
-    while true {
-        true //~  ERROR mismatched types
-             //~| expected type `()`
-             //~| found type `bool`
-             //~| expected (), found bool
-    }
-}
diff --git a/src/test/compile-fail/consider-removing-last-semi.rs b/src/test/compile-fail/consider-removing-last-semi.rs
deleted file mode 100644 (file)
index 530a0e4..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2016 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.
-
-fn f() -> String {  //~ ERROR mismatched types
-    0u8;
-    "bla".to_string();  //~ HELP consider removing this semicolon
-}
-
-fn g() -> String {  //~ ERROR mismatched types
-    "this won't work".to_string();
-    "removeme".to_string(); //~ HELP consider removing this semicolon
-}
-
-fn main() {}
diff --git a/src/test/compile-fail/for-loop-has-unit-body.rs b/src/test/compile-fail/for-loop-has-unit-body.rs
deleted file mode 100644 (file)
index 8c61fc6..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// 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.
-
-fn main() {
-    for x in 0..3 {
-        x //~ ERROR mismatched types
-        //~| NOTE expected ()
-        //~| NOTE expected type `()`
-    }
-}
diff --git a/src/test/compile-fail/issue-11714.rs b/src/test/compile-fail/issue-11714.rs
deleted file mode 100644 (file)
index 192f78e..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2014 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.
-
-fn blah() -> i32 { //~ ERROR mismatched types
-    1
-
-    ; //~ HELP consider removing this semicolon:
-}
-
-fn main() { }
diff --git a/src/test/compile-fail/issue-13428.rs b/src/test/compile-fail/issue-13428.rs
deleted file mode 100644 (file)
index 9406199..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2014 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.
-
-// Regression test for #13428
-
-fn foo() -> String {  //~ ERROR mismatched types
-    format!("Hello {}",
-            "world")
-    // Put the trailing semicolon on its own line to test that the
-    // note message gets the offending semicolon exactly
-    ;   //~ HELP consider removing this semicolon
-}
-
-fn bar() -> String {  //~ ERROR mismatched types
-    "foobar".to_string()
-    ;   //~ HELP consider removing this semicolon
-}
-
-pub fn main() {}
diff --git a/src/test/compile-fail/issue-13624.rs b/src/test/compile-fail/issue-13624.rs
deleted file mode 100644 (file)
index e4ed87c..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2014 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.
-
-mod a {
-  pub enum Enum {
-    EnumStructVariant { x: u8, y: u8, z: u8 }
-  }
-
-  pub fn get_enum_struct_variant() -> () {
-    Enum::EnumStructVariant { x: 1, y: 2, z: 3 }
-    //~^ ERROR mismatched types
-    //~| expected type `()`
-    //~| found type `a::Enum`
-    //~| expected (), found enum `a::Enum`
-  }
-}
-
-mod b {
-  mod test {
-    use a;
-
-    fn test_enum_struct_variant() {
-      let enum_struct_variant = ::a::get_enum_struct_variant();
-      match enum_struct_variant {
-        a::Enum::EnumStructVariant { x, y, z } => {
-        //~^ ERROR mismatched types
-        //~| expected type `()`
-        //~| found type `a::Enum`
-        //~| expected (), found enum `a::Enum`
-        }
-      }
-    }
-  }
-}
-
-fn main() {}
diff --git a/src/test/compile-fail/issue-20862.rs b/src/test/compile-fail/issue-20862.rs
deleted file mode 100644 (file)
index 9df6358..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2015 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.
-
-fn foo(x: i32) {
-    |y| x + y
-//~^ ERROR: mismatched types
-}
-
-fn main() {
-    let x = foo(5)(2);
-//~^ ERROR: expected function, found `()`
-}
diff --git a/src/test/compile-fail/issue-22645.rs b/src/test/compile-fail/issue-22645.rs
deleted file mode 100644 (file)
index 81f66e3..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2015 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.
-
-use std::ops::Add;
-
-trait Scalar {}
-impl Scalar for f64 {}
-
-struct Bob;
-
-impl<RHS: Scalar> Add <RHS> for Bob {
-  type Output = Bob;
-  fn add(self, rhs : RHS) -> Bob { Bob }
-}
-
-fn main() {
-  let b = Bob + 3.5;
-  b + 3 //~ ERROR E0277
-  //~^ ERROR: mismatched types
-}
diff --git a/src/test/compile-fail/issue-3563.rs b/src/test/compile-fail/issue-3563.rs
deleted file mode 100644 (file)
index 7928c04..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2012 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.
-
-trait A {
-    fn a(&self) {
-        || self.b()
-        //~^ ERROR no method named `b` found for type `&Self` in the current scope
-        //~| ERROR mismatched types
-    }
-}
-fn main() {}
diff --git a/src/test/compile-fail/issue-5500.rs b/src/test/compile-fail/issue-5500.rs
deleted file mode 100644 (file)
index 1cbb758..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2013 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.
-
-fn main() {
-    &panic!()
-    //~^ ERROR mismatched types
-    //~| expected type `()`
-    //~| found type `&_`
-    //~| expected (), found reference
-}
diff --git a/src/test/ui/block-result/block-must-not-have-result-do.rs b/src/test/ui/block-result/block-must-not-have-result-do.rs
new file mode 100644 (file)
index 0000000..2a6c71d
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2012 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.
+
+fn main() {
+    loop {
+        true //~  ERROR mismatched types
+    }
+}
diff --git a/src/test/ui/block-result/block-must-not-have-result-do.stderr b/src/test/ui/block-result/block-must-not-have-result-do.stderr
new file mode 100644 (file)
index 0000000..a770ebe
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> $DIR/block-must-not-have-result-do.rs:13:9
+   |
+13 |         true //~  ERROR mismatched types
+   |         ^^^^ expected (), found bool
+   |
+   = note: expected type `()`
+              found type `bool`
+
+error: aborting due to previous error(s)
+
diff --git a/src/test/ui/block-result/block-must-not-have-result-res.rs b/src/test/ui/block-result/block-must-not-have-result-res.rs
new file mode 100644 (file)
index 0000000..8728685
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2012 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.
+
+struct r;
+
+impl Drop for r {
+    fn drop(&mut self) {
+        true //~  ERROR mismatched types
+    }
+}
+
+fn main() {
+}
diff --git a/src/test/ui/block-result/block-must-not-have-result-res.stderr b/src/test/ui/block-result/block-must-not-have-result-res.stderr
new file mode 100644 (file)
index 0000000..b114686
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> $DIR/block-must-not-have-result-res.rs:15:9
+   |
+15 |         true //~  ERROR mismatched types
+   |         ^^^^ expected (), found bool
+   |
+   = note: expected type `()`
+              found type `bool`
+
+error: aborting due to previous error(s)
+
diff --git a/src/test/ui/block-result/block-must-not-have-result-while.rs b/src/test/ui/block-result/block-must-not-have-result-while.rs
new file mode 100644 (file)
index 0000000..a0fb470
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2012 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.
+
+fn main() {
+    while true {
+        true //~  ERROR mismatched types
+             //~| expected type `()`
+             //~| found type `bool`
+             //~| expected (), found bool
+    }
+}
diff --git a/src/test/ui/block-result/block-must-not-have-result-while.stderr b/src/test/ui/block-result/block-must-not-have-result-while.stderr
new file mode 100644 (file)
index 0000000..31ec7cd
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> $DIR/block-must-not-have-result-while.rs:13:9
+   |
+13 |         true //~  ERROR mismatched types
+   |         ^^^^ expected (), found bool
+   |
+   = note: expected type `()`
+              found type `bool`
+
+error: aborting due to previous error(s)
+
diff --git a/src/test/ui/block-result/consider-removing-last-semi.rs b/src/test/ui/block-result/consider-removing-last-semi.rs
new file mode 100644 (file)
index 0000000..530a0e4
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2016 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.
+
+fn f() -> String {  //~ ERROR mismatched types
+    0u8;
+    "bla".to_string();  //~ HELP consider removing this semicolon
+}
+
+fn g() -> String {  //~ ERROR mismatched types
+    "this won't work".to_string();
+    "removeme".to_string(); //~ HELP consider removing this semicolon
+}
+
+fn main() {}
diff --git a/src/test/ui/block-result/consider-removing-last-semi.stderr b/src/test/ui/block-result/consider-removing-last-semi.stderr
new file mode 100644 (file)
index 0000000..282583d
--- /dev/null
@@ -0,0 +1,30 @@
+error[E0308]: mismatched types
+  --> $DIR/consider-removing-last-semi.rs:11:18
+   |
+11 |   fn f() -> String {  //~ ERROR mismatched types
+   |  __________________^
+12 | |     0u8;
+13 | |     "bla".to_string();  //~ HELP consider removing this semicolon
+   | |                      - help: consider removing this semicolon
+14 | | }
+   | |_^ expected struct `std::string::String`, found ()
+   |
+   = note: expected type `std::string::String`
+              found type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/consider-removing-last-semi.rs:16:18
+   |
+16 |   fn g() -> String {  //~ ERROR mismatched types
+   |  __________________^
+17 | |     "this won't work".to_string();
+18 | |     "removeme".to_string(); //~ HELP consider removing this semicolon
+   | |                           - help: consider removing this semicolon
+19 | | }
+   | |_^ expected struct `std::string::String`, found ()
+   |
+   = note: expected type `std::string::String`
+              found type `()`
+
+error: aborting due to previous error(s)
+
diff --git a/src/test/ui/block-result/issue-11714.rs b/src/test/ui/block-result/issue-11714.rs
new file mode 100644 (file)
index 0000000..192f78e
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2014 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.
+
+fn blah() -> i32 { //~ ERROR mismatched types
+    1
+
+    ; //~ HELP consider removing this semicolon:
+}
+
+fn main() { }
diff --git a/src/test/ui/block-result/issue-11714.stderr b/src/test/ui/block-result/issue-11714.stderr
new file mode 100644 (file)
index 0000000..ed61ec6
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-11714.rs:11:18
+   |
+11 |   fn blah() -> i32 { //~ ERROR mismatched types
+   |  __________________^
+12 | |     1
+13 | |
+14 | |     ; //~ HELP consider removing this semicolon:
+   | |     - help: consider removing this semicolon
+15 | | }
+   | |_^ expected i32, found ()
+   |
+   = note: expected type `i32`
+              found type `()`
+
+error: aborting due to previous error(s)
+
diff --git a/src/test/ui/block-result/issue-13428.rs b/src/test/ui/block-result/issue-13428.rs
new file mode 100644 (file)
index 0000000..9406199
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2014 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.
+
+// Regression test for #13428
+
+fn foo() -> String {  //~ ERROR mismatched types
+    format!("Hello {}",
+            "world")
+    // Put the trailing semicolon on its own line to test that the
+    // note message gets the offending semicolon exactly
+    ;   //~ HELP consider removing this semicolon
+}
+
+fn bar() -> String {  //~ ERROR mismatched types
+    "foobar".to_string()
+    ;   //~ HELP consider removing this semicolon
+}
+
+pub fn main() {}
diff --git a/src/test/ui/block-result/issue-13428.stderr b/src/test/ui/block-result/issue-13428.stderr
new file mode 100644 (file)
index 0000000..5e8d92f
--- /dev/null
@@ -0,0 +1,33 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-13428.rs:13:20
+   |
+13 |   fn foo() -> String {  //~ ERROR mismatched types
+   |  ____________________^
+14 | |     format!("Hello {}",
+15 | |             "world")
+16 | |     // Put the trailing semicolon on its own line to test that the
+17 | |     // note message gets the offending semicolon exactly
+18 | |     ;   //~ HELP consider removing this semicolon
+   | |     - help: consider removing this semicolon
+19 | | }
+   | |_^ expected struct `std::string::String`, found ()
+   |
+   = note: expected type `std::string::String`
+              found type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-13428.rs:21:20
+   |
+21 |   fn bar() -> String {  //~ ERROR mismatched types
+   |  ____________________^
+22 | |     "foobar".to_string()
+23 | |     ;   //~ HELP consider removing this semicolon
+   | |     - help: consider removing this semicolon
+24 | | }
+   | |_^ expected struct `std::string::String`, found ()
+   |
+   = note: expected type `std::string::String`
+              found type `()`
+
+error: aborting due to previous error(s)
+
diff --git a/src/test/ui/block-result/issue-13624.rs b/src/test/ui/block-result/issue-13624.rs
new file mode 100644 (file)
index 0000000..e4ed87c
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2014 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.
+
+mod a {
+  pub enum Enum {
+    EnumStructVariant { x: u8, y: u8, z: u8 }
+  }
+
+  pub fn get_enum_struct_variant() -> () {
+    Enum::EnumStructVariant { x: 1, y: 2, z: 3 }
+    //~^ ERROR mismatched types
+    //~| expected type `()`
+    //~| found type `a::Enum`
+    //~| expected (), found enum `a::Enum`
+  }
+}
+
+mod b {
+  mod test {
+    use a;
+
+    fn test_enum_struct_variant() {
+      let enum_struct_variant = ::a::get_enum_struct_variant();
+      match enum_struct_variant {
+        a::Enum::EnumStructVariant { x, y, z } => {
+        //~^ ERROR mismatched types
+        //~| expected type `()`
+        //~| found type `a::Enum`
+        //~| expected (), found enum `a::Enum`
+        }
+      }
+    }
+  }
+}
+
+fn main() {}
diff --git a/src/test/ui/block-result/issue-13624.stderr b/src/test/ui/block-result/issue-13624.stderr
new file mode 100644 (file)
index 0000000..72ff859
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-13624.rs:17:5
+   |
+17 |     Enum::EnumStructVariant { x: 1, y: 2, z: 3 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found enum `a::Enum`
+   |
+   = note: expected type `()`
+              found type `a::Enum`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-13624.rs:32:9
+   |
+32 |         a::Enum::EnumStructVariant { x, y, z } => {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found enum `a::Enum`
+   |
+   = note: expected type `()`
+              found type `a::Enum`
+
+error: aborting due to previous error(s)
+
diff --git a/src/test/ui/block-result/issue-20862.rs b/src/test/ui/block-result/issue-20862.rs
new file mode 100644 (file)
index 0000000..9df6358
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2015 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.
+
+fn foo(x: i32) {
+    |y| x + y
+//~^ ERROR: mismatched types
+}
+
+fn main() {
+    let x = foo(5)(2);
+//~^ ERROR: expected function, found `()`
+}
diff --git a/src/test/ui/block-result/issue-20862.stderr b/src/test/ui/block-result/issue-20862.stderr
new file mode 100644 (file)
index 0000000..e4367f1
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-20862.rs:12:5
+   |
+11 | fn foo(x: i32) {
+   |                - possibly return type missing here?
+12 |     |y| x + y
+   |     ^^^^^^^^^ expected (), found closure
+   |
+   = note: expected type `()`
+              found type `[closure@$DIR/issue-20862.rs:12:5: 12:14 x:_]`
+
+error[E0618]: expected function, found `()`
+  --> $DIR/issue-20862.rs:17:13
+   |
+17 |     let x = foo(5)(2);
+   |             ^^^^^^^^^
+
+error: aborting due to previous error(s)
+
diff --git a/src/test/ui/block-result/issue-22645.rs b/src/test/ui/block-result/issue-22645.rs
new file mode 100644 (file)
index 0000000..81f66e3
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2015 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.
+
+use std::ops::Add;
+
+trait Scalar {}
+impl Scalar for f64 {}
+
+struct Bob;
+
+impl<RHS: Scalar> Add <RHS> for Bob {
+  type Output = Bob;
+  fn add(self, rhs : RHS) -> Bob { Bob }
+}
+
+fn main() {
+  let b = Bob + 3.5;
+  b + 3 //~ ERROR E0277
+  //~^ ERROR: mismatched types
+}
diff --git a/src/test/ui/block-result/issue-22645.stderr b/src/test/ui/block-result/issue-22645.stderr
new file mode 100644 (file)
index 0000000..3921a30
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0277]: the trait bound `{integer}: Scalar` is not satisfied
+  --> $DIR/issue-22645.rs:25:5
+   |
+25 |   b + 3 //~ ERROR E0277
+   |     ^ the trait `Scalar` is not implemented for `{integer}`
+   |
+   = help: the following implementations were found:
+             <f64 as Scalar>
+   = note: required because of the requirements on the impl of `std::ops::Add<{integer}>` for `Bob`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-22645.rs:25:3
+   |
+25 |   b + 3 //~ ERROR E0277
+   |   ^^^^^ expected (), found struct `Bob`
+   |
+   = note: expected type `()`
+              found type `Bob`
+
+error: aborting due to previous error(s)
+
diff --git a/src/test/ui/block-result/issue-3563.rs b/src/test/ui/block-result/issue-3563.rs
new file mode 100644 (file)
index 0000000..7928c04
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2012 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.
+
+trait A {
+    fn a(&self) {
+        || self.b()
+        //~^ ERROR no method named `b` found for type `&Self` in the current scope
+        //~| ERROR mismatched types
+    }
+}
+fn main() {}
diff --git a/src/test/ui/block-result/issue-3563.stderr b/src/test/ui/block-result/issue-3563.stderr
new file mode 100644 (file)
index 0000000..c6ab4cb
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0599]: no method named `b` found for type `&Self` in the current scope
+  --> $DIR/issue-3563.rs:13:17
+   |
+13 |         || self.b()
+   |                 ^
+
+error[E0308]: mismatched types
+  --> $DIR/issue-3563.rs:13:9
+   |
+12 |     fn a(&self) {
+   |                 - possibly return type missing here?
+13 |         || self.b()
+   |         ^^^^^^^^^^^ expected (), found closure
+   |
+   = note: expected type `()`
+              found type `[closure@$DIR/issue-3563.rs:13:9: 13:20 self:_]`
+
+error: aborting due to previous error(s)
+
diff --git a/src/test/ui/block-result/issue-5500.rs b/src/test/ui/block-result/issue-5500.rs
new file mode 100644 (file)
index 0000000..1cbb758
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2013 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.
+
+fn main() {
+    &panic!()
+    //~^ ERROR mismatched types
+    //~| expected type `()`
+    //~| found type `&_`
+    //~| expected (), found reference
+}
diff --git a/src/test/ui/block-result/issue-5500.stderr b/src/test/ui/block-result/issue-5500.stderr
new file mode 100644 (file)
index 0000000..bffe2a8
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-5500.rs:12:5
+   |
+12 |     &panic!()
+   |     ^^^^^^^^^ expected (), found reference
+   |
+   = note: expected type `()`
+              found type `&_`
+
+error: aborting due to previous error(s)
+
diff --git a/src/test/ui/block-result/unexpected-return-on-unit.rs b/src/test/ui/block-result/unexpected-return-on-unit.rs
new file mode 100644 (file)
index 0000000..291b7a1
--- /dev/null
@@ -0,0 +1,24 @@
+// 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.
+
+// Test that we do some basic error correcton in the tokeniser (and don't spew
+// too many bogus errors).
+
+fn foo() -> usize {
+    3
+}
+
+fn bar() {
+    foo()
+}
+
+fn main() {
+    bar()
+}
diff --git a/src/test/ui/block-result/unexpected-return-on-unit.stderr b/src/test/ui/block-result/unexpected-return-on-unit.stderr
new file mode 100644 (file)
index 0000000..18d0cc4
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0308]: mismatched types
+  --> $DIR/unexpected-return-on-unit.rs:19:5
+   |
+19 |     foo()
+   |     ^^^^^ expected (), found usize
+   |
+   = note: expected type `()`
+              found type `usize`
+help: did you mean to add a semicolon here?
+   |     foo();
+help: possibly return type missing here?
+   | fn bar() -> usize {
+
+error: aborting due to previous error(s)
+
index e96bc425e0b45fad9e2732758f5160d7cabec188..49e8b9febc2bb6a4e44bc093bffe9e705d2a7b28 100644 (file)
@@ -4,16 +4,12 @@ error[E0308]: mismatched types
 13 |   fn plus_one(x: i32) -> i32 {
    |  ____________________________^
 14 | |     x + 1;
+   | |          - help: consider removing this semicolon
 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[E0308]: mismatched types
   --> $DIR/coercion-missing-tail-expected-type.rs:17:29
@@ -21,16 +17,12 @@ error[E0308]: mismatched types
 17 |   fn foo() -> Result<u8, u64> {
    |  _____________________________^
 18 | |     Ok(1);
+   | |          - help: consider removing this semicolon
 19 | | }
    | |_^ expected enum `std::result::Result`, found ()
    |
    = note: expected type `std::result::Result<u8, u64>`
               found type `()`
-help: consider removing this semicolon:
-  --> $DIR/coercion-missing-tail-expected-type.rs:18:10
-   |
-18 |     Ok(1);
-   |          ^
 
 error: aborting due to previous error(s)
 
diff --git a/src/test/ui/mismatched_types/for-loop-has-unit-body.rs b/src/test/ui/mismatched_types/for-loop-has-unit-body.rs
new file mode 100644 (file)
index 0000000..8c61fc6
--- /dev/null
@@ -0,0 +1,17 @@
+// 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.
+
+fn main() {
+    for x in 0..3 {
+        x //~ ERROR mismatched types
+        //~| NOTE expected ()
+        //~| NOTE expected type `()`
+    }
+}
diff --git a/src/test/ui/mismatched_types/for-loop-has-unit-body.stderr b/src/test/ui/mismatched_types/for-loop-has-unit-body.stderr
new file mode 100644 (file)
index 0000000..6787fe9
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> $DIR/for-loop-has-unit-body.rs:13:9
+   |
+13 |         x //~ ERROR mismatched types
+   |         ^ expected (), found integral variable
+   |
+   = note: expected type `()`
+              found type `{integer}`
+
+error: aborting due to previous error(s)
+
index cbce4f810c5312469d168dd7e31798c42ead8e28..083c1f953330c0dd4baab3a4dcc4e62dcfb0bd71 100644 (file)
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/issue-19109.rs:14:5
    |
+13 | fn function(t: &mut Trait) {
+   |                            - help: possibly return type missing here? `-> *mut Trait `
 14 |     t as *mut Trait
    |     ^^^^^^^^^^^^^^^ expected (), found *-ptr
    |
index d234c8538fe27a23d8128a70fbb317c7b31043d3..53e9cb2177892eec1f54842fee6091ad2c747b56 100644 (file)
@@ -35,7 +35,9 @@ error[E0308]: mismatched types
   --> $DIR/token-error-correct-3.rs:25:13
    |
 25 |             fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found enum `std::result::Result`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: did you mean to add a semicolon here? `;`
+   |             |
+   |             expected (), found enum `std::result::Result`
    |
    = note: expected type `()`
               found type `std::result::Result<bool, std::io::Error>`