mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
auto merge of #14606 : pcwalton/rust/fn-trait-sugar, r=alexcrichton
r? @alexcrichton
This commit is contained in:
commit
0ee6a8e8a5
@ -57,6 +57,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
|
||||
("linkage", Active),
|
||||
("struct_inherit", Active),
|
||||
("overloaded_calls", Active),
|
||||
("unboxed_closure_sugar", Active),
|
||||
|
||||
("quad_precision_float", Active),
|
||||
|
||||
@ -291,6 +292,11 @@ impl<'a> Visitor<()> for Context<'a> {
|
||||
|
||||
},
|
||||
ast::TyBox(_) => { self.gate_box(t.span); }
|
||||
ast::TyUnboxedFn(_) => {
|
||||
self.gate_feature("unboxed_closure_sugar",
|
||||
t.span,
|
||||
"unboxed closure trait sugar is experimental");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
@ -3856,14 +3856,20 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
|
||||
fn resolve_type_parameter_bound(&mut self,
|
||||
id: NodeId,
|
||||
type_parameter_bound: &TyParamBound) {
|
||||
id: NodeId,
|
||||
type_parameter_bound: &TyParamBound) {
|
||||
match *type_parameter_bound {
|
||||
TraitTyParamBound(ref tref) => {
|
||||
self.resolve_trait_reference(id, tref, TraitBoundingTypeParameter)
|
||||
}
|
||||
StaticRegionTyParamBound => {}
|
||||
OtherRegionTyParamBound(_) => {}
|
||||
UnboxedFnTyParamBound(ref unboxed_function) => {
|
||||
for argument in unboxed_function.decl.inputs.iter() {
|
||||
self.resolve_type(argument.ty);
|
||||
}
|
||||
|
||||
self.resolve_type(unboxed_function.decl.output);
|
||||
}
|
||||
StaticRegionTyParamBound | OtherRegionTyParamBound(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,13 +51,14 @@
|
||||
|
||||
use middle::const_eval;
|
||||
use middle::def;
|
||||
use middle::subst;
|
||||
use middle::lang_items::FnMutTraitLangItem;
|
||||
use middle::subst::{Subst, Substs};
|
||||
use middle::ty::{ty_param_substs_and_ty};
|
||||
use middle::subst;
|
||||
use middle::ty::ty_param_substs_and_ty;
|
||||
use middle::ty;
|
||||
use middle::typeck::rscope;
|
||||
use middle::typeck::rscope::{RegionScope};
|
||||
use middle::typeck::lookup_def_tcx;
|
||||
use middle::typeck::rscope::RegionScope;
|
||||
use middle::typeck::rscope;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
use std::rc::Rc;
|
||||
@ -469,6 +470,38 @@ fn ast_ty_to_mt<AC:AstConv, RS:RegionScope>(this: &AC,
|
||||
ty::mt {ty: ast_ty_to_ty(this, rscope, ty), mutbl: ast::MutImmutable}
|
||||
}
|
||||
|
||||
pub fn trait_ref_for_unboxed_function<AC:AstConv,
|
||||
RS:RegionScope>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
unboxed_function: &ast::UnboxedFnTy)
|
||||
-> ty::TraitRef {
|
||||
let fn_mut_trait_did = this.tcx()
|
||||
.lang_items
|
||||
.require(FnMutTraitLangItem)
|
||||
.unwrap();
|
||||
let input_types =
|
||||
unboxed_function.decl
|
||||
.inputs
|
||||
.iter()
|
||||
.map(|input| {
|
||||
ast_ty_to_ty(this, rscope, input.ty)
|
||||
}).collect::<Vec<_>>();
|
||||
let input_tuple = ty::mk_tup(this.tcx(), input_types);
|
||||
let output_type = ast_ty_to_ty(this,
|
||||
rscope,
|
||||
unboxed_function.decl.output);
|
||||
let substs = subst::Substs {
|
||||
self_ty: None,
|
||||
tps: vec!(input_tuple, output_type),
|
||||
regions: subst::NonerasedRegions(Vec::new()),
|
||||
};
|
||||
ty::TraitRef {
|
||||
def_id: fn_mut_trait_did,
|
||||
substs: substs,
|
||||
}
|
||||
}
|
||||
|
||||
// Handle `~`, `Box`, and `&` being able to mean strs and vecs.
|
||||
// If a_seq_ty is a str or a vec, make it a str/vec.
|
||||
// Also handle first-class trait types.
|
||||
@ -491,6 +524,32 @@ fn mk_pointer<AC:AstConv,
|
||||
}
|
||||
return constr(ty::mk_vec(tcx, mt, None));
|
||||
}
|
||||
ast::TyUnboxedFn(ref unboxed_function) => {
|
||||
let trait_store = match ptr_ty {
|
||||
Uniq => ty::UniqTraitStore,
|
||||
RPtr(r) => {
|
||||
ty::RegionTraitStore(r, a_seq_ty.mutbl)
|
||||
}
|
||||
_ => {
|
||||
tcx.sess.span_err(
|
||||
a_seq_ty.ty.span,
|
||||
"~trait or &trait are the only supported \
|
||||
forms of casting-to-trait");
|
||||
return ty::mk_err();
|
||||
}
|
||||
};
|
||||
let ty::TraitRef {
|
||||
def_id,
|
||||
substs
|
||||
} = trait_ref_for_unboxed_function(this,
|
||||
rscope,
|
||||
*unboxed_function);
|
||||
return ty::mk_trait(this.tcx(),
|
||||
def_id,
|
||||
substs,
|
||||
trait_store,
|
||||
ty::empty_builtin_bounds());
|
||||
}
|
||||
ast::TyPath(ref path, ref bounds, id) => {
|
||||
// Note that the "bounds must be empty if path is not a trait"
|
||||
// restriction is enforced in the below case for ty_path, which
|
||||
@ -528,7 +587,10 @@ fn mk_pointer<AC:AstConv,
|
||||
return ty::mk_err();
|
||||
}
|
||||
};
|
||||
let bounds = conv_builtin_bounds(this.tcx(), bounds, trait_store);
|
||||
let bounds = conv_builtin_bounds(this.tcx(),
|
||||
path.span,
|
||||
bounds,
|
||||
trait_store);
|
||||
return ty::mk_trait(tcx,
|
||||
result.def_id,
|
||||
result.substs.clone(),
|
||||
@ -621,7 +683,10 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
|
||||
// Use corresponding trait store to figure out default bounds
|
||||
// if none were specified.
|
||||
let bounds = conv_builtin_bounds(this.tcx(), &f.bounds, store);
|
||||
let bounds = conv_builtin_bounds(this.tcx(),
|
||||
ast_ty.span,
|
||||
&f.bounds,
|
||||
store);
|
||||
|
||||
let fn_decl = ty_of_closure(this,
|
||||
ast_ty.id,
|
||||
@ -636,7 +701,10 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
ast::TyProc(ref f) => {
|
||||
// Use corresponding trait store to figure out default bounds
|
||||
// if none were specified.
|
||||
let bounds = conv_builtin_bounds(this.tcx(), &f.bounds, ty::UniqTraitStore);
|
||||
let bounds = conv_builtin_bounds(this.tcx(),
|
||||
ast_ty.span,
|
||||
&f.bounds,
|
||||
ty::UniqTraitStore);
|
||||
|
||||
let fn_decl = ty_of_closure(this,
|
||||
ast_ty.id,
|
||||
@ -648,6 +716,11 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
None);
|
||||
ty::mk_closure(tcx, fn_decl)
|
||||
}
|
||||
ast::TyUnboxedFn(_) => {
|
||||
tcx.sess.span_err(ast_ty.span,
|
||||
"cannot use unboxed functions here");
|
||||
ty::mk_err()
|
||||
}
|
||||
ast::TyPath(ref path, ref bounds, id) => {
|
||||
let a_def = match tcx.def_map.borrow().find(&id) {
|
||||
None => {
|
||||
@ -891,7 +964,9 @@ pub fn ty_of_closure<AC:AstConv>(
|
||||
}
|
||||
}
|
||||
|
||||
fn conv_builtin_bounds(tcx: &ty::ctxt, ast_bounds: &Option<OwnedSlice<ast::TyParamBound>>,
|
||||
fn conv_builtin_bounds(tcx: &ty::ctxt,
|
||||
span: Span,
|
||||
ast_bounds: &Option<OwnedSlice<ast::TyParamBound>>,
|
||||
store: ty::TraitStore)
|
||||
-> ty::BuiltinBounds {
|
||||
//! Converts a list of bounds from the AST into a `BuiltinBounds`
|
||||
@ -928,6 +1003,11 @@ fn conv_builtin_bounds(tcx: &ty::ctxt, ast_bounds: &Option<OwnedSlice<ast::TyPar
|
||||
ast::StaticRegionTyParamBound => {
|
||||
builtin_bounds.add(ty::BoundStatic);
|
||||
}
|
||||
ast::UnboxedFnTyParamBound(_) => {
|
||||
tcx.sess.span_err(span,
|
||||
"unboxed functions are not allowed \
|
||||
here");
|
||||
}
|
||||
ast::OtherRegionTyParamBound(span) => {
|
||||
if !tcx.sess.features.issue_5723_bootstrap.get() {
|
||||
tcx.sess.span_err(
|
||||
|
@ -48,22 +48,21 @@ use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx};
|
||||
use util::ppaux;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
use std::rc::Rc;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use std::rc::Rc;
|
||||
use syntax::abi;
|
||||
use syntax::ast::{StaticRegionTyParamBound, OtherRegionTyParamBound,
|
||||
TraitTyParamBound};
|
||||
use syntax::ast::{StaticRegionTyParamBound, OtherRegionTyParamBound};
|
||||
use syntax::ast::{TraitTyParamBound, UnboxedFnTyParamBound};
|
||||
use syntax::ast;
|
||||
use syntax::ast_map;
|
||||
use syntax::ast_util::{local_def, split_trait_methods};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::codemap;
|
||||
use syntax::owned_slice::OwnedSlice;
|
||||
use syntax::parse::token::special_idents;
|
||||
use syntax::parse::token;
|
||||
use syntax::print::pprust::{path_to_str};
|
||||
use syntax::visit;
|
||||
use syntax::owned_slice::OwnedSlice;
|
||||
|
||||
struct CollectItemTypesVisitor<'a> {
|
||||
ccx: &'a CrateCtxt<'a>
|
||||
@ -1114,6 +1113,20 @@ fn ty_generics(ccx: &CrateCtxt,
|
||||
param_bounds.builtin_bounds.add(ty::BoundStatic);
|
||||
}
|
||||
|
||||
UnboxedFnTyParamBound(ref unboxed_function) => {
|
||||
let rscope = ExplicitRscope;
|
||||
let mut trait_ref =
|
||||
astconv::trait_ref_for_unboxed_function(
|
||||
ccx,
|
||||
&rscope,
|
||||
unboxed_function);
|
||||
let self_ty = ty::mk_param(ccx.tcx,
|
||||
param_ty.idx,
|
||||
param_ty.def_id);
|
||||
trait_ref.substs.self_ty = Some(self_ty);
|
||||
param_bounds.trait_bounds.push(Rc::new(trait_ref));
|
||||
}
|
||||
|
||||
OtherRegionTyParamBound(span) => {
|
||||
if !ccx.tcx.sess.features.issue_5723_bootstrap.get() {
|
||||
ccx.tcx.sess.span_err(
|
||||
|
@ -909,6 +909,9 @@ impl<'a> Rebuilder<'a> {
|
||||
match tpb {
|
||||
&ast::StaticRegionTyParamBound => ast::StaticRegionTyParamBound,
|
||||
&ast::OtherRegionTyParamBound(s) => ast::OtherRegionTyParamBound(s),
|
||||
&ast::UnboxedFnTyParamBound(unboxed_function_type) => {
|
||||
ast::UnboxedFnTyParamBound(unboxed_function_type)
|
||||
}
|
||||
&ast::TraitTyParamBound(ref tr) => {
|
||||
let last_seg = tr.path.segments.last().unwrap();
|
||||
let mut insert = Vec::new();
|
||||
|
@ -477,6 +477,10 @@ impl Clean<TyParamBound> for ast::TyParamBound {
|
||||
match *self {
|
||||
ast::StaticRegionTyParamBound => RegionBound,
|
||||
ast::OtherRegionTyParamBound(_) => RegionBound,
|
||||
ast::UnboxedFnTyParamBound(_) => {
|
||||
// FIXME(pcwalton): Wrong.
|
||||
RegionBound
|
||||
}
|
||||
ast::TraitTyParamBound(ref t) => TraitBound(t.clean()),
|
||||
}
|
||||
}
|
||||
|
@ -175,6 +175,7 @@ pub static DUMMY_NODE_ID: NodeId = -1;
|
||||
pub enum TyParamBound {
|
||||
TraitTyParamBound(TraitRef),
|
||||
StaticRegionTyParamBound,
|
||||
UnboxedFnTyParamBound(UnboxedFnTy),
|
||||
OtherRegionTyParamBound(Span) // FIXME -- just here until work for #5723 lands
|
||||
}
|
||||
|
||||
@ -769,6 +770,11 @@ pub struct BareFnTy {
|
||||
pub decl: P<FnDecl>
|
||||
}
|
||||
|
||||
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)]
|
||||
pub struct UnboxedFnTy {
|
||||
pub decl: P<FnDecl>,
|
||||
}
|
||||
|
||||
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)]
|
||||
pub enum Ty_ {
|
||||
TyNil,
|
||||
@ -782,6 +788,7 @@ pub enum Ty_ {
|
||||
TyClosure(@ClosureTy, Option<Lifetime>),
|
||||
TyProc(@ClosureTy),
|
||||
TyBareFn(@BareFnTy),
|
||||
TyUnboxedFn(@UnboxedFnTy),
|
||||
TyTup(Vec<P<Ty>> ),
|
||||
TyPath(Path, Option<OwnedSlice<TyParamBound>>, NodeId), // for #7264; see above
|
||||
TyTypeof(@Expr),
|
||||
|
@ -185,6 +185,11 @@ pub trait Folder {
|
||||
decl: self.fold_fn_decl(f.decl)
|
||||
})
|
||||
}
|
||||
TyUnboxedFn(ref f) => {
|
||||
TyUnboxedFn(@UnboxedFnTy {
|
||||
decl: self.fold_fn_decl(f.decl),
|
||||
})
|
||||
}
|
||||
TyTup(ref tys) => TyTup(tys.iter().map(|&ty| self.fold_ty(ty)).collect()),
|
||||
TyPath(ref path, ref bounds, id) => {
|
||||
let id = self.new_id(id);
|
||||
@ -440,6 +445,11 @@ fn fold_ty_param_bound<T: Folder>(tpb: &TyParamBound, fld: &mut T)
|
||||
match *tpb {
|
||||
TraitTyParamBound(ref ty) => TraitTyParamBound(fold_trait_ref(ty, fld)),
|
||||
StaticRegionTyParamBound => StaticRegionTyParamBound,
|
||||
UnboxedFnTyParamBound(ref unboxed_function_type) => {
|
||||
UnboxedFnTyParamBound(UnboxedFnTy {
|
||||
decl: fld.fold_fn_decl(unboxed_function_type.decl),
|
||||
})
|
||||
}
|
||||
OtherRegionTyParamBound(s) => OtherRegionTyParamBound(s)
|
||||
}
|
||||
}
|
||||
|
@ -52,9 +52,9 @@ use ast::{TTNonterminal, TupleVariantKind, Ty, Ty_, TyBot, TyBox};
|
||||
use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn};
|
||||
use ast::{TyTypeof, TyInfer, TypeMethod};
|
||||
use ast::{TyNil, TyParam, TyParamBound, TyPath, TyPtr, TyRptr};
|
||||
use ast::{TyTup, TyU32, TyUniq, TyVec, UnUniq};
|
||||
use ast::{UnnamedField, UnsafeBlock, UnsafeFn, ViewItem};
|
||||
use ast::{ViewItem_, ViewItemExternCrate, ViewItemUse};
|
||||
use ast::{TyTup, TyU32, TyUnboxedFn, TyUniq, TyVec, UnUniq};
|
||||
use ast::{UnboxedFnTy, UnboxedFnTyParamBound, UnnamedField, UnsafeBlock};
|
||||
use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse};
|
||||
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
|
||||
use ast::Visibility;
|
||||
use ast;
|
||||
@ -1058,15 +1058,27 @@ impl<'a> Parser<'a> {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
let inputs = if self.eat(&token::OROR) {
|
||||
Vec::new()
|
||||
let (is_unboxed, inputs) = if self.eat(&token::OROR) {
|
||||
(false, Vec::new())
|
||||
} else {
|
||||
self.expect_or();
|
||||
|
||||
let is_unboxed = self.token == token::BINOP(token::AND) &&
|
||||
self.look_ahead(1, |t| {
|
||||
token::is_keyword(keywords::Mut, t)
|
||||
}) &&
|
||||
self.look_ahead(2, |t| *t == token::COLON);
|
||||
if is_unboxed {
|
||||
self.bump();
|
||||
self.bump();
|
||||
self.bump();
|
||||
}
|
||||
|
||||
let inputs = self.parse_seq_to_before_or(
|
||||
&token::COMMA,
|
||||
|p| p.parse_arg_general(false));
|
||||
self.expect_or();
|
||||
inputs
|
||||
(is_unboxed, inputs)
|
||||
};
|
||||
|
||||
let (region, bounds) = self.parse_optional_ty_param_bounds(true);
|
||||
@ -1079,13 +1091,19 @@ impl<'a> Parser<'a> {
|
||||
variadic: false
|
||||
});
|
||||
|
||||
TyClosure(@ClosureTy {
|
||||
fn_style: fn_style,
|
||||
onceness: onceness,
|
||||
bounds: bounds,
|
||||
decl: decl,
|
||||
lifetimes: lifetimes,
|
||||
}, region)
|
||||
if is_unboxed {
|
||||
TyUnboxedFn(@UnboxedFnTy {
|
||||
decl: decl,
|
||||
})
|
||||
} else {
|
||||
TyClosure(@ClosureTy {
|
||||
fn_style: fn_style,
|
||||
onceness: onceness,
|
||||
bounds: bounds,
|
||||
decl: decl,
|
||||
lifetimes: lifetimes,
|
||||
}, region)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_unsafety(&mut self) -> FnStyle {
|
||||
@ -3345,6 +3363,41 @@ impl<'a> Parser<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_unboxed_function_type(&mut self) -> UnboxedFnTy {
|
||||
let inputs = if self.eat(&token::OROR) {
|
||||
Vec::new()
|
||||
} else {
|
||||
self.expect_or();
|
||||
|
||||
if self.token == token::BINOP(token::AND) &&
|
||||
self.look_ahead(1, |t| {
|
||||
token::is_keyword(keywords::Mut, t)
|
||||
}) &&
|
||||
self.look_ahead(2, |t| *t == token::COLON) {
|
||||
self.bump();
|
||||
self.bump();
|
||||
self.bump();
|
||||
}
|
||||
|
||||
let inputs = self.parse_seq_to_before_or(&token::COMMA,
|
||||
|p| {
|
||||
p.parse_arg_general(false)
|
||||
});
|
||||
self.expect_or();
|
||||
inputs
|
||||
};
|
||||
|
||||
let (return_style, output) = self.parse_ret_ty();
|
||||
UnboxedFnTy {
|
||||
decl: P(FnDecl {
|
||||
inputs: inputs,
|
||||
output: output,
|
||||
cf: return_style,
|
||||
variadic: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// matches optbounds = ( ( : ( boundseq )? )? )
|
||||
// where boundseq = ( bound + boundseq ) | bound
|
||||
// and bound = 'static | ty
|
||||
@ -3394,6 +3447,11 @@ impl<'a> Parser<'a> {
|
||||
let tref = self.parse_trait_ref();
|
||||
result.push(TraitTyParamBound(tref));
|
||||
}
|
||||
token::BINOP(token::OR) | token::OROR => {
|
||||
let unboxed_function_type =
|
||||
self.parse_unboxed_function_type();
|
||||
result.push(UnboxedFnTyParamBound(unboxed_function_type));
|
||||
}
|
||||
_ => break,
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
use abi;
|
||||
use ast::{P, StaticRegionTyParamBound, OtherRegionTyParamBound,
|
||||
TraitTyParamBound, Required, Provided};
|
||||
TraitTyParamBound, UnboxedFnTyParamBound, Required, Provided};
|
||||
use ast;
|
||||
use ast_util;
|
||||
use owned_slice::OwnedSlice;
|
||||
@ -505,27 +505,64 @@ impl<'a> State<'a> {
|
||||
lifetimes: f.lifetimes.clone(),
|
||||
ty_params: OwnedSlice::empty()
|
||||
};
|
||||
try!(self.print_ty_fn(Some(f.abi), None, &None,
|
||||
f.fn_style, ast::Many, f.decl, None, &None,
|
||||
Some(&generics), None));
|
||||
try!(self.print_ty_fn(Some(f.abi),
|
||||
None,
|
||||
&None,
|
||||
f.fn_style,
|
||||
ast::Many,
|
||||
f.decl,
|
||||
None,
|
||||
&None,
|
||||
Some(&generics),
|
||||
None,
|
||||
false));
|
||||
}
|
||||
ast::TyClosure(f, ref region) => {
|
||||
let generics = ast::Generics {
|
||||
lifetimes: f.lifetimes.clone(),
|
||||
ty_params: OwnedSlice::empty()
|
||||
};
|
||||
try!(self.print_ty_fn(None, Some('&'), region, f.fn_style,
|
||||
f.onceness, f.decl, None, &f.bounds,
|
||||
Some(&generics), None));
|
||||
try!(self.print_ty_fn(None,
|
||||
Some('&'),
|
||||
region,
|
||||
f.fn_style,
|
||||
f.onceness,
|
||||
f.decl,
|
||||
None,
|
||||
&f.bounds,
|
||||
Some(&generics),
|
||||
None,
|
||||
false));
|
||||
}
|
||||
ast::TyProc(f) => {
|
||||
let generics = ast::Generics {
|
||||
lifetimes: f.lifetimes.clone(),
|
||||
ty_params: OwnedSlice::empty()
|
||||
};
|
||||
try!(self.print_ty_fn(None, Some('~'), &None, f.fn_style,
|
||||
f.onceness, f.decl, None, &f.bounds,
|
||||
Some(&generics), None));
|
||||
try!(self.print_ty_fn(None,
|
||||
Some('~'),
|
||||
&None,
|
||||
f.fn_style,
|
||||
f.onceness,
|
||||
f.decl,
|
||||
None,
|
||||
&f.bounds,
|
||||
Some(&generics),
|
||||
None,
|
||||
false));
|
||||
}
|
||||
ast::TyUnboxedFn(f) => {
|
||||
try!(self.print_ty_fn(None,
|
||||
None,
|
||||
&None,
|
||||
ast::NormalFn,
|
||||
ast::Many,
|
||||
f.decl,
|
||||
None,
|
||||
&None,
|
||||
None,
|
||||
None,
|
||||
true));
|
||||
}
|
||||
ast::TyPath(ref path, ref bounds, _) => {
|
||||
try!(self.print_bounded_path(path, bounds));
|
||||
@ -930,7 +967,8 @@ impl<'a> State<'a> {
|
||||
Some(m.ident),
|
||||
&None,
|
||||
Some(&m.generics),
|
||||
Some(m.explicit_self.node)));
|
||||
Some(m.explicit_self.node),
|
||||
false));
|
||||
word(&mut self.s, ";")
|
||||
}
|
||||
|
||||
@ -1925,6 +1963,19 @@ impl<'a> State<'a> {
|
||||
try!(match *bound {
|
||||
TraitTyParamBound(ref tref) => self.print_trait_ref(tref),
|
||||
StaticRegionTyParamBound => word(&mut self.s, "'static"),
|
||||
UnboxedFnTyParamBound(ref unboxed_function_type) => {
|
||||
self.print_ty_fn(None,
|
||||
None,
|
||||
&None,
|
||||
ast::NormalFn,
|
||||
ast::Many,
|
||||
unboxed_function_type.decl,
|
||||
None,
|
||||
&None,
|
||||
None,
|
||||
None,
|
||||
true)
|
||||
}
|
||||
OtherRegionTyParamBound(_) => Ok(())
|
||||
})
|
||||
}
|
||||
@ -2112,8 +2163,9 @@ impl<'a> State<'a> {
|
||||
id: Option<ast::Ident>,
|
||||
opt_bounds: &Option<OwnedSlice<ast::TyParamBound>>,
|
||||
generics: Option<&ast::Generics>,
|
||||
opt_explicit_self: Option<ast::ExplicitSelf_>)
|
||||
-> IoResult<()> {
|
||||
opt_explicit_self: Option<ast::ExplicitSelf_>,
|
||||
is_unboxed: bool)
|
||||
-> IoResult<()> {
|
||||
try!(self.ibox(indent_unit));
|
||||
|
||||
// Duplicates the logic in `print_fn_header_info()`. This is because that
|
||||
@ -2129,7 +2181,9 @@ impl<'a> State<'a> {
|
||||
try!(self.print_fn_style(fn_style));
|
||||
try!(self.print_opt_abi_and_extern_if_nondefault(opt_abi));
|
||||
try!(self.print_onceness(onceness));
|
||||
try!(word(&mut self.s, "fn"));
|
||||
if !is_unboxed {
|
||||
try!(word(&mut self.s, "fn"));
|
||||
}
|
||||
}
|
||||
|
||||
match id {
|
||||
@ -2143,15 +2197,20 @@ impl<'a> State<'a> {
|
||||
match generics { Some(g) => try!(self.print_generics(g)), _ => () }
|
||||
try!(zerobreak(&mut self.s));
|
||||
|
||||
if opt_sigil == Some('&') {
|
||||
if is_unboxed || opt_sigil == Some('&') {
|
||||
try!(word(&mut self.s, "|"));
|
||||
} else {
|
||||
try!(self.popen());
|
||||
}
|
||||
|
||||
if is_unboxed {
|
||||
try!(word(&mut self.s, "&mut"));
|
||||
try!(self.word_space(":"));
|
||||
}
|
||||
|
||||
try!(self.print_fn_args(decl, opt_explicit_self));
|
||||
|
||||
if opt_sigil == Some('&') {
|
||||
if is_unboxed || opt_sigil == Some('&') {
|
||||
try!(word(&mut self.s, "|"));
|
||||
} else {
|
||||
if decl.variadic {
|
||||
|
@ -383,6 +383,12 @@ pub fn walk_ty<E: Clone, V: Visitor<E>>(visitor: &mut V, typ: &Ty, env: E) {
|
||||
walk_lifetime_decls(visitor, &function_declaration.lifetimes,
|
||||
env.clone());
|
||||
}
|
||||
TyUnboxedFn(ref function_declaration) => {
|
||||
for argument in function_declaration.decl.inputs.iter() {
|
||||
visitor.visit_ty(argument.ty, env.clone())
|
||||
}
|
||||
visitor.visit_ty(function_declaration.decl.output, env.clone());
|
||||
}
|
||||
TyPath(ref path, ref bounds, id) => {
|
||||
visitor.visit_path(path, id, env.clone());
|
||||
for bounds in bounds.iter() {
|
||||
@ -501,6 +507,13 @@ pub fn walk_ty_param_bounds<E: Clone, V: Visitor<E>>(visitor: &mut V,
|
||||
walk_trait_ref_helper(visitor, typ, env.clone())
|
||||
}
|
||||
StaticRegionTyParamBound => {}
|
||||
UnboxedFnTyParamBound(ref function_declaration) => {
|
||||
for argument in function_declaration.decl.inputs.iter() {
|
||||
visitor.visit_ty(argument.ty, env.clone())
|
||||
}
|
||||
visitor.visit_ty(function_declaration.decl.output,
|
||||
env.clone());
|
||||
}
|
||||
OtherRegionTyParamBound(..) => {}
|
||||
}
|
||||
}
|
||||
|
38
src/test/run-pass/fn-trait-sugar.rs
Normal file
38
src/test/run-pass/fn-trait-sugar.rs
Normal file
@ -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.
|
||||
|
||||
#![feature(unboxed_closure_sugar)]
|
||||
|
||||
use std::ops::FnMut;
|
||||
|
||||
struct S;
|
||||
|
||||
impl FnMut<(int,),int> for S {
|
||||
fn call_mut(&mut self, (x,): (int,)) -> int {
|
||||
x * x
|
||||
}
|
||||
}
|
||||
|
||||
fn call_it<F:|int|->int>(mut f: F, x: int) -> int {
|
||||
f.call_mut((x,)) + 3
|
||||
}
|
||||
|
||||
fn call_box(f: &mut |&mut: int|->int, x: int) -> int {
|
||||
f.call_mut((x,)) + 3
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = call_it(S, 1);
|
||||
let y = call_box(&mut S, 1);
|
||||
assert!(x == 4);
|
||||
assert!(y == 4);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user