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
This commit is contained in:
Alex Crichton 2014-04-02 09:47:11 -07:00
parent 4e9e25907b
commit d1c584e41b
32 changed files with 295 additions and 171 deletions

View file

@ -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.

View file

@ -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"

View file

@ -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();
/*
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,55 +942,30 @@ impl<'a> Parser<'a> {
}
// parse a TyClosure type
pub fn parse_ty_closure(&mut self,
opt_sigil: Option<ast::Sigil>,
mut region: Option<ast::Lifetime>)
-> Ty_ {
pub fn parse_ty_closure(&mut self) -> Ty_ {
/*
(&|~|@) ['r] [unsafe] [once] fn [:Bounds] <'lt> (S) -> T
^~~~~~^ ^~~^ ^~~~~~~^ ^~~~~^ ^~~~~~~~^ ^~~~^ ^~^ ^
| | | | | | | |
| | | | | | | Return type
| | | | | | Argument types
| | | | | Lifetimes
[unsafe] [once] <'lt> |S| [:Bounds] -> T
^~~~~~~^ ^~~~~^ ^~~~^ ^ ^~~~~~~~^ ^
| | | | | |
| | | | | Return type
| | | | Closure bounds
| | | Once-ness (a.k.a., affine)
| | Purity
| Lifetime bound
Allocation type
| | | 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 onceness = if self.eat_keyword(keywords::Once) {Once} else {Many};
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();
lifetimes
} else {
Vec::new()
@ -971,7 +982,10 @@ impl<'a> Parser<'a> {
inputs
};
let bounds = self.parse_optional_ty_param_bounds();
let (new_region, bounds) = self.parse_optional_ty_param_bounds(true);
// 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 {
@ -981,27 +995,15 @@ impl<'a> Parser<'a> {
variadic: false
});
(BorrowedSigil, decl, lifetimes, bounds)
}
};
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<OwnedSlice<TyParamBound>> {
//
// 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<ast::Lifetime>, Option<OwnedSlice<TyParamBound>>)
{
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 "<T>" and "<T:>".
let bounds = opt_bounds.unwrap_or_default();

View file

@ -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<ast::TyParamBound>,
pub fn print_bounds(&mut self,
region: &Option<ast::Lifetime>,
bounds: &OwnedSlice<ast::TyParamBound>,
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(&param.bounds, false));
try!(s.print_bounds(&None, &param.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 {

View file

@ -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<T> for Iterate<'a, T> {

View file

@ -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;
})
}

View file

@ -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 <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.
// ignore-pretty #13324
#![allow(dead_code)]
fn foo<T>() {}
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::<proc()>();
foo::<proc() -> ()>();
foo::<proc():>();
foo::<proc():'static>();
foo::<proc():Share>();
foo::<proc<'a>(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() {
}

View file

@ -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 };

View file

@ -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() {

View file

@ -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));

View file

@ -10,7 +10,7 @@
#[feature(managed_boxes)];
type compare<T> = 'static |@T, @T| -> bool;
type compare<T> = |@T, @T|: 'static -> bool;
fn test_generic<T>(expected: @T, eq: compare<T>) {
let actual: @T = { expected };

View file

@ -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<T:Clone>(expected: T, eq: compare<T>) {
let actual: T = { expected.clone() };

View file

@ -10,7 +10,7 @@
type compare<'a, T> = 'a |~T, ~T| -> bool;
type compare<'a, T> = |~T, ~T|: 'a -> bool;
fn test_generic<T:Clone>(expected: ~T, eq: compare<T>) {
let actual: ~T = { expected.clone() };

View file

@ -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<T:Clone>(expected: T, eq: compare<T>) {
let actual: T = { expected.clone() };

View file

@ -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<T:Clone>(expected: T, eq: compare<T>) {
let actual: T = { expected.clone() };

View file

@ -10,7 +10,7 @@
#[feature(managed_boxes)];
type compare<T> = 'static |@T, @T| -> bool;
type compare<T> = |@T, @T|: 'static -> bool;
fn test_generic<T>(expected: @T, not_expected: @T, eq: compare<T>) {
let actual: @T = if true { expected } else { not_expected };

View file

@ -12,7 +12,7 @@
// ignore-fast
type compare<T> = 'static |T, T| -> bool;
type compare<T> = |T, T|: 'static -> bool;
fn test_generic<T:Clone>(expected: T, not_expected: T, eq: compare<T>) {
let actual: T = if true { expected.clone() } else { not_expected };

View file

@ -11,7 +11,7 @@
// ignore-fast
// Tests for if as expressions with dynamic type sizes
type compare<T> = 'static |T, T| -> bool;
type compare<T> = |T, T|: 'static -> bool;
fn test_generic<T:Clone>(expected: T, not_expected: T, eq: compare<T>) {
let actual: T = if true { expected.clone() } else { not_expected };

View file

@ -10,7 +10,7 @@
#[feature(managed_boxes)];
type compare<T> = 'static |@T, @T| -> bool;
type compare<T> = |@T, @T|: 'static -> bool;
fn test_generic<T>(expected: @T, eq: compare<T>) {
let actual: @T = match true { true => { expected }, _ => fail!() };

View file

@ -12,7 +12,7 @@
// ignore-fast
type compare<T> = 'static |T, T| -> bool;
type compare<T> = |T, T|: 'static -> bool;
fn test_generic<T:Clone>(expected: T, eq: compare<T>) {
let actual: T = match true { true => { expected.clone() }, _ => fail!("wat") };

View file

@ -10,7 +10,7 @@
type compare<T> = 'static |~T, ~T| -> bool;
type compare<T> = |~T, ~T|: 'static -> bool;
fn test_generic<T:Clone>(expected: ~T, eq: compare<T>) {
let actual: ~T = match true {

View file

@ -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<T:Clone>(expected: T, eq: compare<T>) {
let actual: T = match true {

View file

@ -9,7 +9,7 @@
// except according to those terms.
struct r<'a> {
field: 'a ||
field: ||: 'a,
}
pub fn main() {

View file

@ -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);

View file

@ -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 <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.
pub fn main() {
fn f() {
};
let _: ~fn() = ~f;
}

View file

@ -9,7 +9,7 @@
// except according to those terms.
type Connection = 'static |Vec<u8> |;
type Connection = |Vec<u8>|: 'static;
fn f() -> Option<Connection> {
let mock_connection: Connection = |_| {};

View file

@ -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)

View file

@ -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)
}

View file

@ -12,7 +12,7 @@
// ignore-fast
#[feature(once_fns)];
#![feature(once_fns)]
extern crate sync;
use sync::Arc;

View file

@ -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}
}

View file

@ -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))
}

View file

@ -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}
}