Skip to content

Commit 7c00d77

Browse files
committed
librustc: Implement the syntax in the RFC for unboxed closure sugar.
Part of issue #16640. I am leaving this issue open to handle parsing of higher-rank lifetimes in traits. This change breaks code that used unboxed closures: * Instead of `F:|&: int| -> int`, write `F:Fn(int) -> int`. * Instead of `F:|&mut: int| -> int`, write `F:FnMut(int) -> int`. * Instead of `F:|: int| -> int`, write `F:FnOnce(int) -> int`. [breaking-change]
1 parent 9c41064 commit 7c00d77

17 files changed

+207
-117
lines changed

src/librustc/middle/resolve.rs

+28
Original file line numberDiff line numberDiff line change
@@ -4328,6 +4328,34 @@ impl<'a> Resolver<'a> {
43284328
self.resolve_trait_reference(id, tref, reference_type)
43294329
}
43304330
UnboxedFnTyParamBound(ref unboxed_function) => {
4331+
match self.resolve_path(unboxed_function.ref_id,
4332+
&unboxed_function.path,
4333+
TypeNS,
4334+
true) {
4335+
None => {
4336+
let path_str = self.path_idents_to_string(
4337+
&unboxed_function.path);
4338+
self.resolve_error(unboxed_function.path.span,
4339+
format!("unresolved trait `{}`",
4340+
path_str).as_slice())
4341+
}
4342+
Some(def) => {
4343+
match def {
4344+
(DefTrait(_), _) => {
4345+
self.record_def(unboxed_function.ref_id, def);
4346+
}
4347+
_ => {
4348+
let msg =
4349+
format!("`{}` is not a trait",
4350+
self.path_idents_to_string(
4351+
&unboxed_function.path));
4352+
self.resolve_error(unboxed_function.path.span,
4353+
msg.as_slice());
4354+
}
4355+
}
4356+
}
4357+
}
4358+
43314359
for argument in unboxed_function.decl.inputs.iter() {
43324360
self.resolve_type(&*argument.ty);
43334361
}

src/librustc/middle/typeck/astconv.rs

+13-15
Original file line numberDiff line numberDiff line change
@@ -585,32 +585,29 @@ pub fn trait_ref_for_unboxed_function<'tcx, AC: AstConv<'tcx>,
585585
RS:RegionScope>(
586586
this: &AC,
587587
rscope: &RS,
588-
unboxed_function: &ast::UnboxedFnTy,
588+
kind: ast::UnboxedClosureKind,
589+
decl: &ast::FnDecl,
589590
self_ty: Option<ty::t>)
590591
-> ty::TraitRef {
591-
let lang_item = match unboxed_function.kind {
592+
let lang_item = match kind {
592593
ast::FnUnboxedClosureKind => FnTraitLangItem,
593594
ast::FnMutUnboxedClosureKind => FnMutTraitLangItem,
594595
ast::FnOnceUnboxedClosureKind => FnOnceTraitLangItem,
595596
};
596597
let trait_did = this.tcx().lang_items.require(lang_item).unwrap();
597-
let input_types =
598-
unboxed_function.decl
599-
.inputs
600-
.iter()
601-
.map(|input| {
598+
let input_types = decl.inputs
599+
.iter()
600+
.map(|input| {
602601
ast_ty_to_ty(this, rscope, &*input.ty)
603-
}).collect::<Vec<_>>();
602+
}).collect::<Vec<_>>();
604603
let input_tuple = if input_types.len() == 0 {
605604
ty::mk_nil()
606605
} else {
607606
ty::mk_tup(this.tcx(), input_types)
608607
};
609-
let output_type = ast_ty_to_ty(this,
610-
rscope,
611-
&*unboxed_function.decl.output);
608+
let output_type = ast_ty_to_ty(this, rscope, &*decl.output);
612609
let mut substs = Substs::new_type(vec!(input_tuple, output_type),
613-
Vec::new());
610+
Vec::new());
614611

615612
match self_ty {
616613
Some(s) => substs.types.push(SelfSpace, s),
@@ -648,7 +645,8 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
648645
substs
649646
} = trait_ref_for_unboxed_function(this,
650647
rscope,
651-
&**unboxed_function,
648+
unboxed_function.kind,
649+
&*unboxed_function.decl,
652650
None);
653651
let r = ptr_ty.default_region();
654652
let tr = ty::mk_trait(this.tcx(),
@@ -1510,7 +1508,7 @@ fn compute_region_bound<'tcx, AC: AstConv<'tcx>, RS:RegionScope>(
15101508
pub struct PartitionedBounds<'a> {
15111509
pub builtin_bounds: ty::BuiltinBounds,
15121510
pub trait_bounds: Vec<&'a ast::TraitRef>,
1513-
pub unboxed_fn_ty_bounds: Vec<&'a ast::UnboxedFnTy>,
1511+
pub unboxed_fn_ty_bounds: Vec<&'a ast::UnboxedFnBound>,
15141512
pub region_bounds: Vec<&'a ast::Lifetime>,
15151513
}
15161514

@@ -1574,7 +1572,7 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt,
15741572
region_bounds.push(l);
15751573
}
15761574
ast::UnboxedFnTyParamBound(ref unboxed_function) => {
1577-
unboxed_fn_ty_bounds.push(unboxed_function);
1575+
unboxed_fn_ty_bounds.push(&**unboxed_function);
15781576
}
15791577
}
15801578
}

