Deduce the argument types based on the expected type, trawling through the fulfillment contect if necessary.
This commit is contained in:
parent
fe2fcb39f4
commit
8e44688889
@ -109,6 +109,10 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
||||
self.select(&mut selcx, false)
|
||||
}
|
||||
|
||||
pub fn pending_trait_obligations(&self) -> &[Obligation<'tcx>] {
|
||||
self.trait_obligations[]
|
||||
}
|
||||
|
||||
fn select<'a>(&mut self,
|
||||
selcx: &mut SelectionContext<'a, 'tcx>,
|
||||
only_new_obligations: bool)
|
||||
|
@ -13,10 +13,11 @@
|
||||
*/
|
||||
|
||||
use super::check_fn;
|
||||
use super::Expectation;
|
||||
use super::{Expectation, ExpectCastableToType, ExpectHasType, NoExpectation};
|
||||
use super::FnCtxt;
|
||||
|
||||
use middle::ty;
|
||||
use middle::subst;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::typeck::astconv;
|
||||
use middle::typeck::infer;
|
||||
use middle::typeck::rscope::RegionScope;
|
||||
@ -25,13 +26,40 @@ use syntax::ast;
|
||||
use syntax::ast_util;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
pub fn check_unboxed_closure(fcx: &FnCtxt,
|
||||
expr: &ast::Expr,
|
||||
kind: ast::UnboxedClosureKind,
|
||||
decl: &ast::FnDecl,
|
||||
body: &ast::Block) {
|
||||
pub fn check_unboxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
||||
expr: &ast::Expr,
|
||||
kind: ast::UnboxedClosureKind,
|
||||
decl: &ast::FnDecl,
|
||||
body: &ast::Block,
|
||||
expected: Expectation<'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);
|
||||
|
||||
let mut fn_ty = astconv::ty_of_closure(
|
||||
fcx,
|
||||
ast::NormalFn,
|
||||
@ -46,7 +74,7 @@ pub fn check_unboxed_closure(fcx: &FnCtxt,
|
||||
|
||||
decl,
|
||||
abi::RustCall,
|
||||
None);
|
||||
expected_sig);
|
||||
|
||||
let region = match fcx.infcx().anon_regions(expr.span, 1) {
|
||||
Err(_) => {
|
||||
@ -98,6 +126,95 @@ pub fn check_unboxed_closure(fcx: &FnCtxt,
|
||||
.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)>
|
||||
{
|
||||
match expected_ty.sty {
|
||||
ty::ty_trait(ref object_type) => {
|
||||
deduce_unboxed_closure_expectations_from_trait_ref(fcx, &object_type.principal)
|
||||
}
|
||||
ty::ty_infer(ty::TyVar(vid)) => {
|
||||
deduce_unboxed_closure_expectations_from_obligations(fcx, vid)
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>(
|
||||
fcx: &FnCtxt<'a,'tcx>,
|
||||
trait_ref: &ty::TraitRef<'tcx>)
|
||||
-> Option<(ty::FnSig<'tcx>, ty::UnboxedClosureKind)>
|
||||
{
|
||||
let tcx = fcx.tcx();
|
||||
|
||||
debug!("deduce_unboxed_closure_expectations_from_object_type({})",
|
||||
trait_ref.repr(tcx));
|
||||
|
||||
let def_id_kinds = [
|
||||
(tcx.lang_items.fn_trait(), ty::FnUnboxedClosureKind),
|
||||
(tcx.lang_items.fn_mut_trait(), ty::FnMutUnboxedClosureKind),
|
||||
(tcx.lang_items.fn_once_trait(), ty::FnOnceUnboxedClosureKind),
|
||||
];
|
||||
|
||||
for &(def_id, kind) in def_id_kinds.iter() {
|
||||
if Some(trait_ref.def_id) == def_id {
|
||||
debug!("found object type {}", kind);
|
||||
|
||||
let arg_param_ty = *trait_ref.substs.types.get(subst::TypeSpace, 0);
|
||||
let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(arg_param_ty);
|
||||
debug!("arg_param_ty {}", arg_param_ty.repr(tcx));
|
||||
|
||||
let input_tys = match arg_param_ty.sty {
|
||||
ty::ty_tup(ref tys) => { (*tys).clone() }
|
||||
_ => { continue; }
|
||||
};
|
||||
debug!("input_tys {}", input_tys.repr(tcx));
|
||||
|
||||
let ret_param_ty = *trait_ref.substs.types.get(subst::TypeSpace, 1);
|
||||
let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(ret_param_ty);
|
||||
debug!("ret_param_ty {}", ret_param_ty.repr(tcx));
|
||||
|
||||
let fn_sig = ty::FnSig {
|
||||
inputs: input_tys,
|
||||
output: ty::FnConverging(ret_param_ty),
|
||||
variadic: false
|
||||
};
|
||||
debug!("fn_sig {}", fn_sig.repr(tcx));
|
||||
|
||||
return Some((fn_sig, kind));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn deduce_unboxed_closure_expectations_from_obligations<'a,'tcx>(
|
||||
fcx: &FnCtxt<'a,'tcx>,
|
||||
expected_vid: ty::TyVid)
|
||||
-> Option<(ty::FnSig<'tcx>, ty::UnboxedClosureKind)>
|
||||
{
|
||||
// Here `expected_ty` is known to be a type inference variable.
|
||||
for obligation in fcx.inh.fulfillment_cx.borrow().pending_trait_obligations().iter() {
|
||||
let obligation_self_ty = fcx.infcx().shallow_resolve(obligation.self_ty());
|
||||
match obligation_self_ty.sty {
|
||||
ty::ty_infer(ty::TyVar(v)) if expected_vid == v => { }
|
||||
_ => { continue; }
|
||||
}
|
||||
|
||||
match deduce_unboxed_closure_expectations_from_trait_ref(fcx, &*obligation.trait_ref) {
|
||||
Some(e) => { return Some(e); }
|
||||
None => { }
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
|
||||
pub fn check_expr_fn<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
||||
expr: &ast::Expr,
|
||||
store: ty::TraitStore,
|
||||
|
@ -78,7 +78,7 @@ type parameter).
|
||||
|
||||
pub use self::LvaluePreference::*;
|
||||
pub use self::DerefArgs::*;
|
||||
use self::Expectation::*;
|
||||
pub use self::Expectation::*;
|
||||
use self::IsBinopAssignment::*;
|
||||
use self::TupleArgumentsFlag::*;
|
||||
|
||||
@ -97,7 +97,7 @@ use middle::ty::{FnSig, VariantInfo};
|
||||
use middle::ty::{Polytype};
|
||||
use middle::ty::{Disr, ParamTy, ParameterEnvironment};
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::ty::{replace_late_bound_regions, liberate_late_bound_regions};
|
||||
use middle::ty::liberate_late_bound_regions;
|
||||
use middle::ty_fold::TypeFolder;
|
||||
use middle::typeck::astconv::AstConv;
|
||||
use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty};
|
||||
@ -4165,7 +4165,8 @@ fn check_expr_with_unifier<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
expr,
|
||||
kind,
|
||||
&**decl,
|
||||
&**body);
|
||||
&**body,
|
||||
expected);
|
||||
}
|
||||
ast::ExprProc(ref decl, ref body) => {
|
||||
closure::check_expr_fn(fcx,
|
||||
|
19
src/test/compile-fail/regions-escape-unboxed-closure.rs
Normal file
19
src/test/compile-fail/regions-escape-unboxed-closure.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2012 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.
|
||||
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
fn with_int(f: &mut FnMut(&int)) {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut x: Option<&int> = None;
|
||||
with_int(&mut |&mut: y| x = Some(y)); //~ ERROR cannot infer
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
// That a closure whose expected argument types include two distinct
|
||||
// bound regions.
|
||||
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
fn doit<T,F>(val: T, f: &F)
|
||||
where F : Fn(&Cell<&T>, &T)
|
||||
{
|
||||
let x = Cell::new(&val);
|
||||
f.call((&x,&val))
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
doit(0i, &|&: x, y| {
|
||||
x.set(y); //~ ERROR cannot infer
|
||||
});
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
// 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 are able to infer that the type of `x` is `int` based
|
||||
// on the expected type from the object.
|
||||
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
fn doit<T,F>(val: T, f: &F)
|
||||
where F : Fn(T)
|
||||
{
|
||||
f.call((val,))
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
doit(0i, &|&: x /*: int*/ | { x.to_int(); });
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
// 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 are able to infer that the type of `x` is `int` based
|
||||
// on the expected type from the object.
|
||||
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
fn doit<T>(val: T, f: &Fn(T)) { f.call((val,)) }
|
||||
|
||||
pub fn main() {
|
||||
doit(0i, &|&: x /*: int*/ | { x.to_int(); });
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
// 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 are able to infer that the type of `x` is `int` based
|
||||
// on the expected type from the object.
|
||||
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
fn doit<T,F>(val: T, f: &F)
|
||||
where F : Fn(&T)
|
||||
{
|
||||
f.call((&val,))
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
doit(0i, &|&: x /*: int*/ | { x.to_int(); });
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user