Skip to content

Commit a45366c

Browse files
committed
Move check to FnCtxt::check_block_with_expected
1 parent 555fb3a commit a45366c

19 files changed

+162
-136
lines changed

src/librustc_typeck/check/demand.rs

+14-43
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,10 @@
1010

1111

1212
use check::FnCtxt;
13-
use hir::map::Node;
1413
use rustc::infer::{InferOk, TypeTrace};
1514
use rustc::traits::ObligationCause;
1615
use rustc::ty::Ty;
17-
use rustc::ty::error::TypeError;
16+
use errors;
1817

1918
use syntax_pos::Span;
2019
use rustc::hir;
@@ -53,53 +52,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
5352
}
5453
}
5554

56-
// Checks that the type of `expr` can be coerced to `expected`.
57-
pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>) {
55+
pub fn demand_coerce_diag(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>)
56+
-> Option<errors::DiagnosticBuilder<'tcx>>
57+
{
5858
let expected = self.resolve_type_vars_with_obligations(expected);
5959
if let Err(e) = self.try_coerce(expr, checked_ty, expected) {
6060
let cause = self.misc(expr.span);
6161
let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
6262
let trace = TypeTrace::types(&cause, true, expected, expr_ty);
63-
let mut diag = self.report_and_explain_type_error(trace, &e);
6463

65-
if let Node::NodeBlock(block) = self.tcx.map
66-
.get(self.tcx.map.get_parent_node(expr.id))
67-
{
68-
if let TypeError::Sorts(ref values) = e {
69-
if values.expected.is_nil() {
70-
// An implicit return to a method with return type `()`
71-
diag.span_label(expr.span,
72-
&"possibly missing `;` here?");
73-
// Get the current node's method definition
74-
if let Node::NodeExpr(item) = self.tcx.map
75-
.get(self.tcx.map.get_parent_node(block.id))
76-
{
77-
// The fn has a default return type of ()
78-
if let Node::NodeItem(&hir::Item {
79-
name,
80-
node: hir::ItemFn(ref decl, ..),
81-
..
82-
}) = self.tcx.map.get(self.tcx.map.get_parent_node(item.id)) {
83-
// `main` *must* have return type ()
84-
if name.as_str() != "main" {
85-
decl.clone().and_then(|decl| {
86-
if let hir::FnDecl {
87-
output: hir::FunctionRetTy::DefaultReturn(span),
88-
..
89-
} = decl {
90-
diag.span_label(span,
91-
&format!("possibly return type `{}` \
92-
missing in this fn?",
93-
values.found));
94-
}
95-
});
96-
}
97-
}
98-
}
99-
}
100-
}
101-
};
102-
diag.emit();
64+
Some(self.report_and_explain_type_error(trace, &e))
65+
} else {
66+
None
67+
}
68+
}
69+
70+
// Checks that the type of `expr` can be coerced to `expected`.
71+
pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>) {
72+
if let Some(mut err) = self.demand_coerce_diag(expr, checked_ty, expected) {
73+
err.emit();
10374
}
10475
}
10576
}

src/librustc_typeck/check/mod.rs

+54-4
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ use rustc::hir::intravisit::{self, Visitor};
124124
use rustc::hir::itemlikevisit::ItemLikeVisitor;
125125
use rustc::hir::{self, PatKind};
126126
use rustc::hir::print as pprust;
127+
use rustc::hir::map::Node;
127128
use rustc_back::slice;
128129
use rustc_const_eval::eval_length;
129130

