Skip to content

librustc: Implement sugar for the FnMut trait #14606

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 10, 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
6 changes: 6 additions & 0 deletions src/librustc/front/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
("linkage", Active),
("struct_inherit", Active),
("overloaded_calls", Active),
("unboxed_closure_sugar", Active),

("quad_precision_float", Active),

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

},
ast::TyBox(_) => { self.gate_box(t.span); }
ast::TyUnboxedFn(_) => {
self.gate_feature("unboxed_closure_sugar",
t.span,
"unboxed closure trait sugar is experimental");
}
_ => {}
}

Expand Down
14 changes: 10 additions & 4 deletions src/librustc/middle/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3856,14 +3856,20 @@ impl<'a> Resolver<'a> {
}

fn resolve_type_parameter_bound(&mut self,
id: NodeId,
type_parameter_bound: &TyParamBound) {
id: NodeId,
type_parameter_bound: &TyParamBound) {
match *type_parameter_bound {
TraitTyParamBound(ref tref) => {
self.resolve_trait_reference(id, tref, TraitBoundingTypeParameter)
}
StaticRegionTyParamBound => {}
OtherRegionTyParamBound(_) => {}
UnboxedFnTyParamBound(ref unboxed_function) => {
for argument in unboxed_function.decl.inputs.iter() {
self.resolve_type(argument.ty);
}

self.resolve_type(unboxed_function.decl.output);
}
StaticRegionTyParamBound | OtherRegionTyParamBound(_) => {}
}
}

Expand Down
96 changes: 88 additions & 8 deletions src/librustc/middle/typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,14 @@

use middle::const_eval;
use middle::def;
use middle::subst;
use middle::lang_items::FnMutTraitLangItem;
use middle::subst::{Subst, Substs};
use middle::ty::{ty_param_substs_and_ty};
use middle::subst;
use middle::ty::ty_param_substs_and_ty;
use middle::ty;
use middle::typeck::rscope;
use middle::typeck::rscope::{RegionScope};
use middle::typeck::lookup_def_tcx;
use middle::typeck::rscope::RegionScope;
use middle::typeck::rscope;
use util::ppaux::Repr;

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

pub fn trait_ref_for_unboxed_function<AC:AstConv,
RS:RegionScope>(
this: &AC,
rscope: &RS,
unboxed_function: &ast::UnboxedFnTy)
-> ty::TraitRef {
let fn_mut_trait_did = this.tcx()
.lang_items
.require(FnMutTraitLangItem)
.unwrap();
let input_types =
unboxed_function.decl
.inputs
.iter()
.map(|input| {
ast_ty_to_ty(this, rscope, input.ty)
}).collect::<Vec<_>>();
let input_tuple = ty::mk_tup(this.tcx(), input_types);
let output_type = ast_ty_to_ty(this,
rscope,
unboxed_function.decl.output);
let substs = subst::Substs {
self_ty: None,
tps: vec!(input_tuple, output_type),
regions: subst::NonerasedRegions(Vec::new()),
};
ty::TraitRef {
def_id: fn_mut_trait_did,
substs: substs,
}
}

