Add BuiltinBounds to closure type: parse and handle subtyping,
but do not integrate with kindck etc (requires a snapshot first)
This commit is contained in:
parent
53196bb364
commit
035c01af93
19 changed files with 261 additions and 61 deletions
|
@ -470,12 +470,14 @@ fn parse_closure_ty(st: @mut PState, conv: conv_did) -> ty::ClosureTy {
|
||||||
let purity = parse_purity(next(st));
|
let purity = parse_purity(next(st));
|
||||||
let onceness = parse_onceness(next(st));
|
let onceness = parse_onceness(next(st));
|
||||||
let region = parse_region(st);
|
let region = parse_region(st);
|
||||||
|
let bounds = parse_bounds(st, conv);
|
||||||
let sig = parse_sig(st, conv);
|
let sig = parse_sig(st, conv);
|
||||||
ty::ClosureTy {
|
ty::ClosureTy {
|
||||||
purity: purity,
|
purity: purity,
|
||||||
sigil: sigil,
|
sigil: sigil,
|
||||||
onceness: onceness,
|
onceness: onceness,
|
||||||
region: region,
|
region: region,
|
||||||
|
bounds: bounds.builtin_bounds,
|
||||||
sig: sig
|
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 {
|
fn parse_type_param_def(st: @mut PState, conv: conv_did) -> ty::TypeParameterDef {
|
||||||
ty::TypeParameterDef {def_id: parse_def(st, NominalType, conv),
|
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 {
|
let mut param_bounds = ty::ParamBounds {
|
||||||
builtin_bounds: ty::EmptyBuiltinBounds(),
|
builtin_bounds: ty::EmptyBuiltinBounds(),
|
||||||
trait_bounds: ~[]
|
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));
|
param_bounds.trait_bounds.push(@parse_trait_ref(st, conv));
|
||||||
}
|
}
|
||||||
'.' => {
|
'.' => {
|
||||||
return @param_bounds;
|
return param_bounds;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
fail!("parse_bounds: bad 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_purity(w, ft.purity);
|
||||||
enc_onceness(w, ft.onceness);
|
enc_onceness(w, ft.onceness);
|
||||||
enc_region(w, cx, ft.region);
|
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);
|
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);
|
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| {
|
for bs.builtin_bounds.each |bound| {
|
||||||
match bound {
|
match bound {
|
||||||
ty::BoundOwned => w.write_char('S'),
|
ty::BoundOwned => w.write_char('S'),
|
||||||
|
|
|
@ -20,6 +20,7 @@ use middle::lint::{allow, level, unused_imports};
|
||||||
use middle::lint::{get_lint_level, get_lint_settings_level};
|
use middle::lint::{get_lint_level, get_lint_settings_level};
|
||||||
use middle::pat_util::pat_bindings;
|
use middle::pat_util::pat_bindings;
|
||||||
|
|
||||||
|
use syntax::ast::{TyParamBound, ty_closure};
|
||||||
use syntax::ast::{RegionTyParamBound, TraitTyParamBound, _mod, add, arm};
|
use syntax::ast::{RegionTyParamBound, TraitTyParamBound, _mod, add, arm};
|
||||||
use syntax::ast::{binding_mode, bitand, bitor, bitxor, blk};
|
use syntax::ast::{binding_mode, bitand, bitor, bitxor, blk};
|
||||||
use syntax::ast::{bind_infer, bind_by_ref, bind_by_copy};
|
use syntax::ast::{bind_infer, bind_by_ref, bind_by_copy};
|
||||||
|
@ -3732,16 +3733,22 @@ pub impl Resolver {
|
||||||
type_parameters: &OptVec<TyParam>,
|
type_parameters: &OptVec<TyParam>,
|
||||||
visitor: ResolveVisitor) {
|
visitor: ResolveVisitor) {
|
||||||
for type_parameters.each |type_parameter| {
|
for type_parameters.each |type_parameter| {
|
||||||
for type_parameter.bounds.each |&bound| {
|
for type_parameter.bounds.each |bound| {
|
||||||
match 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) => {
|
TraitTyParamBound(tref) => {
|
||||||
self.resolve_trait_reference(tref, visitor)
|
self.resolve_trait_reference(tref, visitor)
|
||||||
}
|
}
|
||||||
RegionTyParamBound => {}
|
RegionTyParamBound => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_trait_reference(@mut self,
|
fn resolve_trait_reference(@mut self,
|
||||||
trait_reference: &trait_ref,
|
trait_reference: &trait_ref,
|
||||||
|
@ -4070,6 +4077,13 @@ pub impl Resolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ty_closure(c) => {
|
||||||
|
for c.bounds.each |bound| {
|
||||||
|
self.resolve_type_parameter_bound(bound, visitor);
|
||||||
|
}
|
||||||
|
visit_ty(ty, (), visitor);
|
||||||
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
// Just resolve embedded types.
|
// Just resolve embedded types.
|
||||||
visit_ty(ty, (), visitor);
|
visit_ty(ty, (), visitor);
|
||||||
|
|
|
@ -818,6 +818,7 @@ pub fn trans_intrinsic(ccx: @CrateContext,
|
||||||
sigil: ast::BorrowedSigil,
|
sigil: ast::BorrowedSigil,
|
||||||
onceness: ast::Many,
|
onceness: ast::Many,
|
||||||
region: ty::re_bound(ty::br_anon(0)),
|
region: ty::re_bound(ty::br_anon(0)),
|
||||||
|
bounds: ty::EmptyBuiltinBounds(),
|
||||||
sig: FnSig {
|
sig: FnSig {
|
||||||
bound_lifetime_names: opt_vec::Empty,
|
bound_lifetime_names: opt_vec::Empty,
|
||||||
inputs: ~[ star_u8 ],
|
inputs: ~[ star_u8 ],
|
||||||
|
|
|
@ -330,6 +330,7 @@ pub fn normalize_for_monomorphization(tcx: ty::ctxt,
|
||||||
sigil: sigil,
|
sigil: sigil,
|
||||||
onceness: ast::Many,
|
onceness: ast::Many,
|
||||||
region: ty::re_static,
|
region: ty::re_static,
|
||||||
|
bounds: ty::EmptyBuiltinBounds(),
|
||||||
sig: ty::FnSig {bound_lifetime_names: opt_vec::Empty,
|
sig: ty::FnSig {bound_lifetime_names: opt_vec::Empty,
|
||||||
inputs: ~[],
|
inputs: ~[],
|
||||||
output: ty::mk_nil()}})
|
output: ty::mk_nil()}})
|
||||||
|
|
|
@ -22,7 +22,7 @@ use middle::typeck;
|
||||||
use middle;
|
use middle;
|
||||||
use util::ppaux::{note_and_explain_region, bound_region_to_str};
|
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::{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::common::{indenter};
|
||||||
use util::enum_set::{EnumSet, CLike};
|
use util::enum_set::{EnumSet, CLike};
|
||||||
|
|
||||||
|
@ -390,7 +390,8 @@ pub struct ClosureTy {
|
||||||
sigil: ast::Sigil,
|
sigil: ast::Sigil,
|
||||||
onceness: ast::Onceness,
|
onceness: ast::Onceness,
|
||||||
region: Region,
|
region: Region,
|
||||||
sig: FnSig
|
bounds: BuiltinBounds,
|
||||||
|
sig: FnSig,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -685,6 +686,7 @@ pub enum type_err {
|
||||||
terr_int_mismatch(expected_found<IntVarValue>),
|
terr_int_mismatch(expected_found<IntVarValue>),
|
||||||
terr_float_mismatch(expected_found<ast::float_ty>),
|
terr_float_mismatch(expected_found<ast::float_ty>),
|
||||||
terr_traits(expected_found<ast::def_id>),
|
terr_traits(expected_found<ast::def_id>),
|
||||||
|
terr_builtin_bounds(expected_found<BuiltinBounds>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(Eq, IterBytes)]
|
#[deriving(Eq, IterBytes)]
|
||||||
|
@ -707,6 +709,15 @@ pub fn EmptyBuiltinBounds() -> BuiltinBounds {
|
||||||
EnumSet::empty()
|
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 {
|
impl CLike for BuiltinBound {
|
||||||
pub fn to_uint(&self) -> uint {
|
pub fn to_uint(&self) -> uint {
|
||||||
*self as uint
|
*self as uint
|
||||||
|
@ -3169,6 +3180,7 @@ pub fn adjust_ty(cx: ctxt,
|
||||||
sigil: s,
|
sigil: s,
|
||||||
onceness: ast::Many,
|
onceness: ast::Many,
|
||||||
region: r,
|
region: r,
|
||||||
|
bounds: ty::AllBuiltinBounds(),
|
||||||
sig: copy b.sig})
|
sig: copy b.sig})
|
||||||
}
|
}
|
||||||
ref b => {
|
ref b => {
|
||||||
|
@ -3697,6 +3709,19 @@ pub fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str {
|
||||||
item_path_str(cx, values.expected),
|
item_path_str(cx, values.expected),
|
||||||
item_path_str(cx, values.found))
|
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 => {
|
terr_self_substs => {
|
||||||
~"inconsistent self substitution" // XXX this is more of a bug
|
~"inconsistent self substitution" // XXX this is more of a bug
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,7 @@ use middle::ty;
|
||||||
use middle::typeck::rscope::in_binding_rscope;
|
use middle::typeck::rscope::in_binding_rscope;
|
||||||
use middle::typeck::rscope::{region_scope, RegionError};
|
use middle::typeck::rscope::{region_scope, RegionError};
|
||||||
use middle::typeck::rscope::RegionParamNames;
|
use middle::typeck::rscope::RegionParamNames;
|
||||||
|
use middle::typeck::lookup_def_tcx;
|
||||||
|
|
||||||
use syntax::abi::AbiSet;
|
use syntax::abi::AbiSet;
|
||||||
use syntax::{ast, ast_util};
|
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;
|
return trait_ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn ast_path_to_ty<AC:AstConv,RS:region_scope + Copy + 'static>(
|
pub fn ast_path_to_ty<AC:AstConv,RS:region_scope + Copy + 'static>(
|
||||||
this: &AC,
|
this: &AC,
|
||||||
rscope: &RS,
|
rscope: &RS,
|
||||||
|
@ -377,11 +377,13 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>(
|
||||||
bf.abis, &bf.lifetimes, &bf.decl))
|
bf.abis, &bf.lifetimes, &bf.decl))
|
||||||
}
|
}
|
||||||
ast::ty_closure(ref f) => {
|
ast::ty_closure(ref f) => {
|
||||||
|
let bounds = conv_builtin_bounds(this.tcx(), &f.bounds);
|
||||||
let fn_decl = ty_of_closure(this,
|
let fn_decl = ty_of_closure(this,
|
||||||
rscope,
|
rscope,
|
||||||
f.sigil,
|
f.sigil,
|
||||||
f.purity,
|
f.purity,
|
||||||
f.onceness,
|
f.onceness,
|
||||||
|
bounds,
|
||||||
f.region,
|
f.region,
|
||||||
&f.decl,
|
&f.decl,
|
||||||
None,
|
None,
|
||||||
|
@ -651,6 +653,7 @@ pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + 'static>(
|
||||||
sigil: ast::Sigil,
|
sigil: ast::Sigil,
|
||||||
purity: ast::purity,
|
purity: ast::purity,
|
||||||
onceness: ast::Onceness,
|
onceness: ast::Onceness,
|
||||||
|
bounds: ty::BuiltinBounds,
|
||||||
opt_lifetime: Option<@ast::Lifetime>,
|
opt_lifetime: Option<@ast::Lifetime>,
|
||||||
decl: &ast::fn_decl,
|
decl: &ast::fn_decl,
|
||||||
expected_sig: Option<ty::FnSig>,
|
expected_sig: Option<ty::FnSig>,
|
||||||
|
@ -713,8 +716,69 @@ pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + 'static>(
|
||||||
sigil: sigil,
|
sigil: sigil,
|
||||||
onceness: onceness,
|
onceness: onceness,
|
||||||
region: bound_region,
|
region: bound_region,
|
||||||
|
bounds: bounds,
|
||||||
sig: ty::FnSig {bound_lifetime_names: bound_lifetime_names,
|
sig: ty::FnSig {bound_lifetime_names: bound_lifetime_names,
|
||||||
inputs: input_tys,
|
inputs: input_tys,
|
||||||
output: output_ty}
|
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 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
|
||||||
let (expected_sig,
|
let (expected_sig,
|
||||||
expected_purity,
|
expected_purity,
|
||||||
expected_sigil,
|
expected_sigil,
|
||||||
expected_onceness) = {
|
expected_onceness,
|
||||||
|
expected_bounds) = {
|
||||||
match expected_sty {
|
match expected_sty {
|
||||||
Some(ty::ty_closure(ref cenv)) => {
|
Some(ty::ty_closure(ref cenv)) => {
|
||||||
let id = expr.id;
|
let id = expr.id;
|
||||||
|
@ -1669,11 +1670,13 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
|
||||||
replace_bound_regions_in_fn_sig(
|
replace_bound_regions_in_fn_sig(
|
||||||
tcx, @Nil, None, &cenv.sig,
|
tcx, @Nil, None, &cenv.sig,
|
||||||
|br| ty::re_bound(ty::br_cap_avoid(id, @br)));
|
|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
|
// 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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1691,6 +1694,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
|
||||||
sigil,
|
sigil,
|
||||||
purity,
|
purity,
|
||||||
expected_onceness,
|
expected_onceness,
|
||||||
|
expected_bounds,
|
||||||
None,
|
None,
|
||||||
decl,
|
decl,
|
||||||
expected_sig,
|
expected_sig,
|
||||||
|
@ -3526,6 +3530,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) {
|
||||||
sigil: ast::BorrowedSigil,
|
sigil: ast::BorrowedSigil,
|
||||||
onceness: ast::Once,
|
onceness: ast::Once,
|
||||||
region: ty::re_bound(ty::br_anon(0)),
|
region: ty::re_bound(ty::br_anon(0)),
|
||||||
|
bounds: ty::EmptyBuiltinBounds(),
|
||||||
sig: ty::FnSig {
|
sig: ty::FnSig {
|
||||||
bound_lifetime_names: opt_vec::Empty,
|
bound_lifetime_names: opt_vec::Empty,
|
||||||
inputs: ~[ty::mk_imm_ptr(ccx.tcx, ty::mk_mach_uint(ast::ty_u8))],
|
inputs: ~[ty::mk_imm_ptr(ccx.tcx, ty::mk_mach_uint(ast::ty_u8))],
|
||||||
|
|
|
@ -1207,25 +1207,21 @@ pub fn ty_generics(ccx: &CrateCtxt,
|
||||||
builtin_bounds: ty::EmptyBuiltinBounds(),
|
builtin_bounds: ty::EmptyBuiltinBounds(),
|
||||||
trait_bounds: ~[]
|
trait_bounds: ~[]
|
||||||
};
|
};
|
||||||
for ast_bounds.each |b| {
|
for ast_bounds.each |ast_bound| {
|
||||||
match b {
|
match *ast_bound {
|
||||||
&TraitTyParamBound(b) => {
|
TraitTyParamBound(b) => {
|
||||||
let li = &ccx.tcx.lang_items;
|
|
||||||
let ty = ty::mk_param(ccx.tcx, param_ty.idx, param_ty.def_id);
|
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);
|
let trait_ref = instantiate_trait_ref(ccx, b, rp, generics, ty);
|
||||||
if trait_ref.def_id == li.owned_trait() {
|
if !astconv::try_add_builtin_trait(
|
||||||
param_bounds.builtin_bounds.add(ty::BoundOwned);
|
ccx.tcx, trait_ref.def_id,
|
||||||
} else if trait_ref.def_id == li.copy_trait() {
|
&mut param_bounds.builtin_bounds)
|
||||||
param_bounds.builtin_bounds.add(ty::BoundCopy);
|
{
|
||||||
} else if trait_ref.def_id == li.const_trait() {
|
|
||||||
param_bounds.builtin_bounds.add(ty::BoundConst);
|
|
||||||
} else {
|
|
||||||
// Must be a user-defined trait
|
// Must be a user-defined trait
|
||||||
param_bounds.trait_bounds.push(trait_ref);
|
param_bounds.trait_bounds.push(trait_ref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&RegionTyParamBound => {
|
RegionTyParamBound => {
|
||||||
param_bounds.builtin_bounds.add(ty::BoundStatic);
|
param_bounds.builtin_bounds.add(ty::BoundStatic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
|
|
||||||
use middle::ty::{FloatVar, FnSig, IntVar, TyVar};
|
use middle::ty::{FloatVar, FnSig, IntVar, TyVar};
|
||||||
use middle::ty::{IntType, UintType, substs};
|
use middle::ty::{IntType, UintType, substs};
|
||||||
|
use middle::ty::{BuiltinBounds};
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::typeck::infer::glb::Glb;
|
use middle::typeck::infer::glb::Glb;
|
||||||
use middle::typeck::infer::lub::Lub;
|
use middle::typeck::infer::lub::Lub;
|
||||||
|
@ -100,6 +101,7 @@ pub trait Combine {
|
||||||
fn purities(&self, a: purity, b: purity) -> cres<purity>;
|
fn purities(&self, a: purity, b: purity) -> cres<purity>;
|
||||||
fn abis(&self, a: AbiSet, b: AbiSet) -> cres<AbiSet>;
|
fn abis(&self, a: AbiSet, b: AbiSet) -> cres<AbiSet>;
|
||||||
fn oncenesses(&self, a: Onceness, b: Onceness) -> cres<Onceness>;
|
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)
|
fn contraregions(&self, a: ty::Region, b: ty::Region)
|
||||||
-> cres<ty::Region>;
|
-> cres<ty::Region>;
|
||||||
fn regions(&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 r = if_ok!(this.contraregions(a_f.region, b_f.region));
|
||||||
let purity = if_ok!(this.purities(a_f.purity, b_f.purity));
|
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 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));
|
let sig = if_ok!(this.fn_sigs(&a_f.sig, &b_f.sig));
|
||||||
Ok(ty::ClosureTy {purity: purity,
|
Ok(ty::ClosureTy {purity: purity,
|
||||||
sigil: p,
|
sigil: p,
|
||||||
onceness: onceness,
|
onceness: onceness,
|
||||||
region: r,
|
region: r,
|
||||||
|
bounds: bounds,
|
||||||
sig: sig})
|
sig: sig})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
use middle::ty::{BuiltinBounds};
|
||||||
use middle::ty::RegionVid;
|
use middle::ty::RegionVid;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::typeck::infer::combine::*;
|
use middle::typeck::infer::combine::*;
|
||||||
|
@ -114,6 +115,12 @@ impl Combine for Glb {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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> {
|
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
|
||||||
debug!("%s.regions(%?, %?)",
|
debug!("%s.regions(%?, %?)",
|
||||||
self.tag(),
|
self.tag(),
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
use middle::ty::{BuiltinBounds};
|
||||||
use middle::ty::RegionVid;
|
use middle::ty::RegionVid;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::typeck::infer::combine::*;
|
use middle::typeck::infer::combine::*;
|
||||||
|
@ -100,6 +101,12 @@ impl Combine for Lub {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
fn contraregions(&self, a: ty::Region, b: ty::Region)
|
||||||
-> cres<ty::Region> {
|
-> cres<ty::Region> {
|
||||||
return Glb(**self).regions(a, b);
|
return Glb(**self).regions(a, b);
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
use middle::ty::{BuiltinBounds};
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::ty::TyVar;
|
use middle::ty::TyVar;
|
||||||
use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
|
use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
|
||||||
|
@ -99,6 +100,19 @@ impl Combine for Sub {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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> {
|
fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
|
||||||
debug!("%s.tys(%s, %s)", self.tag(),
|
debug!("%s.tys(%s, %s)", self.tag(),
|
||||||
a.inf_str(self.infcx), b.inf_str(self.infcx));
|
a.inf_str(self.infcx), b.inf_str(self.infcx));
|
||||||
|
|
|
@ -12,7 +12,9 @@ use core;
|
||||||
|
|
||||||
#[deriving(Eq, IterBytes)]
|
#[deriving(Eq, IterBytes)]
|
||||||
pub struct EnumSet<E> {
|
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 {
|
pub trait CLike {
|
||||||
|
@ -37,10 +39,18 @@ pub impl<E:CLike> EnumSet<E> {
|
||||||
(self.bits & e.bits) != 0
|
(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 {
|
fn contains(&self, e: EnumSet<E>) -> bool {
|
||||||
(self.bits & e.bits) == e.bits
|
(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) {
|
fn add(&mut self, e: E) {
|
||||||
self.bits |= bit(e);
|
self.bits |= bit(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -828,7 +828,8 @@ pub struct TyClosure {
|
||||||
lifetimes: OptVec<Lifetime>,
|
lifetimes: OptVec<Lifetime>,
|
||||||
purity: purity,
|
purity: purity,
|
||||||
onceness: Onceness,
|
onceness: Onceness,
|
||||||
decl: fn_decl
|
decl: fn_decl,
|
||||||
|
bounds: OptVec<TyParamBound>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(Eq, Encodable, Decodable)]
|
#[deriving(Eq, Encodable, Decodable)]
|
||||||
|
|
|
@ -589,6 +589,7 @@ pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ {
|
||||||
purity: f.purity,
|
purity: f.purity,
|
||||||
region: f.region,
|
region: f.region,
|
||||||
onceness: f.onceness,
|
onceness: f.onceness,
|
||||||
|
bounds: f.bounds.map(|x| fold_ty_param_bound(x, fld)),
|
||||||
decl: fold_fn_decl(&f.decl, fld),
|
decl: fold_fn_decl(&f.decl, fld),
|
||||||
lifetimes: copy f.lifetimes,
|
lifetimes: copy f.lifetimes,
|
||||||
})
|
})
|
||||||
|
|
|
@ -395,12 +395,13 @@ pub impl Parser {
|
||||||
-> ty_ {
|
-> ty_ {
|
||||||
/*
|
/*
|
||||||
|
|
||||||
(&|~|@) ['r] [pure|unsafe] [once] fn <'lt> (S) -> T
|
(&|~|@) ['r] [pure|unsafe] [once] fn [:Bounds] <'lt> (S) -> T
|
||||||
^~~~~~^ ^~~^ ^~~~~~~~~~~~^ ^~~~~^ ^~~~^ ^~^ ^
|
^~~~~~^ ^~~^ ^~~~~~~~~~~~^ ^~~~~^ ^~~~~~~~^ ^~~~^ ^~^ ^
|
||||||
| | | | | | |
|
| | | | | | | |
|
||||||
| | | | | | Return type
|
| | | | | | | Return type
|
||||||
| | | | | Argument types
|
| | | | | | Argument types
|
||||||
| | | | Lifetimes
|
| | | | | Lifetimes
|
||||||
|
| | | | Closure bounds
|
||||||
| | | Once-ness (a.k.a., affine)
|
| | | Once-ness (a.k.a., affine)
|
||||||
| | Purity
|
| | Purity
|
||||||
| Lifetime bound
|
| Lifetime bound
|
||||||
|
@ -414,6 +415,7 @@ pub impl Parser {
|
||||||
let purity = self.parse_unsafety();
|
let purity = self.parse_unsafety();
|
||||||
let onceness = parse_onceness(self);
|
let onceness = parse_onceness(self);
|
||||||
self.expect_keyword("fn");
|
self.expect_keyword("fn");
|
||||||
|
let bounds = self.parse_optional_ty_param_bounds();
|
||||||
|
|
||||||
if self.parse_fn_ty_sigil().is_some() {
|
if self.parse_fn_ty_sigil().is_some() {
|
||||||
self.obsolete(*self.span, ObsoletePostFnTySigil);
|
self.obsolete(*self.span, ObsoletePostFnTySigil);
|
||||||
|
@ -426,6 +428,7 @@ pub impl Parser {
|
||||||
region: region,
|
region: region,
|
||||||
purity: purity,
|
purity: purity,
|
||||||
onceness: onceness,
|
onceness: onceness,
|
||||||
|
bounds: bounds,
|
||||||
decl: decl,
|
decl: decl,
|
||||||
lifetimes: lifetimes,
|
lifetimes: lifetimes,
|
||||||
});
|
});
|
||||||
|
@ -2851,9 +2854,9 @@ pub impl Parser {
|
||||||
// matches optbounds = ( ( : ( boundseq )? )? )
|
// matches optbounds = ( ( : ( boundseq )? )? )
|
||||||
// where boundseq = ( bound + boundseq ) | bound
|
// where boundseq = ( bound + boundseq ) | bound
|
||||||
// and bound = 'static | ty
|
// 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) {
|
if !self.eat(&token::COLON) {
|
||||||
return @opt_vec::Empty;
|
return opt_vec::Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut result = opt_vec::Empty;
|
let mut result = opt_vec::Empty;
|
||||||
|
@ -2907,13 +2910,13 @@ pub impl Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return @result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// matches typaram = IDENT optbounds
|
// matches typaram = IDENT optbounds
|
||||||
fn parse_ty_param(&self) -> TyParam {
|
fn parse_ty_param(&self) -> TyParam {
|
||||||
let ident = self.parse_ident();
|
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 }
|
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…
Add table
Add a link
Reference in a new issue