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
This commit is contained in:
commit
cf8341fc9e
@ -470,12 +470,14 @@ fn parse_closure_ty(st: @mut PState, conv: conv_did) -> ty::ClosureTy {
|
||||
let purity = parse_purity(next(st));
|
||||
let onceness = parse_onceness(next(st));
|
||||
let region = parse_region(st);
|
||||
let bounds = parse_bounds(st, conv);
|
||||
let sig = parse_sig(st, conv);
|
||||
ty::ClosureTy {
|
||||
purity: purity,
|
||||
sigil: sigil,
|
||||
onceness: onceness,
|
||||
region: region,
|
||||
bounds: bounds.builtin_bounds,
|
||||
sig: sig
|
||||
}
|
||||
}
|
||||
@ -540,10 +542,10 @@ pub fn parse_type_param_def_data(data: @~[u8], start: uint,
|
||||
|
||||
fn parse_type_param_def(st: @mut PState, conv: conv_did) -> ty::TypeParameterDef {
|
||||
ty::TypeParameterDef {def_id: parse_def(st, NominalType, conv),
|
||||
bounds: parse_bounds(st, conv)}
|
||||
bounds: @parse_bounds(st, conv)}
|
||||
}
|
||||
|
||||
fn parse_bounds(st: @mut PState, conv: conv_did) -> @ty::ParamBounds {
|
||||
fn parse_bounds(st: @mut PState, conv: conv_did) -> ty::ParamBounds {
|
||||
let mut param_bounds = ty::ParamBounds {
|
||||
builtin_bounds: ty::EmptyBuiltinBounds(),
|
||||
trait_bounds: ~[]
|
||||
@ -566,7 +568,7 @@ fn parse_bounds(st: @mut PState, conv: conv_did) -> @ty::ParamBounds {
|
||||
param_bounds.trait_bounds.push(@parse_trait_ref(st, conv));
|
||||
}
|
||||
'.' => {
|
||||
return @param_bounds;
|
||||
return param_bounds;
|
||||
}
|
||||
_ => {
|
||||
fail!("parse_bounds: bad bounds")
|
||||
|
@ -380,6 +380,9 @@ fn enc_closure_ty(w: @io::Writer, cx: @ctxt, ft: &ty::ClosureTy) {
|
||||
enc_purity(w, ft.purity);
|
||||
enc_onceness(w, ft.onceness);
|
||||
enc_region(w, cx, ft.region);
|
||||
let bounds = ty::ParamBounds {builtin_bounds: ft.bounds,
|
||||
trait_bounds: ~[]};
|
||||
enc_bounds(w, cx, &bounds);
|
||||
enc_fn_sig(w, cx, &ft.sig);
|
||||
}
|
||||
|
||||
@ -392,7 +395,7 @@ fn enc_fn_sig(w: @io::Writer, cx: @ctxt, fsig: &ty::FnSig) {
|
||||
enc_ty(w, cx, fsig.output);
|
||||
}
|
||||
|
||||
fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: @ty::ParamBounds) {
|
||||
fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: &ty::ParamBounds) {
|
||||
for bs.builtin_bounds.each |bound| {
|
||||
match bound {
|
||||
ty::BoundOwned => w.write_char('S'),
|
||||
|
@ -20,6 +20,7 @@
|
||||
use middle::lint::{get_lint_level, get_lint_settings_level};
|
||||
use middle::pat_util::pat_bindings;
|
||||
|
||||
use syntax::ast::{TyParamBound, ty_closure};
|
||||
use syntax::ast::{RegionTyParamBound, TraitTyParamBound, _mod, add, arm};
|
||||
use syntax::ast::{binding_mode, bitand, bitor, bitxor, blk};
|
||||
use syntax::ast::{bind_infer, bind_by_ref, bind_by_copy};
|
||||
@ -3732,17 +3733,23 @@ fn resolve_type_parameters(@mut self,
|
||||
type_parameters: &OptVec<TyParam>,
|
||||
visitor: ResolveVisitor) {
|
||||
for type_parameters.each |type_parameter| {
|
||||
for type_parameter.bounds.each |&bound| {
|
||||
match bound {
|
||||
TraitTyParamBound(tref) => {
|
||||
self.resolve_trait_reference(tref, visitor)
|
||||
}
|
||||
RegionTyParamBound => {}
|
||||
}
|
||||
for type_parameter.bounds.each |bound| {
|
||||
self.resolve_type_parameter_bound(bound, visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_type_parameter_bound(@mut self,
|
||||
type_parameter_bound: &TyParamBound,
|
||||
visitor: ResolveVisitor) {
|
||||
match *type_parameter_bound {
|
||||
TraitTyParamBound(tref) => {
|
||||
self.resolve_trait_reference(tref, visitor)
|
||||
}
|
||||
RegionTyParamBound => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_trait_reference(@mut self,
|
||||
trait_reference: &trait_ref,
|
||||
visitor: ResolveVisitor) {
|
||||
@ -4070,6 +4077,13 @@ fn resolve_type(@mut self, ty: @Ty, visitor: ResolveVisitor) {
|
||||
}
|
||||
}
|
||||
|
||||
ty_closure(c) => {
|
||||
for c.bounds.each |bound| {
|
||||
self.resolve_type_parameter_bound(bound, visitor);
|
||||
}
|
||||
visit_ty(ty, (), visitor);
|
||||
}
|
||||
|
||||
_ => {
|
||||
// Just resolve embedded types.
|
||||
visit_ty(ty, (), visitor);
|
||||
|
@ -818,6 +818,7 @@ pub fn trans_intrinsic(ccx: @CrateContext,
|
||||
sigil: ast::BorrowedSigil,
|
||||
onceness: ast::Many,
|
||||
region: ty::re_bound(ty::br_anon(0)),
|
||||
bounds: ty::EmptyBuiltinBounds(),
|
||||
sig: FnSig {
|
||||
bound_lifetime_names: opt_vec::Empty,
|
||||
inputs: ~[ star_u8 ],
|
||||
|
@ -330,6 +330,7 @@ fn normalized_closure_ty(tcx: ty::ctxt,
|
||||
sigil: sigil,
|
||||
onceness: ast::Many,
|
||||
region: ty::re_static,
|
||||
bounds: ty::EmptyBuiltinBounds(),
|
||||
sig: ty::FnSig {bound_lifetime_names: opt_vec::Empty,
|
||||
inputs: ~[],
|
||||
output: ty::mk_nil()}})
|
||||
|
@ -22,7 +22,7 @@
|
||||
use middle;
|
||||
use util::ppaux::{note_and_explain_region, bound_region_to_str};
|
||||
use util::ppaux::{trait_store_to_str, ty_to_str, vstore_to_str};
|
||||
use util::ppaux::Repr;
|
||||
use util::ppaux::{Repr, UserString};
|
||||
use util::common::{indenter};
|
||||
use util::enum_set::{EnumSet, CLike};
|
||||
|
||||
@ -390,7 +390,8 @@ pub struct ClosureTy {
|
||||
sigil: ast::Sigil,
|
||||
onceness: ast::Onceness,
|
||||
region: Region,
|
||||
sig: FnSig
|
||||
bounds: BuiltinBounds,
|
||||
sig: FnSig,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -685,6 +686,7 @@ pub enum type_err {
|
||||
terr_int_mismatch(expected_found<IntVarValue>),
|
||||
terr_float_mismatch(expected_found<ast::float_ty>),
|
||||
terr_traits(expected_found<ast::def_id>),
|
||||
terr_builtin_bounds(expected_found<BuiltinBounds>),
|
||||
}
|
||||
|
||||
#[deriving(Eq, IterBytes)]
|
||||
@ -707,6 +709,15 @@ pub fn EmptyBuiltinBounds() -> BuiltinBounds {
|
||||
EnumSet::empty()
|
||||
}
|
||||
|
||||
pub fn AllBuiltinBounds() -> BuiltinBounds {
|
||||
let mut set = EnumSet::empty();
|
||||
set.add(BoundCopy);
|
||||
set.add(BoundStatic);
|
||||
set.add(BoundOwned);
|
||||
set.add(BoundConst);
|
||||
set
|
||||
}
|
||||
|
||||
impl CLike for BuiltinBound {
|
||||
pub fn to_uint(&self) -> uint {
|
||||
*self as uint
|
||||
@ -3169,6 +3180,7 @@ pub fn adjust_ty(cx: ctxt,
|
||||
sigil: s,
|
||||
onceness: ast::Many,
|
||||
region: r,
|
||||
bounds: ty::AllBuiltinBounds(),
|
||||
sig: copy b.sig})
|
||||
}
|
||||
ref b => {
|
||||
@ -3697,6 +3709,19 @@ fn terr_vstore_kind_to_str(k: terr_vstore_kind) -> ~str {
|
||||
item_path_str(cx, values.expected),
|
||||
item_path_str(cx, values.found))
|
||||
}
|
||||
terr_builtin_bounds(values) => {
|
||||
if values.expected.is_empty() {
|
||||
fmt!("expected no bounds but found `%s`",
|
||||
values.found.user_string(cx))
|
||||
} else if values.found.is_empty() {
|
||||
fmt!("expected bounds `%s` but found no bounds",
|
||||
values.expected.user_string(cx))
|
||||
} else {
|
||||
fmt!("expected bounds `%s` but found bounds `%s`",
|
||||
values.expected.user_string(cx),
|
||||
values.found.user_string(cx))
|
||||
}
|
||||
}
|
||||
terr_self_substs => {
|
||||
~"inconsistent self substitution" // XXX this is more of a bug
|
||||
}
|
||||
|
@ -59,6 +59,7 @@
|
||||
use middle::typeck::rscope::in_binding_rscope;
|
||||
use middle::typeck::rscope::{region_scope, RegionError};
|
||||
use middle::typeck::rscope::RegionParamNames;
|
||||
use middle::typeck::lookup_def_tcx;
|
||||
|
||||
use syntax::abi::AbiSet;
|
||||
use syntax::{ast, ast_util};
|
||||
@ -220,7 +221,6 @@ pub fn ast_path_to_trait_ref<AC:AstConv,RS:region_scope + Copy + 'static>(
|
||||
return trait_ref;
|
||||
}
|
||||
|
||||
|
||||
pub fn ast_path_to_ty<AC:AstConv,RS:region_scope + Copy + 'static>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
@ -377,11 +377,13 @@ fn check_path_args(tcx: ty::ctxt,
|
||||
bf.abis, &bf.lifetimes, &bf.decl))
|
||||
}
|
||||
ast::ty_closure(ref f) => {
|
||||
let bounds = conv_builtin_bounds(this.tcx(), &f.bounds);
|
||||
let fn_decl = ty_of_closure(this,
|
||||
rscope,
|
||||
f.sigil,
|
||||
f.purity,
|
||||
f.onceness,
|
||||
bounds,
|
||||
f.region,
|
||||
&f.decl,
|
||||
None,
|
||||
@ -646,17 +648,18 @@ fn transform_self_ty<AC:AstConv,RS:region_scope + Copy + 'static>(
|
||||
}
|
||||
|
||||
pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + 'static>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
sigil: ast::Sigil,
|
||||
purity: ast::purity,
|
||||
onceness: ast::Onceness,
|
||||
opt_lifetime: Option<@ast::Lifetime>,
|
||||
decl: &ast::fn_decl,
|
||||
expected_sig: Option<ty::FnSig>,
|
||||
lifetimes: &OptVec<ast::Lifetime>,
|
||||
span: span)
|
||||
-> ty::ClosureTy
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
sigil: ast::Sigil,
|
||||
purity: ast::purity,
|
||||
onceness: ast::Onceness,
|
||||
bounds: ty::BuiltinBounds,
|
||||
opt_lifetime: Option<@ast::Lifetime>,
|
||||
decl: &ast::fn_decl,
|
||||
expected_sig: Option<ty::FnSig>,
|
||||
lifetimes: &OptVec<ast::Lifetime>,
|
||||
span: span)
|
||||
-> ty::ClosureTy
|
||||
{
|
||||
// The caller should not both provide explicit bound lifetime
|
||||
// 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>(
|
||||
sigil: sigil,
|
||||
onceness: onceness,
|
||||
region: bound_region,
|
||||
bounds: bounds,
|
||||
sig: ty::FnSig {bound_lifetime_names: bound_lifetime_names,
|
||||
inputs: input_tys,
|
||||
output: output_ty}
|
||||
}
|
||||
}
|
||||
|
||||
fn conv_builtin_bounds(tcx: ty::ctxt,
|
||||
ast_bounds: &OptVec<ast::TyParamBound>)
|
||||
-> ty::BuiltinBounds {
|
||||
//! Converts a list of bounds from the AST into a `BuiltinBounds`
|
||||
//! struct. Reports an error if any of the bounds that appear
|
||||
//! in the AST refer to general traits and not the built-in traits
|
||||
//! like `Copy` or `Owned`. Used to translate the bounds that
|
||||
//! appear in closure and trait types, where only builtin bounds are
|
||||
//! legal.
|
||||
|
||||
let mut builtin_bounds = ty::EmptyBuiltinBounds();
|
||||
for ast_bounds.each |ast_bound| {
|
||||
match *ast_bound {
|
||||
ast::TraitTyParamBound(b) => {
|
||||
match lookup_def_tcx(tcx, b.path.span, b.ref_id) {
|
||||
ast::def_trait(trait_did) => {
|
||||
if try_add_builtin_trait(tcx,
|
||||
trait_did,
|
||||
&mut builtin_bounds) {
|
||||
loop; // success
|
||||
}
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
tcx.sess.span_fatal(
|
||||
b.path.span,
|
||||
fmt!("only the builtin traits can be used \
|
||||
as closure or object bounds"));
|
||||
}
|
||||
ast::RegionTyParamBound => {
|
||||
builtin_bounds.add(ty::BoundStatic);
|
||||
}
|
||||
}
|
||||
}
|
||||
builtin_bounds
|
||||
}
|
||||
|
||||
pub fn try_add_builtin_trait(tcx: ty::ctxt,
|
||||
trait_def_id: ast::def_id,
|
||||
builtin_bounds: &mut ty::BuiltinBounds) -> bool {
|
||||
//! Checks whether `trait_ref` refers to one of the builtin
|
||||
//! traits, like `Copy` or `Owned`, and adds the corresponding
|
||||
//! bound to the set `builtin_bounds` if so. Returns true if `trait_ref`
|
||||
//! is a builtin trait.
|
||||
|
||||
let li = &tcx.lang_items;
|
||||
if trait_def_id == li.owned_trait() {
|
||||
builtin_bounds.add(ty::BoundOwned);
|
||||
true
|
||||
} else if trait_def_id == li.copy_trait() {
|
||||
builtin_bounds.add(ty::BoundCopy);
|
||||
true
|
||||
} else if trait_def_id == li.const_trait() {
|
||||
builtin_bounds.add(ty::BoundConst);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
@ -1661,7 +1661,8 @@ fn check_expr_fn(fcx: @mut FnCtxt,
|
||||
let (expected_sig,
|
||||
expected_purity,
|
||||
expected_sigil,
|
||||
expected_onceness) = {
|
||||
expected_onceness,
|
||||
expected_bounds) = {
|
||||
match expected_sty {
|
||||
Some(ty::ty_closure(ref cenv)) => {
|
||||
let id = expr.id;
|
||||
@ -1669,11 +1670,13 @@ fn check_expr_fn(fcx: @mut FnCtxt,
|
||||
replace_bound_regions_in_fn_sig(
|
||||
tcx, @Nil, None, &cenv.sig,
|
||||
|br| ty::re_bound(ty::br_cap_avoid(id, @br)));
|
||||
(Some(sig), cenv.purity, cenv.sigil, cenv.onceness)
|
||||
(Some(sig), cenv.purity, cenv.sigil,
|
||||
cenv.onceness, cenv.bounds)
|
||||
}
|
||||
_ => {
|
||||
// Not an error! Means we're inferring the closure type
|
||||
(None, ast::impure_fn, ast::BorrowedSigil, ast::Many)
|
||||
(None, ast::impure_fn, ast::BorrowedSigil,
|
||||
ast::Many, ty::EmptyBuiltinBounds())
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -1687,15 +1690,16 @@ fn check_expr_fn(fcx: @mut FnCtxt,
|
||||
|
||||
// construct the function type
|
||||
let fn_ty = astconv::ty_of_closure(fcx,
|
||||
fcx,
|
||||
sigil,
|
||||
purity,
|
||||
expected_onceness,
|
||||
None,
|
||||
decl,
|
||||
expected_sig,
|
||||
&opt_vec::Empty,
|
||||
expr.span);
|
||||
fcx,
|
||||
sigil,
|
||||
purity,
|
||||
expected_onceness,
|
||||
expected_bounds,
|
||||
None,
|
||||
decl,
|
||||
expected_sig,
|
||||
&opt_vec::Empty,
|
||||
expr.span);
|
||||
|
||||
let fty_sig;
|
||||
let fty = if error_happened {
|
||||
@ -3526,6 +3530,7 @@ fn param(ccx: @mut CrateCtxt, n: uint) -> ty::t {
|
||||
sigil: ast::BorrowedSigil,
|
||||
onceness: ast::Once,
|
||||
region: ty::re_bound(ty::br_anon(0)),
|
||||
bounds: ty::EmptyBuiltinBounds(),
|
||||
sig: ty::FnSig {
|
||||
bound_lifetime_names: opt_vec::Empty,
|
||||
inputs: ~[ty::mk_imm_ptr(ccx.tcx, ty::mk_mach_uint(ast::ty_u8))],
|
||||
|
@ -1207,25 +1207,21 @@ fn compute_bounds(
|
||||
builtin_bounds: ty::EmptyBuiltinBounds(),
|
||||
trait_bounds: ~[]
|
||||
};
|
||||
for ast_bounds.each |b| {
|
||||
match b {
|
||||
&TraitTyParamBound(b) => {
|
||||
let li = &ccx.tcx.lang_items;
|
||||
for ast_bounds.each |ast_bound| {
|
||||
match *ast_bound {
|
||||
TraitTyParamBound(b) => {
|
||||
let ty = ty::mk_param(ccx.tcx, param_ty.idx, param_ty.def_id);
|
||||
let trait_ref = instantiate_trait_ref(ccx, b, rp, generics, ty);
|
||||
if trait_ref.def_id == li.owned_trait() {
|
||||
param_bounds.builtin_bounds.add(ty::BoundOwned);
|
||||
} else if trait_ref.def_id == li.copy_trait() {
|
||||
param_bounds.builtin_bounds.add(ty::BoundCopy);
|
||||
} else if trait_ref.def_id == li.const_trait() {
|
||||
param_bounds.builtin_bounds.add(ty::BoundConst);
|
||||
} else {
|
||||
if !astconv::try_add_builtin_trait(
|
||||
ccx.tcx, trait_ref.def_id,
|
||||
&mut param_bounds.builtin_bounds)
|
||||
{
|
||||
// Must be a user-defined trait
|
||||
param_bounds.trait_bounds.push(trait_ref);
|
||||
}
|
||||
}
|
||||
|
||||
&RegionTyParamBound => {
|
||||
RegionTyParamBound => {
|
||||
param_bounds.builtin_bounds.add(ty::BoundStatic);
|
||||
}
|
||||
}
|
||||
|
@ -56,6 +56,7 @@
|
||||
|
||||
use middle::ty::{FloatVar, FnSig, IntVar, TyVar};
|
||||
use middle::ty::{IntType, UintType, substs};
|
||||
use middle::ty::{BuiltinBounds};
|
||||
use middle::ty;
|
||||
use middle::typeck::infer::glb::Glb;
|
||||
use middle::typeck::infer::lub::Lub;
|
||||
@ -100,6 +101,7 @@ fn closure_tys(&self, a: &ty::ClosureTy,
|
||||
fn purities(&self, a: purity, b: purity) -> cres<purity>;
|
||||
fn abis(&self, a: AbiSet, b: AbiSet) -> cres<AbiSet>;
|
||||
fn oncenesses(&self, a: Onceness, b: Onceness) -> cres<Onceness>;
|
||||
fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds>;
|
||||
fn contraregions(&self, a: ty::Region, b: ty::Region)
|
||||
-> cres<ty::Region>;
|
||||
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region>;
|
||||
@ -372,11 +374,13 @@ pub fn super_closure_tys<C:Combine>(
|
||||
let r = if_ok!(this.contraregions(a_f.region, b_f.region));
|
||||
let purity = if_ok!(this.purities(a_f.purity, b_f.purity));
|
||||
let onceness = if_ok!(this.oncenesses(a_f.onceness, b_f.onceness));
|
||||
let bounds = if_ok!(this.bounds(a_f.bounds, b_f.bounds));
|
||||
let sig = if_ok!(this.fn_sigs(&a_f.sig, &b_f.sig));
|
||||
Ok(ty::ClosureTy {purity: purity,
|
||||
sigil: p,
|
||||
onceness: onceness,
|
||||
region: r,
|
||||
bounds: bounds,
|
||||
sig: sig})
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use middle::ty::{BuiltinBounds};
|
||||
use middle::ty::RegionVid;
|
||||
use middle::ty;
|
||||
use middle::typeck::infer::combine::*;
|
||||
@ -114,6 +115,12 @@ fn oncenesses(&self, a: Onceness, b: Onceness) -> cres<Onceness> {
|
||||
}
|
||||
}
|
||||
|
||||
fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> {
|
||||
// More bounds is a subtype of fewer bounds, so
|
||||
// the GLB (mutual subtype) is the union.
|
||||
Ok(a.union(b))
|
||||
}
|
||||
|
||||
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
|
||||
debug!("%s.regions(%?, %?)",
|
||||
self.tag(),
|
||||
|
@ -8,6 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use middle::ty::{BuiltinBounds};
|
||||
use middle::ty::RegionVid;
|
||||
use middle::ty;
|
||||
use middle::typeck::infer::combine::*;
|
||||
@ -100,6 +101,12 @@ fn oncenesses(&self, a: Onceness, b: Onceness) -> cres<Onceness> {
|
||||
}
|
||||
}
|
||||
|
||||
fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> {
|
||||
// More bounds is a subtype of fewer bounds, so
|
||||
// the LUB (mutual supertype) is the intersection.
|
||||
Ok(a.intersection(b))
|
||||
}
|
||||
|
||||
fn contraregions(&self, a: ty::Region, b: ty::Region)
|
||||
-> cres<ty::Region> {
|
||||
return Glb(**self).regions(a, b);
|
||||
|
@ -8,6 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use middle::ty::{BuiltinBounds};
|
||||
use middle::ty;
|
||||
use middle::ty::TyVar;
|
||||
use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
|
||||
@ -99,6 +100,19 @@ fn oncenesses(&self, a: Onceness, b: Onceness) -> cres<Onceness> {
|
||||
})
|
||||
}
|
||||
|
||||
fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> {
|
||||
// More bounds is a subtype of fewer bounds.
|
||||
//
|
||||
// e.g., fn:Copy() <: fn(), because the former is a function
|
||||
// that only closes over copyable things, but the latter is
|
||||
// any function at all.
|
||||
if a.contains(b) {
|
||||
Ok(a)
|
||||
} else {
|
||||
Err(ty::terr_builtin_bounds(expected_found(self, a, b)))
|
||||
}
|
||||
}
|
||||
|
||||
fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
|
||||
debug!("%s.tys(%s, %s)", self.tag(),
|
||||
a.inf_str(self.infcx), b.inf_str(self.infcx));
|
||||
|
@ -12,7 +12,9 @@
|
||||
|
||||
#[deriving(Eq, IterBytes)]
|
||||
pub struct EnumSet<E> {
|
||||
bits: uint
|
||||
// We must maintain the invariant that no bits are set
|
||||
// for which no variant exists
|
||||
priv bits: uint
|
||||
}
|
||||
|
||||
pub trait CLike {
|
||||
@ -37,10 +39,18 @@ fn intersects(&self, e: EnumSet<E>) -> bool {
|
||||
(self.bits & e.bits) != 0
|
||||
}
|
||||
|
||||
fn intersection(&self, e: EnumSet<E>) -> EnumSet<E> {
|
||||
EnumSet {bits: self.bits & e.bits}
|
||||
}
|
||||
|
||||
fn contains(&self, e: EnumSet<E>) -> bool {
|
||||
(self.bits & e.bits) == e.bits
|
||||
}
|
||||
|
||||
fn union(&self, e: EnumSet<E>) -> EnumSet<E> {
|
||||
EnumSet {bits: self.bits | e.bits}
|
||||
}
|
||||
|
||||
fn add(&mut self, e: E) {
|
||||
self.bits |= bit(e);
|
||||
}
|
||||
|
@ -828,7 +828,8 @@ pub struct TyClosure {
|
||||
lifetimes: OptVec<Lifetime>,
|
||||
purity: purity,
|
||||
onceness: Onceness,
|
||||
decl: fn_decl
|
||||
decl: fn_decl,
|
||||
bounds: OptVec<TyParamBound>
|
||||
}
|
||||
|
||||
#[deriving(Eq, Encodable, Decodable)]
|
||||
|
@ -589,6 +589,7 @@ fn fold_field(f: ty_field, fld: @ast_fold) -> ty_field {
|
||||
purity: f.purity,
|
||||
region: f.region,
|
||||
onceness: f.onceness,
|
||||
bounds: f.bounds.map(|x| fold_ty_param_bound(x, fld)),
|
||||
decl: fold_fn_decl(&f.decl, fld),
|
||||
lifetimes: copy f.lifetimes,
|
||||
})
|
||||
|
@ -395,12 +395,13 @@ fn parse_ty_closure(&self,
|
||||
-> ty_ {
|
||||
/*
|
||||
|
||||
(&|~|@) ['r] [pure|unsafe] [once] fn <'lt> (S) -> T
|
||||
^~~~~~^ ^~~^ ^~~~~~~~~~~~^ ^~~~~^ ^~~~^ ^~^ ^
|
||||
| | | | | | |
|
||||
| | | | | | Return type
|
||||
| | | | | Argument types
|
||||
| | | | Lifetimes
|
||||
(&|~|@) ['r] [pure|unsafe] [once] fn [:Bounds] <'lt> (S) -> T
|
||||
^~~~~~^ ^~~^ ^~~~~~~~~~~~^ ^~~~~^ ^~~~~~~~^ ^~~~^ ^~^ ^
|
||||
| | | | | | | |
|
||||
| | | | | | | Return type
|
||||
| | | | | | Argument types
|
||||
| | | | | Lifetimes
|
||||
| | | | Closure bounds
|
||||
| | | Once-ness (a.k.a., affine)
|
||||
| | Purity
|
||||
| Lifetime bound
|
||||
@ -414,6 +415,7 @@ fn parse_ty_closure(&self,
|
||||
let purity = self.parse_unsafety();
|
||||
let onceness = parse_onceness(self);
|
||||
self.expect_keyword("fn");
|
||||
let bounds = self.parse_optional_ty_param_bounds();
|
||||
|
||||
if self.parse_fn_ty_sigil().is_some() {
|
||||
self.obsolete(*self.span, ObsoletePostFnTySigil);
|
||||
@ -426,6 +428,7 @@ fn parse_ty_closure(&self,
|
||||
region: region,
|
||||
purity: purity,
|
||||
onceness: onceness,
|
||||
bounds: bounds,
|
||||
decl: decl,
|
||||
lifetimes: lifetimes,
|
||||
});
|
||||
@ -2851,9 +2854,9 @@ fn parse_optional_onceness(&self) -> ast::Onceness {
|
||||
// matches optbounds = ( ( : ( boundseq )? )? )
|
||||
// where boundseq = ( bound + boundseq ) | bound
|
||||
// and bound = 'static | ty
|
||||
fn parse_optional_ty_param_bounds(&self) -> @OptVec<TyParamBound> {
|
||||
fn parse_optional_ty_param_bounds(&self) -> OptVec<TyParamBound> {
|
||||
if !self.eat(&token::COLON) {
|
||||
return @opt_vec::Empty;
|
||||
return opt_vec::Empty;
|
||||
}
|
||||
|
||||
let mut result = opt_vec::Empty;
|
||||
@ -2907,13 +2910,13 @@ fn parse_optional_ty_param_bounds(&self) -> @OptVec<TyParamBound> {
|
||||
}
|
||||
}
|
||||
|
||||
return @result;
|
||||
return result;
|
||||
}
|
||||
|
||||
// matches typaram = IDENT optbounds
|
||||
fn parse_ty_param(&self) -> TyParam {
|
||||
let ident = self.parse_ident();
|
||||
let bounds = self.parse_optional_ty_param_bounds();
|
||||
let bounds = @self.parse_optional_ty_param_bounds();
|
||||
ast::TyParam { ident: ident, id: self.get_id(), bounds: bounds }
|
||||
}
|
||||
|
||||
|
8
src/test/compile-fail/closure-bounds-not-builtin.rs
Normal file
8
src/test/compile-fail/closure-bounds-not-builtin.rs
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
trait Foo {}
|
||||
|
||||
fn take(f: &fn:Foo()) {
|
||||
//~^ ERROR only the builtin traits can be used as closure or object bounds
|
||||
}
|
||||
|
||||
fn main() {}
|
34
src/test/compile-fail/closure-bounds-subtype.rs
Normal file
34
src/test/compile-fail/closure-bounds-subtype.rs
Normal file
@ -0,0 +1,34 @@
|
||||
fn take_any(_: &fn()) {
|
||||
}
|
||||
|
||||
fn take_copyable(_: &fn:Copy()) {
|
||||
}
|
||||
|
||||
fn take_copyable_owned(_: &fn:Copy+Owned()) {
|
||||
}
|
||||
|
||||
fn give_any(f: &fn()) {
|
||||
take_any(f);
|
||||
take_copyable(f); //~ ERROR expected bounds `Copy` but found no bounds
|
||||
take_copyable_owned(f); //~ ERROR expected bounds `Copy+Owned` but found no bounds
|
||||
}
|
||||
|
||||
fn give_copyable(f: &fn:Copy()) {
|
||||
take_any(f);
|
||||
take_copyable(f);
|
||||
take_copyable_owned(f); //~ ERROR expected bounds `Copy+Owned` but found bounds `Copy`
|
||||
}
|
||||
|
||||
fn give_owned(f: &fn:Owned()) {
|
||||
take_any(f);
|
||||
take_copyable(f); //~ ERROR expected bounds `Copy` but found bounds `Owned`
|
||||
take_copyable_owned(f); //~ ERROR expected bounds `Copy+Owned` but found bounds `Owned`
|
||||
}
|
||||
|
||||
fn give_copyable_owned(f: &fn:Copy+Owned()) {
|
||||
take_any(f);
|
||||
take_copyable(f);
|
||||
take_copyable_owned(f);
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user