reduce self type to a special type parameter
This commit is contained in:
parent
d41af13334
commit
5e7229b72c
@ -199,12 +199,16 @@ fn parse_vstore(st: @pstate) -> ty::vstore {
|
||||
fn parse_substs(st: @pstate, conv: conv_did) -> ty::substs {
|
||||
let self_r = parse_opt(st) {|| parse_region(st) };
|
||||
|
||||
let self_ty = parse_opt(st) {|| parse_ty(st, conv) };
|
||||
|
||||
assert next(st) == '[';
|
||||
let mut params: [ty::t] = [];
|
||||
while peek(st) != ']' { params += [parse_ty(st, conv)]; }
|
||||
st.pos = st.pos + 1u;
|
||||
|
||||
ret {self_r: self_r, tps: params};
|
||||
ret {self_r: self_r,
|
||||
self_ty: self_ty,
|
||||
tps: params};
|
||||
}
|
||||
|
||||
fn parse_bound_region(st: @pstate) -> ty::bound_region {
|
||||
@ -298,10 +302,7 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t {
|
||||
ret ty::mk_param(st.tcx, parse_int(st) as uint, did);
|
||||
}
|
||||
's' {
|
||||
assert next(st) == '[';
|
||||
let substs = parse_substs(st, conv);
|
||||
assert next(st) == ']';
|
||||
ret ty::mk_self(st.tcx, substs);
|
||||
ret ty::mk_self(st.tcx);
|
||||
}
|
||||
'@' { ret ty::mk_box(st.tcx, parse_mt(st, conv)); }
|
||||
'~' { ret ty::mk_uniq(st.tcx, parse_mt(st, conv)); }
|
||||
|
@ -115,6 +115,7 @@ fn enc_opt<T>(w: io::writer, t: option<T>, enc_f: fn(T)) {
|
||||
|
||||
fn enc_substs(w: io::writer, cx: @ctxt, substs: ty::substs) {
|
||||
enc_opt(w, substs.self_r) { |r| enc_region(w, cx, r) }
|
||||
enc_opt(w, substs.self_ty) { |t| enc_ty(w, cx, t) }
|
||||
w.write_char('[');
|
||||
for substs.tps.each { |t| enc_ty(w, cx, t); }
|
||||
w.write_char(']');
|
||||
@ -281,10 +282,8 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) {
|
||||
w.write_char('|');
|
||||
w.write_str(uint::str(id));
|
||||
}
|
||||
ty::ty_self(substs) {
|
||||
w.write_str("s["/&);
|
||||
enc_substs(w, cx, substs);
|
||||
w.write_char(']');
|
||||
ty::ty_self {
|
||||
w.write_char('s');
|
||||
}
|
||||
ty::ty_type { w.write_char('Y'); }
|
||||
ty::ty_opaque_closure_ptr(ty::ck_block) { w.write_str("C&"/&); }
|
||||
|
@ -630,12 +630,15 @@ fn resolve(typ: ty::t) -> fres<ty::t> {
|
||||
fn resolve1(typ: ty::t) -> ty::t {
|
||||
#debug("Resolve1(%s)", typ.to_str(self.infcx));
|
||||
indent(fn&() -> ty::t {
|
||||
if !ty::get(typ).has_vars { ret typ; }
|
||||
if !ty::type_needs_infer(typ) { ret typ; }
|
||||
|
||||
let tb = ty::get(typ);
|
||||
alt tb.struct {
|
||||
ty::ty_var(vid) { self.resolve_ty_var(vid) }
|
||||
_ if !tb.has_regions && !self.deep { typ }
|
||||
alt ty::get(typ).struct {
|
||||
ty::ty_var(vid) {
|
||||
self.resolve_ty_var(vid)
|
||||
}
|
||||
_ if !ty::type_has_regions(typ) && !self.deep {
|
||||
typ
|
||||
}
|
||||
_ {
|
||||
ty::fold_regions_and_ty(
|
||||
self.infcx.tcx, typ,
|
||||
@ -935,6 +938,7 @@ fn crosspolinate(a_node_id: ast::node_id,
|
||||
fn contratys(a: ty::t, b: ty::t) -> cres<ty::t>;
|
||||
fn tys(a: ty::t, b: ty::t) -> cres<ty::t>;
|
||||
fn tps(as: [ty::t], bs: [ty::t]) -> cres<[ty::t]>;
|
||||
fn self_tys(a: option<ty::t>, b: option<ty::t>) -> cres<option<ty::t>>;
|
||||
fn substs(as: ty::substs, bs: ty::substs) -> cres<ty::substs>;
|
||||
fn fns(a: ty::fn_ty, b: ty::fn_ty) -> cres<ty::fn_ty>;
|
||||
fn flds(a: ty::field, b: ty::field) -> cres<ty::field>;
|
||||
@ -982,8 +986,10 @@ fn eq_opt_regions(infcx: infer_ctxt,
|
||||
}
|
||||
|
||||
self.tps(a.tps, b.tps).chain { |tps|
|
||||
eq_opt_regions(self.infcx(), a.self_r, b.self_r).chain { |self_r|
|
||||
ok({self_r: self_r, tps: tps})
|
||||
self.self_tys(a.self_ty, b.self_ty).chain { |self_ty|
|
||||
eq_opt_regions(self.infcx(), a.self_r, b.self_r).chain { |self_r|
|
||||
ok({self_r: self_r, self_ty: self_ty, tps: tps})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -995,6 +1001,7 @@ fn super_tps<C:combine>(
|
||||
// (otherwise the type system would be unsound). In the
|
||||
// future we could allow type parameters to declare a
|
||||
// variance.
|
||||
|
||||
if check vec::same_length(as, bs) {
|
||||
iter2(as, bs) {|a, b| self.infcx().eq_tys(a, b) }.then {||
|
||||
ok(as)
|
||||
@ -1004,6 +1011,31 @@ fn super_tps<C:combine>(
|
||||
}
|
||||
}
|
||||
|
||||
fn super_self_tys<C:combine>(
|
||||
self: C, a: option<ty::t>, b: option<ty::t>) -> cres<option<ty::t>> {
|
||||
|
||||
// Note: the self type parameter is (currently) always treated as
|
||||
// *invariant* (otherwise the type system would be unsound).
|
||||
|
||||
alt (a, b) {
|
||||
(none, none) {
|
||||
ok(none)
|
||||
}
|
||||
(some(a), some(b)) {
|
||||
self.infcx().eq_tys(a, b).then {||
|
||||
ok(some(a))
|
||||
}
|
||||
}
|
||||
(none, some(_)) |
|
||||
(some(_), none) {
|
||||
// I think it should never happen that we unify two substs and
|
||||
// one of them has a self_ty and one doesn't...? I could be
|
||||
// wrong about this.
|
||||
err(ty::terr_self_substs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn super_flds<C:combine>(
|
||||
self: C, a: ty::field, b: ty::field) -> cres<ty::field> {
|
||||
|
||||
@ -1374,6 +1406,10 @@ fn substs(as: ty::substs, bs: ty::substs) -> cres<ty::substs> {
|
||||
fn tps(as: [ty::t], bs: [ty::t]) -> cres<[ty::t]> {
|
||||
super_tps(self, as, bs)
|
||||
}
|
||||
|
||||
fn self_tys(a: option<ty::t>, b: option<ty::t>) -> cres<option<ty::t>> {
|
||||
super_self_tys(self, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
impl of combine for lub {
|
||||
@ -1549,6 +1585,10 @@ fn substs(as: ty::substs, bs: ty::substs) -> cres<ty::substs> {
|
||||
fn tps(as: [ty::t], bs: [ty::t]) -> cres<[ty::t]> {
|
||||
super_tps(self, as, bs)
|
||||
}
|
||||
|
||||
fn self_tys(a: option<ty::t>, b: option<ty::t>) -> cres<option<ty::t>> {
|
||||
super_self_tys(self, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
impl of combine for glb {
|
||||
@ -1739,6 +1779,10 @@ fn substs(as: ty::substs, bs: ty::substs) -> cres<ty::substs> {
|
||||
fn tps(as: [ty::t], bs: [ty::t]) -> cres<[ty::t]> {
|
||||
super_tps(self, as, bs)
|
||||
}
|
||||
|
||||
fn self_tys(a: option<ty::t>, b: option<ty::t>) -> cres<option<ty::t>> {
|
||||
super_self_tys(self, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
// ______________________________________________________________________
|
||||
|
@ -916,7 +916,9 @@ fn field_idx_strict(cx: ty::ctxt, sp: span, ident: ast::ident,
|
||||
}
|
||||
|
||||
fn dummy_substs(tps: [ty::t]) -> ty::substs {
|
||||
{self_r: some(ty::re_bound(ty::br_self)), tps: tps}
|
||||
{self_r: some(ty::re_bound(ty::br_self)),
|
||||
self_ty: none,
|
||||
tps: tps}
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -256,7 +256,7 @@ fn make_impl_vtable(ccx: @crate_ctxt, impl_id: ast::def_id, substs: [ty::t],
|
||||
let has_tps = (*ty::lookup_item_type(ccx.tcx, impl_id).bounds).len() > 0u;
|
||||
make_vtable(ccx, vec::map(*ty::iface_methods(tcx, ifce_id)) {|im|
|
||||
let fty = ty::subst_tps(tcx, substs, ty::mk_fn(tcx, im.fty));
|
||||
if (*im.tps).len() > 0u || ty::type_has_vars(fty) {
|
||||
if (*im.tps).len() > 0u || ty::type_has_self(fty) {
|
||||
C_null(T_ptr(T_nil()))
|
||||
} else {
|
||||
let m_id = method_with_name(ccx, impl_id, im.ident);
|
||||
|
@ -457,7 +457,7 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint]) -> [u8] {
|
||||
ty::ty_fn({proto: ast::proto_bare, _}) { [shape_bare_fn] }
|
||||
ty::ty_opaque_closure_ptr(_) { [shape_opaque_closure_ptr] }
|
||||
ty::ty_constr(inner_t, _) { shape_of(ccx, inner_t, ty_param_map) }
|
||||
ty::ty_var(_) | ty::ty_self(_) {
|
||||
ty::ty_var(_) | ty::ty_self {
|
||||
ccx.sess.bug("shape_of: unexpected type struct found");
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ fn type_of_fn_from_ty(cx: @crate_ctxt, fty: ty::t) -> TypeRef {
|
||||
}
|
||||
|
||||
fn type_of_non_gc_box(cx: @crate_ctxt, t: ty::t) -> TypeRef {
|
||||
assert !ty::type_has_vars(t);
|
||||
assert !ty::type_needs_infer(t);
|
||||
|
||||
let t_norm = ty::normalize_ty(cx.tcx, t);
|
||||
if t != t_norm {
|
||||
@ -62,7 +62,7 @@ fn type_of_non_gc_box(cx: @crate_ctxt, t: ty::t) -> TypeRef {
|
||||
}
|
||||
|
||||
fn type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef {
|
||||
assert !ty::type_has_vars(t);
|
||||
assert !ty::type_needs_infer(t);
|
||||
|
||||
#debug("type_of %?: %?", t, ty::get(t));
|
||||
|
||||
@ -149,8 +149,7 @@ fn type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef {
|
||||
};
|
||||
T_struct(tys)
|
||||
}
|
||||
ty::ty_self(_) { cx.tcx.sess.unimpl("type_of: ty_self \
|
||||
not implemented"); }
|
||||
ty::ty_self { cx.tcx.sess.unimpl("type_of: ty_self"); }
|
||||
ty::ty_var(_) { cx.tcx.sess.bug("type_of shouldn't see a ty_var"); }
|
||||
}
|
||||
};
|
||||
|
@ -35,7 +35,7 @@
|
||||
export expr_ty_params_and_ty;
|
||||
export expr_is_lval;
|
||||
export field_ty;
|
||||
export fold_ty, fold_sty_to_ty, fold_region, fold_regions, fold_ty_var;
|
||||
export fold_ty, fold_sty_to_ty, fold_region, fold_regions;
|
||||
export fold_regions_and_ty, walk_regions_and_ty;
|
||||
export field;
|
||||
export field_idx;
|
||||
@ -61,7 +61,7 @@
|
||||
export sort_methods;
|
||||
export stmt_node_id;
|
||||
export sty;
|
||||
export subst, subst_tps, substs_is_noop, substs;
|
||||
export subst, subst_tps, substs_is_noop, substs_to_str, substs;
|
||||
export t;
|
||||
export new_ty_hash;
|
||||
export enum_variants, substd_enum_variants;
|
||||
@ -97,10 +97,11 @@
|
||||
export ty_uint, mk_uint, mk_mach_uint;
|
||||
export ty_uniq, mk_uniq, mk_imm_uniq, type_is_unique_box;
|
||||
export ty_var, mk_var, type_is_var;
|
||||
export ty_self, mk_self;
|
||||
export ty_self, mk_self, type_has_self;
|
||||
export region, bound_region;
|
||||
export get, type_has_params, type_has_vars, type_has_regions;
|
||||
export get, type_has_params, type_needs_infer, type_has_regions;
|
||||
export type_has_resources, type_id;
|
||||
export tbox_has_flag;
|
||||
export ty_var_id;
|
||||
export ty_to_def_id;
|
||||
export ty_fn_args;
|
||||
@ -230,12 +231,21 @@ enum ast_ty_to_ty_cache_entry {
|
||||
borrowings: hashmap<ast::node_id, ()>,
|
||||
normalized_cache: hashmap<t, t>};
|
||||
|
||||
enum tbox_flag {
|
||||
has_params = 1,
|
||||
has_self = 2,
|
||||
needs_infer = 4,
|
||||
has_regions = 8,
|
||||
has_resources = 16,
|
||||
|
||||
// a meta-flag: subst may be required if the type has parameters, a self
|
||||
// type, or references bound regions
|
||||
needs_subst = 1 | 2 | 8
|
||||
}
|
||||
|
||||
type t_box = @{struct: sty,
|
||||
id: uint,
|
||||
has_params: bool,
|
||||
has_vars: bool,
|
||||
has_regions: bool,
|
||||
has_resources: bool,
|
||||
flags: uint,
|
||||
o_def_id: option<ast::def_id>};
|
||||
|
||||
// To reduce refcounting cost, we're representing types as unsafe pointers
|
||||
@ -253,10 +263,14 @@ enum t_opaque {}
|
||||
t3
|
||||
}
|
||||
|
||||
fn type_has_params(t: t) -> bool { get(t).has_params }
|
||||
fn type_has_vars(t: t) -> bool { get(t).has_vars }
|
||||
fn type_has_regions(t: t) -> bool { get(t).has_regions }
|
||||
fn type_has_resources(t: t) -> bool { get(t).has_resources }
|
||||
fn tbox_has_flag(tb: t_box, flag: tbox_flag) -> bool {
|
||||
(tb.flags & (flag as uint)) != 0u
|
||||
}
|
||||
fn type_has_params(t: t) -> bool { tbox_has_flag(get(t), has_params) }
|
||||
fn type_has_self(t: t) -> bool { tbox_has_flag(get(t), has_self) }
|
||||
fn type_needs_infer(t: t) -> bool { tbox_has_flag(get(t), needs_infer) }
|
||||
fn type_has_regions(t: t) -> bool { tbox_has_flag(get(t), has_regions) }
|
||||
fn type_has_resources(t: t) -> bool { tbox_has_flag(get(t), has_resources) }
|
||||
fn type_def_id(t: t) -> option<ast::def_id> { get(t).o_def_id }
|
||||
fn type_id(t: t) -> uint { get(t).id }
|
||||
|
||||
@ -301,6 +315,7 @@ enum bound_region {
|
||||
// `&self.T` within the type and report an error.
|
||||
type substs = {
|
||||
self_r: opt_region,
|
||||
self_ty: option<ty::t>,
|
||||
tps: [t]
|
||||
};
|
||||
|
||||
@ -331,7 +346,7 @@ enum sty {
|
||||
|
||||
ty_var(ty_vid), // type variable during typechecking
|
||||
ty_param(uint, def_id), // type parameter
|
||||
ty_self(substs), // interface method self type
|
||||
ty_self, // special, implicit `self` type parameter
|
||||
|
||||
ty_type, // type_desc*
|
||||
ty_opaque_box, // used by monomorphizer to represent any @ box
|
||||
@ -371,7 +386,8 @@ enum type_err {
|
||||
terr_regions_differ(region, region),
|
||||
terr_vstores_differ(terr_vstore_kind, vstore, vstore),
|
||||
terr_in_field(@type_err, str),
|
||||
terr_sorts(t, t)
|
||||
terr_sorts(t, t),
|
||||
terr_self_substs
|
||||
}
|
||||
|
||||
enum param_bound {
|
||||
@ -480,95 +496,65 @@ fn mk_t_with_id(cx: ctxt, st: sty, o_def_id: option<ast::def_id>) -> t {
|
||||
some(t) { unsafe { ret unsafe::reinterpret_cast(t); } }
|
||||
_ {}
|
||||
}
|
||||
let mut has_params = false, has_vars = false, has_regions = false,
|
||||
has_resources = false;
|
||||
fn derive_flags(&has_params: bool, &has_vars: bool, &has_regions: bool,
|
||||
&has_resources: bool, tt: t) {
|
||||
let t = get(tt);
|
||||
has_params |= t.has_params;
|
||||
has_vars |= t.has_vars;
|
||||
has_regions |= t.has_regions;
|
||||
has_resources |= t.has_resources;
|
||||
}
|
||||
fn derive_rflags(&has_vars: bool, &has_regions: bool, r: region) {
|
||||
has_regions = true;
|
||||
alt r {
|
||||
ty::re_var(_) { has_vars = true; }
|
||||
_ { }
|
||||
let mut flags = 0u;
|
||||
fn rflags(r: region) -> uint {
|
||||
(has_regions as uint) | {
|
||||
alt r {
|
||||
ty::re_var(_) {needs_infer as uint}
|
||||
_ {0u}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn derive_sflags(&has_params: bool, &has_vars: bool, &has_regions: bool,
|
||||
&has_resources: bool, substs: substs) {
|
||||
for substs.tps.each {|tt|
|
||||
derive_flags(has_params, has_vars, has_regions,
|
||||
has_resources, tt);
|
||||
}
|
||||
substs.self_r.iter { |r| derive_rflags(has_vars, has_regions, r) }
|
||||
fn sflags(substs: substs) -> uint {
|
||||
let mut f = 0u;
|
||||
for substs.tps.each {|tt| f |= get(tt).flags; }
|
||||
substs.self_r.iter { |r| f |= rflags(r) }
|
||||
ret f;
|
||||
}
|
||||
alt st {
|
||||
ty_estr(vstore_slice(r)) {
|
||||
derive_rflags(has_vars, has_regions, r);
|
||||
flags |= rflags(r);
|
||||
}
|
||||
ty_evec(mt, vstore_slice(r)) {
|
||||
derive_rflags(has_vars, has_regions, r);
|
||||
derive_flags(has_params, has_vars, has_regions,
|
||||
has_resources, mt.ty);
|
||||
flags |= rflags(r);
|
||||
flags |= get(mt.ty).flags;
|
||||
}
|
||||
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) |
|
||||
ty_str | ty_estr(_) | ty_type | ty_opaque_closure_ptr(_) |
|
||||
ty_opaque_box {}
|
||||
ty_param(_, _) { has_params = true; }
|
||||
ty_var(_) | ty_self(_) { has_vars = true; }
|
||||
ty_param(_, _) { flags |= has_params as uint; }
|
||||
ty_var(_) { flags |= needs_infer as uint; }
|
||||
ty_self { flags |= has_self as uint; }
|
||||
ty_enum(_, substs) | ty_class(_, substs) | ty_iface(_, substs) {
|
||||
derive_sflags(has_params, has_vars, has_regions,
|
||||
has_resources, substs);
|
||||
flags |= sflags(substs);
|
||||
}
|
||||
ty_box(m) | ty_uniq(m) | ty_vec(m) | ty_evec(m, _) | ty_ptr(m) {
|
||||
derive_flags(has_params, has_vars, has_regions,
|
||||
has_resources, m.ty);
|
||||
flags |= get(m.ty).flags;
|
||||
}
|
||||
ty_rptr(r, m) {
|
||||
derive_rflags(has_vars, has_regions, r);
|
||||
derive_flags(has_params, has_vars, has_regions,
|
||||
has_resources, m.ty);
|
||||
flags |= rflags(r);
|
||||
flags |= get(m.ty).flags;
|
||||
}
|
||||
ty_rec(flds) {
|
||||
for flds.each {|f|
|
||||
derive_flags(has_params, has_vars, has_regions,
|
||||
has_resources, f.mt.ty);
|
||||
}
|
||||
for flds.each {|f| flags |= get(f.mt.ty).flags; }
|
||||
}
|
||||
ty_tup(ts) {
|
||||
for ts.each {|tt| derive_flags(has_params, has_vars,
|
||||
has_regions, has_resources, tt); }
|
||||
for ts.each {|tt| flags |= get(tt).flags; }
|
||||
}
|
||||
ty_fn(f) {
|
||||
for f.inputs.each {|a|
|
||||
derive_flags(has_params, has_vars, has_regions,
|
||||
has_resources, a.ty);
|
||||
}
|
||||
derive_flags(has_params, has_vars, has_regions,
|
||||
has_resources, f.output);
|
||||
for f.inputs.each {|a| flags |= get(a.ty).flags; }
|
||||
flags |= get(f.output).flags;
|
||||
}
|
||||
ty_res(_, tt, substs) {
|
||||
has_resources = true;
|
||||
derive_flags(has_params, has_vars, has_regions,
|
||||
has_resources, tt);
|
||||
derive_sflags(has_params, has_vars, has_regions,
|
||||
has_resources, substs);
|
||||
flags |= (has_resources as uint);
|
||||
flags |= get(tt).flags;
|
||||
flags |= sflags(substs);
|
||||
}
|
||||
ty_constr(tt, _) {
|
||||
derive_flags(has_params, has_vars, has_regions,
|
||||
has_resources, tt);
|
||||
flags |= get(tt).flags;
|
||||
}
|
||||
}
|
||||
let t = @{struct: st,
|
||||
id: cx.next_id,
|
||||
has_params: has_params,
|
||||
has_vars: has_vars,
|
||||
has_regions: has_regions,
|
||||
has_resources: has_resources,
|
||||
o_def_id: o_def_id};
|
||||
let t = @{struct: st, id: cx.next_id, flags: flags, o_def_id: o_def_id};
|
||||
cx.interner.insert(key, t);
|
||||
cx.next_id += 1u;
|
||||
unsafe { unsafe::reinterpret_cast(t) }
|
||||
@ -660,7 +646,7 @@ fn mk_res(cx: ctxt, did: ast::def_id,
|
||||
|
||||
fn mk_var(cx: ctxt, v: ty_vid) -> t { mk_t(cx, ty_var(v)) }
|
||||
|
||||
fn mk_self(cx: ctxt, substs: substs) -> t { mk_t(cx, ty_self(substs)) }
|
||||
fn mk_self(cx: ctxt) -> t { mk_t(cx, ty_self) }
|
||||
|
||||
fn mk_param(cx: ctxt, n: uint, k: def_id) -> t { mk_t(cx, ty_param(n, k)) }
|
||||
|
||||
@ -699,14 +685,15 @@ fn maybe_walk_ty(ty: t, f: fn(t) -> bool) {
|
||||
if !f(ty) { ret; }
|
||||
alt get(ty).struct {
|
||||
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
|
||||
ty_str | ty_estr(_) | ty_type | ty_opaque_box |
|
||||
ty_opaque_closure_ptr(_) | ty_var(_) | ty_param(_, _) {}
|
||||
ty_str | ty_estr(_) | ty_type | ty_opaque_box | ty_self |
|
||||
ty_opaque_closure_ptr(_) | ty_var(_) | ty_param(_, _) {
|
||||
}
|
||||
ty_box(tm) | ty_vec(tm) | ty_evec(tm, _) |
|
||||
ty_ptr(tm) | ty_rptr(_, tm) {
|
||||
maybe_walk_ty(tm.ty, f);
|
||||
}
|
||||
ty_enum(_, substs) | ty_class(_, substs) |
|
||||
ty_iface(_, substs) | ty_self(substs) {
|
||||
ty_iface(_, substs) {
|
||||
for substs.tps.each {|subty| maybe_walk_ty(subty, f); }
|
||||
}
|
||||
ty_rec(fields) {
|
||||
@ -733,6 +720,7 @@ fn fold_sty_to_ty(tcx: ty::ctxt, sty: sty, foldop: fn(t) -> t) -> t {
|
||||
fn fold_sty(sty: sty, fldop: fn(t) -> t) -> sty {
|
||||
fn fold_substs(substs: substs, fldop: fn(t) -> t) -> substs {
|
||||
{self_r: substs.self_r,
|
||||
self_ty: substs.self_ty.map { |t| fldop(t) },
|
||||
tps: substs.tps.map { |t| fldop(t) }}
|
||||
}
|
||||
|
||||
@ -758,9 +746,6 @@ fn fold_substs(substs: substs, fldop: fn(t) -> t) -> substs {
|
||||
ty_iface(did, substs) {
|
||||
ty_iface(did, fold_substs(substs, fldop))
|
||||
}
|
||||
ty_self(substs) {
|
||||
ty_self(fold_substs(substs, fldop))
|
||||
}
|
||||
ty_rec(fields) {
|
||||
let new_fields = vec::map(fields) {|fl|
|
||||
let new_ty = fldop(fl.mt.ty);
|
||||
@ -796,7 +781,7 @@ fn fold_substs(substs: substs, fldop: fn(t) -> t) -> substs {
|
||||
}
|
||||
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
|
||||
ty_str | ty_estr(_) | ty_type | ty_opaque_closure_ptr(_) |
|
||||
ty_opaque_box | ty_var(_) | ty_param(_, _) {
|
||||
ty_opaque_box | ty_var(_) | ty_param(*) | ty_self {
|
||||
sty
|
||||
}
|
||||
}
|
||||
@ -808,15 +793,6 @@ fn fold_ty(cx: ctxt, t0: t, fldop: fn(t) -> t) -> t {
|
||||
fldop(mk_t(cx, sty))
|
||||
}
|
||||
|
||||
fn fold_ty_var(cx: ctxt, t0: t, fldop: fn(ty_vid) -> t) -> t {
|
||||
let tb = get(t0);
|
||||
if !tb.has_vars { ret t0; }
|
||||
alt tb.struct {
|
||||
ty_var(id) { fldop(id) }
|
||||
sty { fold_sty_to_ty(cx, sty) {|t| fold_ty_var(cx, t, fldop) } }
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_regions_and_ty(
|
||||
cx: ctxt,
|
||||
ty: t,
|
||||
@ -845,6 +821,7 @@ fn fold_substs(
|
||||
fldt: fn(t: t) -> t) -> substs {
|
||||
|
||||
{self_r: substs.self_r.map { |r| fldr(r) },
|
||||
self_ty: substs.self_ty.map { |t| fldt(t) },
|
||||
tps: substs.tps.map { |t| fldt(t) }}
|
||||
}
|
||||
|
||||
@ -873,9 +850,6 @@ fn fold_substs(
|
||||
ty_iface(def_id, substs) {
|
||||
ty::mk_iface(cx, def_id, fold_substs(substs, fldr, fldt))
|
||||
}
|
||||
ty_self(substs) {
|
||||
ty::mk_self(cx, fold_substs(substs, fldr, fldt))
|
||||
}
|
||||
ty_res(def_id, t, substs) {
|
||||
ty::mk_res(cx, def_id, fldt(t),
|
||||
fold_substs(substs, fldr, fldt))
|
||||
@ -916,7 +890,7 @@ fn fold_region(cx: ctxt, t0: t, fldop: fn(region, bool) -> region) -> t {
|
||||
fn do_fold(cx: ctxt, t0: t, under_r: bool,
|
||||
fldop: fn(region, bool) -> region) -> t {
|
||||
let tb = get(t0);
|
||||
if !tb.has_regions { ret t0; }
|
||||
if !tbox_has_flag(tb, has_regions) { ret t0; }
|
||||
alt tb.struct {
|
||||
ty_rptr(r, {ty: t1, mutbl: m}) {
|
||||
let m_r = fldop(r, under_r);
|
||||
@ -951,7 +925,7 @@ fn do_fold(cx: ctxt, t0: t, under_r: bool,
|
||||
fn subst_tps(cx: ctxt, tps: [t], typ: t) -> t {
|
||||
if tps.len() == 0u { ret typ; }
|
||||
let tb = ty::get(typ);
|
||||
if !tb.has_params { ret typ; }
|
||||
if !tbox_has_flag(tb, has_params) { ret typ; }
|
||||
alt tb.struct {
|
||||
ty_param(idx, _) { tps[idx] }
|
||||
sty { fold_sty_to_ty(cx, sty) {|t| subst_tps(cx, tps, t) } }
|
||||
@ -959,12 +933,15 @@ fn subst_tps(cx: ctxt, tps: [t], typ: t) -> t {
|
||||
}
|
||||
|
||||
fn substs_is_noop(substs: substs) -> bool {
|
||||
substs.tps.len() == 0u && substs.self_r.is_none()
|
||||
substs.tps.len() == 0u &&
|
||||
substs.self_r.is_none() &&
|
||||
substs.self_ty.is_none()
|
||||
}
|
||||
|
||||
fn substs_to_str(cx: ctxt, substs: substs) -> str {
|
||||
#fmt["substs(self_r=%s, tps=%?)",
|
||||
#fmt["substs(self_r=%s, self_ty=%s, tps=%?)",
|
||||
substs.self_r.map_default("none", { |r| region_to_str(cx, r) }),
|
||||
substs.self_ty.map_default("none", { |t| ty_to_str(cx, t) }),
|
||||
substs.tps.map { |t| ty_to_str(cx, t) }]
|
||||
}
|
||||
|
||||
@ -985,20 +962,17 @@ fn do_subst(cx: ctxt,
|
||||
substs: substs,
|
||||
typ: t) -> t {
|
||||
let tb = get(typ);
|
||||
if !tb.has_params && !tb.has_regions { ret typ; }
|
||||
if !tbox_has_flag(tb, needs_subst) { ret typ; }
|
||||
alt tb.struct {
|
||||
ty_param(idx, _) { substs.tps[idx] }
|
||||
ty_param(idx, _) {substs.tps[idx]}
|
||||
ty_self {substs.self_ty.get()}
|
||||
_ {
|
||||
fold_regions_and_ty(
|
||||
cx, typ,
|
||||
{ |r|
|
||||
alt r {
|
||||
re_bound(br_self) {
|
||||
option::get(substs.self_r)
|
||||
}
|
||||
_ {
|
||||
r
|
||||
}
|
||||
re_bound(br_self) {substs.self_r.get()}
|
||||
_ {r}
|
||||
}
|
||||
},
|
||||
{ |t| do_subst(cx, substs, t) },
|
||||
@ -1406,14 +1380,14 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
|
||||
}
|
||||
lowest
|
||||
}
|
||||
// Resources are always noncopyable.
|
||||
ty_res(did, inner, tps) { kind_noncopyable }
|
||||
ty_param(_, did) {
|
||||
param_bounds_to_kind(cx.ty_param_bounds.get(did.node))
|
||||
}
|
||||
ty_constr(t, _) { type_kind(cx, t) }
|
||||
ty_var(_) { fail "FIXME"; }
|
||||
ty_self(_) { kind_noncopyable }
|
||||
ty_self { kind_noncopyable }
|
||||
|
||||
ty_var(_) { cx.sess.bug("Asked to compute kind of a type variable"); }
|
||||
};
|
||||
|
||||
cx.kind_cache.insert(ty, result);
|
||||
@ -1459,7 +1433,7 @@ fn subtypes_require(cx: ctxt, seen: @mut [def_id],
|
||||
ty_fn(_) |
|
||||
ty_var(_) |
|
||||
ty_param(_, _) |
|
||||
ty_self(_) |
|
||||
ty_self |
|
||||
ty_type |
|
||||
ty_opaque_box |
|
||||
ty_opaque_closure_ptr(_) |
|
||||
@ -1850,9 +1824,7 @@ fn hash_substs(h: uint, substs: substs) -> uint {
|
||||
}
|
||||
ty_var(v) { hash_uint(30u, v.to_uint()) }
|
||||
ty_param(pid, did) { hash_def(hash_uint(31u, pid), did) }
|
||||
ty_self(substs) {
|
||||
hash_substs(28u, substs)
|
||||
}
|
||||
ty_self { 28u }
|
||||
ty_type { 32u }
|
||||
ty_bot { 34u }
|
||||
ty_ptr(mt) { hash_subty(35u, mt.ty) }
|
||||
@ -2081,7 +2053,7 @@ fn method_lteq(a: method, b: method) -> bool {
|
||||
|
||||
fn occurs_check(tcx: ctxt, sp: span, vid: ty_vid, rt: t) {
|
||||
// Fast path
|
||||
if !type_has_vars(rt) { ret; }
|
||||
if !type_needs_infer(rt) { ret; }
|
||||
|
||||
// Occurs check!
|
||||
if vec::contains(vars_in_type(rt), vid) {
|
||||
@ -2190,7 +2162,7 @@ fn ty_sort_str(cx: ctxt, t: t) -> str {
|
||||
ty_tup(_) { "tuple" }
|
||||
ty_var(_) { "variable" }
|
||||
ty_param(_, _) { "type parameter" }
|
||||
ty_self(_) { "self" }
|
||||
ty_self { "self" }
|
||||
ty_constr(t, _) { ty_sort_str(cx, t) }
|
||||
}
|
||||
}
|
||||
@ -2274,6 +2246,9 @@ fn to_str(s: ast::ret_style) -> str {
|
||||
terr_sorts(exp, act) {
|
||||
ret #fmt("%s vs %s", ty_sort_str(cx, exp), ty_sort_str(cx, act));
|
||||
}
|
||||
terr_self_substs {
|
||||
ret "inconsistent self substitution"; // XXX this is more of a bug
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2730,7 +2705,9 @@ fn normalize_ty(cx: ctxt, t: t) -> t {
|
||||
alt r.self_r {
|
||||
some(_) {
|
||||
// This enum has a self region. Get rid of it
|
||||
mk_enum(cx, did, {self_r: none, tps: r.tps })
|
||||
mk_enum(cx, did, {self_r: none,
|
||||
self_ty: none,
|
||||
tps: r.tps})
|
||||
}
|
||||
none { t }
|
||||
}
|
||||
|
@ -272,7 +272,7 @@ fn instantiate_path(fcx: @fn_ctxt,
|
||||
pth.types.map { |aty| fcx.to_ty(aty) }
|
||||
};
|
||||
|
||||
let substs = {self_r: self_r, tps: tps};
|
||||
let substs = {self_r: self_r, self_ty: none, tps: tps};
|
||||
fcx.write_ty_substs(id, tpt.ty, substs);
|
||||
}
|
||||
|
||||
@ -340,6 +340,8 @@ fn ast_expr_vstore_to_vstore(fcx: @fn_ctxt, e: @ast::expr, n: uint,
|
||||
fn tcx() -> ty::ctxt;
|
||||
fn ccx() -> @crate_ctxt;
|
||||
fn get_item_ty(id: ast::def_id) -> ty::ty_param_bounds_and_ty;
|
||||
|
||||
// what type should we use when a type is omitted?
|
||||
fn ty_infer(span: span) -> ty::t;
|
||||
}
|
||||
|
||||
@ -536,7 +538,7 @@ fn ast_path_to_substs_and_ty<AC: ast_conv, RS: region_scope copy>(
|
||||
}
|
||||
let tps = path.types.map { |a_t| ast_ty_to_ty(self, rscope, a_t) };
|
||||
|
||||
let substs = {self_r: self_r, tps: tps};
|
||||
let substs = {self_r:self_r, self_ty:none, tps:tps};
|
||||
{substs: substs, ty: ty::subst(tcx, substs, decl_ty)}
|
||||
}
|
||||
|
||||
@ -569,9 +571,11 @@ fn instantiate_iface_ref(ccx: @crate_ctxt, t: @ast::iface_ref,
|
||||
let sp = t.path.span, err = "can only implement interface types",
|
||||
sess = ccx.tcx.sess;
|
||||
|
||||
let rscope = type_rscope(rp);
|
||||
|
||||
alt lookup_def_tcx(ccx.tcx, t.path.span, t.id) {
|
||||
ast::def_ty(t_id) {
|
||||
let tpt = ast_path_to_ty(ccx, type_rscope(rp), t_id, t.path, t.id);
|
||||
let tpt = ast_path_to_ty(ccx, rscope, t_id, t.path, t.id);
|
||||
alt ty::get(tpt.ty).struct {
|
||||
ty::ty_iface(*) {
|
||||
(t_id, tpt)
|
||||
@ -740,11 +744,11 @@ fn check_path_args(tcx: ty::ctxt,
|
||||
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
|
||||
ty::mk_param(tcx, n, id)
|
||||
}
|
||||
ast::def_self(self_id) {
|
||||
let {substs, ty: _} =
|
||||
ast_path_to_substs_and_ty(self, rscope,
|
||||
local_def(self_id), path);
|
||||
ty::mk_self(tcx, substs)
|
||||
ast::def_self(_) {
|
||||
// n.b.: resolve guarantees that the self type only appears in an
|
||||
// iface, which we rely upon in various places when creating
|
||||
// substs
|
||||
ty::mk_self(tcx)
|
||||
}
|
||||
_ {
|
||||
tcx.sess.span_fatal(ast_ty.span,
|
||||
@ -1137,30 +1141,35 @@ fn ty_of_native_fn_decl(ccx: @crate_ctxt,
|
||||
fn ty_param_bounds(ccx: @crate_ctxt,
|
||||
params: [ast::ty_param]) -> @[ty::param_bounds] {
|
||||
|
||||
fn compute_bounds(ccx: @crate_ctxt,
|
||||
param: ast::ty_param) -> ty::param_bounds {
|
||||
@vec::flat_map(*param.bounds) { |b|
|
||||
alt b {
|
||||
ast::bound_send { [ty::bound_send] }
|
||||
ast::bound_copy { [ty::bound_copy] }
|
||||
ast::bound_iface(t) {
|
||||
let ity = ast_ty_to_ty(ccx, empty_rscope, t);
|
||||
alt ty::get(ity).struct {
|
||||
ty::ty_iface(*) {
|
||||
[ty::bound_iface(ity)]
|
||||
}
|
||||
_ {
|
||||
ccx.tcx.sess.span_err(
|
||||
t.span, "type parameter bounds must be \
|
||||
interface types");
|
||||
[]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@params.map { |param|
|
||||
alt ccx.tcx.ty_param_bounds.find(param.id) {
|
||||
some(bs) { bs }
|
||||
none {
|
||||
let bounds = @vec::flat_map(*param.bounds) { |b|
|
||||
alt b {
|
||||
ast::bound_send { [ty::bound_send] }
|
||||
ast::bound_copy { [ty::bound_copy] }
|
||||
ast::bound_iface(t) {
|
||||
let ity = ccx.to_ty(empty_rscope, t);
|
||||
alt ty::get(ity).struct {
|
||||
ty::ty_iface(_, _) {
|
||||
[ty::bound_iface(ity)]
|
||||
}
|
||||
_ {
|
||||
ccx.tcx.sess.span_err(
|
||||
t.span, "type parameter bounds must be \
|
||||
interface types");
|
||||
[]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
let bounds = compute_bounds(ccx, param);
|
||||
ccx.tcx.ty_param_bounds.insert(param.id, bounds);
|
||||
bounds
|
||||
}
|
||||
@ -1354,7 +1363,7 @@ fn mk_substs(ccx: @crate_ctxt, atps: [ast::ty_param], rp: ast::region_param)
|
||||
ast::rp_self { some(ty::re_bound(ty::br_self)) }
|
||||
ast::rp_none { none }
|
||||
};
|
||||
{bounds: bounds, substs: {self_r: self_r, tps: params}}
|
||||
{bounds: bounds, substs: {self_r: self_r, self_ty: none, tps: params}}
|
||||
}
|
||||
|
||||
fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
|
||||
@ -1375,7 +1384,7 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
|
||||
} else {
|
||||
let auto_modes = vec::map2(impl_m.fty.inputs, if_m.fty.inputs, {|i, f|
|
||||
alt ty::get(f.ty).struct {
|
||||
ty::ty_param(_, _) | ty::ty_self(_)
|
||||
ty::ty_param(*) | ty::ty_self
|
||||
if alt i.mode { ast::infer(_) { true } _ { false } } {
|
||||
{mode: ast::expl(ast::by_ref) with i}
|
||||
}
|
||||
@ -1387,13 +1396,13 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
|
||||
// Add dummy substs for the parameters of the impl method
|
||||
let substs = {
|
||||
self_r: substs.self_r,
|
||||
self_ty: some(self_ty),
|
||||
tps: substs.tps + vec::from_fn(vec::len(*if_m.tps), {|i|
|
||||
ty::mk_param(tcx, i + impl_tps, {crate: 0, node: 0})
|
||||
})
|
||||
};
|
||||
let mut if_fty = ty::mk_fn(tcx, if_m.fty);
|
||||
if_fty = ty::subst(tcx, substs, if_fty);
|
||||
if_fty = fixup_self_full(tcx, if_fty, substs, self_ty, impl_tps);
|
||||
require_same_types(
|
||||
tcx, sp, impl_fty, if_fty,
|
||||
{|| "method `" + if_m.ident +
|
||||
@ -1402,104 +1411,6 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
|
||||
}
|
||||
}
|
||||
|
||||
// Mangles an iface method ty to make its self type conform to the self type
|
||||
// of a specific impl or bounded type parameter. This is rather involved
|
||||
// because the type parameters of ifaces and impls are not required to line up
|
||||
// (an impl can have less or more parameters than the iface it implements), so
|
||||
// some mangling of the substituted types is required.
|
||||
fn fixup_self_full(cx: ty::ctxt, mty: ty::t, m_substs: ty::substs,
|
||||
selfty: ty::t, impl_n_tps: uint) -> ty::t {
|
||||
|
||||
if !ty::type_has_vars(mty) { ret mty; }
|
||||
|
||||
ty::fold_ty(cx, mty) {|t|
|
||||
alt ty::get(t).struct {
|
||||
ty::ty_self(substs) if ty::substs_is_noop(substs) {
|
||||
selfty
|
||||
}
|
||||
ty::ty_self(substs) {
|
||||
// Move the substs into the type param system of the
|
||||
// context.
|
||||
let mut substs_tps = vec::map(substs.tps) {|t|
|
||||
let f = fixup_self_full(cx, t, m_substs, selfty, impl_n_tps);
|
||||
ty::subst(cx, m_substs, f)
|
||||
};
|
||||
|
||||
// Add extra substs for impl type parameters.
|
||||
while vec::len(substs_tps) < impl_n_tps {
|
||||
substs_tps += [ty::mk_param(cx, substs_tps.len(),
|
||||
{crate: 0, node: 0})];
|
||||
}
|
||||
|
||||
// And for method type parameters.
|
||||
let method_n_tps = (
|
||||
m_substs.tps.len() - substs_tps.len()) as int;
|
||||
if method_n_tps > 0 {
|
||||
substs_tps += vec::tailn(
|
||||
m_substs.tps,
|
||||
m_substs.tps.len() - (method_n_tps as uint));
|
||||
}
|
||||
|
||||
// And then instantiate the self type using all those.
|
||||
let substs_1 = {
|
||||
self_r: substs.self_r,
|
||||
tps: substs_tps
|
||||
};
|
||||
ty::subst(cx, substs_1, selfty)
|
||||
}
|
||||
_ {
|
||||
t
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mangles an iface method ty to make its self type conform to the self type
|
||||
// of a specific impl or bounded type parameter. This is rather involved
|
||||
// because the type parameters of ifaces and impls are not required to line up
|
||||
// (an impl can have less or more parameters than the iface it implements), so
|
||||
// some mangling of the substituted types is required.
|
||||
fn fixup_self_param(fcx: @fn_ctxt, mty: ty::t, m_substs: ty::substs,
|
||||
selfty: ty::t, sp: span) -> ty::t {
|
||||
if !ty::type_has_vars(mty) { ret mty; }
|
||||
|
||||
let tcx = fcx.ccx.tcx;
|
||||
ty::fold_ty(tcx, mty) {|t|
|
||||
alt ty::get(t).struct {
|
||||
ty::ty_self(substs) if ty::substs_is_noop(substs) {
|
||||
selfty
|
||||
}
|
||||
ty::ty_self(substs) {
|
||||
// Move the substs into the type param system of the context.
|
||||
let tps_p = vec::map(substs.tps) {|t|
|
||||
let f = fixup_self_param(fcx, t, m_substs, selfty, sp);
|
||||
ty::subst(tcx, m_substs, f)
|
||||
};
|
||||
let substs_p = {self_r: substs.self_r, tps: tps_p};
|
||||
let self_p = ty::mk_self(tcx, substs_p);
|
||||
let m_self = ty::mk_self(tcx, m_substs);
|
||||
demand::suptype(fcx, sp, m_self, self_p);
|
||||
selfty
|
||||
}
|
||||
_ { t }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Replaces all occurrences of the `self` region with `with_region`. Note
|
||||
// that we descend into `fn()` types here, because `fn()` does not bind the
|
||||
// `self` region.
|
||||
fn replace_self_region(tcx: ty::ctxt, with_region: ty::region,
|
||||
ty: ty::t) -> ty::t {
|
||||
|
||||
ty::fold_region(tcx, ty) {|r, _under_rptr|
|
||||
alt r {
|
||||
ty::re_bound(re_self) { with_region }
|
||||
_ { r }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Item collection - a pair of bootstrap passes:
|
||||
//
|
||||
// (1) Collect the IDs of all type items (typedefs) and store them in a table.
|
||||
@ -1932,7 +1843,7 @@ mod writeback {
|
||||
|
||||
fn resolve_type_vars_in_type(fcx: @fn_ctxt, sp: span, typ: ty::t) ->
|
||||
option<ty::t> {
|
||||
if !ty::type_has_vars(typ) { ret some(typ); }
|
||||
if !ty::type_needs_infer(typ) { ret some(typ); }
|
||||
alt infer::resolve_deep(fcx.infcx, typ, true) {
|
||||
result::ok(new_type) { ret some(new_type); }
|
||||
result::err(e) {
|
||||
@ -2571,7 +2482,8 @@ fn impl_self_ty(fcx: @fn_ctxt, did: ast::def_id) -> ty_param_substs_and_ty {
|
||||
{self_r: alt rp {
|
||||
ast::rp_self { some(fcx.next_region_var()) }
|
||||
ast::rp_none { none }},
|
||||
tps: ty::ty_params_to_tys(tcx, ts)})}
|
||||
self_ty: none,
|
||||
tps: ty::ty_params_to_tys(tcx, ts)})}
|
||||
}
|
||||
_ { tcx.sess.bug("impl_self_ty: unbound item or item that \
|
||||
doesn't have a self_ty"); }
|
||||
@ -2589,7 +2501,7 @@ fn impl_self_ty(fcx: @fn_ctxt, did: ast::def_id) -> ty_param_substs_and_ty {
|
||||
};
|
||||
let tps = fcx.next_ty_vars(n_tps);
|
||||
|
||||
let substs = {self_r: self_r, tps: tps};
|
||||
let substs = {self_r: self_r, self_ty: none, tps: tps};
|
||||
let substd_ty = ty::subst(tcx, substs, raw_ty);
|
||||
{substs: substs, ty: substd_ty}
|
||||
}
|
||||
@ -2657,8 +2569,18 @@ fn method_from_param(n: uint, did: ast::def_id) -> option<method_origin> {
|
||||
}
|
||||
|
||||
some(pos) {
|
||||
// Replace any appearance of `self` with the type of the
|
||||
// generic parameter itself. Note that this is the only case
|
||||
// where this replacement is necessary: in all other cases, we
|
||||
// are either invoking a method directly from an impl or class
|
||||
// (where the self type is not permitted), or from a iface
|
||||
// type (in which case methods that refer to self are not
|
||||
// permitted).
|
||||
let substs = {self_ty: some(self.self_ty)
|
||||
with bound_substs};
|
||||
|
||||
ret some(self.write_mty_from_m(
|
||||
some(self.self_ty), bound_substs, ifce_methods[pos],
|
||||
substs, ifce_methods[pos],
|
||||
method_param(iid, pos, n, iface_bnd_idx)));
|
||||
}
|
||||
}
|
||||
@ -2675,23 +2597,28 @@ fn method_from_iface(
|
||||
|
||||
let m_fty = ty::mk_fn(self.tcx(), m.fty);
|
||||
|
||||
if ty::type_has_vars(m_fty) {
|
||||
self.tcx().sess.span_fatal(
|
||||
if ty::type_has_self(m_fty) {
|
||||
self.tcx().sess.span_err(
|
||||
self.expr.span,
|
||||
"can not call a method that contains a \
|
||||
self type through a boxed iface");
|
||||
}
|
||||
|
||||
if (*m.tps).len() > 0u {
|
||||
self.tcx().sess.span_fatal(
|
||||
self.tcx().sess.span_err(
|
||||
self.expr.span,
|
||||
"can not call a generic method through a \
|
||||
boxed iface");
|
||||
}
|
||||
|
||||
// Note: although it is illegal to invoke a method that uses self
|
||||
// through a iface instance, we use a dummy subst here so that we
|
||||
// can soldier on with the compilation.
|
||||
let substs = {self_ty: some(self.self_ty)
|
||||
with iface_substs};
|
||||
|
||||
ret some(self.write_mty_from_m(
|
||||
none, iface_substs, m,
|
||||
method_iface(did, i)));
|
||||
substs, m, method_iface(did, i)));
|
||||
}
|
||||
|
||||
ret none;
|
||||
@ -2717,7 +2644,7 @@ fn method_from_class(did: ast::def_id, class_substs: ty::substs)
|
||||
self.tcx(), did, self.m_name, self.expr.span);
|
||||
|
||||
ret some(self.write_mty_from_m(
|
||||
none, class_substs, m,
|
||||
class_substs, m,
|
||||
method_static(m_declared)));
|
||||
}
|
||||
|
||||
@ -2813,7 +2740,7 @@ fn method_from_scope() -> option<method_origin> {
|
||||
let (self_substs, n_tps, did) = results[0];
|
||||
let fty = self.ty_from_did(did);
|
||||
ret some(self.write_mty_from_fty(
|
||||
none, self_substs, n_tps, fty,
|
||||
self_substs, n_tps, fty,
|
||||
method_static(did)));
|
||||
}
|
||||
}
|
||||
@ -2821,8 +2748,7 @@ fn method_from_scope() -> option<method_origin> {
|
||||
ret none;
|
||||
}
|
||||
|
||||
fn write_mty_from_m(self_ty_sub: option<ty::t>,
|
||||
self_substs: ty::substs,
|
||||
fn write_mty_from_m(self_substs: ty::substs,
|
||||
m: ty::method,
|
||||
origin: method_origin) -> method_origin {
|
||||
let tcx = self.fcx.ccx.tcx;
|
||||
@ -2831,18 +2757,16 @@ fn write_mty_from_m(self_ty_sub: option<ty::t>,
|
||||
// a.b has a protocol like fn@() (perhaps eventually fn&()):
|
||||
let fty = ty::mk_fn(tcx, {proto: ast::proto_box with m.fty});
|
||||
|
||||
ret self.write_mty_from_fty(self_ty_sub, self_substs,
|
||||
(*m.tps).len(), fty, origin);
|
||||
ret self.write_mty_from_fty(self_substs, (*m.tps).len(),
|
||||
fty, origin);
|
||||
}
|
||||
|
||||
fn write_mty_from_fty(self_ty_sub: option<ty::t>,
|
||||
self_substs: ty::substs,
|
||||
fn write_mty_from_fty(self_substs: ty::substs,
|
||||
n_tps_m: uint,
|
||||
fty: ty::t,
|
||||
origin: method_origin) -> method_origin {
|
||||
|
||||
let tcx = self.fcx.ccx.tcx;
|
||||
let has_self = ty::type_has_vars(fty);
|
||||
|
||||
// Here I will use the "c_" prefix to refer to the method's
|
||||
// owner. You can read it as class, but it may also be an iface.
|
||||
@ -2867,26 +2791,11 @@ fn write_mty_from_fty(self_ty_sub: option<ty::t>,
|
||||
}
|
||||
};
|
||||
|
||||
let all_substs = {self_r: self_substs.self_r,
|
||||
tps: self_substs.tps + m_substs};
|
||||
let all_substs = {tps: self_substs.tps + m_substs
|
||||
with self_substs};
|
||||
|
||||
self.fcx.write_ty_substs(self.node_id, fty, all_substs);
|
||||
|
||||
// n.b. This treatment of self is risky but ok. As a rule of thumb,
|
||||
// one ought to substitute all type parameters at once, and we are not
|
||||
// doing so here. The danger you open up has to do with the
|
||||
// possibility that one of the substs in `all_substs` maps to a self
|
||||
// type. However, right now I think it is safe because the types in
|
||||
// `all_substs` may not refer to self. This may not stay true
|
||||
// forever, though.
|
||||
|
||||
if has_self && !option::is_none(self_ty_sub) {
|
||||
let fty = self.fcx.node_ty(self.node_id);
|
||||
let fty = fixup_self_param(
|
||||
self.fcx, fty, all_substs, self_ty_sub.get(),
|
||||
self.expr.span);
|
||||
self.fcx.write_ty(self.node_id, fty);
|
||||
}
|
||||
|
||||
ret origin;
|
||||
}
|
||||
}
|
||||
@ -4697,13 +4606,13 @@ fn lookup_vtables(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
|
||||
}
|
||||
|
||||
fn fixup_substs(fcx: @fn_ctxt, sp: span,
|
||||
substs: ty::substs) -> ty::substs {
|
||||
id: ast::def_id, substs: ty::substs) -> ty::substs {
|
||||
let tcx = fcx.ccx.tcx;
|
||||
// use a dummy type just to package up the substs that need fixing up
|
||||
let t = ty::mk_self(tcx, substs);
|
||||
let t = ty::mk_iface(tcx, id, substs);
|
||||
let t_f = fixup_ty(fcx, sp, t);
|
||||
alt check ty::get(t_f).struct {
|
||||
ty::ty_self(substs_f) { substs_f }
|
||||
ty::ty_iface(_, substs_f) { substs_f }
|
||||
}
|
||||
}
|
||||
|
||||
@ -4754,7 +4663,7 @@ fn lookup_vtable(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
|
||||
relate_iface_tys(fcx, sp, iface_ty, ty);
|
||||
if !allow_unsafe {
|
||||
for vec::each(*ty::iface_methods(tcx, did)) {|m|
|
||||
if ty::type_has_vars(ty::mk_fn(tcx, m.fty)) {
|
||||
if ty::type_has_self(ty::mk_fn(tcx, m.fty)) {
|
||||
tcx.sess.span_err(
|
||||
sp, "a boxed iface with self types may not be \
|
||||
passed as a bounded type");
|
||||
@ -4804,7 +4713,7 @@ fn lookup_vtable(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
|
||||
|
||||
// recursively process the bounds
|
||||
let iface_tps = iface_substs.tps;
|
||||
let substs_f = fixup_substs(fcx, sp, substs);
|
||||
let substs_f = fixup_substs(fcx, sp, iface_id, substs);
|
||||
connect_iface_tps(fcx, sp, substs_f.tps,
|
||||
iface_tps, im.did);
|
||||
let subres = lookup_vtables(fcx, isc, sp,
|
||||
|
@ -97,7 +97,7 @@ fn fn_input_to_str(cx: ctxt, input: {mode: ast::mode, ty: t}) ->
|
||||
let modestr = alt canon_mode(cx, mode) {
|
||||
ast::infer(_) { "" }
|
||||
ast::expl(m) {
|
||||
if !ty::type_has_vars(ty) &&
|
||||
if !ty::type_needs_infer(ty) &&
|
||||
m == ty::default_arg_mode_for_ty(ty) {
|
||||
""
|
||||
} else {
|
||||
@ -185,9 +185,7 @@ fn field_to_str(cx: ctxt, f: field) -> str {
|
||||
ty_param(id, _) {
|
||||
"'" + str::from_bytes([('a' as u8) + (id as u8)])
|
||||
}
|
||||
ty_self(substs) {
|
||||
parameterized(cx, "self", substs.self_r, substs.tps)
|
||||
}
|
||||
ty_self { "self" }
|
||||
ty_enum(did, substs) | ty_res(did, _, substs) | ty_class(did, substs) {
|
||||
let path = ty::item_path(cx, did);
|
||||
let base = ast_map::path_to_str(path);
|
||||
|
@ -1,7 +1,4 @@
|
||||
iface monad<A> {
|
||||
fn bind<B>(fn(A) -> self<B>);
|
||||
}
|
||||
impl monad<A> of monad<A> for [A] {
|
||||
impl monad<A> for [A] {
|
||||
fn bind<B>(f: fn(A) -> [B]) {
|
||||
let mut r = fail;
|
||||
for self.each {|elt| r += f(elt); }
|
||||
|
15
src/test/compile-fail/selftype-astparam.rs
Normal file
15
src/test/compile-fail/selftype-astparam.rs
Normal file
@ -0,0 +1,15 @@
|
||||
iface add {
|
||||
fn +(x: self) -> self;
|
||||
}
|
||||
|
||||
impl of add for int {
|
||||
fn +(x: int) -> int { self + x }
|
||||
}
|
||||
|
||||
fn do_add<A:add>(x: A, y: A) -> A { x + y }
|
||||
|
||||
fn main() {
|
||||
let x = 3 as add;
|
||||
let y = 4 as add;
|
||||
do_add(x, y); //! ERROR a boxed iface with self types may not be passed as a bounded type
|
||||
}
|
9
src/test/compile-fail/selftype-ifacetype.rs
Normal file
9
src/test/compile-fail/selftype-ifacetype.rs
Normal file
@ -0,0 +1,9 @@
|
||||
iface add {
|
||||
fn +(x: self) -> self;
|
||||
}
|
||||
|
||||
fn do_add(x: add, y: add) -> add {
|
||||
x + y //! ERROR can not call a method that contains a self type through a boxed iface
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -1,8 +1,4 @@
|
||||
iface monad<A> {
|
||||
fn bind<B>(fn(A) -> self<B>) -> self<B>;
|
||||
}
|
||||
|
||||
impl <A> of monad<A> for [A] {
|
||||
impl monad<A> for [A] {
|
||||
fn bind<B>(f: fn(A) -> [B]) -> [B] {
|
||||
let mut r = [];
|
||||
for self.each {|elt| r += f(elt); }
|
||||
@ -10,7 +6,7 @@ fn bind<B>(f: fn(A) -> [B]) -> [B] {
|
||||
}
|
||||
}
|
||||
|
||||
impl <A> of monad<A> for option<A> {
|
||||
impl monad<A> for option<A> {
|
||||
fn bind<B>(f: fn(A) -> option<B>) -> option<B> {
|
||||
alt self {
|
||||
some(a) { f(a) }
|
||||
|
19
src/test/run-pass/selftype-add-ints.rs
Normal file
19
src/test/run-pass/selftype-add-ints.rs
Normal file
@ -0,0 +1,19 @@
|
||||
iface add {
|
||||
fn +(x: self) -> self;
|
||||
}
|
||||
|
||||
impl of add for int {
|
||||
fn +(x: int) -> int { self + x }
|
||||
}
|
||||
|
||||
impl of add for @const int {
|
||||
fn +(x: @const int) -> @const int { @(*self + *x) }
|
||||
}
|
||||
|
||||
fn do_add<A:add>(+x: A, +y: A) -> A { x + y }
|
||||
|
||||
fn main() {
|
||||
assert do_add(3, 4) == 7;
|
||||
assert do_add(@3, @4) == @7;
|
||||
assert do_add(@mut 3, @mut 4) == @mut 7;
|
||||
}
|
Loading…
Reference in New Issue
Block a user