@@ -133,6 +133,8 @@ struct inherited {
133
133
adjustments : HashMap < ast:: node_id , @ty:: AutoAdjustment >
134
134
}
135
135
136
+ enum FnKind { ForLoop , DoBlock , Vanilla }
137
+
136
138
struct fn_ctxt {
137
139
// var_bindings, locals and next_var_id are shared
138
140
// with any nested functions that capture the environment
@@ -158,6 +160,11 @@ struct fn_ctxt {
158
160
// can actually be made to live as long as it needs to live.
159
161
mut region_lb : ast:: node_id ,
160
162
163
+ // Says whether we're inside a for loop, in a do block
164
+ // or neither. Helps with error messages involving the
165
+ // function return type.
166
+ fn_kind : FnKind ,
167
+
161
168
in_scope_regions : isr_alist ,
162
169
163
170
inh : @inherited ,
@@ -187,6 +194,7 @@ fn blank_fn_ctxt(ccx: @crate_ctxt, rty: ty::t,
187
194
purity : ast:: pure_fn,
188
195
mut region_lb : region_bnd,
189
196
in_scope_regions : @Nil ,
197
+ fn_kind : Vanilla ,
190
198
inh : blank_inherited ( ccx) ,
191
199
ccx : ccx
192
200
}
@@ -208,7 +216,7 @@ fn check_bare_fn(ccx: @crate_ctxt,
208
216
let fty = ty:: node_id_to_type ( ccx. tcx , id) ;
209
217
match ty:: get ( fty) . sty {
210
218
ty:: ty_fn( ref fn_ty) => {
211
- check_fn ( ccx, self_info, fn_ty, decl, body, false , None )
219
+ check_fn ( ccx, self_info, fn_ty, decl, body, Vanilla , None )
212
220
}
213
221
_ => ccx. tcx . sess . impossible_case ( body. span ,
214
222
"check_bare_fn: function type expected" )
@@ -220,10 +228,13 @@ fn check_fn(ccx: @crate_ctxt,
220
228
fn_ty : & ty:: FnTy ,
221
229
decl : ast:: fn_decl ,
222
230
body : ast:: blk ,
223
- indirect_ret : bool ,
231
+ fn_kind : FnKind ,
224
232
old_fcx : Option < @fn_ctxt > ) {
225
233
226
234
let tcx = ccx. tcx ;
235
+ let indirect_ret = match fn_kind {
236
+ ForLoop => true , _ => false
237
+ } ;
227
238
228
239
// ______________________________________________________________________
229
240
// First, we have to replace any bound regions in the fn and self
@@ -276,6 +287,7 @@ fn check_fn(ccx: @crate_ctxt,
276
287
purity : purity,
277
288
mut region_lb : body. node . id ,
278
289
in_scope_regions : isr,
290
+ fn_kind : fn_kind,
279
291
inh : inherited,
280
292
ccx : ccx
281
293
}
@@ -304,7 +316,11 @@ fn check_fn(ccx: @crate_ctxt,
304
316
match body. node . expr {
305
317
Some ( tail_expr) => {
306
318
let tail_expr_ty = fcx. expr_ty ( tail_expr) ;
307
- demand:: suptype ( fcx, tail_expr. span , fcx. ret_ty , tail_expr_ty) ;
319
+ // Special case: we print a special error if there appears
320
+ // to be do-block/for-loop confusion
321
+ demand:: suptype_with_fn ( fcx, tail_expr. span , fcx. ret_ty , tail_expr_ty,
322
+ |sp, e, a, s| {
323
+ fcx. report_mismatched_return_types ( sp, e, a, s) } ) ;
308
324
}
309
325
None => ( )
310
326
}
@@ -774,11 +790,27 @@ impl @fn_ctxt {
774
790
self . infcx ( ) . type_error_message ( sp, mk_msg, actual_ty, err) ;
775
791
}
776
792
777
- fn report_mismatched_types ( sp : span , e : ty:: t , a : ty:: t ,
793
+ fn report_mismatched_return_types ( sp : span , e : ty:: t , a : ty:: t ,
778
794
err : & ty:: type_err ) {
779
- self . infcx ( ) . report_mismatched_types ( sp, e, a, err) ;
795
+ match self . fn_kind {
796
+ ForLoop if !ty:: type_is_bool ( e) && !ty:: type_is_nil ( a) =>
797
+ self . tcx ( ) . sess . span_err ( sp, fmt ! ( "A for-loop body must \
798
+ return (), but it returns %s here. \
799
+ Perhaps you meant to write a `do`-block?",
800
+ ty_to_str( self . tcx( ) , a) ) ) ,
801
+ DoBlock if ty:: type_is_bool ( e) && ty:: type_is_nil ( a) =>
802
+ // If we expected bool and got ()...
803
+ self . tcx ( ) . sess . span_err ( sp, fmt ! ( "Do-block body must \
804
+ return %s, but returns () here. Perhaps you meant \
805
+ to write a `for`-loop?", ty_to_str( self . tcx( ) , e) ) ) ,
806
+ _ => self . infcx ( ) . report_mismatched_types ( sp, e, a, err)
807
+ }
780
808
}
781
809
810
+ fn report_mismatched_types ( sp : span , e : ty:: t , a : ty:: t ,
811
+ err : & ty:: type_err ) {
812
+ self . infcx ( ) . report_mismatched_types ( sp, e, a, err)
813
+ }
782
814
}
783
815
784
816
fn do_autoderef ( fcx : @fn_ctxt , sp : span , t : ty:: t ) -> ( ty:: t , uint ) {
@@ -1087,9 +1119,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
1087
1119
DontDerefArgs => { }
1088
1120
}
1089
1121
1122
+ // mismatch error happens in here
1090
1123
bot |= check_expr_with_assignability ( fcx,
1091
1124
* arg, formal_ty) ;
1092
- fcx. write_ty ( arg. id , fcx. expr_ty ( * arg) ) ;
1093
1125
1094
1126
}
1095
1127
}
@@ -1414,7 +1446,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
1414
1446
ast_proto_opt : Option < ast:: Proto > ,
1415
1447
decl : ast:: fn_decl ,
1416
1448
body : ast:: blk ,
1417
- is_loop_body : bool ,
1449
+ fn_kind : FnKind ,
1418
1450
expected : Option < ty:: t > ) {
1419
1451
let tcx = fcx. ccx . tcx ;
1420
1452
@@ -1473,7 +1505,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
1473
1505
fcx. write_ty ( expr. id , fty) ;
1474
1506
1475
1507
check_fn ( fcx. ccx , None , & fn_ty, decl, body,
1476
- is_loop_body , Some ( fcx) ) ;
1508
+ fn_kind , Some ( fcx) ) ;
1477
1509
}
1478
1510
1479
1511
@@ -2041,14 +2073,12 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
2041
2073
}
2042
2074
ast::expr_fn(proto, decl, ref body, cap_clause) => {
2043
2075
check_expr_fn(fcx, expr, Some(proto),
2044
- decl, (*body), false,
2045
- expected);
2076
+ decl, (*body), Vanilla, expected);
2046
2077
capture::check_capture_clause(tcx, expr.id, cap_clause);
2047
2078
}
2048
2079
ast::expr_fn_block(decl, ref body, cap_clause) => {
2049
2080
check_expr_fn(fcx, expr, None,
2050
- decl, (*body), false,
2051
- expected);
2081
+ decl, (*body), Vanilla, expected);
2052
2082
capture::check_capture_clause(tcx, expr.id, cap_clause);
2053
2083
}
2054
2084
ast::expr_loop_body(b) => {
@@ -2058,6 +2088,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
2058
2088
// parameter. The catch here is that we need to validate two things:
2059
2089
// 1. a closure that returns a bool is expected
2060
2090
// 2. the closure that was given returns unit
2091
+ let mut err_happened = false;
2061
2092
let expected_sty = unpack_expected(fcx, expected, |x| Some(x));
2062
2093
let inner_ty = match expected_sty {
2063
2094
Some(ty::ty_fn(ref fty)) => {
@@ -2071,8 +2102,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
2071
2102
should return `bool `, not `%s`", actual)
2072
2103
} ,
2073
2104
( * fty) . sig. output, None ) ;
2105
+ err_happened = true ;
2074
2106
fcx. write_ty ( id, ty:: mk_err ( tcx) ) ;
2075
- return true ;
2076
2107
}
2077
2108
}
2078
2109
ty:: mk_fn ( tcx, FnTyBase {
@@ -2091,8 +2122,10 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
2091
2122
actual)
2092
2123
} ,
2093
2124
expected_t, None ) ;
2094
- fcx. write_ty ( id, ty:: mk_err ( tcx) ) ;
2095
- return true ;
2125
+ let err_ty = ty:: mk_err ( tcx) ;
2126
+ fcx. write_ty ( id, err_ty) ;
2127
+ err_happened = true ;
2128
+ err_ty
2096
2129
}
2097
2130
None => fcx. tcx ( ) . sess . impossible_case ( expr. span ,
2098
2131
~"loop body must have an expected type ")
@@ -2101,8 +2134,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
2101
2134
match b. node {
2102
2135
ast:: expr_fn_block( decl, ref body, cap_clause) => {
2103
2136
check_expr_fn ( fcx, b, None ,
2104
- decl, ( * body) , true ,
2105
- Some ( inner_ty) ) ;
2137
+ decl, ( * body) , ForLoop , Some ( inner_ty) ) ;
2106
2138
demand:: suptype ( fcx, b. span , inner_ty, fcx. expr_ty ( b) ) ;
2107
2139
capture:: check_capture_clause ( tcx, b. id , cap_clause) ;
2108
2140
}
@@ -2113,11 +2145,16 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
2113
2145
fcx, expr. span , fcx. node_ty ( b. id ) ) ;
2114
2146
match ty:: get ( block_ty) . sty {
2115
2147
ty:: ty_fn( ref fty) => {
2116
- fcx. write_ty ( expr. id , ty:: mk_fn ( tcx, FnTyBase {
2117
- meta : ( * fty) . meta ,
2118
- sig : FnSig { output : ty:: mk_bool ( tcx) ,
2119
- ..( * fty) . sig }
2120
- } ) )
2148
+ if !err_happened {
2149
+ fcx. write_ty ( expr. id , ty:: mk_fn ( tcx, FnTyBase {
2150
+ meta : ( * fty) . meta ,
2151
+ sig : FnSig { output : ty:: mk_bool ( tcx) ,
2152
+ ..( * fty) . sig }
2153
+ } ) ) ;
2154
+ }
2155
+ else {
2156
+ fcx. write_ty ( expr. id , ty:: mk_err ( fcx. tcx ( ) ) ) ;
2157
+ }
2121
2158
}
2122
2159
_ => fail ~"expected fn type "
2123
2160
}
@@ -2135,8 +2172,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
2135
2172
function as its last argument , or wrong number \
2136
2173
of arguments passed to a `do` function"
2137
2174
} , expected_t, None ) ;
2138
- fcx. write_ty ( id, ty:: mk_err ( tcx) ) ;
2139
- return true ;
2175
+ let err_ty = ty:: mk_err ( tcx) ;
2176
+ fcx. write_ty ( id, err_ty) ;
2177
+ err_ty
2140
2178
}
2141
2179
None => fcx. tcx ( ) . sess . impossible_case ( expr. span ,
2142
2180
~"do body must have expected type")
@@ -2145,8 +2183,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
2145
2183
match b. node {
2146
2184
ast:: expr_fn_block( decl, ref body, cap_clause) => {
2147
2185
check_expr_fn ( fcx, b, None ,
2148
- decl, ( * body) , true ,
2149
- Some ( inner_ty) ) ;
2186
+ decl, ( * body) , DoBlock , Some ( inner_ty) ) ;
2150
2187
demand:: suptype ( fcx, b. span , inner_ty, fcx. expr_ty ( b) ) ;
2151
2188
capture:: check_capture_clause ( tcx, b. id , cap_clause) ;
2152
2189
}
0 commit comments