1 import syntax::{ast, ast_util};
3 import syntax::ast_util::{local_def, respan};
5 import metadata::csearch;
6 import driver::session::session;
7 import util::common::*;
8 import syntax::codemap::span;
11 import middle::ty::{node_id_to_type, arg, block_ty,
12 expr_ty, field, node_type_table, mk_nil,
13 ty_param_substs_opt_and_ty, ty_param_bounds_and_ty};
14 import util::ppaux::ty_to_str;
15 import middle::ty::unify::{ures_ok, ures_err, fix_ok, fix_err};
16 import core::{int, vec, str, option};
17 import std::smallintmap;
18 import std::map::{hashmap, new_int_hash};
19 import option::{none, some};
20 import syntax::print::pprust::*;
23 export method_map, method_origin, method_static, method_param, method_iface;
24 export dict_map, dict_res, dict_origin, dict_static, dict_param, dict_iface;
27 method_static(ast::def_id),
28 // iface id, method num, param num, bound num
29 method_param(ast::def_id, uint, uint, uint),
32 type method_map = hashmap<ast::node_id, method_origin>;
34 // Resolutions for bounds of all parameters, left to right, for a given path.
35 type dict_res = @[dict_origin];
37 dict_static(ast::def_id, [ty::t], dict_res),
38 // Param number, bound number
39 dict_param(uint, uint),
40 dict_iface(ast::def_id),
42 type dict_map = hashmap<ast::node_id, dict_res>;
44 type ty_table = hashmap<ast::def_id, ty::t>;
46 // Used for typechecking the methods of an impl
51 type crate_ctxt = {mutable self_infos: [self_info],
52 impl_map: resolve::impl_map,
53 method_map: method_map,
58 // var_bindings, locals and next_var_id are shared
59 // with any nested functions that capture the environment
60 // (and with any functions whose environment is being captured).
64 var_bindings: @ty::unify::var_bindings,
65 locals: hashmap<ast::node_id, int>,
66 next_var_id: @mutable int,
67 mutable fixups: [ast::node_id],
71 fn lookup_local(fcx: @fn_ctxt, sp: span, id: ast::node_id) -> int {
72 alt fcx.locals.find(id) {
75 fcx.ccx.tcx.sess.span_fatal(sp,
76 "internal error looking up a local var")
81 fn lookup_def(fcx: @fn_ctxt, sp: span, id: ast::node_id) -> ast::def {
82 alt fcx.ccx.tcx.def_map.find(id) {
85 fcx.ccx.tcx.sess.span_fatal(sp,
86 "internal error looking up a definition")
91 // Returns the type parameter count and the type for the given definition.
92 fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
93 ty_param_bounds_and_ty {
96 assert (fcx.locals.contains_key(id.node));
97 let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id.node));
98 ret {bounds: @[], ty: typ};
100 ast::def_local(id, _) {
101 assert (fcx.locals.contains_key(id.node));
102 let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id.node));
103 ret {bounds: @[], ty: typ};
106 alt get_self_info(fcx.ccx) {
107 some(self_impl(impl_t)) {
108 ret {bounds: @[], ty: impl_t};
112 ast::def_fn(id, _) | ast::def_const(id) |
113 ast::def_variant(_, id) { ret ty::lookup_item_type(fcx.ccx.tcx, id); }
114 ast::def_binding(id) {
115 assert (fcx.locals.contains_key(id.node));
116 let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id.node));
117 ret {bounds: @[], ty: typ};
120 // Hopefully part of a path.
121 // TODO: return a type that's more poisonous, perhaps?
122 ret {bounds: @[], ty: ty::mk_nil(fcx.ccx.tcx)};
125 fcx.ccx.tcx.sess.span_fatal(sp, "expected value but found type");
127 ast::def_upvar(_, inner, _) {
128 ret ty_param_bounds_and_ty_for_def(fcx, sp, *inner);
131 // FIXME: handle other names.
132 fcx.ccx.tcx.sess.unimpl("definition variant");
137 // Instantiates the given path, which must refer to an item with the given
138 // number of type parameters and type.
139 fn instantiate_path(fcx: @fn_ctxt, pth: @ast::path,
140 tpt: ty_param_bounds_and_ty, sp: span)
141 -> ty_param_substs_opt_and_ty {
142 let ty_param_count = vec::len(*tpt.bounds);
143 let vars = vec::init_fn(ty_param_count, {|_i| next_ty_var(fcx)});
144 let ty_substs_len = vec::len(pth.node.types);
145 if ty_substs_len > 0u {
146 let param_var_len = vec::len(vars);
147 if param_var_len == 0u {
148 fcx.ccx.tcx.sess.span_fatal
149 (sp, "this item does not take type parameters");
150 } else if ty_substs_len > param_var_len {
151 fcx.ccx.tcx.sess.span_fatal
152 (sp, "too many type parameter provided for this item");
153 } else if ty_substs_len < param_var_len {
154 fcx.ccx.tcx.sess.span_fatal
155 (sp, "not enough type parameters provided for this item");
157 vec::iter2(pth.node.types, vars) {|sub, var|
158 let ty_subst = ast_ty_to_ty_crate(fcx.ccx, sub);
159 demand::simple(fcx, pth.span, var, ty_subst);
161 if ty_param_count == 0u {
162 fcx.ccx.tcx.sess.span_fatal(
163 sp, "this item does not take type parameters");
166 {substs: some(vars), ty: tpt.ty}
170 fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t {
171 alt ty::unify::resolve_type_structure(fcx.ccx.tcx, fcx.var_bindings, tp) {
172 fix_ok(typ_s) { ret typ_s; }
174 fcx.ccx.tcx.sess.span_fatal
175 (sp, "the type of this value must be known in this context");
181 // Returns the one-level-deep structure of the given type.f
182 fn structure_of(fcx: @fn_ctxt, sp: span, typ: ty::t) -> ty::sty {
183 ret ty::struct(fcx.ccx.tcx, structurally_resolved_type(fcx, sp, typ));
186 // Returns the one-level-deep structure of the given type or none if it
188 fn structure_of_maybe(fcx: @fn_ctxt, _sp: span, typ: ty::t) ->
191 ty::unify::resolve_type_structure(fcx.ccx.tcx, fcx.var_bindings, typ);
193 fix_ok(typ_s) { some(ty::struct(fcx.ccx.tcx, typ_s)) }
198 fn type_is_integral(fcx: @fn_ctxt, sp: span, typ: ty::t) -> bool {
199 let typ_s = structurally_resolved_type(fcx, sp, typ);
200 ret ty::type_is_integral(fcx.ccx.tcx, typ_s);
203 fn type_is_scalar(fcx: @fn_ctxt, sp: span, typ: ty::t) -> bool {
204 let typ_s = structurally_resolved_type(fcx, sp, typ);
205 ret ty::type_is_scalar(fcx.ccx.tcx, typ_s);
208 fn type_is_c_like_enum(fcx: @fn_ctxt, sp: span, typ: ty::t) -> bool {
209 let typ_s = structurally_resolved_type(fcx, sp, typ);
210 ret ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s);
213 // Parses the programmer's textual representation of a type into our internal
214 // notion of a type. `getter` is a function that returns the type
215 // corresponding to a definition ID:
216 fn default_arg_mode_for_ty(tcx: ty::ctxt, m: ast::mode,
217 ty: ty::t) -> ast::mode {
220 alt ty::struct(tcx, ty) {
221 ty::ty_var(_) { ast::mode_infer }
223 if ty::type_is_immediate(tcx, ty) { ast::by_val }
232 enum mode { m_collect, m_check, m_check_tyvar(@fn_ctxt), }
234 fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
235 fn getter(tcx: ty::ctxt, mode: mode, id: ast::def_id)
236 -> ty::ty_param_bounds_and_ty {
238 m_check | m_check_tyvar(_) { ty::lookup_item_type(tcx, id) }
240 if id.crate != ast::local_crate { csearch::get_type(tcx, id) }
242 alt tcx.items.find(id.node) {
243 some(ast_map::node_item(item)) {
244 ty_of_item(tcx, mode, item)
246 some(ast_map::node_native_item(native_item)) {
247 ty_of_native_item(tcx, mode, native_item)
254 fn ast_arg_to_arg(tcx: ty::ctxt, mode: mode, arg: ast::arg)
255 -> {mode: ty::mode, ty: ty::t} {
256 let ty = ast_ty_to_ty(tcx, mode, arg.ty);
257 ret {mode: default_arg_mode_for_ty(tcx, arg.mode, ty), ty: ty};
259 alt tcx.ast_ty_to_ty_cache.find(ast_ty) {
260 some(some(ty)) { ret ty; }
262 tcx.sess.span_fatal(ast_ty.span, "illegal recursive type. \
263 insert a enum in the cycle, \
264 if this is desired)");
269 tcx.ast_ty_to_ty_cache.insert(ast_ty, none::<ty::t>);
270 fn ast_mt_to_mt(tcx: ty::ctxt, mode: mode, mt: ast::mt) -> ty::mt {
271 ret {ty: ast_ty_to_ty(tcx, mode, mt.ty), mut: mt.mut};
273 fn instantiate(tcx: ty::ctxt, sp: span, mode: mode,
274 id: ast::def_id, args: [@ast::ty]) -> ty::t {
275 // TODO: maybe record cname chains so we can do
276 // "foo = int" like OCaml?
278 let ty_param_bounds_and_ty = getter(tcx, mode, id);
279 if vec::len(*ty_param_bounds_and_ty.bounds) == 0u {
280 ret ty_param_bounds_and_ty.ty;
283 // The typedef is type-parametric. Do the type substitution.
284 let param_bindings: [ty::t] = [];
285 if vec::len(args) != vec::len(*ty_param_bounds_and_ty.bounds) {
286 tcx.sess.span_fatal(sp, "Wrong number of type arguments for a \
289 for ast_ty: @ast::ty in args {
290 param_bindings += [ast_ty_to_ty(tcx, mode, ast_ty)];
293 ty::substitute_type_params(tcx, param_bindings,
294 ty_param_bounds_and_ty.ty);
299 ast::ty_nil { typ = ty::mk_nil(tcx); }
300 ast::ty_bot { typ = ty::mk_bot(tcx); }
301 ast::ty_bool { typ = ty::mk_bool(tcx); }
302 ast::ty_int(it) { typ = ty::mk_mach_int(tcx, it); }
303 ast::ty_uint(uit) { typ = ty::mk_mach_uint(tcx, uit); }
304 ast::ty_float(ft) { typ = ty::mk_mach_float(tcx, ft); }
305 ast::ty_str { typ = ty::mk_str(tcx); }
307 typ = ty::mk_box(tcx, ast_mt_to_mt(tcx, mode, mt));
310 typ = ty::mk_uniq(tcx, ast_mt_to_mt(tcx, mode, mt));
313 typ = ty::mk_vec(tcx, ast_mt_to_mt(tcx, mode, mt));
316 typ = ty::mk_ptr(tcx, ast_mt_to_mt(tcx, mode, mt));
318 ast::ty_tup(fields) {
319 let flds = vec::map(fields, bind ast_ty_to_ty(tcx, mode, _));
320 typ = ty::mk_tup(tcx, flds);
322 ast::ty_rec(fields) {
323 let flds: [field] = [];
324 for f: ast::ty_field in fields {
325 let tm = ast_mt_to_mt(tcx, mode, f.node.mt);
326 flds += [{ident: f.node.ident, mt: tm}];
328 typ = ty::mk_rec(tcx, flds);
330 ast::ty_fn(proto, decl) {
331 typ = ty::mk_fn(tcx, ty_of_fn_decl(tcx, mode, proto, decl));
333 ast::ty_path(path, id) {
334 alt tcx.def_map.find(id) {
335 some(ast::def_ty(id)) {
336 typ = instantiate(tcx, ast_ty.span, mode, id, path.node.types);
338 some(ast::def_native_ty(id)) { typ = getter(tcx, mode, id).ty; }
339 some(ast::def_ty_param(id, n)) {
340 typ = ty::mk_param(tcx, n, id);
343 tcx.sess.span_fatal(ast_ty.span,
344 "found type name used as a variable");
347 tcx.sess.span_fatal(ast_ty.span, "internal error in instantiate");
351 ast::ty_constr(t, cs) {
353 for constr: @ast::ty_constr in cs {
354 out_cs += [ty::ast_constr_to_constr(tcx, constr)];
356 typ = ty::mk_constr(tcx, ast_ty_to_ty(tcx, mode, t), out_cs);
360 m_check_tyvar(fcx) { ret next_ty_var(fcx); }
361 _ { tcx.sess.span_bug(ast_ty.span,
362 "found `ty_infer` in unexpected place"); }
366 tcx.ast_ty_to_ty_cache.insert(ast_ty, some(typ));
370 fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item)
371 -> ty::ty_param_bounds_and_ty {
373 ast::item_const(t, _) {
374 let typ = ast_ty_to_ty(tcx, mode, t);
375 let tpt = {bounds: @[], ty: typ};
376 tcx.tcache.insert(local_def(it.id), tpt);
379 ast::item_fn(decl, tps, _) {
380 ret ty_of_fn(tcx, mode, decl, tps, local_def(it.id));
382 ast::item_ty(t, tps) {
383 alt tcx.tcache.find(local_def(it.id)) {
384 some(tpt) { ret tpt; }
387 // Tell ast_ty_to_ty() that we want to perform a recursive
388 // call to resolve any named types.
389 let tpt = {bounds: ty_param_bounds(tcx, mode, tps),
390 ty: ty::mk_named(tcx, ast_ty_to_ty(tcx, mode, t),
392 tcx.tcache.insert(local_def(it.id), tpt);
395 ast::item_res(decl, tps, _, _, _) {
396 let {bounds, params} = mk_ty_params(tcx, tps);
397 let t_arg = ty_of_arg(tcx, mode, decl.inputs[0]);
398 let t = ty::mk_named(tcx, ty::mk_res(tcx, local_def(it.id), t_arg.ty,
401 let t_res = {bounds: bounds, ty: t};
402 tcx.tcache.insert(local_def(it.id), t_res);
405 ast::item_enum(_, tps) {
406 // Create a new generic polytype.
407 let {bounds, params} = mk_ty_params(tcx, tps);
408 let t = ty::mk_named(tcx, ty::mk_enum(tcx, local_def(it.id), params),
410 let tpt = {bounds: bounds, ty: t};
411 tcx.tcache.insert(local_def(it.id), tpt);
414 ast::item_iface(tps, ms) {
415 let s_tp = vec::len(tps) - 1u;
416 tcx.ty_param_bounds.insert(tps[s_tp].id, @[]);
417 let {bounds, params} = mk_ty_params(tcx, vec::slice(tps, 0u, s_tp));
418 let t = ty::mk_named(tcx, ty::mk_iface(tcx, local_def(it.id), params),
420 let tpt = {bounds: bounds, ty: t};
421 tcx.tcache.insert(local_def(it.id), tpt);
426 fn ty_of_native_item(tcx: ty::ctxt, mode: mode, it: @ast::native_item)
427 -> ty::ty_param_bounds_and_ty {
429 ast::native_item_fn(fn_decl, params) {
430 ret ty_of_native_fn_decl(tcx, mode, fn_decl, params,
433 ast::native_item_ty {
434 alt tcx.tcache.find(local_def(it.id)) {
435 some(tpt) { ret tpt; }
438 let t = ty::mk_native(tcx, local_def(it.id));
439 let t = ty::mk_named(tcx, t, @it.ident);
440 let tpt = {bounds: @[], ty: t};
441 tcx.tcache.insert(local_def(it.id), tpt);
446 fn ty_of_arg(tcx: ty::ctxt, mode: mode, a: ast::arg) -> ty::arg {
447 let ty = ast_ty_to_ty(tcx, mode, a.ty);
448 {mode: default_arg_mode_for_ty(tcx, a.mode, ty), ty: ty}
450 fn ty_of_fn_decl(tcx: ty::ctxt, mode: mode,
451 proto: ast::proto, decl: ast::fn_decl) -> ty::fn_ty {
453 for a: ast::arg in decl.inputs { input_tys += [ty_of_arg(tcx, mode, a)]; }
454 let output_ty = ast_ty_to_ty(tcx, mode, decl.output);
456 let out_constrs = [];
457 for constr: @ast::constr in decl.constraints {
458 out_constrs += [ty::ast_constr_to_constr(tcx, constr)];
460 {proto: proto, inputs: input_tys,
461 output: output_ty, ret_style: decl.cf, constraints: out_constrs}
463 fn ty_of_fn(tcx: ty::ctxt, mode: mode, decl: ast::fn_decl,
464 ty_params: [ast::ty_param], def_id: ast::def_id)
465 -> ty::ty_param_bounds_and_ty {
466 let bounds = ty_param_bounds(tcx, mode, ty_params);
467 let tofd = ty_of_fn_decl(tcx, mode, ast::proto_bare, decl);
468 let tpt = {bounds: bounds, ty: ty::mk_fn(tcx, tofd)};
469 tcx.tcache.insert(def_id, tpt);
472 fn ty_of_native_fn_decl(tcx: ty::ctxt, mode: mode, decl: ast::fn_decl,
473 ty_params: [ast::ty_param], def_id: ast::def_id)
474 -> ty::ty_param_bounds_and_ty {
475 let input_tys = [], bounds = ty_param_bounds(tcx, mode, ty_params);
476 for a: ast::arg in decl.inputs { input_tys += [ty_of_arg(tcx, mode, a)]; }
477 let output_ty = ast_ty_to_ty(tcx, mode, decl.output);
479 let t_fn = ty::mk_fn(tcx, {proto: ast::proto_bare,
482 ret_style: ast::return_val,
484 let tpt = {bounds: bounds, ty: t_fn};
485 tcx.tcache.insert(def_id, tpt);
488 fn ty_param_bounds(tcx: ty::ctxt, mode: mode, params: [ast::ty_param])
489 -> @[ty::param_bounds] {
491 for param in params {
492 result += [alt tcx.ty_param_bounds.find(param.id) {
496 for b in *param.bounds {
498 ast::bound_send { ty::bound_send }
499 ast::bound_copy { ty::bound_copy }
500 ast::bound_iface(t) {
501 let ity = ast_ty_to_ty(tcx, mode, t);
502 alt ty::struct(tcx, ity) {
503 ty::ty_iface(_, _) {}
506 t.span, "type parameter bounds must be \
515 tcx.ty_param_bounds.insert(param.id, boxed);
522 fn ty_of_method(tcx: ty::ctxt, mode: mode, m: @ast::method) -> ty::method {
523 {ident: m.ident, tps: ty_param_bounds(tcx, mode, m.tps),
524 fty: ty_of_fn_decl(tcx, mode, ast::proto_bare, m.decl)}
526 fn ty_of_ty_method(tcx: ty::ctxt, mode: mode, m: ast::ty_method)
528 {ident: m.ident, tps: ty_param_bounds(tcx, mode, m.tps),
529 fty: ty_of_fn_decl(tcx, mode, ast::proto_bare, m.decl)}
532 // A convenience function to use a crate_ctxt to resolve names for
534 fn ast_ty_to_ty_crate(ccx: @crate_ctxt, &&ast_ty: @ast::ty) -> ty::t {
535 ret ast_ty_to_ty(ccx.tcx, m_check, ast_ty);
538 // A wrapper around ast_ty_to_ty_crate that handles ty_infer.
539 fn ast_ty_to_ty_crate_infer(ccx: @crate_ctxt, &&ast_ty: @ast::ty) ->
542 ast::ty_infer { none }
543 _ { some(ast_ty_to_ty_crate(ccx, ast_ty)) }
548 // Functions that write types into the node type table
550 fn inner(ntt: node_type_table, node_id: ast::node_id,
551 tpot: ty_param_substs_opt_and_ty) {
552 smallintmap::insert(*ntt, node_id as uint, tpot);
555 // Writes a type parameter count and type pair into the node type table.
556 fn ty(tcx: ty::ctxt, node_id: ast::node_id,
557 tpot: ty_param_substs_opt_and_ty) {
558 assert (!ty::type_contains_vars(tcx, tpot.ty));
559 inner(tcx.node_types, node_id, tpot);
562 // Writes a type parameter count and type pair into the node type table.
563 // This function allows for the possibility of type variables, which will
564 // be rewritten later during the fixup mode.
565 fn ty_fixup(fcx: @fn_ctxt, node_id: ast::node_id,
566 tpot: ty_param_substs_opt_and_ty) {
567 inner(fcx.ccx.tcx.node_types, node_id, tpot);
568 if ty::type_contains_vars(fcx.ccx.tcx, tpot.ty) {
569 fcx.fixups += [node_id];
573 // Writes a type with no type parameters into the node type table.
574 fn ty_only(tcx: ty::ctxt, node_id: ast::node_id, typ: ty::t) {
575 ty(tcx, node_id, {substs: none::<[ty::t]>, ty: typ});
578 // Writes a type with no type parameters into the node type table. This
579 // function allows for the possibility of type variables.
580 fn ty_only_fixup(fcx: @fn_ctxt, node_id: ast::node_id, typ: ty::t) {
581 ret ty_fixup(fcx, node_id, {substs: none::<[ty::t]>, ty: typ});
584 // Writes a nil type into the node type table.
585 fn nil_ty(tcx: ty::ctxt, node_id: ast::node_id) {
586 ret ty(tcx, node_id, {substs: none::<[ty::t]>, ty: ty::mk_nil(tcx)});
589 // Writes the bottom type into the node type table.
590 fn bot_ty(tcx: ty::ctxt, node_id: ast::node_id) {
591 ret ty(tcx, node_id, {substs: none::<[ty::t]>, ty: ty::mk_bot(tcx)});
595 fn mk_ty_params(tcx: ty::ctxt, atps: [ast::ty_param])
596 -> {bounds: @[ty::param_bounds], params: [ty::t]} {
597 let i = 0u, bounds = ty_param_bounds(tcx, m_collect, atps);
599 params: vec::map(atps, {|atp|
600 let t = ty::mk_param(tcx, i, local_def(atp.id));
606 fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
607 impl_tps: uint, if_m: ty::method, substs: [ty::t])
609 if impl_m.tps != if_m.tps {
610 tcx.sess.span_err(sp, "method `" + if_m.ident +
611 "` has an incompatible set of type parameters");
612 ty::mk_fn(tcx, impl_m.fty)
614 let auto_modes = vec::map2(impl_m.fty.inputs, if_m.fty.inputs, {|i, f|
615 alt ty::struct(tcx, f.ty) {
616 ty::ty_param(0u, _) if i.mode == ast::mode_infer {
617 {mode: ast::by_ref with i}
622 let impl_fty = ty::mk_fn(tcx, {inputs: auto_modes with impl_m.fty});
623 // Add dummy substs for the parameters of the impl method
624 let substs = substs + vec::init_fn(vec::len(*if_m.tps), {|i|
625 ty::mk_param(tcx, i + impl_tps, {crate: 0, node: 0})
627 let if_fty = ty::substitute_type_params(tcx, substs,
628 ty::mk_fn(tcx, if_m.fty));
629 alt ty::unify::unify(impl_fty, if_fty, ty::unify::precise, tcx) {
630 ty::unify::ures_err(err) {
631 tcx.sess.span_err(sp, "method `" + if_m.ident +
632 "` has an incompatible type: " +
633 ty::type_err_to_str(err));
636 ty::unify::ures_ok(tp) { tp }
641 // Item collection - a pair of bootstrap passes:
643 // (1) Collect the IDs of all type items (typedefs) and store them in a table.
645 // (2) Translate the AST fragments that describe types to determine a type for
646 // each item. When we encounter a named type, we consult the table built
647 // in pass 1 to find its item, and recursively translate it.
649 // We then annotate the AST with the resulting types and return the annotated
650 // AST, along with a table mapping item IDs to their types.
652 // TODO: This logic is quite convoluted; it's a relic of the time when we
653 // actually wrote types directly into the AST and didn't have a type cache.
654 // Could use some cleanup. Consider topologically sorting in phase (1) above.
656 type ctxt = {tcx: ty::ctxt};
658 fn get_enum_variant_types(cx: @ctxt, enum_ty: ty::t,
659 variants: [ast::variant],
660 ty_params: [ast::ty_param]) {
661 // Create a set of parameter types shared among all the variants.
663 for variant: ast::variant in variants {
664 // Nullary enum constructors get turned into constants; n-ary enum
665 // constructors get turned into functions.
667 let result_ty = if vec::len(variant.node.args) == 0u {
670 // As above, tell ast_ty_to_ty() that trans_ty_item_to_ty()
671 // should be called to resolve named types.
672 let args: [arg] = [];
673 for va: ast::variant_arg in variant.node.args {
674 let arg_ty = ast_ty_to_ty(cx.tcx, m_collect, va.ty);
675 args += [{mode: ast::by_copy, ty: arg_ty}];
677 // FIXME: this will be different for constrained types
679 {proto: ast::proto_box,
680 inputs: args, output: enum_ty,
681 ret_style: ast::return_val, constraints: []})
683 let tpt = {bounds: ty_param_bounds(cx.tcx, m_collect, ty_params),
685 cx.tcx.tcache.insert(local_def(variant.node.id), tpt);
686 write::ty_only(cx.tcx, variant.node.id, result_ty);
689 fn convert(cx: @ctxt, it: @ast::item) {
691 // These don't define types.
692 ast::item_mod(_) | ast::item_native_mod(_) {}
693 ast::item_enum(variants, ty_params) {
694 let tpt = ty_of_item(cx.tcx, m_collect, it);
695 write::ty_only(cx.tcx, it.id, tpt.ty);
696 get_enum_variant_types(cx, tpt.ty, variants, ty_params);
698 ast::item_impl(tps, ifce, selfty, ms) {
699 let i_bounds = ty_param_bounds(cx.tcx, m_collect, tps);
702 let bounds = ty_param_bounds(cx.tcx, m_collect, m.tps);
703 let mty = ty_of_method(cx.tcx, m_collect, m);
704 my_methods += [{mty: mty, id: m.id}];
705 let fty = ty::mk_fn(cx.tcx, mty.fty);
706 cx.tcx.tcache.insert(local_def(m.id),
707 {bounds: @(*i_bounds + *bounds),
709 write::ty_only(cx.tcx, m.id, fty);
711 let selfty = ast_ty_to_ty(cx.tcx, m_collect, selfty);
712 write::ty_only(cx.tcx, it.id, selfty);
715 let iface_ty = ast_ty_to_ty(cx.tcx, m_collect, t);
716 cx.tcx.tcache.insert(local_def(it.id),
717 {bounds: i_bounds, ty: iface_ty});
718 alt ty::struct(cx.tcx, iface_ty) {
719 ty::ty_iface(did, tys) {
720 for if_m in *ty::iface_methods(cx.tcx, did) {
721 alt vec::find(my_methods,
722 {|m| if_m.ident == m.mty.ident}) {
724 let mt = compare_impl_method(
725 cx.tcx, t.span, m, vec::len(tps), if_m,
727 let old = cx.tcx.tcache.get(local_def(id));
729 cx.tcx.tcache.insert(local_def(id),
732 write::ty_only(cx.tcx, id, mt);
736 cx.tcx.sess.span_err(t.span, "missing method `" +
743 cx.tcx.sess.span_fatal(t.span, "can only implement \
751 ast::item_res(decl, tps, _, dtor_id, ctor_id) {
752 let {bounds, params} = mk_ty_params(cx.tcx, tps);
753 let t_arg = ty_of_arg(cx.tcx, m_collect, decl.inputs[0]);
754 let t_res = ty::mk_res(cx.tcx, local_def(it.id), t_arg.ty,
756 let t_ctor = ty::mk_fn(cx.tcx, {
757 proto: ast::proto_box,
758 inputs: [{mode: ast::by_copy with t_arg}],
760 ret_style: ast::return_val, constraints: []
762 let t_dtor = ty::mk_fn(cx.tcx, {
763 proto: ast::proto_box,
764 inputs: [t_arg], output: ty::mk_nil(cx.tcx),
765 ret_style: ast::return_val, constraints: []
767 write::ty_only(cx.tcx, it.id, t_res);
768 write::ty_only(cx.tcx, ctor_id, t_ctor);
769 cx.tcx.tcache.insert(local_def(ctor_id),
770 {bounds: bounds, ty: t_ctor});
771 write::ty_only(cx.tcx, dtor_id, t_dtor);
773 ast::item_iface(_, ms) {
774 let tpt = ty_of_item(cx.tcx, m_collect, it);
775 write::ty_only(cx.tcx, it.id, tpt.ty);
776 ty::store_iface_methods(cx.tcx, it.id, @vec::map(ms, {|m|
777 ty_of_ty_method(cx.tcx, m_collect, m)
781 // This call populates the type cache with the converted type
782 // of the item in passing. All we have to do here is to write
783 // it into the node type table.
784 let tpt = ty_of_item(cx.tcx, m_collect, it);
785 write::ty_only(cx.tcx, it.id, tpt.ty);
789 fn convert_native(cx: @ctxt, i: @ast::native_item) {
790 // As above, this call populates the type table with the converted
791 // type of the native item. We simply write it into the node type
793 let tpt = ty_of_native_item(cx.tcx, m_collect, i);
795 ast::native_item_ty {
796 // FIXME: Native types have no annotation. Should they? --pcw
798 ast::native_item_fn(_, _) {
799 write::ty_only(cx.tcx, i.id, tpt.ty);
803 fn collect_item_types(tcx: ty::ctxt, crate: @ast::crate) {
804 let cx = @{tcx: tcx};
806 visit::mk_simple_visitor(@{visit_item: bind convert(cx, _),
808 bind convert_native(cx, _)
810 *visit::default_simple_visitor()});
811 visit::visit_crate(*crate, (), visit);
818 fn unify(fcx: @fn_ctxt, expected: ty::t, actual: ty::t) ->
820 ret ty::unify::unify(expected, actual,
821 ty::unify::in_bindings(fcx.var_bindings),
827 // FIXME This is almost a duplicate of ty::type_autoderef, with structure_of
828 // instead of ty::struct.
829 fn do_autoderef(fcx: @fn_ctxt, sp: span, t: ty::t) -> ty::t {
832 alt structure_of(fcx, sp, t1) {
833 ty::ty_box(inner) | ty::ty_uniq(inner) {
834 alt ty::struct(fcx.ccx.tcx, t1) {
836 if ty::occurs_check_fails(fcx.ccx.tcx, some(sp), v1,
837 ty::mk_box(fcx.ccx.tcx, inner)) {
845 ty::ty_res(_, inner, tps) {
846 t1 = ty::substitute_type_params(fcx.ccx.tcx, tps, inner);
848 ty::ty_enum(did, tps) {
849 let variants = ty::enum_variants(fcx.ccx.tcx, did);
850 if vec::len(*variants) != 1u || vec::len(variants[0].args) != 1u {
854 ty::substitute_type_params(fcx.ccx.tcx, tps,
855 variants[0].args[0]);
863 fn resolve_type_vars_if_possible(fcx: @fn_ctxt, typ: ty::t) -> ty::t {
864 alt ty::unify::fixup_vars(fcx.ccx.tcx, none, fcx.var_bindings, typ) {
865 fix_ok(new_type) { ret new_type; }
866 fix_err(_) { ret typ; }
871 // Demands - procedures that require that two types unify and emit an error
872 // message if they don't.
873 type ty_param_substs_and_ty = {substs: [ty::t], ty: ty::t};
876 fn simple(fcx: @fn_ctxt, sp: span, expected: ty::t, actual: ty::t) ->
878 full(fcx, sp, expected, actual, []).ty
881 fn with_substs(fcx: @fn_ctxt, sp: span, expected: ty::t, actual: ty::t,
882 ty_param_substs_0: [ty::t]) -> ty_param_substs_and_ty {
883 full(fcx, sp, expected, actual, ty_param_substs_0)
886 // Requires that the two types unify, and prints an error message if they
887 // don't. Returns the unified type and the type parameter substitutions.
888 fn full(fcx: @fn_ctxt, sp: span, expected: ty::t, actual: ty::t,
889 ty_param_substs_0: [ty::t]) ->
890 ty_param_substs_and_ty {
892 let ty_param_substs: [mutable ty::t] = [mutable];
893 let ty_param_subst_var_ids: [int] = [];
894 for ty_param_subst: ty::t in ty_param_substs_0 {
895 // Generate a type variable and unify it with the type parameter
896 // substitution. We will then pull out these type variables.
897 let t_0 = next_ty_var(fcx);
898 ty_param_substs += [mutable t_0];
899 ty_param_subst_var_ids += [ty::ty_var_id(fcx.ccx.tcx, t_0)];
900 simple(fcx, sp, ty_param_subst, t_0);
903 fn mk_result(fcx: @fn_ctxt, result_ty: ty::t,
904 ty_param_subst_var_ids: [int]) ->
905 ty_param_substs_and_ty {
906 let result_ty_param_substs: [ty::t] = [];
907 for var_id: int in ty_param_subst_var_ids {
908 let tp_subst = ty::mk_var(fcx.ccx.tcx, var_id);
909 result_ty_param_substs += [tp_subst];
911 ret {substs: result_ty_param_substs, ty: result_ty};
915 alt unify::unify(fcx, expected, actual) {
916 ures_ok(t) { ret mk_result(fcx, t, ty_param_subst_var_ids); }
918 let e_err = resolve_type_vars_if_possible(fcx, expected);
919 let a_err = resolve_type_vars_if_possible(fcx, actual);
920 fcx.ccx.tcx.sess.span_err(sp,
921 "mismatched types: expected `" +
922 ty_to_str(fcx.ccx.tcx, e_err) +
924 ty_to_str(fcx.ccx.tcx, a_err) +
925 "` (" + ty::type_err_to_str(err) +
927 ret mk_result(fcx, expected, ty_param_subst_var_ids);
934 // Returns true if the two types unify and false if they don't.
935 fn are_compatible(fcx: @fn_ctxt, expected: ty::t, actual: ty::t) -> bool {
936 alt unify::unify(fcx, expected, actual) {
937 ures_ok(_) { ret true; }
938 ures_err(_) { ret false; }
943 // Returns the types of the arguments to a enum variant.
944 fn variant_arg_types(ccx: @crate_ctxt, _sp: span, vid: ast::def_id,
945 enum_ty_params: [ty::t]) -> [ty::t] {
946 let result: [ty::t] = [];
947 let tpt = ty::lookup_item_type(ccx.tcx, vid);
948 alt ty::struct(ccx.tcx, tpt.ty) {
951 for arg: ty::arg in f.inputs {
953 ty::substitute_type_params(ccx.tcx, enum_ty_params, arg.ty);
958 // Nullary variant. Do nothing, as there are no arguments.
961 /* result is a vector of the *expected* types of all the fields */
967 // Type resolution: the phase that finds all the types in the AST with
968 // unresolved type variables and replaces "ty_var" types with their
971 // TODO: inefficient since not all types have vars in them. It would be better
972 // to maintain a list of fixups.
975 export resolve_type_vars_in_block;
976 export resolve_type_vars_in_expr;
978 fn resolve_type_vars_in_type(fcx: @fn_ctxt, sp: span, typ: ty::t) ->
980 if !ty::type_contains_vars(fcx.ccx.tcx, typ) { ret some(typ); }
981 alt ty::unify::fixup_vars(fcx.ccx.tcx, some(sp), fcx.var_bindings,
983 fix_ok(new_type) { ret some(new_type); }
985 fcx.ccx.tcx.sess.span_err(sp, "cannot determine a type \
986 for this expression");
991 fn resolve_type_vars_for_node(wbcx: wb_ctxt, sp: span, id: ast::node_id) {
993 let tpot = ty::node_id_to_ty_param_substs_opt_and_ty(fcx.ccx.tcx, id);
995 alt resolve_type_vars_in_type(fcx, sp, tpot.ty) {
997 none { wbcx.success = false; ret }
1001 none { new_substs_opt = none; }
1003 let new_substs: [ty::t] = [];
1004 for subst: ty::t in substs {
1005 alt resolve_type_vars_in_type(fcx, sp, subst) {
1006 some(t) { new_substs += [t]; }
1007 none { wbcx.success = false; ret; }
1010 new_substs_opt = some(new_substs);
1013 write::ty(fcx.ccx.tcx, id, {substs: new_substs_opt, ty: new_ty});
1017 // As soon as we hit an error we have to stop resolving
1018 // the entire function
1019 {fcx: @fn_ctxt, mutable success: bool};
1020 type wb_vt = visit::vt<wb_ctxt>;
1022 fn visit_stmt(s: @ast::stmt, wbcx: wb_ctxt, v: wb_vt) {
1023 if !wbcx.success { ret; }
1024 resolve_type_vars_for_node(wbcx, s.span, ty::stmt_node_id(s));
1025 visit::visit_stmt(s, wbcx, v);
1027 fn visit_expr(e: @ast::expr, wbcx: wb_ctxt, v: wb_vt) {
1028 if !wbcx.success { ret; }
1029 resolve_type_vars_for_node(wbcx, e.span, e.id);
1031 ast::expr_fn(_, decl, _, _) |
1032 ast::expr_fn_block(decl, _) {
1033 for input in decl.inputs {
1034 resolve_type_vars_for_node(wbcx, e.span, input.id);
1039 visit::visit_expr(e, wbcx, v);
1041 fn visit_block(b: ast::blk, wbcx: wb_ctxt, v: wb_vt) {
1042 if !wbcx.success { ret; }
1043 resolve_type_vars_for_node(wbcx, b.span, b.node.id);
1044 visit::visit_block(b, wbcx, v);
1046 fn visit_pat(p: @ast::pat, wbcx: wb_ctxt, v: wb_vt) {
1047 if !wbcx.success { ret; }
1048 resolve_type_vars_for_node(wbcx, p.span, p.id);
1049 visit::visit_pat(p, wbcx, v);
1051 fn visit_local(l: @ast::local, wbcx: wb_ctxt, v: wb_vt) {
1052 if !wbcx.success { ret; }
1053 let var_id = lookup_local(wbcx.fcx, l.span, l.node.id);
1055 ty::unify::resolve_type_var(wbcx.fcx.ccx.tcx, some(l.span),
1056 wbcx.fcx.var_bindings, var_id);
1058 fix_ok(lty) { write::ty_only(wbcx.fcx.ccx.tcx, l.node.id, lty); }
1060 wbcx.fcx.ccx.tcx.sess.span_err(l.span,
1061 "cannot determine a type \
1062 for this local variable");
1063 wbcx.success = false;
1066 visit::visit_local(l, wbcx, v);
1068 fn visit_item(_item: @ast::item, _wbcx: wb_ctxt, _v: wb_vt) {
1072 fn resolve_type_vars_in_expr(fcx: @fn_ctxt, e: @ast::expr) -> bool {
1073 let wbcx = {fcx: fcx, mutable success: true};
1075 visit::mk_vt(@{visit_item: visit_item,
1076 visit_stmt: visit_stmt,
1077 visit_expr: visit_expr,
1078 visit_block: visit_block,
1079 visit_pat: visit_pat,
1080 visit_local: visit_local
1081 with *visit::default_visitor()});
1082 visit::visit_expr(e, wbcx, visit);
1086 fn resolve_type_vars_in_block(fcx: @fn_ctxt, blk: ast::blk) -> bool {
1087 let wbcx = {fcx: fcx, mutable success: true};
1089 visit::mk_vt(@{visit_item: visit_item,
1090 visit_stmt: visit_stmt,
1091 visit_expr: visit_expr,
1092 visit_block: visit_block,
1093 visit_pat: visit_pat,
1094 visit_local: visit_local
1095 with *visit::default_visitor()});
1096 visit.visit_block(blk, wbcx, visit);
1102 // Local variable gathering. We gather up all locals and create variable IDs
1103 // for them before typechecking the function.
1104 type gather_result =
1105 {var_bindings: @ty::unify::var_bindings,
1106 locals: hashmap<ast::node_id, int>,
1107 next_var_id: @mutable int};
1109 // Used only as a helper for check_fn.
1110 fn gather_locals(ccx: @crate_ctxt,
1114 old_fcx: option::t<@fn_ctxt>) -> gather_result {
1115 let {vb: vb, locals: locals, nvi: nvi} =
1118 {vb: ty::unify::mk_var_bindings(),
1119 locals: new_int_hash::<int>(),
1123 {vb: fcx.var_bindings,
1125 nvi: fcx.next_var_id}
1130 let next_var_id = fn@() -> int { let rv = *nvi; *nvi += 1; ret rv; };
1131 let assign = fn@(nid: ast::node_id, ty_opt: option::t<ty::t>) {
1132 let var_id = next_var_id();
1133 locals.insert(nid, var_id);
1135 none {/* nothing to do */ }
1137 ty::unify::unify(ty::mk_var(tcx, var_id), typ,
1138 ty::unify::in_bindings(vb), tcx);
1143 // Add formal parameters.
1144 let args = ty::ty_fn_args(ccx.tcx, ty::node_id_to_type(ccx.tcx, id));
1146 for arg: ty::arg in args {
1147 assign(decl.inputs[i].id, some(arg.ty));
1151 // Add explicitly-declared locals.
1152 let visit_local = fn@(local: @ast::local, &&e: (), v: visit::vt<()>) {
1153 let local_ty = ast_ty_to_ty_crate_infer(ccx, local.node.ty);
1154 assign(local.node.id, local_ty);
1155 visit::visit_local(local, e, v);
1158 // Add pattern bindings.
1159 let visit_pat = fn@(p: @ast::pat, &&e: (), v: visit::vt<()>) {
1160 alt normalize_pat(ccx.tcx, p).node {
1161 ast::pat_ident(_, _) { assign(p.id, none); }
1164 visit::visit_pat(p, e, v);
1167 // Don't descend into fns and items
1168 fn visit_fn<T>(_fk: visit::fn_kind, _decl: ast::fn_decl, _body: ast::blk,
1169 _sp: span, _id: ast::node_id, _t: T, _v: visit::vt<T>) {
1171 fn visit_item<E>(_i: @ast::item, _e: E, _v: visit::vt<E>) { }
1174 @{visit_local: visit_local,
1175 visit_pat: visit_pat,
1176 visit_fn: bind visit_fn(_, _, _, _, _, _, _),
1177 visit_item: bind visit_item(_, _, _)
1178 with *visit::default_visitor()};
1180 visit::visit_block(body, (), visit::mk_vt(visit));
1181 ret {var_bindings: vb,
1186 // AST fragment checking
1187 fn check_lit(ccx: @crate_ctxt, lit: @ast::lit) -> ty::t {
1189 ast::lit_str(_) { ty::mk_str(ccx.tcx) }
1190 ast::lit_int(_, t) { ty::mk_mach_int(ccx.tcx, t) }
1191 ast::lit_uint(_, t) { ty::mk_mach_uint(ccx.tcx, t) }
1192 ast::lit_float(_, t) { ty::mk_mach_float(ccx.tcx, t) }
1193 ast::lit_nil { ty::mk_nil(ccx.tcx) }
1194 ast::lit_bool(_) { ty::mk_bool(ccx.tcx) }
1198 fn valid_range_bounds(from: @ast::expr, to: @ast::expr) -> bool {
1199 ast_util::compare_lit_exprs(from, to) <= 0
1202 // Pattern checking is top-down rather than bottom-up so that bindings get
1203 // their types immediately.
1204 fn check_pat(fcx: @fn_ctxt, map: pat_util::pat_id_map, pat: @ast::pat,
1206 alt normalize_pat(fcx.ccx.tcx, pat).node {
1208 alt structure_of(fcx, pat.span, expected) {
1209 ty::ty_enum(_, expected_tps) {
1210 let path_tpt = {substs: some(expected_tps),
1212 write::ty_fixup(fcx, pat.id, path_tpt);
1215 write::ty_only_fixup(fcx, pat.id, expected);
1220 check_expr_with(fcx, lt, expected);
1221 write::ty_only_fixup(fcx, pat.id, expr_ty(fcx.ccx.tcx, lt));
1223 ast::pat_range(begin, end) {
1224 check_expr_with(fcx, begin, expected);
1225 check_expr_with(fcx, end, expected);
1226 let b_ty = resolve_type_vars_if_possible(fcx, expr_ty(fcx.ccx.tcx,
1228 if !ty::same_type(fcx.ccx.tcx, b_ty, resolve_type_vars_if_possible(
1229 fcx, expr_ty(fcx.ccx.tcx, end))) {
1230 fcx.ccx.tcx.sess.span_err(pat.span, "mismatched types in range");
1231 } else if !ty::type_is_numeric(fcx.ccx.tcx, b_ty) {
1232 fcx.ccx.tcx.sess.span_err(pat.span,
1233 "non-numeric type used in range");
1234 } else if !valid_range_bounds(begin, end) {
1235 fcx.ccx.tcx.sess.span_err(begin.span,
1236 "lower range bound must be less \
1239 write::ty_only_fixup(fcx, pat.id, b_ty);
1241 ast::pat_ident(name, sub) {
1242 let vid = lookup_local(fcx, pat.span, pat.id);
1243 let typ = ty::mk_var(fcx.ccx.tcx, vid);
1244 typ = demand::simple(fcx, pat.span, expected, typ);
1245 let canon_id = map.get(path_to_ident(name));
1246 if canon_id != pat.id {
1248 ty::mk_var(fcx.ccx.tcx,
1249 lookup_local(fcx, pat.span, canon_id));
1250 typ = demand::simple(fcx, pat.span, ct, typ);
1252 write::ty_only_fixup(fcx, pat.id, typ);
1254 some(p) { check_pat(fcx, map, p, expected); }
1258 ast::pat_enum(path, subpats) {
1259 // Typecheck the path.
1260 let v_def = lookup_def(fcx, path.span, pat.id);
1261 let v_def_ids = ast_util::variant_def_ids(v_def);
1262 let enum_tpt = ty::lookup_item_type(fcx.ccx.tcx, v_def_ids.tg);
1263 let path_tpot = instantiate_path(fcx, path, enum_tpt, pat.span);
1265 // Take the enum type params out of `expected`.
1266 alt structure_of(fcx, pat.span, expected) {
1267 ty::ty_enum(_, expected_tps) {
1268 // Unify with the expected enum type.
1270 ty::ty_param_substs_opt_and_ty_to_monotype(fcx.ccx.tcx,
1274 demand::with_substs(fcx, pat.span, expected, ctor_ty,
1277 {substs: some::<[ty::t]>(path_tpt.substs), ty: path_tpt.ty};
1279 // Get the number of arguments in this enum variant.
1281 variant_arg_types(fcx.ccx, pat.span, v_def_ids.var,
1283 let subpats_len = vec::len::<@ast::pat>(subpats);
1284 if vec::len::<ty::t>(arg_types) > 0u {
1287 let arg_len = vec::len::<ty::t>(arg_types);
1288 if arg_len != subpats_len {
1289 // TODO: note definition of enum variant
1290 // TODO (issue #448): Wrap a #fmt string over multiple
1293 #fmt["this pattern has %u field%s, but the \
1294 corresponding variant has %u field%s",
1296 if subpats_len == 1u { "" } else { "s" },
1297 arg_len, if arg_len == 1u { "" } else { "s" }];
1298 fcx.ccx.tcx.sess.span_fatal(pat.span, s);
1304 for subpat: @ast::pat in subpats {
1305 check_pat(fcx, map, subpat, arg_types[i]);
1308 } else if subpats_len > 0u {
1309 // TODO: note definition of enum variant
1310 fcx.ccx.tcx.sess.span_fatal
1312 #fmt["this pattern has %u field%s, \
1313 but the corresponding \
1314 variant has no fields",
1316 if subpats_len == 1u {
1320 write::ty_fixup(fcx, pat.id, path_tpot);
1323 // FIXME: Switch expected and actual in this message? I
1325 fcx.ccx.tcx.sess.span_fatal
1327 #fmt["mismatched types: expected `%s` but found enum",
1328 ty_to_str(fcx.ccx.tcx, expected)]);
1331 write::ty_fixup(fcx, pat.id, path_tpot);
1333 ast::pat_rec(fields, etc) {
1335 alt structure_of(fcx, pat.span, expected) {
1336 ty::ty_rec(fields) { ex_fields = fields; }
1338 fcx.ccx.tcx.sess.span_fatal
1340 #fmt["mismatched types: expected `%s` but found record",
1341 ty_to_str(fcx.ccx.tcx, expected)]);
1344 let f_count = vec::len(fields);
1345 let ex_f_count = vec::len(ex_fields);
1346 if ex_f_count < f_count || !etc && ex_f_count > f_count {
1347 fcx.ccx.tcx.sess.span_fatal
1348 (pat.span, #fmt["mismatched types: expected a record \
1349 with %u fields, found one with %u \
1351 ex_f_count, f_count]);
1353 fn matches(name: str, f: ty::field) -> bool {
1354 ret str::eq(name, f.ident);
1356 for f: ast::field_pat in fields {
1357 alt vec::find(ex_fields, bind matches(f.ident, _)) {
1358 some(field) { check_pat(fcx, map, f.pat, field.mt.ty); }
1360 fcx.ccx.tcx.sess.span_fatal(pat.span,
1361 #fmt["mismatched types: did not \
1362 expect a record with a field `%s`",
1367 write::ty_only_fixup(fcx, pat.id, expected);
1369 ast::pat_tup(elts) {
1371 alt structure_of(fcx, pat.span, expected) {
1372 ty::ty_tup(elts) { ex_elts = elts; }
1374 fcx.ccx.tcx.sess.span_fatal
1376 #fmt["mismatched types: expected `%s`, found tuple",
1377 ty_to_str(fcx.ccx.tcx, expected)]);
1380 let e_count = vec::len(elts);
1381 if e_count != vec::len(ex_elts) {
1382 fcx.ccx.tcx.sess.span_fatal
1383 (pat.span, #fmt["mismatched types: expected a tuple \
1384 with %u fields, found one with %u \
1385 fields", vec::len(ex_elts), e_count]);
1388 for elt in elts { check_pat(fcx, map, elt, ex_elts[i]); i += 1u; }
1389 write::ty_only_fixup(fcx, pat.id, expected);
1391 ast::pat_box(inner) {
1392 alt structure_of(fcx, pat.span, expected) {
1393 ty::ty_box(e_inner) {
1394 check_pat(fcx, map, inner, e_inner.ty);
1395 write::ty_only_fixup(fcx, pat.id, expected);
1398 fcx.ccx.tcx.sess.span_fatal(pat.span,
1399 "mismatched types: expected `" +
1400 ty_to_str(fcx.ccx.tcx, expected) +
1405 ast::pat_uniq(inner) {
1406 alt structure_of(fcx, pat.span, expected) {
1407 ty::ty_uniq(e_inner) {
1408 check_pat(fcx, map, inner, e_inner.ty);
1409 write::ty_only_fixup(fcx, pat.id, expected);
1412 fcx.ccx.tcx.sess.span_fatal(pat.span,
1413 "mismatched types: expected `" +
1414 ty_to_str(fcx.ccx.tcx, expected) +
1422 fn require_unsafe(sess: session, f_purity: ast::purity, sp: span) {
1424 ast::unsafe_fn { ret; }
1428 "unsafe operation requires unsafe function or block");
1433 fn require_impure(sess: session, f_purity: ast::purity, sp: span) {
1435 ast::unsafe_fn { ret; }
1436 ast::impure_fn { ret; }
1438 sess.span_err(sp, "Found impure expression in pure function decl");
1443 fn require_pure_call(ccx: @crate_ctxt, caller_purity: ast::purity,
1444 callee: @ast::expr, sp: span) {
1446 ast::unsafe_fn { ret; }
1448 alt ccx.tcx.def_map.find(callee.id) {
1449 some(ast::def_fn(_, ast::unsafe_fn)) {
1450 ccx.tcx.sess.span_err(
1452 "safe function calls function marked unsafe");
1460 alt ccx.tcx.def_map.find(callee.id) {
1461 some(ast::def_fn(_, ast::pure_fn)) |
1462 some(ast::def_variant(_, _)) { ret; }
1464 ccx.tcx.sess.span_err
1465 (sp, "pure function calls function not known to be pure");
1472 type unifier = fn@(@fn_ctxt, span, ty::t, ty::t) -> ty::t;
1474 fn check_expr(fcx: @fn_ctxt, expr: @ast::expr) -> bool {
1475 fn dummy_unify(_fcx: @fn_ctxt, _sp: span, _expected: ty::t, actual: ty::t)
1479 ret check_expr_with_unifier(fcx, expr, dummy_unify, 0u);
1481 fn check_expr_with(fcx: @fn_ctxt, expr: @ast::expr, expected: ty::t) -> bool {
1482 ret check_expr_with_unifier(fcx, expr, demand::simple, expected);
1485 fn impl_self_ty(tcx: ty::ctxt, did: ast::def_id) -> {n_tps: uint, ty: ty::t} {
1486 if did.crate == ast::local_crate {
1487 alt tcx.items.get(did.node) {
1488 ast_map::node_item(@{node: ast::item_impl(ts, _, st, _),
1490 {n_tps: vec::len(ts), ty: ast_ty_to_ty(tcx, m_check, st)}
1494 let tpt = csearch::get_type(tcx, did);
1495 {n_tps: vec::len(*tpt.bounds), ty: tpt.ty}
1499 fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
1500 name: ast::ident, ty: ty::t, sp: span)
1501 -> option::t<{method_ty: ty::t, n_tps: uint, substs: [ty::t],
1502 origin: method_origin}> {
1503 let tcx = fcx.ccx.tcx;
1505 // First, see whether this is an interface-bounded parameter
1506 alt ty::struct(tcx, ty) {
1507 ty::ty_param(n, did) {
1509 for bound in *tcx.ty_param_bounds.get(did.node) {
1511 ty::bound_iface(t) {
1512 let (iid, tps) = alt ty::struct(tcx, t) {
1513 ty::ty_iface(i, tps) { (i, tps) }
1515 let ifce_methods = ty::iface_methods(tcx, iid);
1516 alt vec::position(*ifce_methods, {|m| m.ident == name}) {
1518 let m = ifce_methods[pos];
1519 ret some({method_ty: ty::mk_fn(tcx, m.fty),
1520 n_tps: vec::len(*m.tps),
1522 origin: method_param(iid, pos, n, bound_n)});
1533 ty::ty_iface(did, tps) {
1535 for m in *ty::iface_methods(tcx, did) {
1536 if m.ident == name {
1537 ret some({method_ty: ty::mk_fn(tcx, m.fty),
1538 n_tps: vec::len(*m.tps),
1539 substs: tps + [ty::mk_int(tcx)],
1540 origin: method_iface(i)});
1549 std::list::iter(isc) {|impls|
1550 if option::is_some(result) { ret; }
1551 for @{did, methods, _} in *impls {
1552 alt vec::find(methods, {|m| m.ident == name}) {
1554 let {n_tps, ty: self_ty} = impl_self_ty(tcx, did);
1555 let {vars, ty: self_ty} = if n_tps > 0u {
1556 bind_params(fcx, self_ty, n_tps)
1557 } else { {vars: [], ty: self_ty} };
1558 alt unify::unify(fcx, ty, self_ty) {
1560 if option::is_some(result) {
1561 // FIXME[impl] score specificity to resolve ambiguity?
1563 sp, "multiple applicable methods in scope");
1566 method_ty: ty::lookup_item_type(tcx, m.did).ty,
1569 origin: method_static(m.did)
1583 fn check_expr_fn_with_unifier(fcx: @fn_ctxt,
1590 let tcx = fcx.ccx.tcx;
1592 let fty = ty::mk_fn(tcx, ty_of_fn_decl(tcx, m_check_tyvar(fcx),
1595 #debug("check_expr_fn_with_unifier %s fty=%s",
1597 ty_to_str(tcx, fty));
1599 write::ty_only_fixup(fcx, expr.id, fty);
1601 // Unify the type of the function with the expected type before we
1602 // typecheck the body so that we have more information about the
1603 // argument types in the body. This is needed to make binops and
1604 // record projection work on type inferred arguments.
1605 unify(fcx, expr.span, expected, fty);
1607 check_fn(fcx.ccx, proto, decl, body, expr.id, some(fcx));
1610 fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
1611 expected: ty::t) -> bool {
1612 #debug("typechecking expr %s",
1613 syntax::print::pprust::expr_to_str(expr));
1615 // A generic function to factor out common logic from call and bind
1617 fn check_call_or_bind(fcx: @fn_ctxt, sp: span, fty: ty::t,
1618 args: [option::t<@ast::expr>]) -> bool {
1619 let sty = structure_of(fcx, sp, fty);
1620 // Grab the argument types
1621 let arg_tys = alt sty {
1622 ty::ty_fn({inputs: arg_tys, _}) { arg_tys }
1624 fcx.ccx.tcx.sess.span_fatal(sp, "mismatched types: \
1625 expected function or native \
1626 function but found "
1627 + ty_to_str(fcx.ccx.tcx, fty))
1631 // Check that the correct number of arguments were supplied.
1632 let expected_arg_count = vec::len(arg_tys);
1633 let supplied_arg_count = vec::len(args);
1634 if expected_arg_count != supplied_arg_count {
1635 fcx.ccx.tcx.sess.span_err(
1636 sp, #fmt["this function takes %u parameter%s but %u \
1637 parameter%s supplied", expected_arg_count,
1638 expected_arg_count == 1u ? "" : "s",
1640 supplied_arg_count == 1u ? " was" : "s were"]);
1641 // HACK: build an arguments list with dummy arguments to
1643 let dummy = {mode: ast::by_ref, ty: ty::mk_bot(fcx.ccx.tcx)};
1644 arg_tys = vec::init_elt(supplied_arg_count, dummy);
1647 // Check the arguments.
1648 // We do this in a pretty awful way: first we typecheck any arguments
1649 // that are not anonymous functions, then we typecheck the anonymous
1650 // functions. This is so that we have more information about the types
1651 // of arguments when we typecheck the functions. This isn't really the
1652 // right way to do this.
1653 let check_args = fn@(check_blocks: bool) -> bool {
1659 let is_block = alt a.node {
1660 ast::expr_fn_block(_, _) { true }
1663 if is_block == check_blocks {
1664 bot |= check_expr_with_unifier(
1665 fcx, a, demand::simple, arg_tys[i].ty);
1674 check_args(false) | check_args(true)
1677 // A generic function for checking assignment expressions
1678 fn check_assignment(fcx: @fn_ctxt, _sp: span, lhs: @ast::expr,
1679 rhs: @ast::expr, id: ast::node_id) -> bool {
1680 let t = next_ty_var(fcx);
1681 let bot = check_expr_with(fcx, lhs, t) | check_expr_with(fcx, rhs, t);
1682 write::ty_only_fixup(fcx, id, ty::mk_nil(fcx.ccx.tcx));
1686 // A generic function for checking call expressions
1687 fn check_call(fcx: @fn_ctxt, sp: span, f: @ast::expr, args: [@ast::expr])
1689 let args_opt_0: [option::t<@ast::expr>] = [];
1690 for arg: @ast::expr in args {
1691 args_opt_0 += [some::<@ast::expr>(arg)];
1694 let bot = check_expr(fcx, f);
1695 // Call the generic checker.
1696 bot | check_call_or_bind(fcx, sp, expr_ty(fcx.ccx.tcx, f), args_opt_0)
1699 // A generic function for doing all of the checking for call expressions
1700 fn check_call_full(fcx: @fn_ctxt, sp: span, f: @ast::expr,
1701 args: [@ast::expr], id: ast::node_id) -> bool {
1702 /* here we're kind of hosed, as f can be any expr
1703 need to restrict it to being an explicit expr_path if we're
1704 inside a pure function, and need an environment mapping from
1705 function name onto purity-designation */
1706 require_pure_call(fcx.ccx, fcx.purity, f, sp);
1707 let bot = check_call(fcx, sp, f, args);
1709 // Pull the return type out of the type of the function.
1710 let fty = ty::expr_ty(fcx.ccx.tcx, f);
1711 let rt_1 = alt structure_of(fcx, sp, fty) {
1713 bot |= f.ret_style == ast::noreturn;
1716 _ { fcx.ccx.tcx.sess.span_fatal(sp, "calling non-function"); }
1718 write::ty_only_fixup(fcx, id, rt_1);
1722 // A generic function for checking for or for-each loops
1723 fn check_for(fcx: @fn_ctxt, local: @ast::local,
1724 element_ty: ty::t, body: ast::blk,
1725 node_id: ast::node_id) -> bool {
1726 let locid = lookup_local(fcx, local.span, local.node.id);
1727 let element_ty = demand::simple(fcx, local.span, element_ty,
1728 ty::mk_var(fcx.ccx.tcx, locid));
1729 let bot = check_decl_local(fcx, local);
1730 check_block_no_value(fcx, body);
1731 // Unify type of decl with element type of the seq
1732 demand::simple(fcx, local.span,
1733 ty::node_id_to_type(fcx.ccx.tcx, local.node.id),
1735 write::nil_ty(fcx.ccx.tcx, node_id);
1740 // A generic function for checking the then and else in an if
1742 fn check_then_else(fcx: @fn_ctxt, thn: ast::blk,
1743 elsopt: option::t<@ast::expr>, id: ast::node_id,
1744 _sp: span) -> bool {
1745 let (if_t, if_bot) =
1748 let thn_bot = check_block(fcx, thn);
1749 let thn_t = block_ty(fcx.ccx.tcx, thn);
1750 let els_bot = check_expr_with(fcx, els, thn_t);
1751 let els_t = expr_ty(fcx.ccx.tcx, els);
1752 let if_t = if !ty::type_is_bot(fcx.ccx.tcx, els_t) {
1757 (if_t, thn_bot & els_bot)
1760 check_block_no_value(fcx, thn);
1761 (ty::mk_nil(fcx.ccx.tcx), false)
1764 write::ty_only_fixup(fcx, id, if_t);
1768 fn binop_method(op: ast::binop) -> option::t<str> {
1770 ast::add | ast::subtract | ast::mul | ast::div | ast::rem |
1771 ast::bitxor | ast::bitand | ast::bitor | ast::lsl | ast::lsr |
1772 ast::asr { some(ast_util::binop_to_str(op)) }
1776 fn lookup_op_method(fcx: @fn_ctxt, op_ex: @ast::expr, self_t: ty::t,
1778 args: [option::t<@ast::expr>]) -> option::t<ty::t> {
1779 let isc = fcx.ccx.impl_map.get(op_ex.id);
1780 alt lookup_method(fcx, isc, opname, self_t, op_ex.span) {
1781 some({method_ty, n_tps: 0u, substs, origin}) {
1782 let callee_id = ast_util::op_expr_callee_id(op_ex);
1783 write::ty_fixup(fcx, callee_id, {substs: some(substs),
1785 check_call_or_bind(fcx, op_ex.span, method_ty, args);
1786 fcx.ccx.method_map.insert(op_ex.id, origin);
1787 some(ty::ty_fn_ret(fcx.ccx.tcx, method_ty))
1792 fn check_binop(fcx: @fn_ctxt, ex: @ast::expr, ty: ty::t,
1793 op: ast::binop, rhs: @ast::expr) -> ty::t {
1794 let resolved_t = structurally_resolved_type(fcx, ex.span, ty);
1795 let tcx = fcx.ccx.tcx;
1796 if ty::is_binopable(tcx, resolved_t, op) {
1798 ast::eq | ast::lt | ast::le | ast::ne | ast::ge |
1799 ast::gt { ty::mk_bool(tcx) }
1804 alt binop_method(op) {
1806 alt lookup_op_method(fcx, ex, resolved_t, name, [some(rhs)]) {
1807 some(ret_ty) { ret ret_ty; }
1814 ex.span, "binary operation " + ast_util::binop_to_str(op) +
1815 " cannot be applied to type `" + ty_to_str(tcx, resolved_t) +
1819 fn check_user_unop(fcx: @fn_ctxt, op_str: str, mname: str,
1820 ex: @ast::expr, rhs_t: ty::t) -> ty::t {
1821 alt lookup_op_method(fcx, ex, rhs_t, mname, []) {
1822 some(ret_ty) { ret_ty }
1824 fcx.ccx.tcx.sess.span_err(
1825 ex.span, #fmt["cannot apply unary operator `%s` to type `%s`",
1826 op_str, ty_to_str(fcx.ccx.tcx, rhs_t)]);
1832 let tcx = fcx.ccx.tcx;
1836 ast::expr_lit(lit) {
1837 let typ = check_lit(fcx.ccx, lit);
1838 write::ty_only_fixup(fcx, id, typ);
1840 ast::expr_binary(binop, lhs, rhs) {
1841 let lhs_t = next_ty_var(fcx);
1842 bot = check_expr_with(fcx, lhs, lhs_t);
1844 let rhs_bot = check_expr_with(fcx, rhs, lhs_t);
1845 if !ast_util::lazy_binop(binop) { bot |= rhs_bot; }
1847 let result = check_binop(fcx, expr, lhs_t, binop, rhs);
1848 write::ty_only_fixup(fcx, id, result);
1850 ast::expr_assign_op(op, lhs, rhs) {
1851 require_impure(tcx.sess, fcx.purity, expr.span);
1852 bot = check_assignment(fcx, expr.span, lhs, rhs, id);
1853 let lhs_t = ty::expr_ty(tcx, lhs);
1854 let result = check_binop(fcx, expr, lhs_t, op, rhs);
1855 demand::simple(fcx, expr.span, result, lhs_t);
1857 ast::expr_unary(unop, oper) {
1858 bot = check_expr(fcx, oper);
1859 let oper_t = expr_ty(tcx, oper);
1861 ast::box(mut) { oper_t = ty::mk_box(tcx, {ty: oper_t, mut: mut}); }
1863 oper_t = ty::mk_uniq(tcx, {ty: oper_t, mut: mut});
1866 alt structure_of(fcx, expr.span, oper_t) {
1867 ty::ty_box(inner) { oper_t = inner.ty; }
1868 ty::ty_uniq(inner) { oper_t = inner.ty; }
1869 ty::ty_res(_, inner, _) { oper_t = inner; }
1870 ty::ty_enum(id, tps) {
1871 let variants = ty::enum_variants(tcx, id);
1872 if vec::len(*variants) != 1u ||
1873 vec::len(variants[0].args) != 1u {
1874 tcx.sess.span_fatal(expr.span,
1875 "can only dereference enums " +
1876 "with a single variant which has a "
1877 + "single argument");
1880 ty::substitute_type_params(tcx, tps, variants[0].args[0]);
1884 require_unsafe(tcx.sess, fcx.purity, expr.span);
1887 tcx.sess.span_fatal(expr.span,
1888 "dereferencing non-" +
1889 "dereferenceable type: " +
1890 ty_to_str(tcx, oper_t));
1895 oper_t = structurally_resolved_type(fcx, oper.span, oper_t);
1896 if !(ty::type_is_integral(tcx, oper_t) ||
1897 ty::struct(tcx, oper_t) == ty::ty_bool) {
1898 oper_t = check_user_unop(fcx, "!", "!", expr, oper_t);
1902 oper_t = structurally_resolved_type(fcx, oper.span, oper_t);
1903 if !(ty::type_is_integral(tcx, oper_t) ||
1904 ty::type_is_fp(tcx, oper_t)) {
1905 oper_t = check_user_unop(fcx, "-", "unary-", expr, oper_t);
1909 write::ty_only_fixup(fcx, id, oper_t);
1911 ast::expr_path(pth) {
1912 let defn = lookup_def(fcx, pth.span, id);
1914 let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn);
1915 if ty::def_has_ty_params(defn) {
1916 let path_tpot = instantiate_path(fcx, pth, tpt, expr.span);
1917 write::ty_fixup(fcx, id, path_tpot);
1919 // The definition doesn't take type parameters. If the programmer
1920 // supplied some, that's an error
1921 if vec::len::<@ast::ty>(pth.node.types) > 0u {
1922 tcx.sess.span_fatal(expr.span,
1923 "this kind of value does not \
1924 take type parameters");
1926 write::ty_only_fixup(fcx, id, tpt.ty);
1929 ast::expr_mac(_) { tcx.sess.bug("unexpanded macro"); }
1930 ast::expr_fail(expr_opt) {
1933 none {/* do nothing */ }
1934 some(e) { check_expr_with(fcx, e, ty::mk_str(tcx)); }
1936 write::bot_ty(tcx, id);
1938 ast::expr_break { write::bot_ty(tcx, id); bot = true; }
1939 ast::expr_cont { write::bot_ty(tcx, id); bot = true; }
1940 ast::expr_ret(expr_opt) {
1944 let nil = ty::mk_nil(tcx);
1945 if !are_compatible(fcx, fcx.ret_ty, nil) {
1946 tcx.sess.span_err(expr.span,
1947 "ret; in function returning non-nil");
1950 some(e) { check_expr_with(fcx, e, fcx.ret_ty); }
1952 write::bot_ty(tcx, id);
1955 // FIXME: prove instead of assert
1956 assert (ast_util::is_call_expr(e));
1957 check_expr_with(fcx, e, fcx.ret_ty);
1959 write::nil_ty(tcx, id);
1961 ast::expr_log(_, lv, e) {
1962 bot = check_expr_with(fcx, lv, ty::mk_mach_uint(tcx, ast::ty_u32));
1963 bot |= check_expr(fcx, e);
1964 write::nil_ty(tcx, id);
1966 ast::expr_check(_, e) {
1967 bot = check_pred_expr(fcx, e);
1968 write::nil_ty(tcx, id);
1970 ast::expr_if_check(cond, thn, elsopt) {
1972 check_pred_expr(fcx, cond) |
1973 check_then_else(fcx, thn, elsopt, id, expr.span);
1975 ast::expr_ternary(_, _, _) {
1976 bot = check_expr(fcx, ast_util::ternary_to_if(expr));
1978 ast::expr_assert(e) {
1979 bot = check_expr_with(fcx, e, ty::mk_bool(tcx));
1980 write::nil_ty(tcx, id);
1983 bot = check_expr_with_unifier(fcx, a, unify, expected);
1985 ty::node_id_to_ty_param_substs_opt_and_ty(tcx, a.id);
1986 write::ty_fixup(fcx, id, tpot);
1989 ast::expr_move(lhs, rhs) {
1990 require_impure(tcx.sess, fcx.purity, expr.span);
1991 bot = check_assignment(fcx, expr.span, lhs, rhs, id);
1993 ast::expr_assign(lhs, rhs) {
1994 require_impure(tcx.sess, fcx.purity, expr.span);
1995 bot = check_assignment(fcx, expr.span, lhs, rhs, id);
1997 ast::expr_swap(lhs, rhs) {
1998 require_impure(tcx.sess, fcx.purity, expr.span);
1999 bot = check_assignment(fcx, expr.span, lhs, rhs, id);
2001 ast::expr_if(cond, thn, elsopt) {
2003 check_expr_with(fcx, cond, ty::mk_bool(tcx)) |
2004 check_then_else(fcx, thn, elsopt, id, expr.span);
2006 ast::expr_for(decl, seq, body) {
2007 bot = check_expr(fcx, seq);
2009 let ety = expr_ty(tcx, seq);
2010 alt structure_of(fcx, expr.span, ety) {
2011 ty::ty_vec(vec_elt_ty) { elt_ty = vec_elt_ty.ty; }
2012 ty::ty_str { elt_ty = ty::mk_mach_uint(tcx, ast::ty_u8); }
2014 tcx.sess.span_fatal(expr.span,
2015 "mismatched types: expected vector or string "
2016 + "but found `" + ty_to_str(tcx, ety) + "`");
2019 bot |= check_for(fcx, decl, elt_ty, body, id);
2021 ast::expr_while(cond, body) {
2022 bot = check_expr_with(fcx, cond, ty::mk_bool(tcx));
2023 check_block_no_value(fcx, body);
2024 write::ty_only_fixup(fcx, id, ty::mk_nil(tcx));
2026 ast::expr_do_while(body, cond) {
2027 bot = check_expr_with(fcx, cond, ty::mk_bool(tcx)) |
2028 check_block_no_value(fcx, body);
2029 write::ty_only_fixup(fcx, id, block_ty(tcx, body));
2031 ast::expr_alt(expr, arms) {
2032 bot = check_expr(fcx, expr);
2034 // Typecheck the patterns first, so that we get types for all the
2036 let pattern_ty = ty::expr_ty(tcx, expr);
2037 for arm: ast::arm in arms {
2038 let id_map = pat_util::pat_id_map(tcx, arm.pats[0]);
2039 for p: @ast::pat in arm.pats {
2040 check_pat(fcx, id_map, p, pattern_ty);
2043 // Now typecheck the blocks.
2044 let result_ty = next_ty_var(fcx);
2045 let arm_non_bot = false;
2046 for arm: ast::arm in arms {
2048 some(e) { check_expr_with(fcx, e, ty::mk_bool(tcx)); }
2051 if !check_block(fcx, arm.body) { arm_non_bot = true; }
2052 let bty = block_ty(tcx, arm.body);
2053 result_ty = demand::simple(fcx, arm.body.span, result_ty, bty);
2055 bot |= !arm_non_bot;
2056 if !arm_non_bot { result_ty = ty::mk_bot(tcx); }
2057 write::ty_only_fixup(fcx, id, result_ty);
2059 ast::expr_fn(proto, decl, body, captures) {
2060 check_expr_fn_with_unifier(fcx, expr, proto, decl, body,
2062 capture::check_capture_clause(tcx, expr.id, proto, *captures);
2064 ast::expr_fn_block(decl, body) {
2065 // Take the prototype from the expected type, but default to block:
2066 let proto = alt ty::struct(tcx, expected) {
2067 ty::ty_fn({proto, _}) { proto }
2069 tcx.sess.span_warn(expr.span, "unable to infer kind of closure, \
2070 defaulting to block");
2074 #debug("checking expr_fn_block %s expected=%s",
2076 ty_to_str(tcx, expected));
2077 check_expr_fn_with_unifier(fcx, expr, proto, decl, body,
2079 write::ty_only_fixup(fcx, id, expected);
2081 ast::expr_block(b) {
2082 // If this is an unchecked block, turn off purity-checking
2083 bot = check_block(fcx, b);
2086 some(expr) { expr_ty(tcx, expr) }
2087 none { ty::mk_nil(tcx) }
2089 write::ty_only_fixup(fcx, id, typ);
2091 ast::expr_bind(f, args) {
2092 // Call the generic checker.
2093 bot = check_expr(fcx, f);
2094 bot |= check_call_or_bind(fcx, expr.span, expr_ty(tcx, f), args);
2096 // Pull the argument and return types out.
2097 let proto, arg_tys, rt, cf, constrs;
2098 alt structure_of(fcx, expr.span, expr_ty(tcx, f)) {
2100 // probably need to munge the constrs to drop constraints
2101 // for any bound args
2107 constrs = f.constraints;
2109 _ { fail "LHS of bind expr didn't have a function type?!"; }
2112 // For each blank argument, add the type of that argument
2113 // to the resulting function type.
2116 while i < vec::len(args) {
2118 some(_) {/* no-op */ }
2119 none { out_args += [arg_tys[i]]; }
2124 // Determine what fn prototype results from binding
2125 fn lower_bound_proto(proto: ast::proto) -> ast::proto {
2126 // FIXME: This is right for bare fns, possibly not others
2128 ast::proto_bare { ast::proto_box }
2133 let ft = ty::mk_fn(tcx, {proto: lower_bound_proto(proto),
2134 inputs: out_args, output: rt,
2135 ret_style: cf, constraints: constrs});
2136 write::ty_only_fixup(fcx, id, ft);
2138 ast::expr_call(f, args, _) {
2139 bot = check_call_full(fcx, expr.span, f, args, expr.id);
2141 ast::expr_cast(e, t) {
2142 bot = check_expr(fcx, e);
2143 let t_1 = ast_ty_to_ty_crate(fcx.ccx, t);
2144 let t_e = ty::expr_ty(tcx, e);
2146 alt ty::struct(tcx, t_1) {
2147 // This will be looked up later on
2148 ty::ty_iface(_, _) {}
2150 if ty::type_is_nil(tcx, t_e) {
2151 tcx.sess.span_err(expr.span, "cast from nil: " +
2152 ty_to_str(tcx, t_e) + " as " +
2153 ty_to_str(tcx, t_1));
2154 } else if ty::type_is_nil(tcx, t_1) {
2155 tcx.sess.span_err(expr.span, "cast to nil: " +
2156 ty_to_str(tcx, t_e) + " as " +
2157 ty_to_str(tcx, t_1));
2160 let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1);
2161 if type_is_c_like_enum(fcx,expr.span,t_e) && t_1_is_scalar {
2162 /* this case is allowed */
2163 } else if !(type_is_scalar(fcx,expr.span,t_e) && t_1_is_scalar) {
2164 // FIXME there are more forms of cast to support, eventually.
2165 tcx.sess.span_err(expr.span,
2166 "non-scalar cast: " +
2167 ty_to_str(tcx, t_e) + " as " +
2168 ty_to_str(tcx, t_1));
2172 write::ty_only_fixup(fcx, id, t_1);
2174 ast::expr_vec(args, mut) {
2175 let t: ty::t = next_ty_var(fcx);
2176 for e: @ast::expr in args { bot |= check_expr_with(fcx, e, t); }
2177 let typ = ty::mk_vec(tcx, {ty: t, mut: mut});
2178 write::ty_only_fixup(fcx, id, typ);
2180 ast::expr_tup(elts) {
2182 vec::reserve(elt_ts, vec::len(elts));
2185 let ety = expr_ty(tcx, e);
2188 let typ = ty::mk_tup(tcx, elt_ts);
2189 write::ty_only_fixup(fcx, id, typ);
2191 ast::expr_rec(fields, base) {
2192 alt base { none {/* no-op */ } some(b_0) { check_expr(fcx, b_0); } }
2193 let fields_t: [spanned<field>] = [];
2194 for f: ast::field in fields {
2195 bot |= check_expr(fcx, f.node.expr);
2196 let expr_t = expr_ty(tcx, f.node.expr);
2197 let expr_mt = {ty: expr_t, mut: f.node.mut};
2198 // for the most precise error message,
2199 // should be f.node.expr.span, not f.span
2201 [respan(f.node.expr.span,
2202 {ident: f.node.ident, mt: expr_mt})];
2206 fn get_node(f: spanned<field>) -> field { f.node }
2207 let typ = ty::mk_rec(tcx, vec::map(fields_t, get_node));
2208 write::ty_only_fixup(fcx, id, typ);
2211 bot |= check_expr(fcx, bexpr);
2212 let bexpr_t = expr_ty(tcx, bexpr);
2213 let base_fields: [field] = [];
2214 alt structure_of(fcx, expr.span, bexpr_t) {
2215 ty::ty_rec(flds) { base_fields = flds; }
2217 tcx.sess.span_fatal(expr.span,
2218 "record update has non-record base");
2221 write::ty_only_fixup(fcx, id, bexpr_t);
2222 for f: spanned<ty::field> in fields_t {
2224 for bf: ty::field in base_fields {
2225 if str::eq(f.node.ident, bf.ident) {
2226 demand::simple(fcx, f.span, bf.mt.ty, f.node.mt.ty);
2231 tcx.sess.span_fatal(f.span,
2232 "unknown field in record update: " +
2239 ast::expr_field(base, field, tys) {
2240 bot |= check_expr(fcx, base);
2241 let expr_t = structurally_resolved_type(fcx, expr.span,
2242 expr_ty(tcx, base));
2243 let base_t = do_autoderef(fcx, expr.span, expr_t);
2244 let handled = false, n_tys = vec::len(tys);
2245 alt structure_of(fcx, expr.span, base_t) {
2246 ty::ty_rec(fields) {
2247 alt ty::field_idx(field, fields) {
2250 tcx.sess.span_err(expr.span,
2251 "can't provide type parameters \
2252 to a field access");
2254 write::ty_only_fixup(fcx, id, fields[ix].mt.ty);
2263 let iscope = fcx.ccx.impl_map.get(expr.id);
2264 alt lookup_method(fcx, iscope, field, expr_t, expr.span) {
2265 some({method_ty: fty, n_tps: method_n_tps, substs, origin}) {
2266 let substs = substs, n_tps = vec::len(substs);
2267 if method_n_tps + n_tps > 0u {
2269 if n_tys != method_n_tps {
2271 (expr.span, "incorrect number of type \
2272 parameters given for this method");
2276 substs += [ast_ty_to_ty_crate(fcx.ccx, ty)];
2280 while i < method_n_tps {
2281 substs += [ty::mk_var(tcx, next_ty_var_id(fcx))];
2285 write::ty_fixup(fcx, id, {substs: some(substs), ty: fty});
2286 } else if n_tys > 0u {
2287 tcx.sess.span_fatal(expr.span,
2288 "this method does not take type \
2291 write::ty_only_fixup(fcx, id, fty);
2293 fcx.ccx.method_map.insert(id, origin);
2296 let t_err = resolve_type_vars_if_possible(fcx, expr_t);
2297 let msg = #fmt["attempted access of field %s on type %s, but \
2298 no method implementation was found",
2299 field, ty_to_str(tcx, t_err)];
2300 tcx.sess.span_err(expr.span, msg);
2301 // NB: Adding a bogus type to allow typechecking to continue
2302 write::ty_only_fixup(fcx, id, ty::mk_nil(tcx));
2307 ast::expr_index(base, idx) {
2308 bot |= check_expr(fcx, base);
2309 let raw_base_t = expr_ty(tcx, base);
2310 let base_t = do_autoderef(fcx, expr.span, raw_base_t);
2311 bot |= check_expr(fcx, idx);
2312 let idx_t = expr_ty(tcx, idx);
2313 fn require_integral(fcx: @fn_ctxt, sp: span, t: ty::t) {
2314 if !type_is_integral(fcx, sp, t) {
2315 fcx.ccx.tcx.sess.span_err(sp, "mismatched types: expected \
2316 `integer` but found `"
2317 + ty_to_str(fcx.ccx.tcx, t) + "`");
2320 alt structure_of(fcx, expr.span, base_t) {
2322 require_integral(fcx, idx.span, idx_t);
2323 write::ty_only_fixup(fcx, id, mt.ty);
2326 require_integral(fcx, idx.span, idx_t);
2327 let typ = ty::mk_mach_uint(tcx, ast::ty_u8);
2328 write::ty_only_fixup(fcx, id, typ);
2331 let resolved = structurally_resolved_type(fcx, expr.span,
2333 alt lookup_op_method(fcx, expr, resolved, "[]",
2335 some(ret_ty) { write::ty_only_fixup(fcx, id, ret_ty); }
2337 tcx.sess.span_fatal(
2338 expr.span, "cannot index a value of type `" +
2339 ty_to_str(tcx, base_t) + "`");
2345 _ { tcx.sess.unimpl("expr type in typeck::check_expr"); }
2347 if bot { write::ty_only_fixup(fcx, expr.id, ty::mk_bot(tcx)); }
2349 unify(fcx, expr.span, expected, expr_ty(tcx, expr));
2353 fn next_ty_var_id(fcx: @fn_ctxt) -> int {
2354 let id = *fcx.next_var_id;
2355 *fcx.next_var_id += 1;
2359 fn next_ty_var(fcx: @fn_ctxt) -> ty::t {
2360 ret ty::mk_var(fcx.ccx.tcx, next_ty_var_id(fcx));
2363 fn bind_params(fcx: @fn_ctxt, tp: ty::t, count: uint)
2364 -> {vars: [ty::t], ty: ty::t} {
2365 let vars = vec::init_fn(count, {|_i| next_ty_var(fcx)});
2366 {vars: vars, ty: ty::substitute_type_params(fcx.ccx.tcx, vars, tp)}
2369 fn get_self_info(ccx: @crate_ctxt) -> option::t<self_info> {
2370 ret vec::last(ccx.self_infos);
2373 fn check_decl_initializer(fcx: @fn_ctxt, nid: ast::node_id,
2374 init: ast::initializer) -> bool {
2375 let lty = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, init.expr.span, nid));
2376 ret check_expr_with(fcx, init.expr, lty);
2379 fn check_decl_local(fcx: @fn_ctxt, local: @ast::local) -> bool {
2382 alt fcx.locals.find(local.node.id) {
2384 let t = ty::mk_var(fcx.ccx.tcx, i);
2385 write::ty_only_fixup(fcx, local.node.id, t);
2386 alt local.node.init {
2388 bot = check_decl_initializer(fcx, local.node.id, init);
2390 _ {/* fall through */ }
2392 let id_map = pat_util::pat_id_map(fcx.ccx.tcx, local.node.pat);
2393 check_pat(fcx, id_map, local.node.pat, t);
2399 fn check_stmt(fcx: @fn_ctxt, stmt: @ast::stmt) -> bool {
2403 ast::stmt_decl(decl, id) {
2406 ast::decl_local(ls) {
2407 for (_, l) in ls { bot |= check_decl_local(fcx, l); }
2409 ast::decl_item(_) {/* ignore for now */ }
2412 ast::stmt_expr(expr, id) {
2414 bot = check_expr_with(fcx, expr, ty::mk_nil(fcx.ccx.tcx));
2416 ast::stmt_semi(expr, id) {
2418 bot = check_expr(fcx, expr);
2421 write::nil_ty(fcx.ccx.tcx, node_id);
2425 fn check_block_no_value(fcx: @fn_ctxt, blk: ast::blk) -> bool {
2426 let bot = check_block(fcx, blk);
2428 let blkty = ty::node_id_to_monotype(fcx.ccx.tcx, blk.node.id);
2429 let nilty = ty::mk_nil(fcx.ccx.tcx);
2430 demand::simple(fcx, blk.span, nilty, blkty);
2435 fn check_block(fcx0: @fn_ctxt, blk: ast::blk) -> bool {
2436 let fcx = alt blk.node.rules {
2437 ast::unchecked_blk { @{purity: ast::impure_fn with *fcx0} }
2438 ast::unsafe_blk { @{purity: ast::unsafe_fn with *fcx0} }
2439 ast::default_blk { fcx0 }
2443 for s: @ast::stmt in blk.node.stmts {
2444 if bot && !warned &&
2446 ast::stmt_decl(@{node: ast::decl_local(_), _}, _) |
2447 ast::stmt_expr(_, _) | ast::stmt_semi(_, _) {
2452 fcx.ccx.tcx.sess.span_warn(s.span, "unreachable statement");
2455 bot |= check_stmt(fcx, s);
2458 none { write::nil_ty(fcx.ccx.tcx, blk.node.id); }
2461 fcx.ccx.tcx.sess.span_warn(e.span, "unreachable expression");
2463 bot |= check_expr(fcx, e);
2464 let ety = expr_ty(fcx.ccx.tcx, e);
2465 write::ty_only_fixup(fcx, blk.node.id, ety);
2469 write::ty_only_fixup(fcx, blk.node.id, ty::mk_bot(fcx.ccx.tcx));
2474 fn check_const(ccx: @crate_ctxt, _sp: span, e: @ast::expr, id: ast::node_id) {
2475 // FIXME: this is kinda a kludge; we manufacture a fake function context
2476 // and statement context for checking the initializer expression.
2477 let rty = node_id_to_type(ccx.tcx, id);
2478 let fixups: [ast::node_id] = [];
2481 purity: ast::pure_fn,
2482 proto: ast::proto_box,
2483 var_bindings: ty::unify::mk_var_bindings(),
2484 locals: new_int_hash::<int>(),
2485 next_var_id: @mutable 0,
2486 mutable fixups: fixups,
2489 let cty = expr_ty(fcx.ccx.tcx, e);
2490 let declty = fcx.ccx.tcx.tcache.get(local_def(id)).ty;
2491 demand::simple(fcx, e.span, declty, cty);
2494 fn check_enum_variants(ccx: @crate_ctxt, sp: span, vs: [ast::variant],
2496 // FIXME: this is kinda a kludge; we manufacture a fake function context
2497 // and statement context for checking the initializer expression.
2498 let rty = node_id_to_type(ccx.tcx, id);
2499 let fixups: [ast::node_id] = [];
2502 purity: ast::pure_fn,
2503 proto: ast::proto_box,
2504 var_bindings: ty::unify::mk_var_bindings(),
2505 locals: new_int_hash::<int>(),
2506 next_var_id: @mutable 0,
2507 mutable fixups: fixups,
2509 let disr_vals: [int] = [];
2512 alt v.node.disr_expr {
2515 let cty = expr_ty(fcx.ccx.tcx, e);
2516 let declty = ty::mk_int(fcx.ccx.tcx);
2517 demand::simple(fcx, e.span, declty, cty);
2518 // FIXME: issue #1417
2519 // Also, check_expr (from check_const pass) doesn't guarantee that
2520 // the expression in an form that eval_const_expr can handle, so
2521 // we may still get an internal compiler error
2522 alt syntax::ast_util::eval_const_expr(e) {
2523 syntax::ast_util::const_int(val) {
2524 disr_val = val as int;
2527 ccx.tcx.sess.span_err(e.span,
2528 "expected signed integer constant");
2534 if vec::member(disr_val, disr_vals) {
2535 ccx.tcx.sess.span_err(v.span,
2536 "discriminator value already exists.");
2538 disr_vals += [disr_val];
2541 let outer = true, did = local_def(id);
2542 if ty::type_structurally_contains(ccx.tcx, rty, {|sty|
2544 ty::ty_enum(id, _) if id == did {
2545 if outer { outer = false; false }
2551 ccx.tcx.sess.span_fatal(sp, "illegal recursive enum type. \
2552 wrap the inner value in a box to \
2553 make it represenable");
2557 // A generic function for checking the pred in a check
2559 fn check_pred_expr(fcx: @fn_ctxt, e: @ast::expr) -> bool {
2560 let bot = check_expr_with(fcx, e, ty::mk_bool(fcx.ccx.tcx));
2562 /* e must be a call expr where all arguments are either
2563 literals or slots */
2565 ast::expr_call(operator, operands, _) {
2566 if !ty::is_pred_ty(fcx.ccx.tcx, expr_ty(fcx.ccx.tcx, operator)) {
2567 fcx.ccx.tcx.sess.span_err
2569 "operator in constraint has non-boolean return type");
2573 ast::expr_path(oper_name) {
2574 alt fcx.ccx.tcx.def_map.find(operator.id) {
2575 some(ast::def_fn(_, ast::pure_fn)) {
2579 fcx.ccx.tcx.sess.span_err(operator.span,
2580 "Impure function as operator \
2584 for operand: @ast::expr in operands {
2585 if !ast_util::is_constraint_arg(operand) {
2587 "Constraint args must be slot variables or literals";
2588 fcx.ccx.tcx.sess.span_err(e.span, s);
2593 let s = "In a constraint, expected the \
2594 constraint name to be an explicit name";
2595 fcx.ccx.tcx.sess.span_err(e.span, s);
2599 _ { fcx.ccx.tcx.sess.span_err(e.span, "check on non-predicate"); }
2604 fn check_constraints(fcx: @fn_ctxt, cs: [@ast::constr], args: [ast::arg]) {
2606 let num_args = vec::len(args);
2607 for c: @ast::constr in cs {
2609 for a: @spanned<ast::fn_constr_arg> in c.node.args {
2611 // "base" should not occur in a fn type thing, as of
2612 // yet, b/c we don't allow constraints on the return type
2614 // Works b/c no higher-order polymorphism
2616 This is kludgy, and we probably shouldn't be assigning
2617 node IDs here, but we're creating exprs that are
2618 ephemeral, just for the purposes of typechecking. So
2619 that's my justification.
2623 fcx.ccx.tcx.sess.span_bug(a.span,
2624 "check_constraints:\
2625 unexpected carg_base");
2628 let tmp_node_id = fcx.ccx.tcx.sess.next_node_id();
2629 {id: tmp_node_id, node: ast::expr_lit(l), span: a.span}
2631 ast::carg_ident(i) {
2635 idents: [args[i].ident],
2637 let arg_occ_node_id =
2638 fcx.ccx.tcx.sess.next_node_id();
2639 fcx.ccx.tcx.def_map.insert
2641 ast::def_arg(local_def(args[i].id),
2643 {id: arg_occ_node_id,
2644 node: ast::expr_path(@respan(a.span, p)),
2647 fcx.ccx.tcx.sess.span_bug(a.span,
2648 "check_constraints:\
2649 carg_ident index out of bounds");
2654 let p_op: ast::expr_ = ast::expr_path(c.node.path);
2655 let oper: @ast::expr = @{id: c.node.id, node: p_op, span: c.span};
2656 // Another ephemeral expr
2657 let call_expr_id = fcx.ccx.tcx.sess.next_node_id();
2660 node: ast::expr_call(oper, c_args, false),
2662 check_pred_expr(fcx, call_expr);
2666 fn check_fn(ccx: @crate_ctxt,
2671 old_fcx: option::t<@fn_ctxt>) {
2672 // If old_fcx is some(...), this is a block fn { |x| ... }.
2673 // In that case, the purity is inherited from the context.
2674 let purity = alt old_fcx {
2675 none { decl.purity }
2676 some(f) { assert decl.purity == ast::impure_fn; f.purity }
2679 let gather_result = gather_locals(ccx, decl, body, id, old_fcx);
2680 let fixups: [ast::node_id] = [];
2682 @{ret_ty: ty::ty_fn_ret(ccx.tcx, ty::node_id_to_type(ccx.tcx, id)),
2685 var_bindings: gather_result.var_bindings,
2686 locals: gather_result.locals,
2687 next_var_id: gather_result.next_var_id,
2688 mutable fixups: fixups,
2691 check_constraints(fcx, decl.constraints, decl.inputs);
2692 check_block(fcx, body);
2694 // We unify the tail expr's type with the
2695 // function result type, if there is a tail expr.
2696 alt body.node.expr {
2698 let tail_expr_ty = expr_ty(ccx.tcx, tail_expr);
2699 demand::simple(fcx, tail_expr.span, fcx.ret_ty, tail_expr_ty);
2704 let args = ty::ty_fn_args(ccx.tcx, ty::node_id_to_type(ccx.tcx, id));
2706 for arg: ty::arg in args {
2707 write::ty_only_fixup(fcx, decl.inputs[i].id, arg.ty);
2711 // If we don't have any enclosing function scope, it is time to
2712 // force any remaining type vars to be resolved.
2713 // If we have an enclosing function scope, our type variables will be
2714 // resolved when the enclosing scope finishes up.
2715 if option::is_none(old_fcx) {
2716 dict::resolve_in_block(fcx, body);
2717 writeback::resolve_type_vars_in_block(fcx, body);
2721 fn check_method(ccx: @crate_ctxt, method: @ast::method) {
2722 check_fn(ccx, ast::proto_bare, method.decl, method.body, method.id, none);
2725 fn check_item(ccx: @crate_ctxt, it: @ast::item) {
2727 ast::item_const(_, e) { check_const(ccx, it.span, e, it.id); }
2728 ast::item_enum(vs, _) { check_enum_variants(ccx, it.span, vs, it.id); }
2729 ast::item_fn(decl, tps, body) {
2730 check_fn(ccx, ast::proto_bare, decl, body, it.id, none);
2732 ast::item_res(decl, tps, body, dtor_id, _) {
2733 check_fn(ccx, ast::proto_bare, decl, body, dtor_id, none);
2735 ast::item_impl(tps, _, ty, ms) {
2736 ccx.self_infos += [self_impl(ast_ty_to_ty(ccx.tcx, m_check, ty))];
2737 for m in ms { check_method(ccx, m); }
2738 vec::pop(ccx.self_infos);
2740 _ {/* nothing to do */ }
2744 fn arg_is_argv_ty(tcx: ty::ctxt, a: ty::arg) -> bool {
2745 alt ty::struct(tcx, a.ty) {
2747 if mt.mut != ast::imm { ret false; }
2748 alt ty::struct(tcx, mt.ty) {
2749 ty::ty_str { ret true; }
2757 fn check_main_fn_ty(tcx: ty::ctxt, main_id: ast::node_id) {
2758 let main_t = ty::node_id_to_monotype(tcx, main_id);
2759 alt ty::struct(tcx, main_t) {
2760 ty::ty_fn({proto: ast::proto_bare, inputs, output,
2761 ret_style: ast::return_val, constraints}) {
2762 let ok = vec::len(constraints) == 0u;
2763 ok &= ty::type_is_nil(tcx, output);
2764 let num_args = vec::len(inputs);
2765 ok &= num_args == 0u || num_args == 1u &&
2766 arg_is_argv_ty(tcx, inputs[0]);
2768 let span = ast_map::node_span(tcx.items.get(main_id));
2769 tcx.sess.span_err(span,
2770 "wrong type in main function: found `" +
2771 ty_to_str(tcx, main_t) + "`");
2775 let span = ast_map::node_span(tcx.items.get(main_id));
2776 tcx.sess.span_bug(span,
2777 "main has a non-function type: found `" +
2778 ty_to_str(tcx, main_t) + "`");
2783 fn check_for_main_fn(tcx: ty::ctxt, crate: @ast::crate) {
2784 if !tcx.sess.building_library {
2785 alt tcx.sess.main_fn {
2786 some(id) { check_main_fn_ty(tcx, id); }
2787 none { tcx.sess.span_err(crate.span, "main function not found"); }
2793 fn has_iface_bounds(tps: [ty::param_bounds]) -> bool {
2796 alt b { ty::bound_iface(_) { true } _ { false } }
2801 fn lookup_dicts(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
2802 bounds: @[ty::param_bounds], tys: [ty::t])
2804 let tcx = fcx.ccx.tcx, result = [], i = 0u;
2806 for bound in *bounds[i] {
2808 ty::bound_iface(i_ty) {
2809 let i_ty = ty::substitute_type_params(tcx, tys, i_ty);
2810 result += [lookup_dict(fcx, isc, sp, ty, i_ty)];
2820 fn lookup_dict(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
2821 ty: ty::t, iface_ty: ty::t) -> dict_origin {
2822 let tcx = fcx.ccx.tcx;
2823 let (iface_id, iface_tps) = alt ty::struct(tcx, iface_ty) {
2824 ty::ty_iface(did, tps) { (did, tps) }
2826 let ty = fixup_ty(fcx, sp, ty);
2827 alt ty::struct(tcx, ty) {
2828 ty::ty_param(n, did) {
2830 for bound in *tcx.ty_param_bounds.get(did.node) {
2832 ty::bound_iface(ity) {
2833 alt ty::struct(tcx, ity) {
2834 ty::ty_iface(idid, _) {
2835 if iface_id == idid { ret dict_param(n, n_bound); }
2844 ty::ty_iface(did, _) {
2845 ret dict_iface(did);
2849 std::list::iter(isc) {|impls|
2850 if option::is_some(found) { ret; }
2852 let match = alt ty::impl_iface(tcx, im.did) {
2854 alt ty::struct(tcx, ity) {
2855 ty::ty_iface(id, _) { id == iface_id }
2861 let {n_tps, ty: self_ty} = impl_self_ty(tcx, im.did);
2862 let {vars, ty: self_ty} = if n_tps > 0u {
2863 bind_params(fcx, self_ty, n_tps)
2864 } else { {vars: [], ty: self_ty} };
2865 let im_bs = ty::lookup_item_type(tcx, im.did).bounds;
2866 alt unify::unify(fcx, ty, self_ty) {
2868 if option::is_some(found) {
2870 sp, "multiple applicable implementations \
2873 connect_iface_tps(fcx, sp, vars, iface_tps,
2875 let params = vec::map(vars, {|t|
2876 fixup_ty(fcx, sp, t)});
2877 let subres = lookup_dicts(fcx, isc, sp, im_bs,
2879 found = some(dict_static(im.did, params,
2889 some(rslt) { ret rslt; }
2895 tcx.sess.span_fatal(
2896 sp, "failed to find an implementation of interface " +
2897 ty_to_str(tcx, iface_ty) + " for " +
2898 ty_to_str(tcx, ty));
2901 fn fixup_ty(fcx: @fn_ctxt, sp: span, ty: ty::t) -> ty::t {
2902 let tcx = fcx.ccx.tcx;
2903 alt ty::unify::fixup_vars(tcx, some(sp), fcx.var_bindings, ty) {
2904 fix_ok(new_type) { new_type }
2906 tcx.sess.span_fatal(sp, "could not determine a type for a \
2907 bounded type parameter");
2912 fn connect_iface_tps(fcx: @fn_ctxt, sp: span, impl_tys: [ty::t],
2913 iface_tys: [ty::t], impl_did: ast::def_id) {
2914 let tcx = fcx.ccx.tcx;
2915 let ity = option::get(ty::impl_iface(tcx, impl_did));
2916 let iface_ty = ty::substitute_type_params(tcx, impl_tys, ity);
2917 alt ty::struct(tcx, iface_ty) {
2918 ty::ty_iface(_, tps) {
2919 vec::iter2(tps, iface_tys,
2920 {|a, b| demand::simple(fcx, sp, a, b);});
2925 fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) {
2929 let substs = ty::node_id_to_ty_param_substs_opt_and_ty(
2933 let did = ast_util::def_id_of_def(cx.tcx.def_map.get(ex.id));
2934 let item_ty = ty::lookup_item_type(cx.tcx, did);
2935 if has_iface_bounds(*item_ty.bounds) {
2936 let impls = cx.impl_map.get(ex.id);
2937 cx.dict_map.insert(ex.id, lookup_dicts(
2938 fcx, impls, ex.span, item_ty.bounds, ts));
2944 // Must resolve bounds on methods with bounded params
2945 ast::expr_field(_, _, _) | ast::expr_binary(_, _, _) |
2946 ast::expr_unary(_, _) | ast::expr_assign_op(_, _, _) |
2947 ast::expr_index(_, _) {
2948 alt cx.method_map.find(ex.id) {
2949 some(method_static(did)) {
2950 let bounds = ty::lookup_item_type(cx.tcx, did).bounds;
2951 if has_iface_bounds(*bounds) {
2952 let callee_id = alt ex.node {
2953 ast::expr_field(_, _, _) { ex.id }
2954 _ { ast_util::op_expr_callee_id(ex) }
2956 let ts = ty::node_id_to_type_params(cx.tcx, callee_id);
2957 let iscs = cx.impl_map.get(ex.id);
2958 cx.dict_map.insert(callee_id, lookup_dicts(
2959 fcx, iscs, ex.span, bounds, ts));
2965 ast::expr_cast(src, _) {
2966 // Ifaces that refer to a self type can not be cast to -- callers
2967 // wouldn't know what self refers to.
2968 fn type_refers_to_self(tcx: ty::ctxt, t: ty::t, s_param: uint)
2971 if ty::type_contains_params(tcx, t) {
2972 ty::walk_ty(tcx, t) {|t|
2973 alt ty::struct(tcx, t) {
2974 ty::ty_param(n, _) if n == s_param { found = true; }
2981 fn method_refers_to_self(tcx: ty::ctxt, m: ty::method,
2982 s_param: uint) -> bool {
2983 vec::any(m.fty.inputs, {|in|
2984 type_refers_to_self(tcx, in.ty, s_param)
2985 }) || type_refers_to_self(tcx, m.fty.output, s_param)
2987 let target_ty = expr_ty(cx.tcx, ex);
2988 alt ty::struct(cx.tcx, target_ty) {
2989 ty::ty_iface(id, tps) {
2990 for m in *ty::iface_methods(cx.tcx, id) {
2991 if method_refers_to_self(cx.tcx, m, vec::len(tps)) {
2992 cx.tcx.sess.span_err(
2993 ex.span, "can not cast to an iface type that \
2994 refers to `self` " + m.ident);
2998 let impls = cx.impl_map.get(ex.id);
2999 let dict = lookup_dict(fcx, impls, ex.span,
3000 expr_ty(cx.tcx, src), target_ty);
3001 cx.dict_map.insert(ex.id, @[dict]);
3006 ast::expr_fn(p, _, _, _) if ast::is_blockish(p) {}
3007 ast::expr_fn(_, _, _, _) { ret; }
3010 visit::visit_expr(ex, fcx, v);
3013 // Detect points where an interface-bounded type parameter is
3014 // instantiated, resolve the impls for the parameters.
3015 fn resolve_in_block(fcx: @fn_ctxt, bl: ast::blk) {
3016 visit::visit_block(bl, fcx, visit::mk_vt(@{
3017 visit_expr: resolve_expr,
3018 visit_item: fn@(_i: @ast::item, &&_e: @fn_ctxt,
3019 _v: visit::vt<@fn_ctxt>) {}
3020 with *visit::default_visitor()
3025 fn check_crate(tcx: ty::ctxt, impl_map: resolve::impl_map,
3026 crate: @ast::crate) -> (method_map, dict_map) {
3027 collect::collect_item_types(tcx, crate);
3029 let ccx = @{mutable self_infos: [],
3031 method_map: std::map::new_int_hash(),
3032 dict_map: std::map::new_int_hash(),
3034 let visit = visit::mk_simple_visitor(@{
3035 visit_item: bind check_item(ccx, _)
3036 with *visit::default_simple_visitor()
3038 visit::visit_crate(*crate, (), visit);
3039 check_for_main_fn(tcx, crate);
3040 tcx.sess.abort_if_errors();
3041 (ccx.method_map, ccx.dict_map)
3047 // indent-tabs-mode: nil
3048 // c-basic-offset: 4
3049 // buffer-file-coding-system: utf-8-unix