Skip to content

Commit b9c5cd4

Browse files
committed
Use the expected type to decide whether || is an unboxed or boxed closure.
1 parent 3e2929d commit b9c5cd4

File tree

2 files changed

+97
-49
lines changed

2 files changed

+97
-49
lines changed

src/librustc/middle/typeck/check/closure.rs

+59-49
Original file line numberDiff line numberDiff line change
@@ -32,59 +32,62 @@ pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
3232
decl: &ast::FnDecl,
3333
body: &ast::Block,
3434
expected: Expectation<'tcx>) {
35+
debug!("check_expr_closure(expr={},expected={})",
36+
expr.repr(fcx.tcx()),
37+
expected.repr(fcx.tcx()));
38+
3539
match opt_kind {
36-
None => { // old-school boxed closure
37-
let region = astconv::opt_ast_region_to_region(fcx,
38-
fcx.infcx(),
39-
expr.span,
40-
&None);
41-
check_boxed_closure(fcx,
42-
expr,
43-
ty::RegionTraitStore(region, ast::MutMutable),
44-
decl,
45-
body,
46-
expected);
40+
None => {
41+
// If users didn't specify what sort of closure they want,
42+
// examine the expected type. For now, if we see explicit
43+
// evidence than an unboxed closure is desired, we'll use
44+
// that, otherwise we'll fall back to boxed closures.
45+
match deduce_unboxed_closure_expectations_from_expectation(fcx, expected) {
46+
None => { // doesn't look like an unboxed closure
47+
let region = astconv::opt_ast_region_to_region(fcx,
48+
fcx.infcx(),
49+
expr.span,
50+
&None);
51+
check_boxed_closure(fcx,
52+
expr,
53+
ty::RegionTraitStore(region, ast::MutMutable),
54+
decl,
55+
body,
56+
expected);
57+
}
58+
Some((sig, kind)) => {
59+
check_unboxed_closure(fcx, expr, kind, decl, body, Some(sig));
60+
}
61+
}
4762
}
4863

4964
Some(kind) => {
50-
check_unboxed_closure(fcx, expr, kind, decl, body, expected)
65+
let kind = match kind {
66+
ast::FnUnboxedClosureKind => ty::FnUnboxedClosureKind,
67+
ast::FnMutUnboxedClosureKind => ty::FnMutUnboxedClosureKind,
68+
ast::FnOnceUnboxedClosureKind => ty::FnOnceUnboxedClosureKind,
69+
};
70+
71+
let expected_sig =
72+
deduce_unboxed_closure_expectations_from_expectation(fcx, expected)
73+
.map(|t| t.0);
74+
75+
check_unboxed_closure(fcx, expr, kind, decl, body, expected_sig);
5176
}
5277
}
5378
}
5479

5580
fn check_unboxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
5681
expr: &ast::Expr,
57-
kind: ast::UnboxedClosureKind,
82+
kind: ty::UnboxedClosureKind,
5883
decl: &ast::FnDecl,
5984
body: &ast::Block,
60-
expected: Expectation<'tcx>) {
85+
expected_sig: Option<ty::FnSig<'tcx>>) {
6186
let expr_def_id = ast_util::local_def(expr.id);
6287

63-
let expected_sig_and_kind = match expected.resolve(fcx) {
64-
NoExpectation => None,
65-
ExpectCastableToType(t) | ExpectHasType(t) => {
66-
deduce_unboxed_closure_expectations_from_expected_type(fcx, t)
67-
}
68-
};
69-
70-
let (expected_sig, expected_kind) = match expected_sig_and_kind {
71-
None => (None, None),
72-
Some((sig, kind)) => {
73-
// Avoid accidental capture of bound regions by renaming
74-
// them to fresh names, basically.
75-
let sig =
76-
ty::replace_late_bound_regions(
77-
fcx.tcx(),
78-
&sig,
79-
|_, debruijn| fcx.inh.infcx.fresh_bound_region(debruijn)).0;
80-
(Some(sig), Some(kind))
81-
}
82-
};
83-
84-
debug!("check_unboxed_closure expected={} expected_sig={} expected_kind={}",
85-
expected.repr(fcx.tcx()),
86-
expected_sig.repr(fcx.tcx()),
87-
expected_kind);
88+
debug!("check_unboxed_closure kind={} expected_sig={}",
89+
kind,
90+
expected_sig.repr(fcx.tcx()));
8891

8992
let mut fn_ty = astconv::ty_of_closure(
9093
fcx,
@@ -130,12 +133,6 @@ fn check_unboxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
130133
// the `unboxed_closures` table.
131134
fn_ty.sig.inputs = vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.inputs)];
132135

133-
let kind = match kind {
134-
ast::FnUnboxedClosureKind => ty::FnUnboxedClosureKind,
135-
ast::FnMutUnboxedClosureKind => ty::FnMutUnboxedClosureKind,
136-
ast::FnOnceUnboxedClosureKind => ty::FnOnceUnboxedClosureKind,
137-
};
138-
139136
debug!("unboxed_closure for {} --> sig={} kind={}",
140137
expr_def_id.repr(fcx.tcx()),
141138
fn_ty.sig.repr(fcx.tcx()),
@@ -152,10 +149,23 @@ fn check_unboxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
152149
.insert(expr_def_id, unboxed_closure);
153150
}
154151

155-
fn deduce_unboxed_closure_expectations_from_expected_type<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
156-
expected_ty: Ty<'tcx>)
157-
-> Option<(ty::FnSig<'tcx>,
158-
ty::UnboxedClosureKind)>
152+
fn deduce_unboxed_closure_expectations_from_expectation<'a,'tcx>(
153+
fcx: &FnCtxt<'a,'tcx>,
154+
expected: Expectation<'tcx>)
155+
-> Option<(ty::FnSig<'tcx>,ty::UnboxedClosureKind)>
156+
{
157+
match expected.resolve(fcx) {
158+
NoExpectation => None,
159+
ExpectCastableToType(t) | ExpectHasType(t) => {
160+
deduce_unboxed_closure_expectations_from_expected_type(fcx, t)
161+
}
162+
}
163+
}
164+
165+
fn deduce_unboxed_closure_expectations_from_expected_type<'a,'tcx>(
166+
fcx: &FnCtxt<'a,'tcx>,
167+
expected_ty: Ty<'tcx>)
168+
-> Option<(ty::FnSig<'tcx>,ty::UnboxedClosureKind)>
159169
{
160170
match expected_ty.sty {
161171
ty::ty_trait(ref object_type) => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that we can infer the "kind" of an unboxed closure based on
12+
// the expected type.
13+
14+
#![feature(unboxed_closures)]
15+
16+
// Test by-ref capture of environment in unboxed closure types
17+
18+
fn call_fn<F: Fn()>(f: F) {
19+
f()
20+
}
21+
22+
fn call_fn_mut<F: FnMut()>(mut f: F) {
23+
f()
24+
}
25+
26+
fn call_fn_once<F: FnOnce()>(f: F) {
27+
f()
28+
}
29+
30+
fn main() {
31+
let mut x = 0u;
32+
let y = 2u;
33+
34+
call_fn(|| assert_eq!(x, 0));
35+
call_fn_mut(|| x += y);
36+
call_fn_once(|| x += y);
37+
assert_eq!(x, y * 2);
38+
}

0 commit comments

Comments
 (0)