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

further modularization of typeck, add comments

上级 8cc596ce
此差异已折叠。
#[doc = " #[doc = "
Conversion from AST representation of types to the ty.rs representation. Conversion from AST representation of types to the ty.rs
representation. The main routine here is `ast_ty_to_ty()`: each use
The main routine here is `ast_ty_to_ty()`: each use is parameterized is parameterized by an instance of `ast_conv` and a `region_scope`.
by an instance of `ast_conv` and a `region_scope`.
The parameterization of `ast_ty_to_ty()` is because it behaves
The `ast_conv` interface is the conversion context. It has two somewhat differently during the collect and check phases, particularly
implementations, one for the crate context and one for the function with respect to looking up the types of top-level items. In the
context. The main purpose is to provide the `get_item_ty()` hook collect phase, the crate context is used as the `ast_conv` instance;
which looks up the type of an item by its def-id. This can be done in in this phase, the `get_item_ty()` function triggers a recursive call
two ways: in the initial phase, when a crate context is provided, this to `ty_of_item()` (note that `ast_ty_to_ty()` will detect recursive
will potentially trigger a call to `ty_of_item()`. Later, when a types and report an error). In the check phase, when the @fn_ctxt is
function context is used, this will simply be a lookup. 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 The `region_scope` interface controls how region references are
handled. It has two methods which are used to resolve anonymous handled. It has two methods which are used to resolve anonymous
...@@ -21,8 +22,30 @@ ...@@ -21,8 +22,30 @@
region, or `type_rscope`, which permits the self region if the type in region, or `type_rscope`, which permits the self region if the type in
question is parameterized by a region. 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 { iface ast_conv {
fn tcx() -> ty::ctxt; fn tcx() -> ty::ctxt;
fn ccx() -> @crate_ctxt; fn ccx() -> @crate_ctxt;
...@@ -32,48 +55,6 @@ ...@@ -32,48 +55,6 @@
fn ty_infer(span: span) -> ty::t; 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 { iface region_scope {
fn anon_region() -> result<ty::region, str>; fn anon_region() -> result<ty::region, str>;
fn named_region(id: str) -> 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> { ...@@ -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}; enum anon_rscope = {anon: ty::region, base: region_scope};
fn in_anon_rscope<RS: region_scope copy>(self: RS, r: ty::region) fn in_anon_rscope<RS: region_scope copy>(self: RS, r: ty::region)
-> @anon_rscope { -> @anon_rscope {
...@@ -159,6 +123,19 @@ fn named_region(id: str) -> result<ty::region, str> { ...@@ -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>( fn ast_region_to_region<AC: ast_conv, RS: region_scope>(
self: AC, rscope: RS, span: span, a_r: @ast::region) -> ty::region { 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>( ...@@ -233,36 +210,6 @@ fn ast_path_to_ty<AC: ast_conv, RS: region_scope copy>(
ret {substs: substs, ty: ty}; 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_REGIONS: uint = 1u;
const NO_TPS: uint = 2u; const NO_TPS: uint = 2u;
...@@ -474,103 +421,6 @@ fn check_path_args(tcx: ty::ctxt, ...@@ -474,103 +421,6 @@ fn check_path_args(tcx: ty::ctxt,
ret typ; 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>( fn ty_of_arg<AC: ast_conv, RS: region_scope copy>(
self: AC, rscope: RS, a: ast::arg, self: AC, rscope: RS, a: ast::arg,
expected_ty: option<ty::arg>) -> ty::arg { expected_ty: option<ty::arg>) -> ty::arg {
...@@ -651,61 +501,3 @@ fn ty_of_fn_decl<AC: ast_conv, RS: region_scope copy>( ...@@ -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};
# Collect phase
// Item collection - a pair of bootstrap passes:
// The collect phase of type check has the job of visiting all items,
// (1) Collect the IDs of all type items (typedefs) and store them in a table. determining their type, and writing that type into the `tcx.tcache`
// table. Despite its name, this table does not really operate as a
// (2) Translate the AST fragments that describe types to determine a type for *cache*, at least not for the types of items defined within the
// each item. When we encounter a named type, we consult the table built current crate: we assume that after the collect phase, the types of
// in pass 1 to find its item, and recursively translate it. all local items will be present in the table.
//
// We then annotate the AST with the resulting types and return the annotated Unlike most of the types that are present in Rust, the types computed
// AST, along with a table mapping item IDs to their types. 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, fn get_enum_variant_types(ccx: @crate_ctxt,
enum_ty: ty::t, enum_ty: ty::t,
variants: [ast::variant], variants: [ast::variant],
...@@ -36,7 +91,7 @@ fn get_enum_variant_types(ccx: @crate_ctxt, ...@@ -36,7 +91,7 @@ fn get_enum_variant_types(ccx: @crate_ctxt,
ret_style: ast::return_val, ret_style: ast::return_val,
constraints: []}) constraints: []})
}; };
let tpt = {bounds: astconv::ty_param_bounds(ccx, ty_params), let tpt = {bounds: ty_param_bounds(ccx, ty_params),
rp: rp, rp: rp,
ty: result_ty}; ty: result_ty};
tcx.tcache.insert(local_def(variant.node.id), tpt); tcx.tcache.insert(local_def(variant.node.id), tpt);
...@@ -68,6 +123,51 @@ fn store_methods<T>(ccx: @crate_ctxt, id: ast::node_id, ...@@ -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, fn check_methods_against_iface(ccx: @crate_ctxt,
tps: [ast::ty_param], tps: [ast::ty_param],
rp: ast::region_param, rp: ast::region_param,
...@@ -76,7 +176,7 @@ fn check_methods_against_iface(ccx: @crate_ctxt, ...@@ -76,7 +176,7 @@ fn check_methods_against_iface(ccx: @crate_ctxt,
ms: [@ast::method]) { ms: [@ast::method]) {
let tcx = ccx.tcx; 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 my_methods = convert_methods(ccx, ms, rp, i_bounds, selfty);
let (did, tpt) = instantiate_iface_ref(ccx, a_ifacety, rp); let (did, tpt) = instantiate_iface_ref(ccx, a_ifacety, rp);
if did.crate == ast::local_crate { if did.crate == ast::local_crate {
...@@ -138,7 +238,7 @@ fn convert_methods(ccx: @crate_ctxt, ...@@ -138,7 +238,7 @@ fn convert_methods(ccx: @crate_ctxt,
let tcx = ccx.tcx; let tcx = ccx.tcx;
vec::map(ms) { |m| vec::map(ms) { |m|
write_ty_to_tcx(tcx, m.self_id, self_ty); 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 mty = ty_of_method(ccx, m, rp);
let fty = ty::mk_fn(tcx, mty.fty); let fty = ty::mk_fn(tcx, mty.fty);
tcx.tcache.insert( tcx.tcache.insert(
...@@ -169,7 +269,7 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) { ...@@ -169,7 +269,7 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
ty_params, rp); ty_params, rp);
} }
ast::item_impl(tps, rp, ifce, selfty, ms) { 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); let selfty = ccx.to_ty(type_rscope(rp), selfty);
write_ty_to_tcx(tcx, it.id, selfty); write_ty_to_tcx(tcx, it.id, selfty);
tcx.tcache.insert(local_def(it.id), tcx.tcache.insert(local_def(it.id),
...@@ -194,7 +294,7 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) { ...@@ -194,7 +294,7 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
ast::item_res(decl, tps, _, dtor_id, ctor_id, rp) { ast::item_res(decl, tps, _, dtor_id, ctor_id, rp) {
let {bounds, substs} = mk_substs(ccx, tps, rp); let {bounds, substs} = mk_substs(ccx, tps, rp);
let def_id = local_def(it.id); 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); decl.inputs[0], none);
let t_res = ty::mk_res(tcx, def_id, t_arg.ty, substs); 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) { ...@@ -237,7 +337,7 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
let t_ctor = let t_ctor =
ty::mk_fn( ty::mk_fn(
tcx, tcx,
astconv::ty_of_fn_decl(ccx, ty_of_fn_decl(ccx,
empty_rscope, empty_rscope,
ast::proto_any, ast::proto_any,
ctor.node.dec, ctor.node.dec,
...@@ -253,7 +353,7 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) { ...@@ -253,7 +353,7 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
tcx, tcx,
// not sure about empty_rscope // not sure about empty_rscope
// FIXME // FIXME
astconv::ty_of_fn_decl(ccx, ty_of_fn_decl(ccx,
empty_rscope, empty_rscope,
ast::proto_any, ast::proto_any,
ast_util::dtor_dec(), ast_util::dtor_dec(),
...@@ -317,20 +417,13 @@ fn convert_native(ccx: @crate_ctxt, i: @ast::native_item) { ...@@ -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, fn ty_of_method(ccx: @crate_ctxt,
m: @ast::method, m: @ast::method,
rp: ast::region_param) -> ty::method { rp: ast::region_param) -> ty::method {
{ident: m.ident, {ident: m.ident,
tps: astconv::ty_param_bounds(ccx, m.tps), tps: ty_param_bounds(ccx, m.tps),
fty: astconv::ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare, fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare,
m.decl, none), m.decl, none),
purity: m.decl.purity, purity: m.decl.purity,
vis: m.vis} vis: m.vis}
...@@ -340,9 +433,275 @@ fn ty_of_ty_method(self: @crate_ctxt, ...@@ -340,9 +433,275 @@ fn ty_of_ty_method(self: @crate_ctxt,
m: ast::ty_method, m: ast::ty_method,
rp: ast::region_param) -> ty::method { rp: ast::region_param) -> ty::method {
{ident: m.ident, {ident: m.ident,
tps: astconv::ty_param_bounds(self, m.tps), tps: ty_param_bounds(self, m.tps),
fty: astconv::ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare, fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare,
m.decl, none), m.decl, none),
// assume public, because this is only invoked on iface methods // assume public, because this is only invoked on iface methods
purity: m.decl.purity, vis: ast::public} 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 // Requires that the two types unify, and prints an error message if they
// don't. // don't.
fn suptype(fcx: @fn_ctxt, sp: span, fn suptype(fcx: @fn_ctxt, sp: span,
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
import util::ppaux; import util::ppaux;
import syntax::print::pprust; import syntax::print::pprust;
import check::{fn_ctxt, methods};
type rcx = @{fcx: @fn_ctxt, mut errors_reported: uint}; type rcx = @{fcx: @fn_ctxt, mut errors_reported: uint};
type rvt = visit::vt<rcx>; type rvt = visit::vt<rcx>;
......
import check::{fn_ctxt, impl_self_ty, methods};
fn has_iface_bounds(tps: [ty::param_bounds]) -> bool { fn has_iface_bounds(tps: [ty::param_bounds]) -> bool {
vec::any(tps, {|bs| vec::any(tps, {|bs|
vec::any(*bs, {|b| vec::any(*bs, {|b|
......
// Type resolution: the phase that finds all the types in the AST with // Type resolution: the phase that finds all the types in the AST with
// unresolved type variables and replaces "ty_var" types with their // unresolved type variables and replaces "ty_var" types with their
// substitutions. // substitutions.
import check::{fn_ctxt, lookup_local, methods};
export resolve_type_vars_in_fn; export resolve_type_vars_in_fn;
export resolve_type_vars_in_expr; export resolve_type_vars_in_expr;
......
...@@ -52,6 +52,7 @@ mod middle { ...@@ -52,6 +52,7 @@ mod middle {
mod ast_map; mod ast_map;
mod resolve; mod resolve;
mod typeck { mod typeck {
mod check;
mod regionck; mod regionck;
mod demand; mod demand;
mod infer; mod infer;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册