src/librustc/middle/typeck/collect.rs

+38-4
Original file line numberDiff line numberDiff line change
@@ -1427,7 +1427,8 @@ pub fn instantiate_unboxed_fn_ty<'tcx,AC>(this: &AC,
14271427
let param_ty = param_ty.to_ty(this.tcx());
14281428
Rc::new(astconv::trait_ref_for_unboxed_function(this,
14291429
&rscope,
1430-
unboxed_function,
1430+
unboxed_function.kind,
1431+
&*unboxed_function.decl,
14311432
Some(param_ty)))
14321433
}
14331434

@@ -2165,9 +2166,42 @@ fn conv_param_bounds<'tcx,AC>(this: &AC,
21652166
region_bounds,
21662167
unboxed_fn_ty_bounds } =
21672168
astconv::partition_bounds(this.tcx(), span, all_bounds.as_slice());
2168-
let unboxed_fn_ty_bounds =
2169-
unboxed_fn_ty_bounds.into_iter()
2170-
.map(|b| instantiate_unboxed_fn_ty(this, b, param_ty));
2169+
2170+
let unboxed_fn_ty_bounds = unboxed_fn_ty_bounds.move_iter().map(|b| {
2171+
let trait_id = this.tcx().def_map.borrow().get(&b.ref_id).def_id();
2172+
let mut kind = None;
2173+
for &(lang_item, this_kind) in [
2174+
(this.tcx().lang_items.fn_trait(), ast::FnUnboxedClosureKind),
2175+
(this.tcx().lang_items.fn_mut_trait(),
2176+
ast::FnMutUnboxedClosureKind),
2177+
(this.tcx().lang_items.fn_once_trait(),
2178+
ast::FnOnceUnboxedClosureKind)
2179+
].iter() {
2180+
if Some(trait_id) == lang_item {
2181+
kind = Some(this_kind);
2182+
break
2183+
}
2184+
}
2185+
2186+
let kind = match kind {
2187+
Some(kind) => kind,
2188+
None => {
2189+
this.tcx().sess.span_err(b.path.span,
2190+
"unboxed function trait must be one \
2191+
of `Fn`, `FnMut`, or `FnOnce`");
2192+
ast::FnMutUnboxedClosureKind
2193+
}
2194+
};
2195+
2196+
let rscope = ExplicitRscope;
2197+
let param_ty = param_ty.to_ty(this.tcx());
2198+
Rc::new(astconv::trait_ref_for_unboxed_function(this,
2199+
&rscope,
2200+
kind,
2201+
&*b.decl,
2202+
Some(param_ty)))
2203+
});
2204+
21712205
let trait_bounds: Vec<Rc<ty::TraitRef>> =
21722206
trait_bounds.into_iter()
21732207
.map(|b| {

src/libsyntax/ast.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -213,12 +213,19 @@ pub static DUMMY_NODE_ID: NodeId = -1;
213213
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
214214
pub enum TyParamBound {
215215
TraitTyParamBound(TraitRef),
216-
UnboxedFnTyParamBound(UnboxedFnTy),
216+
UnboxedFnTyParamBound(P<UnboxedFnBound>),
217217
RegionTyParamBound(Lifetime)
218218
}
219219

220220
pub type TyParamBounds = OwnedSlice<TyParamBound>;
221221

222+
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
223+
pub struct UnboxedFnBound {
224+
pub path: Path,
225+
pub decl: P<FnDecl>,
226+
pub ref_id: NodeId,
227+
}
228+
222229
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
223230
pub struct TyParam {
224231
pub ident: Ident,

src/libsyntax/fold.rs

+17-7
Original file line numberDiff line numberDiff line change
@@ -657,16 +657,26 @@ pub fn noop_fold_fn_decl<T: Folder>(decl: P<FnDecl>, fld: &mut T) -> P<FnDecl> {
657657
})
658658
}
659659

660-
pub fn noop_fold_ty_param_bound<T: Folder>(tpb: TyParamBound, fld: &mut T)
661-
-> TyParamBound {
660+
pub fn noop_fold_ty_param_bound<T>(tpb: TyParamBound, fld: &mut T)
661+
-> TyParamBound
662+
where T: Folder {
662663
match tpb {
663664
TraitTyParamBound(ty) => TraitTyParamBound(fld.fold_trait_ref(ty)),
664665
RegionTyParamBound(lifetime) => RegionTyParamBound(fld.fold_lifetime(lifetime)),
665-
UnboxedFnTyParamBound(UnboxedFnTy {decl, kind}) => {
666-
UnboxedFnTyParamBound(UnboxedFnTy {
667-
decl: fld.fold_fn_decl(decl),
668-
kind: kind,
669-
})
666+
UnboxedFnTyParamBound(bound) => {
667+
match *bound {
668+
UnboxedFnBound {
669+
ref path,
670+
ref decl,
671+
ref_id
672+
} => {
673+
UnboxedFnTyParamBound(P(UnboxedFnBound {
674+
path: fld.fold_path(path.clone()),
675+
decl: fld.fold_fn_decl(decl.clone()),
676+
ref_id: fld.new_id(ref_id),
677+
}))
678+
}
679+
}
670680
}
671681
}
672682
}

src/libsyntax/parse/parser.rs

+27-49
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ use ast::{TyTypeof, TyInfer, TypeMethod};
5555
use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyPtr, TyQPath};
5656
use ast::{TyRptr, TyTup, TyU32, TyUnboxedFn, TyUniq, TyVec, UnUniq};
5757
use ast::{TypeImplItem, TypeTraitItem, Typedef, UnboxedClosureKind};
58-
use ast::{UnboxedFnTy, UnboxedFnTyParamBound, UnnamedField, UnsafeBlock};
58+
use ast::{UnboxedFnBound, UnboxedFnTy, UnboxedFnTyParamBound};
59+
use ast::{UnnamedField, UnsafeBlock};
5960
use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse};
6061
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
6162
use ast::{Visibility, WhereClause, WherePredicate};
@@ -3666,39 +3667,6 @@ impl<'a> Parser<'a> {
36663667
})
36673668
}
36683669

