Skip to content

Commit

Permalink
Detect missing ; on methods with return type ()
Browse files Browse the repository at this point in the history
On a given file `foo.rs`:

```rust
fn foo() {
    return 1;
}

fn main() {
    3
}
```

Provide the following output:

```bash
error[E0308]: mismatched types
 --> foo.rs:2:12
  |
1 | fn foo() {
  |          ^ possibly return type `{integer}` missing in this fn?
2 |     return 1;
  |            ^ expected (), found integral variable
  |
  = note: expected type `()`
  = note:    found type `{integer}`

error[E0308]: mismatched types
 --> foo.rs:6:5
  |
6 |     3
  |     ^
  |     |
  |     possibly `;` missing here?
  |     expected (), found integral variable
  |
  = note: expected type `()`
  = note:    found type `{integer}`

error: aborting due to 2 previous errors
```
  • Loading branch information
estebank committed Nov 21, 2016
1 parent fb12219 commit 555fb3a
Show file tree
Hide file tree
Showing 14 changed files with 193 additions and 32 deletions.
48 changes: 45 additions & 3 deletions src/librustc_typeck/check/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@


use check::FnCtxt;
use rustc::ty::Ty;
use rustc::infer::{InferOk};
use hir::map::Node;
use rustc::infer::{InferOk, TypeTrace};
use rustc::traits::ObligationCause;
use rustc::ty::Ty;
use rustc::ty::error::TypeError;

use syntax_pos::Span;
use rustc::hir;
Expand Down Expand Up @@ -57,7 +59,47 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if let Err(e) = self.try_coerce(expr, checked_ty, expected) {
let cause = self.misc(expr.span);
let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
self.report_mismatched_types(&cause, expected, expr_ty, e);
let trace = TypeTrace::types(&cause, true, expected, expr_ty);
let mut diag = self.report_and_explain_type_error(trace, &e);

if let Node::NodeBlock(block) = self.tcx.map
.get(self.tcx.map.get_parent_node(expr.id))
{
if let TypeError::Sorts(ref values) = e {
if values.expected.is_nil() {
// An implicit return to a method with return type `()`
diag.span_label(expr.span,
&"possibly missing `;` here?");
// Get the current node's method definition
if let Node::NodeExpr(item) = self.tcx.map
.get(self.tcx.map.get_parent_node(block.id))
{
// The fn has a default return type of ()
if let Node::NodeItem(&hir::Item {
name,
node: hir::ItemFn(ref decl, ..),
..
}) = self.tcx.map.get(self.tcx.map.get_parent_node(item.id)) {
// `main` *must* have return type ()
if name.as_str() != "main" {
decl.clone().and_then(|decl| {
if let hir::FnDecl {
output: hir::FunctionRetTy::DefaultReturn(span),
..
} = decl {
diag.span_label(span,
&format!("possibly return type `{}` \
missing in this fn?",
values.found));
}
});
}
}
}
}
}
};
diag.emit();
}
}
}
10 changes: 9 additions & 1 deletion src/test/compile-fail/block-must-not-have-result-do.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@

fn main() {
loop {
true //~ ERROR mismatched types
true
//~^ ERROR mismatched types
//~| ERROR mismatched types
//~| NOTE: possibly missing `;` here?
//~| NOTE: expected (), found bool
//~| NOTE: expected type `()`
//~| NOTE: expected type `()`
//~| NOTE: found type `bool`
//~| NOTE: found type `bool`
}
}
10 changes: 9 additions & 1 deletion src/test/compile-fail/block-must-not-have-result-res.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,15 @@ struct r;

impl Drop for r {
fn drop(&mut self) {
true //~ ERROR mismatched types
true
//~^ ERROR: mismatched types
//~| ERROR: mismatched types
//~| NOTE: possibly missing `;` here?
//~| NOTE: expected (), found bool
//~| NOTE: expected type `()`
//~| NOTE: expected type `()`
//~| NOTE: found type `bool`
//~| NOTE: found type `bool`
}
}

Expand Down
13 changes: 9 additions & 4 deletions src/test/compile-fail/block-must-not-have-result-while.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,14 @@

fn main() {
while true {
true //~ ERROR mismatched types
//~| expected type `()`
//~| found type `bool`
//~| expected (), found bool
true
//~^ ERROR: mismatched types
//~| ERROR: mismatched types
//~| NOTE: possibly missing `;` here?
//~| NOTE: expected (), found bool
//~| NOTE: expected type `()`
//~| NOTE: expected type `()`
//~| NOTE: found type `bool`
//~| NOTE: found type `bool`
}
}
19 changes: 19 additions & 0 deletions src/test/compile-fail/expected-return-on-unit.rs
Original file line number Diff line number Diff line change
@@ -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 <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 main() {
return 1;
//~^ mismatched types
//~| expected type `()`
//~| found type `{integer}`
}
20 changes: 12 additions & 8 deletions src/test/compile-fail/issue-13624.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ 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
//~| ERROR: mismatched types
//~| NOTE: possibly missing `;` here?
//~| NOTE: expected (), found enum `a::Enum`
//~| NOTE: expected type `()`
//~| NOTE: expected type `()`
//~| NOTE: found type `a::Enum`
//~| NOTE: found type `a::Enum`
}
}

