reduce self type to a special type parameter

This commit is contained in:
Niko Matsakis 2012-05-09 06:09:58 -07:00
parent d41af13334
commit 5e7229b72c
15 changed files with 289 additions and 324 deletions

View File

@ -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)); }

View File

@ -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&"/&); }

View File

@ -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)
}
}
// ______________________________________________________________________

View File

@ -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}
}
//

View File

@ -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);

View File

@ -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");
}
}

View File

@ -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"); }
}
};

View File

@ -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 }
}

View File

@ -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,

View File

@ -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);

View File

@ -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); }

View 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
}

View 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() {}

View File

@ -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) }

View 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;
}