Skip to content

Commit f02b6f3

Browse files
committed
librustc: Implement sugar for the FnMut trait
1 parent 907d961 commit f02b6f3

File tree

12 files changed

+343
-46
lines changed

12 files changed

+343
-46
lines changed

src/librustc/front/feature_gate.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
5757
("linkage", Active),
5858
("struct_inherit", Active),
5959
("overloaded_calls", Active),
60+
("unboxed_closure_sugar", Active),
6061

6162
("quad_precision_float", Active),
6263

@@ -291,6 +292,11 @@ impl<'a> Visitor<()> for Context<'a> {
291292

292293
},
293294
ast::TyBox(_) => { self.gate_box(t.span); }
295+
ast::TyUnboxedFn(_) => {
296+
self.gate_feature("unboxed_closure_sugar",
297+
t.span,
298+
"unboxed closure trait sugar is experimental");
299+
}
294300
_ => {}
295301
}
296302

src/librustc/middle/resolve.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3856,14 +3856,20 @@ impl<'a> Resolver<'a> {
38563856
}
38573857

38583858
fn resolve_type_parameter_bound(&mut self,
3859-
id: NodeId,
3860-
type_parameter_bound: &TyParamBound) {
3859+
id: NodeId,
3860+
type_parameter_bound: &TyParamBound) {
38613861
match *type_parameter_bound {
38623862
TraitTyParamBound(ref tref) => {
38633863
self.resolve_trait_reference(id, tref, TraitBoundingTypeParameter)
38643864
}
3865-
StaticRegionTyParamBound => {}
3866-
OtherRegionTyParamBound(_) => {}
3865+
UnboxedFnTyParamBound(ref unboxed_function) => {
3866+
for argument in unboxed_function.decl.inputs.iter() {
3867+
self.resolve_type(argument.ty);
3868+
}
3869+
3870+
self.resolve_type(unboxed_function.decl.output);
3871+
}
3872+
StaticRegionTyParamBound | OtherRegionTyParamBound(_) => {}
38673873
}
38683874
}
38693875

src/librustc/middle/typeck/astconv.rs

Lines changed: 88 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,14 @@
5151

5252
use middle::const_eval;
5353
use middle::def;
54-
use middle::subst;
54+
use middle::lang_items::FnMutTraitLangItem;
5555
use middle::subst::{Subst, Substs};
56-
use middle::ty::{ty_param_substs_and_ty};
56+
use middle::subst;
57+
use middle::ty::ty_param_substs_and_ty;
5758
use middle::ty;
58-
use middle::typeck::rscope;
59-
use middle::typeck::rscope::{RegionScope};
6059
use middle::typeck::lookup_def_tcx;
60+
use middle::typeck::rscope::RegionScope;
61+
use middle::typeck::rscope;
6162
use util::ppaux::Repr;
6263

6364
use std::rc::Rc;
@@ -469,6 +470,38 @@ fn ast_ty_to_mt<AC:AstConv, RS:RegionScope>(this: &AC,
469470
ty::mt {ty: ast_ty_to_ty(this, rscope, ty), mutbl: ast::MutImmutable}
470471
}
471472