// Handle `~`, `Box`, and `&` being able to mean strs and vecs.
// If a_seq_ty is a str or a vec, make it a str/vec.
// Also handle first-class trait types.
Expand All @@ -491,6 +524,32 @@ fn mk_pointer<AC:AstConv,
}
return constr(ty::mk_vec(tcx, mt, None));
}
ast::TyUnboxedFn(ref unboxed_function) => {
let trait_store = match ptr_ty {
Uniq => ty::UniqTraitStore,
RPtr(r) => {
ty::RegionTraitStore(r, a_seq_ty.mutbl)
}
_ => {
tcx.sess.span_err(
a_seq_ty.ty.span,
"~trait or &trait are the only supported \
forms of casting-to-trait");
return ty::mk_err();
}
};
let ty::TraitRef {
def_id,
substs
} = trait_ref_for_unboxed_function(this,
rscope,
*unboxed_function);
return ty::mk_trait(this.tcx(),
def_id,
substs,
trait_store,
ty::empty_builtin_bounds());
}
ast::TyPath(ref path, ref bounds, id) => {
// Note that the "bounds must be empty if path is not a trait"
// restriction is enforced in the below case for ty_path, which
Expand Down Expand Up @@ -528,7 +587,10 @@ fn mk_pointer<AC:AstConv,
return ty::mk_err();
}
};
let bounds = conv_builtin_bounds(this.tcx(), bounds, trait_store);
let bounds = conv_builtin_bounds(this.tcx(),
path.span,
bounds,
trait_store);
return ty::mk_trait(tcx,
result.def_id,
result.substs.clone(),
Expand Down Expand Up @@ -621,7 +683,10 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(

// Use corresponding trait store to figure out default bounds
// if none were specified.
let bounds = conv_builtin_bounds(this.tcx(), &f.bounds, store);
let bounds = conv_builtin_bounds(this.tcx(),
ast_ty.span,
&f.bounds,
store);

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

let fn_decl = ty_of_closure(this,
ast_ty.id,
Expand All @@ -648,6 +716,11 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
None);
ty::mk_closure(tcx, fn_decl)
}
ast::TyUnboxedFn(_) => {
tcx.sess.span_err(ast_ty.span,
"cannot use unboxed functions here");
ty::mk_err()
}
ast::TyPath(ref path, ref bounds, id) => {
let a_def = match tcx.def_map.borrow().find(&id) {
None => {
Expand Down Expand Up @@ -891,7 +964,9 @@ pub fn ty_of_closure<AC:AstConv>(
}
}

fn conv_builtin_bounds(tcx: &ty::ctxt, ast_bounds: &Option<OwnedSlice<ast::TyParamBound>>,
fn conv_builtin_bounds(tcx: &ty::ctxt,
span: Span,
ast_bounds: &Option<OwnedSlice<ast::TyParamBound>>,
store: ty::TraitStore)
-> ty::BuiltinBounds {
//! Converts a list of bounds from the AST into a `BuiltinBounds`
Expand Down Expand Up @@ -928,6 +1003,11 @@ fn conv_builtin_bounds(tcx: &ty::ctxt, ast_bounds: &Option<OwnedSlice<ast::TyPar
ast::StaticRegionTyParamBound => {
builtin_bounds.add(ty::BoundStatic);
}
ast::UnboxedFnTyParamBound(_) => {
tcx.sess.span_err(span,
"unboxed functions are not allowed \
here");
}
ast::OtherRegionTyParamBound(span) => {
if !tcx.sess.features.issue_5723_bootstrap.get() {
tcx.sess.span_err(
Expand Down
23 changes: 18 additions & 5 deletions src/librustc/middle/typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,22 +48,21 @@ use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx};
use util::ppaux;
use util::ppaux::Repr;

use std::rc::Rc;
use std::collections::{HashMap, HashSet};

use std::rc::Rc;
use syntax::abi;
use syntax::ast::{StaticRegionTyParamBound, OtherRegionTyParamBound,
TraitTyParamBound};
use syntax::ast::{StaticRegionTyParamBound, OtherRegionTyParamBound};
use syntax::ast::{TraitTyParamBound, UnboxedFnTyParamBound};
use syntax::ast;
use syntax::ast_map;
use syntax::ast_util::{local_def, split_trait_methods};
use syntax::codemap::Span;
use syntax::codemap;
use syntax::owned_slice::OwnedSlice;
use syntax::parse::token::special_idents;
use syntax::parse::token;
use syntax::print::pprust::{path_to_str};
use syntax::visit;
use syntax::owned_slice::OwnedSlice;

struct CollectItemTypesVisitor<'a> {
ccx: &'a CrateCtxt<'a>
Expand Down Expand Up @@ -1114,6 +1113,20 @@ fn ty_generics(ccx: &CrateCtxt,
param_bounds.builtin_bounds.add(ty::BoundStatic);
}

UnboxedFnTyParamBound(ref unboxed_function) => {
let rscope = ExplicitRscope;
let mut trait_ref =
astconv::trait_ref_for_unboxed_function(
ccx,
&rscope,
unboxed_function);
let self_ty = ty::mk_param(ccx.tcx,
param_ty.idx,
param_ty.def_id);
trait_ref.substs.self_ty = Some(self_ty);
param_bounds.trait_bounds.push(Rc::new(trait_ref));
}

OtherRegionTyParamBound(span) => {
if !ccx.tcx.sess.features.issue_5723_bootstrap.get() {
ccx.tcx.sess.span_err(
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/middle/typeck/infer/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,9 @@ impl<'a> Rebuilder<'a> {
match tpb {
&ast::StaticRegionTyParamBound => ast::StaticRegionTyParamBound,
&ast::OtherRegionTyParamBound(s) => ast::OtherRegionTyParamBound(s),
&ast::UnboxedFnTyParamBound(unboxed_function_type) => {
ast::UnboxedFnTyParamBound(unboxed_function_type)
}
&ast::TraitTyParamBound(ref tr) => {
let last_seg = tr.path.segments.last().unwrap();
let mut insert = Vec::new();
Expand Down
4 changes: 4 additions & 0 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,10 @@ impl Clean<TyParamBound> for ast::TyParamBound {
match *self {
ast::StaticRegionTyParamBound => RegionBound,
ast::OtherRegionTyParamBound(_) => RegionBound,
ast::UnboxedFnTyParamBound(_) => {
// FIXME(pcwalton): Wrong.
RegionBound
}
ast::TraitTyParamBound(ref t) => TraitBound(t.clean()),
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ pub static DUMMY_NODE_ID: NodeId = -1;
pub enum TyParamBound {
TraitTyParamBound(TraitRef),
StaticRegionTyParamBound,
UnboxedFnTyParamBound(UnboxedFnTy),
OtherRegionTyParamBound(Span) // FIXME -- just here until work for #5723 lands
}

Expand Down Expand Up @@ -769,6 +770,11 @@ pub struct BareFnTy {
pub decl: P<FnDecl>
}

#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)]
pub struct UnboxedFnTy {
pub decl: P<FnDecl>,
}

#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)]
pub enum Ty_ {
TyNil,
Expand All @@ -782,6 +788,7 @@ pub enum Ty_ {
TyClosure(@ClosureTy, Option<Lifetime>),
TyProc(@ClosureTy),
TyBareFn(@BareFnTy),
TyUnboxedFn(@UnboxedFnTy),
TyTup(Vec<P<Ty>> ),
TyPath(Path, Option<OwnedSlice<TyParamBound>>, NodeId), // for #7264; see above
TyTypeof(@Expr),
Expand Down
10 changes: 10 additions & 0 deletions src/libsyntax/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,11 @@ pub trait Folder {
decl: self.fold_fn_decl(f.decl)
})
}
TyUnboxedFn(ref f) => {
TyUnboxedFn(@UnboxedFnTy {
decl: self.fold_fn_decl(f.decl),
})
}
TyTup(ref tys) => TyTup(tys.iter().map(|&ty| self.fold_ty(ty)).collect()),
TyPath(ref path, ref bounds, id) => {
let id = self.new_id(id);
Expand Down Expand Up @@ -440,6 +445,11 @@ fn fold_ty_param_bound<T: Folder>(tpb: &TyParamBound, fld: &mut T)
match *tpb {
TraitTyParamBound(ref ty) => TraitTyParamBound(fold_trait_ref(ty, fld)),
StaticRegionTyParamBound => StaticRegionTyParamBound,
UnboxedFnTyParamBound(ref unboxed_function_type) => {
UnboxedFnTyParamBound(UnboxedFnTy {
decl: fld.fold_fn_decl(unboxed_function_type.decl),
})
}
OtherRegionTyParamBound(s) => OtherRegionTyParamBound(s)
}
}
Expand Down
Loading