Skip to content

Commit cf8341f

Browse files
committed
auto merge of #6457 : nikomatsakis/rust/issue-6308-closure-bounds, r=brson
Add BuiltinBounds to closure type: parse and handle subtyping, but do not integrate with kindck etc (requires a snapshot first) r? @brson
2 parents 53196bb + 035c01a commit cf8341f

File tree

19 files changed

+261
-61
lines changed

19 files changed

+261
-61
lines changed

src/librustc/metadata/tydecode.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -470,12 +470,14 @@ fn parse_closure_ty(st: @mut PState, conv: conv_did) -> ty::ClosureTy {
470470
let purity = parse_purity(next(st));
471471
let onceness = parse_onceness(next(st));
472472
let region = parse_region(st);
473+
let bounds = parse_bounds(st, conv);
473474
let sig = parse_sig(st, conv);
474475
ty::ClosureTy {
475476
purity: purity,
476477
sigil: sigil,
477478
onceness: onceness,
478479
region: region,
480+
bounds: bounds.builtin_bounds,
479481
sig: sig
480482
}
481483
}
@@ -540,10 +542,10 @@ pub fn parse_type_param_def_data(data: @~[u8], start: uint,
540542

541543
fn parse_type_param_def(st: @mut PState, conv: conv_did) -> ty::TypeParameterDef {
542544
ty::TypeParameterDef {def_id: parse_def(st, NominalType, conv),
543-
bounds: parse_bounds(st, conv)}
545+
bounds: @parse_bounds(st, conv)}
544546
}
545547