473+
pub fn trait_ref_for_unboxed_function<AC:AstConv,
474+
RS:RegionScope>(
475+
this: &AC,
476+
rscope: &RS,
477+
unboxed_function: &ast::UnboxedFnTy)
478+
-> ty::TraitRef {
479+
let fn_mut_trait_did = this.tcx()
480+
.lang_items
481+
.require(FnMutTraitLangItem)
482+
.unwrap();
483+
let input_types =
484+
unboxed_function.decl
485+
.inputs
486+
.iter()
487+
.map(|input| {
488+
ast_ty_to_ty(this, rscope, input.ty)
489+
}).collect::<Vec<_>>();
490+
let input_tuple = ty::mk_tup(this.tcx(), input_types);
491+
let output_type = ast_ty_to_ty(this,
492+
rscope,
493+
unboxed_function.decl.output);
494+
let substs = subst::Substs {
495+
self_ty: None,
496+
tps: vec!(input_tuple, output_type),
497+
regions: subst::NonerasedRegions(Vec::new()),
498+
};
499+
ty::TraitRef {
500+
def_id: fn_mut_trait_did,
501+
substs: substs,
502+
}
503+
}
504+
472505
// Handle `~`, `Box`, and `&` being able to mean strs and vecs.
473506
// If a_seq_ty is a str or a vec, make it a str/vec.
474507
// Also handle first-class trait types.
@@ -491,6 +524,32 @@ fn mk_pointer<AC:AstConv,
491524
}
492525
return constr(ty::mk_vec(tcx, mt, None));
493526
}
527+
ast::TyUnboxedFn(ref unboxed_function) => {
528+
let trait_store = match ptr_ty {
529+
Uniq => ty::UniqTraitStore,
530+
RPtr(r) => {
531+
ty::RegionTraitStore(r, a_seq_ty.mutbl)
532+
}
533+
_ => {
534+
tcx.sess.span_err(
535+
a_seq_ty.ty.span,
536+
"~trait or &trait are the only supported \
537+
forms of casting-to-trait");
538+
return ty::mk_err();
539+
}
540+
};
541+
let ty::TraitRef {
542+
def_id,
543+
substs
544+
} = trait_ref_for_unboxed_function(this,
545+
rscope,
546+
*unboxed_function);
547+
return ty::mk_trait(this.tcx(),
548+
def_id,
549+
substs,
550+
trait_store,
551+
ty::empty_builtin_bounds());
552+
}
494553
ast::TyPath(ref path, ref bounds, id) => {
495554
// Note that the "bounds must be empty if path is not a trait"
496555
// restriction is enforced in the below case for ty_path, which
@@ -528,7 +587,10 @@ fn mk_pointer<AC:AstConv,
528587
return ty::mk_err();
529588
}
530589
};
531-
let bounds = conv_builtin_bounds(this.tcx(), bounds, trait_store);
590+
let bounds = conv_builtin_bounds(this.tcx(),
591+
path.span,
592+
bounds,
593+
trait_store);
532594
return ty::mk_trait(tcx,
533595
result.def_id,
534596
result.substs.clone(),
@@ -621,7 +683,10 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
621683

622684
// Use corresponding trait store to figure out default bounds
623685
// if none were specified.
624-
let bounds = conv_builtin_bounds(this.tcx(), &f.bounds, store);
686+
let bounds = conv_builtin_bounds(this.tcx(),
687+
ast_ty.span,
688+
&f.bounds,
689+
store);
625690

626691
let fn_decl = ty_of_closure(this,
627692
ast_ty.id,
@@ -636,7 +701,10 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
636701
ast::TyProc(ref f) => {
637702
// Use corresponding trait store to figure out default bounds
638703
// if none were specified.
639-
let bounds = conv_builtin_bounds(this.tcx(), &f.bounds, ty::UniqTraitStore);
704+
let bounds = conv_builtin_bounds(this.tcx(),
705+
ast_ty.span,
706+
&f.bounds,
707+
ty::UniqTraitStore);
640708

641709
let fn_decl = ty_of_closure(this,
642710
ast_ty.id,
@@ -648,6 +716,11 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
648716
None);
649717
ty::mk_closure(tcx, fn_decl)
650718
}
719+
ast::TyUnboxedFn(_) => {
720+
tcx.sess.span_err(ast_ty.span,
721+
"cannot use unboxed functions here");
722+
ty::mk_err()
723+
}
651724
ast::TyPath(ref path, ref bounds, id) => {
652725
let a_def = match tcx.def_map.borrow().find(&id) {
653726
None => {
@@ -891,7 +964,9 @@ pub fn ty_of_closure<AC:AstConv>(
891964
}
892965
}
893966

894-
fn conv_builtin_bounds(tcx: &ty::ctxt, ast_bounds: &Option<OwnedSlice<ast::TyParamBound>>,
967+
fn conv_builtin_bounds(tcx: &ty::ctxt,
968+
span: Span,
969+
ast_bounds: &Option<OwnedSlice<ast::TyParamBound>>,
895970
store: ty::TraitStore)
896971
-> ty::BuiltinBounds {
897972
//! Converts a list of bounds from the AST into a `BuiltinBounds`
@@ -928,6 +1003,11 @@ fn conv_builtin_bounds(tcx: &ty::ctxt, ast_bounds: &Option<OwnedSlice<ast::TyPar
9281003
ast::StaticRegionTyParamBound => {
9291004
builtin_bounds.add(ty::BoundStatic);
9301005
}
1006+
ast::UnboxedFnTyParamBound(_) => {
1007+
tcx.sess.span_err(span,
1008+
"unboxed functions are not allowed \
1009+
here");
1010+
}
9311011
ast::OtherRegionTyParamBound(span) => {
9321012
if !tcx.sess.features.issue_5723_bootstrap.get() {
9331013
tcx.sess.span_err(

src/librustc/middle/typeck/collect.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,22 +48,21 @@ use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx};
4848
use util::ppaux;
4949
use util::ppaux::Repr;
5050

51-
use std::rc::Rc;
5251
use std::collections::{HashMap, HashSet};
53-
52+
use std::rc::Rc;
5453
use syntax::abi;
55-
use syntax::ast::{StaticRegionTyParamBound, OtherRegionTyParamBound,
56-
TraitTyParamBound};
54+
use syntax::ast::{StaticRegionTyParamBound, OtherRegionTyParamBound};
55+
use syntax::ast::{TraitTyParamBound, UnboxedFnTyParamBound};
5756
use syntax::ast;
5857
use syntax::ast_map;
5958
use syntax::ast_util::{local_def, split_trait_methods};
6059
use syntax::codemap::Span;
6160
use syntax::codemap;
61+
use syntax::owned_slice::OwnedSlice;
6262
use syntax::parse::token::special_idents;
6363
use syntax::parse::token;
6464
use syntax::print::pprust::{path_to_str};
6565
use syntax::visit;
66-
use syntax::owned_slice::OwnedSlice;
6766

6867
struct CollectItemTypesVisitor<'a> {
6968
ccx: &'a CrateCtxt<'a>
@@ -1114,6 +1113,20 @@ fn ty_generics(ccx: &CrateCtxt,
11141113
param_bounds.builtin_bounds.add(ty::BoundStatic);
11151114
}
11161115

1116+
UnboxedFnTyParamBound(ref unboxed_function) => {
1117+
let rscope = ExplicitRscope;
1118+
let mut trait_ref =
1119+
astconv::trait_ref_for_unboxed_function(
1120+
ccx,
1121+
&rscope,
1122+
unboxed_function);
1123+
let self_ty = ty::mk_param(ccx.tcx,
1124+
param_ty.idx,
1125+
param_ty.def_id);
1126+
trait_ref.substs.self_ty = Some(self_ty);
1127+
param_bounds.trait_bounds.push(Rc::new(trait_ref));
1128+
}
1129+
11171130
OtherRegionTyParamBound(span) => {
11181131
if !ccx.tcx.sess.features.issue_5723_bootstrap.get() {
11191132
ccx.tcx.sess.span_err(

src/librustc/middle/typeck/infer/error_reporting.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,9 @@ impl<'a> Rebuilder<'a> {
909909
match tpb {
910910
&ast::StaticRegionTyParamBound => ast::StaticRegionTyParamBound,
911911
&ast::OtherRegionTyParamBound(s) => ast::OtherRegionTyParamBound(s),
912+
&ast::UnboxedFnTyParamBound(unboxed_function_type) => {
913+
ast::UnboxedFnTyParamBound(unboxed_function_type)
914+
}
912915
&ast::TraitTyParamBound(ref tr) => {
913916
let last_seg = tr.path.segments.last().unwrap();
914917
let mut insert = Vec::new();

src/librustdoc/clean/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,10 @@ impl Clean<TyParamBound> for ast::TyParamBound {
477477
match *self {
478478
ast::StaticRegionTyParamBound => RegionBound,
479479
ast::OtherRegionTyParamBound(_) => RegionBound,
480+
ast::UnboxedFnTyParamBound(_) => {
481+
// FIXME(pcwalton): Wrong.
482+
RegionBound
483+
}
480484
ast::TraitTyParamBound(ref t) => TraitBound(t.clean()),
481485
}
482486
}

src/libsyntax/ast.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ pub static DUMMY_NODE_ID: NodeId = -1;
175175
pub enum TyParamBound {
176176
TraitTyParamBound(TraitRef),
177177
StaticRegionTyParamBound,
178+
UnboxedFnTyParamBound(UnboxedFnTy),
178179
OtherRegionTyParamBound(Span) // FIXME -- just here until work for #5723 lands
179180
}
180181

@@ -769,6 +770,11 @@ pub struct BareFnTy {
769770
pub decl: P<FnDecl>
770771
}
771772

773+
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)]
774+
pub struct UnboxedFnTy {
775+
pub decl: P<FnDecl>,
776+
}
777+
772778
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)]
773779
pub enum Ty_ {
774780
TyNil,
@@ -782,6 +788,7 @@ pub enum Ty_ {
782788
TyClosure(@ClosureTy, Option<Lifetime>),
783789
TyProc(@ClosureTy),
784790
TyBareFn(@BareFnTy),
791+
TyUnboxedFn(@UnboxedFnTy),
785792
TyTup(Vec<P<Ty>> ),
786793
TyPath(Path, Option<OwnedSlice<TyParamBound>>, NodeId), // for #7264; see above
787794
TyTypeof(@Expr),

src/libsyntax/fold.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,11 @@ pub trait Folder {
185185
decl: self.fold_fn_decl(f.decl)
186186
})
187187
}
188+
TyUnboxedFn(ref f) => {
189+
TyUnboxedFn(@UnboxedFnTy {
190+
decl: self.fold_fn_decl(f.decl),
191+
})
192+
}
188193
TyTup(ref tys) => TyTup(tys.iter().map(|&ty| self.fold_ty(ty)).collect()),
189194
TyPath(ref path, ref bounds, id) => {
190195
let id = self.new_id(id);
@@ -440,6 +445,11 @@ fn fold_ty_param_bound<T: Folder>(tpb: &TyParamBound, fld: &mut T)
440445
match *tpb {
441446
TraitTyParamBound(ref ty) => TraitTyParamBound(fold_trait_ref(ty, fld)),
442447
StaticRegionTyParamBound => StaticRegionTyParamBound,
448+
UnboxedFnTyParamBound(ref unboxed_function_type) => {
449+
UnboxedFnTyParamBound(UnboxedFnTy {
450+
decl: fld.fold_fn_decl(unboxed_function_type.decl),
451+
})
452+
}
443453
OtherRegionTyParamBound(s) => OtherRegionTyParamBound(s)
444454
}
445455
}

0 commit comments

Comments
 (0)