@@ -3666,7 +3667,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
36663667
self.check_expr_closure(expr, capture, &decl, &body, expected)
36673668
}
36683669
hir::ExprBlock(ref b) => {
3669-
self.check_block_with_expected(&b, expected)
3670+
self.check_block_with_expected(&b, expected)
36703671
}
36713672
hir::ExprCall(ref callee, ref args) => {
36723673
self.check_call(expr, &callee, &args[..], expected)
@@ -4085,7 +4086,57 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
40854086
} else if let ExpectHasType(ety) = expected {
40864087
if let Some(ref e) = blk.expr {
40874088
// Coerce the tail expression to the right type.
4088-
self.demand_coerce(e, ty, ety);
4089+
if let Some(mut err) = self.demand_coerce_diag(e, ty, ety) {
4090+
// Be helpful when the user wrote `{... expr}` and
4091+
// adding a `;` is enough to fix the error.
4092+
if ety.is_nil() {
4093+
let span = Span {
4094+
lo: e.span.hi,
4095+
hi: e.span.hi + BytePos(1),
4096+
expn_id: e.span.expn_id
4097+
};
4098+
err.span_label(span, &"consider adding a semicolon here");
4099+
}
4100+
4101+
// Is the block part of a fn?
4102+
let parent = self.tcx.map.get(self.tcx.map.get_parent(blk.id));
4103+
let fn_decl = if let Node::NodeItem(&hir::Item {
4104+
name, node: hir::ItemFn(ref decl, ..), ..
4105+
}) = parent {
4106+
// `fn main` must return `()`
4107+
if name.as_str() != "main" {
4108+
decl.clone().and_then(|decl| {
4109+
Some(decl)
4110+
})
4111+
} else {
4112+
None
4113+
}
4114+
} else if let Node::NodeTraitItem(&hir::TraitItem {
4115+
node: hir::TraitItem_::MethodTraitItem(hir::MethodSig {
4116+
ref decl, ..
4117+
}, ..), ..
4118+
}) = parent {
4119+
decl.clone().and_then(|decl| {
4120+
Some(decl)
4121+
})
4122+
} else {
4123+
// Do not recomend changing return type of `ImplItemKind::Method`
4124+
None
4125+
};
4126+
4127+
// Only recommend changing the return type for methods that
4128+
// haven't set a return type at all.
4129+
if let Some(hir::FnDecl {
4130+
output: hir::FunctionRetTy::DefaultReturn(span),
4131+
..
4132+
}) = fn_decl {
4133+
err.span_label(span,
4134+
&format!("possibly return type `{}` \
4135+
missing here",
4136+
ty));
4137+
}
4138+
err.emit();
4139+
}
40894140
} else {
40904141
// We're not diverging and there's an expected type, which,
40914142
// in case it's not `()`, could result in an error higher-up.
@@ -4118,9 +4169,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
41184169
hi: original_span.hi,
41194170
expn_id: original_span.expn_id
41204171
};
4121-
err.span_help(span_semi, "consider removing this semicolon:");
4172+
err.span_label(span_semi, &"consider removing this semicolon");
41224173
}
4123-
41244174
err.emit();
41254175
}
41264176
}

src/test/compile-fail/block-must-not-have-result-do.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,9 @@ fn main() {
1212
loop {
1313
true
1414
//~^ ERROR mismatched types
15-
//~| ERROR mismatched types
16-
//~| NOTE: possibly missing `;` here?
15+
//~| NOTE: consider adding a semicolon here
1716
//~| NOTE: expected (), found bool
1817
//~| NOTE: expected type `()`
19-
//~| NOTE: expected type `()`
20-
//~| NOTE: found type `bool`
2118
//~| NOTE: found type `bool`
2219
}
2320
}

src/test/compile-fail/block-must-not-have-result-res.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,9 @@ impl Drop for r {
1414
fn drop(&mut self) {
1515
true
1616
//~^ ERROR: mismatched types
17-
//~| ERROR: mismatched types
18-
//~| NOTE: possibly missing `;` here?
17+
//~| NOTE: consider adding a semicolon here
1918
//~| NOTE: expected (), found bool
2019
//~| NOTE: expected type `()`
21-
//~| NOTE: expected type `()`
22-
//~| NOTE: found type `bool`
2320
//~| NOTE: found type `bool`
2421
}
2522
}