546-
fn parse_bounds(st: @mut PState, conv: conv_did) -> @ty::ParamBounds {
548+
fn parse_bounds(st: @mut PState, conv: conv_did) -> ty::ParamBounds {
547549
let mut param_bounds = ty::ParamBounds {
548550
builtin_bounds: ty::EmptyBuiltinBounds(),
549551
trait_bounds: ~[]
@@ -566,7 +568,7 @@ fn parse_bounds(st: @mut PState, conv: conv_did) -> @ty::ParamBounds {
566568
param_bounds.trait_bounds.push(@parse_trait_ref(st, conv));
567569
}
568570
'.' => {
569-
return @param_bounds;
571+
return param_bounds;
570572
}
571573
_ => {
572574
fail!("parse_bounds: bad bounds")

src/librustc/metadata/tyencode.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,9 @@ fn enc_closure_ty(w: @io::Writer, cx: @ctxt, ft: &ty::ClosureTy) {
380380
enc_purity(w, ft.purity);
381381
enc_onceness(w, ft.onceness);
382382
enc_region(w, cx, ft.region);
383+
let bounds = ty::ParamBounds {builtin_bounds: ft.bounds,
384+
trait_bounds: ~[]};
385+
enc_bounds(w, cx, &bounds);
383386
enc_fn_sig(w, cx, &ft.sig);
384387
}
385388

@@ -392,7 +395,7 @@ fn enc_fn_sig(w: @io::Writer, cx: @ctxt, fsig: &ty::FnSig) {
392395
enc_ty(w, cx, fsig.output);
393396
}
394397

395-
fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: @ty::ParamBounds) {
398+
fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: &ty::ParamBounds) {
396399
for bs.builtin_bounds.each |bound| {
397400
match bound {
398401
ty::BoundOwned => w.write_char('S'),

src/librustc/middle/resolve.rs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use middle::lint::{allow, level, unused_imports};
2020
use middle::lint::{get_lint_level, get_lint_settings_level};
2121
use middle::pat_util::pat_bindings;
2222

23+
use syntax::ast::{TyParamBound, ty_closure};
2324
use syntax::ast::{RegionTyParamBound, TraitTyParamBound, _mod, add, arm};
2425
use syntax::ast::{binding_mode, bitand, bitor, bitxor, blk};
2526
use syntax::ast::{bind_infer, bind_by_ref, bind_by_copy};
@@ -3732,14 +3733,20 @@ pub impl Resolver {
37323733
type_parameters: &OptVec<TyParam>,
37333734
visitor: ResolveVisitor) {
37343735
for type_parameters.each |type_parameter| {
3735-
for type_parameter.bounds.each |&bound| {
3736-
match bound {
3737-
TraitTyParamBound(tref) => {
3738-
self.resolve_trait_reference(tref, visitor)
3739-
}
3740-
RegionTyParamBound => {}
3741-
}
3736+
for type_parameter.bounds.each |bound| {
3737+
self.resolve_type_parameter_bound(bound, visitor);
3738+
}
3739+
}
3740+
}
3741+
3742+
fn resolve_type_parameter_bound(@mut self,
3743+
type_parameter_bound: &TyParamBound,
3744+
visitor: ResolveVisitor) {
3745+
match *type_parameter_bound {
3746+
TraitTyParamBound(tref) => {
3747+
self.resolve_trait_reference(tref, visitor)
37423748
}
3749+
RegionTyParamBound => {}
37433750
}
37443751
}
37453752

@@ -4070,6 +4077,13 @@ pub impl Resolver {
40704077
}
40714078
}
40724079

4080+
ty_closure(c) => {
4081+
for c.bounds.each |bound| {
4082+
self.resolve_type_parameter_bound(bound, visitor);
4083+
}
4084+
visit_ty(ty, (), visitor);
4085+
}
4086+
40734087
_ => {
40744088
// Just resolve embedded types.
40754089
visit_ty(ty, (), visitor);

src/librustc/middle/trans/foreign.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -818,6 +818,7 @@ pub fn trans_intrinsic(ccx: @CrateContext,
818818
sigil: ast::BorrowedSigil,
819819
onceness: ast::Many,
820820
region: ty::re_bound(ty::br_anon(0)),
821+
bounds: ty::EmptyBuiltinBounds(),
821822
sig: FnSig {
822823
bound_lifetime_names: opt_vec::Empty,
823824
inputs: ~[ star_u8 ],

src/librustc/middle/trans/monomorphize.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ pub fn normalize_for_monomorphization(tcx: ty::ctxt,
330330
sigil: sigil,
331331
onceness: ast::Many,
332332
region: ty::re_static,
333+
bounds: ty::EmptyBuiltinBounds(),
333334
sig: ty::FnSig {bound_lifetime_names: opt_vec::Empty,
334335
inputs: ~[],
335336
output: ty::mk_nil()}})

src/librustc/middle/ty.rs

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use middle::typeck;
2222
use middle;
2323
use util::ppaux::{note_and_explain_region, bound_region_to_str};
2424
use util::ppaux::{trait_store_to_str, ty_to_str, vstore_to_str};
25-
use util::ppaux::Repr;
25+
use util::ppaux::{Repr, UserString};
2626
use util::common::{indenter};
2727
use util::enum_set::{EnumSet, CLike};
2828

@@ -390,7 +390,8 @@ pub struct ClosureTy {
390390
sigil: ast::Sigil,
391391
onceness: ast::Onceness,
392392
region: Region,
393-
sig: FnSig
393+
bounds: BuiltinBounds,
394+
sig: FnSig,
394395
}
395396

396397
/**
@@ -685,6 +686,7 @@ pub enum type_err {
685686
terr_int_mismatch(expected_found<IntVarValue>),
686687
terr_float_mismatch(expected_found<ast::float_ty>),
687688
terr_traits(expected_found<ast::def_id>),
689+
terr_builtin_bounds(expected_found<BuiltinBounds>),
688690
}
689691

690692
#[deriving(Eq, IterBytes)]
@@ -707,6 +709,15 @@ pub fn EmptyBuiltinBounds() -> BuiltinBounds {
707709
EnumSet::empty()
708710
}
709711

712+
pub fn AllBuiltinBounds() -> BuiltinBounds {
713+
let mut set = EnumSet::empty();
714+
set.add(BoundCopy);
715+
set.add(BoundStatic);
716+
set.add(BoundOwned);
717+
set.add(BoundConst);
718+
set
719+
}
720+
710721
impl CLike for BuiltinBound {
711722
pub fn to_uint(&self) -> uint {
712723
*self as uint
@@ -3169,6 +3180,7 @@ pub fn adjust_ty(cx: ctxt,
31693180
sigil: s,
31703181
onceness: ast::Many,
31713182
region: r,
3183+
bounds: ty::AllBuiltinBounds(),
31723184
sig: copy b.sig})
31733185
}
31743186
ref b => {
@@ -3697,6 +3709,19 @@ pub fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str {
36973709
item_path_str(cx, values.expected),
36983710
item_path_str(cx, values.found))
36993711
}
3712+
terr_builtin_bounds(values) => {
3713+
if values.expected.is_empty() {
3714+
fmt!("expected no bounds but found `%s`",
3715+
values.found.user_string(cx))
3716+
} else if values.found.is_empty() {
3717+
fmt!("expected bounds `%s` but found no bounds",
3718+
values.expected.user_string(cx))
3719+
} else {
3720+
fmt!("expected bounds `%s` but found bounds `%s`",
3721+
values.expected.user_string(cx),
3722+
values.found.user_string(cx))
3723+
}
3724+
}
37003725
terr_self_substs => {
37013726
~"inconsistent self substitution" // XXX this is more of a bug
37023727
}

src/librustc/middle/typeck/astconv.rs

Lines changed: 76 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ use middle::ty;
5959
use middle::typeck::rscope::in_binding_rscope;
6060
use middle::typeck::rscope::{region_scope, RegionError};
6161
use middle::typeck::rscope::RegionParamNames;
62+
use middle::typeck::lookup_def_tcx;
6263

6364
use syntax::abi::AbiSet;
6465
use syntax::{ast, ast_util};
@@ -220,7 +221,6 @@ pub fn ast_path_to_trait_ref<AC:AstConv,RS:region_scope + Copy + 'static>(
220221
return trait_ref;
221222
}
222223

223-
224224
pub fn ast_path_to_ty<AC:AstConv,RS:region_scope + Copy + 'static>(
225225
this: &AC,
226226
rscope: &RS,
@@ -377,11 +377,13 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>(
377377
bf.abis, &bf.lifetimes, &bf.decl))
378378
}
379379
ast::ty_closure(ref f) => {
380+
let bounds = conv_builtin_bounds(this.tcx(), &f.bounds);
380381
let fn_decl = ty_of_closure(this,
381382
rscope,
382383
f.sigil,
383384
f.purity,
384385
f.onceness,
386+
bounds,
385387
f.region,
386388
&f.decl,
387389
None,
@@ -646,17 +648,18 @@ fn ty_of_method_or_bare_fn<AC:AstConv,RS:region_scope + Copy + 'static>(
646648
}
647649

648650
pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + 'static>(
649-
this: &AC,
650-
rscope: &RS,
651-
sigil: ast::Sigil,
652-
purity: ast::purity,
653-
onceness: ast::Onceness,
654-
opt_lifetime: Option<@ast::Lifetime>,
655-
decl: &ast::fn_decl,
656-
expected_sig: Option<ty::FnSig>,
657-
lifetimes: &OptVec<ast::Lifetime>,
658-
span: span)
659-
-> ty::ClosureTy
651+
this: &AC,
652+
rscope: &RS,
653+
sigil: ast::Sigil,
654+
purity: ast::purity,
655+
onceness: ast::Onceness,
656+
bounds: ty::BuiltinBounds,
657+
opt_lifetime: Option<@ast::Lifetime>,
658+
decl: &ast::fn_decl,
659+
expected_sig: Option<ty::FnSig>,
660+
lifetimes: &OptVec<ast::Lifetime>,
661+
span: span)
662+
-> ty::ClosureTy
660663
{
661664
// The caller should not both provide explicit bound lifetime
662665
// names and expected types. Either we infer the bound lifetime
@@ -713,8 +716,69 @@ pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + 'static>(
713716
sigil: sigil,
714717
onceness: onceness,
715718
region: bound_region,
719+
bounds: bounds,
716720
sig: ty::FnSig {bound_lifetime_names: bound_lifetime_names,
717721
inputs: input_tys,
718722
output: output_ty}
719723
}
720724
}
725+
726+
fn conv_builtin_bounds(tcx: ty::ctxt,
727+
ast_bounds: &OptVec<ast::TyParamBound>)
728+
-> ty::BuiltinBounds {
729+
//! Converts a list of bounds from the AST into a `BuiltinBounds`
730+
//! struct. Reports an error if any of the bounds that appear
731+
//! in the AST refer to general traits and not the built-in traits
732+
//! like `Copy` or `Owned`. Used to translate the bounds that
733+
//! appear in closure and trait types, where only builtin bounds are
734+
//! legal.
735+
736+
let mut builtin_bounds = ty::EmptyBuiltinBounds();
737+
for ast_bounds.each |ast_bound| {
738+
match *ast_bound {
739+
ast::TraitTyParamBound(b) => {
740+
match lookup_def_tcx(tcx, b.path.span, b.ref_id) {
741+
ast::def_trait(trait_did) => {
742+
if try_add_builtin_trait(tcx,
743+
trait_did,
744+
&mut builtin_bounds) {
745+
loop; // success
746+
}
747+
}
748+
_ => { }
749+
}
750+
tcx.sess.span_fatal(
751+
b.path.span,
752+
fmt!("only the builtin traits can be used \
753+
as closure or object bounds"));
754+
}
755+
ast::RegionTyParamBound => {
756+
builtin_bounds.add(ty::BoundStatic);
757+
}
758+
}
759+
}
760+
builtin_bounds
761+
}
762+
763+
pub fn try_add_builtin_trait(tcx: ty::ctxt,
764+
trait_def_id: ast::def_id,
765+
builtin_bounds: &mut ty::BuiltinBounds) -> bool {
766+
//! Checks whether `trait_ref` refers to one of the builtin
767+
//! traits, like `Copy` or `Owned`, and adds the corresponding
768+
//! bound to the set `builtin_bounds` if so. Returns true if `trait_ref`
769+
//! is a builtin trait.
770+
771+
let li = &tcx.lang_items;
772+
if trait_def_id == li.owned_trait() {
773+
builtin_bounds.add(ty::BoundOwned);
774+
true
775+
} else if trait_def_id == li.copy_trait() {
776+
builtin_bounds.add(ty::BoundCopy);
777+
true
778+
} else if trait_def_id == li.const_trait() {
779+
builtin_bounds.add(ty::BoundConst);
780+
true
781+
} else {
782+
false
783+
}
784+
}

src/librustc/middle/typeck/check/mod.rs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1661,19 +1661,22 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
16611661
let (expected_sig,
16621662
expected_purity,
16631663
expected_sigil,
1664-
expected_onceness) = {
1664+
expected_onceness,
1665+
expected_bounds) = {
16651666
match expected_sty {
16661667
Some(ty::ty_closure(ref cenv)) => {
16671668
let id = expr.id;
16681669
let (_, _, sig) =
16691670
replace_bound_regions_in_fn_sig(
16701671
tcx, @Nil, None, &cenv.sig,
16711672
|br| ty::re_bound(ty::br_cap_avoid(id, @br)));
1672-
(Some(sig), cenv.purity, cenv.sigil, cenv.onceness)
1673+
(Some(sig), cenv.purity, cenv.sigil,
1674+
cenv.onceness, cenv.bounds)
16731675
}
16741676
_ => {
16751677
// Not an error! Means we're inferring the closure type
1676-
(None, ast::impure_fn, ast::BorrowedSigil, ast::Many)
1678+
(None, ast::impure_fn, ast::BorrowedSigil,
1679+
ast::Many, ty::EmptyBuiltinBounds())
16771680
}
16781681
}
16791682
};
@@ -1687,15 +1690,16 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
16871690

16881691
// construct the function type
16891692
let fn_ty = astconv::ty_of_closure(fcx,
1690-
fcx,
1691-
sigil,
1692-
purity,
1693-
expected_onceness,
1694-
None,
1695-
decl,
1696-
expected_sig,
1697-
&opt_vec::Empty,
1698-
expr.span);
1693+
fcx,
1694+
sigil,
1695+
purity,
1696+
expected_onceness,
1697+
expected_bounds,
1698+
None,
1699+
decl,
1700+
expected_sig,
1701+
&opt_vec::Empty,
1702+
expr.span);
16991703

17001704
let fty_sig;
17011705
let fty = if error_happened {
@@ -3526,6 +3530,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) {
35263530
sigil: ast::BorrowedSigil,
35273531
onceness: ast::Once,
35283532
region: ty::re_bound(ty::br_anon(0)),
3533+
bounds: ty::EmptyBuiltinBounds(),
35293534
sig: ty::FnSig {
35303535
bound_lifetime_names: opt_vec::Empty,
35313536
inputs: ~[ty::mk_imm_ptr(ccx.tcx, ty::mk_mach_uint(ast::ty_u8))],

0 commit comments

Comments
 (0)