Skip to content

Commit

Permalink
Use the expected type to decide whether || is an unboxed or boxed c…
Browse files Browse the repository at this point in the history
…losure.
  • Loading branch information
nikomatsakis committed Nov 19, 2014
1 parent 3e2929d commit b9c5cd4
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 49 deletions.
108 changes: 59 additions & 49 deletions src/librustc/middle/typeck/check/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,59 +32,62 @@ pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
decl: &ast::FnDecl,
body: &ast::Block,
expected: Expectation<'tcx>) {
debug!("check_expr_closure(expr={},expected={})",
expr.repr(fcx.tcx()),
expected.repr(fcx.tcx()));

match opt_kind {
None => { // old-school boxed closure
let region = astconv::opt_ast_region_to_region(fcx,
fcx.infcx(),
expr.span,
&None);
check_boxed_closure(fcx,
expr,
ty::RegionTraitStore(region, ast::MutMutable),
decl,
body,
expected);
None => {
// If users didn't specify what sort of closure they want,
// examine the expected type. For now, if we see explicit
// evidence than an unboxed closure is desired, we'll use
// that, otherwise we'll fall back to boxed closures.
match deduce_unboxed_closure_expectations_from_expectation(fcx, expected) {
None => { // doesn't look like an unboxed closure
let region = astconv::opt_ast_region_to_region(fcx,
fcx.infcx(),
expr.span,
&None);
check_boxed_closure(fcx,
expr,
ty::RegionTraitStore(region, ast::MutMutable),
decl,
body,
expected);
}
Some((sig, kind)) => {
check_unboxed_closure(fcx, expr, kind, decl, body, Some(sig));
}
}
}

Some(kind) => {
check_unboxed_closure(fcx, expr, kind, decl, body, expected)
let kind = match kind {
ast::FnUnboxedClosureKind => ty::FnUnboxedClosureKind,
ast::FnMutUnboxedClosureKind => ty::FnMutUnboxedClosureKind,
ast::FnOnceUnboxedClosureKind => ty::FnOnceUnboxedClosureKind,
};

let expected_sig =
deduce_unboxed_closure_expectations_from_expectation(fcx, expected)
.map(|t| t.0);

check_unboxed_closure(fcx, expr, kind, decl, body, expected_sig);
}
}
}

fn check_unboxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
expr: &ast::Expr,
kind: ast::UnboxedClosureKind,
kind: ty::UnboxedClosureKind,
decl: &ast::FnDecl,
body: &ast::Block,
expected: Expectation<'tcx>) {
expected_sig: Option<ty::FnSig<'tcx>>) {
let expr_def_id = ast_util::local_def(expr.id);

let expected_sig_and_kind = match expected.resolve(fcx) {
NoExpectation => None,
ExpectCastableToType(t) | ExpectHasType(t) => {
deduce_unboxed_closure_expectations_from_expected_type(fcx, t)
}
};

let (expected_sig, expected_kind) = match expected_sig_and_kind {
None => (None, None),
Some((sig, kind)) => {
// Avoid accidental capture of bound regions by renaming
// them to fresh names, basically.
let sig =
ty::replace_late_bound_regions(
fcx.tcx(),
&sig,
|_, debruijn| fcx.inh.infcx.fresh_bound_region(debruijn)).0;
(Some(sig), Some(kind))
}
};

debug!("check_unboxed_closure expected={} expected_sig={} expected_kind={}",
expected.repr(fcx.tcx()),
expected_sig.repr(fcx.tcx()),
expected_kind);
debug!("check_unboxed_closure kind={} expected_sig={}",
kind,
expected_sig.repr(fcx.tcx()));

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

let kind = match kind {
ast::FnUnboxedClosureKind => ty::FnUnboxedClosureKind,
ast::FnMutUnboxedClosureKind => ty::FnMutUnboxedClosureKind,
ast::FnOnceUnboxedClosureKind => ty::FnOnceUnboxedClosureKind,
};

debug!("unboxed_closure for {} --> sig={} kind={}",
expr_def_id.repr(fcx.tcx()),
fn_ty.sig.repr(fcx.tcx()),
Expand All @@ -152,10 +149,23 @@ fn check_unboxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
.insert(expr_def_id, unboxed_closure);
}

fn deduce_unboxed_closure_expectations_from_expected_type<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
expected_ty: Ty<'tcx>)
-> Option<(ty::FnSig<'tcx>,
ty::UnboxedClosureKind)>
fn deduce_unboxed_closure_expectations_from_expectation<'a,'tcx>(
fcx: &FnCtxt<'a,'tcx>,
expected: Expectation<'tcx>)
-> Option<(ty::FnSig<'tcx>,ty::UnboxedClosureKind)>
{
match expected.resolve(fcx) {
NoExpectation => None,
ExpectCastableToType(t) | ExpectHasType(t) => {
deduce_unboxed_closure_expectations_from_expected_type(fcx, t)
}
}
}

fn deduce_unboxed_closure_expectations_from_expected_type<'a,'tcx>(
fcx: &FnCtxt<'a,'tcx>,
expected_ty: Ty<'tcx>)
-> Option<(ty::FnSig<'tcx>,ty::UnboxedClosureKind)>
{
match expected_ty.sty {
ty::ty_trait(ref object_type) => {
Expand Down
38 changes: 38 additions & 0 deletions src/test/run-pass/unboxed-closures-infer-kind.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2014 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 can infer the "kind" of an unboxed closure based on
// the expected type.

#![feature(unboxed_closures)]

// Test by-ref capture of environment in unboxed closure types

fn call_fn<F: Fn()>(f: F) {
f()
}

fn call_fn_mut<F: FnMut()>(mut f: F) {
f()
}

fn call_fn_once<F: FnOnce()>(f: F) {
f()
}

fn main() {
let mut x = 0u;
let y = 2u;

call_fn(|| assert_eq!(x, 0));
call_fn_mut(|| x += y);
call_fn_once(|| x += y);
assert_eq!(x, y * 2);
}

5 comments on commit b9c5cd4

@bors
Copy link
Contributor

@bors bors commented on b9c5cd4 Nov 20, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from acrichto
at nikomatsakis@b9c5cd4

@bors
Copy link
Contributor

@bors bors commented on b9c5cd4 Nov 20, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging nikomatsakis/rust/unboxed-boxed-closure-unification = b9c5cd4 into auto

@bors
Copy link
Contributor

@bors bors commented on b9c5cd4 Nov 20, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nikomatsakis/rust/unboxed-boxed-closure-unification = b9c5cd4 merged ok, testing candidate = 1d81776

@bors
Copy link
Contributor

@bors bors commented on b9c5cd4 Nov 20, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bors
Copy link
Contributor

@bors bors commented on b9c5cd4 Nov 20, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fast-forwarding master to auto = 1d81776

Please sign in to comment.