diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index a77887cd221de..0f36bdc66d2cb 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -10,9 +10,10 @@ use check::FnCtxt; -use rustc::ty::Ty; -use rustc::infer::{InferOk}; +use rustc::infer::InferOk; use rustc::traits::ObligationCause; +use rustc::ty::Ty; +use errors; use syntax::ast; use syntax_pos::{self, Span}; @@ -66,8 +67,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - // Checks that the type of `expr` can be coerced to `expected`. - 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> + { let expected = self.resolve_type_vars_with_obligations(expected); if let Err(e) = self.try_coerce(expr, checked_ty, expected) { let cause = self.misc(expr.span); @@ -84,7 +86,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { might fulfill your needs:\n{}", self.get_best_match(&suggestions).join("\n"))); }; - err.emit(); + Some(err) + } else { + None } } @@ -132,4 +136,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => false, } } + + // Checks that the type of `expr` can be coerced to `expected`. + 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(); + } + } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e240c70aaa3a5..2e79251ee693f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -122,6 +122,7 @@ use syntax_pos::{self, BytePos, Span, DUMMY_SP}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::{self, PatKind}; +use rustc::hir::map::Node; use rustc::middle::lang_items; use rustc_back::slice; use rustc_const_eval::eval_length; @@ -3792,7 +3793,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_expr_closure(expr, capture, &decl, body_id, expected) } hir::ExprBlock(ref b) => { - self.check_block_with_expected(&b, expected) + self.check_block_with_expected(&b, expected) } hir::ExprCall(ref callee, ref args) => { self.check_call(expr, &callee, args, expected) @@ -4209,7 +4210,57 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else if let ExpectHasType(ety) = expected { if let Some(ref e) = blk.expr { // Coerce the tail expression to the right type. - self.demand_coerce(e, ty, ety); + if let Some(mut err) = self.demand_coerce_diag(e, ty, ety) { + // Be helpful when the user wrote `{... expr}` and + // adding a `;` is enough to fix the error. + if ety.is_nil() { + let span = Span { + lo: e.span.hi, + hi: e.span.hi, + expn_id: e.span.expn_id + }; + err.span_label(span, &"consider adding a semicolon here"); + } + + // Is the block part of a fn? + let parent = self.tcx.map.get(self.tcx.map.get_parent(blk.id)); + let fn_decl = if let Node::NodeItem(&hir::Item { + name, node: hir::ItemFn(ref decl, ..), .. + }) = parent { + // `fn main` must return `()` + if name != Symbol::intern("main") { + decl.clone().and_then(|decl| { + Some(decl) + }) + } else { + None + } + } else if let Node::NodeTraitItem(&hir::TraitItem { + node: hir::TraitItemKind::Method(hir::MethodSig { + ref decl, .. + }, ..), .. + }) = parent { + decl.clone().and_then(|decl| { + Some(decl) + }) + } else { + // Do not recomend changing return type of `ImplItemKind::Method` + None + }; + + // Only recommend changing the return type for methods that + // haven't set a return type at all. + if let Some(hir::FnDecl { + output: hir::FunctionRetTy::DefaultReturn(span), + .. + }) = fn_decl { + err.span_label(span, + &format!("possibly return type `{}` \ + missing here", + ty)); + } + err.emit(); + } } else { // We're not diverging and there's an expected type, which, // in case it's not `()`, could result in an error higher-up. @@ -4242,9 +4293,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hi: original_span.hi, expn_id: original_span.expn_id }; - err.span_help(span_semi, "consider removing this semicolon:"); + err.span_label(span_semi, &"consider removing this semicolon"); } - err.emit(); } } 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 index 2a6c71dbe3923..03385bcc5e768 100644 --- a/src/test/compile-fail/block-must-not-have-result-do.rs +++ b/src/test/compile-fail/block-must-not-have-result-do.rs @@ -10,6 +10,11 @@ fn main() { loop { - true //~ ERROR mismatched types + true + //~^ ERROR mismatched types + //~| NOTE: consider adding a semicolon here + //~| NOTE: expected (), found bool + //~| NOTE: expected type `()` + //~| NOTE: found type `bool` } } 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 index 8728685fc8b02..29a0f920194f5 100644 --- a/src/test/compile-fail/block-must-not-have-result-res.rs +++ b/src/test/compile-fail/block-must-not-have-result-res.rs @@ -12,7 +12,12 @@ struct r; impl Drop for r { fn drop(&mut self) { - true //~ ERROR mismatched types + true + //~^ ERROR: mismatched types + //~| NOTE: consider adding a semicolon here + //~| NOTE: expected (), found bool + //~| NOTE: expected type `()` + //~| NOTE: found type `bool` } } 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 index a0fb470e1e4d0..2b2e9c3386ea9 100644 --- a/src/test/compile-fail/block-must-not-have-result-while.rs +++ b/src/test/compile-fail/block-must-not-have-result-while.rs @@ -10,9 +10,11 @@ fn main() { while true { - true //~ ERROR mismatched types - //~| expected type `()` - //~| found type `bool` - //~| expected (), found bool + true + //~^ ERROR: mismatched types + //~| NOTE: consider adding a semicolon here + //~| NOTE: expected (), found bool + //~| NOTE: expected type `()` + //~| NOTE: found type `bool` } } diff --git a/src/test/compile-fail/consider-removing-last-semi.rs b/src/test/compile-fail/consider-removing-last-semi.rs index 530a0e4156228..fa78f05bf23a9 100644 --- a/src/test/compile-fail/consider-removing-last-semi.rs +++ b/src/test/compile-fail/consider-removing-last-semi.rs @@ -8,14 +8,22 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn f() -> String { //~ ERROR mismatched types +fn f() -> String { + //~^ ERROR mismatched types + //~| NOTE expected struct `std::string::String`, found () + //~| NOTE expected type `std::string::String` + //~| NOTE found type `()` 0u8; - "bla".to_string(); //~ HELP consider removing this semicolon + "bla".to_string(); //~ NOTE consider removing this semicolon } -fn g() -> String { //~ ERROR mismatched types +fn g() -> String { + //~^ ERROR mismatched types + //~| NOTE expected struct `std::string::String`, found () + //~| NOTE expected type `std::string::String` + //~| NOTE found type `()` "this won't work".to_string(); - "removeme".to_string(); //~ HELP consider removing this semicolon + "removeme".to_string(); //~ NOTE consider removing this semicolon } fn main() {} diff --git a/src/test/compile-fail/expected-return-on-unit.rs b/src/test/compile-fail/expected-return-on-unit.rs new file mode 100644 index 0000000000000..742a8b48491a9 --- /dev/null +++ b/src/test/compile-fail/expected-return-on-unit.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , 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 main() { + return 1; + //~^ mismatched types + //~| expected type `()` + //~| found type `{integer}` +} diff --git a/src/test/compile-fail/issue-11714.rs b/src/test/compile-fail/issue-11714.rs index 192f78e41cb43..c550af1b95e0b 100644 --- a/src/test/compile-fail/issue-11714.rs +++ b/src/test/compile-fail/issue-11714.rs @@ -8,10 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn blah() -> i32 { //~ ERROR mismatched types +fn blah() -> i32 { + //~^ ERROR mismatched types + //~| NOTE expected i32, found () + //~| NOTE expected type `i32` + //~| NOTE found type `()` 1 - ; //~ HELP consider removing this semicolon: + ; //~ NOTE consider removing this semicolon } fn main() { } diff --git a/src/test/compile-fail/issue-13428.rs b/src/test/compile-fail/issue-13428.rs index 9406199afc231..d5d719de9fdef 100644 --- a/src/test/compile-fail/issue-13428.rs +++ b/src/test/compile-fail/issue-13428.rs @@ -10,17 +10,25 @@ // Regression test for #13428 -fn foo() -> String { //~ ERROR mismatched types +fn foo() -> String { + //~^ ERROR mismatched types + //~| NOTE expected struct `std::string::String`, found () + //~| NOTE expected type `std::string::String` + //~| NOTE found type `()` 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 + ; //~ NOTE consider removing this semicolon } -fn bar() -> String { //~ ERROR mismatched types +fn bar() -> String { + //~^ ERROR mismatched types + //~| NOTE expected struct `std::string::String`, found () + //~| NOTE expected type `std::string::String` + //~| NOTE found type `()` "foobar".to_string() - ; //~ HELP consider removing this semicolon + ; //~ NOTE 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 index e4ed87c3cb0cd..96e185ed8e20d 100644 --- a/src/test/compile-fail/issue-13624.rs +++ b/src/test/compile-fail/issue-13624.rs @@ -15,10 +15,11 @@ mod a { 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` + //~^ ERROR: mismatched types + //~| NOTE: consider adding a semicolon here + //~| NOTE: expected (), found enum `a::Enum` + //~| NOTE: expected type `()` + //~| NOTE: found type `a::Enum` } } @@ -30,10 +31,10 @@ mod b { 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` + //~^ ERROR: mismatched types + //~| NOTE: expected (), found enum `a::Enum` + //~| NOTE: expected type `()` + //~| NOTE: found type `a::Enum` } } } diff --git a/src/test/compile-fail/issue-20862.rs b/src/test/compile-fail/issue-20862.rs index 9df6358399869..bb3edf9d17817 100644 --- a/src/test/compile-fail/issue-20862.rs +++ b/src/test/compile-fail/issue-20862.rs @@ -9,11 +9,17 @@ // except according to those terms. fn foo(x: i32) { + //~^ NOTE possibly return type |y| x + y -//~^ ERROR: mismatched types + //~^ ERROR mismatched types + //~| NOTE consider adding a semicolon here + //~| NOTE expected (), found closure + //~| NOTE expected type `()` + //~| NOTE found type } + fn main() { let x = foo(5)(2); -//~^ ERROR: expected function, found `()` + //~^ ERROR expected function, found `()` } diff --git a/src/test/compile-fail/issue-22645.rs b/src/test/compile-fail/issue-22645.rs index 81f66e3e2cfee..ef7650020eae1 100644 --- a/src/test/compile-fail/issue-22645.rs +++ b/src/test/compile-fail/issue-22645.rs @@ -24,4 +24,10 @@ fn main() { let b = Bob + 3.5; b + 3 //~ ERROR E0277 //~^ ERROR: mismatched types + //~| NOTE consider adding a semicolon here + //~| NOTE expected (), found + //~| NOTE expected type `()` + //~| NOTE found type + //~| NOTE the trait `Scalar` is not implemented for `{integer}` + //~| NOTE required because of the requirements on the impl of `std::ops::Add<{integer}>` } diff --git a/src/test/compile-fail/issue-3563.rs b/src/test/compile-fail/issue-3563.rs index 7928c04b9df87..784f55689c6b8 100644 --- a/src/test/compile-fail/issue-3563.rs +++ b/src/test/compile-fail/issue-3563.rs @@ -9,10 +9,14 @@ // except according to those terms. trait A { - fn a(&self) { + fn a(&self) { //~ possibly return type || self.b() //~^ ERROR no method named `b` found for type `&Self` in the current scope //~| ERROR mismatched types + //~| NOTE consider adding a semicolon here + //~| NOTE expected (), found closure + //~| NOTE expected type `()` + //~| NOTE found type } } fn main() {} diff --git a/src/test/compile-fail/issue-5500.rs b/src/test/compile-fail/issue-5500.rs index 1cbb7588e17df..54d8e35edd696 100644 --- a/src/test/compile-fail/issue-5500.rs +++ b/src/test/compile-fail/issue-5500.rs @@ -11,7 +11,7 @@ fn main() { &panic!() //~^ ERROR mismatched types - //~| expected type `()` - //~| found type `&_` - //~| expected (), found reference + //~| NOTE expected (), found reference + //~| NOTE expected type `()` + //~| NOTE found type `&_` } diff --git a/src/test/compile-fail/issue-6458-4.rs b/src/test/compile-fail/issue-6458-4.rs index a078cdea4ac4d..e22486345fde0 100644 --- a/src/test/compile-fail/issue-6458-4.rs +++ b/src/test/compile-fail/issue-6458-4.rs @@ -8,8 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn foo(b: bool) -> Result { //~ ERROR mismatched types - Err("bar".to_string()); //~ HELP consider removing this semicolon +fn foo(b: bool) -> Result { + //~^ ERROR mismatched types + //~| NOTE expected enum `std::result::Result`, found () + //~| NOTE expected type `std::result::Result` + //~| NOTE found type `()` + Err("bar".to_string()); //~ NOTE consider removing this semicolon } fn main() { diff --git a/src/test/compile-fail/liveness-return-last-stmt-semi.rs b/src/test/compile-fail/liveness-return-last-stmt-semi.rs index ada91c38d48c3..8b1ee14b912e8 100644 --- a/src/test/compile-fail/liveness-return-last-stmt-semi.rs +++ b/src/test/compile-fail/liveness-return-last-stmt-semi.rs @@ -11,19 +11,37 @@ // regression test for #8005 macro_rules! test { () => { fn foo() -> i32 { 1; } } } - //~^ ERROR mismatched types - //~| HELP consider removing this semicolon +//~^ ERROR mismatched types +//~| NOTE expected i32, found () +//~| NOTE expected type `i32` +//~| NOTE found type `()` +//~| NOTE consider removing this semicolon -fn no_return() -> i32 {} //~ ERROR mismatched types +fn no_return() -> i32 {} + //~^ ERROR mismatched types + //~| NOTE expected i32, found () + //~| NOTE expected type `i32` + //~| NOTE found type `()` -fn bar(x: u32) -> u32 { //~ ERROR mismatched types - x * 2; //~ HELP consider removing this semicolon +fn bar(x: u32) -> u32 { + //~^ ERROR mismatched types + //~| NOTE expected u32, found () + //~| NOTE expected type `u32` + //~| NOTE found type `()` + x * 2; //~ NOTE consider removing this semicolon } -fn baz(x: u64) -> u32 { //~ ERROR mismatched types +fn baz(x: u64) -> u32 { + //~^ ERROR mismatched types + //~| NOTE expected u32, found () + //~| NOTE expected type `u32` + //~| NOTE found type `()` x * 2; } fn main() { test!(); + //~^ NOTE in this expansion of test! + //~| NOTE in this expansion of test! + //~| NOTE in this expansion of test! } diff --git a/src/test/compile-fail/specialization/specialization-default-projection.rs b/src/test/compile-fail/specialization/specialization-default-projection.rs index 96cbd7a485251..9abac07634a2f 100644 --- a/src/test/compile-fail/specialization/specialization-default-projection.rs +++ b/src/test/compile-fail/specialization/specialization-default-projection.rs @@ -28,14 +28,23 @@ fn generic() -> ::Assoc { // `T` could be some downstream crate type that specializes (or, // for that matter, `u8`). - () //~ ERROR mismatched types + () + //~^ ERROR mismatched types + //~| NOTE: expected associated type, found () + //~| NOTE: expected type `::Assoc` + //~| NOTE: found type `()` } fn monomorphic() -> () { // Even though we know that `()` is not specialized in a // downstream crate, typeck refuses to project here. - generic::<()>() //~ ERROR mismatched types + generic::<()>() + //~^ ERROR mismatched types + //~| NOTE: consider adding a semicolon here + //~| NOTE: expected (), found associated type + //~| NOTE: expected type `()` + //~| NOTE: found type } fn main() { diff --git a/src/test/compile-fail/unexpected-return-on-unit.rs b/src/test/compile-fail/unexpected-return-on-unit.rs new file mode 100644 index 0000000000000..7bc2798103db4 --- /dev/null +++ b/src/test/compile-fail/unexpected-return-on-unit.rs @@ -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 or the MIT license +// , 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 main() { + 1 + //~^ ERROR mismatched types + //~| NOTE: consider adding a semicolon here + //~| NOTE: expected (), found integral variable + //~| NOTE: expected type `()` + //~| NOTE: found type `{integer}` +} diff --git a/src/test/ui/mismatched_types/issue-19109.rs b/src/test/ui/mismatched_types/issue-19109.rs index 580684e2e140b..e133988beb77f 100644 --- a/src/test/ui/mismatched_types/issue-19109.rs +++ b/src/test/ui/mismatched_types/issue-19109.rs @@ -11,11 +11,13 @@ trait Trait { } fn function(t: &mut Trait) { + //~^ NOTE possibly return type `*mut Trait` missing here t as *mut Trait - //~^ ERROR: mismatched types - //~| NOTE: expected type `()` - //~| NOTE: found type `*mut Trait` - //~| NOTE: expected (), found *-ptr + //~^ ERROR mismatched types + //~| NOTE consider adding a semicolon here + //~| NOTE expected (), found *-ptr + //~| NOTE expected type `()` + //~| NOTE found type `*mut Trait` } fn main() { } diff --git a/src/test/ui/resolve/token-error-correct-3.rs b/src/test/ui/resolve/token-error-correct-3.rs index f72b7adf593a9..ba0fcc5762df4 100644 --- a/src/test/ui/resolve/token-error-correct-3.rs +++ b/src/test/ui/resolve/token-error-correct-3.rs @@ -22,10 +22,12 @@ pub mod raw { //~^ NOTE: no resolution found callback(path.as_ref(); //~ NOTE: unclosed delimiter //~^ ERROR: expected one of - fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types - //~^ expected (), found enum `std::result::Result` - //~| expected type `()` - //~| found type `std::result::Result` + fs::create_dir_all(path.as_ref()).map(|()| true) + //~^ ERROR mismatched types + //~| NOTE: consider adding a semicolon here + //~| NOTE: expected (), found enum `std::result::Result` + //~| NOTE: expected type `()` + //~| NOTE: found type `std::result::Result` } else { //~ ERROR: incorrect close delimiter: `}` //~^ ERROR: expected one of Ok(false); diff --git a/src/test/ui/resolve/token-error-correct-3.stderr b/src/test/ui/resolve/token-error-correct-3.stderr index 56e3688957502..cee4effd33976 100644 --- a/src/test/ui/resolve/token-error-correct-3.stderr +++ b/src/test/ui/resolve/token-error-correct-3.stderr @@ -1,7 +1,7 @@ error: incorrect close delimiter: `}` - --> $DIR/token-error-correct-3.rs:29:9 + --> $DIR/token-error-correct-3.rs:31:9 | -29 | } else { //~ ERROR: incorrect close delimiter: `}` +31 | } else { //~ ERROR: incorrect close delimiter: `}` | ^ | note: unclosed delimiter @@ -17,9 +17,9 @@ error: expected one of `,`, `.`, `?`, or an operator, found `;` | ^ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)` - --> $DIR/token-error-correct-3.rs:29:9 + --> $DIR/token-error-correct-3.rs:31:9 | -29 | } else { //~ ERROR: incorrect close delimiter: `}` +31 | } else { //~ ERROR: incorrect close delimiter: `}` | ^ error[E0425]: cannot find function `is_directory` in this scope @@ -31,8 +31,10 @@ error[E0425]: cannot find function `is_directory` in this scope 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` +25 | fs::create_dir_all(path.as_ref()).map(|()| true) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- consider adding a semicolon here + | | + | expected (), found enum `std::result::Result` | = note: expected type `()` found type `std::result::Result`