From d1c584e41bc4f7c49123911dd93c2b3db38b0f8f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 2 Apr 2014 09:47:11 -0700 Subject: [PATCH] syntax: Tweak parsing lifetime bounds on closures In summary these are some example transitions this change makes: 'a || => ||: 'a proc:Send() => proc():Send The intended syntax for closures is to put the lifetime bound not at the front but rather in the list of bounds. Currently there is no official support in the AST for bounds that are not 'static, so this case is currently specially handled in the parser to desugar to what the AST is expecting. Additionally, this moves the bounds on procedures to the correct position, which is after the argument list. The current grammar for closures and procedures is: procedure := 'proc' [ '<' lifetime-list '>' ] '(' arg-list ')' [ ':' bound-list ] [ '->' type ] closure := [ 'unsafe' ] ['<' lifetime-list '>' ] '|' arg-list '|' [ ':' bound-list ] [ '->' type ] lifetime-list := lifetime | lifetime ',' lifetime-list arg-list := ident ':' type | ident ':' type ',' arg-list bound-list := bound | bound '+' bound-list bound := path | lifetime This does not currently handle the << ambiguity in `Option<<'a>||>`, I am deferring that to a later patch. Additionally, this removes the support for the obsolete syntaxes of ~fn and &fn. Closes #10553 Closes #10767 Closes #11209 Closes #11210 Closes #11211 --- src/doc/rust.md | 39 ++- src/libsyntax/parse/obsolete.rs | 12 - src/libsyntax/parse/parser.rs | 223 +++++++++--------- src/libsyntax/print/pprust.rs | 35 +-- src/test/bench/shootout-meteor.rs | 4 +- ...ure-bounds-static-cant-capture-borrowed.rs | 4 +- src/test/run-pass/closure-syntax.rs | 76 ++++++ src/test/run-pass/const-fn-val.rs | 2 +- src/test/run-pass/const-vec-of-fns.rs | 2 +- src/test/run-pass/expr-block-fn.rs | 2 +- src/test/run-pass/expr-block-generic-box1.rs | 2 +- src/test/run-pass/expr-block-generic-box2.rs | 2 +- .../run-pass/expr-block-generic-unique1.rs | 2 +- .../run-pass/expr-block-generic-unique2.rs | 2 +- src/test/run-pass/expr-block-generic.rs | 2 +- src/test/run-pass/expr-if-generic-box1.rs | 2 +- src/test/run-pass/expr-if-generic-box2.rs | 2 +- src/test/run-pass/expr-if-generic.rs | 2 +- src/test/run-pass/expr-match-generic-box1.rs | 2 +- src/test/run-pass/expr-match-generic-box2.rs | 2 +- .../run-pass/expr-match-generic-unique1.rs | 2 +- .../run-pass/expr-match-generic-unique2.rs | 2 +- src/test/run-pass/fn-coerce-field.rs | 2 +- src/test/run-pass/hashmap-memory.rs | 2 +- src/test/run-pass/issue-10767.rs | 15 ++ src/test/run-pass/issue-3052.rs | 2 +- src/test/run-pass/issue-3904.rs | 2 +- src/test/run-pass/issue-6157.rs | 2 +- src/test/run-pass/once-move-out-on-stack.rs | 2 +- src/test/run-pass/regions-copy-closure.rs | 4 +- src/test/run-pass/regions-dependent-autofn.rs | 4 +- src/test/run-pass/regions-static-closure.rs | 4 +- 32 files changed, 293 insertions(+), 169 deletions(-) create mode 100644 src/test/run-pass/closure-syntax.rs create mode 100644 src/test/run-pass/issue-10767.rs diff --git a/src/doc/rust.md b/src/doc/rust.md index 96ec52c8cf919..1e1278f08bb93 100644 --- a/src/doc/rust.md +++ b/src/doc/rust.md @@ -3420,8 +3420,21 @@ x = bo(5,7); ### Closure types -The type of a closure mapping an input of type `A` to an output of type `B` is `|A| -> B`. A closure with no arguments or return values has type `||`. +~~~~ {.notrust .ebnf .notation} +closure_type := [ 'unsafe' ] [ '<' lifetime-list '>' ] '|' arg-list '|' + [ ':' bound-list ] [ '->' type ] +procedure_type := 'proc' [ '<' lifetime-list '>' ] '(' arg-list ')' + [ ':' bound-list ] [ '->' type ] +lifetime-list := lifetime | lifetime ',' lifetime-list +arg-list := ident ':' type | ident ':' type ',' arg-list +bound-list := bound | bound '+' bound-list +bound := path | lifetime +~~~~ +The type of a closure mapping an input of type `A` to an output of type `B` is +`|A| -> B`. A closure with no arguments or return values has type `||`. +Similarly, a procedure mapping `A` to `B` is `proc(A) -> B` and a no-argument +and no-return value closure has type `proc()`. An example of creating and calling a closure: @@ -3444,6 +3457,30 @@ call_closure(closure_no_args, closure_args); ``` +Unlike closures, procedures may only be invoked once, but own their +environment, and are allowed to move out of their environment. Procedures are +allocated on the heap (unlike closures). An example of creating and calling a +procedure: + +```rust +let string = ~"Hello"; + +// Creates a new procedure, passing it to the `spawn` function. +spawn(proc() { + println!("{} world!", string); +}); + +// the variable `string` has been moved into the previous procedure, so it is +// no longer usable. + + +// Create an invoke a procedure. Note that the procedure is *moved* when +// invoked, so it cannot be invoked again. +let f = proc(n: int) { n + 22 }; +println!("answer: {}", f(20)); + +``` + ### Object types Every trait item (see [traits](#traits)) defines a type with the same name as the trait. diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index 63b3fb09ee3cd..d09a002e11765 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -36,8 +36,6 @@ pub enum ObsoleteSyntax { ObsoleteEnumWildcard, ObsoleteStructWildcard, ObsoleteVecDotDotWildcard, - ObsoleteBoxedClosure, - ObsoleteClosureType, ObsoleteMultipleImport, ObsoleteManagedPattern, ObsoleteManagedString, @@ -111,16 +109,6 @@ impl<'a> ParserObsoleteMethods for Parser<'a> { "vec slice wildcard", "use `..` instead of `.._` for matching slices" ), - ObsoleteBoxedClosure => ( - "managed or owned closure", - "managed closures have been removed and owned closures are \ - now written `proc()`" - ), - ObsoleteClosureType => ( - "closure type", - "closures are now written `|A| -> B` rather than `&fn(A) -> \ - B`." - ), ObsoleteMultipleImport => ( "multiple imports", "only one import is allowed per `use` statement" diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 94f5458ba535e..62ce0f1e11399 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -29,7 +29,7 @@ use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc}; use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary}; use ast::{ExprVec, ExprVstore, ExprVstoreSlice}; use ast::{ExprVstoreMutSlice, ExprWhile, ExprForLoop, ExternFn, Field, FnDecl}; -use ast::{ExprVstoreUniq, Onceness, Once, Many}; +use ast::{ExprVstoreUniq, Once, Many}; use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod}; use ast::{Ident, ImpureFn, Inherited, Item, Item_, ItemStatic}; use ast::{ItemEnum, ItemFn, ItemForeignMod, ItemImpl}; @@ -892,8 +892,44 @@ impl<'a> Parser<'a> { // Parses a procedure type (`proc`). The initial `proc` keyword must // already have been parsed. pub fn parse_proc_type(&mut self) -> Ty_ { - let bounds = self.parse_optional_ty_param_bounds(); - let (decl, lifetimes) = self.parse_ty_fn_decl(false); + /* + + proc <'lt> (S) [:Bounds] -> T + ^~~^ ^~~~^ ^ ^~~~~~~~^ ^ + | | | | | + | | | | Return type + | | | Bounds + | | Argument types + | Lifetimes + the `proc` keyword + + */ + + // NOTE: remove after the next stage0 snap + let (decl, lifetimes, bounds) = if self.token == token::COLON { + let (_, bounds) = self.parse_optional_ty_param_bounds(false); + let (decl, lifetimes) = self.parse_ty_fn_decl(false); + (decl, lifetimes, bounds) + } else { + let lifetimes = if self.eat(&token::LT) { + let lifetimes = self.parse_lifetimes(); + self.expect_gt(); + lifetimes + } else { + Vec::new() + }; + + let (inputs, variadic) = self.parse_fn_args(false, false); + let (_, bounds) = self.parse_optional_ty_param_bounds(false); + let (ret_style, ret_ty) = self.parse_ret_ty(); + let decl = P(FnDecl { + inputs: inputs, + output: ret_ty, + cf: ret_style, + variadic: variadic + }); + (decl, lifetimes, bounds) + }; TyClosure(@ClosureTy { sigil: OwnedSigil, region: None, @@ -906,102 +942,68 @@ impl<'a> Parser<'a> { } // parse a TyClosure type - pub fn parse_ty_closure(&mut self, - opt_sigil: Option, - mut region: Option) - -> Ty_ { + pub fn parse_ty_closure(&mut self) -> Ty_ { /* - (&|~|@) ['r] [unsafe] [once] fn [:Bounds] <'lt> (S) -> T - ^~~~~~^ ^~~^ ^~~~~~~^ ^~~~~^ ^~~~~~~~^ ^~~~^ ^~^ ^ - | | | | | | | | - | | | | | | | Return type - | | | | | | Argument types - | | | | | Lifetimes - | | | | Closure bounds - | | | Once-ness (a.k.a., affine) - | | Purity - | Lifetime bound - Allocation type + [unsafe] [once] <'lt> |S| [:Bounds] -> T + ^~~~~~~^ ^~~~~^ ^~~~^ ^ ^~~~~~~~^ ^ + | | | | | | + | | | | | Return type + | | | | Closure bounds + | | | Argument types + | | Lifetimes + | Once-ness (a.k.a., affine) + Purity */ - // At this point, the allocation type and lifetime bound have been - // parsed. - + // NOTE: remove 'let region' after a stage0 snap + let region = self.parse_opt_lifetime(); let purity = self.parse_unsafety(); - let onceness = parse_onceness(self); - - let (sigil, decl, lifetimes, bounds) = match opt_sigil { - Some(sigil) => { - // Old-style closure syntax (`fn(A)->B`). - self.expect_keyword(keywords::Fn); - let bounds = self.parse_optional_ty_param_bounds(); - let (decl, lifetimes) = self.parse_ty_fn_decl(false); - (sigil, decl, lifetimes, bounds) - } - None => { - // New-style closure syntax (`<'lt>|A|:K -> B`). - let lifetimes = if self.eat(&token::LT) { - let lifetimes = self.parse_lifetimes(); - self.expect_gt(); - - // Re-parse the region here. What a hack. - if region.is_some() { - self.span_err(self.last_span, - "lifetime declarations must precede \ - the lifetime associated with a \ - closure"); - } - region = self.parse_opt_lifetime(); + let onceness = if self.eat_keyword(keywords::Once) {Once} else {Many}; - lifetimes - } else { - Vec::new() - }; + let lifetimes = if self.eat(&token::LT) { + let lifetimes = self.parse_lifetimes(); + self.expect_gt(); - let inputs = if self.eat(&token::OROR) { - Vec::new() - } else { - self.expect_or(); - let inputs = self.parse_seq_to_before_or( - &token::COMMA, - |p| p.parse_arg_general(false)); - self.expect_or(); - inputs - }; + lifetimes + } else { + Vec::new() + }; - let bounds = self.parse_optional_ty_param_bounds(); + let inputs = if self.eat(&token::OROR) { + Vec::new() + } else { + self.expect_or(); + 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(); - let decl = P(FnDecl { - inputs: inputs, - output: output, - cf: return_style, - variadic: false - }); + let (new_region, bounds) = self.parse_optional_ty_param_bounds(true); - (BorrowedSigil, decl, lifetimes, bounds) - } - }; + // NOTE: this should be removed after a stage0 snap + let region = new_region.or(region); + + let (return_style, output) = self.parse_ret_ty(); + let decl = P(FnDecl { + inputs: inputs, + output: output, + cf: return_style, + variadic: false + }); - return TyClosure(@ClosureTy { - sigil: sigil, + TyClosure(@ClosureTy { + sigil: BorrowedSigil, region: region, purity: purity, onceness: onceness, bounds: bounds, decl: decl, lifetimes: lifetimes, - }); - - fn parse_onceness(this: &mut Parser) -> Onceness { - if this.eat_keyword(keywords::Once) { - Once - } else { - Many - } - } + }) } pub fn parse_unsafety(&mut self) -> Purity { @@ -1245,6 +1247,7 @@ impl<'a> Parser<'a> { self.token == token::BINOP(token::OR) || self.token == token::OROR || self.token == token::LT || + // NOTE: remove this clause after a stage0 snap Parser::token_is_lifetime(&self.token) { // CLOSURE // @@ -1252,9 +1255,7 @@ impl<'a> Parser<'a> { // introduce a closure, once procs can have lifetime bounds. We // will need to refactor the grammar a little bit at that point. - let lifetime = self.parse_opt_lifetime(); - let result = self.parse_ty_closure(None, lifetime); - result + self.parse_ty_closure() } else if self.eat_keyword(keywords::Typeof) { // TYPEOF // In order to not be ambiguous, the type must be surrounded by parens. @@ -1288,23 +1289,6 @@ impl<'a> Parser<'a> { pub fn parse_box_or_uniq_pointee(&mut self, sigil: ast::Sigil) -> Ty_ { - // ~'foo fn() or ~fn() are parsed directly as obsolete fn types: - match self.token { - token::LIFETIME(..) => { - let lifetime = self.parse_lifetime(); - self.obsolete(self.last_span, ObsoleteBoxedClosure); - return self.parse_ty_closure(Some(sigil), Some(lifetime)); - } - - token::IDENT(..) => { - if self.token_is_old_style_closure_keyword() { - self.obsolete(self.last_span, ObsoleteBoxedClosure); - return self.parse_ty_closure(Some(sigil), None); - } - } - _ => {} - } - // other things are parsed as @/~ + a type. Note that constructs like // ~[] and ~str will be resolved during typeck to slices and so forth, // rather than boxed ptrs. But the special casing of str/vec is not @@ -1320,11 +1304,6 @@ impl<'a> Parser<'a> { // look for `&'lt` or `&'foo ` and interpret `foo` as the region name: let opt_lifetime = self.parse_opt_lifetime(); - if self.token_is_old_style_closure_keyword() { - self.obsolete(self.last_span, ObsoleteClosureType); - return self.parse_ty_closure(Some(BorrowedSigil), opt_lifetime); - } - let mt = self.parse_mt(); return TyRptr(opt_lifetime, mt); } @@ -1540,7 +1519,8 @@ impl<'a> Parser<'a> { // Next, parse a colon and bounded type parameters, if applicable. let bounds = if mode == LifetimeAndTypesAndBounds { - self.parse_optional_ty_param_bounds() + let (_, bounds) = self.parse_optional_ty_param_bounds(false); + bounds } else { None }; @@ -3376,11 +3356,19 @@ impl<'a> Parser<'a> { // Returns "Some(Empty)" if there's a colon but nothing after (e.g. "T:") // Returns "Some(stuff)" otherwise (e.g. "T:stuff"). // NB: The None/Some distinction is important for issue #7264. - fn parse_optional_ty_param_bounds(&mut self) -> Option> { + // + // Note that the `allow_any_lifetime` argument is a hack for now while the + // AST doesn't support arbitrary lifetimes in bounds on type parameters. In + // the future, this flag should be removed, and the return value of this + // function should be Option<~[TyParamBound]> + fn parse_optional_ty_param_bounds(&mut self, allow_any_lifetime: bool) + -> (Option, Option>) + { if !self.eat(&token::COLON) { - return None; + return (None, None); } + let mut ret_lifetime = None; let mut result = vec!(); loop { match self.token { @@ -3388,6 +3376,19 @@ impl<'a> Parser<'a> { let lifetime_interned_string = token::get_ident(lifetime); if lifetime_interned_string.equiv(&("static")) { result.push(RegionTyParamBound); + if allow_any_lifetime && ret_lifetime.is_none() { + ret_lifetime = Some(ast::Lifetime { + id: ast::DUMMY_NODE_ID, + span: self.span, + name: lifetime.name + }); + } + } else if allow_any_lifetime && ret_lifetime.is_none() { + ret_lifetime = Some(ast::Lifetime { + id: ast::DUMMY_NODE_ID, + span: self.span, + name: lifetime.name + }); } else { self.span_err(self.span, "`'static` is the only permissible region bound here"); @@ -3406,13 +3407,13 @@ impl<'a> Parser<'a> { } } - return Some(OwnedSlice::from_vec(result)); + return (ret_lifetime, Some(OwnedSlice::from_vec(result))); } // matches typaram = IDENT optbounds ( EQ ty )? fn parse_ty_param(&mut self) -> TyParam { let ident = self.parse_ident(); - let opt_bounds = self.parse_optional_ty_param_bounds(); + let (_, opt_bounds) = self.parse_optional_ty_param_bounds(false); // For typarams we don't care about the difference b/w "" and "". let bounds = opt_bounds.unwrap_or_default(); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index fe969c6fd51a5..44e95aa9573c0 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1557,7 +1557,7 @@ impl<'a> State<'a> { match *opt_bounds { None => Ok(()), - Some(ref bounds) => self.print_bounds(bounds, true), + Some(ref bounds) => self.print_bounds(&None, bounds, true), } } @@ -1813,11 +1813,24 @@ impl<'a> State<'a> { self.maybe_print_comment(decl.output.span.lo) } - pub fn print_bounds(&mut self, bounds: &OwnedSlice, + pub fn print_bounds(&mut self, + region: &Option, + bounds: &OwnedSlice, print_colon_anyway: bool) -> IoResult<()> { - if !bounds.is_empty() { + if !bounds.is_empty() || region.is_some() { try!(word(&mut self.s, ":")); let mut first = true; + match *region { + Some(ref lt) => { + let token = token::get_name(lt.name); + if token.get() != "static" { + try!(self.nbsp()); + first = false; + try!(self.print_lifetime(lt)); + } + } + None => {} + } for bound in bounds.iter() { try!(self.nbsp()); if first { @@ -1866,7 +1879,7 @@ impl<'a> State<'a> { let idx = idx - generics.lifetimes.len(); let param = generics.ty_params.get(idx); try!(s.print_ident(param.ident)); - try!(s.print_bounds(¶m.bounds, false)); + try!(s.print_bounds(&None, ¶m.bounds, false)); match param.default { Some(default) => { try!(space(&mut s.s)); @@ -2027,15 +2040,11 @@ impl<'a> State<'a> { try!(word(&mut self.s, "proc")); } else if opt_sigil == Some(ast::BorrowedSigil) { try!(self.print_extern_opt_abi(opt_abi)); - for lifetime in opt_region.iter() { - try!(self.print_lifetime(lifetime)); - } try!(self.print_purity(purity)); try!(self.print_onceness(onceness)); } else { try!(self.print_opt_abi_and_extern_if_nondefault(opt_abi)); try!(self.print_opt_sigil(opt_sigil)); - try!(self.print_opt_lifetime(opt_region)); try!(self.print_purity(purity)); try!(self.print_onceness(onceness)); try!(word(&mut self.s, "fn")); @@ -2049,10 +2058,6 @@ impl<'a> State<'a> { _ => () } - if opt_sigil != Some(ast::BorrowedSigil) { - opt_bounds.as_ref().map(|bounds| self.print_bounds(bounds, true)); - } - match generics { Some(g) => try!(self.print_generics(g)), _ => () } try!(zerobreak(&mut self.s)); @@ -2066,8 +2071,6 @@ impl<'a> State<'a> { if opt_sigil == Some(ast::BorrowedSigil) { try!(word(&mut self.s, "|")); - - opt_bounds.as_ref().map(|bounds| self.print_bounds(bounds, true)); } else { if decl.variadic { try!(word(&mut self.s, ", ...")); @@ -2075,6 +2078,10 @@ impl<'a> State<'a> { try!(self.pclose()); } + opt_bounds.as_ref().map(|bounds| { + self.print_bounds(opt_region, bounds, true) + }); + try!(self.maybe_print_comment(decl.output.span.lo)); match decl.output.node { diff --git a/src/test/bench/shootout-meteor.rs b/src/test/bench/shootout-meteor.rs index 45ce177662095..ee1697e52cffd 100644 --- a/src/test/bench/shootout-meteor.rs +++ b/src/test/bench/shootout-meteor.rs @@ -15,11 +15,11 @@ // returns an infinite iterator of repeated applications of f to x, // i.e. [x, f(x), f(f(x)), ...], as haskell iterate function. -fn iterate<'a, T>(x: T, f: 'a |&T| -> T) -> Iterate<'a, T> { +fn iterate<'a, T>(x: T, f: |&T|: 'a -> T) -> Iterate<'a, T> { Iterate {f: f, next: x} } struct Iterate<'a, T> { - f: 'a |&T| -> T, + f: |&T|: 'a -> T, next: T } impl<'a, T> Iterator for Iterate<'a, T> { diff --git a/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs b/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs index 1c6d65ba54167..9176412cd79fe 100644 --- a/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs +++ b/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs @@ -12,8 +12,8 @@ fn bar(blk: ||:'static) { } fn foo(x: &()) { - bar(|| { - let _ = x; //~ ERROR does not fulfill `'static` + bar(|| { //~ ERROR cannot infer an appropriate lifetime + let _ = x; }) } diff --git a/src/test/run-pass/closure-syntax.rs b/src/test/run-pass/closure-syntax.rs new file mode 100644 index 0000000000000..798808a157277 --- /dev/null +++ b/src/test/run-pass/closure-syntax.rs @@ -0,0 +1,76 @@ +// 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. + +// ignore-pretty #13324 + +#![allow(dead_code)] + +fn foo() {} + +trait Bar1 {} +impl Bar1 for proc() {} + +trait Bar2 {} +impl Bar2 for proc(): Send {} + +trait Bar3 {} +impl<'b> Bar3 for <'a>|&'a int|: 'b + Send -> &'a int {} + +trait Bar4 {} +impl Bar4 for proc<'a>(&'a int) -> &'a int {} + +struct Foo<'a> { + a: ||: 'a, + b: ||: 'static, + c: <'b>||: 'a, + d: ||: 'a + Share, + e: <'b>|int|: 'a + Share -> &'b f32, + f: proc(), + g: proc(): 'static + Share, + h: proc<'b>(int): Share -> &'b f32, +} + +fn f<'a>(a: &'a int, f: <'b>|&'b int| -> &'b int) -> &'a int { + f(a) +} + +fn g<'a>(a: &'a int, f: proc<'b>(&'b int) -> &'b int) -> &'a int { + f(a) +} + +fn bar<'b>() { + foo::<||>(); + foo::<|| -> ()>(); + foo::<||:>(); + foo::<||:'b>(); + foo::<||:'b + Share>(); + foo::<||:Share>(); + foo::< <'a>|int, f32, &'a int|:'b + Share -> &'a int>(); + foo::(); + foo:: ()>(); + foo::(); + foo::(); + foo::(); + foo::(int, f32, &'a int):'static + Share -> &'a int>(); + + // issue #11209 + let _: 'b ||; // for comparison + let _: <'a> ||; + + let _: Option<||:'b>; + // let _: Option<<'a>||>; + let _: Option< <'a>||>; + + // issue #11210 + let _: 'static ||; +} + +pub fn main() { +} diff --git a/src/test/run-pass/const-fn-val.rs b/src/test/run-pass/const-fn-val.rs index 18638ab68776e..57e37aaf393bc 100644 --- a/src/test/run-pass/const-fn-val.rs +++ b/src/test/run-pass/const-fn-val.rs @@ -12,7 +12,7 @@ fn foo() -> int { return 0xca7f000d; } -struct Bar<'a> { f: 'a || -> int } +struct Bar<'a> { f: ||: 'a -> int } static mut b : Bar<'static> = Bar { f: foo }; diff --git a/src/test/run-pass/const-vec-of-fns.rs b/src/test/run-pass/const-vec-of-fns.rs index 9a93fcb5f8912..1f5c1a556a991 100644 --- a/src/test/run-pass/const-vec-of-fns.rs +++ b/src/test/run-pass/const-vec-of-fns.rs @@ -17,7 +17,7 @@ fn f() { } static bare_fns: &'static [fn()] = &[f, f]; -struct S<'a>('a ||); +struct S<'a>(||:'a); static mut closures: &'static [S<'static>] = &[S(f), S(f)]; pub fn main() { diff --git a/src/test/run-pass/expr-block-fn.rs b/src/test/run-pass/expr-block-fn.rs index 9ca41c56dc960..3a6cd61fa0992 100644 --- a/src/test/run-pass/expr-block-fn.rs +++ b/src/test/run-pass/expr-block-fn.rs @@ -11,7 +11,7 @@ fn test_fn() { - type t = 'static || -> int; + type t = ||: 'static -> int; fn ten() -> int { return 10; } let rs: t = ten; assert!((rs() == 10)); diff --git a/src/test/run-pass/expr-block-generic-box1.rs b/src/test/run-pass/expr-block-generic-box1.rs index eaead09a2f7a9..513dbf2eba866 100644 --- a/src/test/run-pass/expr-block-generic-box1.rs +++ b/src/test/run-pass/expr-block-generic-box1.rs @@ -10,7 +10,7 @@ #[feature(managed_boxes)]; -type compare = 'static |@T, @T| -> bool; +type compare = |@T, @T|: 'static -> bool; fn test_generic(expected: @T, eq: compare) { let actual: @T = { expected }; diff --git a/src/test/run-pass/expr-block-generic-box2.rs b/src/test/run-pass/expr-block-generic-box2.rs index 9727f41d144c7..5eb3f36ce1b78 100644 --- a/src/test/run-pass/expr-block-generic-box2.rs +++ b/src/test/run-pass/expr-block-generic-box2.rs @@ -12,7 +12,7 @@ // ignore-fast -type compare<'a, T> = 'a |T, T| -> bool; +type compare<'a, T> = |T, T|: 'a -> bool; fn test_generic(expected: T, eq: compare) { let actual: T = { expected.clone() }; diff --git a/src/test/run-pass/expr-block-generic-unique1.rs b/src/test/run-pass/expr-block-generic-unique1.rs index b3fbd8c765809..95f3ff62d2697 100644 --- a/src/test/run-pass/expr-block-generic-unique1.rs +++ b/src/test/run-pass/expr-block-generic-unique1.rs @@ -10,7 +10,7 @@ -type compare<'a, T> = 'a |~T, ~T| -> bool; +type compare<'a, T> = |~T, ~T|: 'a -> bool; fn test_generic(expected: ~T, eq: compare) { let actual: ~T = { expected.clone() }; diff --git a/src/test/run-pass/expr-block-generic-unique2.rs b/src/test/run-pass/expr-block-generic-unique2.rs index 787f50c1b037a..85a1d137d211b 100644 --- a/src/test/run-pass/expr-block-generic-unique2.rs +++ b/src/test/run-pass/expr-block-generic-unique2.rs @@ -10,7 +10,7 @@ // ignore-fast -type compare<'a, T> = 'a |T, T| -> bool; +type compare<'a, T> = |T, T|: 'a -> bool; fn test_generic(expected: T, eq: compare) { let actual: T = { expected.clone() }; diff --git a/src/test/run-pass/expr-block-generic.rs b/src/test/run-pass/expr-block-generic.rs index 3a1a79aa38e2a..4c8a32ce3cb39 100644 --- a/src/test/run-pass/expr-block-generic.rs +++ b/src/test/run-pass/expr-block-generic.rs @@ -12,7 +12,7 @@ // ignore-fast // Tests for standalone blocks as expressions with dynamic type sizes -type compare<'a, T> = 'a |T, T| -> bool; +type compare<'a, T> = |T, T|: 'a -> bool; fn test_generic(expected: T, eq: compare) { let actual: T = { expected.clone() }; diff --git a/src/test/run-pass/expr-if-generic-box1.rs b/src/test/run-pass/expr-if-generic-box1.rs index cba01fbd8dd81..78f42120ab77f 100644 --- a/src/test/run-pass/expr-if-generic-box1.rs +++ b/src/test/run-pass/expr-if-generic-box1.rs @@ -10,7 +10,7 @@ #[feature(managed_boxes)]; -type compare = 'static |@T, @T| -> bool; +type compare = |@T, @T|: 'static -> bool; fn test_generic(expected: @T, not_expected: @T, eq: compare) { let actual: @T = if true { expected } else { not_expected }; diff --git a/src/test/run-pass/expr-if-generic-box2.rs b/src/test/run-pass/expr-if-generic-box2.rs index eba30fa9bca42..8b78aabd8601c 100644 --- a/src/test/run-pass/expr-if-generic-box2.rs +++ b/src/test/run-pass/expr-if-generic-box2.rs @@ -12,7 +12,7 @@ // ignore-fast -type compare = 'static |T, T| -> bool; +type compare = |T, T|: 'static -> bool; fn test_generic(expected: T, not_expected: T, eq: compare) { let actual: T = if true { expected.clone() } else { not_expected }; diff --git a/src/test/run-pass/expr-if-generic.rs b/src/test/run-pass/expr-if-generic.rs index 7e58d466b9044..f250db1f692c3 100644 --- a/src/test/run-pass/expr-if-generic.rs +++ b/src/test/run-pass/expr-if-generic.rs @@ -11,7 +11,7 @@ // ignore-fast // Tests for if as expressions with dynamic type sizes -type compare = 'static |T, T| -> bool; +type compare = |T, T|: 'static -> bool; fn test_generic(expected: T, not_expected: T, eq: compare) { let actual: T = if true { expected.clone() } else { not_expected }; diff --git a/src/test/run-pass/expr-match-generic-box1.rs b/src/test/run-pass/expr-match-generic-box1.rs index 82e80e7da7dc3..287e0ea349de6 100644 --- a/src/test/run-pass/expr-match-generic-box1.rs +++ b/src/test/run-pass/expr-match-generic-box1.rs @@ -10,7 +10,7 @@ #[feature(managed_boxes)]; -type compare = 'static |@T, @T| -> bool; +type compare = |@T, @T|: 'static -> bool; fn test_generic(expected: @T, eq: compare) { let actual: @T = match true { true => { expected }, _ => fail!() }; diff --git a/src/test/run-pass/expr-match-generic-box2.rs b/src/test/run-pass/expr-match-generic-box2.rs index 1ad9db4625788..01b46528c7b45 100644 --- a/src/test/run-pass/expr-match-generic-box2.rs +++ b/src/test/run-pass/expr-match-generic-box2.rs @@ -12,7 +12,7 @@ // ignore-fast -type compare = 'static |T, T| -> bool; +type compare = |T, T|: 'static -> bool; fn test_generic(expected: T, eq: compare) { let actual: T = match true { true => { expected.clone() }, _ => fail!("wat") }; diff --git a/src/test/run-pass/expr-match-generic-unique1.rs b/src/test/run-pass/expr-match-generic-unique1.rs index af9022ed3222c..991a1f449f191 100644 --- a/src/test/run-pass/expr-match-generic-unique1.rs +++ b/src/test/run-pass/expr-match-generic-unique1.rs @@ -10,7 +10,7 @@ -type compare = 'static |~T, ~T| -> bool; +type compare = |~T, ~T|: 'static -> bool; fn test_generic(expected: ~T, eq: compare) { let actual: ~T = match true { diff --git a/src/test/run-pass/expr-match-generic-unique2.rs b/src/test/run-pass/expr-match-generic-unique2.rs index 9784847159071..6c1a6d22de703 100644 --- a/src/test/run-pass/expr-match-generic-unique2.rs +++ b/src/test/run-pass/expr-match-generic-unique2.rs @@ -10,7 +10,7 @@ // ignore-fast -type compare<'a, T> = 'a |T, T| -> bool; +type compare<'a, T> = |T, T|: 'a -> bool; fn test_generic(expected: T, eq: compare) { let actual: T = match true { diff --git a/src/test/run-pass/fn-coerce-field.rs b/src/test/run-pass/fn-coerce-field.rs index e49b1e9ed61a6..6b7490ba67368 100644 --- a/src/test/run-pass/fn-coerce-field.rs +++ b/src/test/run-pass/fn-coerce-field.rs @@ -9,7 +9,7 @@ // except according to those terms. struct r<'a> { - field: 'a || + field: ||: 'a, } pub fn main() { diff --git a/src/test/run-pass/hashmap-memory.rs b/src/test/run-pass/hashmap-memory.rs index a57cf3e59ae1d..3ff7fea95f1b7 100644 --- a/src/test/run-pass/hashmap-memory.rs +++ b/src/test/run-pass/hashmap-memory.rs @@ -28,7 +28,7 @@ mod map_reduce { use std::str; use std::task; - pub type putter<'a> = 'a |~str, ~str|; + pub type putter<'a> = |~str, ~str|: 'a; pub type mapper = extern fn(~str, putter); diff --git a/src/test/run-pass/issue-10767.rs b/src/test/run-pass/issue-10767.rs new file mode 100644 index 0000000000000..3254f5bc35f90 --- /dev/null +++ b/src/test/run-pass/issue-10767.rs @@ -0,0 +1,15 @@ +// 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. + +pub fn main() { + fn f() { + }; + let _: ~fn() = ~f; +} diff --git a/src/test/run-pass/issue-3052.rs b/src/test/run-pass/issue-3052.rs index 5bd41e8bf3bd3..00e6b5ca8fedc 100644 --- a/src/test/run-pass/issue-3052.rs +++ b/src/test/run-pass/issue-3052.rs @@ -9,7 +9,7 @@ // except according to those terms. -type Connection = 'static |Vec |; +type Connection = |Vec|: 'static; fn f() -> Option { let mock_connection: Connection = |_| {}; diff --git a/src/test/run-pass/issue-3904.rs b/src/test/run-pass/issue-3904.rs index fe6521b4df9a6..81a7d073c4cda 100644 --- a/src/test/run-pass/issue-3904.rs +++ b/src/test/run-pass/issue-3904.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -type ErrPrinter<'a> = 'a |&str, &str|; +type ErrPrinter<'a> = |&str, &str|: 'a; fn example_err(prog: &str, arg: &str) { println!("{}: {}", prog, arg) diff --git a/src/test/run-pass/issue-6157.rs b/src/test/run-pass/issue-6157.rs index 50e5f97034a1a..5a78aed5826de 100644 --- a/src/test/run-pass/issue-6157.rs +++ b/src/test/run-pass/issue-6157.rs @@ -10,7 +10,7 @@ pub trait OpInt<'a> { fn call<'a>(&'a self, int, int) -> int; } -impl<'a> OpInt<'a> for 'a |int, int| -> int { +impl<'a> OpInt<'a> for |int, int|: 'a -> int { fn call(&self, a:int, b:int) -> int { (*self)(a, b) } diff --git a/src/test/run-pass/once-move-out-on-stack.rs b/src/test/run-pass/once-move-out-on-stack.rs index f14827c7245f4..995fc0911130e 100644 --- a/src/test/run-pass/once-move-out-on-stack.rs +++ b/src/test/run-pass/once-move-out-on-stack.rs @@ -12,7 +12,7 @@ // ignore-fast -#[feature(once_fns)]; +#![feature(once_fns)] extern crate sync; use sync::Arc; diff --git a/src/test/run-pass/regions-copy-closure.rs b/src/test/run-pass/regions-copy-closure.rs index 55cb5c6268462..ac40fb885a134 100644 --- a/src/test/run-pass/regions-copy-closure.rs +++ b/src/test/run-pass/regions-copy-closure.rs @@ -9,10 +9,10 @@ // except according to those terms. struct closure_box<'a> { - cl: 'a ||, + cl: ||: 'a, } -fn box_it<'r>(x: 'r ||) -> closure_box<'r> { +fn box_it<'r>(x: ||: 'r) -> closure_box<'r> { closure_box {cl: x} } diff --git a/src/test/run-pass/regions-dependent-autofn.rs b/src/test/run-pass/regions-dependent-autofn.rs index b50930dd2947b..e9cd7fb49731f 100644 --- a/src/test/run-pass/regions-dependent-autofn.rs +++ b/src/test/run-pass/regions-dependent-autofn.rs @@ -11,9 +11,9 @@ // Test lifetimes are linked properly when we autoslice a vector. // Issue #3148. -fn subslice<'r>(v: 'r ||) -> 'r || { v } +fn subslice<'r>(v: ||: 'r) -> ||: 'r { v } -fn both<'r>(v: 'r ||) -> 'r || { +fn both<'r>(v: ||: 'r) -> ||: 'r { subslice(subslice(v)) } diff --git a/src/test/run-pass/regions-static-closure.rs b/src/test/run-pass/regions-static-closure.rs index ff4b43cb6b5fa..d91c11dde10e2 100644 --- a/src/test/run-pass/regions-static-closure.rs +++ b/src/test/run-pass/regions-static-closure.rs @@ -9,10 +9,10 @@ // except according to those terms. struct closure_box<'a> { - cl: 'a ||, + cl: ||: 'a, } -fn box_it<'r>(x: 'r ||) -> closure_box<'r> { +fn box_it<'r>(x: ||: 'r) -> closure_box<'r> { closure_box {cl: x} }