mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-04 11:54:34 +00:00
Move return type an associated type of the Fn*
traits. Mostly this involves tweaking things in
the compiler that assumed two input types to assume two ouputs; we also have to teach `project.rs` to project `Output` from the unboxed closure and fn traits.
This commit is contained in:
parent
c61d7889b4
commit
07cdb85331
@ -758,7 +758,9 @@ mod test {
|
||||
expected: &'b [int],
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'c> FnMut(&'c int) -> bool for Counter<'a, 'b> {
|
||||
impl<'a, 'b, 'c> FnMut<(&'c int,)> for Counter<'a, 'b> {
|
||||
type Output = bool;
|
||||
|
||||
extern "rust-call" fn call_mut(&mut self, (&x,): (&'c int,)) -> bool {
|
||||
assert_eq!(x, self.expected[*self.i]);
|
||||
*self.i += 1;
|
||||
|
@ -1117,29 +1117,33 @@ impl<'a, T: ?Sized> DerefMut for &'a mut T {
|
||||
#[lang="fn"]
|
||||
#[unstable(feature = "core",
|
||||
reason = "uncertain about variadic generics, input versus associated types")]
|
||||
pub trait Fn<Args,Result> {
|
||||
#[cfg(stage0)]
|
||||
pub trait Fn<Args,Output> {
|
||||
/// This is called when the call operator is used.
|
||||
extern "rust-call" fn call(&self, args: Args) -> Result;
|
||||
extern "rust-call" fn call(&self, args: Args) -> Output;
|
||||
}
|
||||
|
||||
/// A version of the call operator that takes a mutable receiver.
|
||||
#[lang="fn_mut"]
|
||||
#[unstable(feature = "core",
|
||||
reason = "uncertain about variadic generics, input versus associated types")]
|
||||
pub trait FnMut<Args,Result> {
|
||||
#[cfg(stage0)]
|
||||
pub trait FnMut<Args,Output> {
|
||||
/// This is called when the call operator is used.
|
||||
extern "rust-call" fn call_mut(&mut self, args: Args) -> Result;
|
||||
extern "rust-call" fn call_mut(&mut self, args: Args) -> Output;
|
||||
}
|
||||
|
||||
/// A version of the call operator that takes a by-value receiver.
|
||||
#[lang="fn_once"]
|
||||
#[unstable(feature = "core",
|
||||
reason = "uncertain about variadic generics, input versus associated types")]
|
||||
pub trait FnOnce<Args,Result> {
|
||||
#[cfg(stage0)]
|
||||
pub trait FnOnce<Args,Output> {
|
||||
/// This is called when the call operator is used.
|
||||
extern "rust-call" fn call_once(self, args: Args) -> Result;
|
||||
extern "rust-call" fn call_once(self, args: Args) -> Output;
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<F: ?Sized, A, R> FnMut<A, R> for F
|
||||
where F : Fn<A, R>
|
||||
{
|
||||
@ -1148,6 +1152,7 @@ impl<F: ?Sized, A, R> FnMut<A, R> for F
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<F,A,R> FnOnce<A,R> for F
|
||||
where F : FnMut<A,R>
|
||||
{
|
||||
@ -1155,3 +1160,61 @@ impl<F,A,R> FnOnce<A,R> for F
|
||||
self.call_mut(args)
|
||||
}
|
||||
}
|
||||
|
||||
/// A version of the call operator that takes an immutable receiver.
|
||||
#[lang="fn"]
|
||||
#[unstable(feature = "core",
|
||||
reason = "uncertain about variadic generics, input versus associated types")]
|
||||
#[cfg(not(stage0))]
|
||||
pub trait Fn<Args> {
|
||||
type Output;
|
||||
|
||||
/// This is called when the call operator is used.
|
||||
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
|
||||
}
|
||||
|
||||
/// A version of the call operator that takes a mutable receiver.
|
||||
#[lang="fn_mut"]
|
||||
#[unstable(feature = "core",
|
||||
reason = "uncertain about variadic generics, input versus associated types")]
|
||||
#[cfg(not(stage0))]
|
||||
pub trait FnMut<Args> {
|
||||
type Output;
|
||||
|
||||
/// This is called when the call operator is used.
|
||||
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
|
||||
}
|
||||
|
||||
/// A version of the call operator that takes a by-value receiver.
|
||||
#[lang="fn_once"]
|
||||
#[unstable(feature = "core",
|
||||
reason = "uncertain about variadic generics, input versus associated types")]
|
||||
#[cfg(not(stage0))]
|
||||
pub trait FnOnce<Args> {
|
||||
type Output;
|
||||
|
||||
/// This is called when the call operator is used.
|
||||
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl<F: ?Sized, A> FnMut<A> for F
|
||||
where F : Fn<A>
|
||||
{
|
||||
type Output = <F as Fn<A>>::Output;
|
||||
|
||||
extern "rust-call" fn call_mut(&mut self, args: A) -> <F as Fn<A>>::Output {
|
||||
self.call(args)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl<F,A> FnOnce<A> for F
|
||||
where F : FnMut<A>
|
||||
{
|
||||
type Output = <F as FnMut<A>>::Output;
|
||||
|
||||
extern "rust-call" fn call_once(mut self, args: A) -> <F as FnMut<A>>::Output {
|
||||
self.call_mut(args)
|
||||
}
|
||||
}
|
||||
|
@ -461,6 +461,7 @@ delegate_iter!{exact u8 : Bytes<'a>}
|
||||
#[derive(Copy, Clone)]
|
||||
struct BytesDeref;
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<'a> Fn(&'a u8) -> u8 for BytesDeref {
|
||||
#[inline]
|
||||
extern "rust-call" fn call(&self, (ptr,): (&'a u8,)) -> u8 {
|
||||
@ -468,6 +469,16 @@ impl<'a> Fn(&'a u8) -> u8 for BytesDeref {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl<'a> Fn<(&'a u8,)> for BytesDeref {
|
||||
type Output = u8;
|
||||
|
||||
#[inline]
|
||||
extern "rust-call" fn call(&self, (ptr,): (&'a u8,)) -> u8 {
|
||||
*ptr
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over the substrings of a string, separated by `sep`.
|
||||
#[derive(Clone)]
|
||||
struct CharSplits<'a, Sep> {
|
||||
|
@ -18,13 +18,17 @@ use super::PredicateObligation;
|
||||
use super::SelectionContext;
|
||||
use super::SelectionError;
|
||||
use super::VtableImplData;
|
||||
use super::util;
|
||||
|
||||
use middle::infer;
|
||||
use middle::subst::Subst;
|
||||
use middle::subst::{Subst, Substs};
|
||||
use middle::ty::{self, AsPredicate, ReferencesError, RegionEscape,
|
||||
HasProjectionTypes, ToPolyTraitRef, Ty};
|
||||
use middle::ty_fold::{self, TypeFoldable, TypeFolder};
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax::parse::token;
|
||||
use util::common::FN_OUTPUT_NAME;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
pub type PolyProjectionObligation<'tcx> =
|
||||
@ -53,6 +57,8 @@ pub struct MismatchedProjectionTypes<'tcx> {
|
||||
enum ProjectionTyCandidate<'tcx> {
|
||||
ParamEnv(ty::PolyProjectionPredicate<'tcx>),
|
||||
Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>),
|
||||
Closure(ast::DefId, Substs<'tcx>),
|
||||
FnPointer(Ty<'tcx>),
|
||||
}
|
||||
|
||||
struct ProjectionTyCandidateSet<'tcx> {
|
||||
@ -486,20 +492,22 @@ fn assemble_candidates_from_predicates<'cx,'tcx>(
|
||||
|
||||
let is_match = same_name && infcx.probe(|_| {
|
||||
let origin = infer::Misc(obligation.cause.span);
|
||||
let obligation_poly_trait_ref =
|
||||
obligation_trait_ref.to_poly_trait_ref();
|
||||
let data_poly_trait_ref =
|
||||
data.to_poly_trait_ref();
|
||||
let obligation_poly_trait_ref =
|
||||
obligation_trait_ref.to_poly_trait_ref();
|
||||
infcx.sub_poly_trait_refs(false,
|
||||
origin,
|
||||
obligation_poly_trait_ref,
|
||||
data_poly_trait_ref).is_ok()
|
||||
data_poly_trait_ref,
|
||||
obligation_poly_trait_ref).is_ok()
|
||||
});
|
||||
|
||||
if is_match {
|
||||
debug!("assemble_candidates_from_predicates: candidate {}",
|
||||
data.repr(selcx.tcx()));
|
||||
debug!("assemble_candidates_from_predicates: candidate {} is_match {} same_name {}",
|
||||
data.repr(selcx.tcx()),
|
||||
is_match,
|
||||
same_name);
|
||||
|
||||
if is_match {
|
||||
candidate_set.vec.push(
|
||||
ProjectionTyCandidate::ParamEnv(data.clone()));
|
||||
}
|
||||
@ -573,6 +581,14 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
|
||||
selcx, obligation, obligation_trait_ref, candidate_set,
|
||||
data.object_ty);
|
||||
}
|
||||
super::VtableClosure(closure_def_id, substs) => {
|
||||
candidate_set.vec.push(
|
||||
ProjectionTyCandidate::Closure(closure_def_id, substs));
|
||||
}
|
||||
super::VtableFnPointer(fn_type) => {
|
||||
candidate_set.vec.push(
|
||||
ProjectionTyCandidate::FnPointer(fn_type));
|
||||
}
|
||||
super::VtableParam(..) => {
|
||||
// This case tell us nothing about the value of an
|
||||
// associated type. Consider:
|
||||
@ -600,9 +616,7 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
|
||||
// projection. And the projection where clause is handled
|
||||
// in `assemble_candidates_from_param_env`.
|
||||
}
|
||||
super::VtableBuiltin(..) |
|
||||
super::VtableClosure(..) |
|
||||
super::VtableFnPointer(..) => {
|
||||
super::VtableBuiltin(..) => {
|
||||
// These traits have no associated types.
|
||||
selcx.tcx().sess.span_bug(
|
||||
obligation.cause.span,
|
||||
@ -628,67 +642,150 @@ fn confirm_candidate<'cx,'tcx>(
|
||||
|
||||
match candidate {
|
||||
ProjectionTyCandidate::ParamEnv(poly_projection) => {
|
||||
let projection =
|
||||
infcx.replace_late_bound_regions_with_fresh_var(
|
||||
obligation.cause.span,
|
||||
infer::LateBoundRegionConversionTime::HigherRankedType,
|
||||
&poly_projection).0;
|
||||
|
||||
assert_eq!(projection.projection_ty.item_name,
|
||||
obligation.predicate.item_name);
|
||||
|
||||
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
|
||||
match infcx.sub_trait_refs(false,
|
||||
origin,
|
||||
obligation.predicate.trait_ref.clone(),
|
||||
projection.projection_ty.trait_ref.clone()) {
|
||||
Ok(()) => { }
|
||||
Err(e) => {
|
||||
selcx.tcx().sess.span_bug(
|
||||
obligation.cause.span,
|
||||
format!("Failed to unify `{}` and `{}` in projection: {}",
|
||||
obligation.repr(selcx.tcx()),
|
||||
projection.repr(selcx.tcx()),
|
||||
ty::type_err_to_str(selcx.tcx(), &e)).as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
(projection.ty, vec!())
|
||||
confirm_param_env_candidate(selcx, obligation, poly_projection)
|
||||
}
|
||||
|
||||
ProjectionTyCandidate::Impl(impl_vtable) => {
|
||||
// there don't seem to be nicer accessors to these:
|
||||
let impl_items_map = selcx.tcx().impl_items.borrow();
|
||||
let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow();
|
||||
confirm_impl_candidate(selcx, obligation, impl_vtable)
|
||||
}
|
||||
|
||||
let impl_items = &impl_items_map[impl_vtable.impl_def_id];
|
||||
let mut impl_ty = None;
|
||||
for impl_item in impl_items.iter() {
|
||||
let assoc_type = match impl_or_trait_items_map[impl_item.def_id()] {
|
||||
ty::TypeTraitItem(ref assoc_type) => assoc_type.clone(),
|
||||
ty::MethodTraitItem(..) => { continue; }
|
||||
};
|
||||
ProjectionTyCandidate::Closure(def_id, substs) => {
|
||||
confirm_closure_candidate(selcx, obligation, def_id, &substs)
|
||||
}
|
||||
|
||||
if assoc_type.name != obligation.predicate.item_name {
|
||||
continue;
|
||||
}
|
||||
ProjectionTyCandidate::FnPointer(fn_type) => {
|
||||
confirm_fn_pointer_candidate(selcx, obligation, fn_type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let impl_poly_ty = ty::lookup_item_type(selcx.tcx(), assoc_type.def_id);
|
||||
impl_ty = Some(impl_poly_ty.ty.subst(selcx.tcx(), &impl_vtable.substs));
|
||||
break;
|
||||
}
|
||||
fn confirm_fn_pointer_candidate<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
fn_type: Ty<'tcx>)
|
||||
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
|
||||
{
|
||||
let fn_type = selcx.infcx().shallow_resolve(fn_type);
|
||||
let sig = ty::ty_fn_sig(fn_type);
|
||||
confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes)
|
||||
}
|
||||
|
||||
match impl_ty {
|
||||
Some(ty) => (ty, impl_vtable.nested.into_vec()),
|
||||
None => {
|
||||
// This means that the impl is missing a
|
||||
// definition for the associated type. This error
|
||||
// ought to be reported by the type checker method
|
||||
// `check_impl_items_against_trait`, so here we
|
||||
// just return ty_err.
|
||||
(selcx.tcx().types.err, vec!())
|
||||
}
|
||||
}
|
||||
fn confirm_closure_candidate<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
closure_def_id: ast::DefId,
|
||||
substs: &Substs<'tcx>)
|
||||
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
|
||||
{
|
||||
let closure_typer = selcx.closure_typer();
|
||||
let closure_type = closure_typer.closure_type(closure_def_id, substs);
|
||||
confirm_callable_candidate(selcx, obligation, &closure_type.sig, util::TupleArgumentsFlag::No)
|
||||
}
|
||||
|
||||
fn confirm_callable_candidate<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
fn_sig: &ty::PolyFnSig<'tcx>,
|
||||
flag: util::TupleArgumentsFlag)
|
||||
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
|
||||
{
|
||||
let tcx = selcx.tcx();
|
||||
|
||||
debug!("confirm_closure_candidate({},{})",
|
||||
obligation.repr(tcx),
|
||||
fn_sig.repr(tcx));
|
||||
|
||||
// Note: we unwrap the binder here but re-create it below (1)
|
||||
let ty::Binder((trait_ref, ret_type)) =
|
||||
util::closure_trait_ref_and_return_type(tcx,
|
||||
obligation.predicate.trait_ref.def_id,
|
||||
obligation.predicate.trait_ref.self_ty(),
|
||||
fn_sig,
|
||||
flag);
|
||||
|
||||
let predicate = ty::Binder(ty::ProjectionPredicate { // (1) recreate binder here
|
||||
projection_ty: ty::ProjectionTy {
|
||||
trait_ref: trait_ref,
|
||||
item_name: token::intern(FN_OUTPUT_NAME),
|
||||
},
|
||||
ty: ret_type
|
||||
});
|
||||
|
||||
confirm_param_env_candidate(selcx, obligation, predicate)
|
||||
}
|
||||
|
||||
fn confirm_param_env_candidate<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
poly_projection: ty::PolyProjectionPredicate<'tcx>)
|
||||
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
|
||||
{
|
||||
let infcx = selcx.infcx();
|
||||
|
||||
let projection =
|
||||
infcx.replace_late_bound_regions_with_fresh_var(
|
||||
obligation.cause.span,
|
||||
infer::LateBoundRegionConversionTime::HigherRankedType,
|
||||
&poly_projection).0;
|
||||
|
||||
assert_eq!(projection.projection_ty.item_name,
|
||||
obligation.predicate.item_name);
|
||||
|
||||
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
|
||||
match infcx.sub_trait_refs(false,
|
||||
origin,
|
||||
obligation.predicate.trait_ref.clone(),
|
||||
projection.projection_ty.trait_ref.clone()) {
|
||||
Ok(()) => { }
|
||||
Err(e) => {
|
||||
selcx.tcx().sess.span_bug(
|
||||
obligation.cause.span,
|
||||
format!("Failed to unify `{}` and `{}` in projection: {}",
|
||||
obligation.repr(selcx.tcx()),
|
||||
projection.repr(selcx.tcx()),
|
||||
ty::type_err_to_str(selcx.tcx(), &e)).as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
(projection.ty, vec!())
|
||||
}
|
||||
|
||||
fn confirm_impl_candidate<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
impl_vtable: VtableImplData<'tcx, PredicateObligation<'tcx>>)
|
||||
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
|
||||
{
|
||||
// there don't seem to be nicer accessors to these:
|
||||
let impl_items_map = selcx.tcx().impl_items.borrow();
|
||||
let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow();
|
||||
|
||||
let impl_items = &impl_items_map[impl_vtable.impl_def_id];
|
||||
let mut impl_ty = None;
|
||||
for impl_item in impl_items.iter() {
|
||||
let assoc_type = match impl_or_trait_items_map[impl_item.def_id()] {
|
||||
ty::TypeTraitItem(ref assoc_type) => assoc_type.clone(),
|
||||
ty::MethodTraitItem(..) => { continue; }
|
||||
};
|
||||
|
||||
if assoc_type.name != obligation.predicate.item_name {
|
||||
continue;
|
||||
}
|
||||
|
||||
let impl_poly_ty = ty::lookup_item_type(selcx.tcx(), assoc_type.def_id);
|
||||
impl_ty = Some(impl_poly_ty.ty.subst(selcx.tcx(), &impl_vtable.substs));
|
||||
break;
|
||||
}
|
||||
|
||||
match impl_ty {
|
||||
Some(ty) => (ty, impl_vtable.nested.into_vec()),
|
||||
None => {
|
||||
// This means that the impl is missing a
|
||||
// definition for the associated type. This error
|
||||
// ought to be reported by the type checker method
|
||||
// `check_impl_items_against_trait`, so here we
|
||||
// just return ty_err.
|
||||
(selcx.tcx().types.err, vec!())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -710,7 +807,11 @@ impl<'tcx> Repr<'tcx> for ProjectionTyCandidate<'tcx> {
|
||||
ProjectionTyCandidate::ParamEnv(ref data) =>
|
||||
format!("ParamEnv({})", data.repr(tcx)),
|
||||
ProjectionTyCandidate::Impl(ref data) =>
|
||||
format!("Impl({})", data.repr(tcx))
|
||||
format!("Impl({})", data.repr(tcx)),
|
||||
ProjectionTyCandidate::Closure(ref a, ref b) =>
|
||||
format!("Closure(({},{}))", a.repr(tcx), b.repr(tcx)),
|
||||
ProjectionTyCandidate::FnPointer(a) =>
|
||||
format!("FnPointer(({}))", a.repr(tcx)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -214,6 +214,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
self.closure_typer.param_env()
|
||||
}
|
||||
|
||||
pub fn closure_typer(&self) -> &'cx (ty::UnboxedClosureTyper<'tcx>+'cx) {
|
||||
self.closure_typer
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Selection
|
||||
//
|
||||
@ -1913,33 +1917,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
obligation.repr(self.tcx()));
|
||||
|
||||
let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
|
||||
let sig = match self_ty.sty {
|
||||
ty::ty_bare_fn(_, &ty::BareFnTy {
|
||||
unsafety: ast::Unsafety::Normal,
|
||||
abi: abi::Rust,
|
||||
ref sig
|
||||
}) => {
|
||||
sig
|
||||
}
|
||||
_ => {
|
||||
self.tcx().sess.span_bug(
|
||||
obligation.cause.span,
|
||||
&format!("Fn pointer candidate for inappropriate self type: {}",
|
||||
self_ty.repr(self.tcx()))[]);
|
||||
}
|
||||
};
|
||||
|
||||
let arguments_tuple = ty::mk_tup(self.tcx(), sig.0.inputs.to_vec());
|
||||
let output_type = sig.0.output.unwrap();
|
||||
let substs =
|
||||
Substs::new_trait(
|
||||
vec![arguments_tuple, output_type],
|
||||
vec![],
|
||||
self_ty);
|
||||
let trait_ref = ty::Binder(Rc::new(ty::TraitRef {
|
||||
def_id: obligation.predicate.def_id(),
|
||||
substs: self.tcx().mk_substs(substs),
|
||||
}));
|
||||
let sig = ty::ty_fn_sig(self_ty);
|
||||
let ty::Binder((trait_ref, _)) =
|
||||
util::closure_trait_ref_and_return_type(self.tcx(),
|
||||
obligation.predicate.def_id(),
|
||||
self_ty,
|
||||
sig,
|
||||
util::TupleArgumentsFlag::Yes);
|
||||
let trait_ref = ty::Binder(trait_ref);
|
||||
|
||||
try!(self.confirm_poly_trait_refs(obligation.cause.clone(),
|
||||
obligation.predicate.to_poly_trait_ref(),
|
||||
@ -1958,23 +1943,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
closure_def_id.repr(self.tcx()),
|
||||
substs.repr(self.tcx()));
|
||||
|
||||
let closure_type = self.closure_typer.closure_type(closure_def_id, substs);
|
||||
|
||||
debug!("confirm_closure_candidate: closure_def_id={} closure_type={}",
|
||||
closure_def_id.repr(self.tcx()),
|
||||
closure_type.repr(self.tcx()));
|
||||
|
||||
let closure_sig = &closure_type.sig;
|
||||
let arguments_tuple = closure_sig.0.inputs[0];
|
||||
let trait_substs =
|
||||
Substs::new_trait(
|
||||
vec![arguments_tuple, closure_sig.0.output.unwrap()],
|
||||
vec![],
|
||||
obligation.self_ty());
|
||||
let trait_ref = ty::Binder(Rc::new(ty::TraitRef {
|
||||
def_id: obligation.predicate.def_id(),
|
||||
substs: self.tcx().mk_substs(trait_substs),
|
||||
}));
|
||||
let trait_ref = self.closure_trait_ref(obligation,
|
||||
closure_def_id,
|
||||
substs);
|
||||
|
||||
debug!("confirm_closure_candidate(closure_def_id={}, trait_ref={})",
|
||||
closure_def_id.repr(self.tcx()),
|
||||
@ -2280,6 +2251,29 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn closure_trait_ref(&self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
closure_def_id: ast::DefId,
|
||||
substs: &Substs<'tcx>)
|
||||
-> ty::PolyTraitRef<'tcx>
|
||||
{
|
||||
let closure_type = self.closure_typer.closure_type(closure_def_id, substs);
|
||||
let ty::Binder((trait_ref, _)) =
|
||||
util::closure_trait_ref_and_return_type(self.tcx(),
|
||||
obligation.predicate.def_id(),
|
||||
obligation.predicate.0.self_ty(), // (1)
|
||||
&closure_type.sig,
|
||||
util::TupleArgumentsFlag::No);
|
||||
|
||||
// (1) Feels icky to skip the binder here, but OTOH we know
|
||||
// that the self-type is an unboxed closure type and hence is
|
||||
// in fact unparameterized (or at least does not reference any
|
||||
// regions bound in the obligation). Still probably some
|
||||
// refactoring could make this nicer.
|
||||
|
||||
ty::Binder(trait_ref)
|
||||
}
|
||||
|
||||
fn impl_obligations(&mut self,
|
||||
cause: ObligationCause<'tcx>,
|
||||
recursion_depth: uint,
|
||||
|
@ -353,6 +353,36 @@ pub fn get_vtable_index_of_object_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
method_count + method_index_in_trait
|
||||
}
|
||||
|
||||
pub fn unboxed_closure_trait_ref_and_return_type<'tcx>(
|
||||
closure_typer: &ty::UnboxedClosureTyper<'tcx>,
|
||||
fn_trait_def_id: ast::DefId,
|
||||
self_ty: Ty<'tcx>,
|
||||
closure_def_id: ast::DefId,
|
||||
substs: &Substs<'tcx>)
|
||||
-> ty::Binder<(Rc<ty::TraitRef<'tcx>>, Ty<'tcx>)>
|
||||
{
|
||||
let tcx = closure_typer.param_env().tcx;
|
||||
let closure_type = closure_typer.unboxed_closure_type(closure_def_id, substs);
|
||||
|
||||
debug!("unboxed_closure_trait_ref: closure_def_id={} closure_type={}",
|
||||
closure_def_id.repr(tcx),
|
||||
closure_type.repr(tcx));
|
||||
|
||||
let closure_sig = &closure_type.sig;
|
||||
let arguments_tuple = closure_sig.0.inputs[0];
|
||||
let trait_substs =
|
||||
Substs::new_trait(
|
||||
vec![arguments_tuple],
|
||||
vec![],
|
||||
self_ty);
|
||||
let trait_ref = Rc::new(ty::TraitRef {
|
||||
def_id: fn_trait_def_id,
|
||||
substs: tcx.mk_substs(trait_substs),
|
||||
});
|
||||
|
||||
ty::Binder((trait_ref, closure_sig.0.output.unwrap()))
|
||||
}
|
||||
|
||||
impl<'tcx,O:Repr<'tcx>> Repr<'tcx> for super::Obligation<'tcx, O> {
|
||||
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||
format!("Obligation(predicate={},depth={})",
|
||||
|
@ -22,6 +22,9 @@ use syntax::ast;
|
||||
use syntax::visit;
|
||||
use syntax::visit::Visitor;
|
||||
|
||||
// The name of the associated type for `Fn` return types
|
||||
pub const FN_OUTPUT_NAME: &'static str = "Output";
|
||||
|
||||
// Useful type to use with `Result<>` indicate that an error has already
|
||||
// been reported to the user, so no need to continue checking.
|
||||
#[derive(Clone, Copy, Show)]
|
||||
|
@ -512,7 +512,7 @@ pub fn parameterized<'tcx>(cx: &ctxt<'tcx>,
|
||||
}
|
||||
|
||||
if cx.lang_items.fn_trait_kind(did).is_some() {
|
||||
format!("{}({}){}",
|
||||
format!("{}({})", // TODO
|
||||
base,
|
||||
if strs[0].starts_with("(") && strs[0].ends_with(",)") {
|
||||
&strs[0][1 .. strs[0].len() - 2] // Remove '(' and ',)'
|
||||
@ -520,8 +520,7 @@ pub fn parameterized<'tcx>(cx: &ctxt<'tcx>,
|
||||
&strs[0][1 .. strs[0].len() - 1] // Remove '(' and ')'
|
||||
} else {
|
||||
&strs[0][]
|
||||
},
|
||||
if &*strs[1] == "()" { String::new() } else { format!(" -> {}", strs[1]) })
|
||||
})
|
||||
} else if strs.len() > 0 {
|
||||
format!("{}<{}>", base, strs.connect(", "))
|
||||
} else {
|
||||
|
@ -57,7 +57,7 @@ use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
|
||||
use rscope::{self, UnelidableRscope, RegionScope, SpecificRscope,
|
||||
ShiftedRscope, BindingRscope};
|
||||
use TypeAndSubsts;
|
||||
use util::common::ErrorReported;
|
||||
use util::common::{ErrorReported, FN_OUTPUT_NAME};
|
||||
use util::nodemap::DefIdMap;
|
||||
use util::ppaux::{self, Repr, UserString};
|
||||
|
||||
@ -268,7 +268,7 @@ pub fn ast_path_substs_for_ty<'tcx>(
|
||||
ast::ParenthesizedParameters(ref data) => {
|
||||
span_err!(tcx.sess, path.span, E0214,
|
||||
"parenthesized parameters may only be used with a trait");
|
||||
(Vec::new(), convert_parenthesized_parameters(this, data), Vec::new())
|
||||
convert_parenthesized_parameters(this, data)
|
||||
}
|
||||
};
|
||||
|
||||
@ -479,7 +479,9 @@ fn convert_ty_with_lifetime_elision<'tcx>(this: &AstConv<'tcx>,
|
||||
|
||||
fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>,
|
||||
data: &ast::ParenthesizedParameterData)
|
||||
-> Vec<Ty<'tcx>>
|
||||
-> (Vec<ty::Region>,
|
||||
Vec<Ty<'tcx>>,
|
||||
Vec<ConvertedBinding<'tcx>>)
|
||||
{
|
||||
let binding_rscope = BindingRscope::new();
|
||||
let inputs = data.inputs.iter()
|
||||
@ -492,15 +494,26 @@ fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>,
|
||||
|
||||
let input_ty = ty::mk_tup(this.tcx(), inputs);
|
||||
|
||||
let output = match data.output {
|
||||
Some(ref output_ty) => convert_ty_with_lifetime_elision(this,
|
||||
implied_output_region,
|
||||
params_lifetimes,
|
||||
&**output_ty),
|
||||
None => ty::mk_nil(this.tcx()),
|
||||
let (output, output_span) = match data.output {
|
||||
Some(ref output_ty) => {
|
||||
(convert_ty_with_lifetime_elision(this,
|
||||
implied_output_region,
|
||||
params_lifetimes,
|
||||
&**output_ty),
|
||||
output_ty.span)
|
||||
}
|
||||
None => {
|
||||
(ty::mk_nil(this.tcx()), data.span)
|
||||
}
|
||||
};
|
||||
|
||||
vec![input_ty, output]
|
||||
let output_binding = ConvertedBinding {
|
||||
item_name: token::intern(FN_OUTPUT_NAME),
|
||||
ty: output,
|
||||
span: output_span
|
||||
};
|
||||
|
||||
(vec![], vec![input_ty], vec![output_binding])
|
||||
}
|
||||
|
||||
pub fn instantiate_poly_trait_ref<'tcx>(
|
||||
@ -630,7 +643,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
|
||||
the crate attributes to enable");
|
||||
}
|
||||
|
||||
(Vec::new(), convert_parenthesized_parameters(this, data), Vec::new())
|
||||
convert_parenthesized_parameters(this, data)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -347,6 +347,9 @@ impl AngleBracketedParameterData {
|
||||
/// A path like `Foo(A,B) -> C`
|
||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Show)]
|
||||
pub struct ParenthesizedParameterData {
|
||||
/// Overall span
|
||||
pub span: Span,
|
||||
|
||||
/// `(A,B)`
|
||||
pub inputs: Vec<P<Ty>>,
|
||||
|
||||
|
@ -536,9 +536,10 @@ pub fn noop_fold_parenthesized_parameter_data<T: Folder>(data: ParenthesizedPara
|
||||
fld: &mut T)
|
||||
-> ParenthesizedParameterData
|
||||
{
|
||||
let ParenthesizedParameterData { inputs, output } = data;
|
||||
let ParenthesizedParameterData { inputs, output, span } = data;
|
||||
ParenthesizedParameterData { inputs: inputs.move_map(|ty| fld.fold_ty(ty)),
|
||||
output: output.map(|ty| fld.fold_ty(ty)) }
|
||||
output: output.map(|ty| fld.fold_ty(ty)),
|
||||
span: fld.new_span(span) }
|
||||
}
|
||||
|
||||
pub fn noop_fold_local<T: Folder>(l: P<Local>, fld: &mut T) -> P<Local> {
|
||||
|
@ -1796,6 +1796,8 @@ impl<'a> Parser<'a> {
|
||||
bindings: OwnedSlice::from_vec(bindings),
|
||||
})
|
||||
} else if self.eat(&token::OpenDelim(token::Paren)) {
|
||||
let lo = self.last_span.lo;
|
||||
|
||||
let inputs = self.parse_seq_to_end(
|
||||
&token::CloseDelim(token::Paren),
|
||||
seq_sep_trailing_allowed(token::Comma),
|
||||
@ -1807,9 +1809,12 @@ impl<'a> Parser<'a> {
|
||||
None
|
||||
};
|
||||
|
||||
let hi = self.last_span.hi;
|
||||
|
||||
ast::ParenthesizedParameters(ast::ParenthesizedParameterData {
|
||||
span: mk_sp(lo, hi),
|
||||
inputs: inputs,
|
||||
output: output_ty
|
||||
output: output_ty,
|
||||
})
|
||||
} else {
|
||||
ast::PathParameters::none()
|
||||
|
Loading…
Reference in New Issue
Block a user