提交 7512284a 编写于 作者: N Niko Matsakis

further modularization of typeck, add comments

上级 8cc596ce
此差异已折叠。
#[doc = "
Conversion from AST representation of types to the ty.rs representation.
The main routine here is `ast_ty_to_ty()`: each use is parameterized
by an instance of `ast_conv` and a `region_scope`.
The `ast_conv` interface is the conversion context. It has two
implementations, one for the crate context and one for the function
context. The main purpose is to provide the `get_item_ty()` hook
which looks up the type of an item by its def-id. This can be done in
two ways: in the initial phase, when a crate context is provided, this
will potentially trigger a call to `ty_of_item()`. Later, when a
function context is used, this will simply be a lookup.
Conversion from AST representation of types to the ty.rs
representation. The main routine here is `ast_ty_to_ty()`: each use
is parameterized by an instance of `ast_conv` and a `region_scope`.
The parameterization of `ast_ty_to_ty()` is because it behaves
somewhat differently during the collect and check phases, particularly
with respect to looking up the types of top-level items. In the
collect phase, the crate context is used as the `ast_conv` instance;
in this phase, the `get_item_ty()` function triggers a recursive call
to `ty_of_item()` (note that `ast_ty_to_ty()` will detect recursive
types and report an error). In the check phase, when the @fn_ctxt is
used as the `ast_conv`, `get_item_ty()` just looks up the item type in
`tcx.tcache`.
The `region_scope` interface controls how region references are
handled. It has two methods which are used to resolve anonymous
......@@ -21,8 +22,30 @@
region, or `type_rscope`, which permits the self region if the type in
question is parameterized by a region.
Unlike the `ast_conv` iface, the region scope can change as we descend
the type. This is to accommodate the fact that (a) fn types are binding
scopes and (b) the default region may change. To understand case (a),
consider something like:
type foo = { x: &a.int, y: fn(&a.int) }
The type of `x` is an error because there is no region `a` in scope.
In the type of `y`, however, region `a` is considered a bound region
as it does not already appear in scope.
Case (b) says that if you have a type:
type foo/& = ...;
type bar = fn(&foo, &a.foo)
The fully expanded version of type bar is:
type bar = fn(&foo/&, &a.foo/&a)
Note that the self region for the `foo` defaulted to `&` in the first
case but `&a` in the second. Basically, defaults that appear inside
an rptr (`&r.T`) use the region `r` that appears in the rptr.
"];
import check::fn_ctxt;
iface ast_conv {
fn tcx() -> ty::ctxt;
fn ccx() -> @crate_ctxt;
......@@ -32,48 +55,6 @@
fn ty_infer(span: span) -> ty::t;
}
impl of ast_conv for @crate_ctxt {
fn tcx() -> ty::ctxt { self.tcx }
fn ccx() -> @crate_ctxt { self }
fn get_item_ty(id: ast::def_id) -> ty::ty_param_bounds_and_ty {
if id.crate != ast::local_crate {
csearch::get_type(self.tcx, id)
} else {
alt self.tcx.items.find(id.node) {
some(ast_map::node_item(item, _)) {
ty_of_item(self, item)
}
some(ast_map::node_native_item(native_item, _, _)) {
ty_of_native_item(self, native_item)
}
x {
self.tcx.sess.bug(#fmt["unexpected sort of item \
in get_item_ty(): %?", x]);
}
}
}
}
fn ty_infer(span: span) -> ty::t {
self.tcx.sess.span_bug(span,
"found `ty_infer` in unexpected place");
}
}
impl of ast_conv for @fn_ctxt {
fn tcx() -> ty::ctxt { self.ccx.tcx }
fn ccx() -> @crate_ctxt { self.ccx }
fn get_item_ty(id: ast::def_id) -> ty::ty_param_bounds_and_ty {
ty::lookup_item_type(self.tcx(), id)
}
fn ty_infer(_span: span) -> ty::t {
self.next_ty_var()
}
}
iface region_scope {
fn anon_region() -> result<ty::region, str>;
fn named_region(id: str) -> result<ty::region, str>;
......@@ -112,23 +93,6 @@ fn named_region(id: str) -> result<ty::region, str> {
}
}
impl of region_scope for @fn_ctxt {
fn anon_region() -> result<ty::region, str> {
result::ok(self.next_region_var())
}
fn named_region(id: str) -> result<ty::region, str> {
empty_rscope.named_region(id).chain_err { |_e|
alt self.in_scope_regions.find(ty::br_named(id)) {
some(r) { result::ok(r) }
none if id == "blk" { self.block_region() }
none {
result::err(#fmt["named region `%s` not in scope here", id])
}
}
}
}
}
enum anon_rscope = {anon: ty::region, base: region_scope};
fn in_anon_rscope<RS: region_scope copy>(self: RS, r: ty::region)
-> @anon_rscope {
......@@ -159,6 +123,19 @@ fn named_region(id: str) -> result<ty::region, str> {
}
}
fn get_region_reporting_err(tcx: ty::ctxt,
span: span,
res: result<ty::region, str>) -> ty::region {
alt res {
result::ok(r) { r }
result::err(e) {
tcx.sess.span_err(span, e);
ty::re_static
}
}
}
fn ast_region_to_region<AC: ast_conv, RS: region_scope>(
self: AC, rscope: RS, span: span, a_r: @ast::region) -> ty::region {
......@@ -233,36 +210,6 @@ fn ast_path_to_ty<AC: ast_conv, RS: region_scope copy>(
ret {substs: substs, ty: ty};
}
/*
Instantiates the path for the given iface reference, assuming that
it's bound to a valid iface type. Returns the def_id for the defining
iface. Fails if the type is a type other than an iface type.
*/
fn instantiate_iface_ref(ccx: @crate_ctxt, t: @ast::iface_ref,
rp: ast::region_param)
-> (ast::def_id, ty_param_substs_and_ty) {
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, rscope, t_id, t.path, t.id);
alt ty::get(tpt.ty).struct {
ty::ty_iface(*) {
(t_id, tpt)
}
_ { sess.span_fatal(sp, err); }
}
}
_ {
sess.span_fatal(sp, err);
}
}
}
const NO_REGIONS: uint = 1u;
const NO_TPS: uint = 2u;
......@@ -474,103 +421,6 @@ fn check_path_args(tcx: ty::ctxt,
ret typ;
}
fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
-> ty::ty_param_bounds_and_ty {
let def_id = local_def(it.id);
let tcx = ccx.tcx;
alt tcx.tcache.find(def_id) {
some(tpt) { ret tpt; }
_ {}
}
alt it.node {
ast::item_const(t, _) {
let typ = ccx.to_ty(empty_rscope, t);
let tpt = no_params(typ);
tcx.tcache.insert(local_def(it.id), tpt);
ret tpt;
}
ast::item_fn(decl, tps, _) {
let bounds = ty_param_bounds(ccx, tps);
let tofd = ty_of_fn_decl(ccx, empty_rscope, ast::proto_bare,
decl, none);
let tpt = {bounds: bounds,
rp: ast::rp_none, // functions do not have a self
ty: ty::mk_fn(ccx.tcx, tofd)};
ccx.tcx.tcache.insert(local_def(it.id), tpt);
ret tpt;
}
ast::item_ty(t, tps, rp) {
alt tcx.tcache.find(local_def(it.id)) {
some(tpt) { ret tpt; }
none { }
}
let tpt = {
let ty = {
let t0 = ccx.to_ty(type_rscope(rp), t);
// Do not associate a def id with a named, parameterized type
// like "foo<X>". This is because otherwise ty_to_str will
// print the name as merely "foo", as it has no way to
// reconstruct the value of X.
if !vec::is_empty(tps) { t0 } else {
ty::mk_with_id(tcx, t0, def_id)
}
};
{bounds: ty_param_bounds(ccx, tps), rp: rp, ty: ty}
};
check_bounds_are_used(ccx, t.span, tps, rp, tpt.ty);
tcx.tcache.insert(local_def(it.id), tpt);
ret tpt;
}
ast::item_res(decl, tps, _, _, _, rp) {
let {bounds, substs} = mk_substs(ccx, tps, rp);
let t_arg = ty_of_arg(ccx, type_rscope(rp),
decl.inputs[0], none);
let t = ty::mk_res(tcx, local_def(it.id), t_arg.ty, substs);
let t_res = {bounds: bounds, rp: rp, ty: t};
tcx.tcache.insert(local_def(it.id), t_res);
ret t_res;
}
ast::item_enum(_, tps, rp) {
// Create a new generic polytype.
let {bounds, substs} = mk_substs(ccx, tps, rp);
let t = ty::mk_enum(tcx, local_def(it.id), substs);
let tpt = {bounds: bounds, rp: rp, ty: t};
tcx.tcache.insert(local_def(it.id), tpt);
ret tpt;
}
ast::item_iface(tps, rp, ms) {
let {bounds, substs} = mk_substs(ccx, tps, rp);
let t = ty::mk_iface(tcx, local_def(it.id), substs);
let tpt = {bounds: bounds, rp: rp, ty: t};
tcx.tcache.insert(local_def(it.id), tpt);
ret tpt;
}
ast::item_class(tps, _, _, _, _, rp) {
let {bounds,substs} = mk_substs(ccx, tps, rp);
let t = ty::mk_class(tcx, local_def(it.id), substs);
let tpt = {bounds: bounds, rp: rp, ty: t};
tcx.tcache.insert(local_def(it.id), tpt);
ret tpt;
}
ast::item_impl(*) | ast::item_mod(_) |
ast::item_native_mod(_) { fail; }
}
}
fn ty_of_native_item(ccx: @crate_ctxt, it: @ast::native_item)
-> ty::ty_param_bounds_and_ty {
alt it.node {
ast::native_item_fn(fn_decl, params) {
ret ty_of_native_fn_decl(ccx, fn_decl, params,
local_def(it.id));
}
}
}
fn ty_of_arg<AC: ast_conv, RS: region_scope copy>(
self: AC, rscope: RS, a: ast::arg,
expected_ty: option<ty::arg>) -> ty::arg {
......@@ -651,61 +501,3 @@ fn ty_of_fn_decl<AC: ast_conv, RS: region_scope copy>(
}
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 = compute_bounds(ccx, param);
ccx.tcx.ty_param_bounds.insert(param.id, bounds);
bounds
}
}
}
}
fn ty_of_native_fn_decl(ccx: @crate_ctxt,
decl: ast::fn_decl,
ty_params: [ast::ty_param],
def_id: ast::def_id) -> ty::ty_param_bounds_and_ty {
let bounds = ty_param_bounds(ccx, ty_params);
let rb = in_binding_rscope(empty_rscope);
let input_tys = decl.inputs.map { |a| ty_of_arg(ccx, rb, a, none) };
let output_ty = ast_ty_to_ty(ccx, rb, decl.output);
let t_fn = ty::mk_fn(ccx.tcx, {proto: ast::proto_bare,
inputs: input_tys,
output: output_ty,
ret_style: ast::return_val,
constraints: []});
let tpt = {bounds: bounds, rp: ast::rp_none, ty: t_fn};
ccx.tcx.tcache.insert(def_id, tpt);
ret tpt;
}
此差异已折叠。
import astconv::{type_rscope, instantiate_iface_ref, ty_of_item,
empty_rscope, ty_of_native_item, ast_conv};
// Item collection - a pair of bootstrap passes:
//
// (1) Collect the IDs of all type items (typedefs) and store them in a table.
//
// (2) Translate the AST fragments that describe types to determine a type for
// each item. When we encounter a named type, we consult the table built
// in pass 1 to find its item, and recursively translate it.
//
// We then annotate the AST with the resulting types and return the annotated
// AST, along with a table mapping item IDs to their types.
/*
# Collect phase
The collect phase of type check has the job of visiting all items,
determining their type, and writing that type into the `tcx.tcache`
table. Despite its name, this table does not really operate as a
*cache*, at least not for the types of items defined within the
current crate: we assume that after the collect phase, the types of
all local items will be present in the table.
Unlike most of the types that are present in Rust, the types computed
for each item are in fact polytypes. In "layman's terms", this means
that they are generic types that may have type parameters (more
mathematically phrased, they are universally quantified over a set of
type parameters). Polytypes are represented by an instance of
`ty::ty_param_bounds_and_ty`. This combines the core type along with
a list of the bounds for each parameter. Type parameters themselves
are represented as `ty_param()` instances.
*/
import astconv::{type_rscope, empty_rscope, in_binding_rscope, ast_conv,
ty_of_fn_decl, ty_of_arg, region_scope, ast_ty_to_ty};
fn collect_item_types(ccx: @crate_ctxt, crate: @ast::crate) {
visit::visit_crate(*crate, (), visit::mk_simple_visitor(@{
visit_item: bind convert(ccx, _),
visit_native_item: bind convert_native(ccx, _)
with *visit::default_simple_visitor()
}));
}
impl methods for @crate_ctxt {
fn to_ty<RS: region_scope copy>(rs: RS, ast_ty: @ast::ty) -> ty::t {
ast_ty_to_ty(self, rs, ast_ty)
}
}
impl of ast_conv for @crate_ctxt {
fn tcx() -> ty::ctxt { self.tcx }
fn ccx() -> @crate_ctxt { self }
fn get_item_ty(id: ast::def_id) -> ty::ty_param_bounds_and_ty {
if id.crate != ast::local_crate {
csearch::get_type(self.tcx, id)
} else {
alt self.tcx.items.find(id.node) {
some(ast_map::node_item(item, _)) {
ty_of_item(self, item)
}
some(ast_map::node_native_item(native_item, _, _)) {
ty_of_native_item(self, native_item)
}
x {
self.tcx.sess.bug(#fmt["unexpected sort of item \
in get_item_ty(): %?", x]);
}
}
}
}
fn ty_infer(span: span) -> ty::t {
self.tcx.sess.span_bug(span,
"found `ty_infer` in unexpected place");
}
}
fn get_enum_variant_types(ccx: @crate_ctxt,
enum_ty: ty::t,
variants: [ast::variant],
......@@ -36,7 +91,7 @@ fn get_enum_variant_types(ccx: @crate_ctxt,
ret_style: ast::return_val,
constraints: []})
};
let tpt = {bounds: astconv::ty_param_bounds(ccx, ty_params),
let tpt = {bounds: ty_param_bounds(ccx, ty_params),
rp: rp,
ty: result_ty};
tcx.tcache.insert(local_def(variant.node.id), tpt);
......@@ -68,6 +123,51 @@ fn store_methods<T>(ccx: @crate_ctxt, id: ast::node_id,
}
}
fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
impl_tps: uint, if_m: ty::method, substs: ty::substs,
self_ty: ty::t) -> ty::t {
if impl_m.tps != if_m.tps {
tcx.sess.span_err(sp, "method `" + if_m.ident +
"` has an incompatible set of type parameters");
ty::mk_fn(tcx, impl_m.fty)
} else if vec::len(impl_m.fty.inputs) != vec::len(if_m.fty.inputs) {
tcx.sess.span_err(sp,#fmt["method `%s` has %u parameters \
but the iface has %u",
if_m.ident,
vec::len(impl_m.fty.inputs),
vec::len(if_m.fty.inputs)]);
ty::mk_fn(tcx, impl_m.fty)
} 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
if alt i.mode { ast::infer(_) { true } _ { false } } {
{mode: ast::expl(ast::by_ref) with i}
}
_ { i }
}
});
let impl_fty = ty::mk_fn(tcx, {inputs: auto_modes with impl_m.fty});
// 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);
require_same_types(
tcx, sp, impl_fty, if_fty,
{|| "method `" + if_m.ident +
"` has an incompatible type"});
ret impl_fty;
}
}
fn check_methods_against_iface(ccx: @crate_ctxt,
tps: [ast::ty_param],
rp: ast::region_param,
......@@ -76,7 +176,7 @@ fn check_methods_against_iface(ccx: @crate_ctxt,
ms: [@ast::method]) {
let tcx = ccx.tcx;
let i_bounds = astconv::ty_param_bounds(ccx, tps);
let i_bounds = ty_param_bounds(ccx, tps);
let my_methods = convert_methods(ccx, ms, rp, i_bounds, selfty);
let (did, tpt) = instantiate_iface_ref(ccx, a_ifacety, rp);
if did.crate == ast::local_crate {
......@@ -138,7 +238,7 @@ fn convert_methods(ccx: @crate_ctxt,
let tcx = ccx.tcx;
vec::map(ms) { |m|
write_ty_to_tcx(tcx, m.self_id, self_ty);
let bounds = astconv::ty_param_bounds(ccx, m.tps);
let bounds = ty_param_bounds(ccx, m.tps);
let mty = ty_of_method(ccx, m, rp);
let fty = ty::mk_fn(tcx, mty.fty);
tcx.tcache.insert(
......@@ -169,7 +269,7 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
ty_params, rp);
}
ast::item_impl(tps, rp, ifce, selfty, ms) {
let i_bounds = astconv::ty_param_bounds(ccx, tps);
let i_bounds = ty_param_bounds(ccx, tps);
let selfty = ccx.to_ty(type_rscope(rp), selfty);
write_ty_to_tcx(tcx, it.id, selfty);
tcx.tcache.insert(local_def(it.id),
......@@ -194,7 +294,7 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
ast::item_res(decl, tps, _, dtor_id, ctor_id, rp) {
let {bounds, substs} = mk_substs(ccx, tps, rp);
let def_id = local_def(it.id);
let t_arg = astconv::ty_of_arg(ccx, type_rscope(rp),
let t_arg = ty_of_arg(ccx, type_rscope(rp),
decl.inputs[0], none);
let t_res = ty::mk_res(tcx, def_id, t_arg.ty, substs);
......@@ -237,7 +337,7 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
let t_ctor =
ty::mk_fn(
tcx,
astconv::ty_of_fn_decl(ccx,
ty_of_fn_decl(ccx,
empty_rscope,
ast::proto_any,
ctor.node.dec,
......@@ -253,7 +353,7 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
tcx,
// not sure about empty_rscope
// FIXME
astconv::ty_of_fn_decl(ccx,
ty_of_fn_decl(ccx,
empty_rscope,
ast::proto_any,
ast_util::dtor_dec(),
......@@ -317,20 +417,13 @@ fn convert_native(ccx: @crate_ctxt, i: @ast::native_item) {
}
}
}
fn collect_item_types(ccx: @crate_ctxt, crate: @ast::crate) {
visit::visit_crate(*crate, (), visit::mk_simple_visitor(@{
visit_item: bind convert(ccx, _),
visit_native_item: bind convert_native(ccx, _)
with *visit::default_simple_visitor()
}));
}
fn ty_of_method(ccx: @crate_ctxt,
m: @ast::method,
rp: ast::region_param) -> ty::method {
{ident: m.ident,
tps: astconv::ty_param_bounds(ccx, m.tps),
fty: astconv::ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare,
tps: ty_param_bounds(ccx, m.tps),
fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare,
m.decl, none),
purity: m.decl.purity,
vis: m.vis}
......@@ -340,9 +433,275 @@ fn ty_of_ty_method(self: @crate_ctxt,
m: ast::ty_method,
rp: ast::region_param) -> ty::method {
{ident: m.ident,
tps: astconv::ty_param_bounds(self, m.tps),
fty: astconv::ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare,
tps: ty_param_bounds(self, m.tps),
fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare,
m.decl, none),
// assume public, because this is only invoked on iface methods
purity: m.decl.purity, vis: ast::public}
}
fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::native_item) {
fn param(ccx: @crate_ctxt, n: uint) -> ty::t {
ty::mk_param(ccx.tcx, n, local_def(0))
}
fn arg(m: ast::rmode, ty: ty::t) -> ty::arg {
{mode: ast::expl(m), ty: ty}
}
let tcx = ccx.tcx;
let (n_tps, inputs, output) = alt it.ident {
"size_of" |
"pref_align_of" | "min_align_of" { (1u, [], ty::mk_uint(ccx.tcx)) }
"get_tydesc" { (1u, [], ty::mk_nil_ptr(tcx)) }
"init" { (1u, [], param(ccx, 0u)) }
"forget" { (1u, [arg(ast::by_move, param(ccx, 0u))],
ty::mk_nil(tcx)) }
"reinterpret_cast" { (2u, [arg(ast::by_ref, param(ccx, 0u))],
param(ccx, 1u)) }
"addr_of" { (1u, [arg(ast::by_ref, param(ccx, 0u))],
ty::mk_imm_ptr(tcx, param(ccx, 0u))) }
"needs_drop" { (1u, [], ty::mk_bool(tcx)) }
"visit_ty" { (2u, [arg(ast::by_ref, param(ccx, 1u))],
ty::mk_nil(tcx)) }
"visit_val" { (2u, [arg(ast::by_ref, param(ccx, 0u)),
arg(ast::by_ref, param(ccx, 1u))],
ty::mk_nil(tcx)) }
"visit_val_pair" { (2u, [arg(ast::by_ref, param(ccx, 0u)),
arg(ast::by_ref, param(ccx, 0u)),
arg(ast::by_ref, param(ccx, 1u))],
ty::mk_nil(tcx)) }
other {
tcx.sess.span_err(it.span, "unrecognized intrinsic function: `" +
other + "`");
ret;
}
};
let fty = ty::mk_fn(tcx, {proto: ast::proto_bare,
inputs: inputs, output: output,
ret_style: ast::return_val,
constraints: []});
let i_ty = ty_of_native_item(ccx, it);
let i_n_tps = (*i_ty.bounds).len();
if i_n_tps != n_tps {
tcx.sess.span_err(it.span, #fmt("intrinsic has wrong number \
of type parameters. found %u, \
expected %u", i_n_tps, n_tps));
} else {
require_same_types(
tcx, it.span, i_ty.ty, fty,
{|| #fmt["intrinsic has wrong type. \
expected %s",
ty_to_str(ccx.tcx, fty)]});
}
}
/*
Instantiates the path for the given iface reference, assuming that
it's bound to a valid iface type. Returns the def_id for the defining
iface. Fails if the type is a type other than an iface type.
*/
fn instantiate_iface_ref(ccx: @crate_ctxt, t: @ast::iface_ref,
rp: ast::region_param)
-> (ast::def_id, ty_param_substs_and_ty) {
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 = astconv::ast_path_to_ty(ccx, rscope, t_id, t.path, t.id);
alt ty::get(tpt.ty).struct {
ty::ty_iface(*) {
(t_id, tpt)
}
_ { sess.span_fatal(sp, err); }
}
}
_ {
sess.span_fatal(sp, err);
}
}
}
fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
-> ty::ty_param_bounds_and_ty {
let def_id = local_def(it.id);
let tcx = ccx.tcx;
alt tcx.tcache.find(def_id) {
some(tpt) { ret tpt; }
_ {}
}
alt it.node {
ast::item_const(t, _) {
let typ = ccx.to_ty(empty_rscope, t);
let tpt = no_params(typ);
tcx.tcache.insert(local_def(it.id), tpt);
ret tpt;
}
ast::item_fn(decl, tps, _) {
let bounds = ty_param_bounds(ccx, tps);
let tofd = ty_of_fn_decl(ccx, empty_rscope, ast::proto_bare,
decl, none);
let tpt = {bounds: bounds,
rp: ast::rp_none, // functions do not have a self
ty: ty::mk_fn(ccx.tcx, tofd)};
ccx.tcx.tcache.insert(local_def(it.id), tpt);
ret tpt;
}
ast::item_ty(t, tps, rp) {
alt tcx.tcache.find(local_def(it.id)) {
some(tpt) { ret tpt; }
none { }
}
let tpt = {
let ty = {
let t0 = ccx.to_ty(type_rscope(rp), t);
// Do not associate a def id with a named, parameterized type
// like "foo<X>". This is because otherwise ty_to_str will
// print the name as merely "foo", as it has no way to
// reconstruct the value of X.
if !vec::is_empty(tps) { t0 } else {
ty::mk_with_id(tcx, t0, def_id)
}
};
{bounds: ty_param_bounds(ccx, tps), rp: rp, ty: ty}
};
tcx.tcache.insert(local_def(it.id), tpt);
ret tpt;
}
ast::item_res(decl, tps, _, _, _, rp) {
let {bounds, substs} = mk_substs(ccx, tps, rp);
let t_arg = ty_of_arg(ccx, type_rscope(rp),
decl.inputs[0], none);
let t = ty::mk_res(tcx, local_def(it.id), t_arg.ty, substs);
let t_res = {bounds: bounds, rp: rp, ty: t};
tcx.tcache.insert(local_def(it.id), t_res);
ret t_res;
}
ast::item_enum(_, tps, rp) {
// Create a new generic polytype.
let {bounds, substs} = mk_substs(ccx, tps, rp);
let t = ty::mk_enum(tcx, local_def(it.id), substs);
let tpt = {bounds: bounds, rp: rp, ty: t};
tcx.tcache.insert(local_def(it.id), tpt);
ret tpt;
}
ast::item_iface(tps, rp, ms) {
let {bounds, substs} = mk_substs(ccx, tps, rp);
let t = ty::mk_iface(tcx, local_def(it.id), substs);
let tpt = {bounds: bounds, rp: rp, ty: t};
tcx.tcache.insert(local_def(it.id), tpt);
ret tpt;
}
ast::item_class(tps, _, _, _, _, rp) {
let {bounds,substs} = mk_substs(ccx, tps, rp);
let t = ty::mk_class(tcx, local_def(it.id), substs);
let tpt = {bounds: bounds, rp: rp, ty: t};
tcx.tcache.insert(local_def(it.id), tpt);
ret tpt;
}
ast::item_impl(*) | ast::item_mod(_) |
ast::item_native_mod(_) { fail; }
}
}
fn ty_of_native_item(ccx: @crate_ctxt, it: @ast::native_item)
-> ty::ty_param_bounds_and_ty {
alt it.node {
ast::native_item_fn(fn_decl, params) {
ret ty_of_native_fn_decl(ccx, fn_decl, params,
local_def(it.id));
}
}
}
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 = compute_bounds(ccx, param);
ccx.tcx.ty_param_bounds.insert(param.id, bounds);
bounds
}
}
}
}
fn ty_of_native_fn_decl(ccx: @crate_ctxt,
decl: ast::fn_decl,
ty_params: [ast::ty_param],
def_id: ast::def_id) -> ty::ty_param_bounds_and_ty {
let bounds = ty_param_bounds(ccx, ty_params);
let rb = in_binding_rscope(empty_rscope);
let input_tys = decl.inputs.map { |a| ty_of_arg(ccx, rb, a, none) };
let output_ty = ast_ty_to_ty(ccx, rb, decl.output);
let t_fn = ty::mk_fn(ccx.tcx, {proto: ast::proto_bare,
inputs: input_tys,
output: output_ty,
ret_style: ast::return_val,
constraints: []});
let tpt = {bounds: bounds, rp: ast::rp_none, ty: t_fn};
ccx.tcx.tcache.insert(def_id, tpt);
ret tpt;
}
fn mk_ty_params(ccx: @crate_ctxt, atps: [ast::ty_param])
-> {bounds: @[ty::param_bounds], params: [ty::t]} {
let mut i = 0u;
let bounds = ty_param_bounds(ccx, atps);
{bounds: bounds,
params: vec::map(atps, {|atp|
let t = ty::mk_param(ccx.tcx, i, local_def(atp.id));
i += 1u;
t
})}
}
fn mk_substs(ccx: @crate_ctxt, atps: [ast::ty_param], rp: ast::region_param)
-> {bounds: @[ty::param_bounds], substs: ty::substs} {
let {bounds, params} = mk_ty_params(ccx, atps);
let self_r = alt rp {
ast::rp_self { some(ty::re_bound(ty::br_self)) }
ast::rp_none { none }
};
{bounds: bounds, substs: {self_r: self_r, self_ty: none, tps: params}}
}
import check::{fn_ctxt, methods};
// Requires that the two types unify, and prints an error message if they
// don't.
fn suptype(fcx: @fn_ctxt, sp: span,
......
......@@ -15,6 +15,7 @@
import util::ppaux;
import syntax::print::pprust;
import check::{fn_ctxt, methods};
type rcx = @{fcx: @fn_ctxt, mut errors_reported: uint};
type rvt = visit::vt<rcx>;
......
import check::{fn_ctxt, impl_self_ty, methods};
fn has_iface_bounds(tps: [ty::param_bounds]) -> bool {
vec::any(tps, {|bs|
vec::any(*bs, {|b|
......
// Type resolution: the phase that finds all the types in the AST with
// unresolved type variables and replaces "ty_var" types with their
// substitutions.
import check::{fn_ctxt, lookup_local, methods};
export resolve_type_vars_in_fn;
export resolve_type_vars_in_expr;
......
......@@ -52,6 +52,7 @@ mod middle {
mod ast_map;
mod resolve;
mod typeck {
mod check;
mod regionck;
mod demand;
mod infer;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册