diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 3e040c14a0a81..a83570225b884 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -98,7 +98,13 @@ fn chain(res: result, op: fn(T) -> result) // deforested) style because I have found that, in practice, this is // the most concise way to do things. That means that they do not not // terminate with a call to `ok(v)` but rather `nxt(v)`. If you would -// like to just get the result, just pass in `ok` as `nxt`. +// like to just get the result, just pass in `ok1` as `nxt`. + +#[doc = "An annoying helper function for bridging argument modes when +using deforested functions."] +fn ok1(x: T) -> result { + ok(x) +} #[doc = " Maps each element in the vector `ts` using the operation `op`. Should an @@ -118,7 +124,7 @@ checking for overflow: } Note: if you have to combine a deforested style transform with map, -you should use `ok` for the `nxt` operation, as shown here (this is an +you should use `ok1` for the `nxt` operation, as shown here (this is an alternate version of the previous example where the `inc_conditionally()` routine is deforested): @@ -127,7 +133,7 @@ alternate version of the previous example where the if x == uint::max_value { ret err(\"overflow\"); } else { ret nxt(x+1u); } } - map([1u, 2u, 3u], inc_conditionally(_, ok)) {|incd| + map([1u, 2u, 3u], inc_conditionally(_, ok1)) {|incd| assert incd == [2u, 3u, 4u]; } "] diff --git a/src/rustc/metadata/decoder.rs b/src/rustc/metadata/decoder.rs index 1a3f6123d5771..4639dbcae0cf0 100644 --- a/src/rustc/metadata/decoder.rs +++ b/src/rustc/metadata/decoder.rs @@ -14,6 +14,7 @@ import tydecode::{parse_ty_data, parse_def_id, parse_bounds_data, import syntax::print::pprust; import cmd=cstore::crate_metadata; import middle::trans::common::maps; +import ty::ty_ops; export get_class_items; export get_symbol; diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs index e36b982ff12ac..7199967b52a79 100644 --- a/src/rustc/metadata/encoder.rs +++ b/src/rustc/metadata/encoder.rs @@ -11,7 +11,7 @@ import syntax::ast_util::local_def; import common::*; import middle::trans::common::crate_ctxt; import middle::ty; -import middle::ty::node_id_to_type; +import middle::ty::{node_id_to_type, ty_ops}; import middle::ast_map; import front::attr; import driver::session::session; diff --git a/src/rustc/metadata/tydecode.rs b/src/rustc/metadata/tydecode.rs index 9b2a87d9e18ba..6b00560ecc111 100644 --- a/src/rustc/metadata/tydecode.rs +++ b/src/rustc/metadata/tydecode.rs @@ -5,6 +5,7 @@ import syntax::ast::*; import syntax::ast_util; import syntax::ast_util::respan; import middle::ty; +import middle::ty::ty_ops; import std::map::hashmap; export parse_ty_data, parse_def_id, parse_ident; @@ -265,7 +266,6 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t { st.pos = st.pos + 1u; ret ty::mk_res(st.tcx, def, inner, params); } - 'X' { ret ty::mk_var(st.tcx, parse_int(st)); } 'Y' { ret ty::mk_type(st.tcx); } 'C' { let ck = alt check next(st) { diff --git a/src/rustc/metadata/tyencode.rs b/src/rustc/metadata/tyencode.rs index 7e16129846cae..b0f504c711bfd 100644 --- a/src/rustc/metadata/tyencode.rs +++ b/src/rustc/metadata/tyencode.rs @@ -190,7 +190,6 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) { for t: ty::t in tps { enc_ty(w, cx, t); } w.write_char(']'); } - ty::ty_var(id) { w.write_char('X'); w.write_str(int::str(id)); } ty::ty_param(id, did) { w.write_char('p'); w.write_str(cx.ds(did)); diff --git a/src/rustc/middle/ast_map.rs b/src/rustc/middle/ast_map.rs index 1b2dbaf9d58d0..82ad4bbea4603 100644 --- a/src/rustc/middle/ast_map.rs +++ b/src/rustc/middle/ast_map.rs @@ -1,6 +1,7 @@ import std::map; import std::map::hashmap; import syntax::ast::*; +import syntax::print::pprust; import syntax::ast_util; import syntax::ast_util::inlined_item_methods; import syntax::{visit, codemap}; @@ -24,6 +25,14 @@ fn path_to_str(p: path) -> str { path_to_str_with_sep(p, "::") } +fn path_ident_to_str(p: path, i: ident) -> str { + if vec::is_empty(p) { + i + } else { + #fmt["%s::%s", path_to_str(p), i] + } +} + enum ast_node { node_item(@item, @path), node_native_item(@native_item, native_abi, @path), @@ -44,6 +53,49 @@ type ctx = {map: map, mutable path: path, mutable local_id: uint, sess: session}; type vt = visit::vt; +fn node_str(map: map, id: node_id) -> str { + alt map.find(id) { + none { + #fmt["unknown node (id=%d)", id] + } + some(node_item(item, path)) { + #fmt["item %s (id=%?)", path_ident_to_str(*path, item.ident), id] + } + some(node_native_item(item, abi, path)) { + #fmt["native item %s with abi %? (id=%?)", + path_ident_to_str(*path, item.ident), abi, id] + } + some(node_method(m, impl_did, path)) { + #fmt["method %s in %s (id=%?)", + m.ident, path_to_str(*path), id] + } + some(node_variant(variant, def_id, path)) { + #fmt["variant %s in %s (id=%?)", + variant.node.name, path_to_str(*path), id] + } + some(node_expr(expr)) { + #fmt["expr %s (id=%?)", + pprust::expr_to_str(expr), id] + } + some(node_export(_, path)) { + #fmt["export %s (id=%?)", // FIXME: add more info here + path_to_str(*path), id] + } + some(node_arg(_, _)) { // FIXME: add more info here + #fmt["arg (id=%?)", id] + } + some(node_local(_)) { // FIXME: add more info here + #fmt["local (id=%?)", id] + } + some(node_ctor(_, _)) { // FIXME: add more info here + #fmt["node_ctor (id=%?)", id] + } + some(node_block(_)) { + #fmt["block"] + } + } +} + fn extend(cx: ctx, elt: str) -> @path { @(cx.path + [path_name(elt)]) } diff --git a/src/rustc/middle/fn_usage.rs b/src/rustc/middle/fn_usage.rs index 332b316b986dd..da2dce3d4ddf2 100644 --- a/src/rustc/middle/fn_usage.rs +++ b/src/rustc/middle/fn_usage.rs @@ -21,7 +21,7 @@ fn fn_usage_expr(expr: @ast::expr, alt ctx.tcx.def_map.find(expr.id) { some(ast::def_fn(_, ast::unsafe_fn)) { log(error, ("expr=", expr_to_str(expr))); - ctx.tcx.sess.span_fatal( + ctx.tcx.sess.span_err( expr.span, "unsafe functions can only be called"); } @@ -33,7 +33,7 @@ fn fn_usage_expr(expr: @ast::expr, && ty::expr_has_ty_params(ctx.tcx, expr) { alt ty::get(ty::expr_ty(ctx.tcx, expr)).struct { ty::ty_fn({proto: ast::proto_bare, _}) { - ctx.tcx.sess.span_fatal( + ctx.tcx.sess.span_err( expr.span, "generic bare functions can only be called or bound"); } diff --git a/src/rustc/middle/trans/alt.rs b/src/rustc/middle/trans/alt.rs index c8f10f214ef5b..8c17e5007d81f 100644 --- a/src/rustc/middle/trans/alt.rs +++ b/src/rustc/middle/trans/alt.rs @@ -13,6 +13,7 @@ import syntax::print::pprust::pat_to_str; import back::abi; import resolve::def_map; import std::map::hashmap; +import ty::ty_ops; import common::*; diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index a3b8dfd215425..1e7388124262f 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -40,6 +40,7 @@ import link::{mangle_internal_name_by_type_only, mangle_exported_name}; import metadata::{csearch, cstore}; import util::ppaux::{ty_to_str, ty_to_short_str}; +import ty::ty_ops; import common::*; import build::*; diff --git a/src/rustc/middle/trans/closure.rs b/src/rustc/middle/trans/closure.rs index 225c22d5b405b..8d976faf9d15b 100644 --- a/src/rustc/middle/trans/closure.rs +++ b/src/rustc/middle/trans/closure.rs @@ -18,6 +18,7 @@ import util::ppaux::ty_to_str; import ast_map::{path, path_mod, path_name}; import driver::session::session; import std::map::hashmap; +import ty::ty_ops; // ___Good to know (tm)__________________________________________________ // diff --git a/src/rustc/middle/trans/common.rs b/src/rustc/middle/trans/common.rs index df5f03e9922ea..bf883e840e919 100644 --- a/src/rustc/middle/trans/common.rs +++ b/src/rustc/middle/trans/common.rs @@ -19,6 +19,7 @@ import lib::llvm::{ModuleRef, ValueRef, TypeRef, BasicBlockRef, BuilderRef}; import lib::llvm::{True, False, Bool}; import metadata::csearch; import ast_map::path; +import ty::ty_ops; type namegen = fn@(str) -> str; fn new_namegen() -> namegen { diff --git a/src/rustc/middle/trans/debuginfo.rs b/src/rustc/middle/trans/debuginfo.rs index 98b5224f9ff0a..128507d160b1e 100644 --- a/src/rustc/middle/trans/debuginfo.rs +++ b/src/rustc/middle/trans/debuginfo.rs @@ -11,6 +11,7 @@ import ast::ty; import pat_util::*; import util::ppaux::ty_to_str; import driver::session::session; +import ty::ty_ops; export create_local_var; export create_function; diff --git a/src/rustc/middle/trans/impl.rs b/src/rustc/middle/trans/impl.rs index f4620677701dc..4499cb7e718da 100644 --- a/src/rustc/middle/trans/impl.rs +++ b/src/rustc/middle/trans/impl.rs @@ -13,6 +13,7 @@ import lib::llvm::{ValueRef, TypeRef}; import lib::llvm::llvm::LLVMGetParam; import ast_map::{path, path_mod, path_name}; import std::map::hashmap; +import ty::ty_ops; fn trans_impl(ccx: @crate_ctxt, path: path, name: ast::ident, methods: [@ast::method], tps: [ast::ty_param]) { @@ -238,7 +239,7 @@ fn make_impl_vtable(ccx: @crate_ctxt, impl_id: ast::def_id, substs: [ty::t], make_vtable(ccx, vec::map(*ty::iface_methods(tcx, ifce_id), {|im| let fty = ty::substitute_type_params(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); diff --git a/src/rustc/middle/trans/shape.rs b/src/rustc/middle/trans/shape.rs index 2029b86b9742e..4330e132253e9 100644 --- a/src/rustc/middle/trans/shape.rs +++ b/src/rustc/middle/trans/shape.rs @@ -10,13 +10,13 @@ import middle::trans::common::*; import back::abi; import middle::ty; import middle::ty::field; +import middle::ty::ty_ops; import syntax::ast; import syntax::ast_util::dummy_sp; import syntax::util::interner; import util::common; import trans::build::{Load, Store, Add, GEPi}; import syntax::codemap::span; - import std::map::hashmap; import ty_ctxt = middle::ty::ctxt; @@ -405,7 +405,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_self(_) { ccx.sess.bug("shape_of: unexpected type struct found"); } } @@ -635,7 +635,7 @@ fn simplify_type(tcx: ty::ctxt, typ: ty::t) -> ty::t { _ { typ } } } - ty::fold_ty(tcx, ty::fm_general(bind simplifier(tcx, _)), typ) + ty::fold(tcx, typ) {|t| simplifier(tcx, t) } } // Given a tag type `ty`, returns the offset of the payload. diff --git a/src/rustc/middle/trans/tvec.rs b/src/rustc/middle/trans/tvec.rs index c322e9255e0fc..ceaf8c5908102 100644 --- a/src/rustc/middle/trans/tvec.rs +++ b/src/rustc/middle/trans/tvec.rs @@ -9,6 +9,7 @@ import base::{call_memmove, trans_shared_malloc, import shape::llsize_of; import build::*; import common::*; +import ty::ty_ops; fn get_fill(bcx: block, vptr: ValueRef) -> ValueRef { Load(bcx, GEPi(bcx, vptr, [0, abi::vec_elt_fill])) diff --git a/src/rustc/middle/trans/type_of.rs b/src/rustc/middle/trans/type_of.rs index 77cf5e578d4fe..736baa16ce997 100644 --- a/src/rustc/middle/trans/type_of.rs +++ b/src/rustc/middle/trans/type_of.rs @@ -38,9 +38,6 @@ fn type_of_fn_from_ty(cx: @crate_ctxt, fty: ty::t) -> TypeRef { } fn type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef { - assert !ty::type_has_vars(t); - // Check the cache. - if cx.lltypes.contains_key(t) { ret cx.lltypes.get(t); } let llty = alt ty::get(t).struct { ty::ty_nil | ty::ty_bot { T_nil() } @@ -87,18 +84,17 @@ fn type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef { for ci in cls_items { // only instance vars are record fields at runtime alt ci.contents { - var_ty(t) { - let fty = type_of(cx, t); - tys += [fty]; - } - _ {} + var_ty(t) { + let fty = type_of(cx, t); + tys += [fty]; + } + _ {} } } T_struct(tys) } ty::ty_self(_) { cx.tcx.sess.unimpl("type_of: ty_self \ not implemented"); } - ty::ty_var(_) { cx.tcx.sess.bug("type_of shouldn't see a ty_var"); } }; cx.lltypes.insert(t, llty); ret llty; diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index fd9765e3fc340..c2b748d083df8 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -11,6 +11,7 @@ import metadata::csearch; import util::common::*; import util::ppaux::region_to_str; import util::ppaux::ty_to_str; +import util::ppaux::ty_i_to_str; import util::ppaux::ty_constr_to_str; import syntax::print::pprust::*; @@ -32,15 +33,13 @@ export expr_has_ty_params; export expr_ty; export expr_ty_params_and_ty; export expr_is_lval; -export fold_ty; +export fold, fold_rptr; export field; export field_idx; export get_field; export get_fields; -export fm_general, fm_rptr; export get_element_type; export is_binopable; -export is_pred_ty; export lookup_class_item_tys; export lookup_item_type; export method; @@ -55,27 +54,30 @@ export sequence_element_type; export sort_methods; export stmt_node_id; export sty; -export substitute_type_params; +export substitute_type_params, substitute_type_params_i; export t; export new_ty_hash; export enum_variants, substd_enum_variants; export iface_methods, store_iface_methods, impl_iface; export enum_variant_with_id; -export ty_param_bounds_and_ty; -export ty_bool, mk_bool, type_is_bool; +export ty_ops; +export ty_param_bounds_and_ty, ty_param_bounds_and_ty_i; +export ty_bool, mk_bool, type_is_bool, sty_is_bool; export ty_bot, mk_bot, type_is_bot; -export ty_box, mk_box, mk_imm_box, type_is_box, type_is_boxed; +export ty_box, mk_box, mk_imm_box; +export type_is_box, type_is_boxed; export ty_constr, mk_constr; export ty_opaque_closure_ptr, mk_opaque_closure_ptr; export ty_opaque_box, mk_opaque_box; export ty_constr_arg; -export ty_float, mk_float, mk_mach_float, type_is_fp; +export ty_float, mk_float, mk_mach_float; +export type_is_fp; export ty_fn, fn_ty, mk_fn; export ty_fn_proto, ty_fn_ret, ty_fn_ret_style; export ty_int, mk_int, mk_mach_int, mk_char; export ty_str, mk_str, type_is_str; export ty_vec, mk_vec, type_is_vec; -export ty_nil, mk_nil, type_is_nil; +export ty_nil, mk_nil, type_is_nil, sty_is_nil; export ty_iface, mk_iface; export ty_res, mk_res; export ty_param, mk_param; @@ -87,25 +89,25 @@ export ty_tup, mk_tup; export ty_type, mk_type; 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; +export ty_var_i, mk_var; export ty_self, mk_self; export region, re_named, re_caller, re_block, re_inferred; -export get, type_has_params, type_has_vars, type_has_rptrs, type_id; -export same_type; -export ty_var_id; +export get, type_has_rptrs, type_id; +export type_has_self, ty_i_has_self; +export type_has_params, ty_i_has_params; export ty_to_def_id; export ty_fn_args; export type_constr; export kind, kind_sendable, kind_copyable, kind_noncopyable; export kind_can_be_copied, kind_can_be_sent, proto_kind, kind_lteq, type_kind; -export type_err; -export type_err_to_str; +export type_err, resolve_err; +export type_err_to_str, resolve_err_to_str; export type_needs_drop; export type_allows_implicit_copy; -export type_is_integral; -export type_is_numeric; +export type_is_integral, sty_is_integral; +export type_is_numeric, sty_is_numeric; export type_is_pod; -export type_is_scalar; +export type_is_scalar, sty_is_scalar; export type_is_immediate; export type_is_sequence; export type_is_signed; @@ -113,7 +115,7 @@ export type_is_structural; export type_is_copyable; export type_is_tup_like; export type_is_unique; -export type_is_c_like_enum; +export type_is_c_like_enum, sty_is_c_like_enum; export type_structurally_contains; export type_structurally_contains_uniques; export type_autoderef; @@ -125,8 +127,7 @@ export unify_mode; export set_default_mode; export unify; export variant_info; -export walk_ty, maybe_walk_ty; -export occurs_check; +export walk_ty, walk_ty_i, maybe_walk_ty; export closure_kind; export ck_block; export ck_box; @@ -136,51 +137,163 @@ export param_bounds_to_kind; export default_arg_mode_for_ty; export item_path; export item_path_str; -export ast_ty_to_ty_cache_entry; -export atttce_unresolved, atttce_resolved, atttce_has_regions; + +export var_bindings; +export t_i; +export sty_i, ty_var_i; +export arg_i; +export field_i; +export class_contents_ty_i; +export class_item_ty_i; +export param_bounds_i; +export param_bound_i; +export method_i; +export mt_i; +export sty_i; +export fn_ty_i; + +export sty_base; +export arg_base; +export field_base; +export class_contents_ty_base; +export class_item_ty_base; +export param_bounds_base; +export param_bound_base; +export method_base; +export mt_base; +export fn_ty_base; + +export ty_to_ty_i, ty_to_ty_i_subst; // Data types +// +// To accommodate inference, the types are defined in two "layers". The base +// layer (e.g., `sty_base`) is parameterized by a type variable T, which +// defines a reference to a type. Typically, you will the type alias `sty` +// which is defined as `sty_base`, where `t` is an entry in the type table. +// During inference, however, we use the infer family of types (e.g., +// `sty_i`), defined with `T` equal to `t_i`. `t_i` allows for +// both concrete types but also type variables. // Note: after typeck, you should use resolved_mode() to convert this mode // into an rmode, which will take into account the results of mode inference. -type arg = {mode: ast::mode, ty: t}; +type arg_base = {mode: ast::mode, ty: T}; -type field = {ident: ast::ident, mt: mt}; +type field_base = {ident: ast::ident, mt: mt_base}; -type param_bounds = @[param_bound]; +type param_bounds_base = @[param_bound_base]; + +enum param_bound_base { + bound_copy, + bound_send, + bound_iface(T), +} -type method = {ident: ast::ident, - tps: @[param_bounds], - fty: fn_ty, - purity: ast::purity}; +type method_base = {ident: ast::ident, + tps: @[param_bounds_base], + fty: fn_ty_base, + purity: ast::purity}; type constr_table = hashmap; -type mt = {ty: t, mutbl: ast::mutability}; +type mt_base = {ty: T, mutbl: ast::mutability}; -type class_item_ty = { +type class_item_ty_base = { ident: ident, id: node_id, contents: class_contents_ty }; -enum class_contents_ty { - var_ty(t), // FIXME: need mutability, too +enum class_contents_ty_base { + var_ty(T), // FIXME: need mutability, too method_ty(fn_decl) } +type fn_ty_base = {proto: ast::proto, + inputs: [arg_base], + output: T, + ret_style: ret_style, + constraints: [@constr]}; + +enum region { + re_named(def_id), + re_caller(def_id), + re_self(def_id), + re_block(node_id), + re_inferred /* currently unresolved (for typedefs) */ +} + +// NB: If you change this, you'll probably want to change the corresponding +// AST structure in front/ast::rs as well. +enum sty_base { + ty_nil, + ty_bot, + ty_bool, + ty_int(ast::int_ty), + ty_uint(ast::uint_ty), + ty_float(ast::float_ty), + ty_str, + ty_enum(def_id, [T]), + ty_box(mt_base), + ty_uniq(mt_base), + ty_vec(mt_base), + ty_ptr(mt_base), + ty_rptr(region, mt_base), + ty_rec([field_base]), + ty_fn(fn_ty_base), + ty_iface(def_id, [T]), + ty_class(def_id, [T]), + ty_res(def_id, T, [T]), + ty_tup([T]), + + ty_param(uint, def_id), // type parameter + ty_self([T]), // interface method self type + + ty_type, // type_desc* + ty_opaque_box, // used by monomorphizer to represend any @ box + ty_constr(T, [@type_constr]), + ty_opaque_closure_ptr(closure_kind), // ptr to env for fn, fn@, fn~ +} + +enum t_i_box { + ty_var_i(int), // var index relative to in-scope set of var_bindings + sty_i(sty_i) +} +type t_i = @t_i_box; +type arg_i = arg_base; +type field_i = field_base; +type param_bounds_i = param_bounds_base; +type param_bound_i = param_bound_base; +type method_i = method_base; +type mt_i = mt_base; +type fn_ty_i = fn_ty_base; +type sty_i = sty_base; +type class_item_ty_i = class_item_ty_base; +type class_contents_ty_i = class_contents_ty_base; + +type arg = arg_base; +type field = field_base; +type param_bounds = param_bounds_base; +type param_bound = param_bound_base; +type method = method_base; +type mt = mt_base; +type fn_ty = fn_ty_base; +type sty = sty_base; +type class_item_ty = class_item_ty_base; +type class_contents_ty = class_contents_ty_base; + +// In the middle end, constraints have a def_id attached, referring +// to the definition of the operator in the constraint. +type constr_general = spanned>; +type type_constr = constr_general<@path>; +type constr = constr_general; + // Contains information needed to resolve types and (in the future) look up // the types of AST nodes. type creader_cache = hashmap<{cnum: int, pos: uint, len: uint}, t>; type intern_key = {struct: sty, o_def_id: option}; -enum ast_ty_to_ty_cache_entry { - atttce_unresolved, /* not resolved yet */ - atttce_resolved(t), /* resolved to a type, irrespective of region */ - atttce_has_regions /* has regions; cannot be cached */ -} - type ctxt = @{interner: hashmap, mutable next_id: uint, @@ -196,17 +309,33 @@ type ctxt = short_names_cache: hashmap, needs_drop_cache: hashmap, kind_cache: hashmap, - ast_ty_to_ty_cache: hashmap<@ast::ty, ast_ty_to_ty_cache_entry>, enum_var_cache: hashmap, iface_method_cache: hashmap, ty_param_bounds: hashmap, inferred_modes: hashmap}; +type var_bindings = + {tcx: ctxt, + sets: ufind::ufind, + node_types: hashmap, + node_type_substs: hashmap, + var_types: smallintmap::smallintmap}; + +fn var_bindings(tcx: ctxt) -> @var_bindings { + ret @{tcx: tcx, + sets: ufind::make(), + node_types: map::int_hash(), + node_type_substs: map::int_hash(), + var_types: smallintmap::mk()}; +} + +type t_flags = {has_params: bool, + has_self: bool, + has_rptrs: bool}; + type t_box = @{struct: sty, id: uint, - has_params: bool, - has_vars: bool, - has_rptrs: bool, + t_flags: t_flags, o_def_id: option}; // To reduce refcounting cost, we're representing types as unsafe pointers @@ -224,9 +353,11 @@ pure fn get(t: t) -> t_box unsafe { 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_rptrs(t: t) -> bool { get(t).has_rptrs } +fn ty_i_has_params(t: t_i) -> bool { flags_for_t_i(t).has_params } +fn type_has_params(t: t) -> bool { get(t).t_flags.has_params } +fn ty_i_has_self(t: t_i) -> bool { flags_for_t_i(t).has_self } +fn type_has_self(t: t) -> bool { get(t).t_flags.has_self } +fn type_has_rptrs(t: t) -> bool { get(t).t_flags.has_rptrs } fn type_def_id(t: t) -> option { get(t).o_def_id } fn type_id(t: t) -> uint { get(t).id } @@ -236,59 +367,11 @@ enum closure_kind { ck_uniq, } -type fn_ty = {proto: ast::proto, - inputs: [arg], - output: t, - ret_style: ret_style, - constraints: [@constr]}; - -enum region { - re_named(def_id), - re_caller(def_id), - re_self(def_id), - re_block(node_id), - re_inferred /* currently unresolved (for typedefs) */ -} - -// NB: If you change this, you'll probably want to change the corresponding -// AST structure in front/ast::rs as well. -enum sty { - ty_nil, - ty_bot, - ty_bool, - ty_int(ast::int_ty), - ty_uint(ast::uint_ty), - ty_float(ast::float_ty), - ty_str, - ty_enum(def_id, [t]), - ty_box(mt), - ty_uniq(mt), - ty_vec(mt), - ty_ptr(mt), - ty_rptr(region, mt), - ty_rec([field]), - ty_fn(fn_ty), - ty_iface(def_id, [t]), - ty_class(def_id, [t]), - ty_res(def_id, t, [t]), - ty_tup([t]), - - ty_var(int), // type variable during typechecking - ty_param(uint, def_id), // type parameter - ty_self([t]), // interface method self type - - ty_type, // type_desc* - ty_opaque_box, // used by monomorphizer to represent any @ box - ty_constr(t, [@type_constr]), - ty_opaque_closure_ptr(closure_kind), // ptr to env for fn, fn@, fn~ +enum resolve_err { + rerr_unresolved_var(int), + rerr_cyclic_var(int) } -// In the middle end, constraints have a def_id attached, referring -// to the definition of the operator in the constraint. -type constr_general = spanned>; -type type_constr = constr_general<@path>; -type constr = constr_general; - // Data structures used in type unification enum type_err { terr_mismatch, @@ -307,12 +390,7 @@ enum type_err { terr_constr_len(uint, uint), terr_constr_mismatch(@type_constr, @type_constr), terr_regions_differ(bool /* variance */, region, region), -} - -enum param_bound { - bound_copy, - bound_send, - bound_iface(t), + terr_cyclic_type } fn param_bounds_to_kind(bounds: param_bounds) -> kind { @@ -331,6 +409,8 @@ fn param_bounds_to_kind(bounds: param_bounds) -> kind { type ty_param_bounds_and_ty = {bounds: @[param_bounds], ty: t}; +type ty_param_bounds_and_ty_i = {bounds: @[param_bounds_i], ty: t_i}; + type type_cache = hashmap; type node_type_table = @smallintmap::smallintmap; @@ -372,8 +452,6 @@ fn mk_ctxt(s: session::session, dm: resolve::def_map, amap: ast_map::map, short_names_cache: new_ty_hash(), needs_drop_cache: new_ty_hash(), kind_cache: new_ty_hash(), - ast_ty_to_ty_cache: map::hashmap( - ast_util::hash_ty, ast_util::eq_ty), enum_var_cache: new_def_hash(), iface_method_cache: new_def_hash(), ty_param_bounds: map::int_hash(), @@ -384,167 +462,206 @@ fn mk_ctxt(s: session::session, dm: resolve::def_map, amap: ast_map::map, // Type constructors fn mk_t(cx: ctxt, st: sty) -> t { mk_t_with_id(cx, st, none) } -// Interns a type/name combination, stores the resulting box in cx.interner, -// and returns the box as cast to an unsafe ptr (see comments for t above). -fn mk_t_with_id(cx: ctxt, st: sty, o_def_id: option) -> t { - let key = {struct: st, o_def_id: o_def_id}; - alt cx.interner.find(key) { - some(t) { unsafe { ret unsafe::reinterpret_cast(t); } } - _ {} - } - let has_params = false, has_vars = false, has_rptrs = false; - fn derive_flags(&has_params: bool, &has_vars: bool, &has_rptrs: bool, - tt: t) { - let t = get(tt); - has_params |= t.has_params; - has_vars |= t.has_vars; - has_rptrs |= t.has_rptrs; +fn flags_for_sty_base(sty: sty_base, + t_flags: fn(T) -> t_flags) -> t_flags { + let has_params = false; + let has_self = false; + let has_rptrs = false; + + fn derive_flags(&has_params: bool, + &has_self: bool, + &has_rptrs: bool, + t: T, + t_flags: fn(T) -> t_flags) { + let f = t_flags(t); + has_params = has_params || f.has_params; + has_rptrs = has_rptrs || f.has_rptrs; + has_self = has_self || f.has_self; } - alt st { + + alt sty { ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) | - ty_str | ty_type | ty_opaque_closure_ptr(_) | - ty_opaque_box {} - ty_param(_, _) { has_params = true; } - ty_var(_) | ty_self(_) { has_vars = true; } + ty_str | ty_type | ty_opaque_closure_ptr(_) | ty_opaque_box { + } + ty_self(_) { + has_self = true; + } + ty_param(_, _) { + has_params = true; + } ty_enum(_, tys) | ty_iface(_, tys) | ty_class(_, tys) { - for tt in tys { derive_flags(has_params, has_vars, has_rptrs, tt); } + for tt in tys { + derive_flags(has_params, has_self, has_rptrs, tt, t_flags); + } } ty_box(m) | ty_uniq(m) | ty_vec(m) | ty_ptr(m) { - derive_flags(has_params, has_vars, has_rptrs, m.ty); + derive_flags(has_params, has_self, has_rptrs, m.ty, t_flags); } ty_rptr(_, m) { has_rptrs = true; - derive_flags(has_params, has_vars, has_rptrs, m.ty); + derive_flags(has_params, has_self, has_rptrs, m.ty, t_flags); } ty_rec(flds) { for f in flds { - derive_flags(has_params, has_vars, has_rptrs, f.mt.ty); + derive_flags(has_params, has_self, has_rptrs, f.mt.ty, t_flags); } } ty_tup(ts) { - for tt in ts { derive_flags(has_params, has_vars, has_rptrs, tt); } + for tt in ts { + derive_flags(has_params, has_self, has_rptrs, tt, t_flags); + } } ty_fn(f) { for a in f.inputs { - derive_flags(has_params, has_vars, has_rptrs, a.ty); + derive_flags(has_params, has_self, has_rptrs, a.ty, t_flags); } - derive_flags(has_params, has_vars, has_rptrs, f.output); + derive_flags(has_params, has_self, has_rptrs, f.output, t_flags); } ty_res(_, tt, tps) { - derive_flags(has_params, has_vars, has_rptrs, tt); - for tt in tps { derive_flags(has_params, has_vars, has_rptrs, tt); } + derive_flags(has_params, has_self, has_rptrs, tt, t_flags); + for tt in tps { + derive_flags(has_params, has_self, has_rptrs, tt, t_flags); + } } ty_constr(tt, _) { - derive_flags(has_params, has_vars, has_rptrs, tt); + derive_flags(has_params, has_self, has_rptrs, tt, t_flags); } } + + ret {has_params: has_params, has_self: has_self, has_rptrs: has_rptrs}; +} + +fn flags_for_sty(st: sty) -> t_flags { + flags_for_sty_base(st) {|t| get(t).t_flags } +} + +fn flags_for_t_i(&&t: t_i) -> t_flags { + alt *t { + ty_var_i(_) { {has_params: false, has_self: false, has_rptrs: false} } + sty_i(st) { flags_for_sty_base(st, flags_for_t_i(_)) } + } +} + +// Interns a type/name combination, stores the resulting box in cx.interner, +// and returns the box as cast to an unsafe ptr (see comments for t above). +fn mk_t_with_id(cx: ctxt, st: sty, o_def_id: option) -> t { + let key = {struct: st, o_def_id: o_def_id}; + alt cx.interner.find(key) { + some(t) { unsafe { ret unsafe::reinterpret_cast(t); } } + _ {} + } + let t_flags = flags_for_sty(st); let t = @{struct: st, id: cx.next_id, - has_params: has_params, - has_vars: has_vars, - has_rptrs: has_rptrs, + t_flags: t_flags, o_def_id: o_def_id}; cx.interner.insert(key, t); cx.next_id += 1u; unsafe { unsafe::reinterpret_cast(t) } } -fn mk_nil(cx: ctxt) -> t { mk_t(cx, ty_nil) } +fn mk_nil>(cx: C) -> T { cx.mk(ty_nil) } -fn mk_bot(cx: ctxt) -> t { mk_t(cx, ty_bot) } +fn mk_bot>(cx: C) -> T { cx.mk(ty_bot) } -fn mk_bool(cx: ctxt) -> t { mk_t(cx, ty_bool) } +fn mk_bool>(cx: C) -> T { cx.mk(ty_bool) } -fn mk_int(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_i)) } +fn mk_int>(cx: C) -> T { cx.mk(ty_int(ast::ty_i)) } -fn mk_float(cx: ctxt) -> t { mk_t(cx, ty_float(ast::ty_f)) } +fn mk_float>(cx: C) -> T { cx.mk(ty_float(ast::ty_f)) } -fn mk_uint(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u)) } +fn mk_uint>(cx: C) -> T { cx.mk(ty_uint(ast::ty_u)) } -fn mk_mach_int(cx: ctxt, tm: ast::int_ty) -> t { mk_t(cx, ty_int(tm)) } +fn mk_mach_int>(cx: C, tm: ast::int_ty) -> T { cx.mk(ty_int(tm)) } -fn mk_mach_uint(cx: ctxt, tm: ast::uint_ty) -> t { mk_t(cx, ty_uint(tm)) } +fn mk_mach_uint>(cx: C, tm: ast::uint_ty) -> T { cx.mk(ty_uint(tm)) } -fn mk_mach_float(cx: ctxt, tm: ast::float_ty) -> t { mk_t(cx, ty_float(tm)) } +fn mk_mach_float>(cx: C, tm: ast::float_ty) -> T { cx.mk(ty_float(tm)) } -fn mk_char(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_char)) } +fn mk_char>(cx: C) -> T { cx.mk(ty_int(ast::ty_char)) } -fn mk_str(cx: ctxt) -> t { mk_t(cx, ty_str) } +fn mk_str>(cx: C) -> T { cx.mk(ty_str) } -fn mk_enum(cx: ctxt, did: ast::def_id, tys: [t]) -> t { - mk_t(cx, ty_enum(did, tys)) +fn mk_enum>(cx: C, did: ast::def_id, tys: [T]) -> T { + cx.mk(ty_enum(did, tys)) } -fn mk_box(cx: ctxt, tm: mt) -> t { mk_t(cx, ty_box(tm)) } +fn mk_box>(cx: C, tm: mt_base) -> T { cx.mk(ty_box(tm)) } -fn mk_imm_box(cx: ctxt, ty: t) -> t { mk_box(cx, {ty: ty, - mutbl: ast::m_imm}) } +fn mk_imm_box>(cx: C, ty: T) -> T { mk_box(cx, {ty: ty, + mutbl: ast::m_imm}) } -fn mk_uniq(cx: ctxt, tm: mt) -> t { mk_t(cx, ty_uniq(tm)) } +fn mk_uniq>(cx: C, tm: mt_base) -> T { cx.mk(ty_uniq(tm)) } -fn mk_imm_uniq(cx: ctxt, ty: t) -> t { mk_uniq(cx, {ty: ty, - mutbl: ast::m_imm}) } +fn mk_imm_uniq>(cx: C, ty: T) -> T { mk_uniq(cx, {ty: ty, + mutbl: ast::m_imm}) } -fn mk_ptr(cx: ctxt, tm: mt) -> t { mk_t(cx, ty_ptr(tm)) } +fn mk_ptr>(cx: C, tm: mt_base) -> T { + cx.mk(ty_ptr(tm)) +} -fn mk_rptr(cx: ctxt, r: region, tm: mt) -> t { mk_t(cx, ty_rptr(r, tm)) } +fn mk_rptr>(cx: C, r: region, tm: mt_base) -> T { + cx.mk(ty_rptr(r, tm)) +} -fn mk_mut_ptr(cx: ctxt, ty: t) -> t { mk_ptr(cx, {ty: ty, - mutbl: ast::m_mutbl}) } +fn mk_mut_ptr>(cx: C, ty: T) -> T { mk_ptr(cx, {ty: ty, + mutbl: ast::m_mutbl}) } -fn mk_nil_ptr(cx: ctxt) -> t { +fn mk_nil_ptr>(cx: C) -> T { mk_ptr(cx, {ty: mk_nil(cx), mutbl: ast::m_imm}) } -fn mk_vec(cx: ctxt, tm: mt) -> t { mk_t(cx, ty_vec(tm)) } +fn mk_vec>(cx: C, tm: mt_base) -> T { cx.mk(ty_vec(tm)) } -fn mk_rec(cx: ctxt, fs: [field]) -> t { mk_t(cx, ty_rec(fs)) } +fn mk_rec>(cx: C, fs: [field_base]) -> T { cx.mk(ty_rec(fs)) } -fn mk_constr(cx: ctxt, t: t, cs: [@type_constr]) -> t { - mk_t(cx, ty_constr(t, cs)) +fn mk_constr>(cx: C, t: T, cs: [@type_constr]) -> T { + cx.mk(ty_constr(t, cs)) } -fn mk_tup(cx: ctxt, ts: [t]) -> t { mk_t(cx, ty_tup(ts)) } +fn mk_tup>(cx: C, ts: [T]) -> T { cx.mk(ty_tup(ts)) } -fn mk_fn(cx: ctxt, fty: fn_ty) -> t { mk_t(cx, ty_fn(fty)) } +fn mk_fn>(cx: C, fty: fn_ty_base) -> T { cx.mk(ty_fn(fty)) } -fn mk_iface(cx: ctxt, did: ast::def_id, tys: [t]) -> t { - mk_t(cx, ty_iface(did, tys)) +fn mk_iface>(cx: C, did: ast::def_id, tys: [T]) -> T { + cx.mk(ty_iface(did, tys)) } -fn mk_class(cx: ctxt, class_id: ast::def_id, tys: [t]) -> t { - mk_t(cx, ty_class(class_id, tys)) +fn mk_class>(cx: C, class_id: ast::def_id, tys: [T]) -> T { + cx.mk(ty_class(class_id, tys)) } -fn mk_res(cx: ctxt, did: ast::def_id, inner: t, tps: [t]) -> t { - mk_t(cx, ty_res(did, inner, tps)) +fn mk_res>(cx: C, did: ast::def_id, inner: T, tps: [T]) -> T { + cx.mk(ty_res(did, inner, tps)) } -fn mk_var(cx: ctxt, v: int) -> t { mk_t(cx, ty_var(v)) } +fn mk_var(v: int) -> t_i { @ty_var_i(v) } -fn mk_self(cx: ctxt, tps: [t]) -> t { mk_t(cx, ty_self(tps)) } +fn mk_self>(cx: C, tps: [T]) -> T { cx.mk(ty_self(tps)) } -fn mk_param(cx: ctxt, n: uint, k: def_id) -> t { mk_t(cx, ty_param(n, k)) } +fn mk_param>(cx: C, n: uint, k: def_id) -> T { cx.mk(ty_param(n, k)) } -fn mk_type(cx: ctxt) -> t { mk_t(cx, ty_type) } +fn mk_type>(cx: C) -> T { cx.mk(ty_type) } -fn mk_opaque_closure_ptr(cx: ctxt, ck: closure_kind) -> t { - mk_t(cx, ty_opaque_closure_ptr(ck)) +fn mk_opaque_closure_ptr>(cx: C, ck: closure_kind) -> T { + cx.mk(ty_opaque_closure_ptr(ck)) } -fn mk_opaque_box(cx: ctxt) -> t { mk_t(cx, ty_opaque_box) } +fn mk_opaque_box>(cx: C) -> T { cx.mk(ty_opaque_box) } fn mk_with_id(cx: ctxt, base: t, def_id: ast::def_id) -> t { mk_t_with_id(cx, get(base).struct, some(def_id)) } // Converts s to its machine type equivalent -pure fn mach_sty(cfg: @session::config, t: t) -> sty { - alt get(t).struct { +pure fn mach_sty( + cfg: @session::config, t: sty_base) -> sty_base { + + alt t { ty_int(ast::ty_i) { ty_int(cfg.int_type) } ty_uint(ast::ty_u) { ty_uint(cfg.uint_type) } ty_float(ast::ty_f) { ty_float(cfg.float_type) } - s { s } + _ { t } } } @@ -554,145 +671,300 @@ fn default_arg_mode_for_ty(ty: ty::t) -> ast::rmode { } fn walk_ty(ty: t, f: fn(t)) { - maybe_walk_ty(ty, {|t| f(t); true}); + f(ty); + walk_sty_base(get(ty).struct) {|t| + walk_ty(t, f) + } } fn maybe_walk_ty(ty: t, f: fn(t) -> bool) { if !f(ty) { ret; } - alt get(ty).struct { + walk_sty_base(get(ty).struct) {|t| + maybe_walk_ty(t, f) + } +} + +fn walk_sty_base(sty: sty_base, walkf: fn(T)) { + alt sty { ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | ty_str | ty_type | ty_opaque_box | - ty_opaque_closure_ptr(_) | ty_var(_) | ty_param(_, _) {} + ty_opaque_closure_ptr(_) | ty_param(_, _) {} ty_box(tm) | ty_vec(tm) | ty_ptr(tm) | ty_rptr(_, tm) { - maybe_walk_ty(tm.ty, f); + walkf(tm.ty); } ty_enum(_, subtys) | ty_iface(_, subtys) | ty_class(_, subtys) - | ty_self(subtys) { - for subty: t in subtys { maybe_walk_ty(subty, f); } + | ty_self(subtys) { + for subty in subtys { walkf(subty); } } ty_rec(fields) { - for fl: field in fields { maybe_walk_ty(fl.mt.ty, f); } + for fl in fields { walkf(fl.mt.ty); } } - ty_tup(ts) { for tt in ts { maybe_walk_ty(tt, f); } } + ty_tup(ts) { for tt in ts { walkf(tt); } } ty_fn(ft) { - for a: arg in ft.inputs { maybe_walk_ty(a.ty, f); } - maybe_walk_ty(ft.output, f); + for a in ft.inputs { walkf(a.ty); } + walkf(ft.output); } ty_res(_, sub, tps) { - maybe_walk_ty(sub, f); - for tp: t in tps { maybe_walk_ty(tp, f); } + walkf(sub); + for tp in tps { walkf(tp); } } - ty_constr(sub, _) { maybe_walk_ty(sub, f); } - ty_uniq(tm) { maybe_walk_ty(tm.ty, f); } + ty_constr(sub, _) { walkf(sub); } + ty_uniq(tm) { walkf(tm.ty); } } } -enum fold_mode { - fm_var(fn@(int) -> t), - fm_param(fn@(uint, def_id) -> t), - fm_rptr(fn@(region) -> region), - fm_general(fn@(t) -> t), +fn walk_ty_i(cx: ctxt, &&ty: t_i, f: fn(t_i)) { + alt *ty { + ty_var_i(_) { } + sty_i(sty) { walk_sty_base(sty) {|t| walk_ty_i(cx, t, f) } } + } } -fn fold_ty(cx: ctxt, fld: fold_mode, ty_0: t) -> t { - let ty = ty_0; +// The base for all folding operations. This is written in a "result monad" +// style so that errors can be propagated if necessary. I chose not to +// "deforest" this version though. If you wish to write a folding routine +// which cannot fail, then use `fold_sty_base()` below, which presents +// a friendlier interface. +fn fold_sty_base_err( + sty: sty_base, + fold_t: fn(T) -> result) -> result,E> { + import result::{chain, ok, map}; + + fn fold_mt( + mt: mt_base, + fold_t: fn(T) -> result) -> result,E> { - let tb = get(ty); - alt fld { - fm_var(_) { if !tb.has_vars { ret ty; } } - fm_param(_) { if !tb.has_params { ret ty; } } - fm_rptr(_) { if !tb.has_rptrs { ret ty; } } - fm_general(_) {/* no fast path */ } + chain(fold_t(mt.ty)) {|t| + ok({ty: t, mutbl: mt.mutbl}) + } } - alt tb.struct { - ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | - ty_str | ty_type | ty_opaque_closure_ptr(_) | - ty_opaque_box {} - ty_box(tm) { - ty = mk_box(cx, {ty: fold_ty(cx, fld, tm.ty), mutbl: tm.mutbl}); + fn fold_f( + fld: field_base, + fold_t: fn(T) -> result) -> result,E> { + + chain(fold_mt(fld.mt, fold_t)) {|fld_mt| + ok({ident: fld.ident, mt: fld_mt}) + } + } + + fn fold_arg( + arg: arg_base, + fold_t: fn(T) -> result) -> result,E> { + + chain(fold_t(arg.ty)) {|arg_ty| + ok({mode: arg.mode, ty: arg_ty}) + } + } + + alt sty { + ty_nil { ok(ty_nil) } + ty_bot { ok(ty_bot) } + ty_bool { ok(ty_bool) } + ty_int(i) { ok(ty_int(i)) } + ty_uint(i) { ok(ty_uint(i)) } + ty_float(i) { ok(ty_float(i)) } + ty_str { ok(ty_str) } + ty_type { ok(ty_type) } + ty_opaque_closure_ptr(c) { ok(ty_opaque_closure_ptr(c)) } + ty_opaque_box { ok(ty_opaque_box) } + ty_box(mt) { + chain(fold_mt(mt, fold_t)) {|mt| + ok(ty_box(mt)) + } } - ty_uniq(tm) { - ty = mk_uniq(cx, {ty: fold_ty(cx, fld, tm.ty), mutbl: tm.mutbl}); + ty_uniq(mt) { + chain(fold_mt(mt, fold_t)) {|mt| + ok(ty_uniq(mt)) + } } - ty_ptr(tm) { - ty = mk_ptr(cx, {ty: fold_ty(cx, fld, tm.ty), mutbl: tm.mutbl}); + ty_vec(mt) { + chain(fold_mt(mt, fold_t)) {|mt| + ok(ty_vec(mt)) + } } - ty_vec(tm) { - ty = mk_vec(cx, {ty: fold_ty(cx, fld, tm.ty), mutbl: tm.mutbl}); + ty_ptr(mt) { + chain(fold_mt(mt, fold_t)) {|mt| + ok(ty_ptr(mt)) + } } ty_enum(tid, subtys) { - ty = mk_enum(cx, tid, vec::map(subtys, {|t| fold_ty(cx, fld, t) })); + map(subtys, fold_t) {|subtys| + ok(ty_enum(tid, subtys)) + } } - ty_iface(did, subtys) { - ty = mk_iface(cx, did, vec::map(subtys, {|t| fold_ty(cx, fld, t) })); + ty_iface(tid, subtys) { + map(subtys, fold_t) {|subtys| + ok(ty_iface(tid, subtys)) + } + } + ty_class(did, subtys) { + map(subtys, fold_t) {|subtys| + ok(ty_class(did, subtys)) + } } ty_self(subtys) { - ty = mk_self(cx, vec::map(subtys, {|t| fold_ty(cx, fld, t) })); + map(subtys, fold_t) {|subtys| + ok(ty_self(subtys)) + } } ty_rec(fields) { - let new_fields: [field] = []; - for fl: field in fields { - let new_ty = fold_ty(cx, fld, fl.mt.ty); - let new_mt = {ty: new_ty, mutbl: fl.mt.mutbl}; - new_fields += [{ident: fl.ident, mt: new_mt}]; + map(fields, {|f| fold_f(f, fold_t)}) {|fields| + ok(ty_rec(fields)) } - ty = mk_rec(cx, new_fields); } ty_tup(ts) { - let new_ts = []; - for tt in ts { new_ts += [fold_ty(cx, fld, tt)]; } - ty = mk_tup(cx, new_ts); + map(ts, fold_t) {|ts| + ok(ty_tup(ts)) + } } ty_fn(f) { - let new_args: [arg] = []; - for a: arg in f.inputs { - let new_ty = fold_ty(cx, fld, a.ty); - new_args += [{mode: a.mode, ty: new_ty}]; + map(f.inputs, {|a| fold_arg(a, fold_t)}) {|inputs| + chain(fold_t(f.output)) {|output| + ok(ty_fn({proto: f.proto, + inputs: inputs, + output: output, + ret_style: f.ret_style, + constraints: f.constraints})) + } } - ty = mk_fn(cx, {inputs: new_args, - output: fold_ty(cx, fld, f.output) - with f}); } ty_res(did, subty, tps) { - let new_tps = []; - for tp: t in tps { new_tps += [fold_ty(cx, fld, tp)]; } - ty = mk_res(cx, did, fold_ty(cx, fld, subty), new_tps); - } - ty_var(id) { - alt fld { fm_var(folder) { ty = folder(id); } _ {/* no-op */ } } + chain(fold_t(subty)) {|subty| + map(tps, fold_t) {|tps| + ok(ty_res(did, subty, tps)) + } + } } ty_param(id, did) { - alt fld { fm_param(folder) { ty = folder(id, did); } _ {} } + ok(ty_param(id, did)) } - ty_rptr(r, tm) { - let region = alt fld { fm_rptr(folder) { folder(r) } _ { r } }; - ty = mk_rptr(cx, region, - {ty: fold_ty(cx, fld, tm.ty), mutbl: tm.mutbl}); + ty_rptr(r, mt) { + chain(fold_mt(mt, fold_t)) {|mt| + ok(ty_rptr(r, mt)) + } } ty_constr(subty, cs) { - ty = mk_constr(cx, fold_ty(cx, fld, subty), cs); - } - _ { - cx.sess.bug("unsupported sort of type in fold_ty"); + chain(fold_t(subty)) {|subty| + ok(ty_constr(subty, cs)) + } } } - alt tb.o_def_id { - some(did) { ty = mk_t_with_id(cx, get(ty).struct, some(did)); } - _ {} +} + +iface ty_ops { + fn tcx() -> ctxt; + fn no_rptrs(t: T) -> bool; + fn if_struct(t: T, r0: R, op: fn(sty_base) -> R) -> R; + fn mk(s: sty_base) -> T; + fn swap_T(t: T, s: sty_base) -> T; + fn to_str(t: T) -> str; + fn sess() -> session::session; +} + +impl of ty_ops for ctxt { + fn tcx() -> ctxt { self } + + fn no_rptrs(&&t: t) -> bool { !get(t).t_flags.has_rptrs } + + fn if_struct(&&t: t, _r0: R, op: fn(sty_base) -> R) -> R { + op(get(t).struct) + } + + fn mk(s: sty_base) -> t { + mk_t(self, s) + } + + fn swap_T(&&t: t, s: sty_base) -> t { + mk_t_with_id(self, s, get(t).o_def_id) } - // If this is a general type fold, then we need to run it now. - alt fld { fm_general(folder) { ret folder(ty); } _ { ret ty; } } + fn to_str(&&t: t) -> str { + ty_to_str(self, t) + } + + fn sess() -> session::session { + self.sess + } } +impl of ty_ops for @var_bindings { + fn tcx() -> ctxt { self.tcx } + + fn no_rptrs(&&_t: t_i) -> bool { false } // no cheap way to check + + fn if_struct(&&t: t_i, r0: R, op: fn(sty_base) -> R) -> R { + alt *t { + ty_var_i(_) { r0 } + sty_i(s) { op(s) } + } + } + + fn mk(s: sty_base) -> t_i { + @sty_i(s) + } + + fn swap_T(&&_t: t_i, s: sty_base) -> t_i { + self.mk(s) + } + + fn to_str(&&t: t_i) -> str { + ty_i_to_str(self, t) + } + + fn sess() -> session::session { + self.tcx.sess + } +} + +// Friendlier version of `fold_sty_base_err` for the case where the fold +// cannot fail. +fn fold_sty_base( + sty: sty_base, + fold_t: fn(T) -> U) -> sty_base { + + result::get(fold_sty_base_err(sty) {|t| + result::ok::( + fold_t(t)) + }) +} + +fn fold>( + cx: C, t0: T, f: fn(T) -> T) -> T { + + let t1 = cx.if_struct(t0, t0) {|sty| + cx.mk( + fold_sty_base(sty, {|t| fold(cx, t, f) })) + }; + f(t1) +} + +fn fold_rptr>( + cx: C, t0: T, f: fn(region) -> region) -> T { + + if cx.no_rptrs(t0) { ret t0; } + + fold(cx, t0) {|t| + cx.if_struct(t, t) {|sty| + let sty1 = alt sty { + ty_rptr(r, rt) { ty_rptr(f(r), rt) } + _ { sty } + }; + cx.mk(sty1) + } + } +} // Type utilities fn type_is_nil(ty: t) -> bool { get(ty).struct == ty_nil } +fn sty_is_nil(sty: sty_base) -> bool { sty == ty_nil } + fn type_is_bot(ty: t) -> bool { get(ty).struct == ty_bot } +fn sty_is_bool(sty: sty_base) -> bool { sty == ty_bool } + fn type_is_bool(ty: t) -> bool { get(ty).struct == ty_bool } fn type_is_structural(ty: t) -> bool { @@ -740,13 +1012,17 @@ fn get_element_type(ty: t, i: uint) -> t { } } -pure fn type_is_box(ty: t) -> bool { - alt get(ty).struct { +pure fn sty_is_box(sty: sty_base) -> bool { + alt sty { ty_box(_) { ret true; } _ { ret false; } } } +pure fn type_is_box(ty: t) -> bool { + sty_is_box(get(ty).struct) +} + pure fn type_is_boxed(ty: t) -> bool { alt get(ty).struct { ty_box(_) | ty_opaque_box { true } @@ -785,14 +1061,18 @@ pure fn type_is_unique(ty: t) -> bool { } } -pure fn type_is_scalar(ty: t) -> bool { - alt get(ty).struct { +pure fn sty_is_scalar(ty: sty_base) -> bool { + alt ty { ty_nil | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) | ty_type | ty_ptr(_) | ty_rptr(_, _) { true } _ { false } } } +pure fn type_is_scalar(ty: t) -> bool { + sty_is_scalar(get(ty).struct) +} + // FIXME maybe inline this for speed? fn type_is_immediate(ty: t) -> bool { ret type_is_scalar(ty) || type_is_boxed(ty) || @@ -1010,20 +1290,39 @@ fn type_structurally_contains_uniques(cx: ctxt, ty: t) -> bool { }); } -fn type_is_integral(ty: t) -> bool { - alt get(ty).struct { +fn sty_is_integral(ty: sty_base) -> bool { + alt ty { ty_int(_) | ty_uint(_) | ty_bool { true } _ { false } } } -fn type_is_fp(ty: t) -> bool { - alt get(ty).struct { +fn struct_test(ty: t_i, pfn: fn(sty_base) -> bool) -> bool { + alt *ty { + ty_var_i(_) { false } + sty_i(sty) { pfn(sty) } + } +} + +fn type_is_integral(ty: t) -> bool { + sty_is_integral(get(ty).struct) +} + +fn sty_is_fp(ty: sty_base) -> bool { + alt ty { ty_float(_) { true } _ { false } } } +fn type_is_fp(ty: t) -> bool { + sty_is_fp(get(ty).struct) +} + +fn sty_is_numeric(sty: sty_base) -> bool { + ret sty_is_integral(sty) || sty_is_fp(sty); +} + fn type_is_numeric(ty: t) -> bool { ret type_is_integral(ty) || type_is_fp(ty); } @@ -1084,10 +1383,8 @@ fn type_is_enum(ty: t) -> bool { } } -// Whether a type is enum like, that is a enum type with only nullary -// constructors -fn type_is_c_like_enum(cx: ctxt, ty: t) -> bool { - alt get(ty).struct { +fn sty_is_c_like_enum(cx: ctxt, ty: sty_base) -> bool { + alt ty { ty_enum(did, tps) { let variants = enum_variants(cx, did); let some_n_ary = vec::any(*variants, {|v| vec::len(v.args) > 0u}); @@ -1097,6 +1394,12 @@ fn type_is_c_like_enum(cx: ctxt, ty: t) -> bool { } } +// Whether a type is enum like, that is a enum type with only nullary +// constructors +fn type_is_c_like_enum(cx: ctxt, ty: t) -> bool { + sty_is_c_like_enum(cx, get(ty).struct) +} + fn type_param(ty: t) -> option { alt get(ty).struct { ty_param(id, _) { ret some(id); } @@ -1105,16 +1408,6 @@ fn type_param(ty: t) -> option { ret none; } -// Returns a vec of all the type variables -// occurring in t. It may contain duplicates. -fn vars_in_type(ty: t) -> [int] { - let rslt = []; - walk_ty(ty) {|ty| - alt get(ty).struct { ty_var(v) { rslt += [v]; } _ { } } - } - rslt -} - fn type_autoderef(cx: ctxt, t: t) -> t { let t1 = t; loop { @@ -1207,7 +1500,6 @@ fn hash_type_structure(st: sty) -> uint { for a in f.inputs { h = hash_subty(h, a.ty); } hash_subty(h, f.output) } - ty_var(v) { hash_uint(30u, v as uint) } ty_param(pid, did) { hash_def(hash_uint(31u, pid), did) } ty_self(ts) { let h = 28u; @@ -1295,7 +1587,8 @@ fn constrs_eq(cs: [@constr], ds: [@constr]) -> bool { fn node_id_to_type(cx: ctxt, id: ast::node_id) -> t { alt smallintmap::find(*cx.node_types, id as uint) { some(t) { t } - none { cx.sess.bug(#fmt("node_id_to_type: unbound node ID %?", id)); } + none { cx.sess.bug(#fmt("node_id_to_type: no type for node %s", + ast_map::node_str(cx.items, id))); } } } @@ -1346,20 +1639,6 @@ fn is_fn_ty(fty: t) -> bool { } } -// Just checks whether it's a fn that returns bool, -// not its purity. -fn is_pred_ty(fty: t) -> bool { - is_fn_ty(fty) && type_is_bool(ty_fn_ret(fty)) -} - -fn ty_var_id(typ: t) -> int { - alt get(typ).struct { - ty_var(vid) { ret vid; } - _ { #error("ty_var_id called on non-var ty"); fail; } - } -} - - // Type accessors for AST nodes fn block_ty(cx: ctxt, b: ast::blk) -> t { ret node_id_to_type(cx, b.node.id); @@ -1372,7 +1651,6 @@ fn pat_ty(cx: ctxt, pat: @ast::pat) -> t { ret node_id_to_type(cx, pat.id); } - // Returns the type of an expression as a monotype. // // NB: This type doesn't provide type parameter substitutions; e.g. if you @@ -1410,7 +1688,7 @@ fn stmt_node_id(s: @ast::stmt) -> ast::node_id { } } -fn field_idx(id: ast::ident, fields: [field]) -> option { +fn field_idx(id: ast::ident, fields: [field_base]) -> option { let i = 0u; for f in fields { if f.ident == id { ret some(i); } i += 1u; } ret none; @@ -1441,24 +1719,6 @@ fn sort_methods(meths: [method]) -> [method] { ret std::sort::merge_sort(bind method_lteq(_, _), meths); } -fn occurs_check(tcx: ctxt, sp: span, vid: int, rt: t) { - // Fast path - if !type_has_vars(rt) { ret; } - - // Occurs check! - if vec::contains(vars_in_type(rt), vid) { - // Maybe this should be span_err -- however, there's an - // assertion later on that the type doesn't contain - // variables, so in this case we have to be sure to die. - tcx.sess.span_fatal - (sp, "type inference failed because I \ - could not find a type\n that's both of the form " - + ty_to_str(tcx, mk_var(tcx, vid)) + - " and of the form " + ty_to_str(tcx, rt) + - " - such a type would have to be infinitely large."); - } -} - // Maintains a little union-set tree for inferred modes. `canon()` returns // the current head value for `m0`. fn canon(tbl: hashmap>, @@ -1530,73 +1790,73 @@ fn set_default_mode(cx: ctxt, m: ast::mode, m_def: ast::rmode) { } } +fn ty_to_ty_i(tcx: ctxt, t: t) -> t_i { + fn ty_to_sty_i(tcx: ctxt, t: t) -> sty_i { + fold_sty_base(get(t).struct, {|t| ty_to_ty_i(tcx, t)}) + } + + @sty_i(ty_to_sty_i(tcx, t)) +} + +fn ty_to_ty_i_subst(tcx: ctxt, t: t, substs: [t_i]) -> t_i { + alt get(t).struct { + ty_param(idx, _) { + substs[idx] + } + sty { + @sty_i(fold_sty_base(sty) {|t1| + ty_to_ty_i_subst(tcx, t1, substs) + }) + } + } +} + // Type unification via Robinson's algorithm (Robinson 1965). Implemented as // described in Hoder and Voronkov: // // http://www.cs.man.ac.uk/~hoderk/ubench/unification_full.pdf mod unify { - import result::{result, ok, err, chain, map, map2}; + import result::{result, ok, ok1, err, chain, map, map2}; + import std::list; - export fixup_vars; - export mk_var_bindings; - export resolve_type_structure; + export resolve_type; export resolve_type_var; export unify; - export var_bindings; - export precise, in_bindings; + export get_var_binding; + export uctxt; type ures = result; // in case of failure, value is the idx of an unresolved type var - type fres = result; - - type var_bindings = - {sets: ufind::ufind, types: smallintmap::smallintmap}; - - enum unify_style { - precise, - in_bindings(@var_bindings), - } - type uctxt = {st: unify_style, tcx: ctxt}; - - fn mk_var_bindings() -> @var_bindings { - ret @{sets: ufind::make(), types: smallintmap::mk::()}; - } + type fres = result; // Unifies two sets. fn union( - cx: @uctxt, set_a: uint, set_b: uint, + vb: @var_bindings, set_a: uint, set_b: uint, variance: variance, nxt: fn() -> ures) -> ures { - let vb = alt cx.st { - in_bindings(vb) { vb } - _ { cx.tcx.sess.bug("someone forgot to document an invariant \ - in union"); } - }; ufind::grow(vb.sets, uint::max(set_a, set_b) + 1u); let root_a = ufind::find(vb.sets, set_a); let root_b = ufind::find(vb.sets, set_b); - let replace_type = ( - fn@(vb: @var_bindings, t: t) { - ufind::union(vb.sets, set_a, set_b); - let root_c: uint = ufind::find(vb.sets, set_a); - smallintmap::insert::(vb.types, root_c, t); - } - ); + let replace_type = fn@(vb: @var_bindings, t: sty_i) { + ufind::union(vb.sets, set_a, set_b); + let root_c: uint = ufind::find(vb.sets, set_a); + smallintmap::insert(vb.var_types, root_c, t); + }; - alt smallintmap::find(vb.types, root_a) { + alt smallintmap::find(vb.var_types, root_a) { none { - alt smallintmap::find(vb.types, root_b) { + alt smallintmap::find(vb.var_types, root_b) { none { ufind::union(vb.sets, set_a, set_b); ret nxt(); } some(t_b) { replace_type(vb, t_b); ret nxt(); } } } some(t_a) { - alt smallintmap::find(vb.types, root_b) { + alt smallintmap::find(vb.var_types, root_b) { none { replace_type(vb, t_a); ret nxt(); } some(t_b) { - ret unify_step(cx, t_a, t_b, variance) {|t_c| + ret unify_sty(vb, t_a, t_b, variance) {|t_c| replace_type(vb, t_c); nxt() }; @@ -1607,33 +1867,108 @@ mod unify { } fn record_var_binding( - cx: @uctxt, key: int, - typ: t, variance: variance, - nxt: fn(t) -> ures) -> ures { + vb: @var_bindings, key: int, + typ: sty_i, variance: variance, + nxt: fn(&&t_i) -> ures) -> ures { - let vb = alt check cx.st { in_bindings(vb) { vb } }; ufind::grow(vb.sets, (key as uint) + 1u); let root = ufind::find(vb.sets, key as uint); - let result_type = typ; - alt smallintmap::find(vb.types, root) { + alt smallintmap::find(vb.var_types, root) { some(old_type) { - alt unify_step(cx, old_type, typ, variance, {|v| ok(v)}) { - ok(unified_type) { result_type = unified_type; } - err(e) { ret err(e); } + alt unify_sty(vb, old_type, typ, variance, ok1(_)) { + err(e) { + ret err(e); + } + ok(unified_type) { + smallintmap::insert(vb.var_types, root, unified_type); + ret nxt(@ty_var_i(key)); + } } } - none {/* fall through */ } + none { + smallintmap::insert(vb.var_types, root, typ); + ret nxt(@ty_var_i(key)); + } + } + } + + fn get_var_binding(vb: @var_bindings, vid: int, + unbound: fn(int) -> T, + bound: fn(sty_i) -> T) -> T { + if vid as uint >= ufind::set_count(vb.sets) { + ret unbound(vid); + } + let root_id = ufind::find(vb.sets, vid as uint); + #debug["vid=%d root_id=%?", vid, root_id]; + alt smallintmap::find(vb.var_types, root_id) { + none { ret unbound(vid); } + some(rt) { ret bound(rt); } } - smallintmap::insert(vb.types, root, result_type); - ret nxt(mk_var(cx.tcx, key)); + } + + iface uctxt { + fn tcx() -> ctxt; + fn unify_step( + expected: T, actual: T, variance: variance, + nxt: fn(T) -> ures) -> ures; + } + + impl of uctxt for @var_bindings { + fn tcx() -> ctxt { self.tcx } + + fn unify_step( + expected: t_i, actual: t_i, variance: variance, + nxt: fn(&&t_i) -> ures) -> ures { + + alt (*expected, *actual) { + (ty_var_i(e_id), ty_var_i(a_id)) { + union(self, e_id as uint, a_id as uint, variance) {|| + nxt(actual) + } + } + (sty_i(e), ty_var_i(a_id)) { + let v = variance_transform(variance, contravariant); + record_var_binding(self, a_id, e, v, nxt) + } + (ty_var_i(e_id), sty_i(a)) { + let v = variance_transform(variance, covariant); + record_var_binding(self, e_id, a, v, nxt) + } + (sty_i(e), sty_i(a)) { + unify_sty(self, e, a, variance) {|r| + nxt(@sty_i(r)) + } + } + } + } + } + + impl of uctxt for ctxt { + fn tcx() -> ctxt { self } + + fn unify_step( + expected: t, actual: t, variance: variance, + nxt: fn(&&t) -> ures) -> ures { + + if expected == actual { ret nxt(expected); } // fast path + + unify_sty(self, get(expected).struct, + get(actual).struct, variance) {|sty| + nxt(mk_t(self, sty)) + } + } + } + + fn unify>(cx: U, expected: T, actual: T) -> ures { + ret cx.unify_step(expected, actual, covariant, ok1(_)); } // Simple structural type comparison. - fn struct_cmp( - cx: @uctxt, expected: t, actual: t, - nxt: fn(t) -> ures) -> ures { + fn struct_cmp,R:copy>( + cx: U, expected: sty_base, actual: sty_base, + nxt: fn(&&sty_base) -> ures) -> ures { - let tcx = cx.tcx; + let tcx = cx.tcx(); let cfg = tcx.sess.targ_cfg; if mach_sty(cfg, expected) == mach_sty(cfg, actual) { ret nxt(expected); @@ -1643,60 +1978,51 @@ mod unify { // Right now this just checks that the lists of constraints are // pairwise equal. - fn unify_constrs( + fn unify_constrs( expected: [@type_constr], actual: [@type_constr], - nxt: fn([@type_constr]) -> ures) -> ures { + nxt: fn([@type_constr]) -> ures) -> ures { if check vec::same_length(expected, actual) { map2(expected, actual, - {|e,a| unify_constr(e, a, {|v| ok(v)})}, nxt) + {|e,a| unify_constr(e, a, ok1(_))}, nxt) } else { ret err(terr_constr_len(expected.len(), actual.len())); } } - fn unify_constr( - expected: @type_constr, - actual_constr: @type_constr, - nxt: fn(@type_constr) -> ures) -> ures { + fn unify_constr( + e_constr: @type_constr, + a_constr: @type_constr, + nxt: fn(&&@type_constr) -> ures) -> ures { - let err_res = err(terr_constr_mismatch(expected, actual_constr)); - if expected.node.id != actual_constr.node.id { ret err_res; } - let expected_arg_len = vec::len(expected.node.args); - let actual_arg_len = vec::len(actual_constr.node.args); - if expected_arg_len != actual_arg_len { ret err_res; } - let i = 0u; - let actual; - for a: @ty_constr_arg in expected.node.args { - actual = actual_constr.node.args[i]; - alt a.node { - carg_base { - alt actual.node { carg_base { } _ { ret err_res; } } - } - carg_lit(l) { - alt actual.node { - carg_lit(m) { if l != m { ret err_res; } } - _ { ret err_res; } - } - } - carg_ident(p) { - alt actual.node { - carg_ident(q) { if p.node != q.node { ret err_res; } } - _ { ret err_res; } + if e_constr.node.id != a_constr.node.id { + ret err(terr_constr_mismatch(e_constr, a_constr)); + } + let e_args = e_constr.node.args; + let a_args = a_constr.node.args; + if check vec::same_length(e_args, a_args) { + let check_arg = fn@(&&e_arg: @ty_constr_arg, + &&a_arg: @ty_constr_arg) -> ures<()> { + if e_arg.node != a_arg.node { + ret err(terr_constr_mismatch(e_constr, a_constr)); + } else { + ret ok(()); } - } + }; + map2(e_args, a_args, check_arg) {|_i| + ret nxt(e_constr); } - i += 1u; + } else { + ret err(terr_constr_mismatch(e_constr, a_constr)); } - ret nxt(expected); } // Unifies two mutability flags. - fn unify_mut( + fn unify_mut( expected: ast::mutability, actual: ast::mutability, variance: variance, mut_err: type_err, - nxt: fn(ast::mutability, variance) -> ures) -> ures { + nxt: fn(ast::mutability, variance) -> ures) -> ures { // If you're unifying on something mutable then we have to // be invariant on the inner type @@ -1724,9 +2050,9 @@ mod unify { ret err(mut_err); } - fn unify_fn_proto( + fn unify_fn_proto( e_proto: ast::proto, a_proto: ast::proto, variance: variance, - nxt: fn(ast::proto) -> ures) -> ures { + nxt: fn(ast::proto) -> ures) -> ures { // Prototypes form a diamond-shaped partial order: // @@ -1756,39 +2082,38 @@ mod unify { }; } - fn unify_arg( - cx: @uctxt, e_arg: arg, a_arg: arg, - variance: variance, - nxt: fn(arg) -> ures) -> ures { + fn unify_arg,R:copy>( + cx: U, e_arg: arg_base, a_arg: arg_base, + variance: variance, nxt: fn(arg_base) -> ures) -> ures { // Unify the result modes. - chain(unify_mode(cx.tcx, e_arg.mode, a_arg.mode)) {|mode| - unify_step(cx, e_arg.ty, a_arg.ty, variance) {|ty| + chain(unify_mode(cx.tcx(), e_arg.mode, a_arg.mode)) {|mode| + cx.unify_step(e_arg.ty, a_arg.ty, variance) {|ty| nxt({mode: mode, ty: ty}) } } } - fn unify_args( - cx: @uctxt, e_args: [arg], a_args: [arg], - variance: variance, nxt: fn([arg]) -> ures) -> ures { + fn unify_args,R:copy>( + cx: U, e_args: [arg_base], a_args: [arg_base], + variance: variance, nxt: fn([arg_base]) -> ures) -> ures { if check vec::same_length(e_args, a_args) { // The variance changes (flips basically) when descending // into arguments of function types let variance = variance_transform(variance, contravariant); map2(e_args, a_args, - {|e,a| unify_arg(cx, e, a, variance, {|v| ok(v)})}, + {|e,a| unify_arg(cx, e, a, variance, ok1(_))}, nxt) } else { ret err(terr_arg_count); } } - fn unify_ret_style( + fn unify_ret_style( e_ret_style: ret_style, a_ret_style: ret_style, - nxt: fn(ret_style) -> ures) -> ures { + nxt: fn(ret_style) -> ures) -> ures { if a_ret_style != ast::noreturn && a_ret_style != e_ret_style { /* even though typestate checking is mostly @@ -1802,124 +2127,65 @@ mod unify { } } - fn unify_fn( - cx: @uctxt, e_f: fn_ty, a_f: fn_ty, variance: variance, - nxt: fn(t) -> ures) -> ures { + fn unify_fn,R:copy>( + cx: U, e_f: fn_ty_base, a_f: fn_ty_base, variance: variance, + nxt: fn(&&fn_ty_base) -> ures) -> ures { unify_fn_proto(e_f.proto, a_f.proto, variance) {|proto| unify_ret_style(e_f.ret_style, a_f.ret_style) {|rs| unify_args(cx, e_f.inputs, a_f.inputs, variance) {|args| - unify_step(cx, e_f.output, a_f.output, variance) {|rty| + cx.unify_step(e_f.output, a_f.output, variance) {|rty| let cs = e_f.constraints; // FIXME: Unify? - nxt(mk_fn(cx.tcx, {proto: proto, - inputs: args, - output: rty, - ret_style: rs, - constraints: cs})) + nxt({proto: proto, + inputs: args, + output: rty, + ret_style: rs, + constraints: cs}) } } } } } - // If the given type is a variable, returns the structure of that type. - fn resolve_type_structure(vb: @var_bindings, typ: t) -> fres { - alt get(typ).struct { - ty_var(vid) { - if vid as uint >= ufind::set_count(vb.sets) { ret err(vid); } - let root_id = ufind::find(vb.sets, vid as uint); - alt smallintmap::find::(vb.types, root_id) { - none { ret err(vid); } - some(rt) { ret ok(rt); } - } - } - _ { ret ok(typ); } - } - } - - // Specifies the allowable subtyping between expected and actual types - enum variance { - // Actual may be a subtype of expected - covariant, - // Actual may be a supertype of expected - contravariant, - // Actual must be the same type as expected - invariant, - } - - // The calculation for recursive variance - // "Taming the Wildcards: Combining Definition- and Use-Site Variance" - // by John Altidor, et. al. - // - // I'm just copying the table from figure 1 - haven't actually - // read the paper (yet). - fn variance_transform(a: variance, b: variance) -> variance { - alt a { - covariant { - alt b { - covariant { covariant } - contravariant { contravariant } - invariant { invariant } - } - } - contravariant { - alt b { - covariant { contravariant } - contravariant { covariant } - invariant { invariant } - } - } - invariant { - alt b { - covariant { invariant } - contravariant { invariant } - invariant { invariant } - } - } - } - } - - fn unify_tys( - cx: @uctxt, expected_tps: [t], actual_tps: [t], - variance: variance, nxt: fn([t]) -> ures) + fn unify_tys,R:copy>( + cx: U, expected_tps: [T], actual_tps: [T], + variance: variance, nxt: fn([T]) -> ures) : vec::same_length(expected_tps, actual_tps) - -> ures { + -> ures { map2(expected_tps, actual_tps, - {|e,a| unify_step(cx, e, a, variance, {|v| ok(v)})}, + {|e,a| cx.unify_step(e, a, variance, ok1(_))}, nxt) } - fn unify_tps( - cx: @uctxt, expected_tps: [t], actual_tps: [t], - variance: variance, nxt: fn([t]) -> ures) - -> ures { + fn unify_tps,R:copy>( + cx: U, expected_tps: [T], actual_tps: [T], + variance: variance, nxt: fn([T]) -> ures) + -> ures { if check vec::same_length(expected_tps, actual_tps) { - map2(expected_tps, actual_tps, - {|e,a| unify_step(cx, e, a, variance, {|v| ok(v)})}, - nxt) + unify_tys(cx, expected_tps, actual_tps, variance, nxt) } else { err(terr_ty_param_size(expected_tps.len(), actual_tps.len())) } } - fn unify_mt( - cx: @uctxt, e_mt: mt, a_mt: mt, variance: variance, - mut_err: type_err, - nxt: fn(mt) -> ures) -> ures { + fn unify_mt,R:copy>( + cx: U, e_mt: mt_base, a_mt: mt_base, variance: variance, + mut_err: type_err, nxt: fn(mt_base) -> ures) -> ures { + unify_mut(e_mt.mutbl, a_mt.mutbl, variance, mut_err) {|mutbl,var| - unify_step(cx, e_mt.ty, a_mt.ty, var) {|ty| + cx.unify_step(e_mt.ty, a_mt.ty, var) {|ty| nxt({ty: ty, mutbl: mutbl}) } } } - fn unify_regions( - cx: @uctxt, e_region: region, a_region: region, - variance: variance, - nxt: fn(region) -> ures) -> ures { + fn unify_regions,R:copy>( + cx: U, e_region: region, a_region: region, + variance: variance, nxt: fn(region) -> ures) -> ures { + let sub, super; alt variance { covariant { super = e_region; sub = a_region; } @@ -1943,18 +2209,17 @@ mod unify { // Outer regions are subtypes of inner regions. (This is somewhat // surprising!) - let superscope = region::region_to_scope(cx.tcx.region_map, super); - let subscope = region::region_to_scope(cx.tcx.region_map, sub); - if region::scope_contains(cx.tcx.region_map, subscope, superscope) { + let superscope = region::region_to_scope(cx.tcx().region_map, super); + let subscope = region::region_to_scope(cx.tcx().region_map, sub); + if region::scope_contains(cx.tcx().region_map, subscope, superscope) { ret nxt(super); } ret err(terr_regions_differ(false, sub, super)); } - fn unify_field( - cx: @uctxt, e_field: field, a_field: field, - variance: variance, - nxt: fn(field) -> ures) -> ures { + fn unify_field,R:copy>( + cx: U, e_field: field_base, a_field: field_base, + variance: variance, nxt: fn(field_base) -> ures) -> ures { if e_field.ident != a_field.ident { ret err(terr_record_fields(e_field.ident, @@ -1967,27 +2232,11 @@ mod unify { } } - fn unify_step( - cx: @uctxt, expected: t, actual: t, - variance: variance, nxt: fn(t) -> ures) -> ures { + fn unify_sty,R:copy>( + cx: U, expected: sty_base, actual: sty_base, + variance: variance, nxt: fn(&&sty_base) -> ures) -> ures { - // Fast path. - if expected == actual { ret nxt(expected); } - - alt (get(expected).struct, get(actual).struct) { - (ty_var(e_id), ty_var(a_id)) { - union(cx, e_id as uint, a_id as uint, variance) {|| - nxt(actual) - } - } - (_, ty_var(a_id)) { - let v = variance_transform(variance, contravariant); - record_var_binding(cx, a_id, expected, v, nxt) - } - (ty_var(e_id), _) { - let v = variance_transform(variance, covariant); - record_var_binding(cx, e_id, actual, v, nxt) - } + alt (expected, actual) { // induces copies, uncool. (_, ty_bot) { nxt(expected) } (ty_bot, _) { nxt(actual) } (ty_nil, _) | (ty_bool, _) | (ty_int(_), _) | (ty_uint(_), _) | @@ -1999,54 +2248,54 @@ mod unify { } (ty_enum(e_id, e_tps), ty_enum(a_id, a_tps)) if e_id == a_id { unify_tps(cx, e_tps, a_tps, variance) {|tps| - nxt(mk_enum(cx.tcx, e_id, tps)) + nxt(ty_enum(e_id, tps)) } } (ty_iface(e_id, e_tps), ty_iface(a_id, a_tps)) if e_id == a_id { unify_tps(cx, e_tps, a_tps, variance) {|tps| - nxt(mk_iface(cx.tcx, e_id, tps)) + nxt(ty_iface(e_id, tps)) } } (ty_class(e_id, e_tps), ty_class(a_id, a_tps)) if e_id == a_id { unify_tps(cx, e_tps, a_tps, variance) {|tps| - nxt(mk_class(cx.tcx, e_id, tps)) + nxt(ty_class(e_id, tps)) } } (ty_box(e_mt), ty_box(a_mt)) { unify_mt(cx, e_mt, a_mt, variance, terr_box_mutability, - {|mt| nxt(mk_box(cx.tcx, mt))}) + {|mt| nxt(ty_box(mt))}) } (ty_uniq(e_mt), ty_uniq(a_mt)) { unify_mt(cx, e_mt, a_mt, variance, terr_box_mutability, - {|mt| nxt(mk_uniq(cx.tcx, mt))}) + {|mt| nxt(ty_uniq(mt))}) } (ty_vec(e_mt), ty_vec(a_mt)) { unify_mt(cx, e_mt, a_mt, variance, terr_vec_mutability, - {|mt| nxt(mk_vec(cx.tcx, mt))}) + {|mt| nxt(ty_vec(mt))}) } (ty_ptr(e_mt), ty_ptr(a_mt)) { unify_mt(cx, e_mt, a_mt, variance, terr_ptr_mutability, - {|mt| nxt(mk_ptr(cx.tcx, mt))}) + {|mt| nxt(ty_ptr(mt))}) } (ty_rptr(e_region, e_mt), ty_rptr(a_region, a_mt)) { - unify_regions(cx, e_region, a_region, variance) {|r| + unify_regions::(cx, e_region, a_region, variance) {|r| unify_mt(cx, e_mt, a_mt, variance, terr_ref_mutability, - {|mt| nxt(mk_rptr(cx.tcx, r, mt))}) + {|mt| nxt(ty_rptr(r, mt))}) } } (ty_res(e_id, e_inner, e_tps), ty_res(a_id, a_inner, a_tps)) if e_id == a_id { - unify_step(cx, e_inner, a_inner, variance) {|t| - unify_tps(cx, e_tps, a_tps, variance) {|tps| - nxt(mk_res(cx.tcx, a_id, t, tps)) - } - } + cx.unify_step(e_inner, a_inner, variance) {|t| + unify_tps(cx, e_tps, a_tps, variance) {|tps| + nxt(ty_res(a_id, t, tps)) + } + } } (ty_rec(e_fields), ty_rec(a_fields)) { if check vec::same_length(e_fields, a_fields) { map2(e_fields, a_fields, - {|e,a| unify_field(cx, e, a, variance, {|v| ok(v)})}, - {|fields| nxt(mk_rec(cx.tcx, fields))}) + {|e,a| unify_field(cx, e, a, variance, ok1(_))}, + {|fields| nxt(ty_rec(fields))}) } else { ret err(terr_record_size(e_fields.len(), a_fields.len())); @@ -2055,40 +2304,143 @@ mod unify { (ty_tup(e_elems), ty_tup(a_elems)) { if check vec::same_length(e_elems, a_elems) { unify_tys(cx, e_elems, a_elems, variance) {|elems| - nxt(mk_tup(cx.tcx, elems)) + nxt(ty_tup(elems)) } } else { err(terr_tuple_size(e_elems.len(), a_elems.len())) } } (ty_fn(e_fty), ty_fn(a_fty)) { - unify_fn(cx, e_fty, a_fty, variance, nxt) + unify_fn(cx, e_fty, a_fty, variance) {|fty| + nxt(ty_fn(fty)) + } } (ty_constr(e_t, e_constrs), ty_constr(a_t, a_constrs)) { // unify the base types... - unify_step(cx, e_t, a_t, variance) {|rty| + cx.unify_step(e_t, a_t, variance) {|rty| // FIXME: probably too restrictive -- // requires the constraints to be syntactically equal unify_constrs(e_constrs, a_constrs) {|constrs| - nxt(mk_constr(cx.tcx, rty, constrs)) + nxt(ty_constr(rty, constrs)) } } } - (ty_constr(e_t, _), _) { + /*NDM + (ty_constr(e_t, e_constrs), _) { // If the actual type is *not* a constrained type, // then we go ahead and just ignore the constraints on // the expected type. typestate handles the rest. - unify_step(cx, e_t, actual, variance, nxt) + cx.unify_step(e_t, sty_i(actual), variance) {|e_t| + // FIXME--is it ok to assign this type? seems a bit risky. + nxt(ty_constr(e_t, e_constrs)) + } } + */ _ { err(terr_mismatch) } } } - fn unify(expected: t, actual: t, st: unify_style, - tcx: ctxt) -> ures { - let cx = @{st: st, tcx: tcx}; - ret unify_step(cx, expected, actual, covariant, {|v| ok(v)}); + + fn refresh_var(vb: @var_bindings, vid: int) -> t_i { + get_var_binding( + vb, vid, + /* if unbound: */ {|vid| @ty_var_i(vid)}, + /* if bound: */ {|s| @sty_i(s) }) + } + + type resolve_ctxt = { + vb: @var_bindings, + vars_seen: @list::list + }; + + fn resolve_sty( + rc: resolve_ctxt, t: sty_i, + nxt: fn(&&sty_base) -> fres) -> fres { + + chain(fold_sty_base_err(t, resolve_t(rc, _, ok1(_))), nxt) + } + + fn resolve_t( + rc: resolve_ctxt, &&t: t_i, nxt: fn(&&t) -> fres) -> fres { + + alt *t { + ty_var_i(vid) { + if list::has(*rc.vars_seen, vid) { + err(rerr_cyclic_var(vid)) + } else { + get_var_binding( + rc.vb, vid, + + // if unbound: + {|vid| err(rerr_unresolved_var(vid))}, + + // if bound: + {|sty| + let rc1 = {vars_seen: @list::cons(vid, rc.vars_seen) + with rc}; + resolve_sty(rc1, sty) {|sty| + nxt(mk_t(rc.vb.tcx, sty)) + } + }) + } + } + + sty_i(sty) { + resolve_sty(rc, sty) {|sty| + nxt(mk_t(rc.vb.tcx, sty)) + } + } + } + } + + // If the given type is a variable, returns the structure of that type. + fn resolve_type(vb: @var_bindings, t: t_i) -> fres { + let rc = {vb: vb, vars_seen: @list::nil}; + resolve_t(rc, t, ok1(_)) } - fn dump_var_bindings(tcx: ctxt, vb: @var_bindings) { + + // Specifies the allowable subtyping between expected and actual types + enum variance { + // Actual may be a subtype of expected + covariant, + // Actual may be a supertype of expected + contravariant, + // Actual must be the same type as expected + invariant, + } + + // The calculation for recursive variance + // "Taming the Wildcards: Combining Definition- and Use-Site Variance" + // by John Altidor, et. al. + // + // I'm just copying the table from figure 1 - haven't actually + // read the paper (yet). + fn variance_transform(a: variance, b: variance) -> variance { + alt a { + covariant { + alt b { + covariant { covariant } + contravariant { contravariant } + invariant { invariant } + } + } + contravariant { + alt b { + covariant { contravariant } + contravariant { covariant } + invariant { invariant } + } + } + invariant { + alt b { + covariant { invariant } + contravariant { invariant } + invariant { invariant } + } + } + } + } + + fn dump_var_bindings(vb: @var_bindings) { let i = 0u; while i < vec::len::(vb.sets.nodes) { let sets = ""; @@ -2098,77 +2450,24 @@ mod unify { j += 1u; } let typespec; - alt smallintmap::find::(vb.types, i) { + alt smallintmap::find(vb.var_types, i) { none { typespec = ""; } - some(typ) { typespec = " =" + ty_to_str(tcx, typ); } + some(typ) { typespec = " =" + ty_i_to_str(vb, @sty_i(typ)); } } #error("set %u:%s%s", i, typespec, sets); i += 1u; } } - // Fixups and substitutions - // Takes an optional span - complain about occurs check violations - // iff the span is present (so that if we already know we're going - // to error anyway, we don't complain) - fn fixup_vars(tcx: ctxt, sp: option, vb: @var_bindings, - typ: t) -> fres { - fn subst_vars(tcx: ctxt, sp: option, vb: @var_bindings, - unresolved: @mutable option, - vars_seen: std::list::list, vid: int) -> t { - // Should really return a fixup_result instead of a t, but fold_ty - // doesn't allow returning anything but a t. - if vid as uint >= ufind::set_count(vb.sets) { - *unresolved = some(vid); - ret mk_var(tcx, vid); - } - let root_id = ufind::find(vb.sets, vid as uint); - alt smallintmap::find::(vb.types, root_id) { - none { *unresolved = some(vid); ret mk_var(tcx, vid); } - some(rt) { - let give_up = false; - std::list::iter(vars_seen) {|v| - if v == vid { - give_up = true; - option::may(sp) {|sp| - tcx.sess.span_fatal( - sp, "can not instantiate infinite type"); - } - } - } - // Return the type unchanged, so we can error out - // downstream - if give_up { ret rt; } - ret fold_ty(tcx, fm_var(bind subst_vars( - tcx, sp, vb, unresolved, std::list::cons(vid, @vars_seen), - _)), rt); - } - } - } - let unresolved = @mutable none::; - let rty = fold_ty(tcx, fm_var(bind subst_vars( - tcx, sp, vb, unresolved, std::list::nil, _)), typ); - let ur = *unresolved; - alt ur { - none { ret ok(rty); } - some(var_id) { ret err(var_id); } - } - } - fn resolve_type_var(tcx: ctxt, sp: option, vb: @var_bindings, - vid: int) -> fres { - if vid as uint >= ufind::set_count(vb.sets) { ret err(vid); } - let root_id = ufind::find(vb.sets, vid as uint); - alt smallintmap::find::(vb.types, root_id) { - none { ret err(vid); } - some(rt) { ret fixup_vars(tcx, sp, vb, rt); } - } + fn resolve_type_var(vb: @var_bindings, vid: int) -> fres { + resolve_type(vb, @ty_var_i(vid)) } } -fn same_type(cx: ctxt, a: t, b: t) -> bool { - alt unify::unify(a, b, unify::precise, cx) { - result::ok(_) { true } - result::err(_) { false } +fn resolve_err_to_str(err: resolve_err) -> str { + alt err { + rerr_unresolved_var(_) { ret "type variable unresolved"; } + rerr_cyclic_var(_) { ret "type of infinite size"; } } } @@ -2234,6 +2533,9 @@ fn type_err_to_str(cx: ctxt, err: type_err) -> str { region_to_str(cx, subregion), region_to_str(cx, superregion)); } + terr_cyclic_type { + ret "cyclic type of infinite size"; + } } } @@ -2241,8 +2543,24 @@ fn type_err_to_str(cx: ctxt, err: type_err) -> str { // substitions. fn substitute_type_params(cx: ctxt, substs: [ty::t], typ: t) -> t { if !type_has_params(typ) { ret typ; } + // Precondition? idx < vec::len(substs) - fold_ty(cx, fm_param({|idx, _id| substs[idx]}), typ) + if !get(typ).t_flags.has_params { ret typ; } + fold(cx, typ) {|t| + alt get(t).struct { + ty_param(i, d) { substs[i] } + _ { t } + } + } +} + +fn substitute_type_params_i(vb: @var_bindings, substs: [ty::t_i], &&typ: t_i) -> t_i { + fold(vb, typ) {|t| + alt *t { + sty_i(ty_param(idx, _id)) { substs[idx] } + _ { t } + } + } } fn def_has_ty_params(def: ast::def) -> bool { @@ -2499,7 +2817,7 @@ fn class_items_as_fields(cx:ctxt, did: ast::def_id) -> [field] { rslt } -fn is_binopable(_cx: ctxt, ty: t, op: ast::binop) -> bool { +fn is_binopable(_cx: ctxt, ty: sty_base, op: ast::binop) -> bool { const tycat_other: int = 0; const tycat_bool: int = 1; const tycat_int: int = 2; @@ -2542,8 +2860,8 @@ fn is_binopable(_cx: ctxt, ty: t, op: ast::binop) -> bool { } } - fn tycat(ty: t) -> int { - alt get(ty).struct { + fn tycat(ty: sty_base) -> int { + alt ty { ty_bool { tycat_bool } ty_int(_) { tycat_int } ty_uint(_) { tycat_int } diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index 528e8fb9500c6..30368e0f86812 100644 --- a/src/rustc/middle/typeck.rs +++ b/src/rustc/middle/typeck.rs @@ -1,4 +1,5 @@ import result::result; +import std::{map, list}; import syntax::{ast, ast_util}; import ast::spanned; import syntax::ast_util::{local_def, respan}; @@ -9,14 +10,15 @@ import util::common::*; import syntax::codemap::span; import pat_util::*; import middle::ty; -import middle::ty::{node_id_to_type, arg, block_ty, - expr_ty, field, node_type_table, mk_nil, - ty_param_bounds_and_ty, lookup_class_item_tys}; -import util::ppaux::ty_to_str; +import middle::ty::{arg, field, node_type_table, mk_nil, + ty_param_bounds_and_ty, lookup_class_item_tys, + ty_ops}; +import util::ppaux::{ty_to_str, ty_i_to_str}; import std::smallintmap; import std::map::{hashmap, int_hash}; import std::serialization::{serialize_uint, deserialize_uint}; import syntax::print::pprust::*; +import ty::unify::uctxt; export check_crate; export method_map; @@ -24,6 +26,7 @@ export method_origin, serialize_method_origin, deserialize_method_origin; export vtable_map; export vtable_res; export vtable_origin; +export vtable_origin_base; #[auto_serialize] enum method_origin { @@ -35,14 +38,19 @@ enum method_origin { type method_map = hashmap; // Resolutions for bounds of all parameters, left to right, for a given path. -type vtable_res = @[vtable_origin]; -enum vtable_origin { - vtable_static(ast::def_id, [ty::t], vtable_res), +enum vtable_origin_base { + vtable_static(ast::def_id, [T], vtable_res), // Param number, bound number vtable_param(uint, uint), vtable_iface(ast::def_id, [ty::t]), } +type vtable_origin_i = vtable_origin_base; +type vtable_res_i = @[vtable_origin_i]; +type vtable_map_i = hashmap; + +type vtable_origin = vtable_origin_base; +type vtable_res = @[vtable_origin]; type vtable_map = hashmap; type ty_table = hashmap; @@ -50,6 +58,12 @@ type ty_table = hashmap; // Used for typechecking the methods of an impl enum self_info { self_impl(ty::t) } +enum ast_ty_to_ty_cache_entry { + atttce_unresolved, /* not resolved yet */ + atttce_resolved(ty::t), /* resolved to a type, irrespective of region */ + atttce_has_regions /* has regions; cannot be cached */ +} + type crate_ctxt = {mutable self_infos: [self_info], impl_map: resolve::impl_map, method_map: method_map, @@ -61,6 +75,8 @@ type crate_ctxt = {mutable self_infos: [self_info], /* map from node_ids for enclosing-class vars and methods to types */ enclosing_class: class_map, + ast_ty_to_ty_cache: + hashmap<@ast::ty, ast_ty_to_ty_cache_entry>, tcx: ty::ctxt}; type class_map = hashmap; @@ -69,14 +85,33 @@ type fn_ctxt = // var_bindings, locals and next_var_id are shared // with any nested functions that capture the environment // (and with any functions whose environment is being captured). - {ret_ty: ty::t, + {ret_ty: ty::t_i, purity: ast::purity, proto: ast::proto, - var_bindings: @ty::unify::var_bindings, + vb: @ty::var_bindings, locals: hashmap, next_var_id: @mutable int, ccx: @crate_ctxt}; +fn ty_str(fcx: @fn_ctxt, t: ty::t_i) -> str { + ty_i_to_str(fcx.vb, t) +} + +fn node_ty(fcx: @fn_ctxt, id: ast::node_id) -> ty::t_i { + fcx.vb.node_types.get(id) +} + +fn expr_ty(fcx: @fn_ctxt, expr: @ast::expr) -> ty::t_i { + node_ty(fcx, expr.id) +} + +fn node_ty_substs(fcx: @fn_ctxt, id: ast::node_id) -> [ty::t_i] { + fcx.vb.node_type_substs.get(id) +} + +fn node_ty_substs_find(fcx: @fn_ctxt, id: ast::node_id) -> option<[ty::t_i]> { + fcx.vb.node_type_substs.find(id) +} fn lookup_local(fcx: @fn_ctxt, sp: span, id: ast::node_id) -> int { alt fcx.locals.find(id) { @@ -98,184 +133,231 @@ fn lookup_def(fcx: @fn_ctxt, sp: span, id: ast::node_id) -> ast::def { } } -// Returns the type parameter count and the type for the given definition. -fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) -> - ty_param_bounds_and_ty { - alt defn { - ast::def_arg(nid, _) { - assert (fcx.locals.contains_key(nid)); - let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid)); - ret {bounds: @[], ty: typ}; - } - ast::def_local(nid, _) { - assert (fcx.locals.contains_key(nid)); - let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid)); - ret {bounds: @[], ty: typ}; - } - ast::def_self(_) { - alt get_self_info(fcx.ccx) { - some(self_impl(impl_t)) { - ret {bounds: @[], ty: impl_t}; +// Instantiates the given path, which must refer to an item with the given +// number of type parameters and type. +fn write_path_ty(fcx: @fn_ctxt, sp: span, pth: @ast::path, id: ast::node_id) { + + fn substd(fcx: @fn_ctxt, sp: span, pth: @ast::path, id: ast::node_id, + tpt: ty_param_bounds_and_ty) { + let ty_param_count = vec::len(*tpt.bounds); + let ty_substs_len = vec::len(pth.node.types); + let substs = if ty_substs_len > 0u { + if ty_param_count == 0u { + fcx.ccx.tcx.sess.span_err + (sp, "this item does not take type parameters"); + next_ty_vars(fcx, ty_param_count) + } else if ty_substs_len > ty_param_count { + fcx.ccx.tcx.sess.span_err + (sp, "too many type parameter provided for this item"); + next_ty_vars(fcx, ty_param_count) + } else if ty_substs_len < ty_param_count { + fcx.ccx.tcx.sess.span_err + (sp, "not enough type parameters provided for this item"); + next_ty_vars(fcx, ty_param_count) + } else { + vec::map(pth.node.types) {|aty| ast_ty_to_ty_i(fcx, aty) } + } + } else { + next_ty_vars(fcx, ty_param_count) + }; + write_ty_substs(fcx, id, tpt.ty, substs); + } + + fn from_defn(fcx: @fn_ctxt, sp: span, pth: @ast::path, id: ast::node_id, + defn: ast::def) { + + alt defn { + ast::def_arg(nid, _) { + assert (fcx.locals.contains_key(nid)); + let typ = ty::mk_var(lookup_local(fcx, sp, nid)); + ret write_ty(fcx, id, typ); } - none { - fcx.ccx.tcx.sess.span_bug(sp, "def_self with no self_info"); + ast::def_local(nid, _) { + assert (fcx.locals.contains_key(nid)); + let typ = ty::mk_var(lookup_local(fcx, sp, nid)); + ret write_ty(fcx, id, typ); } - } - } - ast::def_fn(id, ast::crust_fn) { - // Crust functions are just u8 pointers - ret { - bounds: @[], - ty: ty::mk_ptr( - fcx.ccx.tcx, - { - ty: ty::mk_mach_uint(fcx.ccx.tcx, ast::ty_u8), - mutbl: ast::m_imm - }) - }; - } - ast::def_fn(id, _) | ast::def_const(id) | - ast::def_variant(_, id) | ast::def_class(id) - { ret ty::lookup_item_type(fcx.ccx.tcx, id); } - ast::def_binding(nid) { - assert (fcx.locals.contains_key(nid)); - let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid)); - ret {bounds: @[], ty: typ}; - } - ast::def_ty(_) | ast::def_prim_ty(_) { - fcx.ccx.tcx.sess.span_fatal(sp, "expected value but found type"); - } - ast::def_upvar(_, inner, _) { - ret ty_param_bounds_and_ty_for_def(fcx, sp, *inner); - } - ast::def_class_method(_, id) | ast::def_class_field(_, id) { - if id.crate != ast::local_crate { - fcx.ccx.tcx.sess.span_fatal(sp, - "class method or field referred to \ - out of scope"); + ast::def_self(_) { + alt get_self_info(fcx.ccx) { + some(self_impl(impl_t)) { + ret substd(fcx, sp, pth, id, + {bounds: @[], ty: impl_t}); + } + none { + fcx.ccx.tcx.sess.span_bug(sp, "def_self with no self_info"); + } + } } - alt fcx.ccx.enclosing_class.find(id.node) { - some(a_ty) { ret {bounds: @[], ty: a_ty}; } - _ { fcx.ccx.tcx.sess.span_fatal(sp, - "class method or field referred to \ - out of scope"); } + ast::def_fn(_, ast::crust_fn) { + // Crust functions are just u8 pointers + let t = ty::mk_ptr(fcx.vb, {ty: ty::mk_mach_uint(fcx.vb, ast::ty_u8), + mutbl: ast::m_imm}); + ret write_ty(fcx, id, t); + } + ast::def_fn(did, _) | ast::def_const(did) | + ast::def_variant(_, did) | ast::def_class(did) { + ret substd(fcx, sp, pth, id, + ty::lookup_item_type(fcx.ccx.tcx, did)); + } + ast::def_binding(nid) { + assert (fcx.locals.contains_key(nid)); + ret write_ty(fcx, id, ty::mk_var(lookup_local(fcx, sp, nid))); + } + ast::def_ty(_) | ast::def_prim_ty(_) { + fcx.ccx.tcx.sess.span_fatal(sp, "expected value but found type"); + } + ast::def_upvar(_, inner, _) { + ret from_defn(fcx, sp, pth, id, *inner); + } + ast::def_class_method(_, did) | ast::def_class_field(_, did) { + if did.crate != ast::local_crate { + fcx.ccx.tcx.sess.span_fatal(sp, + "class method or field referred to \ + out of scope"); + } + alt fcx.ccx.enclosing_class.find(did.node) { + some(a_ty) { ret substd(fcx, sp, pth, id, + {bounds: @[], ty: a_ty}); } + _ { fcx.ccx.tcx.sess.span_fatal(sp, + "class method or field referred to \ + out of scope"); } + } } - } - _ { - // FIXME: handle other names. - fcx.ccx.tcx.sess.unimpl("definition variant"); - } + _ { + // FIXME: handle other names. + fcx.ccx.tcx.sess.unimpl("definition variant"); + } + } + } + + let defn = lookup_def(fcx, pth.span, id); + from_defn(fcx, sp, pth, id, defn); +} + +// Returns the one-level-deep structure of the given type. +fn structure_of(fcx: @fn_ctxt, sp: span, typ: ty::t_i, + f: fn(ty::sty_i) -> R) -> R { + alt *typ { + ty::ty_var_i(vid) { + ty::unify::get_var_binding( + fcx.vb, vid, + {|_vid| /* ...if unbound */ + fcx.ccx.tcx.sess.span_fatal + (sp, "the type of this value must \ + be known in this context"); + }, + f /* ...if bound */) } + + ty::sty_i(sty) { + f(sty) + } + } } -// Instantiates the given path, which must refer to an item with the given -// number of type parameters and type. -fn instantiate_path(fcx: @fn_ctxt, pth: @ast::path, - tpt: ty_param_bounds_and_ty, sp: span, - id: ast::node_id) { - let ty_param_count = vec::len(*tpt.bounds); - let ty_substs_len = vec::len(pth.node.types); - if ty_substs_len > 0u { - if ty_param_count == 0u { - fcx.ccx.tcx.sess.span_fatal - (sp, "this item does not take type parameters"); - } else if ty_substs_len > ty_param_count { - fcx.ccx.tcx.sess.span_fatal - (sp, "too many type parameter provided for this item"); - } else if ty_substs_len < ty_param_count { - fcx.ccx.tcx.sess.span_fatal - (sp, "not enough type parameters provided for this item"); - } - if ty_param_count == 0u { - fcx.ccx.tcx.sess.span_fatal( - sp, "this item does not take type parameters"); +fn fn_args(fcx: @fn_ctxt, sp: span, fty: ty::t_i) -> [ty::arg_i] { + structure_of(fcx, sp, fty) {|sty| + alt sty { + ty::ty_fn(f) { f.inputs } + _ { fcx.ccx.tcx.sess.span_err(sp, "calling non-function"); [] } } - let substs = vec::map(pth.node.types, {|aty| - ast_ty_to_ty_crate(fcx.ccx, aty) - }); - write_ty_substs(fcx.ccx.tcx, id, tpt.ty, substs); - } else if ty_param_count > 0u { - let vars = vec::from_fn(ty_param_count, {|_i| next_ty_var(fcx)}); - write_ty_substs(fcx.ccx.tcx, id, tpt.ty, vars); - } else { - write_ty(fcx.ccx.tcx, id, tpt.ty); } } -// Type tests -fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t { - alt ty::unify::resolve_type_structure(fcx.var_bindings, tp) { - result::ok(typ_s) { ret typ_s; } - result::err(_) { - fcx.ccx.tcx.sess.span_fatal - (sp, "the type of this value must be known in this context"); - } +fn fn_ret(fcx: @fn_ctxt, sp: span, fty: ty::t_i, &bot: bool) -> ty::t_i { + structure_of(fcx, sp, fty) {|sty| + alt sty { + ty::ty_fn(f) { + if f.ret_style == ast::noreturn { bot = true; } + f.output + } + _ { fcx.ccx.tcx.sess.span_fatal(sp, "calling non-function"); } + } } } +// Just checks whether it's a fn that returns bool, +// not its purity. +fn type_is_pred_ty(fcx: @fn_ctxt, sp: span, typ: ty::t_i) -> bool { + structure_of(fcx, sp, typ) {|sty| + alt sty { + ty::ty_fn(f) { type_is_bool(fcx, sp, f.output) } + _ { false } + } + } +} -// Returns the one-level-deep structure of the given type. -fn structure_of(fcx: @fn_ctxt, sp: span, typ: ty::t) -> ty::sty { - ty::get(structurally_resolved_type(fcx, sp, typ)).struct +fn type_is_bool(fcx: @fn_ctxt, sp: span, typ: ty::t_i) -> bool { + structure_of(fcx, sp, typ, ty::sty_is_bool(_)) } -// Returns the one-level-deep structure of the given type or none if it -// is not known yet. -fn structure_of_maybe(fcx: @fn_ctxt, _sp: span, typ: ty::t) -> - option { - let r = ty::unify::resolve_type_structure(fcx.var_bindings, typ); - alt r { - result::ok(typ_s) { some(ty::get(typ_s).struct) } - result::err(_) { none } - } +fn type_is_integral(fcx: @fn_ctxt, sp: span, typ: ty::t_i) -> bool { + structure_of(fcx, sp, typ, ty::sty_is_integral(_)) } -fn type_is_integral(fcx: @fn_ctxt, sp: span, typ: ty::t) -> bool { - let typ_s = structurally_resolved_type(fcx, sp, typ); - ret ty::type_is_integral(typ_s); +fn type_is_numeric(fcx: @fn_ctxt, sp: span, typ: ty::t_i) -> bool { + structure_of(fcx, sp, typ, ty::sty_is_numeric(_)) } -fn type_is_scalar(fcx: @fn_ctxt, sp: span, typ: ty::t) -> bool { - let typ_s = structurally_resolved_type(fcx, sp, typ); - ret ty::type_is_scalar(typ_s); +fn type_is_nil(fcx: @fn_ctxt, sp: span, typ: ty::t_i) -> bool { + structure_of(fcx, sp, typ) {|sty| sty == ty::ty_nil } } -fn type_is_c_like_enum(fcx: @fn_ctxt, sp: span, typ: ty::t) -> bool { - let typ_s = structurally_resolved_type(fcx, sp, typ); - ret ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s); +fn type_is_scalar(fcx: @fn_ctxt, sp: span, typ: ty::t_i) -> bool { + structure_of(fcx, sp, typ, ty::sty_is_scalar(_)) } -enum mode { m_collect, m_check, m_check_tyvar(@fn_ctxt), } +fn type_is_c_like_enum(fcx: @fn_ctxt, sp: span, typ: ty::t_i) -> bool { + structure_of(fcx, sp, typ, ty::sty_is_c_like_enum(fcx.ccx.tcx, _)) +} + +fn type_is_bot(fcx: @fn_ctxt, sp: span, typ: ty::t_i) -> bool { + structure_of(fcx, sp, typ) {|sty| + alt sty { + ty::ty_bot { true } + _ { false } + } + } +} + +enum mode { m_collect, m_check } // Parses the programmer's textual representation of a type into our // internal notion of a type. `getter` is a function that returns the type // corresponding to a definition ID: -fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t { - fn subst_inferred_regions(tcx: ty::ctxt, use_site: ast::node_id, +fn ast_ty_to_ty(ccx: @crate_ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t { + + fn subst_inferred_regions(ccx: @crate_ctxt, use_site: ast::node_id, ty: ty::t) -> ty::t { - ret ty::fold_ty(tcx, ty::fm_rptr({|r| + let tcx = ccx.tcx; + ret ty::fold_rptr(tcx, ty) {|r| alt r { ty::re_inferred | ty::re_self(_) { tcx.region_map.ast_type_to_inferred_region.get(use_site) } _ { r } } - }), ty); + }; } - fn getter(tcx: ty::ctxt, use_site: ast::node_id, mode: mode, + + fn getter(ccx: @crate_ctxt, use_site: ast::node_id, mode: mode, id: ast::def_id) -> ty::ty_param_bounds_and_ty { + let tcx = ccx.tcx; let tpt = alt mode { - m_check | m_check_tyvar(_) { ty::lookup_item_type(tcx, id) } + m_check { + ty::lookup_item_type(tcx, id) + } m_collect { - if id.crate != ast::local_crate { csearch::get_type(tcx, id) } - else { + if id.crate != ast::local_crate { + csearch::get_type(tcx, id) + } else { alt tcx.items.find(id.node) { some(ast_map::node_item(item, _)) { - ty_of_item(tcx, mode, item) + ty_of_item(ccx, mode, item) } some(ast_map::node_native_item(native_item, _, _)) { - ty_of_native_item(tcx, mode, native_item) + ty_of_native_item(ccx, mode, native_item) } _ { tcx.sess.bug("unexpected sort of item in ast_ty_to_ty"); @@ -287,19 +369,21 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t { if ty::type_has_rptrs(tpt.ty) { ret {bounds: tpt.bounds, - ty: subst_inferred_regions(tcx, use_site, tpt.ty)}; + ty: subst_inferred_regions(ccx, use_site, tpt.ty)}; } ret tpt; } - fn ast_mt_to_mt(tcx: ty::ctxt, use_site: ast::node_id, mode: mode, + + fn ast_mt_to_mt(ccx: @crate_ctxt, use_site: ast::node_id, mode: mode, mt: ast::mt) -> ty::mt { - ret {ty: do_ast_ty_to_ty(tcx, use_site, mode, mt.ty), + ret {ty: do_ast_ty_to_ty(ccx, use_site, mode, mt.ty), mutbl: mt.mutbl}; } - fn instantiate(tcx: ty::ctxt, use_site: ast::node_id, sp: span, + fn instantiate(ccx: @crate_ctxt, use_site: ast::node_id, sp: span, mode: mode, id: ast::def_id, path_id: ast::node_id, args: [@ast::ty]) -> ty::t { - let ty_param_bounds_and_ty = getter(tcx, use_site, mode, id); + let tcx = ccx.tcx; + let ty_param_bounds_and_ty = getter(ccx, use_site, mode, id); if vec::len(*ty_param_bounds_and_ty.bounds) == 0u { ret ty_param_bounds_and_ty.ty; } @@ -311,44 +395,46 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t { polymorphic type"); } for ast_ty: @ast::ty in args { - param_bindings += [do_ast_ty_to_ty(tcx, use_site, mode, ast_ty)]; + param_bindings += [do_ast_ty_to_ty(ccx, use_site, mode, ast_ty)]; } #debug("substituting(%s into %s)", str::concat(vec::map(param_bindings, {|t| ty_to_str(tcx, t)})), ty_to_str(tcx, ty_param_bounds_and_ty.ty)); let typ = - ty::substitute_type_params(tcx, param_bindings, + ty::substitute_type_params(ccx.tcx, param_bindings, ty_param_bounds_and_ty.ty); - write_substs(tcx, path_id, param_bindings); + write_substs_to_tcx(tcx, path_id, param_bindings); ret typ; } - fn do_ast_ty_to_ty(tcx: ty::ctxt, use_site: ast::node_id, mode: mode, - &&ast_ty: @ast::ty) -> ty::t { - alt tcx.ast_ty_to_ty_cache.find(ast_ty) { - some(ty::atttce_resolved(ty)) { ret ty; } - some(ty::atttce_unresolved) { + + fn do_ast_ty_to_ty(ccx: @crate_ctxt, use_site: ast::node_id, + mode: mode, &&ast_ty: @ast::ty) -> ty::t { + let tcx = ccx.tcx; + alt ccx.ast_ty_to_ty_cache.find(ast_ty) { + some(atttce_resolved(ty)) { ret ty; } + some(atttce_unresolved) { tcx.sess.span_fatal(ast_ty.span, "illegal recursive type. \ insert a enum in the cycle, \ if this is desired)"); } - some(ty::atttce_has_regions) | none { /* go on */ } + some(atttce_has_regions) | none { /* go on */ } } - tcx.ast_ty_to_ty_cache.insert(ast_ty, ty::atttce_unresolved); + ccx.ast_ty_to_ty_cache.insert(ast_ty, atttce_unresolved); let typ = alt ast_ty.node { ast::ty_nil { ty::mk_nil(tcx) } ast::ty_bot { ty::mk_bot(tcx) } ast::ty_box(mt) { - ty::mk_box(tcx, ast_mt_to_mt(tcx, use_site, mode, mt)) + ty::mk_box(tcx, ast_mt_to_mt(ccx, use_site, mode, mt)) } ast::ty_uniq(mt) { - ty::mk_uniq(tcx, ast_mt_to_mt(tcx, use_site, mode, mt)) + ty::mk_uniq(tcx, ast_mt_to_mt(ccx, use_site, mode, mt)) } ast::ty_vec(mt) { - ty::mk_vec(tcx, ast_mt_to_mt(tcx, use_site, mode, mt)) + ty::mk_vec(tcx, ast_mt_to_mt(ccx, use_site, mode, mt)) } ast::ty_ptr(mt) { - ty::mk_ptr(tcx, ast_mt_to_mt(tcx, use_site, mode, mt)) + ty::mk_ptr(tcx, ast_mt_to_mt(ccx, use_site, mode, mt)) } ast::ty_rptr(region, mt) { let region = alt region.node { @@ -363,23 +449,23 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t { tcx.region_map.ast_type_to_region.get(region.id) } }; - ty::mk_rptr(tcx, region, ast_mt_to_mt(tcx, use_site, mode, mt)) + ty::mk_rptr(tcx, region, ast_mt_to_mt(ccx, use_site, mode, mt)) } ast::ty_tup(fields) { let flds = vec::map(fields, - bind do_ast_ty_to_ty(tcx, use_site, mode, _)); + bind do_ast_ty_to_ty(ccx, use_site, mode, _)); ty::mk_tup(tcx, flds) } ast::ty_rec(fields) { let flds: [field] = []; for f: ast::ty_field in fields { - let tm = ast_mt_to_mt(tcx, use_site, mode, f.node.mt); + let tm = ast_mt_to_mt(ccx, use_site, mode, f.node.mt); flds += [{ident: f.node.ident, mt: tm}]; } ty::mk_rec(tcx, flds) } ast::ty_fn(proto, decl) { - ty::mk_fn(tcx, ty_of_fn_decl(tcx, mode, proto, decl)) + ty::mk_fn(tcx, ty_of_fn_decl(ccx, mode, proto, decl)) } ast::ty_path(path, id) { let a_def = alt tcx.def_map.find(id) { @@ -388,7 +474,7 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t { some(d) { d }}; alt a_def { ast::def_ty(did) { - instantiate(tcx, use_site, ast_ty.span, mode, did, + instantiate(ccx, use_site, ast_ty.span, mode, did, id, path.node.types) } ast::def_prim_ty(nty) { @@ -416,7 +502,7 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t { self type"); } ty::mk_self(tcx, vec::map(path.node.types, {|ast_ty| - do_ast_ty_to_ty(tcx, use_site, mode, ast_ty) + do_ast_ty_to_ty(ccx, use_site, mode, ast_ty) })) } } @@ -431,7 +517,7 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t { of type parameters to object type"); } ty::mk_class(tcx, class_id, vec::map(path.node.types, - {|ast_ty| ast_ty_to_ty(tcx, mode, ast_ty)})) + {|ast_ty| do_ast_ty_to_ty(ccx, use_site, mode, ast_ty)})) } _ { tcx.sess.span_bug(ast_ty.span, #fmt("class id is \ @@ -440,7 +526,7 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t { } } else { - getter(tcx, use_site, mode, class_id).ty + getter(ccx, use_site, mode, class_id).ty } } _ { @@ -454,15 +540,12 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t { for constr: @ast::ty_constr in cs { out_cs += [ty::ast_constr_to_constr(tcx, constr)]; } - ty::mk_constr(tcx, do_ast_ty_to_ty(tcx, use_site, mode, t), - out_cs) + ty::mk_constr(tcx, do_ast_ty_to_ty(ccx, use_site, mode, t), + out_cs) } ast::ty_infer { - alt mode { - m_check_tyvar(fcx) { ret next_ty_var(fcx); } - _ { tcx.sess.span_bug(ast_ty.span, - "found `ty_infer` in unexpected place"); } - } + tcx.sess.span_bug(ast_ty.span, + "found `ty_infer` in unexpected place"); } ast::ty_mac(_) { tcx.sess.span_bug(ast_ty.span, @@ -471,33 +554,48 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t { }; if ty::type_has_rptrs(typ) { - tcx.ast_ty_to_ty_cache.insert(ast_ty, ty::atttce_has_regions); + ccx.ast_ty_to_ty_cache.insert(ast_ty, atttce_has_regions); } else { - tcx.ast_ty_to_ty_cache.insert(ast_ty, ty::atttce_resolved(typ)); + ccx.ast_ty_to_ty_cache.insert(ast_ty, atttce_resolved(typ)); } ret typ; } - ret do_ast_ty_to_ty(tcx, ast_ty.id, mode, ast_ty); + ret do_ast_ty_to_ty(ccx, ast_ty.id, mode, ast_ty); +} + +fn ast_ty_to_opt_ty_i(ccx: @crate_ctxt, t: @ast::ty) -> option { + alt t.node { + ast::ty_infer { none } + _ { some(ty::ty_to_ty_i(ccx.tcx, ast_ty_to_ty(ccx, m_check, t))) } + } +} + +fn ast_ty_to_ty_i(fcx: @fn_ctxt, t: @ast::ty) -> ty::t_i { + alt ast_ty_to_opt_ty_i(fcx.ccx, t) { + none { next_ty_var(fcx) } + some(r) { r } + } } -fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item) +fn ty_of_item(ccx: @crate_ctxt, mode: mode, 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 = ast_ty_to_ty(tcx, mode, t); + let typ = ast_ty_to_ty(ccx, mode, t); let tpt = {bounds: @[], ty: typ}; tcx.tcache.insert(local_def(it.id), tpt); ret tpt; } ast::item_fn(decl, tps, _) { - ret ty_of_fn(tcx, mode, decl, tps, local_def(it.id)); + ret ty_of_fn(ccx, mode, decl, tps, local_def(it.id)); } ast::item_ty(t, tps) { alt tcx.tcache.find(local_def(it.id)) { @@ -507,7 +605,7 @@ fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item) // Tell ast_ty_to_ty() that we want to perform a recursive // call to resolve any named types. let tpt = { - let t0 = ast_ty_to_ty(tcx, mode, t); + let t0 = ast_ty_to_ty(ccx, mode, t); let t1 = { // Do not associate a def id with a named, parameterized type // like "foo". This is because otherwise ty_to_str will @@ -519,14 +617,14 @@ fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item) t0 } }; - {bounds: ty_param_bounds(tcx, mode, tps), ty: t1} + {bounds: ty_param_bounds(ccx, mode, tps), ty: t1} }; tcx.tcache.insert(local_def(it.id), tpt); ret tpt; } ast::item_res(decl, tps, _, _, _) { - let {bounds, params} = mk_ty_params(tcx, tps); - let t_arg = ty_of_arg(tcx, mode, decl.inputs[0]); + let {bounds, params} = mk_ty_params(ccx, tps); + let t_arg = ty_of_arg(ccx, mode, decl.inputs[0]); let t = ty::mk_res(tcx, local_def(it.id), t_arg.ty, params); let t_res = {bounds: bounds, ty: t}; tcx.tcache.insert(local_def(it.id), t_res); @@ -534,21 +632,21 @@ fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item) } ast::item_enum(_, tps) { // Create a new generic polytype. - let {bounds, params} = mk_ty_params(tcx, tps); + let {bounds, params} = mk_ty_params(ccx, tps); let t = ty::mk_enum(tcx, local_def(it.id), params); let tpt = {bounds: bounds, ty: t}; tcx.tcache.insert(local_def(it.id), tpt); ret tpt; } ast::item_iface(tps, ms) { - let {bounds, params} = mk_ty_params(tcx, tps); + let {bounds, params} = mk_ty_params(ccx, tps); let t = ty::mk_iface(tcx, local_def(it.id), params); let tpt = {bounds: bounds, ty: t}; tcx.tcache.insert(local_def(it.id), tpt); ret tpt; } ast::item_class(tps,_,_) { - let {bounds,params} = mk_ty_params(tcx, tps); + let {bounds,params} = mk_ty_params(ccx, tps); let t = ty::mk_class(tcx, local_def(it.id), params); let tpt = {bounds: bounds, ty: t}; tcx.tcache.insert(local_def(it.id), tpt); @@ -558,74 +656,79 @@ fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item) ast::item_native_mod(_) { fail; } } } -fn ty_of_native_item(tcx: ty::ctxt, mode: mode, it: @ast::native_item) +fn ty_of_native_item(ccx: @crate_ctxt, mode: mode, 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(tcx, mode, fn_decl, params, + ret ty_of_native_fn_decl(ccx, mode, fn_decl, params, local_def(it.id)); } } } -fn ty_of_arg(tcx: ty::ctxt, mode: mode, a: ast::arg) -> ty::arg { - fn arg_mode(tcx: ty::ctxt, m: ast::mode, ty: ty::t) -> ast::mode { + +fn ty_of_arg(ccx: @crate_ctxt, mode: mode, a: ast::arg) -> ty::arg { + fn arg_mode(ccx: @crate_ctxt, m: ast::mode, ty: ty::t) -> ast::mode { alt m { ast::infer(_) { - alt ty::get(ty).struct { - // If the type is not specified, then this must be a fn expr. - // Leave the mode as infer(_), it will get inferred based - // on constraints elsewhere. - ty::ty_var(_) { m } - - // If the type is known, then use the default for that type. - // Here we unify m and the default. This should update the - // tables in tcx but should never fail, because nothing else - // will have been unified with m yet: - _ { - let m1 = ast::expl(ty::default_arg_mode_for_ty(ty)); - result::get(ty::unify_mode(tcx, m, m1)) - } - } + // Unspecified modes in a non-inferred ctx (e.g., item decl) + // use the default for the type: + let m1 = ast::expl(ty::default_arg_mode_for_ty(ty)); + result::get(ty::unify_mode(ccx.tcx, m, m1)) } ast::expl(_) { m } } } - let ty = ast_ty_to_ty(tcx, mode, a.ty); - let mode = arg_mode(tcx, a.mode, ty); + let ty = ast_ty_to_ty(ccx, mode, a.ty); + let mode = arg_mode(ccx, a.mode, ty); {mode: mode, ty: ty} } -fn ty_of_fn_decl(tcx: ty::ctxt, + +fn ty_of_fn_decl_base(tcx: ty::ctxt, + proto: ast::proto, + decl: ast::fn_decl, + arg_fn: fn(ast::arg) -> ty::arg_base, + t_fn: fn(@ast::ty) -> T) -> ty::fn_ty_base { + let input_tys = vec::map(decl.inputs, arg_fn); + let output_ty = t_fn(decl.output); + let out_constrs = vec::map(decl.constraints) {|c| + ty::ast_constr_to_constr(tcx, c) + }; + {proto: proto, + inputs: input_tys, + output: output_ty, + ret_style: decl.cf, constraints: out_constrs} +} + +fn ty_of_fn_decl(ccx: @crate_ctxt, mode: mode, proto: ast::proto, decl: ast::fn_decl) -> ty::fn_ty { - let input_tys = vec::map(decl.inputs) {|a| ty_of_arg(tcx, mode, a) }; - let output_ty = ast_ty_to_ty(tcx, mode, decl.output); - - let out_constrs = []; - for constr: @ast::constr in decl.constraints { - out_constrs += [ty::ast_constr_to_constr(tcx, constr)]; - } - {proto: proto, inputs: input_tys, - output: output_ty, ret_style: decl.cf, constraints: out_constrs} + ty_of_fn_decl_base( + ccx.tcx, proto, decl, + {|a| ty_of_arg(ccx, mode, a)}, + {|t| ast_ty_to_ty(ccx, mode, t)}) } -fn ty_of_fn(tcx: ty::ctxt, mode: mode, decl: ast::fn_decl, + +fn ty_of_fn(ccx: @crate_ctxt, mode: mode, 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(tcx, mode, ty_params); - let tofd = ty_of_fn_decl(tcx, mode, ast::proto_bare, decl); + let tcx = ccx.tcx; + let bounds = ty_param_bounds(ccx, mode, ty_params); + let tofd = ty_of_fn_decl(ccx, mode, ast::proto_bare, decl); let tpt = {bounds: bounds, ty: ty::mk_fn(tcx, tofd)}; tcx.tcache.insert(def_id, tpt); ret tpt; } -fn ty_of_native_fn_decl(tcx: ty::ctxt, mode: mode, decl: ast::fn_decl, +fn ty_of_native_fn_decl(ccx: @crate_ctxt, mode: mode, decl: ast::fn_decl, ty_params: [ast::ty_param], def_id: ast::def_id) -> ty::ty_param_bounds_and_ty { - let input_tys = [], bounds = ty_param_bounds(tcx, mode, ty_params); + let tcx = ccx.tcx; + let input_tys = [], bounds = ty_param_bounds(ccx, mode, ty_params); for a: ast::arg in decl.inputs { - input_tys += [ty_of_arg(tcx, mode, a)]; + input_tys += [ty_of_arg(ccx, mode, a)]; } - let output_ty = ast_ty_to_ty(tcx, mode, decl.output); + let output_ty = ast_ty_to_ty(ccx, mode, decl.output); let t_fn = ty::mk_fn(tcx, {proto: ast::proto_bare, inputs: input_tys, @@ -636,8 +739,9 @@ fn ty_of_native_fn_decl(tcx: ty::ctxt, mode: mode, decl: ast::fn_decl, tcx.tcache.insert(def_id, tpt); ret tpt; } -fn ty_param_bounds(tcx: ty::ctxt, mode: mode, params: [ast::ty_param]) +fn ty_param_bounds(ccx: @crate_ctxt, mode: mode, params: [ast::ty_param]) -> @[ty::param_bounds] { + let tcx = ccx.tcx; let result = []; for param in params { result += [alt tcx.ty_param_bounds.find(param.id) { @@ -649,7 +753,7 @@ fn ty_param_bounds(tcx: ty::ctxt, mode: mode, params: [ast::ty_param]) ast::bound_send { ty::bound_send } ast::bound_copy { ty::bound_copy } ast::bound_iface(t) { - let ity = ast_ty_to_ty(tcx, mode, t); + let ity = ast_ty_to_ty(ccx, mode, t); alt ty::get(ity).struct { ty::ty_iface(_, _) {} _ { @@ -670,62 +774,64 @@ fn ty_param_bounds(tcx: ty::ctxt, mode: mode, params: [ast::ty_param]) } @result } -fn ty_of_method(tcx: ty::ctxt, mode: mode, m: @ast::method) -> ty::method { - {ident: m.ident, tps: ty_param_bounds(tcx, mode, m.tps), - fty: ty_of_fn_decl(tcx, mode, ast::proto_bare, m.decl), + +fn ty_of_method(ccx: @crate_ctxt, mode: mode, m: @ast::method) -> ty::method { + {ident: m.ident, tps: ty_param_bounds(ccx, mode, m.tps), + fty: ty_of_fn_decl(ccx, mode, ast::proto_bare, m.decl), purity: m.decl.purity} } -fn ty_of_ty_method(tcx: ty::ctxt, mode: mode, m: ast::ty_method) + +fn ty_of_ty_method(ccx: @crate_ctxt, mode: mode, m: ast::ty_method) -> ty::method { - {ident: m.ident, tps: ty_param_bounds(tcx, mode, m.tps), - fty: ty_of_fn_decl(tcx, mode, ast::proto_bare, m.decl), + {ident: m.ident, tps: ty_param_bounds(ccx, mode, m.tps), + fty: ty_of_fn_decl(ccx, mode, ast::proto_bare, m.decl), purity: m.decl.purity} } -// A convenience function to use a crate_ctxt to resolve names for -// ast_ty_to_ty. -fn ast_ty_to_ty_crate(ccx: @crate_ctxt, &&ast_ty: @ast::ty) -> ty::t { - ret ast_ty_to_ty(ccx.tcx, m_check, ast_ty); -} - -// A wrapper around ast_ty_to_ty_crate that handles ty_infer. -fn ast_ty_to_ty_crate_infer(ccx: @crate_ctxt, &&ast_ty: @ast::ty) -> - option { - alt ast_ty.node { - ast::ty_infer { none } - _ { some(ast_ty_to_ty_crate(ccx, ast_ty)) } - } -} - - // Functions that write types into the node type table -fn write_ty(tcx: ty::ctxt, node_id: ast::node_id, ty: ty::t) { +fn write_ty_to_tcx(tcx: ty::ctxt, node_id: ast::node_id, ty: ty::t) { smallintmap::insert(*tcx.node_types, node_id as uint, ty); } -fn write_substs(tcx: ty::ctxt, node_id: ast::node_id, +substs: [ty::t]) { +fn write_substs_to_tcx(tcx: ty::ctxt, node_id: ast::node_id, + +substs: [ty::t]) { tcx.node_type_substs.insert(node_id, substs); } -fn write_ty_substs(tcx: ty::ctxt, node_id: ast::node_id, ty: ty::t, - +substs: [ty::t]) { +fn write_ty_substs_to_tcx(tcx: ty::ctxt, node_id: ast::node_id, ty: ty::t, + +substs: [ty::t]) { let ty = if ty::type_has_params(ty) { ty::substitute_type_params(tcx, substs, ty) } else { ty }; - write_ty(tcx, node_id, ty); - write_substs(tcx, node_id, substs); + write_ty_to_tcx(tcx, node_id, ty); + write_substs_to_tcx(tcx, node_id, substs); +} + +fn write_ty(fcx: @fn_ctxt, node_id: ast::node_id, ty: ty::t_i) { + #debug["write_ty for %s = %s", + ast_map::node_str(fcx.ccx.tcx.items, node_id), + ty_str(fcx, ty)]; + fcx.vb.node_types.insert(node_id, ty); +} +fn write_ty_substs(fcx: @fn_ctxt, + node_id: ast::node_id, + t0: ty::t, + +substs: [ty::t_i]) { + let t1 = ty::ty_to_ty_i_subst(fcx.ccx.tcx, t0, substs); + write_ty(fcx, node_id, t1); + fcx.vb.node_type_substs.insert(node_id, substs); } -fn write_nil(tcx: ty::ctxt, node_id: ast::node_id) { - write_ty(tcx, node_id, ty::mk_nil(tcx)); +fn write_nil(fcx: @fn_ctxt, node_id: ast::node_id) { + write_ty(fcx, node_id, ty::mk_nil(fcx.vb)); } -fn write_bot(tcx: ty::ctxt, node_id: ast::node_id) { - write_ty(tcx, node_id, ty::mk_bot(tcx)); +fn write_bot(fcx: @fn_ctxt, node_id: ast::node_id) { + write_ty(fcx, node_id, ty::mk_bot(fcx.vb)); } -fn mk_ty_params(tcx: ty::ctxt, atps: [ast::ty_param]) +fn mk_ty_params(ccx: @crate_ctxt, atps: [ast::ty_param]) -> {bounds: @[ty::param_bounds], params: [ty::t]} { - let i = 0u, bounds = ty_param_bounds(tcx, m_collect, atps); + let i = 0u, bounds = ty_param_bounds(ccx, m_collect, atps); {bounds: bounds, params: vec::map(atps, {|atp| - let t = ty::mk_param(tcx, i, local_def(atp.id)); + let t = ty::mk_param(ccx.tcx, i, local_def(atp.id)); i += 1u; t })} @@ -756,17 +862,16 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method, } }); 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 = substs + vec::from_fn(vec::len(*if_m.tps), {|i| ty::mk_param(tcx, i + impl_tps, {crate: 0, node: 0}) }); let 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)); - } - alt ty::unify::unify(impl_fty, if_fty, ty::unify::precise, tcx) { + let if_fty = ty::substitute_type_params(tcx, substs, if_fty); + let if_fty = fixup_self_def(tcx, if_fty, substs, self_ty, impl_tps); + + alt ty::unify::unify(tcx, impl_fty, if_fty) { result::err(err) { tcx.sess.span_err(sp, "method `" + if_m.ident + "` has an incompatible type: " + @@ -778,73 +883,104 @@ 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) } +// These two functions mangle 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. +// +// There are two methods: one is used when performing a method call, and the +// other when checking implementations against the interfaces they implement. +// Both of these routines have similarities, and could potentially be +// collapsed, but they operate on different types and are also more different +// than similar, so I opted to divide them. -// 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, ty::fm_general(fn@(t: ty::t) -> ty::t { - alt ty::get(t).struct { +fn fixup_self_call( + fcx: @fn_ctxt, + span: span, + mty: ty::t_i, + m_substs: [ty::t_i], + self_ty: ty::t_i) -> ty::t_i { + + if !ty::ty_i_has_self(mty) { ret mty; } + + ty::fold(fcx.vb, mty) {|foldt| + structure_of(fcx, span, foldt) {|sty| + alt sty { ty::ty_self(tps) { - if vec::len(tps) > 0u { - // Move the substs into the type param system of the - // context. - let 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 } } - } + // Move the substs into the type param system of the + // context. + let tps1 = vec::map(tps) {|t| + let f = fixup_self_call( + fcx, span, t, m_substs, self_ty); + ty::substitute_type_params_i( + fcx.vb, m_substs, f) + }; + + // Simply ensure that the type parameters for the self + // type match the context. + demand::tys(fcx.vb, span, demand::ek_mismatched_types, + tps1, m_substs); + self_ty } - _ { t } + _ { foldt } + } + } + } +} + +fn fixup_self_def( + tcx: ty::ctxt, + mty: ty::t, + m_substs: [ty::t], + self_ty: ty::t, + impl_n_tps: uint) -> ty::t { + + if !ty::type_has_self(mty) { ret mty; } + + ty::fold(tcx, mty) {|t| + alt ty::get(t).struct { + ty::ty_self(tps) { + // Move the substs into the type param system of the + // context. + let substs = vec::map(tps) {|t| + let f = fixup_self_def(tcx, t, m_substs, self_ty, impl_n_tps); + ty::substitute_type_params(tcx, m_substs, f) + }; + + // Add extra substs for impl type parameters. + while vec::len(substs) < impl_n_tps { + substs += [ty::mk_param(tcx, vec::len(substs), + {crate: 0, node: 0})]; } - }), mty) - } else { mty } + + // 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(tcx, substs, self_ty) + } + _ { t } + } + } } // Mangles an iface method ty to instantiate its `self` region. -fn fixup_self_region_in_method_ty(fcx: @fn_ctxt, mty: ty::t, - self_expr: @ast::expr) -> ty::t { +fn fixup_self_region_in_method_ty(fcx: @fn_ctxt, mty: ty::t_i, + self_expr: @ast::expr) -> ty::t_i { let self_region = region_of(fcx, self_expr); - ty::fold_ty(fcx.ccx.tcx, ty::fm_rptr({|r| + ty::fold_rptr(fcx.vb, mty) {|r| alt r { ty::re_self(_) { self_region } _ { r } } - }), mty) + } } // Item collection - a pair of bootstrap passes: @@ -858,9 +994,11 @@ fn fixup_self_region_in_method_ty(fcx: @fn_ctxt, mty: ty::t, // We then annotate the AST with the resulting types and return the annotated // AST, along with a table mapping item IDs to their types. mod collect { - fn get_enum_variant_types(tcx: ty::ctxt, enum_ty: ty::t, + fn get_enum_variant_types(ccx: @crate_ctxt, enum_ty: ty::t, variants: [ast::variant], ty_params: [ast::ty_param]) { + let tcx = ccx.tcx; + // Create a set of parameter types shared among all the variants. for variant in variants { // Nullary enum constructors get turned into constants; n-ary enum @@ -872,7 +1010,7 @@ mod collect { // should be called to resolve named types. let args: [arg] = []; for va: ast::variant_arg in variant.node.args { - let arg_ty = ast_ty_to_ty(tcx, m_collect, va.ty); + let arg_ty = ast_ty_to_ty(ccx, m_collect, va.ty); args += [{mode: ast::expl(ast::by_copy), ty: arg_ty}]; } // FIXME: this will be different for constrained types @@ -881,22 +1019,22 @@ mod collect { inputs: args, output: enum_ty, ret_style: ast::return_val, constraints: []}) }; - let tpt = {bounds: ty_param_bounds(tcx, m_collect, ty_params), + let tpt = {bounds: ty_param_bounds(ccx, m_collect, ty_params), ty: result_ty}; tcx.tcache.insert(local_def(variant.node.id), tpt); - write_ty(tcx, variant.node.id, result_ty); + write_ty_to_tcx(tcx, variant.node.id, result_ty); } } - fn ensure_iface_methods(tcx: ty::ctxt, id: ast::node_id) { - alt check tcx.items.get(id) { + fn ensure_iface_methods(ccx: @crate_ctxt, id: ast::node_id) { + alt check ccx.tcx.items.get(id) { ast_map::node_item(@{node: ast::item_iface(_, ms), _}, _) { - ty::store_iface_methods(tcx, id, @vec::map(ms, {|m| - ty_of_ty_method(tcx, m_collect, m) + ty::store_iface_methods(ccx.tcx, id, @vec::map(ms, {|m| + ty_of_ty_method(ccx, m_collect, m) })); } } } - fn convert_class_item(tcx: ty::ctxt, ci: ast::class_member) { + fn convert_class_item(ccx: @crate_ctxt, ci: ast::class_member) { /* we want to do something here, b/c within the scope of the class, it's ok to refer to fields & methods unqualified */ @@ -905,50 +1043,53 @@ mod collect { class. outside the class, it's done with expr_field */ alt ci { ast::instance_var(_,t,_,id) { - let tt = ast_ty_to_ty(tcx, m_collect, t); - write_ty(tcx, id, tt); + let tt = ast_ty_to_ty(ccx, m_collect, t); + write_ty_to_tcx(ccx.tcx, id, tt); } - ast::class_method(it) { convert(tcx, it); } + ast::class_method(it) { convert(ccx, it); } } } - fn convert(tcx: ty::ctxt, it: @ast::item) { + fn convert(ccx: @crate_ctxt, it: @ast::item) { + let tcx = ccx.tcx; alt it.node { // These don't define types. ast::item_mod(_) | ast::item_native_mod(_) {} ast::item_enum(variants, ty_params) { - let tpt = ty_of_item(tcx, m_collect, it); - write_ty(tcx, it.id, tpt.ty); - get_enum_variant_types(tcx, tpt.ty, variants, ty_params); + let tpt = ty_of_item(ccx, m_collect, it); + write_ty_to_tcx(tcx, it.id, tpt.ty); + get_enum_variant_types(ccx, tpt.ty, variants, ty_params); } ast::item_impl(tps, ifce, selfty, ms) { - let i_bounds = ty_param_bounds(tcx, m_collect, tps); + let i_bounds = ty_param_bounds(ccx, m_collect, tps); let my_methods = []; - let selfty = ast_ty_to_ty(tcx, m_collect, selfty); - write_ty(tcx, it.id, selfty); + let selfty = ast_ty_to_ty(ccx, m_collect, selfty); + write_ty_to_tcx(tcx, it.id, selfty); tcx.tcache.insert(local_def(it.id), {bounds: i_bounds, ty: selfty}); for m in ms { - write_ty(tcx, m.self_id, selfty); - let bounds = ty_param_bounds(tcx, m_collect, m.tps); - let mty = ty_of_method(tcx, m_collect, m); + write_ty_to_tcx(tcx, m.self_id, selfty); + let bounds = ty_param_bounds(ccx, m_collect, m.tps); + let mty = ty_of_method(ccx, m_collect, m); my_methods += [{mty: mty, id: m.id, span: m.span}]; let fty = ty::mk_fn(tcx, mty.fty); tcx.tcache.insert(local_def(m.id), {bounds: @(*i_bounds + *bounds), ty: fty}); - write_ty(tcx, m.id, fty); + write_ty_to_tcx(tcx, m.id, fty); } alt ifce { some(t) { - let iface_ty = ast_ty_to_ty(tcx, m_collect, t); + let iface_ty = ast_ty_to_ty(ccx, m_collect, t); alt ty::get(iface_ty).struct { ty::ty_iface(did, tys) { // Store the iface type in the type node alt check t.node { - ast::ty_path(_, t_id) { write_ty(tcx, t_id, iface_ty); } + ast::ty_path(_, t_id) { + write_ty_to_tcx(tcx, t_id, iface_ty); + } } if did.crate == ast::local_crate { - ensure_iface_methods(tcx, did.node); + ensure_iface_methods(ccx, did.node); } for if_m in *ty::iface_methods(tcx, did) { alt vec::find(my_methods, @@ -968,7 +1109,7 @@ mod collect { tcx.tcache.insert(local_def(id), {bounds: old.bounds, ty: mt}); - write_ty(tcx, id, mt); + write_ty_to_tcx(tcx, id, mt); } } none { @@ -988,9 +1129,9 @@ mod collect { } } ast::item_res(decl, tps, _, dtor_id, ctor_id) { - let {bounds, params} = mk_ty_params(tcx, tps); + let {bounds, params} = mk_ty_params(ccx, tps); let def_id = local_def(it.id); - let t_arg = ty_of_arg(tcx, m_collect, decl.inputs[0]); + let t_arg = ty_of_arg(ccx, m_collect, decl.inputs[0]); let t_res = ty::mk_res(tcx, def_id, t_arg.ty, params); let t_ctor = ty::mk_fn(tcx, { proto: ast::proto_box, @@ -1003,174 +1144,170 @@ mod collect { inputs: [t_arg], output: ty::mk_nil(tcx), ret_style: ast::return_val, constraints: [] }); - write_ty(tcx, it.id, t_res); - write_ty(tcx, ctor_id, t_ctor); + write_ty_to_tcx(tcx, it.id, t_res); + write_ty_to_tcx(tcx, ctor_id, t_ctor); tcx.tcache.insert(local_def(ctor_id), {bounds: bounds, ty: t_ctor}); tcx.tcache.insert(def_id, {bounds: bounds, ty: t_res}); - write_ty(tcx, dtor_id, t_dtor); + write_ty_to_tcx(tcx, dtor_id, t_dtor); } ast::item_iface(_, ms) { - let tpt = ty_of_item(tcx, m_collect, it); - write_ty(tcx, it.id, tpt.ty); - ensure_iface_methods(tcx, it.id); + let tpt = ty_of_item(ccx, m_collect, it); + write_ty_to_tcx(tcx, it.id, tpt.ty); + ensure_iface_methods(ccx, it.id); } ast::item_class(tps, members, ctor) { // Write the class type - let tpt = ty_of_item(tcx, m_collect, it); - write_ty(tcx, it.id, tpt.ty); + let tpt = ty_of_item(ccx, m_collect, it); + write_ty_to_tcx(tcx, it.id, tpt.ty); // Write the ctor type let t_ctor = ty::mk_fn(tcx, - ty_of_fn_decl(tcx, m_collect, - ast::proto_any, ctor.node.dec)); - write_ty(tcx, ctor.node.id, t_ctor); + ty_of_fn_decl(ccx, + m_collect, + ast::proto_any, + ctor.node.dec)); + write_ty_to_tcx(tcx, ctor.node.id, t_ctor); tcx.tcache.insert(local_def(ctor.node.id), {bounds: tpt.bounds, ty: t_ctor}); /* FIXME: check for proper public/privateness */ // Write the type of each of the members for m in members { - convert_class_item(tcx, m.node.decl); + convert_class_item(ccx, m.node.decl); } } _ { // This call populates the type cache with the converted type // of the item in passing. All we have to do here is to write // it into the node type table. - let tpt = ty_of_item(tcx, m_collect, it); - write_ty(tcx, it.id, tpt.ty); + let tpt = ty_of_item(ccx, m_collect, it); + write_ty_to_tcx(tcx, it.id, tpt.ty); } } } - fn convert_native(tcx: ty::ctxt, i: @ast::native_item) { + fn convert_native(ccx: @crate_ctxt, i: @ast::native_item) { // As above, this call populates the type table with the converted // type of the native item. We simply write it into the node type // table. - let tpt = ty_of_native_item(tcx, m_collect, i); - alt i.node { - ast::native_item_fn(_, _) { write_ty(tcx, i.id, tpt.ty); } - } + let tpt = ty_of_native_item(ccx, m_collect, i); + write_ty_to_tcx(ccx.tcx, i.id, tpt.ty); } - fn collect_item_types(tcx: ty::ctxt, crate: @ast::crate) { + fn collect_item_types(ccx: @crate_ctxt, crate: @ast::crate) { visit::visit_crate(*crate, (), visit::mk_simple_visitor(@{ - visit_item: bind convert(tcx, _), - visit_native_item: bind convert_native(tcx, _) + visit_item: bind convert(ccx, _), + visit_native_item: bind convert_native(ccx, _) with *visit::default_simple_visitor() })); } } - -// Type unification -mod unify { - fn unify(fcx: @fn_ctxt, expected: ty::t, actual: ty::t) -> - result { - ret ty::unify::unify(expected, actual, - ty::unify::in_bindings(fcx.var_bindings), - fcx.ccx.tcx); - } -} - - -// FIXME This is almost a duplicate of ty::type_autoderef, with structure_of -// instead of ty::struct. -fn do_autoderef(fcx: @fn_ctxt, sp: span, t: ty::t) -> ty::t { - let t1 = t; - loop { - alt structure_of(fcx, sp, t1) { - ty::ty_box(inner) | ty::ty_uniq(inner) | ty::ty_rptr(_, inner) { - alt ty::get(t1).struct { - ty::ty_var(v1) { - ty::occurs_check(fcx.ccx.tcx, sp, v1, - ty::mk_box(fcx.ccx.tcx, inner)); - } - _ { } - } - t1 = inner.ty; +// FIXME Duplicate logic with ty::type_autoderef. This could be refactored +// following the usual pattern (type_autoderef would take a helper for the +// actual recursion). +fn do_autoderef(fcx: @fn_ctxt, sp: span, t: ty::t_i) -> ty::t_i { + let mut t = t; + let mut visited = []; + let mut done = false; + while !done { + alt *t { + ty::ty_var_i(id) if vec::contains(visited, id) { + fcx.ccx.tcx.sess.span_fatal( + sp, #fmt["cyclic type `%s` of infinite size", + ty_str(fcx, t)]); } - ty::ty_res(_, inner, tps) { - t1 = ty::substitute_type_params(fcx.ccx.tcx, tps, inner); + ty::ty_var_i(id) { + visited += [id]; } - ty::ty_enum(did, tps) { - let variants = ty::enum_variants(fcx.ccx.tcx, did); - if vec::len(*variants) != 1u || vec::len(variants[0].args) != 1u { - ret t1; + ty::sty_i(_) { } + } + + structure_of(fcx, sp, t) {|sty| + alt sty { + ty::ty_box(inner) | ty::ty_uniq(inner) | ty::ty_rptr(_, inner) { + t = inner.ty; + } + ty::ty_res(_, inner, tps) { + t = ty::substitute_type_params_i(fcx.vb, tps, inner); + } + ty::ty_enum(did, tps) { + let variants = ty::enum_variants(fcx.ccx.tcx, did); + if vec::len(*variants) != 1u + || vec::len(variants[0].args) != 1u { + done = true; + } else { + t = ty::ty_to_ty_i_subst(fcx.ccx.tcx, variants[0].args[0], + tps); + } + } + _ { + done = true; + } } - t1 = - ty::substitute_type_params(fcx.ccx.tcx, tps, - variants[0].args[0]); - } - _ { ret t1; } } - }; + } + ret t; } -fn resolve_type_vars_if_possible(fcx: @fn_ctxt, typ: ty::t) -> ty::t { - alt ty::unify::fixup_vars(fcx.ccx.tcx, none, fcx.var_bindings, typ) { - result::ok(new_type) { ret new_type; } - result::err(_) { ret typ; } +fn resolve_type_vars(fcx: @fn_ctxt, sp: span, typ: ty::t_i) -> ty::t { + alt ty::unify::resolve_type(fcx.vb, typ) { + result::ok(new_type) { + ret new_type; + } + result::err(e) { + fcx.ccx.tcx.sess.span_err(sp, ty::resolve_err_to_str(e)); + + // better to return something than halt? + ret ty::mk_bot(fcx.ccx.tcx); + } } } - // Demands - procedures that require that two types unify and emit an error // message if they don't. -type ty_param_substs_and_ty = {substs: [ty::t], ty: ty::t}; - mod demand { - fn simple(fcx: @fn_ctxt, sp: span, expected: ty::t, actual: ty::t) -> - ty::t { - full(fcx, sp, expected, actual, []).ty + enum err_kernel { + ek_mismatched_types, + ek_mismatched_types_in_range } - fn with_substs(fcx: @fn_ctxt, sp: span, expected: ty::t, actual: ty::t, - ty_param_substs_0: [ty::t]) -> ty_param_substs_and_ty { - full(fcx, sp, expected, actual, ty_param_substs_0) + fn ek_to_str(ek: err_kernel) -> str { + alt ek { + ek_mismatched_types { "mismatched types" } + ek_mismatched_types_in_range { "mismatched types in range" } + } } - // Requires that the two types unify, and prints an error message if they - // don't. Returns the unified type and the type parameter substitutions. - fn full(fcx: @fn_ctxt, sp: span, expected: ty::t, actual: ty::t, - ty_param_substs_0: [ty::t]) -> - ty_param_substs_and_ty { + fn tys uctxt>( + cx: C, sp: span, ek: err_kernel, + expecteds: [T], actuals: [T]) { - let ty_param_substs: [mutable ty::t] = [mutable]; - let ty_param_subst_var_ids: [int] = []; - for ty_param_subst: ty::t in ty_param_substs_0 { - // Generate a type variable and unify it with the type parameter - // substitution. We will then pull out these type variables. - let t_0 = next_ty_var(fcx); - ty_param_substs += [mutable t_0]; - ty_param_subst_var_ids += [ty::ty_var_id(t_0)]; - simple(fcx, sp, ty_param_subst, t_0); - } - - fn mk_result(fcx: @fn_ctxt, result_ty: ty::t, - ty_param_subst_var_ids: [int]) -> - ty_param_substs_and_ty { - let result_ty_param_substs: [ty::t] = []; - for var_id: int in ty_param_subst_var_ids { - let tp_subst = ty::mk_var(fcx.ccx.tcx, var_id); - result_ty_param_substs += [tp_subst]; + if check vec::same_length(expecteds, actuals) { + vec::iter2(expecteds, actuals) {|e, a| + ty(cx, sp, ek, e, a); } - ret {substs: result_ty_param_substs, ty: result_ty}; + } else { + cx.sess().span_err( + sp, #fmt["%s: expected %u types but found %u", + ek_to_str(ek), + expecteds.len(), + actuals.len()]) } + } - - alt unify::unify(fcx, expected, actual) { - result::ok(t) { ret mk_result(fcx, t, ty_param_subst_var_ids); } + // Requires that the two types unify, and prints an error message if they + // don't. Returns the unified type and the type parameter substitutions. + fn ty uctxt>(cx: C, sp: span, ek: err_kernel, + expected: T, actual: T) -> T { + alt ty::unify::unify(cx, expected, actual) { + result::ok(t) { + ret t; + } result::err(err) { - let e_err = resolve_type_vars_if_possible(fcx, expected); - let a_err = resolve_type_vars_if_possible(fcx, actual); - fcx.ccx.tcx.sess.span_err(sp, - "mismatched types: expected `" + - ty_to_str(fcx.ccx.tcx, e_err) + - "` but found `" + - ty_to_str(fcx.ccx.tcx, a_err) + - "` (" + - ty::type_err_to_str(fcx.ccx.tcx, - err) + - ")"); - ret mk_result(fcx, expected, ty_param_subst_var_ids); + cx.sess().span_err( + sp, #fmt["%s: expected `%s` but found `%s`", + ek_to_str(ek), + cx.to_str(expected), + cx.to_str(actual)]); + ret expected; } } } @@ -1178,8 +1315,8 @@ mod demand { // Returns true if the two types unify and false if they don't. -fn are_compatible(fcx: @fn_ctxt, expected: ty::t, actual: ty::t) -> bool { - alt unify::unify(fcx, expected, actual) { +fn are_compatible(fcx: @fn_ctxt, expected: ty::t_i, actual: ty::t_i) -> bool { + alt ty::unify::unify(fcx.vb, expected, actual) { result::ok(_) { ret true; } result::err(_) { ret false; } } @@ -1188,25 +1325,18 @@ fn are_compatible(fcx: @fn_ctxt, expected: ty::t, actual: ty::t) -> bool { // Returns the types of the arguments to a enum variant. fn variant_arg_types(ccx: @crate_ctxt, _sp: span, vid: ast::def_id, - enum_ty_params: [ty::t]) -> [ty::t] { - let result: [ty::t] = []; + enum_ty_params: [ty::t_i]) -> [ty::t_i] { let tpt = ty::lookup_item_type(ccx.tcx, vid); alt ty::get(tpt.ty).struct { ty::ty_fn(f) { // N-ary variant. - for arg: ty::arg in f.inputs { - let arg_ty = - ty::substitute_type_params(ccx.tcx, enum_ty_params, arg.ty); - result += [arg_ty]; - } + vec::map(f.inputs) {|a| ty::ty_to_ty_i_subst(ccx.tcx, a.ty, enum_ty_params) } } _ { - // Nullary variant. Do nothing, as there are no arguments. + // Nullary variant. + [] } } - /* result is a vector of the *expected* types of all the fields */ - - ret result; } @@ -1215,19 +1345,19 @@ fn variant_arg_types(ccx: @crate_ctxt, _sp: span, vid: ast::def_id, // substitutions. mod writeback { - export resolve_type_vars_in_block; + export resolve_type_vars_in_fn; export resolve_type_vars_in_expr; - fn resolve_type_vars_in_type(fcx: @fn_ctxt, sp: span, typ: ty::t) -> + fn resolve_type_vars_in_type(fcx: @fn_ctxt, sp: span, typ: ty::t_i) -> option { - if !ty::type_has_vars(typ) { ret some(typ); } - alt ty::unify::fixup_vars(fcx.ccx.tcx, some(sp), fcx.var_bindings, - typ) { + alt ty::unify::resolve_type(fcx.vb, typ) { result::ok(new_type) { ret some(new_type); } - result::err(vid) { + result::err(e) { if !fcx.ccx.tcx.sess.has_errors() { - fcx.ccx.tcx.sess.span_err(sp, "cannot determine a type \ - for this expression"); + fcx.ccx.tcx.sess.span_err( + sp, + #fmt["cannot determine a type for this expression: %s", + ty::resolve_err_to_str(e)]); } ret none; } @@ -1236,24 +1366,28 @@ mod writeback { fn resolve_type_vars_for_node(wbcx: wb_ctxt, sp: span, id: ast::node_id) -> option { let fcx = wbcx.fcx, tcx = fcx.ccx.tcx; - alt resolve_type_vars_in_type(fcx, sp, ty::node_id_to_type(tcx, id)) { + alt resolve_type_vars_in_type(fcx, sp, node_ty(fcx, id)) { none { wbcx.success = false; ret none; } some(t) { - write_ty(tcx, id, t); - alt tcx.node_type_substs.find(id) { + #debug["resolve_type_vars_for_node(node=%s) t=%s", + ast_map::node_str(tcx.items, id), + ty_to_str(tcx, t)]; + + write_ty_to_tcx(tcx, id, t); + alt node_ty_substs_find(fcx, id) { some(substs) { let new_substs = []; - for subst: ty::t in substs { + for subst in substs { alt resolve_type_vars_in_type(fcx, sp, subst) { some(t) { new_substs += [t]; } none { wbcx.success = false; ret none; } } } - write_substs(tcx, id, new_substs); + write_substs_to_tcx(tcx, id, new_substs); } none {} } @@ -1261,6 +1395,15 @@ mod writeback { } } } + fn maybe_resolve_type_vars_for_node(wbcx: wb_ctxt, sp: span, + id: ast::node_id) + -> option { + if wbcx.fcx.vb.node_types.contains_key(id) { + resolve_type_vars_for_node(wbcx, sp, id) + } else { + none + } + } type wb_ctxt = // As soon as we hit an error we have to stop resolving @@ -1294,6 +1437,13 @@ mod writeback { } } } + + ast::expr_binary(_, _, _) | ast::expr_unary(_, _) | + ast::expr_assign_op(_, _, _) | ast::expr_index(_, _) { + maybe_resolve_type_vars_for_node(wbcx, e.span, + ast_util::op_expr_callee_id(e)); + } + _ { } } visit::visit_expr(e, wbcx, v); @@ -1311,11 +1461,14 @@ mod writeback { fn visit_local(l: @ast::local, wbcx: wb_ctxt, v: wb_vt) { if !wbcx.success { ret; } let var_id = lookup_local(wbcx.fcx, l.span, l.node.id); + #debug["Local %s corresponds to ty var %?", + pat_to_str(l.node.pat), var_id]; let fix_rslt = - ty::unify::resolve_type_var(wbcx.fcx.ccx.tcx, some(l.span), - wbcx.fcx.var_bindings, var_id); + ty::unify::resolve_type_var(wbcx.fcx.vb, var_id); alt fix_rslt { - result::ok(lty) { write_ty(wbcx.fcx.ccx.tcx, l.node.id, lty); } + result::ok(lty) { + write_ty_to_tcx(wbcx.fcx.ccx.tcx, l.node.id, lty); + } result::err(_) { wbcx.fcx.ccx.tcx.sess.span_err(l.span, "cannot determine a type \ @@ -1339,11 +1492,13 @@ mod writeback { visit_pat: visit_pat, visit_local: visit_local with *visit::default_visitor()}); - visit::visit_expr(e, wbcx, visit); + visit.visit_expr(e, wbcx, visit); ret wbcx.success; } - fn resolve_type_vars_in_block(fcx: @fn_ctxt, blk: ast::blk) -> bool { + fn resolve_type_vars_in_fn(fcx: @fn_ctxt, + decl: ast::fn_decl, + blk: ast::blk) -> bool { let wbcx = {fcx: fcx, mutable success: true}; let visit = visit::mk_vt(@{visit_item: visit_item, @@ -1354,15 +1509,17 @@ mod writeback { visit_local: visit_local with *visit::default_visitor()}); visit.visit_block(blk, wbcx, visit); + for arg in decl.inputs { + resolve_type_vars_for_node(wbcx, arg.ty.span, arg.id); + } ret wbcx.success; } } - // Local variable gathering. We gather up all locals and create variable IDs // for them before typechecking the function. type gather_result = - {var_bindings: @ty::unify::var_bindings, + {var_bindings: @ty::var_bindings, locals: hashmap, next_var_id: @mutable int}; @@ -1370,16 +1527,17 @@ type gather_result = fn gather_locals(ccx: @crate_ctxt, decl: ast::fn_decl, body: ast::blk, - id: ast::node_id, + _id: ast::node_id, + arg_tys: [ty::t_i], old_fcx: option<@fn_ctxt>) -> gather_result { let {vb: vb, locals: locals, nvi: nvi} = alt old_fcx { none { - {vb: ty::unify::mk_var_bindings(), - locals: int_hash::(), + {vb: ty::var_bindings(ccx.tcx), + locals: int_hash(), nvi: @mutable 0} } some(fcx) { - {vb: fcx.var_bindings, + {vb: fcx.vb, locals: fcx.locals, nvi: fcx.next_var_id} } @@ -1388,29 +1546,25 @@ fn gather_locals(ccx: @crate_ctxt, let next_var_id = fn@() -> int { let rv = *nvi; *nvi += 1; ret rv; }; - let assign = fn@(nid: ast::node_id, ty_opt: option) { + let assign = fn@(nid: ast::node_id, ty_opt: option) { let var_id = next_var_id(); locals.insert(nid, var_id); alt ty_opt { none {/* nothing to do */ } some(typ) { - ty::unify::unify(ty::mk_var(tcx, var_id), typ, - ty::unify::in_bindings(vb), tcx); + ty::unify::unify(vb, ty_var(var_id), typ); } } }; - // Add formal parameters. - let args = ty::ty_fn_args(ty::node_id_to_type(ccx.tcx, id)); - let i = 0u; - for arg: ty::arg in args { - assign(decl.inputs[i].id, some(arg.ty)); - i += 1u; + // Add for parameters. + vec::iter2(decl.inputs, arg_tys) {|inp,aty| + assign(inp.id, some(aty)); } // Add explicitly-declared locals. let visit_local = fn@(local: @ast::local, &&e: (), v: visit::vt<()>) { - let local_ty = ast_ty_to_ty_crate_infer(ccx, local.node.ty); + let local_ty = ast_ty_to_opt_ty_i(ccx, local.node.ty); assign(local.node.id, local_ty); visit::visit_local(local, e, v); }; @@ -1419,7 +1573,7 @@ fn gather_locals(ccx: @crate_ctxt, let visit_pat = fn@(p: @ast::pat, &&e: (), v: visit::vt<()>) { alt p.node { ast::pat_ident(_, _) - if !pat_util::pat_is_variant(ccx.tcx.def_map, p) { + if !pat_util::pat_is_variant(tcx.def_map, p) { assign(p.id, none); } _ {} @@ -1447,14 +1601,14 @@ fn gather_locals(ccx: @crate_ctxt, } // AST fragment checking -fn check_lit(ccx: @crate_ctxt, lit: @ast::lit) -> ty::t { +fn check_lit(fcx: @fn_ctxt, lit: @ast::lit) -> ty::t_i { alt lit.node { - ast::lit_str(_) { ty::mk_str(ccx.tcx) } - ast::lit_int(_, t) { ty::mk_mach_int(ccx.tcx, t) } - ast::lit_uint(_, t) { ty::mk_mach_uint(ccx.tcx, t) } - ast::lit_float(_, t) { ty::mk_mach_float(ccx.tcx, t) } - ast::lit_nil { ty::mk_nil(ccx.tcx) } - ast::lit_bool(_) { ty::mk_bool(ccx.tcx) } + ast::lit_str(_) { ty::mk_str(fcx.vb) } + ast::lit_int(_, t) { ty::mk_mach_int(fcx.vb, t) } + ast::lit_uint(_, t) { ty::mk_mach_uint(fcx.vb, t) } + ast::lit_float(_, t) { ty::mk_mach_float(fcx.vb, t) } + ast::lit_nil { ty::mk_nil(fcx.vb) } + ast::lit_bool(_) { ty::mk_bool(fcx.vb) } } } @@ -1474,127 +1628,138 @@ type pat_ctxt = { // Replaces self, caller, or inferred regions in the given type with the given // region. -fn instantiate_self_regions(tcx: ty::ctxt, region: ty::region, &&ty: ty::t) - -> ty::t { - if ty::type_has_rptrs(ty) { - ty::fold_ty(tcx, ty::fm_rptr({|r| - alt r { - ty::re_inferred | ty::re_caller(_) | ty::re_self(_) { region } - _ { r } - } - }), ty) - } else { - ty +fn instantiate_self_regions>( + cx: C, region: ty::region, &&ty: T) -> T { + + ty::fold_rptr(cx, ty) {|r| + alt r { + ty::re_inferred | ty::re_caller(_) | ty::re_self(_) { region } + _ { r } + } } } // Replaces all region variables in the given type with "inferred regions". // This is used during method lookup to allow typeclass implementations to // refer to inferred regions. -fn universally_quantify_regions(tcx: ty::ctxt, ty: ty::t) -> ty::t { - if ty::type_has_rptrs(ty) { - ty::fold_ty(tcx, ty::fm_rptr({|_r| ty::re_inferred}), ty) - } else { - ty +fn universally_quantify_regions(fcx: @fn_ctxt, ty: ty::t_i) -> ty::t_i { + ty::fold_rptr(fcx.vb, ty) {|_r| + ty::re_inferred } } fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path, - subpats: [@ast::pat], expected: ty::t) { + subpats: [@ast::pat], expected: ty::t_i) { // Typecheck the path. let tcx = pcx.fcx.ccx.tcx; + let fcx = pcx.fcx; + write_path_ty(fcx, pat.span, path, pat.id); + let v_def = lookup_def(pcx.fcx, path.span, pat.id); let v_def_ids = ast_util::variant_def_ids(v_def); - let ctor_tpt = ty::lookup_item_type(tcx, v_def_ids.enm); - instantiate_path(pcx.fcx, path, ctor_tpt, pat.span, pat.id); // Take the enum type params out of `expected`. - alt structure_of(pcx.fcx, pat.span, expected) { - ty::ty_enum(_, expected_tps) { - let ctor_ty = ty::node_id_to_type(tcx, pat.id); - demand::with_substs(pcx.fcx, pat.span, expected, ctor_ty, - expected_tps); - // Get the number of arguments in this enum variant. - let arg_types = variant_arg_types(pcx.fcx.ccx, pat.span, - v_def_ids.var, expected_tps); - arg_types = vec::map(arg_types, - bind instantiate_self_regions(pcx.fcx.ccx.tcx, - pcx.pat_region, - _)); - let subpats_len = subpats.len(), arg_len = arg_types.len(); - if arg_len > 0u { - // N-ary variant. - if arg_len != subpats_len { - let s = #fmt["this pattern has %u field%s, but the \ - corresponding variant has %u field%s", - subpats_len, - if subpats_len == 1u { "" } else { "s" }, - arg_len, - if arg_len == 1u { "" } else { "s" }]; - tcx.sess.span_err(pat.span, s); - } - - vec::iter2(subpats, arg_types) {|subpat, arg_ty| - check_pat(pcx, subpat, arg_ty); - } - } else if subpats_len > 0u { + structure_of(fcx, pat.span, expected) {|expected_sty| + alt expected_sty { + ty::ty_enum(_, expected_tps) { + //let ctor_ty = node_ty(fcx, pat.id); + + // unify provided parameters (if any) with parameters present + // on the expected type + demand::tys(fcx.vb, pat.span, demand::ek_mismatched_types, + expected_tps, node_ty_substs(fcx, pat.id)); + + // Get the number of arguments in this enum variant. + let arg_types = variant_arg_types( + fcx.ccx, pat.span, v_def_ids.var, expected_tps); + let arg_types = vec::map(arg_types) {|t| + instantiate_self_regions(fcx.vb, pcx.pat_region, t) + }; + let subpats_len = subpats.len(), arg_len = arg_types.len(); + if arg_len > 0u { + // N-ary variant. + if arg_len != subpats_len { + let s = #fmt["this pattern has %u field%s, but the \ + corresponding variant has %u field%s", + subpats_len, + if subpats_len == 1u { "" } else { "s" }, + arg_len, + if arg_len == 1u { "" } else { "s" }]; + tcx.sess.span_err(pat.span, s); + } + + vec::iter2(subpats, arg_types) {|subpat, arg_ty| + check_pat(pcx, subpat, arg_ty); + } + } else if subpats_len > 0u { + tcx.sess.span_err( + pat.span, + #fmt["this pattern has %u field%s, \ + but the corresponding variant has no fields", + subpats_len, + if subpats_len == 1u { "" } + else { "s" }]); + } + } + _ { tcx.sess.span_err - (pat.span, #fmt["this pattern has %u field%s, \ - but the corresponding variant has no fields", - subpats_len, - if subpats_len == 1u { "" } - else { "s" }]); + (pat.span, + #fmt["mismatched types: expected enum but found `%s`", + ty_str(fcx, expected)]); + } } - } - _ { - tcx.sess.span_err - (pat.span, - #fmt["mismatched types: expected enum but found `%s`", - ty_to_str(tcx, expected)]); - } } } +fn ty_var(vid: int) -> ty::t_i { + @ty::ty_var_i(vid) +} + // Pattern checking is top-down rather than bottom-up so that bindings get // their types immediately. -fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { +fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t_i) { + let fcx = pcx.fcx; let tcx = pcx.fcx.ccx.tcx; alt pat.node { ast::pat_wild { - write_ty(tcx, pat.id, expected); + write_ty(fcx, pat.id, expected); } ast::pat_lit(lt) { - check_expr_with(pcx.fcx, lt, expected); - write_ty(tcx, pat.id, expr_ty(tcx, lt)); + check_expr_with(fcx, lt, expected); + write_ty(fcx, pat.id, expr_ty(fcx, lt)); } ast::pat_range(begin, end) { - check_expr_with(pcx.fcx, begin, expected); - check_expr_with(pcx.fcx, end, expected); - let b_ty = resolve_type_vars_if_possible(pcx.fcx, - expr_ty(tcx, begin)); - if !ty::same_type(tcx, b_ty, resolve_type_vars_if_possible( - pcx.fcx, expr_ty(tcx, end))) { - tcx.sess.span_err(pat.span, "mismatched types in range"); - } else if !ty::type_is_numeric(b_ty) { + check_expr_with(fcx, begin, expected); + check_expr_with(fcx, end, expected); + let b_ty = expr_ty(fcx, begin); + let e_ty = expr_ty(fcx, end); + + // "mismatched types in range" + demand::ty(fcx.vb, pat.span, demand::ek_mismatched_types_in_range, + b_ty, e_ty); + + if !type_is_numeric(fcx, pat.span, b_ty) { tcx.sess.span_err(pat.span, "non-numeric type used in range"); } else if !valid_range_bounds(tcx, begin, end) { tcx.sess.span_err(begin.span, "lower range bound must be less \ than upper"); } - write_ty(tcx, pat.id, b_ty); + + write_ty(fcx, pat.id, b_ty); } ast::pat_ident(name, sub) if !pat_util::pat_is_variant(tcx.def_map, pat) { - let vid = lookup_local(pcx.fcx, pat.span, pat.id); - let typ = ty::mk_var(tcx, vid); - typ = demand::simple(pcx.fcx, pat.span, expected, typ); + let vid = lookup_local(fcx, pat.span, pat.id); + let typ = ty_var(vid); + typ = demand::ty(fcx.vb, pat.span, demand::ek_mismatched_types, + expected, typ); let canon_id = pcx.map.get(path_to_ident(name)); if canon_id != pat.id { - let tv_id = lookup_local(pcx.fcx, pat.span, canon_id); - let ct = ty::mk_var(tcx, tv_id); - typ = demand::simple(pcx.fcx, pat.span, ct, typ); + let ct = ty_var(lookup_local(fcx, pat.span, canon_id)); + typ = demand::ty(fcx.vb, pat.span, demand::ek_mismatched_types, + ct, typ); } - write_ty(tcx, pat.id, typ); + write_ty(fcx, pat.id, typ); alt sub { some(p) { check_pat(pcx, p, expected); } _ {} @@ -1607,16 +1772,17 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { check_pat_variant(pcx, pat, path, subpats, expected); } ast::pat_rec(fields, etc) { - let ex_fields; - alt structure_of(pcx.fcx, pat.span, expected) { - ty::ty_rec(fields) { ex_fields = fields; } - _ { - tcx.sess.span_fatal - (pat.span, - #fmt["mismatched types: expected `%s` but found record", - ty_to_str(tcx, expected)]); - } - } + let ex_fields = structure_of(fcx, pat.span, expected) {|sty| + alt sty { + ty::ty_rec(fields) { fields } + _ { + tcx.sess.span_fatal + (pat.span, + #fmt["mismatched types: expected `%s` but found record", + ty_str(fcx, expected)]); + } + } + }; let f_count = vec::len(fields); let ex_f_count = vec::len(ex_fields); if ex_f_count < f_count || !etc && ex_f_count > f_count { @@ -1626,7 +1792,7 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { fields", ex_f_count, f_count]); } - fn matches(name: str, f: ty::field) -> bool { + fn matches(name: str, f: ty::field_i) -> bool { ret str::eq(name, f.ident); } for f: ast::field_pat in fields { @@ -1642,19 +1808,20 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { } } } - write_ty(tcx, pat.id, expected); + write_ty(fcx, pat.id, expected); } ast::pat_tup(elts) { - let ex_elts; - alt structure_of(pcx.fcx, pat.span, expected) { - ty::ty_tup(elts) { ex_elts = elts; } - _ { - tcx.sess.span_fatal - (pat.span, - #fmt["mismatched types: expected `%s`, found tuple", - ty_to_str(tcx, expected)]); - } - } + let ex_elts = structure_of(fcx, pat.span, expected) {|sty| + alt sty { + ty::ty_tup(elts) { elts } + _ { + tcx.sess.span_fatal + (pat.span, + #fmt["mismatched types: expected `%s`, found tuple", + ty_str(fcx, expected)]); + } + } + }; let e_count = vec::len(elts); if e_count != vec::len(ex_elts) { tcx.sess.span_fatal @@ -1667,35 +1834,39 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { check_pat(pcx, elt, ex_elts[i]); i += 1u; } - - write_ty(tcx, pat.id, expected); + write_ty(fcx, pat.id, expected); } ast::pat_box(inner) { - alt structure_of(pcx.fcx, pat.span, expected) { - ty::ty_box(e_inner) { - check_pat(pcx, inner, e_inner.ty); - write_ty(tcx, pat.id, expected); - } - _ { - tcx.sess.span_fatal(pat.span, - "mismatched types: expected `" + - ty_to_str(tcx, expected) + - "` found box"); - } + structure_of(pcx.fcx, pat.span, expected) {|sty| + alt sty { + ty::ty_box(e_inner) { + check_pat(pcx, inner, e_inner.ty); + write_ty(fcx, pat.id, expected); + } + _ { + tcx.sess.span_fatal( + pat.span, + "mismatched types: expected `" + + ty_str(fcx, expected) + + "` found box"); + } + } } } ast::pat_uniq(inner) { - alt structure_of(pcx.fcx, pat.span, expected) { - ty::ty_uniq(e_inner) { - check_pat(pcx, inner, e_inner.ty); - write_ty(tcx, pat.id, expected); - } - _ { - tcx.sess.span_fatal(pat.span, - "mismatched types: expected `" + - ty_to_str(tcx, expected) + - "` found uniq"); - } + structure_of(pcx.fcx, pat.span, expected) {|sty| + alt sty { + ty::ty_uniq(e_inner) { + check_pat(pcx, inner, e_inner.ty); + write_ty(fcx, pat.id, expected); + } + _ { + tcx.sess.span_fatal(pat.span, + "mismatched types: expected `" + + ty_str(fcx, expected) + + "` found uniq"); + } + } } } } @@ -1759,42 +1930,51 @@ fn require_pure_call(ccx: @crate_ctxt, caller_purity: ast::purity, } } -type unifier = fn@(@fn_ctxt, span, ty::t, ty::t) -> ty::t; +type unifier = fn@(@fn_ctxt, span, ty::t_i, ty::t_i); fn check_expr(fcx: @fn_ctxt, expr: @ast::expr) -> bool { - fn dummy_unify(_fcx: @fn_ctxt, _sp: span, _expected: ty::t, actual: ty::t) - -> ty::t { - actual + fn dummy_unify(_fcx: @fn_ctxt, _sp: span, _e: ty::t_i, _a: ty::t_i) { } - ret check_expr_with_unifier(fcx, expr, dummy_unify, - ty::mk_nil(fcx.ccx.tcx)); + check_expr_with_unifier(fcx, expr, dummy_unify, @ty::sty_i(ty::ty_nil)) } -fn check_expr_with(fcx: @fn_ctxt, expr: @ast::expr, expected: ty::t) -> bool { - ret check_expr_with_unifier(fcx, expr, demand::simple, expected); + +fn check_expr_with(fcx: @fn_ctxt, expr: @ast::expr, expected: ty::t_i) -> bool { + fn demand_unify(fcx: @fn_ctxt, sp: span, e: ty::t_i, a: ty::t_i) { + demand::ty(fcx.vb, sp, demand::ek_mismatched_types, e, a); + } + ret check_expr_with_unifier(fcx, expr, demand_unify, expected); } -fn impl_self_ty(tcx: ty::ctxt, did: ast::def_id) -> {n_tps: uint, ty: ty::t} { - if did.crate == ast::local_crate { - alt check tcx.items.get(did.node) { +fn impl_self_ty(fcx: @fn_ctxt, did: ast::def_id) + -> {vars: [ty::t_i], self_ty: ty::t_i} { + + let {n_tps, self_ty} = if did.crate == ast::local_crate { + alt check fcx.ccx.tcx.items.get(did.node) { ast_map::node_item(@{node: ast::item_impl(ts, _, st, _), _}, _) { - {n_tps: vec::len(ts), ty: ast_ty_to_ty(tcx, m_check, st)} + {n_tps: ts.len(), + self_ty: ast_ty_to_ty(fcx.ccx, m_check, st)} } } } else { - let ity = ty::lookup_item_type(tcx, did); - {n_tps: vec::len(*ity.bounds), ty: ity.ty} - } + let ity = ty::lookup_item_type(fcx.ccx.tcx, did); + {n_tps: vec::len(*ity.bounds), + self_ty: ity.ty} + }; + + let vars = next_ty_vars(fcx, n_tps); + + {vars: vars, self_ty: ty::ty_to_ty_i_subst(fcx.ccx.tcx, self_ty, vars)} } fn lookup_method(fcx: @fn_ctxt, expr: @ast::expr, node_id: ast::node_id, - name: ast::ident, ty: ty::t, tps: [ty::t]) + name: ast::ident, ty: ty::t_i, tps: [ty::t_i]) -> option { alt lookup_method_inner(fcx, expr, name, ty) { some({method_ty: fty, n_tps: method_n_tps, substs, origin, self_sub}) { let tcx = fcx.ccx.tcx; let substs = substs, n_tps = vec::len(substs), n_tys = vec::len(tps); - let has_self = ty::type_has_vars(fty); + let has_self = ty::type_has_self(fty); if method_n_tps + n_tps > 0u { if n_tys == 0u || n_tys != method_n_tps { if n_tys != 0u { @@ -1803,30 +1983,26 @@ fn lookup_method(fcx: @fn_ctxt, expr: @ast::expr, node_id: ast::node_id, parameters given for this method"); } - substs += vec::from_fn(method_n_tps, {|_i| - ty::mk_var(tcx, next_ty_var_id(fcx)) - }); + substs += next_ty_vars(fcx, method_n_tps); } else { substs += tps; } - write_ty_substs(tcx, node_id, fty, substs); } else { - if n_tys > 0u { - tcx.sess.span_err(expr.span, "this method does not take type \ - parameters"); - } - write_ty(tcx, node_id, fty); + substs += tps; } + write_ty_substs(fcx, node_id, fty, substs); + if has_self && !option::is_none(self_sub) { - let fty = ty::node_id_to_type(tcx, node_id); - fty = fixup_self_in_method_ty( - tcx, fty, substs, option::get(self_sub)); - write_ty(tcx, node_id, fty); + let (self_ty, span) = option::get(self_sub); + let fty = node_ty(fcx, node_id); + let fty = fixup_self_call( + fcx, span, fty, substs, self_ty); + write_ty(fcx, node_id, fty); } if ty::type_has_rptrs(ty::ty_fn_ret(fty)) { - let fty = ty::node_id_to_type(tcx, node_id); + let fty = node_ty(fcx, node_id); fty = fixup_self_region_in_method_ty(fcx, fty, expr); - write_ty(tcx, node_id, fty); + write_ty(fcx, node_id, fty); } some(origin) } @@ -1835,13 +2011,14 @@ fn lookup_method(fcx: @fn_ctxt, expr: @ast::expr, node_id: ast::node_id, } fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr, - name: ast::ident, ty: ty::t) - -> option<{method_ty: ty::t, n_tps: uint, substs: [ty::t], + name: ast::ident, ty: ty::t_i) + -> option<{method_ty: ty::t, n_tps: uint, substs: [ty::t_i], origin: method_origin, - self_sub: option}> { + self_sub: option<(ty::t_i, span)>}> { let tcx = fcx.ccx.tcx; + // First, see whether this is an interface-bounded parameter - alt ty::get(ty).struct { + alt structure_of(fcx, expr.span, ty, {|sty| sty }) { ty::ty_param(n, did) { let bound_n = 0u; for bound in *tcx.ty_param_bounds.get(did.node) { @@ -1854,12 +2031,13 @@ fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr, alt vec::position(*ifce_methods, {|m| m.ident == name}) { some(pos) { let m = ifce_methods[pos]; + let tps_i = vec::map(tps) {|t| ty::ty_to_ty_i(tcx, t) }; ret some({method_ty: ty::mk_fn(tcx, {proto: ast::proto_box with m.fty}), n_tps: vec::len(*m.tps), - substs: tps, + substs: tps_i, origin: method_param(iid, pos, n, bound_n), - self_sub: some(self_param(ty, fcx, expr.span)) + self_sub: some((ty, expr.span)) }); } _ {} @@ -1875,7 +2053,7 @@ fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr, for m in *ty::iface_methods(tcx, did) { if m.ident == name { let fty = ty::mk_fn(tcx, {proto: ast::proto_box with m.fty}); - if ty::type_has_vars(fty) { + if ty::type_has_self(fty) { tcx.sess.span_fatal( expr.span, "can not call a method that contains a \ self type through a boxed iface"); @@ -1896,11 +2074,13 @@ fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr, _ {} } - fn ty_from_did(tcx: ty::ctxt, did: ast::def_id) -> ty::t { - if did.crate == ast::local_crate { - alt check tcx.items.get(did.node) { + fn ty_from_did(fcx: @fn_ctxt, did: ast::def_id) -> ty::t { + let ccx = fcx.ccx; + let tcx = ccx.tcx; + /*if did.crate == ast::local_crate { + alt check ccx.tcx.items.get(did.node) { ast_map::node_method(m, _, _) { - let mt = ty_of_method(tcx, m_check, m); + let mt = ty_of_method(ccx, m_check, m); ty::mk_fn(tcx, {proto: ast::proto_box with mt.fty}) } } @@ -1910,6 +2090,15 @@ fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr, ty::mk_fn(tcx, {proto: ast::proto_box with fty}) } } + }*/ + + // FIXME/NDM--Why don't we just use proto_box for method types + // in the first place? + let mty = ty::lookup_item_type(tcx, did); + alt check ty::get(mty.ty).struct { + ty::ty_fn(fty) { + ty::mk_fn(tcx, {proto: ast::proto_box with fty}) + } } } @@ -1919,16 +2108,9 @@ fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr, for @{did, methods, _} in *impls { alt vec::find(methods, {|m| m.ident == name}) { some(m) { - let {n_tps, ty: self_ty} = impl_self_ty(tcx, did); - let {vars, ty: self_ty} = if n_tps > 0u { - bind_params(fcx, self_ty, n_tps) - } else { - {vars: [], ty: self_ty} - }; - - let ty = universally_quantify_regions(tcx, ty); - - alt unify::unify(fcx, self_ty, ty) { + let {vars, self_ty} = impl_self_ty(fcx, did); + let ty = universally_quantify_regions(fcx, ty); + alt ty::unify::unify(fcx.vb, self_ty, ty) { result::ok(_) { if option::is_some(result) { // FIXME[impl] score specificity to resolve ambiguity? @@ -1939,7 +2121,7 @@ fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr, } } else { result = some({ - method_ty: ty_from_did(tcx, m.did), + method_ty: ty_from_did(fcx, m.did), n_tps: m.n_tps, substs: vars, origin: method_static(m.did), @@ -1959,17 +2141,19 @@ fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr, // problem -- class_item_ty should really be only used for internal stuff. // or should have a privacy field. -fn lookup_field_ty(cx: ty::ctxt, items:[@ty::class_item_ty], - fieldname: ast::ident, sp: span) - -> ty::t { +fn lookup_field_ty(fcx: @fn_ctxt, items:[@ty::class_item_ty], + fieldname: ast::ident, sp: span, tps: [ty::t_i]) + -> ty::t_i { for item in items { - #debug("%s $$$ %s", fieldname, item.ident); + #debug("%s $$$ %s", fieldname, item.ident); alt item.contents { - ty::var_ty(t) if item.ident == fieldname { ret t; } + ty::var_ty(t) if item.ident == fieldname { + ret ty::ty_to_ty_i_subst(fcx.ccx.tcx, t, tps); + } _ { } } } - cx.sess.span_fatal(sp, #fmt("unbound field %s", fieldname)); + fcx.ccx.tcx.sess.span_fatal(sp, #fmt("unbound field %s", fieldname)); } /* @@ -2008,14 +2192,15 @@ fn region_of(fcx: @fn_ctxt, expr: @ast::expr) -> ty::region { "regions of index operations"); } ast::expr_unary(ast::deref, base) { - let expr_ty = ty::expr_ty(fcx.ccx.tcx, base); - let expr_ty = structurally_resolved_type(fcx, expr.span, expr_ty); - alt ty::get(expr_ty).struct { - ty::ty_rptr(region, _) { region } - ty::ty_box(_) | ty::ty_uniq(_) { + let expr_ty = expr_ty(fcx, base); + structure_of(fcx, expr.span, expr_ty) {|sty| + alt sty { + ty::ty_rptr(region, _) { region } + ty::ty_box(_) | ty::ty_uniq(_) { fcx.ccx.tcx.sess.span_unimpl(expr.span, "borrowing"); + } + _ { ret region_of(fcx, base); } } - _ { ret region_of(fcx, base); } } } _ { @@ -2030,39 +2215,48 @@ fn check_expr_fn_with_unifier(fcx: @fn_ctxt, proto: ast::proto, decl: ast::fn_decl, body: ast::blk, - unify: unifier, - expected: ty::t) { + unifier: unifier, + expected: ty::t_i) { let tcx = fcx.ccx.tcx; - let fty = ty::mk_fn(tcx, - ty_of_fn_decl(tcx, m_check_tyvar(fcx), proto, decl)); + let fty = + @ty::sty_i(ty::ty_fn( + ty_of_fn_decl_base( + tcx, proto, decl, + {|a| {mode: a.mode, ty: ast_ty_to_ty_i(fcx, a.ty)} }, + {|t| ast_ty_to_ty_i(fcx, t) }))); #debug("check_expr_fn_with_unifier %s fty=%s", - expr_to_str(expr), - ty_to_str(tcx, fty)); + expr_to_str(expr), ty_str(fcx, fty)); - write_ty(tcx, expr.id, fty); + write_ty(fcx, expr.id, fty); // Unify the type of the function with the expected type before we // typecheck the body so that we have more information about the // argument types in the body. This is needed to make binops and // record projection work on type inferred arguments. - unify(fcx, expr.span, expected, fty); + unifier(fcx, expr.span, expected, fty); - check_fn(fcx.ccx, proto, decl, body, expr.id, some(fcx)); + let bot = false; + let ret_ty = fn_ret(fcx, body.span, fty, bot); + let arg_tys = vec::map(fn_args(fcx, body.span, fty)) {|a| a.ty }; + + check_fn(fcx.ccx, proto, decl, body, expr.id, + ret_ty, arg_tys, some(fcx)); } -fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, - expected: ty::t) -> bool { +fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unifier: unifier, + expected: ty::t_i) -> bool { #debug("typechecking expr %s", syntax::print::pprust::expr_to_str(expr)); // A generic function to factor out common logic from call and bind // expressions. fn check_call_or_bind(fcx: @fn_ctxt, sp: span, id: ast::node_id, - fty: ty::t, args: [option<@ast::expr>]) -> bool { + fty: ty::t_i, args: [option<@ast::expr>]) -> bool { + // Replaces "caller" regions in the arguments with the local region. fn instantiate_caller_regions(fcx: @fn_ctxt, id: ast::node_id, - args: [ty::arg]) -> [ty::arg] { + args: [ty::arg_i]) -> [ty::arg_i] { let site_to_block = fcx.ccx.tcx.region_map.call_site_to_block; let block_id = alt site_to_block.find(id) { none { @@ -2076,35 +2270,21 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, let region = ty::re_block(block_id); ret vec::map(args) {|arg| - if ty::type_has_rptrs(arg.ty) { - let ty = ty::fold_ty(fcx.ccx.tcx, ty::fm_rptr({|r| - alt r { - ty::re_caller(_) { - // FIXME: We should not recurse into nested - // function types here. - region - } - _ { r } - } - }), arg.ty); - {ty: ty with arg} - } else { - arg - } + let ty = ty::fold_rptr(fcx.vb, arg.ty) {|r| + alt r { + ty::re_caller(_) { + // FIXME: We should not recurse into nested + // function types here. + region + } + _ { r } + } + }; + {ty: ty with arg} }; } - let sty = structure_of(fcx, sp, fty); - // Grab the argument types - let arg_tys = alt sty { - ty::ty_fn({inputs: arg_tys, _}) { arg_tys } - _ { - fcx.ccx.tcx.sess.span_fatal(sp, "mismatched types: \ - expected function or native \ - function but found " - + ty_to_str(fcx.ccx.tcx, fty)) - } - }; + let arg_tys = fn_args(fcx, sp, fty); // Check that the correct number of arguments were supplied. let expected_arg_count = vec::len(arg_tys); @@ -2127,7 +2307,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, // HACK: build an arguments list with dummy arguments to // check against let dummy = {mode: ast::expl(ast::by_ref), - ty: ty::mk_bot(fcx.ccx.tcx)}; + ty: ty::mk_bot(fcx.vb)}; arg_tys = vec::from_elem(supplied_arg_count, dummy); } @@ -2150,8 +2330,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, _ { false } }; if is_block == check_blocks { - bot |= check_expr_with_unifier( - fcx, a, demand::simple, arg_tys[i].ty); + bot |= check_expr_with(fcx, a, arg_tys[i].ty); } } none { } @@ -2168,7 +2347,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, rhs: @ast::expr, id: ast::node_id) -> bool { let t = next_ty_var(fcx); let bot = check_expr_with(fcx, lhs, t) | check_expr_with(fcx, rhs, t); - write_ty(fcx.ccx.tcx, id, ty::mk_nil(fcx.ccx.tcx)); + write_ty(fcx, id, ty::mk_nil(fcx.vb)); ret bot; } @@ -2183,7 +2362,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, let bot = check_expr(fcx, f); // Call the generic checker. - bot | check_call_or_bind(fcx, sp, id, expr_ty(fcx.ccx.tcx, f), + bot | check_call_or_bind(fcx, sp, id, expr_ty(fcx, f), args_opt_0) } @@ -2198,32 +2377,25 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, require_pure_call(fcx.ccx, fcx.purity, f, sp); // Pull the return type out of the type of the function. - let fty = ty::expr_ty(fcx.ccx.tcx, f); - let rt_1 = alt structure_of(fcx, sp, fty) { - ty::ty_fn(f) { - bot |= f.ret_style == ast::noreturn; - f.output - } - _ { fcx.ccx.tcx.sess.span_fatal(sp, "calling non-function"); } - }; - write_ty(fcx.ccx.tcx, id, rt_1); + let fty = expr_ty(fcx, f); + let rt_1 = fn_ret(fcx, sp, fty, bot); + write_ty(fcx, id, rt_1); ret bot; } // A generic function for checking for or for-each loops fn check_for(fcx: @fn_ctxt, local: @ast::local, - element_ty: ty::t, body: ast::blk, + element_ty: ty::t_i, body: ast::blk, node_id: ast::node_id) -> bool { let locid = lookup_local(fcx, local.span, local.node.id); - let element_ty = demand::simple(fcx, local.span, element_ty, - ty::mk_var(fcx.ccx.tcx, locid)); + let element_ty = demand::ty(fcx.vb, local.span, demand::ek_mismatched_types, + element_ty, ty::mk_var(locid)); let bot = check_decl_local(fcx, local); check_block_no_value(fcx, body); // Unify type of decl with element type of the seq - demand::simple(fcx, local.span, - ty::node_id_to_type(fcx.ccx.tcx, local.node.id), - element_ty); - write_nil(fcx.ccx.tcx, node_id); + demand::ty(fcx.vb, local.span, demand::ek_mismatched_types, + node_ty(fcx, local.node.id), element_ty); + write_nil(fcx, node_id); ret bot; } @@ -2232,15 +2404,15 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, // or if-check fn check_then_else(fcx: @fn_ctxt, thn: ast::blk, elsopt: option<@ast::expr>, id: ast::node_id, - _sp: span) -> bool { + sp: span) -> bool { let (if_t, if_bot) = alt elsopt { some(els) { let thn_bot = check_block(fcx, thn); - let thn_t = block_ty(fcx.ccx.tcx, thn); + let thn_t = node_ty(fcx, thn.node.id); let els_bot = check_expr_with(fcx, els, thn_t); - let els_t = expr_ty(fcx.ccx.tcx, els); - let if_t = if !ty::type_is_bot(els_t) { + let els_t = expr_ty(fcx, els); + let if_t = if !type_is_bot(fcx, sp, els_t) { els_t } else { thn_t @@ -2249,10 +2421,10 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, } none { check_block_no_value(fcx, thn); - (ty::mk_nil(fcx.ccx.tcx), false) + (ty::mk_nil(fcx.vb), false) } }; - write_ty(fcx.ccx.tcx, id, if_t); + write_ty(fcx, id, if_t); ret if_bot; } @@ -2264,55 +2436,56 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, _ { none } } } - fn lookup_op_method(fcx: @fn_ctxt, op_ex: @ast::expr, self_t: ty::t, + fn lookup_op_method(fcx: @fn_ctxt, op_ex: @ast::expr, self_t: ty::t_i, opname: str, args: [option<@ast::expr>]) - -> option { + -> option { let callee_id = ast_util::op_expr_callee_id(op_ex); alt lookup_method(fcx, op_ex, callee_id, opname, self_t, []) { some(origin) { - let method_ty = ty::node_id_to_type(fcx.ccx.tcx, callee_id); + let method_ty = node_ty(fcx, callee_id); check_call_or_bind(fcx, op_ex.span, op_ex.id, method_ty, args); fcx.ccx.method_map.insert(op_ex.id, origin); - some(ty::ty_fn_ret(method_ty)) + let bot = false; + some(fn_ret(fcx, op_ex.span, method_ty, bot)) } _ { none } } } - fn check_binop(fcx: @fn_ctxt, ex: @ast::expr, ty: ty::t, - op: ast::binop, rhs: @ast::expr) -> ty::t { - let resolved_t = structurally_resolved_type(fcx, ex.span, ty); + fn check_binop(fcx: @fn_ctxt, ex: @ast::expr, ty: ty::t_i, + op: ast::binop, rhs: @ast::expr) -> ty::t_i { let tcx = fcx.ccx.tcx; - if ty::is_binopable(tcx, resolved_t, op) { + if structure_of(fcx, ex.span, ty, ty::is_binopable(tcx, _, op)) { ret alt op { ast::eq | ast::lt | ast::le | ast::ne | ast::ge | - ast::gt { ty::mk_bool(tcx) } - _ { resolved_t } + ast::gt { ty::mk_bool(fcx.vb) } + _ { ty } }; } alt binop_method(op) { some(name) { - alt lookup_op_method(fcx, ex, resolved_t, name, [some(rhs)]) { + alt lookup_op_method(fcx, ex, ty, name, [some(rhs)]) { some(ret_ty) { ret ret_ty; } _ {} } } _ {} } + tcx.sess.span_err( ex.span, "binary operation " + ast_util::binop_to_str(op) + - " cannot be applied to type `" + ty_to_str(tcx, resolved_t) + + " cannot be applied to type `" + ty_str(fcx, ty) + "`"); - resolved_t + ty } fn check_user_unop(fcx: @fn_ctxt, op_str: str, mname: str, - ex: @ast::expr, rhs_t: ty::t) -> ty::t { + ex: @ast::expr, rhs_t: ty::t_i) -> ty::t_i { alt lookup_op_method(fcx, ex, rhs_t, mname, []) { some(ret_ty) { ret_ty } _ { fcx.ccx.tcx.sess.span_err( ex.span, #fmt["cannot apply unary operator `%s` to type `%s`", - op_str, ty_to_str(fcx.ccx.tcx, rhs_t)]); + op_str, ty_str(fcx, rhs_t)]); rhs_t } } @@ -2323,8 +2496,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, let bot = false; alt expr.node { ast::expr_lit(lit) { - let typ = check_lit(fcx.ccx, lit); - write_ty(tcx, id, typ); + let typ = check_lit(fcx, lit); + write_ty(fcx, id, typ); } ast::expr_binary(binop, lhs, rhs) { let lhs_t = next_ty_var(fcx); @@ -2334,7 +2507,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, check_expr_with(fcx, rhs, lhs_t) } else { let rhs_bot = check_expr(fcx, rhs); - let rhs_t = expr_ty(tcx, rhs); + let rhs_t = expr_ty(fcx, rhs); require_integral(fcx, rhs.span, rhs_t); rhs_bot }; @@ -2342,113 +2515,97 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, if !ast_util::lazy_binop(binop) { bot |= rhs_bot; } let result = check_binop(fcx, expr, lhs_t, binop, rhs); - write_ty(tcx, id, result); + write_ty(fcx, id, result); } ast::expr_assign_op(op, lhs, rhs) { require_impure(tcx.sess, fcx.purity, expr.span); bot = check_assignment(fcx, expr.span, lhs, rhs, id); - let lhs_t = ty::expr_ty(tcx, lhs); + let lhs_t = expr_ty(fcx, lhs); let result = check_binop(fcx, expr, lhs_t, op, rhs); - demand::simple(fcx, expr.span, result, lhs_t); + demand::ty(fcx.vb, expr.span, demand::ek_mismatched_types, + result, lhs_t); } ast::expr_unary(unop, oper) { bot = check_expr(fcx, oper); - let oper_t = expr_ty(tcx, oper); + let oper_t = expr_ty(fcx, oper); alt unop { ast::box(mutbl) { - oper_t = ty::mk_box(tcx, {ty: oper_t, mutbl: mutbl}); + oper_t = @ty::sty_i(ty::ty_box({ty: oper_t, mutbl: mutbl})); } ast::uniq(mutbl) { - oper_t = ty::mk_uniq(tcx, {ty: oper_t, mutbl: mutbl}); + oper_t = @ty::sty_i(ty::ty_uniq({ty: oper_t, mutbl: mutbl})); } ast::deref { - alt structure_of(fcx, expr.span, oper_t) { - ty::ty_box(inner) { oper_t = inner.ty; } - ty::ty_uniq(inner) { oper_t = inner.ty; } - ty::ty_res(_, inner, _) { oper_t = inner; } - ty::ty_enum(id, tps) { - let variants = ty::enum_variants(tcx, id); - if vec::len(*variants) != 1u || - vec::len(variants[0].args) != 1u { + structure_of(fcx, expr.span, oper_t) {|sty| + alt sty { + ty::ty_box(inner) { oper_t = inner.ty; } + ty::ty_uniq(inner) { oper_t = inner.ty; } + ty::ty_res(_, inner, _) { oper_t = inner; } + ty::ty_enum(id, tps) { + let variants = ty::enum_variants(tcx, id); + if vec::len(*variants) != 1u || + vec::len(variants[0].args) != 1u { + tcx.sess.span_err(expr.span, + "can only dereference enums " + + "with a single variant which has a " + + "single argument"); + } + oper_t = ty::ty_to_ty_i_subst(tcx, variants[0].args[0], tps); + } + ty::ty_ptr(inner) { + oper_t = inner.ty; + require_unsafe(tcx.sess, fcx.purity, expr.span); + } + ty::ty_rptr(_, inner) { oper_t = inner.ty; } + _ { tcx.sess.span_err(expr.span, - "can only dereference enums " + - "with a single variant which has a " - + "single argument"); + #fmt("Type %s cannot be dereferenced", + ty_str(fcx, oper_t))); + } } - oper_t = - ty::substitute_type_params(tcx, tps, variants[0].args[0]); - } - ty::ty_ptr(inner) { - oper_t = inner.ty; - require_unsafe(tcx.sess, fcx.purity, expr.span); - } - ty::ty_rptr(_, inner) { oper_t = inner.ty; } - _ { - tcx.sess.span_err(expr.span, - #fmt("Type %s cannot be dereferenced", - ty_to_str(tcx, oper_t))); - } } } ast::not { - oper_t = structurally_resolved_type(fcx, oper.span, oper_t); - if !(ty::type_is_integral(oper_t) || - ty::get(oper_t).struct == ty::ty_bool) { + if !type_is_integral(fcx, expr.span, oper_t) { oper_t = check_user_unop(fcx, "!", "!", expr, oper_t); } } ast::neg { - oper_t = structurally_resolved_type(fcx, oper.span, oper_t); - if !(ty::type_is_integral(oper_t) || - ty::type_is_fp(oper_t)) { + if !type_is_integral(fcx, expr.span, oper_t) { oper_t = check_user_unop(fcx, "-", "unary-", expr, oper_t); } } } - write_ty(tcx, id, oper_t); + write_ty(fcx, id, oper_t); } ast::expr_addr_of(mutbl, oper) { bot = check_expr(fcx, oper); - let oper_t = expr_ty(tcx, oper); + let oper_t = expr_ty(fcx, oper); let region = region_of(fcx, oper); let tm = { ty: oper_t, mutbl: mutbl }; - oper_t = ty::mk_rptr(tcx, region, tm); - write_ty(tcx, id, oper_t); + oper_t = ty::mk_rptr(fcx.vb, region, tm); + write_ty(fcx, id, oper_t); } ast::expr_path(pth) { - let defn = lookup_def(fcx, pth.span, id); - - let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn); - if ty::def_has_ty_params(defn) { - instantiate_path(fcx, pth, tpt, expr.span, expr.id); - } else { - // The definition doesn't take type parameters. If the programmer - // supplied some, that's an error - if vec::len::<@ast::ty>(pth.node.types) > 0u { - tcx.sess.span_fatal(expr.span, - "this kind of value does not \ - take type parameters"); - } - write_ty(tcx, id, tpt.ty); - } + write_path_ty(fcx, expr.span, pth, id); } ast::expr_mac(_) { tcx.sess.bug("unexpanded macro"); } ast::expr_fail(expr_opt) { bot = true; alt expr_opt { none {/* do nothing */ } - some(e) { check_expr_with(fcx, e, ty::mk_str(tcx)); } + some(e) { check_expr_with(fcx, e, ty::mk_str(fcx.vb)); } } - write_bot(tcx, id); + write_bot(fcx, id); } - ast::expr_break { write_bot(tcx, id); bot = true; } - ast::expr_cont { write_bot(tcx, id); bot = true; } + ast::expr_break { write_bot(fcx, id); bot = true; } + ast::expr_cont { write_bot(fcx, id); bot = true; } ast::expr_ret(expr_opt) { bot = true; alt expr_opt { none { - let nil = ty::mk_nil(tcx); + let nil = ty::mk_nil(fcx.vb); if !are_compatible(fcx, fcx.ret_ty, nil) { tcx.sess.span_err(expr.span, "ret; in function returning non-nil"); @@ -2456,23 +2613,23 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, } some(e) { check_expr_with(fcx, e, fcx.ret_ty); } } - write_bot(tcx, id); + write_bot(fcx, id); } ast::expr_be(e) { // FIXME: prove instead of assert assert (ast_util::is_call_expr(e)); check_expr_with(fcx, e, fcx.ret_ty); bot = true; - write_nil(tcx, id); + write_nil(fcx, id); } ast::expr_log(_, lv, e) { - bot = check_expr_with(fcx, lv, ty::mk_mach_uint(tcx, ast::ty_u32)); + bot = check_expr_with(fcx, lv, ty::mk_mach_uint(fcx.vb, ast::ty_u32)); bot |= check_expr(fcx, e); - write_nil(tcx, id); + write_nil(fcx, id); } ast::expr_check(_, e) { bot = check_pred_expr(fcx, e); - write_nil(tcx, id); + write_nil(fcx, id); } ast::expr_if_check(cond, thn, elsopt) { bot = @@ -2480,12 +2637,12 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, check_then_else(fcx, thn, elsopt, id, expr.span); } ast::expr_assert(e) { - bot = check_expr_with(fcx, e, ty::mk_bool(tcx)); - write_nil(tcx, id); + bot = check_expr_with(fcx, e, ty::mk_bool(fcx.vb)); + write_nil(fcx, id); } ast::expr_copy(a) { - bot = check_expr_with_unifier(fcx, a, unify, expected); - write_ty(tcx, id, ty::node_id_to_type(tcx, a.id)); + bot = check_expr_with_unifier(fcx, a, unifier, expected); + write_ty(fcx, id, expr_ty(fcx, a)); } ast::expr_move(lhs, rhs) { require_impure(tcx.sess, fcx.purity, expr.span); @@ -2501,37 +2658,38 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, } ast::expr_if(cond, thn, elsopt) { bot = - check_expr_with(fcx, cond, ty::mk_bool(tcx)) | + check_expr_with(fcx, cond, ty::mk_bool(fcx.vb)) | check_then_else(fcx, thn, elsopt, id, expr.span); } ast::expr_for(decl, seq, body) { bot = check_expr(fcx, seq); - let elt_ty; - let ety = expr_ty(tcx, seq); - alt structure_of(fcx, expr.span, ety) { - ty::ty_vec(vec_elt_ty) { elt_ty = vec_elt_ty.ty; } - ty::ty_str { elt_ty = ty::mk_mach_uint(tcx, ast::ty_u8); } - _ { - tcx.sess.span_fatal(expr.span, - "mismatched types: expected vector or string " - + "but found `" + ty_to_str(tcx, ety) + "`"); - } - } + let ety = expr_ty(fcx, seq); + let elt_ty = structure_of(fcx, expr.span, ety) {|sty| + alt sty { + ty::ty_vec(vec_elt_ty) { vec_elt_ty.ty } + ty::ty_str { ty::mk_mach_uint(fcx.vb, ast::ty_u8) } + _ { + tcx.sess.span_fatal(expr.span, + "mismatched types: expected vector or string " + + "but found `" + ty_str(fcx, ety) + "`"); + } + } + }; bot |= check_for(fcx, decl, elt_ty, body, id); } ast::expr_while(cond, body) { - bot = check_expr_with(fcx, cond, ty::mk_bool(tcx)); + bot = check_expr_with(fcx, cond, ty::mk_bool(fcx.vb)); check_block_no_value(fcx, body); - write_ty(tcx, id, ty::mk_nil(tcx)); + write_ty(fcx, id, ty::mk_nil(fcx.vb)); } ast::expr_do_while(body, cond) { - bot = check_expr_with(fcx, cond, ty::mk_bool(tcx)) | + bot = check_expr_with(fcx, cond, ty::mk_bool(fcx.vb)) | check_block_no_value(fcx, body); - write_ty(tcx, id, block_ty(tcx, body)); + write_ty(fcx, id, node_ty(fcx, body.node.id)); } ast::expr_loop(body) { check_block_no_value(fcx, body); - write_ty(tcx, id, ty::mk_nil(tcx)); + write_ty(fcx, id, ty::mk_nil(fcx.vb)); bot = !may_break(body); } ast::expr_alt(discrim, arms, _) { @@ -2541,7 +2699,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, // Typecheck the patterns first, so that we get types for all the // bindings. - let pattern_ty = ty::expr_ty(tcx, discrim); + let pattern_ty = expr_ty(fcx, discrim); for arm: ast::arm in arms { let pcx = { fcx: fcx, @@ -2560,65 +2718,68 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, let arm_non_bot = false; for arm: ast::arm in arms { alt arm.guard { - some(e) { check_expr_with(fcx, e, ty::mk_bool(tcx)); } + some(e) { check_expr_with(fcx, e, ty::mk_bool(fcx.vb)); } none { } } if !check_block(fcx, arm.body) { arm_non_bot = true; } - let bty = block_ty(tcx, arm.body); - result_ty = demand::simple(fcx, arm.body.span, result_ty, bty); + let bty = node_ty(fcx, arm.body.node.id); + result_ty = demand::ty(fcx.vb, arm.body.span, demand::ek_mismatched_types, + result_ty, bty); } bot |= !arm_non_bot; - if !arm_non_bot { result_ty = ty::mk_bot(tcx); } - write_ty(tcx, id, result_ty); + if !arm_non_bot { result_ty = ty::mk_bot(fcx.vb); } + write_ty(fcx, id, result_ty); } ast::expr_fn(proto, decl, body, captures) { check_expr_fn_with_unifier(fcx, expr, proto, decl, body, - unify, expected); + unifier, expected); capture::check_capture_clause(tcx, expr.id, proto, *captures); } ast::expr_fn_block(decl, body) { // Take the prototype from the expected type, but default to block: - let proto = alt ty::get(expected).struct { - ty::ty_fn({proto, _}) { proto } + let proto = alt expected { + @ty::sty_i(ty::ty_fn({proto, _})) { proto } _ { ast::proto_box } }; #debug("checking expr_fn_block %s expected=%s", expr_to_str(expr), - ty_to_str(tcx, expected)); + ty_str(fcx, expected)); check_expr_fn_with_unifier(fcx, expr, proto, decl, body, - unify, expected); + unifier, expected); } ast::expr_block(b) { // If this is an unchecked block, turn off purity-checking bot = check_block(fcx, b); let typ = alt b.node.expr { - some(expr) { expr_ty(tcx, expr) } - none { ty::mk_nil(tcx) } + some(expr) { expr_ty(fcx, expr) } + none { ty::mk_nil(fcx.vb) } }; - write_ty(tcx, id, typ); + write_ty(fcx, id, typ); } ast::expr_bind(f, args) { // Call the generic checker. bot = check_expr(fcx, f); - bot |= check_call_or_bind(fcx, expr.span, expr.id, expr_ty(tcx, f), + bot |= check_call_or_bind(fcx, expr.span, expr.id, expr_ty(fcx, f), args); // Pull the argument and return types out. - let proto, arg_tys, rt, cf, constrs; - alt structure_of(fcx, expr.span, expr_ty(tcx, f)) { - // FIXME: - // probably need to munge the constrs to drop constraints - // for any bound args - ty::ty_fn(f) { - proto = f.proto; - arg_tys = f.inputs; - rt = f.output; - cf = f.ret_style; - constrs = f.constraints; - } - _ { fail "LHS of bind expr didn't have a function type?!"; } - } + let {proto, arg_tys, rt, cf, constrs} = + structure_of(fcx, expr.span, expr_ty(fcx, f)) {|sty| + alt sty { + // FIXME: + // probably need to munge the constrs to drop constraints + // for any bound args + ty::ty_fn(f) { + {proto: f.proto, + arg_tys: f.inputs, + rt: f.output, + cf: f.ret_style, + constrs: f.constraints} + } + _ { fail "LHS of bind expr didn't have a function type?!"; } + } + }; let proto = alt proto { ast::proto_bare | ast::proto_box | ast::proto_uniq { @@ -2644,31 +2805,31 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, i += 1u; } - let ft = ty::mk_fn(tcx, {proto: proto, - inputs: out_args, output: rt, - ret_style: cf, constraints: constrs}); - write_ty(tcx, id, ft); + let ft = ty::mk_fn(fcx.vb, {proto: proto, + inputs: out_args, output: rt, + ret_style: cf, constraints: constrs}); + write_ty(fcx, id, ft); } ast::expr_call(f, args, _) { bot = check_call_full(fcx, expr.span, expr.id, f, args); } ast::expr_cast(e, t) { bot = check_expr(fcx, e); - let t_1 = ast_ty_to_ty_crate(fcx.ccx, t); - let t_e = ty::expr_ty(tcx, e); + let t_1 = ast_ty_to_ty_i(fcx, t); + let t_e = expr_ty(fcx, e); - alt ty::get(t_1).struct { + alt t_1 { // This will be looked up later on - ty::ty_iface(_, _) {} + @ty::sty_i(ty::ty_iface(_, _)) {} _ { - if ty::type_is_nil(t_e) { + if type_is_nil(fcx, expr.span, t_e) { tcx.sess.span_err(expr.span, "cast from nil: " + - ty_to_str(tcx, t_e) + " as " + - ty_to_str(tcx, t_1)); - } else if ty::type_is_nil(t_1) { + ty_str(fcx, t_e) + " as " + + ty_str(fcx, t_1)); + } else if type_is_nil(fcx, expr.span, t_1) { tcx.sess.span_err(expr.span, "cast to nil: " + - ty_to_str(tcx, t_e) + " as " + - ty_to_str(tcx, t_1)); + ty_str(fcx, t_e) + " as " + + ty_str(fcx, t_1)); } let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1); @@ -2678,36 +2839,36 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, // FIXME there are more forms of cast to support, eventually. tcx.sess.span_err(expr.span, "non-scalar cast: " + - ty_to_str(tcx, t_e) + " as " + - ty_to_str(tcx, t_1)); + ty_str(fcx, t_e) + " as " + + ty_str(fcx, t_1)); } } } - write_ty(tcx, id, t_1); + write_ty(fcx, id, t_1); } ast::expr_vec(args, mutbl) { - let t: ty::t = next_ty_var(fcx); + let t = next_ty_var(fcx); for e: @ast::expr in args { bot |= check_expr_with(fcx, e, t); } - let typ = ty::mk_vec(tcx, {ty: t, mutbl: mutbl}); - write_ty(tcx, id, typ); + let typ = ty::mk_vec(fcx.vb, {ty: t, mutbl: mutbl}); + write_ty(fcx, id, typ); } ast::expr_tup(elts) { let elt_ts = []; vec::reserve(elt_ts, vec::len(elts)); for e in elts { check_expr(fcx, e); - let ety = expr_ty(tcx, e); + let ety = expr_ty(fcx, e); elt_ts += [ety]; } - let typ = ty::mk_tup(tcx, elt_ts); - write_ty(tcx, id, typ); + let typ = ty::mk_tup(fcx.vb, elt_ts); + write_ty(fcx, id, typ); } ast::expr_rec(fields, base) { alt base { none {/* no-op */ } some(b_0) { check_expr(fcx, b_0); } } - let fields_t: [spanned] = []; + let fields_t: [spanned] = []; for f: ast::field in fields { bot |= check_expr(fcx, f.node.expr); - let expr_t = expr_ty(tcx, f.node.expr); + let expr_t = expr_ty(fcx, f.node.expr); let expr_mt = {ty: expr_t, mutbl: f.node.mutbl}; // for the most precise error message, // should be f.node.expr.span, not f.span @@ -2717,27 +2878,30 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, } alt base { none { - fn get_node(f: spanned) -> field { f.node } - let typ = ty::mk_rec(tcx, vec::map(fields_t, get_node)); - write_ty(tcx, id, typ); + fn get_node(f: spanned) -> ty::field_i { f.node } + let typ = ty::mk_rec(fcx.vb, vec::map(fields_t, get_node)); + write_ty(fcx, id, typ); } some(bexpr) { bot |= check_expr(fcx, bexpr); - let bexpr_t = expr_ty(tcx, bexpr); - let base_fields: [field] = []; - alt structure_of(fcx, expr.span, bexpr_t) { - ty::ty_rec(flds) { base_fields = flds; } - _ { - tcx.sess.span_fatal(expr.span, - "record update has non-record base"); - } + let bexpr_t = expr_ty(fcx, bexpr); + let base_fields: [ty::field_i] = []; + structure_of(fcx, expr.span, bexpr_t) {|sty| + alt sty { + ty::ty_rec(flds) { base_fields = flds; } + _ { + tcx.sess.span_fatal(expr.span, + "record update has non-record base"); + } + } } - write_ty(tcx, id, bexpr_t); - for f: spanned in fields_t { + write_ty(fcx, id, bexpr_t); + for f in fields_t { let found = false; - for bf: ty::field in base_fields { + for bf in base_fields { if str::eq(f.node.ident, bf.ident) { - demand::simple(fcx, f.span, bf.mt.ty, f.node.mt.ty); + demand::ty(fcx.vb, f.span, demand::ek_mismatched_types, + bf.mt.ty, f.node.mt.ty); found = true; } } @@ -2752,99 +2916,98 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, } ast::expr_field(base, field, tys) { bot |= check_expr(fcx, base); - let expr_t = structurally_resolved_type(fcx, expr.span, - expr_ty(tcx, base)); + let expr_t = expr_ty(fcx, base); let base_t = do_autoderef(fcx, expr.span, expr_t); let handled = false, n_tys = vec::len(tys); - alt structure_of(fcx, expr.span, base_t) { - ty::ty_rec(fields) { - alt ty::field_idx(field, fields) { - some(ix) { - if n_tys > 0u { - tcx.sess.span_err(expr.span, - "can't provide type parameters \ - to a field access"); + structure_of(fcx, expr.span, base_t) {|sty| + alt sty { + ty::ty_rec(fields) { + alt ty::field_idx(field, fields) { + some(ix) { + if n_tys > 0u { + tcx.sess.span_err(expr.span, + "can't provide type parameters \ + to a field access"); + } + write_ty(fcx, id, fields[ix].mt.ty); + handled = true; + } + _ {} } - write_ty(tcx, id, fields[ix].mt.ty); + } + ty::ty_class(base_id, tps) { + // (1) verify that the class id actually has a field called + // field + let cls_items = lookup_class_item_tys(tcx, base_id); + let field_ty = lookup_field_ty(fcx, cls_items, field, + expr.span, tps); + // (2) look up what field's type is, and return it + // FIXME: actually instantiate any type params + write_ty(fcx, id, field_ty); handled = true; } _ {} } - } - ty::ty_class(base_id, _params) { - // (1) verify that the class id actually has a field called - // field - let cls_items = lookup_class_item_tys(tcx, base_id); - let field_ty = lookup_field_ty(fcx.ccx.tcx, cls_items, field, - expr.span); - // (2) look up what field's type is, and return it - // FIXME: actually instantiate any type params - write_ty(tcx, id, field_ty); - handled = true; - } - _ {} } if !handled { - let tps = vec::map(tys, {|ty| ast_ty_to_ty_crate(fcx.ccx, ty)}); + let tps = vec::map(tys, {|ty| ast_ty_to_ty_i(fcx, ty)}); alt lookup_method(fcx, expr, expr.id, field, expr_t, tps) { some(origin) { fcx.ccx.method_map.insert(id, origin); } none { - let t_err = resolve_type_vars_if_possible(fcx, expr_t); let msg = #fmt["attempted access of field %s on type %s, but \ - no field or method with that name was found", - field, ty_to_str(tcx, t_err)]; + no field or method implementation was found", + field, ty_str(fcx, expr_t)]; tcx.sess.span_err(expr.span, msg); // NB: Adding a bogus type to allow typechecking to continue - write_ty(tcx, id, next_ty_var(fcx)); + write_ty(fcx, id, next_ty_var(fcx)); } } } } ast::expr_index(base, idx) { bot |= check_expr(fcx, base); - let raw_base_t = expr_ty(tcx, base); + let raw_base_t = expr_ty(fcx, base); let base_t = do_autoderef(fcx, expr.span, raw_base_t); bot |= check_expr(fcx, idx); - let idx_t = expr_ty(tcx, idx); - alt structure_of(fcx, expr.span, base_t) { - ty::ty_vec(mt) { - require_integral(fcx, idx.span, idx_t); - write_ty(tcx, id, mt.ty); - } - ty::ty_str { - require_integral(fcx, idx.span, idx_t); - let typ = ty::mk_mach_uint(tcx, ast::ty_u8); - write_ty(tcx, id, typ); - } - _ { - let resolved = structurally_resolved_type(fcx, expr.span, - raw_base_t); - alt lookup_op_method(fcx, expr, resolved, "[]", - [some(idx)]) { - some(ret_ty) { write_ty(tcx, id, ret_ty); } + let idx_t = expr_ty(fcx, idx); + structure_of(fcx, expr.span, base_t) {|sty| + alt sty { + ty::ty_vec(mt) { + require_integral(fcx, idx.span, idx_t); + write_ty(fcx, id, mt.ty); + } + ty::ty_str { + require_integral(fcx, idx.span, idx_t); + let typ = ty::mk_mach_uint(fcx.vb, ast::ty_u8); + write_ty(fcx, id, typ); + } _ { - tcx.sess.span_fatal( - expr.span, "cannot index a value of type `" + - ty_to_str(tcx, base_t) + "`"); + alt lookup_op_method(fcx, expr, raw_base_t, "[]", [some(idx)]) { + some(ret_ty) { write_ty(fcx, id, ret_ty); } + _ { + tcx.sess.span_fatal( + expr.span, "cannot index a value of type `" + + ty_str(fcx, base_t) + "`"); + } + } } } - } } } } - if bot { write_ty(tcx, expr.id, ty::mk_bot(tcx)); } + if bot { write_ty(fcx, expr.id, ty::mk_bot(fcx.vb)); } - unify(fcx, expr.span, expected, expr_ty(tcx, expr)); + unifier(fcx, expr.span, expected, expr_ty(fcx, expr)); ret bot; } -fn require_integral(fcx: @fn_ctxt, sp: span, t: ty::t) { +fn require_integral(fcx: @fn_ctxt, sp: span, t: ty::t_i) { if !type_is_integral(fcx, sp, t) { fcx.ccx.tcx.sess.span_err(sp, "mismatched types: expected \ `integer` but found `" - + ty_to_str(fcx.ccx.tcx, t) + "`"); + + ty_str(fcx, t) + "`"); } } @@ -2854,14 +3017,12 @@ fn next_ty_var_id(fcx: @fn_ctxt) -> int { ret id; } -fn next_ty_var(fcx: @fn_ctxt) -> ty::t { - ret ty::mk_var(fcx.ccx.tcx, next_ty_var_id(fcx)); +fn next_ty_var(fcx: @fn_ctxt) -> ty::t_i { + ret ty::mk_var(next_ty_var_id(fcx)); } -fn bind_params(fcx: @fn_ctxt, tp: ty::t, count: uint) - -> {vars: [ty::t], ty: ty::t} { - let vars = vec::from_fn(count, {|_i| next_ty_var(fcx)}); - {vars: vars, ty: ty::substitute_type_params(fcx.ccx.tcx, vars, tp)} +fn next_ty_vars(fcx: @fn_ctxt, n: uint) -> [ty::t_i] { + vec::from_fn(n) {|_i| next_ty_var(fcx)} } fn get_self_info(ccx: @crate_ctxt) -> option { @@ -2870,15 +3031,15 @@ fn get_self_info(ccx: @crate_ctxt) -> option { fn check_decl_initializer(fcx: @fn_ctxt, nid: ast::node_id, init: ast::initializer) -> bool { - let lty = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, init.expr.span, nid)); + let lty = ty::mk_var(lookup_local(fcx, init.expr.span, nid)); ret check_expr_with(fcx, init.expr, lty); } fn check_decl_local(fcx: @fn_ctxt, local: @ast::local) -> bool { let bot = false; - let t = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(local.node.id)); - write_ty(fcx.ccx.tcx, local.node.id, t); + let t = ty::mk_var(fcx.locals.get(local.node.id)); + write_ty(fcx, local.node.id, t); alt local.node.init { some(init) { bot = check_decl_initializer(fcx, local.node.id, init); @@ -2915,23 +3076,24 @@ fn check_stmt(fcx: @fn_ctxt, stmt: @ast::stmt) -> bool { } ast::stmt_expr(expr, id) { node_id = id; - bot = check_expr_with(fcx, expr, ty::mk_nil(fcx.ccx.tcx)); + bot = check_expr_with(fcx, expr, ty::mk_nil(fcx.vb)); } ast::stmt_semi(expr, id) { node_id = id; bot = check_expr(fcx, expr); } } - write_nil(fcx.ccx.tcx, node_id); + write_nil(fcx, node_id); ret bot; } fn check_block_no_value(fcx: @fn_ctxt, blk: ast::blk) -> bool { let bot = check_block(fcx, blk); if !bot { - let blkty = ty::node_id_to_type(fcx.ccx.tcx, blk.node.id); - let nilty = ty::mk_nil(fcx.ccx.tcx); - demand::simple(fcx, blk.span, nilty, blkty); + let blkty = node_ty(fcx, blk.node.id); + let nilty = ty::mk_nil(fcx.vb); + demand::ty(fcx.vb, blk.span, demand::ek_mismatched_types, + nilty, blkty); } ret bot; } @@ -2959,18 +3121,18 @@ fn check_block(fcx0: @fn_ctxt, blk: ast::blk) -> bool { bot |= check_stmt(fcx, s); } alt blk.node.expr { - none { write_nil(fcx.ccx.tcx, blk.node.id); } + none { write_nil(fcx, blk.node.id); } some(e) { if bot && !warned { fcx.ccx.tcx.sess.span_warn(e.span, "unreachable expression"); } bot |= check_expr(fcx, e); - let ety = expr_ty(fcx.ccx.tcx, e); - write_ty(fcx.ccx.tcx, blk.node.id, ety); + let ety = expr_ty(fcx, e); + write_ty(fcx, blk.node.id, ety); } } if bot { - write_ty(fcx.ccx.tcx, blk.node.id, ty::mk_bot(fcx.ccx.tcx)); + write_ty(fcx, blk.node.id, ty::mk_bot(fcx.vb)); } ret bot; } @@ -2978,32 +3140,34 @@ fn check_block(fcx0: @fn_ctxt, blk: ast::blk) -> bool { fn check_const(ccx: @crate_ctxt, _sp: span, e: @ast::expr, id: ast::node_id) { // FIXME: this is kinda a kludge; we manufacture a fake function context // and statement context for checking the initializer expression. - let rty = node_id_to_type(ccx.tcx, id); + let rty = ty::node_id_to_type(ccx.tcx, id); let fcx: @fn_ctxt = - @{ret_ty: rty, + @{ret_ty: ty::ty_to_ty_i(ccx.tcx, rty), purity: ast::pure_fn, proto: ast::proto_box, - var_bindings: ty::unify::mk_var_bindings(), - locals: int_hash::(), + vb: ty::var_bindings(ccx.tcx), + locals: int_hash(), next_var_id: @mutable 0, ccx: ccx}; check_expr(fcx, e); - let cty = expr_ty(fcx.ccx.tcx, e); + writeback::resolve_type_vars_in_expr(fcx, e); + let declty = fcx.ccx.tcx.tcache.get(local_def(id)).ty; - demand::simple(fcx, e.span, declty, cty); + demand::ty(fcx.ccx.tcx, e.span, demand::ek_mismatched_types, + declty, ty::node_id_to_type(ccx.tcx, e.id)); } fn check_enum_variants(ccx: @crate_ctxt, sp: span, vs: [ast::variant], id: ast::node_id) { // FIXME: this is kinda a kludge; we manufacture a fake function context // and statement context for checking the initializer expression. - let rty = node_id_to_type(ccx.tcx, id); + let rty = ty::node_id_to_type(ccx.tcx, id); let fcx: @fn_ctxt = - @{ret_ty: rty, + @{ret_ty: ty::ty_to_ty_i(ccx.tcx, rty), purity: ast::pure_fn, proto: ast::proto_box, - var_bindings: ty::unify::mk_var_bindings(), - locals: int_hash::(), + vb: ty::var_bindings(ccx.tcx), + locals: int_hash(), next_var_id: @mutable 0, ccx: ccx}; let disr_vals: [int] = []; @@ -3012,9 +3176,12 @@ fn check_enum_variants(ccx: @crate_ctxt, sp: span, vs: [ast::variant], alt v.node.disr_expr { some(e) { check_expr(fcx, e); - let cty = expr_ty(ccx.tcx, e); - let declty = ty::mk_int(ccx.tcx); - demand::simple(fcx, e.span, declty, cty); + let cty = expr_ty(fcx, e); + let declty = ty::mk_int(fcx.vb); + demand::ty(fcx.vb, e.span, demand::ek_mismatched_types, + declty, cty); + writeback::resolve_type_vars_in_expr(fcx, e); + // FIXME: issue #1417 // Also, check_expr (from check_const pass) doesn't guarantee that // the expression in an form that eval_const_expr can handle, so @@ -3057,13 +3224,13 @@ fn check_enum_variants(ccx: @crate_ctxt, sp: span, vs: [ast::variant], // A generic function for checking the pred in a check // or if-check fn check_pred_expr(fcx: @fn_ctxt, e: @ast::expr) -> bool { - let bot = check_expr_with(fcx, e, ty::mk_bool(fcx.ccx.tcx)); + let bot = check_expr_with(fcx, e, ty::mk_bool(fcx.vb)); /* e must be a call expr where all arguments are either literals or slots */ alt e.node { ast::expr_call(operator, operands, _) { - if !ty::is_pred_ty(expr_ty(fcx.ccx.tcx, operator)) { + if !type_is_pred_ty(fcx, e.span, expr_ty(fcx, operator)) { fcx.ccx.tcx.sess.span_err (operator.span, "operator in constraint has non-boolean return type"); @@ -3162,11 +3329,24 @@ fn check_constraints(fcx: @fn_ctxt, cs: [@ast::constr], args: [ast::arg]) { } } +// check_bare_fn: wrapper around check_fn for non-closure fns +fn check_bare_fn(ccx: @crate_ctxt, + decl: ast::fn_decl, + body: ast::blk, + id: ast::node_id) { + let fty = ty::node_id_to_type(ccx.tcx, id); + let ret_ty = ty::ty_to_ty_i(ccx.tcx, ty::ty_fn_ret(fty)); + let arg_tys = vec::map(ty::ty_fn_args(fty)) {|a| ty::ty_to_ty_i(ccx.tcx, a.ty) }; + check_fn(ccx, ast::proto_bare, decl, body, id, ret_ty, arg_tys, none); +} + fn check_fn(ccx: @crate_ctxt, proto: ast::proto, decl: ast::fn_decl, body: ast::blk, id: ast::node_id, + ret_ty: ty::t_i, + arg_tys: [ty::t_i], old_fcx: option<@fn_ctxt>) { // If old_fcx is some(...), this is a block fn { |x| ... }. // In that case, the purity is inherited from the context. @@ -3175,12 +3355,12 @@ fn check_fn(ccx: @crate_ctxt, some(f) { assert decl.purity == ast::impure_fn; f.purity } }; - let gather_result = gather_locals(ccx, decl, body, id, old_fcx); + let gather_result = gather_locals(ccx, decl, body, id, arg_tys, old_fcx); let fcx: @fn_ctxt = - @{ret_ty: ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, id)), + @{ret_ty: ret_ty, purity: purity, proto: proto, - var_bindings: gather_result.var_bindings, + vb: gather_result.var_bindings, locals: gather_result.locals, next_var_id: gather_result.next_var_id, ccx: ccx}; @@ -3192,18 +3372,14 @@ fn check_fn(ccx: @crate_ctxt, // function result type, if there is a tail expr. alt body.node.expr { some(tail_expr) { - let tail_expr_ty = expr_ty(ccx.tcx, tail_expr); - demand::simple(fcx, tail_expr.span, fcx.ret_ty, tail_expr_ty); + let tail_expr_ty = expr_ty(fcx, tail_expr); + demand::ty(fcx.vb, tail_expr.span, demand::ek_mismatched_types, + fcx.ret_ty, tail_expr_ty); } none { } } - let args = ty::ty_fn_args(ty::node_id_to_type(ccx.tcx, id)); - let i = 0u; - for arg: ty::arg in args { - write_ty(ccx.tcx, decl.inputs[i].id, arg.ty); - i += 1u; - } + vec::iter2(decl.inputs, arg_tys) {|inp,aty| write_ty(fcx, inp.id, aty) }; // If we don't have any enclosing function scope, it is time to // force any remaining type vars to be resolved. @@ -3211,12 +3387,12 @@ fn check_fn(ccx: @crate_ctxt, // resolved when the enclosing scope finishes up. if option::is_none(old_fcx) { vtable::resolve_in_block(fcx, body); - writeback::resolve_type_vars_in_block(fcx, body); + writeback::resolve_type_vars_in_fn(fcx, decl, body); } } fn check_method(ccx: @crate_ctxt, method: @ast::method) { - check_fn(ccx, ast::proto_bare, method.decl, method.body, method.id, none); + check_bare_fn(ccx, method.decl, method.body, method.id); } fn class_types(ccx: @crate_ctxt, members: [@ast::class_item]) -> class_map { @@ -3224,10 +3400,10 @@ fn class_types(ccx: @crate_ctxt, members: [@ast::class_item]) -> class_map { for m in members { alt m.node.decl { ast::instance_var(_,t,_,id) { - rslt.insert(id, ast_ty_to_ty(ccx.tcx, m_collect, t)); + rslt.insert(id, ast_ty_to_ty(ccx, m_collect, t)); } ast::class_method(it) { - rslt.insert(it.id, ty_of_item(ccx.tcx, m_collect, it).ty); + rslt.insert(it.id, ty_of_item(ccx, m_collect, it).ty); } } } @@ -3248,13 +3424,13 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) { ast::item_const(_, e) { check_const(ccx, it.span, e, it.id); } ast::item_enum(vs, _) { check_enum_variants(ccx, it.span, vs, it.id); } ast::item_fn(decl, tps, body) { - check_fn(ccx, ast::proto_bare, decl, body, it.id, none); + check_bare_fn(ccx, decl, body, it.id); } ast::item_res(decl, tps, body, dtor_id, _) { - check_fn(ccx, ast::proto_bare, decl, body, dtor_id, none); + check_bare_fn(ccx, decl, body, dtor_id); } ast::item_impl(tps, _, ty, ms) { - let self_ty = ast_ty_to_ty(ccx.tcx, m_check, ty); + let self_ty = ast_ty_to_ty(ccx, m_check, ty); let self_region = ty::re_self({crate: ast::local_crate, node: it.id}); self_ty = instantiate_self_regions(ccx.tcx, self_region, self_ty); ccx.self_infos += [self_impl(self_ty)]; @@ -3266,9 +3442,11 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) { let members_info = class_types(ccx, members); let class_ccx = @{enclosing_class_id:cid, enclosing_class:members_info with *ccx}; + // typecheck the ctor - check_fn(class_ccx, ast::proto_bare, ctor.node.dec, - ctor.node.body, ctor.node.id, none); + check_bare_fn(class_ccx, ctor.node.dec, ctor.node.body, + ctor.node.id); + // typecheck the members for m in members { check_class_member(class_ccx, m.node.decl); } } @@ -3346,14 +3524,14 @@ mod vtable { } fn lookup_vtables(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span, - bounds: @[ty::param_bounds], tys: [ty::t], + bounds: @[ty::param_bounds], tys: [ty::t_i], allow_unsafe: bool) -> vtable_res { let tcx = fcx.ccx.tcx, result = [], i = 0u; for ty in tys { for bound in *bounds[i] { alt bound { ty::bound_iface(i_ty) { - let i_ty = ty::substitute_type_params(tcx, tys, i_ty); + let i_ty = ty::ty_to_ty_i_subst(tcx, i_ty, tys); result += [lookup_vtable(fcx, isc, sp, ty, i_ty, allow_unsafe)]; } @@ -3366,14 +3544,17 @@ mod vtable { } fn lookup_vtable(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span, - ty: ty::t, iface_ty: ty::t, allow_unsafe: bool) + ty: ty::t_i, iface_ty: ty::t_i, allow_unsafe: bool) -> vtable_origin { let tcx = fcx.ccx.tcx; - let (iface_id, iface_tps) = alt check ty::get(iface_ty).struct { - ty::ty_iface(did, tps) { (did, tps) } + let (iface_id, iface_tps) = structure_of(fcx, sp, iface_ty) {|sty| + alt check sty { + ty::ty_iface(did, tps) { (did, tps) } + } }; - let ty = fixup_ty(fcx, sp, ty); - alt ty::get(ty).struct { + + let tyf = fixup_ty(fcx, sp, ty); + alt ty::get(tyf).struct { ty::ty_param(n, did) { let n_bound = 0u; for bound in *tcx.ty_param_bounds.get(did.node) { @@ -3393,7 +3574,7 @@ mod vtable { ty::ty_iface(did, tps) if iface_id == did { if !allow_unsafe { for m in *ty::iface_methods(tcx, did) { - 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"); @@ -3407,81 +3588,76 @@ mod vtable { } ret vtable_iface(did, tps); } - _ { - let found = none; - std::list::iter(isc) {|impls| - if option::is_some(found) { ret; } - for im in *impls { - let match = alt ty::impl_iface(tcx, im.did) { - some(ity) { - alt check ty::get(ity).struct { - ty::ty_iface(id, _) { id == iface_id } + _ { /*fallthrough */ } + } + + let found = none; + std::list::iter(isc) {|impls| + if option::is_some(found) { ret; } + for im in *impls { + let match = alt ty::impl_iface(tcx, im.did) { + some(ity) { + alt check ty::get(ity).struct { + ty::ty_iface(id, _) { id == iface_id } + } + } + _ { false } + }; + if match { + let {vars, self_ty} = impl_self_ty(fcx, im.did); + let im_bs = ty::lookup_item_type(tcx, im.did).bounds; + alt ty::unify::unify(fcx.vb, ty, self_ty) { + result::ok(_) { + if option::is_some(found) { + tcx.sess.span_err( + sp, "multiple applicable implementations \ + in scope"); + } else { + connect_iface_tps(fcx, sp, vars, iface_tps, im.did); + let subres = lookup_vtables(fcx, isc, sp, im_bs, vars, + allow_unsafe); + let params = vec::map(vars) {|v| fixup_ty(fcx, sp, v) }; + found = some(vtable_static(im.did, params, subres)); } } - _ { false } - }; - if match { - let {n_tps, ty: self_ty} = impl_self_ty(tcx, im.did); - let {vars, ty: self_ty} = if n_tps > 0u { - bind_params(fcx, self_ty, n_tps) - } else { {vars: [], ty: self_ty} }; - let im_bs = ty::lookup_item_type(tcx, im.did).bounds; - alt unify::unify(fcx, ty, self_ty) { - result::ok(_) { - if option::is_some(found) { - tcx.sess.span_err( - sp, "multiple applicable implementations \ - in scope"); - } else { - connect_iface_tps(fcx, sp, vars, iface_tps, - im.did); - let params = vec::map(vars, {|t| - fixup_ty(fcx, sp, t)}); - let subres = lookup_vtables( - fcx, isc, sp, im_bs, params, false); - found = some(vtable_static(im.did, params, - subres)); - } - } - result::err(_) {} - } + result::err(_) {} } } } - alt found { - some(rslt) { ret rslt; } - _ {} - } - } + } + alt found { + some(rslt) { ret rslt; } + _ {} } tcx.sess.span_fatal( sp, "failed to find an implementation of interface " + - ty_to_str(tcx, iface_ty) + " for " + - ty_to_str(tcx, ty)); + ty_str(fcx, iface_ty) + " for " + + ty_str(fcx, ty)); } - fn fixup_ty(fcx: @fn_ctxt, sp: span, ty: ty::t) -> ty::t { + fn fixup_ty(fcx: @fn_ctxt, sp: span, ty: ty::t_i) -> ty::t { let tcx = fcx.ccx.tcx; - alt ty::unify::fixup_vars(tcx, some(sp), fcx.var_bindings, ty) { + alt ty::unify::resolve_type(fcx.vb, ty) { result::ok(new_type) { new_type } - result::err(vid) { - tcx.sess.span_fatal(sp, "could not determine a type for a \ - bounded type parameter"); + result::err(rerr) { + tcx.sess.span_fatal(sp, ty::resolve_err_to_str(rerr)); } } } - fn connect_iface_tps(fcx: @fn_ctxt, sp: span, impl_tys: [ty::t], - iface_tys: [ty::t], impl_did: ast::def_id) { + fn connect_iface_tps(fcx: @fn_ctxt, sp: span, impl_tys: [ty::t_i], + iface_tys: [ty::t_i], impl_did: ast::def_id) { let tcx = fcx.ccx.tcx; let ity = option::get(ty::impl_iface(tcx, impl_did)); - let iface_ty = ty::substitute_type_params(tcx, impl_tys, ity); - alt check ty::get(iface_ty).struct { - ty::ty_iface(_, tps) { - vec::iter2(tps, iface_tys, - {|a, b| demand::simple(fcx, sp, a, b);}); - } + let iface_ty = ty::ty_to_ty_i_subst(tcx, ity, impl_tys); + structure_of(fcx, sp, iface_ty) {|sty| + alt check sty { + ty::ty_iface(_, tps) { + demand::tys(fcx.vb, sp, demand::ek_mismatched_types, + tps, iface_tys); + } + } } } @@ -3489,7 +3665,7 @@ mod vtable { let cx = fcx.ccx; alt ex.node { ast::expr_path(_) { - alt cx.tcx.node_type_substs.find(ex.id) { + alt node_ty_substs_find(fcx, ex.id) { some(ts) { let did = ast_util::def_id_of_def(cx.tcx.def_map.get(ex.id)); let item_ty = ty::lookup_item_type(cx.tcx, did); @@ -3514,7 +3690,7 @@ mod vtable { ast::expr_field(_, _, _) { ex.id } _ { ast_util::op_expr_callee_id(ex) } }; - let ts = ty::node_id_to_type_params(cx.tcx, callee_id); + let ts = node_ty_substs(fcx, callee_id); let iscs = cx.impl_map.get(ex.id); cx.vtable_map.insert(callee_id, lookup_vtables( fcx, iscs, ex.span, bounds, ts, false)); @@ -3524,16 +3700,18 @@ mod vtable { } } ast::expr_cast(src, _) { - let target_ty = expr_ty(cx.tcx, ex); - alt ty::get(target_ty).struct { - ty::ty_iface(_, _) { - let impls = cx.impl_map.get(ex.id); - let vtable = lookup_vtable(fcx, impls, ex.span, - expr_ty(cx.tcx, src), target_ty, - true); - cx.vtable_map.insert(ex.id, @[vtable]); - } - _ {} + let target_ty = expr_ty(fcx, ex); + structure_of(fcx, ex.span, target_ty) {|sty| + alt sty { + ty::ty_iface(_, _) { + let impls = cx.impl_map.get(ex.id); + let vtable = lookup_vtable(fcx, impls, ex.span, + expr_ty(fcx, src), target_ty, + true); + cx.vtable_map.insert(ex.id, @[vtable]); + } + _ {} + } } } ast::expr_fn(p, _, _, _) if ast::is_blockish(p) {} @@ -3557,15 +3735,16 @@ mod vtable { fn check_crate(tcx: ty::ctxt, impl_map: resolve::impl_map, crate: @ast::crate) -> (method_map, vtable_map) { - collect::collect_item_types(tcx, crate); - let ccx = @{mutable self_infos: [], impl_map: impl_map, method_map: std::map::int_hash(), vtable_map: std::map::int_hash(), enclosing_class_id: none, enclosing_class: std::map::int_hash(), + ast_ty_to_ty_cache: map::hashmap( + ast_util::hash_ty, ast_util::eq_ty), tcx: tcx}; + collect::collect_item_types(ccx, crate); let visit = visit::mk_simple_visitor(@{ visit_item: bind check_item(ccx, _) with *visit::default_simple_visitor() diff --git a/src/rustc/syntax/parse/parser.rs b/src/rustc/syntax/parse/parser.rs index 06d59be06545b..7f2cbdd3e2f94 100644 --- a/src/rustc/syntax/parse/parser.rs +++ b/src/rustc/syntax/parse/parser.rs @@ -1628,10 +1628,15 @@ fn parse_local(p: parser, is_mutbl: bool, allow_init: bool) -> @ast::local { let lo = p.span.lo; let pat = parse_pat(p); - let ty = @{id: p.get_id(), - node: ast::ty_infer, - span: ast_util::mk_sp(lo, lo)}; - if eat(p, token::COLON) { ty = parse_ty(p, false); } + let ty = { + if eat(p, token::COLON) { + parse_ty(p, false) + } else { + @{id: p.get_id(), + node: ast::ty_infer, + span: ast_util::mk_sp(lo, lo)} + } + }; let init = if allow_init { parse_initializer(p) } else { none }; ret @spanned(lo, p.last_span.hi, {is_mutbl: is_mutbl, ty: ty, pat: pat, @@ -1895,19 +1900,23 @@ fn parse_fn_decl(p: parser, purity: ast::purity) } fn parse_fn_block_decl(p: parser) -> ast::fn_decl { - let inputs = if eat(p, token::OROR) { - [] - } else { - parse_seq(token::BINOP(token::OR), - token::BINOP(token::OR), - seq_sep(token::COMMA), - parse_fn_block_arg, p).node - }; - let output = if eat(p, token::RARROW) { - parse_ty(p, false) - } else { - @{id: p.get_id(), node: ast::ty_infer, span: p.span} - }; + let inputs = { + if eat(p, token::OROR) { + [] + } else { + parse_seq(token::BINOP(token::OR), + token::BINOP(token::OR), + seq_sep(token::COMMA), + parse_fn_block_arg, p).node + } + }; + let output = { + if eat(p, token::RARROW) { + parse_ty(p, false) + } else { + @{id: p.get_id(), node: ast::ty_infer, span: p.span} + } + }; ret {inputs: inputs, output: output, purity: ast::impure_fn, diff --git a/src/rustc/syntax/visit.rs b/src/rustc/syntax/visit.rs index 5f92d533f3238..1ccbb5a25b2d9 100644 --- a/src/rustc/syntax/visit.rs +++ b/src/rustc/syntax/visit.rs @@ -127,7 +127,7 @@ fn visit_item(i: @item, e: E, v: vt) { } item_impl(tps, ifce, ty, methods) { v.visit_ty_params(tps, e, v); - alt ifce { some(ty) { v.visit_ty(ty, e, v); } _ {} } + alt ifce { some(ty) { v.visit_ty(ty, e, v); } none {} } v.visit_ty(ty, e, v); for m in methods { visit_method_helper(m, e, v) @@ -190,7 +190,8 @@ fn visit_ty(t: @ty, e: E, v: vt) { v.visit_constr(tc.node.path, tc.span, tc.node.id, e, v); } } - _ {} + ty_mac(m) { visit_mac(m, e, v); } + ty_nil | ty_bot | ty_infer { /* fallthrough */ } } } @@ -240,7 +241,7 @@ fn visit_ty_params(tps: [ty_param], e: E, v: vt) { for bound in *tp.bounds { alt bound { bound_iface(t) { v.visit_ty(t, e, v); } - _ {} + bound_copy | bound_send { /* fallthrough */ } } } } diff --git a/src/rustc/util/ppaux.rs b/src/rustc/util/ppaux.rs index 8e2e71aeeb383..735c03d09ab8e 100644 --- a/src/rustc/util/ppaux.rs +++ b/src/rustc/util/ppaux.rs @@ -40,84 +40,87 @@ fn region_to_str(cx: ctxt, region: region) -> str { } } -fn ty_to_str(cx: ctxt, typ: t) -> str { - fn fn_input_to_str(cx: ctxt, input: {mode: ast::mode, ty: t}) -> - str { - let {mode, ty} = input; - let modestr = alt canon_mode(cx, mode) { +iface pp_ctxt { + fn tcx() -> ty::ctxt; + fn is_nil(T) -> bool; + fn t_to_str(t: T) -> str; +} + +fn sty_base_to_str>( + cx: C, + typ: sty_base) -> str { + + fn fn_input_to_str>( + cx: C, + input: {mode: ast::mode, ty: T}) -> str { + + let modestr = alt canon_mode(cx.tcx(), input.mode) { ast::infer(_) { "" } - ast::expl(m) { - if !ty::type_has_vars(ty) && - m == ty::default_arg_mode_for_ty(ty) { - "" - } else { - mode_to_str(ast::expl(m)) - } - } + ast::expl(m) { mode_to_str(ast::expl(m)) } }; - modestr + ty_to_str(cx, ty) - } - fn fn_to_str(cx: ctxt, proto: ast::proto, ident: option, - inputs: [arg], output: t, cf: ast::ret_style, - constrs: [@constr]) -> str { + modestr + cx.t_to_str(input.ty) + }; + + fn fn_to_str>( + cx: C, + proto: ast::proto, + ident: option, + inputs: [arg_base], + output: T, + cf: ast::ret_style, + constrs: [@constr]) -> str { + let s = proto_to_str(proto); alt ident { some(i) { s += " "; s += i; } _ { } } s += "("; let strs = []; - for a: arg in inputs { strs += [fn_input_to_str(cx, a)]; } + for a in inputs { strs += [fn_input_to_str(cx, a)]; } s += str::connect(strs, ", "); s += ")"; - if ty::get(output).struct != ty_nil { + if !cx.is_nil(output) { s += " -> "; alt cf { ast::noreturn { s += "!"; } - ast::return_val { s += ty_to_str(cx, output); } + ast::return_val { s += cx.t_to_str(output); } } } s += constrs_str(constrs); ret s; - } - fn method_to_str(cx: ctxt, m: method) -> str { - ret fn_to_str(cx, m.fty.proto, some(m.ident), m.fty.inputs, - m.fty.output, m.fty.ret_style, m.fty.constraints) + ";"; - } - fn field_to_str(cx: ctxt, f: field) -> str { - ret f.ident + ": " + mt_to_str(cx, f.mt); - } - fn mt_to_str(cx: ctxt, m: mt) -> str { + }; + + fn mt_to_str>( + cx: C, + m: mt_base) -> str { + let mstr = alt m.mutbl { ast::m_mutbl { "mut " } ast::m_imm { "" } ast::m_const { "const " } }; - ret mstr + ty_to_str(cx, m.ty); - } - fn parameterized(cx: ctxt, base: str, tps: [ty::t]) -> str { + ret mstr + cx.t_to_str(m.ty); + }; + + fn field_to_str>( + cx: C, + f: field_base) -> str { + + ret f.ident + ": " + mt_to_str(cx, f.mt); + }; + + fn parameterized>( + cx: C, + base: str, + tps: [T]) -> str { + if vec::len(tps) > 0u { - let strs = vec::map(tps, {|t| ty_to_str(cx, t)}); + let strs = vec::map(tps, cx.t_to_str); #fmt["%s<%s>", base, str::connect(strs, ",")] } else { base } - } + }; - // if there is an id, print that instead of the structural type: - alt ty::type_def_id(typ) { - some(def_id) { - let cs = ast_map::path_to_str(ty::item_path(cx, def_id)); - ret alt ty::get(typ).struct { - ty_enum(_, tps) | ty_res(_, _, tps) | ty_iface(_, tps) | - ty_class(_, tps) { - parameterized(cx, cs, tps) - } - _ { cs } - }; - } - none { /* fallthrough */} - } - - // pretty print the structural type representation: - ret alt ty::get(typ).struct { + ret alt typ { ty_nil { "()" } ty_bot { "_|_" } ty_bool { "bool" } @@ -133,37 +136,97 @@ fn ty_to_str(cx: ctxt, typ: t) -> str { ty_box(tm) { "@" + mt_to_str(cx, tm) } ty_uniq(tm) { "~" + mt_to_str(cx, tm) } ty_ptr(tm) { "*" + mt_to_str(cx, tm) } - ty_rptr(r, tm) { "&" + region_to_str(cx, r) + "." + mt_to_str(cx, tm) } + ty_rptr(r, tm) { "&" + region_to_str(cx.tcx(), r) + "." + mt_to_str(cx, tm) } ty_vec(tm) { "[" + mt_to_str(cx, tm) + "]" } ty_type { "type" } - ty_rec(elems) { - let strs: [str] = []; - for fld: field in elems { strs += [field_to_str(cx, fld)]; } + ty_rec(flds) { + let strs = vec::map(flds) {|f| field_to_str(cx, f) }; "{" + str::connect(strs, ",") + "}" } ty_tup(elems) { - let strs = []; - for elem in elems { strs += [ty_to_str(cx, elem)]; } + let strs = vec::map(elems, cx.t_to_str); "(" + str::connect(strs, ",") + ")" } ty_fn(f) { - fn_to_str(cx, f.proto, none, f.inputs, f.output, f.ret_style, - f.constraints) + fn_to_str(cx, f.proto, none, f.inputs, f.output, f.ret_style, f.constraints) } - ty_var(v) { "" } ty_param(id, _) { "'" + str::from_bytes([('a' as u8) + (id as u8)]) } ty_enum(did, tps) | ty_res(did, _, tps) | ty_iface(did, tps) | ty_class(did, tps) { - let path = ty::item_path(cx, did); + let path = ty::item_path(cx.tcx(), did); let base = ast_map::path_to_str(path); parameterized(cx, base, tps) } - _ { ty_to_short_str(cx, typ) } + ty_constr(t, ts) { #fmt["%s:...", cx.t_to_str(t)] } + ty_opaque_box { "@?" } + ty_opaque_closure_ptr(ty::ck_block) { "fn&(...)" } + ty_opaque_closure_ptr(ty::ck_box) { "fn@(...)" } + ty_opaque_closure_ptr(ty::ck_uniq) { "fn~(...)" } + } +} + +type ti_pp_ctxt = { + vb: @var_bindings, + mut visited: [int] +}; + +impl of pp_ctxt for ti_pp_ctxt { + fn tcx() -> ctxt { + self.vb.tcx + } + + fn is_nil(&&t: ty::t_i) -> bool { + alt t { + @ty::sty_i(ty_nil) { true } + _ { false } + } + } + + fn t_to_str(&&t: ty::t_i) -> str { + alt t { + @ty::ty_var_i(vid) if vec::contains(self.visited, vid) { + #fmt["", vid] + } + @ty::ty_var_i(vid) { + unify::get_var_binding( + self.vb, vid, + {|vid| #fmt["", vid] }, //...if unbound + {|sty| // ...if bound + self.visited += [vid]; + sty_base_to_str(self, sty) + }) + } + @ty::sty_i(sty) { + sty_base_to_str(self, sty) + } + } } } +fn ty_i_to_str(vb: @var_bindings, + ti: t_i) -> str { + let cx: ti_pp_ctxt = {vb: vb, mut visited: []}; + cx.t_to_str(ti) +} + +impl of pp_ctxt for ctxt { + fn tcx() -> ctxt { self } + + fn is_nil(&&t: t) -> bool { + type_is_nil(t) + } + + fn t_to_str(&&t: t) -> str { + sty_base_to_str(self, ty::get(t).struct) + } +} + +fn ty_to_str(cx: ctxt, typ: t) -> str { + ret cx.t_to_str(typ); +} + fn ty_to_short_str(cx: ctxt, typ: t) -> str { let s = encoder::encoded_ty(cx, typ); if str::len(s) >= 32u { s = str::slice(s, 0u, 32u); }