3669-
fn parse_unboxed_function_type(&mut self) -> UnboxedFnTy {
3670-
let (optional_unboxed_closure_kind, inputs) =
3671-
if self.eat(&token::OROR) {
3672-
(None, Vec::new())
3673-
} else {
3674-
self.expect_or();
3675-
3676-
let optional_unboxed_closure_kind =
3677-
self.parse_optional_unboxed_closure_kind();
3678-
3679-
let inputs = self.parse_seq_to_before_or(&token::COMMA,
3680-
|p| {
3681-
p.parse_arg_general(false)
3682-
});
3683-
self.expect_or();
3684-
(optional_unboxed_closure_kind, inputs)
3685-
};
3686-
3687-
let (return_style, output) = self.parse_ret_ty();
3688-
UnboxedFnTy {
3689-
decl: P(FnDecl {
3690-
inputs: inputs,
3691-
output: output,
3692-
cf: return_style,
3693-
variadic: false,
3694-
}),
3695-
kind: match optional_unboxed_closure_kind {
3696-
Some(kind) => kind,
3697-
None => FnMutUnboxedClosureKind,
3698-
},
3699-
}
3700-
}
3701-
37023670
// Parses a sequence of bounds if a `:` is found,
37033671
// otherwise returns empty list.
37043672
fn parse_colon_then_ty_param_bounds(&mut self)
@@ -3730,13 +3698,31 @@ impl<'a> Parser<'a> {
37303698
self.bump();
37313699
}
37323700
token::MOD_SEP | token::IDENT(..) => {
3733-
let tref = self.parse_trait_ref();
3734-
result.push(TraitTyParamBound(tref));
3735-
}
3736-
token::BINOP(token::OR) | token::OROR => {
3737-
let unboxed_function_type =
3738-
self.parse_unboxed_function_type();
3739-
result.push(UnboxedFnTyParamBound(unboxed_function_type));
3701+
let path =
3702+
self.parse_path(LifetimeAndTypesWithoutColons).path;
3703+
if self.token == token::LPAREN {
3704+
self.bump();
3705+
let inputs = self.parse_seq_to_end(
3706+
&token::RPAREN,
3707+
seq_sep_trailing_allowed(token::COMMA),
3708+
|p| p.parse_arg_general(false));
3709+
let (return_style, output) = self.parse_ret_ty();
3710+
result.push(UnboxedFnTyParamBound(P(UnboxedFnBound {
3711+
path: path,
3712+
decl: P(FnDecl {
3713+
inputs: inputs,
3714+
output: output,
3715+
cf: return_style,
3716+
variadic: false,
3717+
}),
3718+
ref_id: ast::DUMMY_NODE_ID,
3719+
})));
3720+
} else {
3721+
result.push(TraitTyParamBound(ast::TraitRef {
3722+
path: path,
3723+
ref_id: ast::DUMMY_NODE_ID,
3724+
}))
3725+
}
37403726
}
37413727
_ => break,
37423728
}
@@ -4423,14 +4409,6 @@ impl<'a> Parser<'a> {
44234409
Some(attrs))
44244410
}
44254411

