mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-11 17:37:41 +00:00
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)
|
self.select(&mut selcx, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pending_trait_obligations(&self) -> &[Obligation<'tcx>] {
|
||||||
|
self.trait_obligations[]
|
||||||
|
}
|
||||||
|
|
||||||
fn select<'a>(&mut self,
|
fn select<'a>(&mut self,
|
||||||
selcx: &mut SelectionContext<'a, 'tcx>,
|
selcx: &mut SelectionContext<'a, 'tcx>,
|
||||||
only_new_obligations: bool)
|
only_new_obligations: bool)
|
||||||
|
@ -13,10 +13,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use super::check_fn;
|
use super::check_fn;
|
||||||
use super::Expectation;
|
use super::{Expectation, ExpectCastableToType, ExpectHasType, NoExpectation};
|
||||||
use super::FnCtxt;
|
use super::FnCtxt;
|
||||||
|
|
||||||
use middle::ty;
|
use middle::subst;
|
||||||
|
use middle::ty::{mod, Ty};
|
||||||
use middle::typeck::astconv;
|
use middle::typeck::astconv;
|
||||||
use middle::typeck::infer;
|
use middle::typeck::infer;
|
||||||
use middle::typeck::rscope::RegionScope;
|
use middle::typeck::rscope::RegionScope;
|
||||||
@ -25,13 +26,40 @@ use syntax::ast;
|
|||||||
use syntax::ast_util;
|
use syntax::ast_util;
|
||||||
use util::ppaux::Repr;
|
use util::ppaux::Repr;
|
||||||
|
|
||||||
pub fn check_unboxed_closure(fcx: &FnCtxt,
|
pub fn check_unboxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
||||||
expr: &ast::Expr,
|
expr: &ast::Expr,
|
||||||
kind: ast::UnboxedClosureKind,
|
kind: ast::UnboxedClosureKind,
|
||||||
decl: &ast::FnDecl,
|
decl: &ast::FnDecl,
|
||||||
body: &ast::Block) {
|
body: &ast::Block,
|
||||||
|
expected: Expectation<'tcx>) {
|
||||||
let expr_def_id = ast_util::local_def(expr.id);
|
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(
|
let mut fn_ty = astconv::ty_of_closure(
|
||||||
fcx,
|
fcx,
|
||||||
ast::NormalFn,
|
ast::NormalFn,
|
||||||
@ -46,7 +74,7 @@ pub fn check_unboxed_closure(fcx: &FnCtxt,
|
|||||||
|
|
||||||
decl,
|
decl,
|
||||||
abi::RustCall,
|
abi::RustCall,
|
||||||
None);
|
expected_sig);
|
||||||
|
|
||||||
let region = match fcx.infcx().anon_regions(expr.span, 1) {
|
let region = match fcx.infcx().anon_regions(expr.span, 1) {
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
@ -98,6 +126,95 @@ pub fn check_unboxed_closure(fcx: &FnCtxt,
|
|||||||
.insert(expr_def_id, unboxed_closure);
|
.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>,
|
pub fn check_expr_fn<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
||||||
expr: &ast::Expr,
|
expr: &ast::Expr,
|
||||||
store: ty::TraitStore,
|
store: ty::TraitStore,
|
||||||
|
@ -78,7 +78,7 @@ type parameter).
|
|||||||
|
|
||||||
pub use self::LvaluePreference::*;
|
pub use self::LvaluePreference::*;
|
||||||
pub use self::DerefArgs::*;
|
pub use self::DerefArgs::*;
|
||||||
use self::Expectation::*;
|
pub use self::Expectation::*;
|
||||||
use self::IsBinopAssignment::*;
|
use self::IsBinopAssignment::*;
|
||||||
use self::TupleArgumentsFlag::*;
|
use self::TupleArgumentsFlag::*;
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ use middle::ty::{FnSig, VariantInfo};
|
|||||||
use middle::ty::{Polytype};
|
use middle::ty::{Polytype};
|
||||||
use middle::ty::{Disr, ParamTy, ParameterEnvironment};
|
use middle::ty::{Disr, ParamTy, ParameterEnvironment};
|
||||||
use middle::ty::{mod, Ty};
|
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::ty_fold::TypeFolder;
|
||||||
use middle::typeck::astconv::AstConv;
|
use middle::typeck::astconv::AstConv;
|
||||||
use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty};
|
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,
|
expr,
|
||||||
kind,
|
kind,
|
||||||
&**decl,
|
&**decl,
|
||||||
&**body);
|
&**body,
|
||||||
|
expected);
|
||||||
}
|
}
|
||||||
ast::ExprProc(ref decl, ref body) => {
|
ast::ExprProc(ref decl, ref body) => {
|
||||||
closure::check_expr_fn(fcx,
|
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…
Reference in New Issue
Block a user