Expand All @@ -30,10 +34,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`
}
}
}
Expand Down
13 changes: 9 additions & 4 deletions src/test/compile-fail/issue-19109.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,16 @@
trait Trait { }

fn function(t: &mut Trait) {
//~^ NOTE: possibly return type `*mut Trait` missing in this fn?
t as *mut Trait
//~^ ERROR: mismatched types
//~| NOTE: expected type `()`
//~| NOTE: found type `*mut Trait`
//~| NOTE: expected (), found *-ptr
//~^ ERROR: mismatched types
//~| ERROR: mismatched types
//~| NOTE: possibly missing `;` here?
//~| NOTE: expected (), found *-ptr
//~| NOTE: expected type `()`
//~| NOTE: expected type `()`
//~| NOTE: found type `*mut Trait`
//~| NOTE: found type `*mut Trait`
}

fn main() { }
13 changes: 11 additions & 2 deletions src/test/compile-fail/issue-20862.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,20 @@
// except according to those terms.

fn foo(x: i32) {
//~^ NOTE: possibly return type
|y| x + y
//~^ ERROR: mismatched types
//~^ ERROR: mismatched types
//~| ERROR: mismatched types
//~| NOTE: possibly missing `;` here?
//~| NOTE: expected (), found closure
//~| NOTE: expected type `()`
//~| NOTE: expected type `()`
//~| NOTE: found type
//~| NOTE: found type
}


fn main() {
let x = foo(5)(2);
//~^ ERROR: expected function, found `()`
//~^ ERROR: expected function, found `()`
}
9 changes: 9 additions & 0 deletions src/test/compile-fail/issue-22645.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,13 @@ fn main() {
let b = Bob + 3.5;
b + 3 //~ ERROR E0277
//~^ ERROR: mismatched types
//~| ERROR: mismatched types
//~| NOTE: possibly missing `;` here?
//~| NOTE: expected (), found
//~| NOTE: expected type `()`
//~| NOTE: expected type `()`
//~| NOTE: found 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}>`
}
7 changes: 7 additions & 0 deletions src/test/compile-fail/issue-3563.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ trait A {
|| self.b()
//~^ ERROR no method named `b` found for type `&Self` in the current scope
//~| ERROR mismatched types
//~| ERROR mismatched types
//~| NOTE: possibly missing `;` here?
//~| NOTE: expected (), found closure
//~| NOTE: expected type `()`
//~| NOTE: expected type `()`
//~| NOTE: found type
//~| NOTE: found type
}
}
fn main() {}
10 changes: 7 additions & 3 deletions src/test/compile-fail/issue-5500.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@
fn main() {
&panic!()
//~^ ERROR mismatched types
//~| expected type `()`
//~| found type `&_`
//~| expected (), found reference
//~| ERROR mismatched types
//~| NOTE: possibly missing `;` here?
//~| NOTE: expected (), found reference
//~| NOTE: expected type `()`
//~| NOTE: expected type `()`
//~| NOTE: found type `&_`
//~| NOTE: found type `&_`
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,26 @@ fn generic<T>() -> <T as Foo>::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 `<T as Foo>::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
//~| ERROR mismatched types
//~| NOTE: possibly missing `;` here?
//~| NOTE: expected (), found associated type
//~| NOTE: expected type `()`
//~| NOTE: expected type `()`
//~| NOTE: found type
//~| NOTE: found type
}

fn main() {
Expand Down
13 changes: 9 additions & 4 deletions src/test/compile-fail/token-error-correct-3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,15 @@ pub mod raw {
//~| NOTE unresolved name
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<bool, std::io::Error>`
fs::create_dir_all(path.as_ref()).map(|()| true)
//~^ ERROR mismatched types
//~| ERROR mismatched types
//~| NOTE: possibly missing `;` here?
//~| NOTE: expected (), found enum `std::result::Result`
//~| NOTE: expected type `()`
//~| NOTE: expected type `()`
//~| NOTE: found type `std::result::Result<bool, std::io::Error>`
//~| NOTE: found type `std::result::Result<bool, std::io::Error>`
} else { //~ ERROR: incorrect close delimiter: `}`
//~^ ERROR: expected one of
Ok(false);
Expand Down
24 changes: 24 additions & 0 deletions src/test/compile-fail/unexpected-return-on-unit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// 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.

// 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
//~| ERROR mismatched types
//~| NOTE: possibly missing `;` here?
//~| NOTE: expected (), found integral variable
//~| NOTE: expected type `()`
//~| NOTE: expected type `()`
//~| NOTE: found type `{integer}`
//~| NOTE: found type `{integer}`
}

0 comments on commit 555fb3a

Please sign in to comment.