4426-
/// Parse a::B<String,int>
4427-
fn parse_trait_ref(&mut self) -> TraitRef {
4428-
ast::TraitRef {
4429-
path: self.parse_path(LifetimeAndTypesWithoutColons).path,
4430-
ref_id: ast::DUMMY_NODE_ID,
4431-
}
4432-
}
4433-
44344412
/// Parse struct Foo { ... }
44354413
fn parse_item_struct(&mut self, is_virtual: bool) -> ItemInfo {
44364414
let class_name = self.parse_ident();

src/libsyntax/print/pprust.rs

+25-24
Original file line numberDiff line numberDiff line change
@@ -2190,16 +2190,13 @@ impl<'a> State<'a> {
21902190
self.print_lifetime(lt)
21912191
}
21922192
UnboxedFnTyParamBound(ref unboxed_function_type) => {
2193-
self.print_ty_fn(None,
2194-
None,
2195-
ast::NormalFn,
2196-
ast::Many,
2197-
&*unboxed_function_type.decl,
2198-
None,
2199-
&OwnedSlice::empty(),
2200-
None,
2201-
None,
2202-
Some(unboxed_function_type.kind))
2193+
try!(self.print_path(&unboxed_function_type.path,
2194+
false));
2195+
try!(self.popen());
2196+
try!(self.print_fn_args(&*unboxed_function_type.decl,
2197+
None));
2198+
try!(self.pclose());
2199+
self.print_fn_output(&*unboxed_function_type.decl)
22032200
}
22042201
})
22052202
}
@@ -2430,6 +2427,23 @@ impl<'a> State<'a> {
24302427
self.end()
24312428
}
24322429

2430+
pub fn print_fn_output(&mut self, decl: &ast::FnDecl) -> IoResult<()> {
2431+
match decl.output.node {
2432+
ast::TyNil => Ok(()),
2433+
_ => {
2434+
try!(self.space_if_not_bol());
2435+
try!(self.ibox(indent_unit));
2436+
try!(self.word_space("->"));
2437+
if decl.cf == ast::NoReturn {
2438+
try!(self.word_nbsp("!"));
2439+
} else {
2440+
try!(self.print_type(&*decl.output));
2441+
}
2442+
self.end()
2443+
}
2444+
}
2445+
}
2446+
24332447
pub fn print_ty_fn(&mut self,
24342448
opt_abi: Option<abi::Abi>,
24352449
opt_sigil: Option<char>,
@@ -2510,20 +2524,7 @@ impl<'a> State<'a> {
25102524

25112525
try!(self.maybe_print_comment(decl.output.span.lo));
25122526

2513-
match decl.output.node {
2514-
ast::TyNil => {}
2515-
_ => {
2516-
try!(self.space_if_not_bol());
2517-
try!(self.ibox(indent_unit));
2518-
try!(self.word_space("->"));
2519-
if decl.cf == ast::NoReturn {
2520-
try!(self.word_nbsp("!"));
2521-
} else {
2522-
try!(self.print_type(&*decl.output));
2523-
}
2524-
try!(self.end());
2525-
}
2526-
}
2527+
try!(self.print_fn_output(decl));
25272528

25282529
match generics {
25292530
Some(generics) => try!(self.print_where_clause(generics)),

0 commit comments

Comments
 (0)