1
Fork 0

refactor fixup_self

This commit is contained in:
Niko Matsakis 2012-04-11 13:10:35 -07:00
parent c1c60c023e
commit 3e6943d820
2 changed files with 90 additions and 59 deletions

View file

@ -934,10 +934,7 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
});
let mut if_fty = ty::mk_fn(tcx, if_m.fty);
if_fty = ty::substitute_type_params(tcx, substs, if_fty);
if ty::type_has_vars(if_fty) {
if_fty = fixup_self_in_method_ty(tcx, if_fty, substs,
self_full(self_ty, impl_tps));
}
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 +
@ -946,61 +943,84 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
}
}
enum self_subst { self_param(ty::t, @fn_ctxt, span), self_full(ty::t, uint) }
// 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::t],
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(tps) if vec::len(tps) == 0u {
selfty
}
ty::ty_self(tps) {
// Move the substs into the type param system of the
// context.
let mut substs = vec::map(tps) {|t|
let f = fixup_self_full(cx, t, m_substs, selfty, impl_n_tps);
ty::substitute_type_params(cx, m_substs, f)
};
// Add extra substs for impl type parameters.
while vec::len(substs) < impl_n_tps {
substs += [ty::mk_param(cx, vec::len(substs),
{crate: 0, node: 0})];
}
// And for method type parameters.
let method_n_tps =
(vec::len(m_substs) - vec::len(tps)) as int;
if method_n_tps > 0 {
substs += vec::tailn(m_substs, vec::len(m_substs)
- (method_n_tps as uint));
}
// And then instantiate the self type using all those.
ty::substitute_type_params(cx, substs, 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_in_method_ty(cx: ty::ctxt, mty: ty::t, m_substs: [ty::t],
self: self_subst) -> ty::t {
if ty::type_has_vars(mty) {
ty::fold_ty(cx, mty) {|t|
alt ty::get(t).struct {
ty::ty_self(tps) {
if vec::len(tps) > 0u {
// Move the substs into the type param system of the
// context.
let mut substs = vec::map(tps, {|t|
let f = fixup_self_in_method_ty(cx, t, m_substs,
self);
ty::substitute_type_params(cx, m_substs, f)
});
alt self {
self_param(t, fcx, sp) {
// Simply ensure that the type parameters for the self
// type match the context.
vec::iter2(substs, m_substs) {|s, ms|
demand::simple(fcx, sp, s, ms);
}
t
}
self_full(selfty, impl_n_tps) {
// Add extra substs for impl type parameters.
while vec::len(substs) < impl_n_tps {
substs += [ty::mk_param(cx, vec::len(substs),
{crate: 0, node: 0})];
}
// And for method type parameters.
let method_n_tps =
(vec::len(m_substs) - vec::len(tps)) as int;
if method_n_tps > 0 {
substs += vec::tailn(m_substs, vec::len(m_substs)
- (method_n_tps as uint));
}
// And then instantiate the self type using all those.
ty::substitute_type_params(cx, substs, selfty)
}
}
} else {
alt self { self_param(t, _, _) | self_full(t, _) { t } }
}
}
_ { t }
fn fixup_self_param(fcx: @fn_ctxt, mty: ty::t, m_substs: [ty::t],
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(tps) if vec::len(tps) == 0u { selfty }
ty::ty_self(tps) {
// Move the substs into the type param system of the
// context.
let mut substs = vec::map(tps) {|t|
let f = fixup_self_param(fcx, t, m_substs, selfty, sp);
ty::substitute_type_params(tcx, m_substs, f)
};
// Simply ensure that the type parameters for the self
// type match the context.
vec::iter2(substs, m_substs) {|s, ms|
demand::simple(fcx, sp, s, ms);
}
selfty
}
_ { t }
}
} else { mty }
}
}
// Replaces all occurrences of the `self` region with `with_region`. Note
@ -2190,6 +2210,10 @@ fn impl_self_ty(tcx: ty::ctxt, did: ast::def_id) -> {n_tps: uint, ty: ty::t} {
}
}
type self_subst = {selfty: ty::t,
fcx: @fn_ctxt,
sp: span};
/*
Takes arguments describing a method, and returns either its origin,
or <none> if it's unbound.
@ -2249,8 +2273,8 @@ fn lookup_method(fcx: @fn_ctxt, expr: @ast::expr, node_id: ast::node_id,
}
if has_self && !option::is_none(self_sub) {
let fty = fcx.node_ty(node_id);
let fty = fixup_self_in_method_ty(
tcx, fty, substs, option::get(self_sub));
let fty = fixup_self_param(
fcx, fty, substs, option::get(self_sub), expr.span);
fcx.write_ty(node_id, fty);
}
if ty::type_has_rptrs(ty::ty_fn_ret(fty)) {
@ -2273,8 +2297,11 @@ enum method_kind {
fn lookup_method_inner_(tcx: ty::ctxt, ms: [ty::method],
tps: [ty::t], parent: method_kind, name: ast::ident, sp: span,
include_private: bool)
-> option<{method_ty: ty::t, n_tps: uint, substs: [ty::t],
origin: method_origin, self_sub: option<self_subst>}> {
-> option<{method_ty: ty::t,
n_tps: uint,
substs: [ty::t],
origin: method_origin,
self_sub: option<ty::t>}> {
let mut i = 0u;
for ms.each {|m|
if m.ident == name {
@ -2318,9 +2345,11 @@ fn lookup_method_inner_(tcx: ty::ctxt, ms: [ty::method],
fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr,
name: ast::ident, ty: ty::t,
include_private: bool)
-> option<{method_ty: ty::t, n_tps: uint, substs: [ty::t],
origin: method_origin,
self_sub: option<self_subst>}> {
-> option<{method_ty: ty::t,
n_tps: uint,
substs: [ty::t],
origin: method_origin,
self_sub: option<ty::t>}> {
let tcx = fcx.ccx.tcx;
#debug["lookup_method_inner: expr=%s name=%s ty=%s",
@ -2345,7 +2374,7 @@ fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr,
n_tps: vec::len(*m.tps),
substs: tps,
origin: method_param(iid, pos, n, bound_n),
self_sub: some(self_param(ty, fcx, expr.span))
self_sub: some(ty)
});
}
_ {}

View file

@ -1,3 +1,5 @@
// xfail-test
fn foo(x: &uint) -> &uint { x }
fn main() {