diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 6fa33f4b5aa03..15564f7bc531b 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -4328,6 +4328,34 @@ impl<'a> Resolver<'a> { self.resolve_trait_reference(id, tref, reference_type) } UnboxedFnTyParamBound(ref unboxed_function) => { + match self.resolve_path(unboxed_function.ref_id, + &unboxed_function.path, + TypeNS, + true) { + None => { + let path_str = self.path_idents_to_string( + &unboxed_function.path); + self.resolve_error(unboxed_function.path.span, + format!("unresolved trait `{}`", + path_str).as_slice()) + } + Some(def) => { + match def { + (DefTrait(_), _) => { + self.record_def(unboxed_function.ref_id, def); + } + _ => { + let msg = + format!("`{}` is not a trait", + self.path_idents_to_string( + &unboxed_function.path)); + self.resolve_error(unboxed_function.path.span, + msg.as_slice()); + } + } + } + } + for argument in unboxed_function.decl.inputs.iter() { self.resolve_type(&*argument.ty); } diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 8f60be8f7fbc0..2503fb2541b90 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -585,32 +585,29 @@ pub fn trait_ref_for_unboxed_function<'tcx, AC: AstConv<'tcx>, RS:RegionScope>( this: &AC, rscope: &RS, - unboxed_function: &ast::UnboxedFnTy, + kind: ast::UnboxedClosureKind, + decl: &ast::FnDecl, self_ty: Option) -> ty::TraitRef { - let lang_item = match unboxed_function.kind { + let lang_item = match kind { ast::FnUnboxedClosureKind => FnTraitLangItem, ast::FnMutUnboxedClosureKind => FnMutTraitLangItem, ast::FnOnceUnboxedClosureKind => FnOnceTraitLangItem, }; let trait_did = this.tcx().lang_items.require(lang_item).unwrap(); - let input_types = - unboxed_function.decl - .inputs - .iter() - .map(|input| { + let input_types = decl.inputs + .iter() + .map(|input| { ast_ty_to_ty(this, rscope, &*input.ty) - }).collect::>(); + }).collect::>(); let input_tuple = if input_types.len() == 0 { ty::mk_nil() } else { ty::mk_tup(this.tcx(), input_types) }; - let output_type = ast_ty_to_ty(this, - rscope, - &*unboxed_function.decl.output); + let output_type = ast_ty_to_ty(this, rscope, &*decl.output); let mut substs = Substs::new_type(vec!(input_tuple, output_type), - Vec::new()); + Vec::new()); match self_ty { Some(s) => substs.types.push(SelfSpace, s), @@ -648,7 +645,8 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( substs } = trait_ref_for_unboxed_function(this, rscope, - &**unboxed_function, + unboxed_function.kind, + &*unboxed_function.decl, None); let r = ptr_ty.default_region(); let tr = ty::mk_trait(this.tcx(), @@ -1510,7 +1508,7 @@ fn compute_region_bound<'tcx, AC: AstConv<'tcx>, RS:RegionScope>( pub struct PartitionedBounds<'a> { pub builtin_bounds: ty::BuiltinBounds, pub trait_bounds: Vec<&'a ast::TraitRef>, - pub unboxed_fn_ty_bounds: Vec<&'a ast::UnboxedFnTy>, + pub unboxed_fn_ty_bounds: Vec<&'a ast::UnboxedFnBound>, pub region_bounds: Vec<&'a ast::Lifetime>, } @@ -1574,7 +1572,7 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt, region_bounds.push(l); } ast::UnboxedFnTyParamBound(ref unboxed_function) => { - unboxed_fn_ty_bounds.push(unboxed_function); + unboxed_fn_ty_bounds.push(&**unboxed_function); } } } diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index b7aa7656ae919..40c52fd36b9c1 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -1427,7 +1427,8 @@ pub fn instantiate_unboxed_fn_ty<'tcx,AC>(this: &AC, let param_ty = param_ty.to_ty(this.tcx()); Rc::new(astconv::trait_ref_for_unboxed_function(this, &rscope, - unboxed_function, + unboxed_function.kind, + &*unboxed_function.decl, Some(param_ty))) } @@ -2165,9 +2166,42 @@ fn conv_param_bounds<'tcx,AC>(this: &AC, region_bounds, unboxed_fn_ty_bounds } = astconv::partition_bounds(this.tcx(), span, all_bounds.as_slice()); - let unboxed_fn_ty_bounds = - unboxed_fn_ty_bounds.into_iter() - .map(|b| instantiate_unboxed_fn_ty(this, b, param_ty)); + + let unboxed_fn_ty_bounds = unboxed_fn_ty_bounds.move_iter().map(|b| { + let trait_id = this.tcx().def_map.borrow().get(&b.ref_id).def_id(); + let mut kind = None; + for &(lang_item, this_kind) in [ + (this.tcx().lang_items.fn_trait(), ast::FnUnboxedClosureKind), + (this.tcx().lang_items.fn_mut_trait(), + ast::FnMutUnboxedClosureKind), + (this.tcx().lang_items.fn_once_trait(), + ast::FnOnceUnboxedClosureKind) + ].iter() { + if Some(trait_id) == lang_item { + kind = Some(this_kind); + break + } + } + + let kind = match kind { + Some(kind) => kind, + None => { + this.tcx().sess.span_err(b.path.span, + "unboxed function trait must be one \ + of `Fn`, `FnMut`, or `FnOnce`"); + ast::FnMutUnboxedClosureKind + } + }; + + let rscope = ExplicitRscope; + let param_ty = param_ty.to_ty(this.tcx()); + Rc::new(astconv::trait_ref_for_unboxed_function(this, + &rscope, + kind, + &*b.decl, + Some(param_ty))) + }); + let trait_bounds: Vec> = trait_bounds.into_iter() .map(|b| { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index eac158e664c26..e74222fac09e7 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -213,12 +213,19 @@ pub static DUMMY_NODE_ID: NodeId = -1; #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum TyParamBound { TraitTyParamBound(TraitRef), - UnboxedFnTyParamBound(UnboxedFnTy), + UnboxedFnTyParamBound(P), RegionTyParamBound(Lifetime) } pub type TyParamBounds = OwnedSlice; +#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +pub struct UnboxedFnBound { + pub path: Path, + pub decl: P, + pub ref_id: NodeId, +} + #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub struct TyParam { pub ident: Ident, diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 3beba5bcda4b2..1441f5beb6aba 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -657,16 +657,26 @@ pub fn noop_fold_fn_decl(decl: P, fld: &mut T) -> P { }) } -pub fn noop_fold_ty_param_bound(tpb: TyParamBound, fld: &mut T) - -> TyParamBound { +pub fn noop_fold_ty_param_bound(tpb: TyParamBound, fld: &mut T) + -> TyParamBound + where T: Folder { match tpb { TraitTyParamBound(ty) => TraitTyParamBound(fld.fold_trait_ref(ty)), RegionTyParamBound(lifetime) => RegionTyParamBound(fld.fold_lifetime(lifetime)), - UnboxedFnTyParamBound(UnboxedFnTy {decl, kind}) => { - UnboxedFnTyParamBound(UnboxedFnTy { - decl: fld.fold_fn_decl(decl), - kind: kind, - }) + UnboxedFnTyParamBound(bound) => { + match *bound { + UnboxedFnBound { + ref path, + ref decl, + ref_id + } => { + UnboxedFnTyParamBound(P(UnboxedFnBound { + path: fld.fold_path(path.clone()), + decl: fld.fold_fn_decl(decl.clone()), + ref_id: fld.new_id(ref_id), + })) + } + } } } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ff4fd41fbd78f..8a0027e5c06e6 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -55,7 +55,8 @@ use ast::{TyTypeof, TyInfer, TypeMethod}; use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyPtr, TyQPath}; use ast::{TyRptr, TyTup, TyU32, TyUnboxedFn, TyUniq, TyVec, UnUniq}; use ast::{TypeImplItem, TypeTraitItem, Typedef, UnboxedClosureKind}; -use ast::{UnboxedFnTy, UnboxedFnTyParamBound, UnnamedField, UnsafeBlock}; +use ast::{UnboxedFnBound, UnboxedFnTy, UnboxedFnTyParamBound}; +use ast::{UnnamedField, UnsafeBlock}; use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse}; use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple}; use ast::{Visibility, WhereClause, WherePredicate}; @@ -3666,39 +3667,6 @@ impl<'a> Parser<'a> { }) } - fn parse_unboxed_function_type(&mut self) -> UnboxedFnTy { - let (optional_unboxed_closure_kind, inputs) = - if self.eat(&token::OROR) { - (None, Vec::new()) - } else { - self.expect_or(); - - let optional_unboxed_closure_kind = - self.parse_optional_unboxed_closure_kind(); - - let inputs = self.parse_seq_to_before_or(&token::COMMA, - |p| { - p.parse_arg_general(false) - }); - self.expect_or(); - (optional_unboxed_closure_kind, inputs) - }; - - let (return_style, output) = self.parse_ret_ty(); - UnboxedFnTy { - decl: P(FnDecl { - inputs: inputs, - output: output, - cf: return_style, - variadic: false, - }), - kind: match optional_unboxed_closure_kind { - Some(kind) => kind, - None => FnMutUnboxedClosureKind, - }, - } - } - // Parses a sequence of bounds if a `:` is found, // otherwise returns empty list. fn parse_colon_then_ty_param_bounds(&mut self) @@ -3730,13 +3698,31 @@ impl<'a> Parser<'a> { self.bump(); } token::MOD_SEP | token::IDENT(..) => { - 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)); + let path = + self.parse_path(LifetimeAndTypesWithoutColons).path; + if self.token == token::LPAREN { + self.bump(); + let inputs = self.parse_seq_to_end( + &token::RPAREN, + seq_sep_trailing_allowed(token::COMMA), + |p| p.parse_arg_general(false)); + let (return_style, output) = self.parse_ret_ty(); + result.push(UnboxedFnTyParamBound(P(UnboxedFnBound { + path: path, + decl: P(FnDecl { + inputs: inputs, + output: output, + cf: return_style, + variadic: false, + }), + ref_id: ast::DUMMY_NODE_ID, + }))); + } else { + result.push(TraitTyParamBound(ast::TraitRef { + path: path, + ref_id: ast::DUMMY_NODE_ID, + })) + } } _ => break, } @@ -4423,14 +4409,6 @@ impl<'a> Parser<'a> { Some(attrs)) } - /// Parse a::B - fn parse_trait_ref(&mut self) -> TraitRef { - ast::TraitRef { - path: self.parse_path(LifetimeAndTypesWithoutColons).path, - ref_id: ast::DUMMY_NODE_ID, - } - } - /// Parse struct Foo { ... } fn parse_item_struct(&mut self, is_virtual: bool) -> ItemInfo { let class_name = self.parse_ident(); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 0ae5303641bc6..d7dd87a096e17 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2190,16 +2190,13 @@ impl<'a> State<'a> { self.print_lifetime(lt) } UnboxedFnTyParamBound(ref unboxed_function_type) => { - self.print_ty_fn(None, - None, - ast::NormalFn, - ast::Many, - &*unboxed_function_type.decl, - None, - &OwnedSlice::empty(), - None, - None, - Some(unboxed_function_type.kind)) + try!(self.print_path(&unboxed_function_type.path, + false)); + try!(self.popen()); + try!(self.print_fn_args(&*unboxed_function_type.decl, + None)); + try!(self.pclose()); + self.print_fn_output(&*unboxed_function_type.decl) } }) } @@ -2430,6 +2427,23 @@ impl<'a> State<'a> { self.end() } + pub fn print_fn_output(&mut self, decl: &ast::FnDecl) -> IoResult<()> { + match decl.output.node { + ast::TyNil => Ok(()), + _ => { + try!(self.space_if_not_bol()); + try!(self.ibox(indent_unit)); + try!(self.word_space("->")); + if decl.cf == ast::NoReturn { + try!(self.word_nbsp("!")); + } else { + try!(self.print_type(&*decl.output)); + } + self.end() + } + } + } + pub fn print_ty_fn(&mut self, opt_abi: Option, opt_sigil: Option, @@ -2510,20 +2524,7 @@ impl<'a> State<'a> { try!(self.maybe_print_comment(decl.output.span.lo)); - match decl.output.node { - ast::TyNil => {} - _ => { - try!(self.space_if_not_bol()); - try!(self.ibox(indent_unit)); - try!(self.word_space("->")); - if decl.cf == ast::NoReturn { - try!(self.word_nbsp("!")); - } else { - try!(self.print_type(&*decl.output)); - } - try!(self.end()); - } - } + try!(self.print_fn_output(decl)); match generics { Some(generics) => try!(self.print_where_clause(generics)), diff --git a/src/test/compile-fail/borrowck-unboxed-closures.rs b/src/test/compile-fail/borrowck-unboxed-closures.rs index d822bb22e2a72..03438b1d7e1e5 100644 --- a/src/test/compile-fail/borrowck-unboxed-closures.rs +++ b/src/test/compile-fail/borrowck-unboxed-closures.rs @@ -10,17 +10,17 @@ #![feature(overloaded_calls)] -fn a int>(mut f: F) { +fn a int>(mut f: F) { let g = &mut f; f(1, 2); //~ ERROR cannot borrow `f` as immutable //~^ ERROR cannot borrow `f` as immutable } -fn b int>(f: F) { +fn b int>(f: F) { f(1, 2); //~ ERROR cannot borrow immutable argument } -fn c int>(f: F) { +fn c int>(f: F) { f(1, 2); f(1, 2); //~ ERROR use of moved value } diff --git a/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs b/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs new file mode 100644 index 0000000000000..f51160a1b233d --- /dev/null +++ b/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs @@ -0,0 +1,18 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn f int>(x: F) {} //~ ERROR unresolved trait + +type Typedef = int; + +fn g int>(x: F) {} //~ ERROR `Typedef` is not a trait + +fn main() {} + diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs new file mode 100644 index 0000000000000..a751ae1c518ea --- /dev/null +++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs @@ -0,0 +1,17 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Trait {} + +fn f int>(x: F) {} +//~^ ERROR unboxed function trait must be one of `Fn`, `FnMut`, or `FnOnce` + +fn main() {} + diff --git a/src/test/compile-fail/unboxed-closures-wrong-trait.rs b/src/test/compile-fail/unboxed-closures-wrong-trait.rs index 27f1da75c3aef..97ad64a77baf4 100644 --- a/src/test/compile-fail/unboxed-closures-wrong-trait.rs +++ b/src/test/compile-fail/unboxed-closures-wrong-trait.rs @@ -10,7 +10,7 @@ #![feature(lang_items, overloaded_calls, unboxed_closures)] -fn c int>(f: F) -> int { +fn c int>(f: F) -> int { f(5, 6) } diff --git a/src/test/run-pass/fn-trait-sugar.rs b/src/test/run-pass/fn-trait-sugar.rs index ccb5634f7a290..b0947f46a86ae 100644 --- a/src/test/run-pass/fn-trait-sugar.rs +++ b/src/test/run-pass/fn-trait-sugar.rs @@ -21,7 +21,7 @@ impl FnMut<(int,),int> for S { } } -fn call_itint>(mut f: F, x: int) -> int { +fn call_itint>(mut f: F, x: int) -> int { f.call_mut((x,)) + 3 } diff --git a/src/test/run-pass/unboxed-closures-all-traits.rs b/src/test/run-pass/unboxed-closures-all-traits.rs index c362a83e60c4a..d91204951551a 100644 --- a/src/test/run-pass/unboxed-closures-all-traits.rs +++ b/src/test/run-pass/unboxed-closures-all-traits.rs @@ -10,15 +10,15 @@ #![feature(lang_items, overloaded_calls, unboxed_closures)] -fn a int>(f: F) -> int { +fn a int>(f: F) -> int { f(1, 2) } -fn b int>(mut f: F) -> int { +fn b int>(mut f: F) -> int { f(3, 4) } -fn c int>(f: F) -> int { +fn c int>(f: F) -> int { f(5, 6) } diff --git a/src/test/run-pass/unboxed-closures-drop.rs b/src/test/run-pass/unboxed-closures-drop.rs index f20dddcae54b3..a455e4d203263 100644 --- a/src/test/run-pass/unboxed-closures-drop.rs +++ b/src/test/run-pass/unboxed-closures-drop.rs @@ -41,15 +41,15 @@ impl Drop for Droppable { } } -fn a int>(f: F) -> int { +fn a int>(f: F) -> int { f(1, 2) } -fn b int>(mut f: F) -> int { +fn b int>(mut f: F) -> int { f(3, 4) } -fn c int>(f: F) -> int { +fn c int>(f: F) -> int { f(5, 6) } diff --git a/src/test/run-pass/unboxed-closures-single-word-env.rs b/src/test/run-pass/unboxed-closures-single-word-env.rs index 754b1f706444b..aef6956118ecb 100644 --- a/src/test/run-pass/unboxed-closures-single-word-env.rs +++ b/src/test/run-pass/unboxed-closures-single-word-env.rs @@ -13,15 +13,15 @@ #![feature(overloaded_calls, unboxed_closures)] -fn a int>(f: F) -> int { +fn a int>(f: F) -> int { f(1, 2) } -fn b int>(mut f: F) -> int { +fn b int>(mut f: F) -> int { f(3, 4) } -fn c int>(f: F) -> int { +fn c int>(f: F) -> int { f(5, 6) } diff --git a/src/test/run-pass/unboxed-closures-unique-type-id.rs b/src/test/run-pass/unboxed-closures-unique-type-id.rs index 55d89d4e4f689..f35daa65a4390 100644 --- a/src/test/run-pass/unboxed-closures-unique-type-id.rs +++ b/src/test/run-pass/unboxed-closures-unique-type-id.rs @@ -21,8 +21,7 @@ use std::ptr; -pub fn replace_map<'a, T, F>(src: &mut T, prod: F) -where F: |: T| -> T { +pub fn replace_map<'a, T, F>(src: &mut T, prod: F) where F: FnOnce(T) -> T { unsafe { *src = prod(ptr::read(src as *mut T as *const T)); } } diff --git a/src/test/run-pass/where-clauses-unboxed-closures.rs b/src/test/run-pass/where-clauses-unboxed-closures.rs index ae005b4ae5306..808e937bc72e3 100644 --- a/src/test/run-pass/where-clauses-unboxed-closures.rs +++ b/src/test/run-pass/where-clauses-unboxed-closures.rs @@ -13,7 +13,7 @@ struct Bencher; // ICE -fn warm_up<'a, F>(f: F) where F: |&: &'a mut Bencher| { +fn warm_up<'a, F>(f: F) where F: Fn(&'a mut Bencher) { } fn main() {