("linkage", Active),
("struct_inherit", Active),
("overloaded_calls", Active),
+ ("unboxed_closure_sugar", Active),
("quad_precision_float", Active),
},
ast::TyBox(_) => { self.gate_box(t.span); }
+ ast::TyUnboxedFn(_) => {
+ self.gate_feature("unboxed_closure_sugar",
+ t.span,
+ "unboxed closure trait sugar is experimental");
+ }
_ => {}
}
}
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(_) => {}
}
}
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;
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.
}
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
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(),
// 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,
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,
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 => {
}
}
-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`
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(
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>
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(
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();
match *self {
ast::StaticRegionTyParamBound => RegionBound,
ast::OtherRegionTyParamBound(_) => RegionBound,
+ ast::UnboxedFnTyParamBound(_) => {
+ // FIXME(pcwalton): Wrong.
+ RegionBound
+ }
ast::TraitTyParamBound(ref t) => TraitBound(t.clean()),
}
}
pub enum TyParamBound {
TraitTyParamBound(TraitRef),
StaticRegionTyParamBound,
+ UnboxedFnTyParamBound(UnboxedFnTy),
OtherRegionTyParamBound(Span) // FIXME -- just here until work for #5723 lands
}
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,
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),
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);
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)
}
}
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;
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);
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 {
})
}
+ 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
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,
}
use abi;
use ast::{P, StaticRegionTyParamBound, OtherRegionTyParamBound,
- TraitTyParamBound, Required, Provided};
+ TraitTyParamBound, UnboxedFnTyParamBound, Required, Provided};
use ast;
use ast_util;
use owned_slice::OwnedSlice;
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));
Some(m.ident),
&None,
Some(&m.generics),
- Some(m.explicit_self.node)));
+ Some(m.explicit_self.node),
+ false));
word(&mut self.s, ";")
}
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(())
})
}
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
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 {
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 {
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() {
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(..) => {}
}
}
--- /dev/null
+
+// 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);
+}
+