Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

librustc: Implement the syntax in the RFC for unboxed closure sugar. #17041

Merged
merged 1 commit into from
Sep 20, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/librustc/middle/resolve.rs
Original file line number Diff line number Diff line change
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());
}
Copy link
Member

Choose a reason for hiding this comment

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

Could you also add tests for these two errors?

}
}
}

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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Copy link
Member

Choose a reason for hiding this comment

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

Can you add a test for this error?

}
};

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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Loading