src/test/compile-fail/block-must-not-have-result-while.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,9 @@ fn main() {
1212
while true {
1313
true
1414
//~^ ERROR: mismatched types
15-
//~| ERROR: mismatched types
16-
//~| NOTE: possibly missing `;` here?
15+
//~| NOTE: consider adding a semicolon here
1716
//~| NOTE: expected (), found bool
1817
//~| NOTE: expected type `()`
19-
//~| NOTE: expected type `()`
20-
//~| NOTE: found type `bool`
2118
//~| NOTE: found type `bool`
2219
}
2320
}

src/test/compile-fail/consider-removing-last-semi.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,22 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
fn f() -> String { //~ ERROR mismatched types
11+
fn f() -> String {
12+
//~^ ERROR mismatched types
13+
//~| NOTE expected struct `std::string::String`, found ()
14+
//~| NOTE expected type `std::string::String`
15+
//~| NOTE found type `()`
1216
0u8;
13-
"bla".to_string(); //~ HELP consider removing this semicolon
17+
"bla".to_string(); //~ NOTE consider removing this semicolon
1418
}
1519

16-
fn g() -> String { //~ ERROR mismatched types
20+
fn g() -> String {
21+
//~^ ERROR mismatched types
22+
//~| NOTE expected struct `std::string::String`, found ()
23+
//~| NOTE expected type `std::string::String`
24+
//~| NOTE found type `()`
1725
"this won't work".to_string();
18-
"removeme".to_string(); //~ HELP consider removing this semicolon
26+
"removeme".to_string(); //~ NOTE consider removing this semicolon
1927
}
2028

2129
fn main() {}

src/test/compile-fail/issue-11714.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
fn blah() -> i32 { //~ ERROR mismatched types
11+
fn blah() -> i32 {
12+
//~^ ERROR mismatched types
13+
//~| NOTE expected i32, found ()
14+
//~| NOTE expected type `i32`
15+
//~| NOTE found type `()`
1216
1
1317

14-
; //~ HELP consider removing this semicolon:
18+
; //~ NOTE consider removing this semicolon
1519
}
1620

1721
fn main() { }

src/test/compile-fail/issue-13428.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,25 @@
1010

1111
// Regression test for #13428
1212

13-
fn foo() -> String { //~ ERROR mismatched types
13+
fn foo() -> String {
14+
//~^ ERROR mismatched types
15+
//~| NOTE expected struct `std::string::String`, found ()
16+
//~| NOTE expected type `std::string::String`
17+
//~| NOTE found type `()`
1418
format!("Hello {}",
1519
"world")
1620
// Put the trailing semicolon on its own line to test that the
1721
// note message gets the offending semicolon exactly
18-
; //~ HELP consider removing this semicolon
22+
; //~ NOTE consider removing this semicolon
1923
}
2024

21-
fn bar() -> String { //~ ERROR mismatched types
25+
fn bar() -> String {
26+
//~^ ERROR mismatched types
27+
//~| NOTE expected struct `std::string::String`, found ()
28+
//~| NOTE expected type `std::string::String`
29+
//~| NOTE found type `()`
2230
"foobar".to_string()
23-
; //~ HELP consider removing this semicolon
31+
; //~ NOTE consider removing this semicolon
2432
}
2533

2634
pub fn main() {}

src/test/compile-fail/issue-13624.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,9 @@ mod a {
1616
pub fn get_enum_struct_variant() -> () {
1717
Enum::EnumStructVariant { x: 1, y: 2, z: 3 }
1818
//~^ ERROR: mismatched types
19-
//~| ERROR: mismatched types
20-
//~| NOTE: possibly missing `;` here?
19+
//~| NOTE: consider adding a semicolon here
2120
//~| NOTE: expected (), found enum `a::Enum`
2221
//~| NOTE: expected type `()`
23-
//~| NOTE: expected type `()`
24-
//~| NOTE: found type `a::Enum`
2522
//~| NOTE: found type `a::Enum`
2623
}
2724
}

src/test/compile-fail/issue-19109.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,13 @@
1111
trait Trait { }
1212

1313
fn function(t: &mut Trait) {
14-
//~^ NOTE: possibly return type `*mut Trait` missing in this fn?
14+
//~^ NOTE possibly return type `*mut Trait` missing here
1515
t as *mut Trait
16-
//~^ ERROR: mismatched types
17-
//~| ERROR: mismatched types
18-
//~| NOTE: possibly missing `;` here?
19-
//~| NOTE: expected (), found *-ptr
20-
//~| NOTE: expected type `()`
21-
//~| NOTE: expected type `()`
22-
//~| NOTE: found type `*mut Trait`
23-
//~| NOTE: found type `*mut Trait`
16+
//~^ ERROR mismatched types
17+
//~| NOTE consider adding a semicolon here
18+
//~| NOTE expected (), found *-ptr
19+
//~| NOTE expected type `()`
20+
//~| NOTE found type `*mut Trait`
2421
}
2522

2623
fn main() { }

src/test/compile-fail/issue-20862.rs

+7-10
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,17 @@
99
// except according to those terms.
1010

1111
fn foo(x: i32) {
12-
//~^ NOTE: possibly return type
12+
//~^ NOTE possibly return type
1313
|y| x + y
14-
//~^ ERROR: mismatched types
15-
//~| ERROR: mismatched types
16-
//~| NOTE: possibly missing `;` here?
17-
//~| NOTE: expected (), found closure
18-
//~| NOTE: expected type `()`
19-
//~| NOTE: expected type `()`
20-
//~| NOTE: found type
21-
//~| NOTE: found type
14+
//~^ ERROR mismatched types
15+
//~| NOTE consider adding a semicolon here
16+
//~| NOTE expected (), found closure
17+
//~| NOTE expected type `()`
18+
//~| NOTE found type
2219
}
2320

2421

2522
fn main() {
2623
let x = foo(5)(2);
27-
//~^ ERROR: expected function, found `()`
24+
//~^ ERROR expected function, found `()`
2825
}

src/test/compile-fail/issue-22645.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,10 @@ fn main() {
2424
let b = Bob + 3.5;
2525
b + 3 //~ ERROR E0277
2626
//~^ ERROR: mismatched types
27-
//~| ERROR: mismatched types
28-
//~| NOTE: possibly missing `;` here?
29-
//~| NOTE: expected (), found
30-
//~| NOTE: expected type `()`
31-
//~| NOTE: expected type `()`
32-
//~| NOTE: found type
33-
//~| NOTE: found type
34-
//~| NOTE: the trait `Scalar` is not implemented for `{integer}`
35-
//~| NOTE: required because of the requirements on the impl of `std::ops::Add<{integer}>`
27+
//~| NOTE consider adding a semicolon here
28+
//~| NOTE expected (), found
29+
//~| NOTE expected type `()`
30+
//~| NOTE found type
31+
//~| NOTE the trait `Scalar` is not implemented for `{integer}`
32+
//~| NOTE required because of the requirements on the impl of `std::ops::Add<{integer}>`
3633
}

src/test/compile-fail/issue-3563.rs

+5-8
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,14 @@
99
// except according to those terms.
1010

1111
trait A {
12-
fn a(&self) {
12+
fn a(&self) { //~ possibly return type
1313
|| self.b()
1414
//~^ ERROR no method named `b` found for type `&Self` in the current scope
1515
//~| ERROR mismatched types
16-
//~| ERROR mismatched types
17-
//~| NOTE: possibly missing `;` here?
18-
//~| NOTE: expected (), found closure
19-
//~| NOTE: expected type `()`
20-
//~| NOTE: expected type `()`
21-
//~| NOTE: found type
22-
//~| NOTE: found type
16+
//~| NOTE consider adding a semicolon here
17+
//~| NOTE expected (), found closure
18+
//~| NOTE expected type `()`
19+
//~| NOTE found type
2320
}
2421
}
2522
fn main() {}

0 commit comments

Comments
 (0)