Skip to content

Commit

Permalink
librustc: Implement the syntax in the RFC for unboxed closure sugar.
Browse files Browse the repository at this point in the history
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]
  • Loading branch information
pcwalton committed Sep 18, 2014
1 parent 9c41064 commit 7c00d77
Show file tree
Hide file tree
Showing 17 changed files with 207 additions and 117 deletions.
28 changes: 28 additions & 0 deletions src/librustc/middle/resolve.rs
Expand Up @@ -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);
}
Expand Down
28 changes: 13 additions & 15 deletions src/librustc/middle/typeck/astconv.rs
Expand Up @@ -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::t>)
-> 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::<Vec<_>>();
}).collect::<Vec<_>>();
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),
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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>,
}

Expand Down Expand Up @@ -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);
}
}
}
Expand Down
42 changes: 38 additions & 4 deletions src/librustc/middle/typeck/collect.rs
Expand Up @@ -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)))
}

Expand Down Expand Up @@ -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<Rc<ty::TraitRef>> =
trait_bounds.into_iter()
.map(|b| {
Expand Down
9 changes: 8 additions & 1 deletion src/libsyntax/ast.rs
Expand Up @@ -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<UnboxedFnBound>),
RegionTyParamBound(Lifetime)
}

pub type TyParamBounds = OwnedSlice<TyParamBound>;

#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub struct UnboxedFnBound {
pub path: Path,
pub decl: P<FnDecl>,
pub ref_id: NodeId,
}

#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub struct TyParam {
pub ident: Ident,
Expand Down
24 changes: 17 additions & 7 deletions src/libsyntax/fold.rs
Expand Up @@ -657,16 +657,26 @@ pub fn noop_fold_fn_decl<T: Folder>(decl: P<FnDecl>, fld: &mut T) -> P<FnDecl> {
})
}

pub fn noop_fold_ty_param_bound<T: Folder>(tpb: TyParamBound, fld: &mut T)
-> TyParamBound {
pub fn noop_fold_ty_param_bound<T>(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),
}))
}
}
}
}
}
Expand Down
76 changes: 27 additions & 49 deletions src/libsyntax/parse/parser.rs
Expand Up @@ -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};
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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,
}
Expand Down Expand Up @@ -4423,14 +4409,6 @@ impl<'a> Parser<'a> {
Some(attrs))
}

/// Parse a::B<String,int>
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();
Expand Down
49 changes: 25 additions & 24 deletions src/libsyntax/print/pprust.rs
Expand Up @@ -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)
}
})
}
Expand Down Expand Up @@ -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<abi::Abi>,
opt_sigil: Option<char>,
Expand Down Expand Up @@ -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)),
Expand Down

12 comments on commit 7c00d77

@bors
Copy link
Contributor

@bors bors commented on 7c00d77 Sep 19, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from alexcrichton
at pcwalton@7c00d77

@bors
Copy link
Contributor

@bors bors commented on 7c00d77 Sep 19, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging pcwalton/rust/right-unboxed-closure-sugar = 7c00d77 into auto

@bors
Copy link
Contributor

@bors bors commented on 7c00d77 Sep 19, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pcwalton/rust/right-unboxed-closure-sugar = 7c00d77 merged ok, testing candidate = e441fed4

@bors
Copy link
Contributor

@bors bors commented on 7c00d77 Sep 19, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from alexcrichton
at pcwalton@7c00d77

@bors
Copy link
Contributor

@bors bors commented on 7c00d77 Sep 19, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging pcwalton/rust/right-unboxed-closure-sugar = 7c00d77 into auto

@bors
Copy link
Contributor

@bors bors commented on 7c00d77 Sep 19, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pcwalton/rust/right-unboxed-closure-sugar = 7c00d77 merged ok, testing candidate = 08e17c87

@bors
Copy link
Contributor

@bors bors commented on 7c00d77 Sep 20, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from alexcrichton
at pcwalton@7c00d77

@bors
Copy link
Contributor

@bors bors commented on 7c00d77 Sep 20, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging pcwalton/rust/right-unboxed-closure-sugar = 7c00d77 into auto

@bors
Copy link
Contributor

@bors bors commented on 7c00d77 Sep 20, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pcwalton/rust/right-unboxed-closure-sugar = 7c00d77 merged ok, testing candidate = d4381e3c

@bors
Copy link
Contributor

@bors bors commented on 7c00d77 Sep 20, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bors
Copy link
Contributor

@bors bors commented on 7c00d77 Sep 20, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.