| // #[warn(deprecated_mode)]; |
| #[warn(deprecated_pattern)]; |
| |
| use std::{map, smallintmap}; |
| use result::Result; |
| use std::map::HashMap; |
| use driver::session; |
| use session::session; |
| use syntax::{ast, ast_map}; |
| use syntax::ast_util; |
| use syntax::ast_util::{is_local, local_def}; |
| use syntax::codemap::span; |
| use metadata::csearch; |
| use util::ppaux::{region_to_str, explain_region, vstore_to_str, |
| note_and_explain_region}; |
| use middle::lint; |
| use middle::lint::{get_lint_level, allow}; |
| use syntax::ast::*; |
| use syntax::print::pprust::*; |
| use util::ppaux::{ty_to_str, proto_ty_to_str, tys_to_str}; |
| |
| export TyVid, IntVid, FnVid, RegionVid, vid; |
| export br_hashmap; |
| export is_instantiable; |
| export node_id_to_type; |
| export node_id_to_type_params; |
| export arg; |
| export args_eq; |
| export block_ty; |
| export class_items_as_fields, class_items_as_mutable_fields; |
| export ctxt; |
| export deref, deref_sty; |
| export index, index_sty; |
| export def_has_ty_params; |
| export expr_has_ty_params; |
| export expr_ty; |
| export expr_ty_params_and_ty; |
| export expr_is_lval, expr_kind; |
| export ExprKind, LvalueExpr, RvalueDatumExpr, RvalueDpsExpr, RvalueStmtExpr; |
| export field_ty; |
| export fold_ty, fold_sty_to_ty, fold_region, fold_regions; |
| export fold_regions_and_ty, walk_regions_and_ty; |
| export field; |
| export field_idx, field_idx_strict; |
| export get_field; |
| export get_fields; |
| export get_element_type; |
| export has_dtor; |
| export is_binopable; |
| export is_pred_ty; |
| export lookup_class_field, lookup_class_fields; |
| export lookup_class_method_by_name; |
| export lookup_field_type; |
| export lookup_item_type; |
| export lookup_public_fields; |
| export method; |
| export method_idx; |
| export mk_class; |
| export mk_ctxt; |
| export mk_with_id, type_def_id; |
| export mt; |
| export node_type_table; |
| export pat_ty; |
| export sequence_element_type; |
| export stmt_node_id; |
| export sty; |
| export subst, subst_tps, substs_is_noop, substs_to_str, substs; |
| export t; |
| export new_ty_hash; |
| export enum_variants, substd_enum_variants, enum_is_univariant; |
| export trait_methods, store_trait_methods, impl_traits; |
| export enum_variant_with_id; |
| export ty_dtor; |
| export ty_param_bounds_and_ty; |
| export ty_bool, mk_bool, type_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_opaque_closure_ptr, mk_opaque_closure_ptr; |
| export ty_opaque_box, mk_opaque_box; |
| export ty_float, mk_float, mk_mach_float, type_is_fp; |
| export ty_fn, FnTy, FnTyBase, FnMeta, FnSig, mk_fn; |
| export ty_fn_proto, ty_fn_purity, ty_fn_ret, ty_fn_ret_style, tys_in_fn_ty; |
| export ty_int, mk_int, mk_mach_int, mk_char; |
| export mk_i8, mk_u8, mk_i16, mk_u16, mk_i32, mk_u32, mk_i64, mk_u64; |
| export ty_estr, mk_estr, type_is_str; |
| export ty_evec, mk_evec, type_is_vec; |
| export ty_unboxed_vec, mk_unboxed_vec, mk_mut_unboxed_vec; |
| export vstore, vstore_fixed, vstore_uniq, vstore_box, vstore_slice; |
| export serialize_vstore, deserialize_vstore; |
| export ty_nil, mk_nil, type_is_nil; |
| export ty_trait, mk_trait; |
| export ty_param, mk_param, ty_params_to_tys; |
| export ty_ptr, mk_ptr, mk_mut_ptr, mk_imm_ptr, mk_nil_ptr, type_is_unsafe_ptr; |
| export ty_rptr, mk_rptr, mk_mut_rptr, mk_imm_rptr; |
| export ty_rec, mk_rec; |
| export ty_enum, mk_enum, type_is_enum; |
| 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_infer, mk_infer, type_is_ty_var, mk_var, mk_int_var; |
| export InferTy, TyVar, IntVar; |
| export ty_self, mk_self, type_has_self; |
| export ty_class; |
| export region, bound_region, encl_region; |
| export re_bound, re_free, re_scope, re_static, re_var; |
| export br_self, br_anon, br_named, br_cap_avoid; |
| export get, type_has_params, type_needs_infer, type_has_regions; |
| export type_is_region_ptr; |
| export type_id; |
| export tbox_has_flag; |
| export ty_var_id; |
| export ty_to_def_id; |
| export ty_fn_args; |
| export ty_region; |
| export kind, kind_implicitly_copyable, kind_send_copy, kind_copyable; |
| export kind_noncopyable, kind_const; |
| export kind_can_be_copied, kind_can_be_sent, kind_can_be_implicitly_copied; |
| export kind_is_safe_for_default_mode; |
| export kind_is_owned; |
| export meta_kind, kind_lteq, type_kind; |
| export operators; |
| export type_err, terr_vstore_kind; |
| export type_err_to_str, note_and_explain_type_err; |
| export expected_found; |
| export type_needs_drop; |
| export type_is_empty; |
| export type_is_integral; |
| export type_is_numeric; |
| export type_is_pod; |
| export type_is_scalar; |
| export type_is_immediate; |
| export type_is_borrowed; |
| export type_is_sequence; |
| export type_is_signed; |
| export type_is_structural; |
| export type_is_copyable; |
| export type_is_slice; |
| export type_is_unique; |
| export type_is_c_like_enum; |
| export type_structurally_contains; |
| export type_structurally_contains_uniques; |
| export type_autoderef, deref, deref_sty; |
| export type_param; |
| export type_needs_unwind_cleanup; |
| export canon_mode; |
| export resolved_mode; |
| export arg_mode; |
| export unify_mode; |
| export set_default_mode; |
| export variant_info; |
| export walk_ty, maybe_walk_ty; |
| export occurs_check; |
| export closure_kind; |
| export ck_block; |
| export ck_box; |
| export ck_uniq; |
| export param_ty; |
| export param_bound, param_bounds, bound_copy, bound_owned; |
| export param_bounds_to_str, param_bound_to_str; |
| export bound_send, bound_trait; |
| 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; |
| export mach_sty; |
| export ty_sort_str; |
| export normalize_ty; |
| export to_str; |
| export bound_const; |
| export terr_no_integral_type, terr_ty_param_size, terr_self_substs; |
| export terr_in_field, terr_record_fields, terr_vstores_differ, terr_arg_count; |
| export terr_sorts, terr_vec, terr_str, terr_record_size, terr_tuple_size; |
| export terr_regions_does_not_outlive, terr_mutability, terr_purity_mismatch; |
| export terr_regions_not_same, terr_regions_no_overlap; |
| export terr_proto_mismatch; |
| export terr_ret_style_mismatch; |
| export terr_fn, terr_trait; |
| export purity_to_str; |
| export param_tys_in_type; |
| export eval_repeat_count; |
| export fn_proto, proto_bare, proto_vstore; |
| export ast_proto_to_proto; |
| export is_blockish; |
| export method_call_bounds; |
| export hash_region; |
| export region_variance, rv_covariant, rv_invariant, rv_contravariant; |
| export opt_region_variance; |
| export determine_inherited_purity; |
| export provided_trait_methods; |
| export AutoAdjustment; |
| export AutoRef, AutoRefKind, AutoSlice, AutoPtr; |
| |
| // Data types |
| |
| // 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 field = {ident: ast::ident, mt: mt}; |
| |
| type param_bounds = @~[param_bound]; |
| |
| type method = {ident: ast::ident, |
| tps: @~[param_bounds], |
| fty: FnTy, |
| self_ty: ast::self_ty_, |
| vis: ast::visibility}; |
| |
| type mt = {ty: t, mutbl: ast::mutability}; |
| |
| #[auto_serialize] |
| #[auto_deserialize] |
| enum vstore { |
| vstore_fixed(uint), |
| vstore_uniq, |
| vstore_box, |
| vstore_slice(region) |
| } |
| |
| type field_ty = { |
| ident: ident, |
| id: def_id, |
| vis: ast::visibility, |
| mutability: ast::class_mutability |
| }; |
| |
| // Contains information needed to resolve types and (in the future) look up |
| // the types of AST nodes. |
| type creader_cache_key = {cnum: int, pos: uint, len: uint}; |
| type creader_cache = HashMap<creader_cache_key, t>; |
| |
| impl creader_cache_key : cmp::Eq { |
| pure fn eq(other: &creader_cache_key) -> bool { |
| self.cnum == (*other).cnum && |
| self.pos == (*other).pos && |
| self.len == (*other).len |
| } |
| pure fn ne(other: &creader_cache_key) -> bool { |
| !(self == (*other)) |
| } |
| } |
| |
| impl creader_cache_key : to_bytes::IterBytes { |
| pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) { |
| to_bytes::iter_bytes_3(&self.cnum, &self.pos, &self.len, lsb0, f); |
| } |
| } |
| |
| type intern_key = {sty: sty, o_def_id: Option<ast::def_id>}; |
| |
| impl intern_key : cmp::Eq { |
| pure fn eq(other: &intern_key) -> bool { |
| self.sty == (*other).sty && self.o_def_id == (*other).o_def_id |
| } |
| pure fn ne(other: &intern_key) -> bool { !self.eq(other) } |
| } |
| |
| impl intern_key : to_bytes::IterBytes { |
| pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) { |
| to_bytes::iter_bytes_2(&self.sty, &self.o_def_id, lsb0, f); |
| } |
| } |
| |
| enum ast_ty_to_ty_cache_entry { |
| atttce_unresolved, /* not resolved yet */ |
| atttce_resolved(t) /* resolved to a type, irrespective of region */ |
| } |
| |
| type opt_region_variance = Option<region_variance>; |
| |
| #[auto_serialize] |
| #[auto_deserialize] |
| enum region_variance { rv_covariant, rv_invariant, rv_contravariant } |
| |
| impl region_variance : cmp::Eq { |
| pure fn eq(other: ®ion_variance) -> bool { |
| match (self, (*other)) { |
| (rv_covariant, rv_covariant) => true, |
| (rv_invariant, rv_invariant) => true, |
| (rv_contravariant, rv_contravariant) => true, |
| (rv_covariant, _) => false, |
| (rv_invariant, _) => false, |
| (rv_contravariant, _) => false |
| } |
| } |
| pure fn ne(other: ®ion_variance) -> bool { !self.eq(other) } |
| } |
| |
| #[auto_serialize] |
| #[auto_deserialize] |
| type AutoAdjustment = { |
| autoderefs: uint, |
| autoref: Option<AutoRef> |
| }; |
| |
| #[auto_serialize] |
| #[auto_deserialize] |
| type AutoRef = { |
| kind: AutoRefKind, |
| region: region, |
| mutbl: ast::mutability |
| }; |
| |
| #[auto_serialize] |
| #[auto_deserialize] |
| enum AutoRefKind { |
| /// Convert from @[]/~[] to &[] (or str) |
| AutoSlice, |
| |
| /// Convert from T to &T |
| AutoPtr |
| } |
| |
| type ctxt = |
| @{diag: syntax::diagnostic::span_handler, |
| interner: HashMap<intern_key, t_box>, |
| mut next_id: uint, |
| vecs_implicitly_copyable: bool, |
| legacy_modes: bool, |
| cstore: metadata::cstore::cstore, |
| sess: session::session, |
| def_map: resolve::DefMap, |
| |
| region_map: middle::region::region_map, |
| region_paramd_items: middle::region::region_paramd_items, |
| |
| // Stores the types for various nodes in the AST. Note that this table |
| // is not guaranteed to be populated until after typeck. See |
| // typeck::check::fn_ctxt for details. |
| node_types: node_type_table, |
| |
| // Stores the type parameters which were substituted to obtain the type |
| // of this node. This only applies to nodes that refer to entities |
| // parameterized by type parameters, such as generic fns, types, or |
| // other items. |
| node_type_substs: HashMap<node_id, ~[t]>, |
| |
| items: ast_map::map, |
| intrinsic_defs: HashMap<ast::ident, (ast::def_id, t)>, |
| freevars: freevars::freevar_map, |
| tcache: type_cache, |
| rcache: creader_cache, |
| ccache: constness_cache, |
| short_names_cache: HashMap<t, @~str>, |
| needs_drop_cache: HashMap<t, bool>, |
| needs_unwind_cleanup_cache: HashMap<t, bool>, |
| kind_cache: HashMap<t, kind>, |
| ast_ty_to_ty_cache: HashMap<@ast::ty, ast_ty_to_ty_cache_entry>, |
| enum_var_cache: HashMap<def_id, @~[variant_info]>, |
| trait_method_cache: HashMap<def_id, @~[method]>, |
| ty_param_bounds: HashMap<ast::node_id, param_bounds>, |
| inferred_modes: HashMap<ast::node_id, ast::mode>, |
| adjustments: HashMap<ast::node_id, @AutoAdjustment>, |
| normalized_cache: HashMap<t, t>, |
| lang_items: middle::lang_items::LanguageItems, |
| legacy_boxed_traits: HashMap<node_id, ()>}; |
| |
| enum tbox_flag { |
| has_params = 1, |
| has_self = 2, |
| needs_infer = 4, |
| has_regions = 8, |
| |
| // a meta-flag: subst may be required if the type has parameters, a self |
| // type, or references bound regions |
| needs_subst = 1 | 2 | 8 |
| } |
| |
| type t_box = @{sty: sty, |
| id: uint, |
| flags: uint, |
| o_def_id: Option<ast::def_id>}; |
| |
| // To reduce refcounting cost, we're representing types as unsafe pointers |
| // throughout the compiler. These are simply casted t_box values. Use ty::get |
| // to cast them back to a box. (Without the cast, compiler performance suffers |
| // ~15%.) This does mean that a t value relies on the ctxt to keep its box |
| // alive, and using ty::get is unsafe when the ctxt is no longer alive. |
| enum t_opaque {} |
| type t = *t_opaque; |
| |
| pure fn get(t: t) -> t_box unsafe { |
| let t2 = cast::reinterpret_cast::<t, t_box>(&t); |
| let t3 = t2; |
| cast::forget(move t2); |
| t3 |
| } |
| |
| pure fn tbox_has_flag(tb: t_box, flag: tbox_flag) -> bool { |
| (tb.flags & (flag as uint)) != 0u |
| } |
| pure fn type_has_params(t: t) -> bool { tbox_has_flag(get(t), has_params) } |
| pure fn type_has_self(t: t) -> bool { tbox_has_flag(get(t), has_self) } |
| pure fn type_needs_infer(t: t) -> bool { tbox_has_flag(get(t), needs_infer) } |
| pure fn type_has_regions(t: t) -> bool { tbox_has_flag(get(t), has_regions) } |
| pure fn type_def_id(t: t) -> Option<ast::def_id> { get(t).o_def_id } |
| pure fn type_id(t: t) -> uint { get(t).id } |
| |
| enum closure_kind { |
| ck_block, |
| ck_box, |
| ck_uniq, |
| } |
| |
| impl closure_kind : to_bytes::IterBytes { |
| pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) { |
| (self as u8).iter_bytes(lsb0, f) |
| } |
| } |
| |
| impl closure_kind : cmp::Eq { |
| pure fn eq(other: &closure_kind) -> bool { |
| (self as uint) == ((*other) as uint) |
| } |
| pure fn ne(other: &closure_kind) -> bool { !self.eq(other) } |
| } |
| |
| enum fn_proto { |
| proto_bare, // supertype of all other protocols |
| proto_vstore(vstore) |
| } |
| |
| impl fn_proto : to_bytes::IterBytes { |
| pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) { |
| match self { |
| proto_bare => |
| 0u8.iter_bytes(lsb0, f), |
| |
| proto_vstore(ref v) => |
| to_bytes::iter_bytes_2(&1u8, v, lsb0, f) |
| } |
| } |
| } |
| |
| impl fn_proto : cmp::Eq { |
| pure fn eq(other: &fn_proto) -> bool { |
| match self { |
| proto_bare => { |
| match (*other) { |
| proto_bare => true, |
| _ => false |
| } |
| } |
| proto_vstore(e0a) => { |
| match (*other) { |
| proto_vstore(e0b) => e0a == e0b, |
| _ => false |
| } |
| } |
| } |
| } |
| pure fn ne(other: &fn_proto) -> bool { !self.eq(other) } |
| } |
| |
| /** |
| * Meta information about a closure. |
| * |
| * - `purity` is the function's effect (pure, impure, unsafe). |
| * - `proto` is the protocol (fn@, fn~, etc). |
| * - `bounds` is the parameter bounds on the function's upvars. |
| * - `ret_style` indicates whether the function returns a value or fails. */ |
| struct FnMeta { |
| purity: ast::purity, |
| proto: fn_proto, |
| bounds: @~[param_bound], |
| ret_style: ret_style |
| } |
| |
| /** |
| * Signature of a function type, which I have arbitrarily |
| * decided to use to refer to the input/output types. |
| * |
| * - `inputs` is the list of arguments and their modes. |
| * - `output` is the return type. */ |
| struct FnSig { |
| inputs: ~[arg], |
| output: t |
| } |
| |
| /** |
| * Function type: combines the meta information and the |
| * type signature. This particular type is parameterized |
| * by the meta information because, in some cases, the |
| * meta information is inferred. */ |
| struct FnTyBase<M: cmp::Eq> { |
| meta: M, |
| sig: FnSig |
| } |
| |
| type FnTy = FnTyBase<FnMeta>; |
| |
| type param_ty = {idx: uint, def_id: def_id}; |
| |
| impl param_ty : cmp::Eq { |
| pure fn eq(other: ¶m_ty) -> bool { |
| self.idx == (*other).idx && self.def_id == (*other).def_id |
| } |
| pure fn ne(other: ¶m_ty) -> bool { !self.eq(other) } |
| } |
| |
| impl param_ty : to_bytes::IterBytes { |
| pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) { |
| to_bytes::iter_bytes_2(&self.idx, &self.def_id, lsb0, f) |
| } |
| } |
| |
| |
| /// Representation of regions: |
| #[auto_serialize] |
| #[auto_deserialize] |
| enum region { |
| /// Bound regions are found (primarily) in function types. They indicate |
| /// region parameters that have yet to be replaced with actual regions |
| /// (analogous to type parameters, except that due to the monomorphic |
| /// nature of our type system, bound type parameters are always replaced |
| /// with fresh type variables whenever an item is referenced, so type |
| /// parameters only appear "free" in types. Regions in contrast can |
| /// appear free or bound.). When a function is called, all bound regions |
| /// tied to that function's node-id are replaced with fresh region |
| /// variables whose value is then inferred. |
| re_bound(bound_region), |
| |
| /// When checking a function body, the types of all arguments and so forth |
| /// that refer to bound region parameters are modified to refer to free |
| /// region parameters. |
| re_free(node_id, bound_region), |
| |
| /// A concrete region naming some expression within the current function. |
| re_scope(node_id), |
| |
| /// Static data that has an "infinite" lifetime. |
| re_static, |
| |
| /// A region variable. Should not exist after typeck. |
| re_var(RegionVid) |
| } |
| |
| #[auto_serialize] |
| #[auto_deserialize] |
| enum bound_region { |
| /// The self region for classes, impls (&T in a type defn or &self/T) |
| br_self, |
| |
| /// An anonymous region parameter for a given fn (&T) |
| br_anon(uint), |
| |
| /// Named region parameters for functions (a in &a/T) |
| br_named(ast::ident), |
| |
| /** |
| * Handles capture-avoiding substitution in a rather subtle case. If you |
| * have a closure whose argument types are being inferred based on the |
| * expected type, and the expected type includes bound regions, then we |
| * will wrap those bound regions in a br_cap_avoid() with the id of the |
| * fn expression. This ensures that the names are not "captured" by the |
| * enclosing scope, which may define the same names. For an example of |
| * where this comes up, see src/test/compile-fail/regions-ret-borrowed.rs |
| * and regions-ret-borrowed-1.rs. */ |
| br_cap_avoid(ast::node_id, @bound_region), |
| } |
| |
| type opt_region = Option<region>; |
| |
| /** |
| * The type substs represents the kinds of things that can be substituted to |
| * convert a polytype into a monotype. Note however that substituting bound |
| * regions other than `self` is done through a different mechanism: |
| * |
| * - `tps` represents the type parameters in scope. They are indexed |
| * according to the order in which they were declared. |
| * |
| * - `self_r` indicates the region parameter `self` that is present on nominal |
| * types (enums, classes) declared as having a region parameter. `self_r` |
| * should always be none for types that are not region-parameterized and |
| * Some(_) for types that are. The only bound region parameter that should |
| * appear within a region-parameterized type is `self`. |
| * |
| * - `self_ty` is the type to which `self` should be remapped, if any. The |
| * `self` type is rather funny in that it can only appear on traits and is |
| * always substituted away to the implementing type for a trait. */ |
| type substs = { |
| self_r: opt_region, |
| self_ty: Option<ty::t>, |
| tps: ~[t] |
| }; |
| |
| // NB: If you change this, you'll probably want to change the corresponding |
| // AST structure in libsyntax/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_estr(vstore), |
| ty_enum(def_id, substs), |
| ty_box(mt), |
| ty_uniq(mt), |
| ty_evec(mt, vstore), |
| ty_ptr(mt), |
| ty_rptr(region, mt), |
| ty_rec(~[field]), |
| ty_fn(FnTy), |
| ty_trait(def_id, substs, vstore), |
| ty_class(def_id, substs), |
| ty_tup(~[t]), |
| |
| ty_param(param_ty), // type parameter |
| ty_self, // special, implicit `self` type parameter |
| |
| ty_infer(InferTy), // soething used only during inference/typeck |
| |
| // "Fake" types, used for trans purposes |
| ty_type, // type_desc* |
| ty_opaque_box, // used by monomorphizer to represent any @ box |
| ty_opaque_closure_ptr(closure_kind), // ptr to env for fn, fn@, fn~ |
| ty_unboxed_vec(mt), |
| } |
| |
| enum terr_vstore_kind { |
| terr_vec, terr_str, terr_fn, terr_trait |
| } |
| |
| struct expected_found<T> { |
| expected: T, |
| found: T |
| } |
| |
| // Data structures used in type unification |
| enum type_err { |
| terr_mismatch, |
| terr_ret_style_mismatch(expected_found<ast::ret_style>), |
| terr_purity_mismatch(expected_found<purity>), |
| terr_mutability, |
| terr_proto_mismatch(expected_found<ty::fn_proto>), |
| terr_box_mutability, |
| terr_ptr_mutability, |
| terr_ref_mutability, |
| terr_vec_mutability, |
| terr_tuple_size(expected_found<uint>), |
| terr_ty_param_size(expected_found<uint>), |
| terr_record_size(expected_found<uint>), |
| terr_record_mutability, |
| terr_record_fields(expected_found<ident>), |
| terr_arg_count, |
| terr_mode_mismatch(expected_found<mode>), |
| terr_regions_does_not_outlive(region, region), |
| terr_regions_not_same(region, region), |
| terr_regions_no_overlap(region, region), |
| terr_vstores_differ(terr_vstore_kind, expected_found<vstore>), |
| terr_in_field(@type_err, ast::ident), |
| terr_sorts(expected_found<t>), |
| terr_self_substs, |
| terr_no_integral_type, |
| } |
| |
| enum param_bound { |
| bound_copy, |
| bound_owned, |
| bound_send, |
| bound_const, |
| bound_trait(t), |
| } |
| |
| enum TyVid = uint; |
| enum IntVid = uint; |
| enum FnVid = uint; |
| #[auto_serialize] |
| #[auto_deserialize] |
| enum RegionVid = uint; |
| |
| enum InferTy { |
| TyVar(TyVid), |
| IntVar(IntVid) |
| } |
| |
| impl InferTy : to_bytes::IterBytes { |
| pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) { |
| match self { |
| TyVar(ref tv) => to_bytes::iter_bytes_2(&0u8, tv, lsb0, f), |
| IntVar(ref iv) => to_bytes::iter_bytes_2(&1u8, iv, lsb0, f) |
| } |
| } |
| } |
| |
| impl param_bound : to_bytes::IterBytes { |
| pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) { |
| match self { |
| bound_copy => 0u8.iter_bytes(lsb0, f), |
| bound_owned => 1u8.iter_bytes(lsb0, f), |
| bound_send => 2u8.iter_bytes(lsb0, f), |
| bound_const => 3u8.iter_bytes(lsb0, f), |
| bound_trait(ref t) => |
| to_bytes::iter_bytes_2(&4u8, t, lsb0, f) |
| } |
| } |
| } |
| |
| trait vid { |
| pure fn to_uint() -> uint; |
| pure fn to_str() -> ~str; |
| } |
| |
| impl TyVid: vid { |
| pure fn to_uint() -> uint { *self } |
| pure fn to_str() -> ~str { fmt!("<V%u>", self.to_uint()) } |
| } |
| |
| impl IntVid: vid { |
| pure fn to_uint() -> uint { *self } |
| pure fn to_str() -> ~str { fmt!("<VI%u>", self.to_uint()) } |
| } |
| |
| impl FnVid: vid { |
| pure fn to_uint() -> uint { *self } |
| pure fn to_str() -> ~str { fmt!("<F%u>", self.to_uint()) } |
| } |
| |
| impl RegionVid: vid { |
| pure fn to_uint() -> uint { *self } |
| pure fn to_str() -> ~str { fmt!("%?", self) } |
| } |
| |
| impl InferTy { |
| pure fn to_hash() -> uint { |
| match self { |
| TyVar(v) => v.to_uint() << 1, |
| IntVar(v) => (v.to_uint() << 1) + 1, |
| } |
| } |
| |
| pure fn to_str() -> ~str { |
| match self { |
| TyVar(v) => v.to_str(), |
| IntVar(v) => v.to_str(), |
| } |
| } |
| } |
| |
| trait purity_to_str { |
| pure fn to_str() -> ~str; |
| } |
| |
| impl purity: purity_to_str { |
| pure fn to_str() -> ~str { |
| purity_to_str(self) |
| } |
| } |
| |
| impl RegionVid : to_bytes::IterBytes { |
| pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) { |
| (*self).iter_bytes(lsb0, f) |
| } |
| } |
| |
| impl TyVid : to_bytes::IterBytes { |
| pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) { |
| (*self).iter_bytes(lsb0, f) |
| } |
| } |
| |
| impl IntVid : to_bytes::IterBytes { |
| pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) { |
| (*self).iter_bytes(lsb0, f) |
| } |
| } |
| |
| impl FnVid : to_bytes::IterBytes { |
| pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) { |
| (*self).iter_bytes(lsb0, f) |
| } |
| } |
| |
| fn param_bounds_to_kind(bounds: param_bounds) -> kind { |
| let mut kind = kind_noncopyable(); |
| for vec::each(*bounds) |bound| { |
| match *bound { |
| bound_copy => { |
| kind = raise_kind(kind, kind_implicitly_copyable()); |
| } |
| bound_owned => { |
| kind = raise_kind(kind, kind_owned()); |
| } |
| bound_send => { |
| kind = raise_kind(kind, kind_send_only() | kind_owned()); |
| } |
| bound_const => { |
| kind = raise_kind(kind, kind_const()); |
| } |
| bound_trait(_) => () |
| } |
| } |
| kind |
| } |
| |
| /// A polytype. |
| /// |
| /// - `bounds`: The list of bounds for each type parameter. The length of the |
| /// list also tells you how many type parameters there are. |
| /// |
| /// - `rp`: true if the type is region-parameterized. Types can have at |
| /// most one region parameter, always called `&self`. |
| /// |
| /// - `ty`: the base type. May have reference to the (unsubstituted) bound |
| /// region `&self` or to (unsubstituted) ty_param types |
| type ty_param_bounds_and_ty = {bounds: @~[param_bounds], |
| region_param: Option<region_variance>, |
| ty: t}; |
| |
| type type_cache = HashMap<ast::def_id, ty_param_bounds_and_ty>; |
| |
| type constness_cache = HashMap<ast::def_id, const_eval::constness>; |
| |
| type node_type_table = @smallintmap::SmallIntMap<t>; |
| |
| fn mk_rcache() -> creader_cache { |
| type val = {cnum: int, pos: uint, len: uint}; |
| return map::HashMap(); |
| } |
| |
| fn new_ty_hash<V: Copy>() -> map::HashMap<t, V> { |
| map::HashMap() |
| } |
| |
| fn mk_ctxt(s: session::session, |
| dm: resolve::DefMap, |
| amap: ast_map::map, |
| freevars: freevars::freevar_map, |
| region_map: middle::region::region_map, |
| region_paramd_items: middle::region::region_paramd_items, |
| +lang_items: middle::lang_items::LanguageItems, |
| crate: @ast::crate) -> ctxt { |
| let mut legacy_modes = false; |
| for crate.node.attrs.each |attribute| { |
| match attribute.node.value.node { |
| ast::meta_word(w) if w == ~"legacy_modes" => { |
| legacy_modes = true; |
| break; |
| } |
| _ => {} |
| } |
| } |
| |
| let interner = map::HashMap(); |
| let vecs_implicitly_copyable = |
| get_lint_level(s.lint_settings.default_settings, |
| lint::vecs_implicitly_copyable) == allow; |
| @{diag: s.diagnostic(), |
| interner: interner, |
| mut next_id: 0u, |
| vecs_implicitly_copyable: vecs_implicitly_copyable, |
| legacy_modes: legacy_modes, |
| cstore: s.cstore, |
| sess: s, |
| def_map: dm, |
| region_map: region_map, |
| region_paramd_items: region_paramd_items, |
| node_types: @smallintmap::mk(), |
| node_type_substs: map::HashMap(), |
| items: amap, |
| intrinsic_defs: map::HashMap(), |
| freevars: freevars, |
| tcache: HashMap(), |
| rcache: mk_rcache(), |
| ccache: HashMap(), |
| short_names_cache: new_ty_hash(), |
| needs_drop_cache: new_ty_hash(), |
| needs_unwind_cleanup_cache: new_ty_hash(), |
| kind_cache: new_ty_hash(), |
| ast_ty_to_ty_cache: HashMap(), |
| enum_var_cache: HashMap(), |
| trait_method_cache: HashMap(), |
| ty_param_bounds: HashMap(), |
| inferred_modes: HashMap(), |
| adjustments: HashMap(), |
| normalized_cache: new_ty_hash(), |
| lang_items: move lang_items, |
| legacy_boxed_traits: HashMap()} |
| } |
| |
| |
| // 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<ast::def_id>) -> t { |
| let key = {sty: st, o_def_id: o_def_id}; |
| match cx.interner.find(key) { |
| Some(t) => unsafe { return cast::reinterpret_cast(&t); }, |
| _ => () |
| } |
| let mut flags = 0u; |
| fn rflags(r: region) -> uint { |
| (has_regions as uint) | { |
| match r { |
| ty::re_var(_) => needs_infer as uint, |
| _ => 0u |
| } |
| } |
| } |
| fn sflags(substs: &substs) -> uint { |
| let mut f = 0u; |
| for substs.tps.each |tt| { f |= get(*tt).flags; } |
| substs.self_r.iter(|r| f |= rflags(*r)); |
| return f; |
| } |
| match st { |
| ty_estr(vstore_slice(r)) => { |
| flags |= rflags(r); |
| } |
| ty_evec(mt, vstore_slice(r)) => { |
| flags |= rflags(r); |
| flags |= get(mt.ty).flags; |
| } |
| ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) | |
| ty_estr(_) | ty_type | ty_opaque_closure_ptr(_) | |
| ty_opaque_box => (), |
| ty_param(_) => flags |= has_params as uint, |
| ty_infer(_) => flags |= needs_infer as uint, |
| ty_self => flags |= has_self as uint, |
| ty_enum(_, ref substs) | ty_class(_, ref substs) |
| | ty_trait(_, ref substs, _) => { |
| flags |= sflags(substs); |
| } |
| ty_box(m) | ty_uniq(m) | ty_evec(m, _) | |
| ty_ptr(m) | ty_unboxed_vec(m) => { |
| flags |= get(m.ty).flags; |
| } |
| ty_rptr(r, m) => { |
| flags |= rflags(r); |
| flags |= get(m.ty).flags; |
| } |
| ty_rec(flds) => for flds.each |f| { flags |= get(f.mt.ty).flags; }, |
| ty_tup(ts) => for ts.each |tt| { flags |= get(*tt).flags; }, |
| ty_fn(ref f) => { |
| match f.meta.proto { |
| ty::proto_vstore(vstore_slice(r)) => flags |= rflags(r), |
| ty::proto_bare | ty::proto_vstore(_) => {} |
| } |
| for f.sig.inputs.each |a| { flags |= get(a.ty).flags; } |
| flags |= get(f.sig.output).flags; |
| } |
| } |
| let t = @{sty: st, id: cx.next_id, flags: flags, o_def_id: o_def_id}; |
| cx.interner.insert(key, t); |
| cx.next_id += 1u; |
| unsafe { cast::reinterpret_cast(&t) } |
| } |
| |
| fn mk_nil(cx: ctxt) -> t { mk_t(cx, ty_nil) } |
| |
| fn mk_bot(cx: ctxt) -> t { mk_t(cx, ty_bot) } |
| |
| fn mk_bool(cx: ctxt) -> t { mk_t(cx, ty_bool) } |
| |
| fn mk_int(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_i)) } |
| |
| fn mk_i8(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_i8)) } |
| |
| fn mk_i16(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_i16)) } |
| |
| fn mk_i32(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_i32)) } |
| |
| fn mk_i64(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_i64)) } |
| |
| fn mk_float(cx: ctxt) -> t { mk_t(cx, ty_float(ast::ty_f)) } |
| |
| fn mk_uint(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u)) } |
| |
| fn mk_u8(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u8)) } |
| |
| fn mk_u16(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u16)) } |
| |
| fn mk_u32(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u32)) } |
| |
| fn mk_u64(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u64)) } |
| |
| fn mk_mach_int(cx: ctxt, tm: ast::int_ty) -> t { mk_t(cx, ty_int(tm)) } |
| |
| fn mk_mach_uint(cx: ctxt, tm: ast::uint_ty) -> t { mk_t(cx, ty_uint(tm)) } |
| |
| fn mk_mach_float(cx: ctxt, tm: ast::float_ty) -> t { mk_t(cx, ty_float(tm)) } |
| |
| fn mk_char(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_char)) } |
| |
| fn mk_estr(cx: ctxt, t: vstore) -> t { |
| mk_t(cx, ty_estr(t)) |
| } |
| |
| fn mk_enum(cx: ctxt, did: ast::def_id, +substs: substs) -> t { |
| // take a copy of substs so that we own the vectors inside |
| mk_t(cx, ty_enum(did, substs)) |
| } |
| |
| fn mk_box(cx: ctxt, tm: mt) -> t { mk_t(cx, ty_box(tm)) } |
| |
| fn mk_imm_box(cx: ctxt, 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_imm_uniq(cx: ctxt, 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_rptr(cx: ctxt, r: region, tm: mt) -> t { mk_t(cx, ty_rptr(r, tm)) } |
| |
| fn mk_mut_rptr(cx: ctxt, r: region, ty: t) -> t { |
| mk_rptr(cx, r, {ty: ty, mutbl: ast::m_mutbl}) |
| } |
| fn mk_imm_rptr(cx: ctxt, r: region, ty: t) -> t { |
| mk_rptr(cx, r, {ty: ty, mutbl: ast::m_imm}) |
| } |
| |
| fn mk_mut_ptr(cx: ctxt, ty: t) -> t { mk_ptr(cx, {ty: ty, |
| mutbl: ast::m_mutbl}) } |
| |
| fn mk_imm_ptr(cx: ctxt, ty: t) -> t { |
| mk_ptr(cx, {ty: ty, mutbl: ast::m_imm}) |
| } |
| |
| fn mk_nil_ptr(cx: ctxt) -> t { |
| mk_ptr(cx, {ty: mk_nil(cx), mutbl: ast::m_imm}) |
| } |
| |
| fn mk_evec(cx: ctxt, tm: mt, t: vstore) -> t { |
| mk_t(cx, ty_evec(tm, t)) |
| } |
| |
| fn mk_unboxed_vec(cx: ctxt, tm: mt) -> t { |
| mk_t(cx, ty_unboxed_vec(tm)) |
| } |
| fn mk_mut_unboxed_vec(cx: ctxt, ty: t) -> t { |
| mk_t(cx, ty_unboxed_vec({ty: ty, mutbl: ast::m_imm})) |
| } |
| |
| fn mk_rec(cx: ctxt, fs: ~[field]) -> t { mk_t(cx, ty_rec(fs)) } |
| |
| fn mk_tup(cx: ctxt, ts: ~[t]) -> t { mk_t(cx, ty_tup(ts)) } |
| |
| // take a copy because we want to own the various vectors inside |
| fn mk_fn(cx: ctxt, +fty: FnTy) -> t { mk_t(cx, ty_fn(fty)) } |
| |
| fn mk_trait(cx: ctxt, did: ast::def_id, +substs: substs, vstore: vstore) |
| -> t { |
| // take a copy of substs so that we own the vectors inside |
| mk_t(cx, ty_trait(did, substs, vstore)) |
| } |
| |
| fn mk_class(cx: ctxt, class_id: ast::def_id, +substs: substs) -> t { |
| // take a copy of substs so that we own the vectors inside |
| mk_t(cx, ty_class(class_id, substs)) |
| } |
| |
| fn mk_var(cx: ctxt, v: TyVid) -> t { mk_infer(cx, TyVar(v)) } |
| |
| fn mk_int_var(cx: ctxt, v: IntVid) -> t { |
| mk_infer(cx, IntVar(v)) |
| } |
| |
| fn mk_infer(cx: ctxt, it: InferTy) -> t { mk_t(cx, ty_infer(it)) } |
| |
| fn mk_self(cx: ctxt) -> t { mk_t(cx, ty_self) } |
| |
| fn mk_param(cx: ctxt, n: uint, k: def_id) -> t { |
| mk_t(cx, ty_param({idx: n, def_id: k})) |
| } |
| |
| fn mk_type(cx: ctxt) -> t { mk_t(cx, ty_type) } |
| |
| fn mk_opaque_closure_ptr(cx: ctxt, ck: closure_kind) -> t { |
| mk_t(cx, ty_opaque_closure_ptr(ck)) |
| } |
| |
| fn mk_opaque_box(cx: ctxt) -> t { mk_t(cx, ty_opaque_box) } |
| |
| fn mk_with_id(cx: ctxt, base: t, def_id: ast::def_id) -> t { |
| mk_t_with_id(cx, get(base).sty, Some(def_id)) |
| } |
| |
| // Converts s to its machine type equivalent |
| pure fn mach_sty(cfg: @session::config, t: t) -> sty { |
| match get(t).sty { |
| 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 |
| } |
| } |
| |
| fn default_arg_mode_for_ty(tcx: ctxt, ty: ty::t) -> ast::rmode { |
| // FIXME(#2202) --- We retain by-ref for fn& things to workaround a |
| // memory leak that otherwise results when @fn is upcast to &fn. |
| if type_is_fn(ty) { |
| match ty_fn_proto(ty) { |
| proto_vstore(vstore_slice(_)) => return ast::by_ref, |
| _ => () |
| } |
| } |
| return if tcx.legacy_modes { |
| if type_is_borrowed(ty) { |
| // the old mode default was ++ for things like &ptr, but to be |
| // forward-compatible with non-legacy, we should use + |
| ast::by_copy |
| } else if ty::type_is_immediate(ty) { |
| ast::by_val |
| } else { |
| ast::by_ref |
| } |
| } else { |
| ast::by_copy |
| }; |
| |
| fn type_is_fn(ty: t) -> bool { |
| match get(ty).sty { |
| ty_fn(*) => true, |
| _ => false |
| } |
| } |
| |
| fn type_is_borrowed(ty: t) -> bool { |
| match ty::get(ty).sty { |
| ty::ty_rptr(*) => true, |
| ty_evec(_, vstore_slice(_)) => true, |
| ty_estr(vstore_slice(_)) => true, |
| |
| // technically, we prob ought to include |
| // &fn(), but that is treated specially due to #2202 |
| _ => false |
| } |
| } |
| } |
| |
| // Returns the narrowest lifetime enclosing the evaluation of the expression |
| // with id `id`. |
| fn encl_region(cx: ctxt, id: ast::node_id) -> ty::region { |
| match cx.region_map.find(id) { |
| Some(encl_scope) => ty::re_scope(encl_scope), |
| None => ty::re_static |
| } |
| } |
| |
| fn walk_ty(ty: t, f: fn(t)) { |
| maybe_walk_ty(ty, |t| { f(t); true }); |
| } |
| |
| fn maybe_walk_ty(ty: t, f: fn(t) -> bool) { |
| if !f(ty) { return; } |
| match get(ty).sty { |
| ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | |
| ty_estr(_) | ty_type | ty_opaque_box | ty_self | |
| ty_opaque_closure_ptr(_) | ty_infer(_) | ty_param(_) => { |
| } |
| ty_box(tm) | ty_evec(tm, _) | ty_unboxed_vec(tm) | |
| ty_ptr(tm) | ty_rptr(_, tm) => { |
| maybe_walk_ty(tm.ty, f); |
| } |
| ty_enum(_, substs) | ty_class(_, substs) | |
| ty_trait(_, substs, _) => { |
| for substs.tps.each |subty| { maybe_walk_ty(*subty, f); } |
| } |
| ty_rec(fields) => { |
| for fields.each |fl| { maybe_walk_ty(fl.mt.ty, f); } |
| } |
| ty_tup(ts) => { for ts.each |tt| { maybe_walk_ty(*tt, f); } } |
| ty_fn(ref ft) => { |
| for ft.sig.inputs.each |a| { maybe_walk_ty(a.ty, f); } |
| maybe_walk_ty(ft.sig.output, f); |
| } |
| ty_uniq(tm) => { maybe_walk_ty(tm.ty, f); } |
| } |
| } |
| |
| fn fold_sty_to_ty(tcx: ty::ctxt, sty: &sty, foldop: fn(t) -> t) -> t { |
| mk_t(tcx, fold_sty(sty, foldop)) |
| } |
| |
| fn fold_sty(sty: &sty, fldop: fn(t) -> t) -> sty { |
| fn fold_substs(substs: &substs, fldop: fn(t) -> t) -> substs { |
| {self_r: substs.self_r, |
| self_ty: substs.self_ty.map(|t| fldop(*t)), |
| tps: substs.tps.map(|t| fldop(*t))} |
| } |
| |
| match *sty { |
| ty_box(tm) => { |
| ty_box({ty: fldop(tm.ty), mutbl: tm.mutbl}) |
| } |
| ty_uniq(tm) => { |
| ty_uniq({ty: fldop(tm.ty), mutbl: tm.mutbl}) |
| } |
| ty_ptr(tm) => { |
| ty_ptr({ty: fldop(tm.ty), mutbl: tm.mutbl}) |
| } |
| ty_unboxed_vec(tm) => { |
| ty_unboxed_vec({ty: fldop(tm.ty), mutbl: tm.mutbl}) |
| } |
| ty_evec(tm, vst) => { |
| ty_evec({ty: fldop(tm.ty), mutbl: tm.mutbl}, vst) |
| } |
| ty_enum(tid, ref substs) => { |
| ty_enum(tid, fold_substs(substs, fldop)) |
| } |
| ty_trait(did, ref substs, vst) => { |
| ty_trait(did, fold_substs(substs, fldop), vst) |
| } |
| ty_rec(fields) => { |
| let new_fields = do vec::map(fields) |fl| { |
| let new_ty = fldop(fl.mt.ty); |
| let new_mt = {ty: new_ty, mutbl: fl.mt.mutbl}; |
| {ident: fl.ident, mt: new_mt} |
| }; |
| ty_rec(new_fields) |
| } |
| ty_tup(ts) => { |
| let new_ts = vec::map(ts, |tt| fldop(*tt)); |
| ty_tup(new_ts) |
| } |
| ty_fn(ref f) => { |
| let new_args = f.sig.inputs.map(|a| { |
| let new_ty = fldop(a.ty); |
| {mode: a.mode, ty: new_ty} |
| }); |
| let new_output = fldop(f.sig.output); |
| ty_fn(FnTyBase { |
| meta: f.meta, |
| sig: FnSig {inputs: new_args, output: new_output} |
| }) |
| } |
| ty_rptr(r, tm) => { |
| ty_rptr(r, {ty: fldop(tm.ty), mutbl: tm.mutbl}) |
| } |
| ty_class(did, ref substs) => { |
| ty_class(did, fold_substs(substs, fldop)) |
| } |
| ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | |
| ty_estr(_) | ty_type | ty_opaque_closure_ptr(_) | |
| ty_opaque_box | ty_infer(_) | ty_param(*) | ty_self => { |
| *sty |
| } |
| } |
| } |
| |
| // Folds types from the bottom up. |
| fn fold_ty(cx: ctxt, t0: t, fldop: fn(t) -> t) -> t { |
| let sty = fold_sty(&get(t0).sty, |t| fold_ty(cx, fldop(t), fldop)); |
| fldop(mk_t(cx, sty)) |
| } |
| |
| fn walk_regions_and_ty( |
| cx: ctxt, |
| ty: t, |
| walkr: fn(r: region), |
| walkt: fn(t: t) -> bool) { |
| |
| if (walkt(ty)) { |
| fold_regions_and_ty( |
| cx, ty, |
| |r| { walkr(r); r }, |
| |t| { walkt(t); walk_regions_and_ty(cx, t, walkr, walkt); t }, |
| |t| { walkt(t); walk_regions_and_ty(cx, t, walkr, walkt); t }); |
| } |
| } |
| |
| fn fold_regions_and_ty( |
| cx: ctxt, |
| ty: t, |
| fldr: fn(r: region) -> region, |
| fldfnt: fn(t: t) -> t, |
| fldt: fn(t: t) -> t) -> t { |
| |
| fn fold_substs( |
| substs: &substs, |
| fldr: fn(r: region) -> region, |
| fldt: fn(t: t) -> t) -> substs { |
| |
| {self_r: substs.self_r.map(|r| fldr(*r)), |
| self_ty: substs.self_ty.map(|t| fldt(*t)), |
| tps: substs.tps.map(|t| fldt(*t))} |
| } |
| |
| let tb = ty::get(ty); |
| match tb.sty { |
| ty::ty_rptr(r, mt) => { |
| let m_r = fldr(r); |
| let m_t = fldt(mt.ty); |
| ty::mk_rptr(cx, m_r, {ty: m_t, mutbl: mt.mutbl}) |
| } |
| ty_estr(vstore_slice(r)) => { |
| let m_r = fldr(r); |
| ty::mk_estr(cx, vstore_slice(m_r)) |
| } |
| ty_evec(mt, vstore_slice(r)) => { |
| let m_r = fldr(r); |
| let m_t = fldt(mt.ty); |
| ty::mk_evec(cx, {ty: m_t, mutbl: mt.mutbl}, vstore_slice(m_r)) |
| } |
| ty_enum(def_id, ref substs) => { |
| ty::mk_enum(cx, def_id, fold_substs(substs, fldr, fldt)) |
| } |
| ty_class(def_id, ref substs) => { |
| ty::mk_class(cx, def_id, fold_substs(substs, fldr, fldt)) |
| } |
| ty_trait(def_id, ref substs, vst) => { |
| ty::mk_trait(cx, def_id, fold_substs(substs, fldr, fldt), vst) |
| } |
| ty_fn(ref f) => { |
| let new_proto; |
| match f.meta.proto { |
| proto_bare => |
| new_proto = proto_bare, |
| proto_vstore(vstore_slice(r)) => |
| new_proto = proto_vstore(vstore_slice(fldr(r))), |
| proto_vstore(old_vstore) => |
| new_proto = proto_vstore(old_vstore) |
| } |
| let new_args = vec::map(f.sig.inputs, |a| { |
| let new_ty = fldfnt(a.ty); |
| {mode: a.mode, ty: new_ty} |
| }); |
| let new_output = fldfnt(f.sig.output); |
| ty::mk_fn(cx, FnTyBase { |
| meta: FnMeta {proto: new_proto, ..f.meta}, |
| sig: FnSig {inputs: new_args, |
| output: new_output} |
| }) |
| } |
| ref sty => { |
| fold_sty_to_ty(cx, sty, |t| fldt(t)) |
| } |
| } |
| } |
| |
| // n.b. this function is intended to eventually replace fold_region() below, |
| // that is why its name is so similar. |
| fn fold_regions( |
| cx: ctxt, |
| ty: t, |
| fldr: fn(r: region, in_fn: bool) -> region) -> t { |
| |
| fn do_fold(cx: ctxt, ty: t, in_fn: bool, |
| fldr: fn(region, bool) -> region) -> t { |
| if !type_has_regions(ty) { return ty; } |
| fold_regions_and_ty( |
| cx, ty, |
| |r| fldr(r, in_fn), |
| |t| do_fold(cx, t, true, fldr), |
| |t| do_fold(cx, t, in_fn, fldr)) |
| } |
| do_fold(cx, ty, false, fldr) |
| } |
| |
| fn fold_region(cx: ctxt, t0: t, fldop: fn(region, bool) -> region) -> t { |
| fn do_fold(cx: ctxt, t0: t, under_r: bool, |
| fldop: fn(region, bool) -> region) -> t { |
| let tb = get(t0); |
| if !tbox_has_flag(tb, has_regions) { return t0; } |
| match tb.sty { |
| ty_rptr(r, {ty: t1, mutbl: m}) => { |
| let m_r = fldop(r, under_r); |
| let m_t1 = do_fold(cx, t1, true, fldop); |
| ty::mk_rptr(cx, m_r, {ty: m_t1, mutbl: m}) |
| } |
| ty_estr(vstore_slice(r)) => { |
| let m_r = fldop(r, under_r); |
| ty::mk_estr(cx, vstore_slice(m_r)) |
| } |
| ty_evec({ty: t1, mutbl: m}, vstore_slice(r)) => { |
| let m_r = fldop(r, under_r); |
| let m_t1 = do_fold(cx, t1, true, fldop); |
| ty::mk_evec(cx, {ty: m_t1, mutbl: m}, vstore_slice(m_r)) |
| } |
| ty_fn(_) => { |
| // do not recurse into functions, which introduce fresh bindings |
| t0 |
| } |
| ref sty => { |
| do fold_sty_to_ty(cx, sty) |t| { |
| do_fold(cx, t, under_r, fldop) |
| } |
| } |
| } |
| } |
| |
| do_fold(cx, t0, false, fldop) |
| } |
| |
| // Substitute *only* type parameters. Used in trans where regions are erased. |
| fn subst_tps(cx: ctxt, tps: &[t], typ: t) -> t { |
| if tps.len() == 0u { return typ; } |
| let tb = ty::get(typ); |
| if !tbox_has_flag(tb, has_params) { return typ; } |
| match tb.sty { |
| ty_param(p) => tps[p.idx], |
| ref sty => fold_sty_to_ty(cx, sty, |t| subst_tps(cx, tps, t)) |
| } |
| } |
| |
| fn substs_is_noop(substs: &substs) -> bool { |
| substs.tps.len() == 0u && |
| substs.self_r.is_none() && |
| substs.self_ty.is_none() |
| } |
| |
| fn substs_to_str(cx: ctxt, substs: &substs) -> ~str { |
| fmt!("substs(self_r=%s, self_ty=%s, tps=%?)", |
| substs.self_r.map_default(~"none", |r| region_to_str(cx, *r)), |
| substs.self_ty.map_default(~"none", |t| ty_to_str(cx, *t)), |
| tys_to_str(cx, substs.tps)) |
| } |
| |
| fn param_bound_to_str(cx: ctxt, pb: ¶m_bound) -> ~str { |
| match *pb { |
| bound_copy => ~"copy", |
| bound_owned => ~"owned", |
| bound_send => ~"send", |
| bound_const => ~"const", |
| bound_trait(t) => ty_to_str(cx, t) |
| } |
| } |
| |
| fn param_bounds_to_str(cx: ctxt, pbs: param_bounds) -> ~str { |
| fmt!("%?", pbs.map(|pb| param_bound_to_str(cx, pb))) |
| } |
| |
| fn subst(cx: ctxt, |
| substs: &substs, |
| typ: t) -> t { |
| |
| debug!("subst(substs=%s, typ=%s)", |
| substs_to_str(cx, substs), |
| ty_to_str(cx, typ)); |
| |
| if substs_is_noop(substs) { return typ; } |
| let r = do_subst(cx, substs, typ); |
| debug!(" r = %s", ty_to_str(cx, r)); |
| return r; |
| |
| fn do_subst(cx: ctxt, |
| substs: &substs, |
| typ: t) -> t { |
| let tb = get(typ); |
| if !tbox_has_flag(tb, needs_subst) { return typ; } |
| match tb.sty { |
| ty_param(p) => substs.tps[p.idx], |
| ty_self => substs.self_ty.get(), |
| _ => { |
| fold_regions_and_ty( |
| cx, typ, |
| |r| match r { |
| re_bound(br_self) => substs.self_r.get(), |
| _ => r |
| }, |
| |t| do_subst(cx, substs, t), |
| |t| do_subst(cx, substs, t)) |
| } |
| } |
| } |
| } |
| |
| // Type utilities |
| |
| fn type_is_nil(ty: t) -> bool { get(ty).sty == ty_nil } |
| |
| fn type_is_bot(ty: t) -> bool { get(ty).sty == ty_bot } |
| |
| fn type_is_ty_var(ty: t) -> bool { |
| match get(ty).sty { |
| ty_infer(TyVar(_)) => true, |
| _ => false |
| } |
| } |
| |
| fn type_is_bool(ty: t) -> bool { get(ty).sty == ty_bool } |
| |
| fn type_is_structural(ty: t) -> bool { |
| match get(ty).sty { |
| ty_rec(_) | ty_class(*) | ty_tup(_) | ty_enum(*) | ty_fn(_) | |
| ty_trait(*) | |
| ty_evec(_, vstore_fixed(_)) | ty_estr(vstore_fixed(_)) | |
| ty_evec(_, vstore_slice(_)) | ty_estr(vstore_slice(_)) |
| => true, |
| _ => false |
| } |
| } |
| |
| fn type_is_copyable(cx: ctxt, ty: t) -> bool { |
| return kind_can_be_copied(type_kind(cx, ty)); |
| } |
| |
| fn type_is_sequence(ty: t) -> bool { |
| match get(ty).sty { |
| ty_estr(_) | ty_evec(_, _) => true, |
| _ => false |
| } |
| } |
| |
| fn type_is_str(ty: t) -> bool { |
| match get(ty).sty { |
| ty_estr(_) => true, |
| _ => false |
| } |
| } |
| |
| fn sequence_element_type(cx: ctxt, ty: t) -> t { |
| match get(ty).sty { |
| ty_estr(_) => return mk_mach_uint(cx, ast::ty_u8), |
| ty_evec(mt, _) | ty_unboxed_vec(mt) => return mt.ty, |
| _ => cx.sess.bug( |
| ~"sequence_element_type called on non-sequence value"), |
| } |
| } |
| |
| fn get_element_type(ty: t, i: uint) -> t { |
| match get(ty).sty { |
| ty_rec(flds) => return flds[i].mt.ty, |
| ty_tup(ts) => return ts[i], |
| _ => fail ~"get_element_type called on invalid type" |
| } |
| } |
| |
| pure fn type_is_box(ty: t) -> bool { |
| match get(ty).sty { |
| ty_box(_) => return true, |
| _ => return false |
| } |
| } |
| |
| pure fn type_is_boxed(ty: t) -> bool { |
| match get(ty).sty { |
| ty_box(_) | ty_opaque_box | |
| ty_evec(_, vstore_box) | ty_estr(vstore_box) => true, |
| _ => false |
| } |
| } |
| |
| pure fn type_is_region_ptr(ty: t) -> bool { |
| match get(ty).sty { |
| ty_rptr(_, _) => true, |
| _ => false |
| } |
| } |
| |
| pure fn type_is_slice(ty: t) -> bool { |
| match get(ty).sty { |
| ty_evec(_, vstore_slice(_)) | ty_estr(vstore_slice(_)) => true, |
| _ => return false |
| } |
| } |
| |
| pure fn type_is_unique_box(ty: t) -> bool { |
| match get(ty).sty { |
| ty_uniq(_) => return true, |
| _ => return false |
| } |
| } |
| |
| pure fn type_is_unsafe_ptr(ty: t) -> bool { |
| match get(ty).sty { |
| ty_ptr(_) => return true, |
| _ => return false |
| } |
| } |
| |
| pure fn type_is_vec(ty: t) -> bool { |
| return match get(ty).sty { |
| ty_evec(_, _) | ty_unboxed_vec(_) => true, |
| ty_estr(_) => true, |
| _ => false |
| }; |
| } |
| |
| pure fn type_is_unique(ty: t) -> bool { |
| match get(ty).sty { |
| ty_uniq(_) => return true, |
| ty_evec(_, vstore_uniq) => true, |
| ty_estr(vstore_uniq) => true, |
| _ => return false |
| } |
| } |
| |
| /* |
| A scalar type is one that denotes an atomic datum, with no sub-components. |
| (A ty_ptr is scalar because it represents a non-managed pointer, so its |
| contents are abstract to rustc.) |
| */ |
| pure fn type_is_scalar(ty: t) -> bool { |
| match get(ty).sty { |
| ty_nil | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) | |
| ty_infer(IntVar(_)) | ty_type | ty_ptr(_) => true, |
| _ => false |
| } |
| } |
| |
| fn type_is_immediate(ty: t) -> bool { |
| return type_is_scalar(ty) || type_is_boxed(ty) || |
| type_is_unique(ty) || type_is_region_ptr(ty); |
| } |
| |
| fn type_needs_drop(cx: ctxt, ty: t) -> bool { |
| match cx.needs_drop_cache.find(ty) { |
| Some(result) => return result, |
| None => {/* fall through */ } |
| } |
| |
| let mut accum = false; |
| let result = match get(ty).sty { |
| // scalar types |
| ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) | |
| ty_type | ty_ptr(_) | ty_rptr(_, _) | |
| ty_estr(vstore_fixed(_)) | |
| ty_estr(vstore_slice(_)) | |
| ty_evec(_, vstore_slice(_)) | |
| ty_self => false, |
| |
| ty_box(_) | ty_uniq(_) | |
| ty_opaque_box | ty_opaque_closure_ptr(*) | |
| ty_estr(vstore_uniq) | |
| ty_estr(vstore_box) | |
| ty_evec(_, vstore_uniq) | |
| ty_evec(_, vstore_box) => true, |
| |
| ty_trait(_, _, vstore_box) | |
| ty_trait(_, _, vstore_uniq) => true, |
| ty_trait(_, _, vstore_fixed(_)) | |
| ty_trait(_, _, vstore_slice(_)) => false, |
| |
| ty_param(*) | ty_infer(*) => true, |
| |
| ty_evec(mt, vstore_fixed(_)) => type_needs_drop(cx, mt.ty), |
| ty_unboxed_vec(mt) => type_needs_drop(cx, mt.ty), |
| ty_rec(flds) => { |
| for flds.each |f| { |
| if type_needs_drop(cx, f.mt.ty) { accum = true; } |
| } |
| accum |
| } |
| ty_class(did, ref substs) => { |
| // Any class with a dtor needs a drop |
| ty_dtor(cx, did).is_some() || { |
| for vec::each(ty::class_items_as_fields(cx, did, substs)) |f| { |
| if type_needs_drop(cx, f.mt.ty) { accum = true; } |
| } |
| accum |
| } |
| } |
| ty_tup(elts) => { |
| for elts.each |m| { if type_needs_drop(cx, *m) { accum = true; } } |
| accum |
| } |
| ty_enum(did, ref substs) => { |
| let variants = enum_variants(cx, did); |
| for vec::each(*variants) |variant| { |
| for variant.args.each |aty| { |
| // Perform any type parameter substitutions. |
| let arg_ty = subst(cx, substs, *aty); |
| if type_needs_drop(cx, arg_ty) { accum = true; } |
| } |
| if accum { break; } |
| } |
| accum |
| } |
| ty_fn(ref fty) => { |
| match fty.meta.proto { |
| proto_bare | proto_vstore(vstore_slice(_)) => false, |
| _ => true |
| } |
| } |
| }; |
| |
| cx.needs_drop_cache.insert(ty, result); |
| return result; |
| } |
| |
| // Some things don't need cleanups during unwinding because the |
| // task can free them all at once later. Currently only things |
| // that only contain scalars and shared boxes can avoid unwind |
| // cleanups. |
| fn type_needs_unwind_cleanup(cx: ctxt, ty: t) -> bool { |
| match cx.needs_unwind_cleanup_cache.find(ty) { |
| Some(result) => return result, |
| None => () |
| } |
| |
| let tycache = new_ty_hash(); |
| let needs_unwind_cleanup = |
| type_needs_unwind_cleanup_(cx, ty, tycache, false); |
| cx.needs_unwind_cleanup_cache.insert(ty, needs_unwind_cleanup); |
| return needs_unwind_cleanup; |
| } |
| |
| fn type_needs_unwind_cleanup_(cx: ctxt, ty: t, |
| tycache: map::HashMap<t, ()>, |
| encountered_box: bool) -> bool { |
| |
| // Prevent infinite recursion |
| match tycache.find(ty) { |
| Some(_) => return false, |
| None => { tycache.insert(ty, ()); } |
| } |
| |
| let mut encountered_box = encountered_box; |
| let mut needs_unwind_cleanup = false; |
| do maybe_walk_ty(ty) |ty| { |
| let old_encountered_box = encountered_box; |
| let result = match get(ty).sty { |
| ty_box(_) | ty_opaque_box => { |
| encountered_box = true; |
| true |
| } |
| ty_nil | ty_bot | ty_bool | |
| ty_int(_) | ty_uint(_) | ty_float(_) | |
| ty_rec(_) | ty_tup(_) | ty_ptr(_) => { |
| true |
| } |
| ty_enum(did, ref substs) => { |
| for vec::each(*enum_variants(cx, did)) |v| { |
| for v.args.each |aty| { |
| let t = subst(cx, substs, *aty); |
| needs_unwind_cleanup |= |
| type_needs_unwind_cleanup_(cx, t, tycache, |
| encountered_box); |
| } |
| } |
| !needs_unwind_cleanup |
| } |
| ty_uniq(_) | |
| ty_estr(vstore_uniq) | |
| ty_estr(vstore_box) | |
| ty_evec(_, vstore_uniq) | |
| ty_evec(_, vstore_box) |
| => { |
| // Once we're inside a box, the annihilator will find |
| // it and destroy it. |
| if !encountered_box { |
| needs_unwind_cleanup = true; |
| false |
| } else { |
| true |
| } |
| } |
| _ => { |
| needs_unwind_cleanup = true; |
| false |
| } |
| }; |
| |
| encountered_box = old_encountered_box; |
| result |
| } |
| |
| return needs_unwind_cleanup; |
| } |
| |
| enum kind { kind_(u32) } |
| |
| /// can be copied (implicitly or explicitly) |
| const KIND_MASK_COPY : u32 = 0b000000000000000000000000001_u32; |
| |
| /// can be sent: no shared box, borrowed ptr (must imply OWNED) |
| const KIND_MASK_SEND : u32 = 0b000000000000000000000000010_u32; |
| |
| /// is owned (no borrowed ptrs) |
| const KIND_MASK_OWNED : u32 = 0b000000000000000000000000100_u32; |
| |
| /// is deeply immutable |
| const KIND_MASK_CONST : u32 = 0b000000000000000000000001000_u32; |
| |
| /// can be implicitly copied (must imply COPY) |
| const KIND_MASK_IMPLICIT : u32 = 0b000000000000000000000010000_u32; |
| |
| /// safe for default mode (subset of KIND_MASK_IMPLICIT) |
| const KIND_MASK_DEFAULT_MODE : u32 = 0b000000000000000000000100000_u32; |
| |
| fn kind_noncopyable() -> kind { |
| kind_(0u32) |
| } |
| |
| fn kind_copyable() -> kind { |
| kind_(KIND_MASK_COPY) |
| } |
| |
| fn kind_implicitly_copyable() -> kind { |
| kind_(KIND_MASK_IMPLICIT | KIND_MASK_COPY) |
| } |
| |
| fn kind_safe_for_default_mode() -> kind { |
| // similar to implicit copy, but always includes vectors and strings |
| kind_(KIND_MASK_DEFAULT_MODE | KIND_MASK_IMPLICIT | KIND_MASK_COPY) |
| } |
| |
| fn kind_implicitly_sendable() -> kind { |
| kind_(KIND_MASK_IMPLICIT | KIND_MASK_COPY | KIND_MASK_SEND) |
| } |
| |
| fn kind_safe_for_default_mode_send() -> kind { |
| // similar to implicit copy, but always includes vectors and strings |
| kind_(KIND_MASK_DEFAULT_MODE | KIND_MASK_IMPLICIT | |
| KIND_MASK_COPY | KIND_MASK_SEND) |
| } |
| |
| |
| fn kind_send_copy() -> kind { |
| kind_(KIND_MASK_COPY | KIND_MASK_SEND) |
| } |
| |
| fn kind_send_only() -> kind { |
| kind_(KIND_MASK_SEND) |
| } |
| |
| fn kind_const() -> kind { |
| kind_(KIND_MASK_CONST) |
| } |
| |
| fn kind_owned() -> kind { |
| kind_(KIND_MASK_OWNED) |
| } |
| |
| fn kind_top() -> kind { |
| kind_(0xffffffffu32) |
| } |
| |
| fn remove_const(k: kind) -> kind { |
| k - kind_const() |
| } |
| |
| fn remove_implicit(k: kind) -> kind { |
| k - kind_(KIND_MASK_IMPLICIT | KIND_MASK_DEFAULT_MODE) |
| } |
| |
| fn remove_send(k: kind) -> kind { |
| k - kind_(KIND_MASK_SEND) |
| } |
| |
| fn remove_owned_send(k: kind) -> kind { |
| k - kind_(KIND_MASK_OWNED) - kind_(KIND_MASK_SEND) |
| } |
| |
| fn remove_copyable(k: kind) -> kind { |
| k - kind_(KIND_MASK_COPY | KIND_MASK_DEFAULT_MODE) |
| } |
| |
| impl kind : ops::BitAnd<kind,kind> { |
| pure fn bitand(other: &kind) -> kind { |
| unsafe { |
| lower_kind(self, (*other)) |
| } |
| } |
| } |
| |
| impl kind : ops::BitOr<kind,kind> { |
| pure fn bitor(other: &kind) -> kind { |
| unsafe { |
| raise_kind(self, (*other)) |
| } |
| } |
| } |
| |
| impl kind : ops::Sub<kind,kind> { |
| pure fn sub(other: &kind) -> kind { |
| unsafe { |
| kind_(*self & !*(*other)) |
| } |
| } |
| } |
| |
| // Using these query functions is preferable to direct comparison or matching |
| // against the kind constants, as we may modify the kind hierarchy in the |
| // future. |
| pure fn kind_can_be_implicitly_copied(k: kind) -> bool { |
| *k & KIND_MASK_IMPLICIT == KIND_MASK_IMPLICIT |
| } |
| |
| pure fn kind_is_safe_for_default_mode(k: kind) -> bool { |
| *k & KIND_MASK_DEFAULT_MODE == KIND_MASK_DEFAULT_MODE |
| } |
| |
| pure fn kind_can_be_copied(k: kind) -> bool { |
| *k & KIND_MASK_COPY == KIND_MASK_COPY |
| } |
| |
| pure fn kind_can_be_sent(k: kind) -> bool { |
| *k & KIND_MASK_SEND == KIND_MASK_SEND |
| } |
| |
| pure fn kind_is_owned(k: kind) -> bool { |
| *k & KIND_MASK_OWNED == KIND_MASK_OWNED |
| } |
| |
| fn meta_kind(p: FnMeta) -> kind { |
| match p.proto { // XXX consider the kind bounds! |
| proto_vstore(vstore_slice(_)) => |
| kind_noncopyable() | kind_(KIND_MASK_DEFAULT_MODE), |
| proto_vstore(vstore_box) => |
| kind_safe_for_default_mode() | kind_owned(), |
| proto_vstore(vstore_uniq) => |
| kind_send_copy() | kind_owned(), |
| proto_vstore(vstore_fixed(_)) => |
| fail ~"fixed vstore protos are not allowed", |
| proto_bare => |
| kind_safe_for_default_mode_send() | kind_const() | kind_owned() |
| } |
| } |
| |
| fn kind_lteq(a: kind, b: kind) -> bool { |
| *a & *b == *a |
| } |
| |
| fn lower_kind(a: kind, b: kind) -> kind { |
| kind_(*a & *b) |
| } |
| |
| fn raise_kind(a: kind, b: kind) -> kind { |
| kind_(*a | *b) |
| } |
| |
| #[test] |
| fn test_kinds() { |
| // The kind "lattice" is defined by the subset operation on the |
| // set of permitted operations. |
| assert kind_lteq(kind_send_copy(), kind_send_copy()); |
| assert kind_lteq(kind_copyable(), kind_send_copy()); |
| assert kind_lteq(kind_copyable(), kind_copyable()); |
| assert kind_lteq(kind_noncopyable(), kind_send_copy()); |
| assert kind_lteq(kind_noncopyable(), kind_copyable()); |
| assert kind_lteq(kind_noncopyable(), kind_noncopyable()); |
| assert kind_lteq(kind_copyable(), kind_implicitly_copyable()); |
| assert kind_lteq(kind_copyable(), kind_implicitly_sendable()); |
| assert kind_lteq(kind_send_copy(), kind_implicitly_sendable()); |
| assert !kind_lteq(kind_send_copy(), kind_implicitly_copyable()); |
| assert !kind_lteq(kind_copyable(), kind_send_only()); |
| } |
| |
| // Return the most permissive kind that a composite object containing a field |
| // with the given mutability can have. |
| // This is used to prevent objects containing mutable state from being |
| // implicitly copied and to compute whether things have const kind. |
| fn mutability_kind(m: mutability) -> kind { |
| match (m) { |
| m_mutbl => remove_const(remove_implicit(kind_top())), |
| m_const => remove_implicit(kind_top()), |
| m_imm => kind_top() |
| } |
| } |
| |
| fn mutable_type_kind(cx: ctxt, ty: mt) -> kind { |
| lower_kind(mutability_kind(ty.mutbl), type_kind(cx, ty.ty)) |
| } |
| |
| fn type_kind(cx: ctxt, ty: t) -> kind { |
| match cx.kind_cache.find(ty) { |
| Some(result) => return result, |
| None => {/* fall through */ } |
| } |
| |
| // Insert a default in case we loop back on self recursively. |
| cx.kind_cache.insert(ty, kind_top()); |
| |
| let mut result = match get(ty).sty { |
| // Scalar and unique types are sendable, constant, and owned |
| ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | |
| ty_ptr(_) => { |
| kind_safe_for_default_mode_send() | kind_const() | kind_owned() |
| } |
| |
| // Implicit copyability of strs is configurable |
| ty_estr(vstore_uniq) => { |
| if cx.vecs_implicitly_copyable { |
| kind_implicitly_sendable() | kind_const() | kind_owned() |
| } else { |
| kind_send_copy() | kind_const() | kind_owned() |
| } |
| } |
| |
| // functions depend on the protocol |
| ty_fn(ref f) => meta_kind(f.meta), |
| |
| // Those with refcounts raise noncopyable to copyable, |
| // lower sendable to copyable. Therefore just set result to copyable. |
| ty_box(tm) => { |
| remove_send(mutable_type_kind(cx, tm) | kind_safe_for_default_mode()) |
| } |
| |
| // Trait instances are (for now) like shared boxes, basically |
| ty_trait(_, _, _) => kind_safe_for_default_mode() | kind_owned(), |
| |
| // Static region pointers are copyable and sendable, but not owned |
| ty_rptr(re_static, mt) => |
| kind_safe_for_default_mode() | mutable_type_kind(cx, mt), |
| |
| // General region pointers are copyable but NOT owned nor sendable |
| ty_rptr(_, _) => kind_safe_for_default_mode(), |
| |
| // Unique boxes and vecs have the kind of their contained type, |
| // but unique boxes can't be implicitly copyable. |
| ty_uniq(tm) => remove_implicit(mutable_type_kind(cx, tm)), |
| |
| // Implicit copyability of vecs is configurable |
| ty_evec(tm, vstore_uniq) => { |
| if cx.vecs_implicitly_copyable { |
| mutable_type_kind(cx, tm) |
| } else { |
| remove_implicit(mutable_type_kind(cx, tm)) |
| } |
| } |
| |
| // Slices, refcounted evecs are copyable; uniques depend on the their |
| // contained type, but aren't implicitly copyable. Fixed vectors have |
| // the kind of the element they contain, taking mutability into account. |
| ty_evec(tm, vstore_box) => { |
| remove_send(kind_safe_for_default_mode() | mutable_type_kind(cx, tm)) |
| } |
| ty_evec(tm, vstore_slice(re_static)) => { |
| kind_safe_for_default_mode() | mutable_type_kind(cx, tm) |
| } |
| ty_evec(tm, vstore_slice(_)) => { |
| remove_owned_send(kind_safe_for_default_mode() | |
| mutable_type_kind(cx, tm)) |
| } |
| ty_evec(tm, vstore_fixed(_)) => { |
| mutable_type_kind(cx, tm) |
| } |
| |
| // All estrs are copyable; uniques and interiors are sendable. |
| ty_estr(vstore_box) => { |
| kind_safe_for_default_mode() | kind_const() | kind_owned() |
| } |
| ty_estr(vstore_slice(re_static)) => { |
| kind_safe_for_default_mode() | kind_send_copy() | kind_const() |
| } |
| ty_estr(vstore_slice(_)) => { |
| kind_safe_for_default_mode() | kind_const() |
| } |
| ty_estr(vstore_fixed(_)) => { |
| kind_safe_for_default_mode_send() | kind_const() | kind_owned() |
| } |
| |
| // Records lower to the lowest of their members. |
| ty_rec(flds) => { |
| let mut lowest = kind_top(); |
| for flds.each |f| { |
| lowest = lower_kind(lowest, mutable_type_kind(cx, f.mt)); |
| } |
| lowest |
| } |
| |
| ty_class(did, ref substs) => { |
| // Classes are sendable if all their fields are sendable, |
| // likewise for copyable... |
| // also factor out this code, copied from the records case |
| let mut lowest = kind_top(); |
| let flds = class_items_as_fields(cx, did, substs); |
| for flds.each |f| { |
| lowest = lower_kind(lowest, mutable_type_kind(cx, f.mt)); |
| } |
| // ...but classes with dtors are never copyable (they can be |
| // sendable) |
| if ty::has_dtor(cx, did) { |
| lowest = remove_copyable(lowest); |
| } |
| lowest |
| } |
| |
| // Tuples lower to the lowest of their members. |
| ty_tup(tys) => { |
| let mut lowest = kind_top(); |
| for tys.each |ty| { lowest = lower_kind(lowest, type_kind(cx, *ty)); } |
| lowest |
| } |
| |
| // Enums lower to the lowest of their variants. |
| ty_enum(did, ref substs) => { |
| let mut lowest = kind_top(); |
| let variants = enum_variants(cx, did); |
| if vec::len(*variants) == 0u { |
| lowest = kind_send_only() | kind_owned(); |
| } else { |
| for vec::each(*variants) |variant| { |
| for variant.args.each |aty| { |
| // Perform any type parameter substitutions. |
| let arg_ty = subst(cx, substs, *aty); |
| lowest = lower_kind(lowest, type_kind(cx, arg_ty)); |
| if lowest == kind_noncopyable() { break; } |
| } |
| } |
| } |
| lowest |
| } |
| |
| ty_param(p) => { |
| param_bounds_to_kind(cx.ty_param_bounds.get(p.def_id.node)) |
| } |
| |
| // self is a special type parameter that can only appear in traits; it |
| // is never bounded in any way, hence it has the bottom kind. |
| ty_self => kind_noncopyable(), |
| |
| ty_infer(_) => { |
| cx.sess.bug(~"Asked to compute kind of a type variable"); |
| } |
| ty_type | ty_opaque_closure_ptr(_) |
| | ty_opaque_box | ty_unboxed_vec(_) => { |
| cx.sess.bug(~"Asked to compute kind of fictitious type"); |
| } |
| }; |
| |
| // arbitrary threshold to prevent by-value copying of big records |
| if kind_is_safe_for_default_mode(result) { |
| if type_size(cx, ty) > 4 { |
| result -= kind_(KIND_MASK_DEFAULT_MODE); |
| } |
| } |
| |
| cx.kind_cache.insert(ty, result); |
| return result; |
| } |
| |
| /// gives a rough estimate of how much space it takes to represent |
| /// an instance of `ty`. Used for the mode transition. |
| fn type_size(cx: ctxt, ty: t) -> uint { |
| match get(ty).sty { |
| ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | |
| ty_ptr(_) | ty_box(_) | ty_uniq(_) | ty_estr(vstore_uniq) | |
| ty_trait(*) | ty_rptr(*) | ty_evec(_, vstore_uniq) | |
| ty_evec(_, vstore_box) | ty_estr(vstore_box) => { |
| 1 |
| } |
| |
| ty_evec(_, vstore_slice(_)) | |
| ty_estr(vstore_slice(_)) | |
| ty_fn(_) => { |
| 2 |
| } |
| |
| ty_evec(t, vstore_fixed(n)) => { |
| type_size(cx, t.ty) * n |
| } |
| |
| ty_estr(vstore_fixed(n)) => { |
| n |
| } |
| |
| ty_rec(flds) => { |
| flds.foldl(0, |s, f| *s + type_size(cx, f.mt.ty)) |
| } |
| |
| ty_class(did, ref substs) => { |
| let flds = class_items_as_fields(cx, did, substs); |
| flds.foldl(0, |s, f| *s + type_size(cx, f.mt.ty)) |
| } |
| |
| ty_tup(tys) => { |
| tys.foldl(0, |s, t| *s + type_size(cx, *t)) |
| } |
| |
| ty_enum(did, ref substs) => { |
| let variants = substd_enum_variants(cx, did, substs); |
| variants.foldl( // find max size of any variant |
| 0, |
| |m, v| uint::max(*m, |
| // find size of this variant: |
| v.args.foldl(0, |s, a| *s + type_size(cx, *a)))) |
| } |
| |
| ty_param(_) | ty_self => { |
| 1 |
| } |
| |
| ty_infer(_) => { |
| cx.sess.bug(~"Asked to compute kind of a type variable"); |
| } |
| ty_type | ty_opaque_closure_ptr(_) |
| | ty_opaque_box | ty_unboxed_vec(_) => { |
| cx.sess.bug(~"Asked to compute kind of fictitious type"); |
| } |
| } |
| } |
| |
| // True if instantiating an instance of `r_ty` requires an instance of `r_ty`. |
| fn is_instantiable(cx: ctxt, r_ty: t) -> bool { |
| |
| fn type_requires(cx: ctxt, seen: @mut ~[def_id], |
| r_ty: t, ty: t) -> bool { |
| debug!("type_requires(%s, %s)?", |
| ty_to_str(cx, r_ty), |
| ty_to_str(cx, ty)); |
| |
| let r = { |
| get(r_ty).sty == get(ty).sty || |
| subtypes_require(cx, seen, r_ty, ty) |
| }; |
| |
| debug!("type_requires(%s, %s)? %b", |
| ty_to_str(cx, r_ty), |
| ty_to_str(cx, ty), |
| r); |
| return r; |
| } |
| |
| fn subtypes_require(cx: ctxt, seen: @mut ~[def_id], |
| r_ty: t, ty: t) -> bool { |
| debug!("subtypes_require(%s, %s)?", |
| ty_to_str(cx, r_ty), |
| ty_to_str(cx, ty)); |
| |
| let r = match get(ty).sty { |
| ty_nil | |
| ty_bot | |
| ty_bool | |
| ty_int(_) | |
| ty_uint(_) | |
| ty_float(_) | |
| ty_estr(_) | |
| ty_fn(_) | |
| ty_infer(_) | |
| ty_param(_) | |
| ty_self | |
| ty_type | |
| ty_opaque_box | |
| ty_opaque_closure_ptr(_) | |
| ty_evec(_, _) | |
| ty_unboxed_vec(_) => { |
| false |
| } |
| ty_box(mt) | |
| ty_uniq(mt) | |
| ty_rptr(_, mt) => { |
| return type_requires(cx, seen, r_ty, mt.ty); |
| } |
| |
| ty_ptr(*) => { |
| false // unsafe ptrs can always be NULL |
| } |
| |
| ty_rec(fields) => { |
| do vec::any(fields) |field| { |
| type_requires(cx, seen, r_ty, field.mt.ty) |
| } |
| } |
| |
| ty_trait(_, _, _) => { |
| false |
| } |
| |
| ty_class(ref did, _) if vec::contains(*seen, did) => { |
| false |
| } |
| |
| ty_class(did, ref substs) => { |
| seen.push(did); |
| let r = vec::any(class_items_as_fields(cx, did, substs), |
| |f| type_requires(cx, seen, r_ty, f.mt.ty)); |
| seen.pop(); |
| r |
| } |
| |
| ty_tup(ts) => { |
| vec::any(ts, |t| type_requires(cx, seen, r_ty, *t)) |
| } |
| |
| ty_enum(ref did, _) if vec::contains(*seen, did) => { |
| false |
| } |
| |
| ty_enum(did, ref substs) => { |
| seen.push(did); |
| let vs = enum_variants(cx, did); |
| let r = vec::len(*vs) > 0u && vec::all(*vs, |variant| { |
| vec::any(variant.args, |aty| { |
| let sty = subst(cx, substs, *aty); |
| type_requires(cx, seen, r_ty, sty) |
| }) |
| }); |
| seen.pop(); |
| r |
| } |
| }; |
| |
| debug!("subtypes_require(%s, %s)? %b", |
| ty_to_str(cx, r_ty), |
| ty_to_str(cx, ty), |
| r); |
| |
| return r; |
| } |
| |
| let seen = @mut ~[]; |
| !subtypes_require(cx, seen, r_ty, r_ty) |
| } |
| |
| fn type_structurally_contains(cx: ctxt, ty: t, test: fn(x: &sty) -> bool) -> |
| bool { |
| let sty = &get(ty).sty; |
| debug!("type_structurally_contains: %s", ty_to_str(cx, ty)); |
| if test(sty) { return true; } |
| match *sty { |
| ty_enum(did, ref substs) => { |
| for vec::each(*enum_variants(cx, did)) |variant| { |
| for variant.args.each |aty| { |
| let sty = subst(cx, substs, *aty); |
| if type_structurally_contains(cx, sty, test) { return true; } |
| } |
| } |
| return false; |
| } |
| ty_rec(fields) => { |
| for fields.each |field| { |
| if type_structurally_contains(cx, field.mt.ty, test) { |
| return true; |
| } |
| } |
| return false; |
| } |
| ty_class(did, ref substs) => { |
| for lookup_class_fields(cx, did).each |field| { |
| let ft = lookup_field_type(cx, did, field.id, substs); |
| if type_structurally_contains(cx, ft, test) { return true; } |
| } |
| return false; |
| } |
| |
| ty_tup(ts) => { |
| for ts.each |tt| { |
| if type_structurally_contains(cx, *tt, test) { return true; } |
| } |
| return false; |
| } |
| ty_evec(mt, vstore_fixed(_)) => { |
| return type_structurally_contains(cx, mt.ty, test); |
| } |
| _ => return false |
| } |
| } |
| |
| fn type_structurally_contains_uniques(cx: ctxt, ty: t) -> bool { |
| return type_structurally_contains(cx, ty, |sty| { |
| match *sty { |
| ty_uniq(_) | |
| ty_evec(_, vstore_uniq) | |
| ty_estr(vstore_uniq) => true, |
| _ => false, |
| } |
| }); |
| } |
| |
| fn type_is_integral(ty: t) -> bool { |
| match get(ty).sty { |
| ty_infer(IntVar(_)) | ty_int(_) | ty_uint(_) | ty_bool => true, |
| _ => false |
| } |
| } |
| |
| fn type_is_fp(ty: t) -> bool { |
| match get(ty).sty { |
| ty_float(_) => true, |
| _ => false |
| } |
| } |
| |
| fn type_is_numeric(ty: t) -> bool { |
| return type_is_integral(ty) || type_is_fp(ty); |
| } |
| |
| fn type_is_signed(ty: t) -> bool { |
| match get(ty).sty { |
| ty_int(_) => true, |
| _ => false |
| } |
| } |
| |
| // Whether a type is Plain Old Data -- meaning it does not contain pointers |
| // that the cycle collector might care about. |
| fn type_is_pod(cx: ctxt, ty: t) -> bool { |
| let mut result = true; |
| match get(ty).sty { |
| // Scalar types |
| ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) | |
| ty_type | ty_ptr(_) => result = true, |
| // Boxed types |
| ty_box(_) | ty_uniq(_) | ty_fn(_) | |
| ty_estr(vstore_uniq) | ty_estr(vstore_box) | |
| ty_evec(_, vstore_uniq) | ty_evec(_, vstore_box) | |
| ty_trait(_, _, _) | ty_rptr(_,_) | ty_opaque_box => result = false, |
| // Structural types |
| ty_enum(did, ref substs) => { |
| let variants = enum_variants(cx, did); |
| for vec::each(*variants) |variant| { |
| let tup_ty = mk_tup(cx, variant.args); |
| |
| // Perform any type parameter substitutions. |
| let tup_ty = subst(cx, substs, tup_ty); |
| if !type_is_pod(cx, tup_ty) { result = false; } |
| } |
| } |
| ty_rec(flds) => { |
| for flds.each |f| { |
| if !type_is_pod(cx, f.mt.ty) { result = false; } |
| } |
| } |
| ty_tup(elts) => { |
| for elts.each |elt| { if !type_is_pod(cx, *elt) { result = false; } } |
| } |
| ty_estr(vstore_fixed(_)) => result = true, |
| ty_evec(mt, vstore_fixed(_)) | ty_unboxed_vec(mt) => { |
| result = type_is_pod(cx, mt.ty); |
| } |
| ty_param(_) => result = false, |
| ty_opaque_closure_ptr(_) => result = true, |
| ty_class(did, ref substs) => { |
| result = vec::any(lookup_class_fields(cx, did), |f| { |
| let fty = ty::lookup_item_type(cx, f.id); |
| let sty = subst(cx, substs, fty.ty); |
| type_is_pod(cx, sty) |
| }); |
| } |
| |
| ty_estr(vstore_slice(*)) | ty_evec(_, vstore_slice(*)) => { |
| result = false; |
| } |
| |
| ty_infer(*) | ty_self(*) => { |
| cx.sess.bug(~"non concrete type in type_is_pod"); |
| } |
| } |
| |
| return result; |
| } |
| |
| fn type_is_enum(ty: t) -> bool { |
| match get(ty).sty { |
| ty_enum(_, _) => return true, |
| _ => return false |
| } |
| } |
| |
| // 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 { |
| match get(ty).sty { |
| ty_enum(did, _) => { |
| let variants = enum_variants(cx, did); |
| let some_n_ary = vec::any(*variants, |v| vec::len(v.args) > 0u); |
| return !some_n_ary; |
| } |
| _ => return false |
| } |
| } |
| |
| fn type_param(ty: t) -> Option<uint> { |
| match get(ty).sty { |
| ty_param(p) => return Some(p.idx), |
| _ => {/* fall through */ } |
| } |
| return None; |
| } |
| |
| // Returns the type and mutability of *t. |
| // |
| // The parameter `expl` indicates if this is an *explicit* dereference. Some |
| // types---notably unsafe ptrs---can only be dereferenced explicitly. |
| fn deref(cx: ctxt, t: t, expl: bool) -> Option<mt> { |
| deref_sty(cx, &get(t).sty, expl) |
| } |
| fn deref_sty(cx: ctxt, sty: &sty, expl: bool) -> Option<mt> { |
| match *sty { |
| ty_rptr(_, mt) | ty_box(mt) | ty_uniq(mt) => { |
| Some(mt) |
| } |
| |
| ty_ptr(mt) if expl => { |
| Some(mt) |
| } |
| |
| ty_enum(did, ref substs) => { |
| let variants = enum_variants(cx, did); |
| if vec::len(*variants) == 1u && vec::len(variants[0].args) == 1u { |
| let v_t = subst(cx, substs, variants[0].args[0]); |
| Some({ty: v_t, mutbl: ast::m_imm}) |
| } else { |
| None |
| } |
| } |
| |
| _ => None |
| } |
| } |
| |
| fn type_autoderef(cx: ctxt, t: t) -> t { |
| let mut t = t; |
| loop { |
| match deref(cx, t, false) { |
| None => return t, |
| Some(mt) => t = mt.ty |
| } |
| } |
| } |
| |
| // Returns the type and mutability of t[i] |
| fn index(cx: ctxt, t: t) -> Option<mt> { |
| index_sty(cx, &get(t).sty) |
| } |
| |
| fn index_sty(cx: ctxt, sty: &sty) -> Option<mt> { |
| match *sty { |
| ty_evec(mt, _) => Some(mt), |
| ty_estr(_) => Some({ty: mk_u8(cx), mutbl: ast::m_imm}), |
| _ => None |
| } |
| } |
| |
| impl bound_region : to_bytes::IterBytes { |
| pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) { |
| match self { |
| ty::br_self => 0u8.iter_bytes(lsb0, f), |
| |
| ty::br_anon(ref idx) => |
| to_bytes::iter_bytes_2(&1u8, idx, lsb0, f), |
| |
| ty::br_named(ref ident) => |
| to_bytes::iter_bytes_2(&2u8, ident, lsb0, f), |
| |
| ty::br_cap_avoid(ref id, ref br) => |
| to_bytes::iter_bytes_3(&3u8, id, br, lsb0, f) |
| } |
| } |
| } |
| |
| impl region : to_bytes::IterBytes { |
| pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) { |
| match self { |
| re_bound(ref br) => |
| to_bytes::iter_bytes_2(&0u8, br, lsb0, f), |
| |
| re_free(ref id, ref br) => |
| to_bytes::iter_bytes_3(&1u8, id, br, lsb0, f), |
| |
| re_scope(ref id) => |
| to_bytes::iter_bytes_2(&2u8, id, lsb0, f), |
| |
| re_var(ref id) => |
| to_bytes::iter_bytes_2(&3u8, id, lsb0, f), |
| |
| re_static => 4u8.iter_bytes(lsb0, f) |
| } |
| } |
| } |
| |
| impl vstore : to_bytes::IterBytes { |
| pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) { |
| match self { |
| vstore_fixed(ref u) => |
| to_bytes::iter_bytes_2(&0u8, u, lsb0, f), |
| |
| vstore_uniq => 1u8.iter_bytes(lsb0, f), |
| vstore_box => 2u8.iter_bytes(lsb0, f), |
| |
| vstore_slice(ref r) => |
| to_bytes::iter_bytes_2(&3u8, r, lsb0, f), |
| } |
| } |
| } |
| |
| impl substs : to_bytes::IterBytes { |
| pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) { |
| to_bytes::iter_bytes_3(&self.self_r, |
| &self.self_ty, |
| &self.tps, lsb0, f) |
| } |
| } |
| |
| impl mt : to_bytes::IterBytes { |
| pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) { |
| to_bytes::iter_bytes_2(&self.ty, |
| &self.mutbl, lsb0, f) |
| } |
| } |
| |
| impl field : to_bytes::IterBytes { |
| pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) { |
| to_bytes::iter_bytes_2(&self.ident, |
| &self.mt, lsb0, f) |
| } |
| } |
| |
| impl arg : to_bytes::IterBytes { |
| pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) { |
| to_bytes::iter_bytes_2(&self.mode, |
| &self.ty, lsb0, f) |
| } |
| } |
| |
| impl sty : to_bytes::IterBytes { |
| pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) { |
| match self { |
| ty_nil => 0u8.iter_bytes(lsb0, f), |
| ty_bool => 1u8.iter_bytes(lsb0, f), |
| |
| ty_int(ref t) => |
| to_bytes::iter_bytes_2(&2u8, t, lsb0, f), |
| |
| ty_uint(ref t) => |
| to_bytes::iter_bytes_2(&3u8, t, lsb0, f), |
| |
| ty_float(ref t) => |
| to_bytes::iter_bytes_2(&4u8, t, lsb0, f), |
| |
| ty_estr(ref v) => |
| to_bytes::iter_bytes_2(&5u8, v, lsb0, f), |
| |
| ty_enum(ref did, ref substs) => |
| to_bytes::iter_bytes_3(&6u8, did, substs, lsb0, f), |
| |
| ty_box(ref mt) => |
| to_bytes::iter_bytes_2(&7u8, mt, lsb0, f), |
| |
| ty_evec(ref mt, ref v) => |
| to_bytes::iter_bytes_3(&8u8, mt, v, lsb0, f), |
| |
| ty_unboxed_vec(ref mt) => |
| to_bytes::iter_bytes_2(&9u8, mt, lsb0, f), |
| |
| ty_tup(ref ts) => |
| to_bytes::iter_bytes_2(&10u8, ts, lsb0, f), |
| |
| ty_rec(ref fs) => |
| to_bytes::iter_bytes_2(&11u8, fs, lsb0, f), |
| |
| ty_fn(ref ft) => |
| to_bytes::iter_bytes_7(&12u8, |
| &ft.meta.purity, |
| &ft.meta.proto, |
| &ft.meta.bounds, |
| &ft.sig.inputs, |
| &ft.sig.output, |
| &ft.meta.ret_style, |
| lsb0, f), |
| |
| ty_self => 13u8.iter_bytes(lsb0, f), |
| |
| ty_infer(ref v) => |
| to_bytes::iter_bytes_2(&14u8, v, lsb0, f), |
| |
| ty_param(ref p) => |
| to_bytes::iter_bytes_2(&15u8, p, lsb0, f), |
| |
| ty_type => 16u8.iter_bytes(lsb0, f), |
| ty_bot => 17u8.iter_bytes(lsb0, f), |
| |
| ty_ptr(ref mt) => |
| to_bytes::iter_bytes_2(&18u8, mt, lsb0, f), |
| |
| ty_uniq(ref mt) => |
| to_bytes::iter_bytes_2(&19u8, mt, lsb0, f), |
| |
| ty_trait(ref did, ref substs, ref v) => |
| to_bytes::iter_bytes_4(&20u8, did, substs, v, lsb0, f), |
| |
| ty_opaque_closure_ptr(ref ck) => |
| to_bytes::iter_bytes_2(&21u8, ck, lsb0, f), |
| |
| ty_opaque_box => 22u8.iter_bytes(lsb0, f), |
| |
| ty_class(ref did, ref substs) => |
| to_bytes::iter_bytes_3(&23u8, did, substs, lsb0, f), |
| |
| ty_rptr(ref r, ref mt) => |
| to_bytes::iter_bytes_3(&24u8, r, mt, lsb0, f), |
| } |
| } |
| } |
| |
| fn br_hashmap<V:Copy>() -> HashMap<bound_region, V> { |
| map::HashMap() |
| } |
| |
| fn node_id_to_type(cx: ctxt, id: ast::node_id) -> t { |
| //io::println(fmt!("%?/%?", id, cx.node_types.size())); |
| match smallintmap::find(*cx.node_types, id as uint) { |
| Some(t) => t, |
| None => cx.sess.bug( |
| fmt!("node_id_to_type: no type for node `%s`", |
| ast_map::node_id_to_str(cx.items, id, |
| cx.sess.parse_sess.interner))) |
| } |
| } |
| |
| fn node_id_to_type_params(cx: ctxt, id: ast::node_id) -> ~[t] { |
| match cx.node_type_substs.find(id) { |
| None => return ~[], |
| Some(ts) => return ts |
| } |
| } |
| |
| fn node_id_has_type_params(cx: ctxt, id: ast::node_id) -> bool { |
| return cx.node_type_substs.contains_key(id); |
| } |
| |
| // Type accessors for substructures of types |
| fn ty_fn_args(fty: t) -> ~[arg] { |
| match get(fty).sty { |
| ty_fn(ref f) => f.sig.inputs, |
| _ => fail ~"ty_fn_args() called on non-fn type" |
| } |
| } |
| |
| fn ty_fn_proto(fty: t) -> fn_proto { |
| match get(fty).sty { |
| ty_fn(ref f) => f.meta.proto, |
| _ => fail ~"ty_fn_proto() called on non-fn type" |
| } |
| } |
| |
| fn ty_fn_purity(fty: t) -> ast::purity { |
| match get(fty).sty { |
| ty_fn(ref f) => f.meta.purity, |
| _ => fail ~"ty_fn_purity() called on non-fn type" |
| } |
| } |
| |
| pure fn ty_fn_ret(fty: t) -> t { |
| match get(fty).sty { |
| ty_fn(ref f) => f.sig.output, |
| _ => fail ~"ty_fn_ret() called on non-fn type" |
| } |
| } |
| |
| fn ty_fn_ret_style(fty: t) -> ast::ret_style { |
| match get(fty).sty { |
| ty_fn(ref f) => f.meta.ret_style, |
| _ => fail ~"ty_fn_ret_style() called on non-fn type" |
| } |
| } |
| |
| fn is_fn_ty(fty: t) -> bool { |
| match get(fty).sty { |
| ty_fn(_) => true, |
| _ => false |
| } |
| } |
| |
| fn ty_region(ty: t) -> region { |
| match get(ty).sty { |
| ty_rptr(r, _) => r, |
| s => fail fmt!("ty_region() invoked on non-rptr: %?", s) |
| } |
| } |
| |
| // Returns a vec of all the input and output types of fty. |
| fn tys_in_fn_ty(fty: &FnTy) -> ~[t] { |
| vec::append_one(fty.sig.inputs.map(|a| a.ty), fty.sig.output) |
| } |
| |
| // 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) -> TyVid { |
| match get(typ).sty { |
| ty_infer(TyVar(vid)) => return vid, |
| _ => { error!("ty_var_id called on non-var ty"); fail; } |
| } |
| } |
| |
| fn int_var_id(typ: t) -> IntVid { |
| match get(typ).sty { |
| ty_infer(IntVar(vid)) => return vid, |
| _ => { error!("ty_var_integral_id called on ty other than \ |
| ty_var_integral"); |
| fail; } |
| } |
| } |
| */ |
| |
| // Type accessors for AST nodes |
| fn block_ty(cx: ctxt, b: &ast::blk) -> t { |
| return node_id_to_type(cx, b.node.id); |
| } |
| |
| |
| // Returns the type of a pattern as a monotype. Like @expr_ty, this function |
| // doesn't provide type parameter substitutions. |
| fn pat_ty(cx: ctxt, pat: @ast::pat) -> t { |
| return 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 |
| // ask for the type of "id" in "id(3)", it will return "fn(&int) -> int" |
| // instead of "fn(t) -> T with T = int". If this isn't what you want, see |
| // expr_ty_params_and_ty() below. |
| fn expr_ty(cx: ctxt, expr: @ast::expr) -> t { |
| return node_id_to_type(cx, expr.id); |
| } |
| |
| fn expr_ty_params_and_ty(cx: ctxt, |
| expr: @ast::expr) -> {params: ~[t], ty: t} { |
| return {params: node_id_to_type_params(cx, expr.id), |
| ty: node_id_to_type(cx, expr.id)}; |
| } |
| |
| fn expr_has_ty_params(cx: ctxt, expr: @ast::expr) -> bool { |
| return node_id_has_type_params(cx, expr.id); |
| } |
| |
| fn method_call_bounds(tcx: ctxt, method_map: typeck::method_map, |
| id: ast::node_id) |
| -> Option<@~[param_bounds]> { |
| do method_map.find(id).map |method| { |
| match method.origin { |
| typeck::method_static(did) => { |
| // n.b.: When we encode class/impl methods, the bounds |
| // that we encode include both the class/impl bounds |
| // and then the method bounds themselves... |
| ty::lookup_item_type(tcx, did).bounds |
| } |
| typeck::method_param({trait_id:trt_id, |
| method_num:n_mth, _}) | |
| typeck::method_trait(trt_id, n_mth, _) | |
| typeck::method_self(trt_id, n_mth) => { |
| // ...trait methods bounds, in contrast, include only the |
| // method bounds, so we must preprend the tps from the |
| // trait itself. This ought to be harmonized. |
| let trt_bounds = |
| ty::lookup_item_type(tcx, trt_id).bounds; |
| let mth = ty::trait_methods(tcx, trt_id)[n_mth]; |
| @(vec::append(*trt_bounds, *mth.tps)) |
| } |
| } |
| } |
| } |
| |
| fn resolve_expr(tcx: ctxt, expr: @ast::expr) -> ast::def { |
| match tcx.def_map.find(expr.id) { |
| Some(def) => def, |
| None => { |
| tcx.sess.span_bug(expr.span, fmt!( |
| "No def-map entry for expr %?", expr.id)); |
| } |
| } |
| } |
| |
| fn expr_is_lval(tcx: ctxt, |
| method_map: typeck::method_map, |
| e: @ast::expr) -> bool { |
| match expr_kind(tcx, method_map, e) { |
| LvalueExpr => true, |
| RvalueDpsExpr | RvalueDatumExpr | RvalueStmtExpr => false |
| } |
| } |
| |
| /// We categorize expressions into three kinds. The distinction between |
| /// lvalue/rvalue is fundamental to the language. The distinction between the |
| /// two kinds of rvalues is an artifact of trans which reflects how we will |
| /// generate code for that kind of expression. See trans/expr.rs for more |
| /// information. |
| enum ExprKind { |
| LvalueExpr, |
| RvalueDpsExpr, |
| RvalueDatumExpr, |
| RvalueStmtExpr |
| } |
| |
| fn expr_kind(tcx: ctxt, |
| method_map: typeck::method_map, |
| expr: @ast::expr) -> ExprKind { |
| if method_map.contains_key(expr.id) { |
| // Overloaded operations are generally calls, and hence they are |
| // generated via DPS. However, assign_op (e.g., `x += y`) is an |
| // exception, as its result is always unit. |
| return match expr.node { |
| ast::expr_assign_op(*) => RvalueStmtExpr, |
| _ => RvalueDpsExpr |
| }; |
| } |
| |
| match expr.node { |
| ast::expr_path(*) => { |
| match resolve_expr(tcx, expr) { |
| ast::def_fn(*) | ast::def_static_method(*) | |
| ast::def_variant(*) => RvalueDpsExpr, |
| |
| // Note: there is actually a good case to be made that |
| // def_args, particularly those of immediate type, ought to |
| // considered rvalues. |
| ast::def_const(*) | |
| ast::def_binding(*) | |
| ast::def_upvar(*) | |
| ast::def_arg(*) | |
| ast::def_local(*) | |
| ast::def_self(*) => LvalueExpr, |
| |
| move def => { |
| tcx.sess.span_bug(expr.span, fmt!( |
| "Uncategorized def for expr %?: %?", |
| expr.id, def)); |
| } |
| } |
| } |
| |
| ast::expr_unary(ast::deref, _) | |
| ast::expr_field(*) | |
| ast::expr_index(*) => { |
| LvalueExpr |
| } |
| |
| ast::expr_call(*) | |
| ast::expr_rec(*) | |
| ast::expr_struct(*) | |
| ast::expr_tup(*) | |
| ast::expr_if(*) | |
| ast::expr_match(*) | |
| ast::expr_fn(*) | |
| ast::expr_fn_block(*) | |
| ast::expr_loop_body(*) | |
| ast::expr_do_body(*) | |
| ast::expr_block(*) | |
| ast::expr_copy(*) | |
| ast::expr_unary_move(*) | |
| ast::expr_repeat(*) | |
| ast::expr_lit(@{node: lit_str(_), _}) | |
| ast::expr_vstore(_, ast::expr_vstore_slice) | |
| ast::expr_vstore(_, ast::expr_vstore_fixed(_)) | |
| ast::expr_vec(*) => { |
| RvalueDpsExpr |
| } |
| |
| ast::expr_cast(*) => { |
| match smallintmap::find(*tcx.node_types, expr.id as uint) { |
| Some(t) => { |
| if ty::type_is_immediate(t) { |
| RvalueDatumExpr |
| } else { |
| RvalueDpsExpr |
| } |
| } |
| None => { |
| // Technically, it should not happen that the expr is not |
| // present within the table. However, it DOES happen |
| // during type check, because the final types from the |
| // expressions are not yet recorded in the tcx. At that |
| // time, though, we are only interested in knowing lvalue |
| // vs rvalue. It would be better to base this decision on |
| // the AST type in cast node---but (at the time of this |
| // writing) it's not easy to distinguish casts to traits |
| // from other casts based on the AST. This should be |
| // easier in the future, when casts to traits would like |
| // like @Foo, ~Foo, or &Foo. |
| RvalueDatumExpr |
| } |
| } |
| } |
| |
| ast::expr_break(*) | |
| ast::expr_again(*) | |
| ast::expr_ret(*) | |
| ast::expr_log(*) | |
| ast::expr_fail(*) | |
| ast::expr_assert(*) | |
| ast::expr_while(*) | |
| ast::expr_loop(*) | |
| ast::expr_assign(*) | |
| ast::expr_move(*) | |
| ast::expr_swap(*) | |
| ast::expr_assign_op(*) => { |
| RvalueStmtExpr |
| } |
| |
| ast::expr_lit(_) | // Note: lit_str is carved out above |
| ast::expr_unary(*) | |
| ast::expr_addr_of(*) | |
| ast::expr_binary(*) | |
| ast::expr_vstore(_, ast::expr_vstore_box) | |
| ast::expr_vstore(_, ast::expr_vstore_uniq) => { |
| RvalueDatumExpr |
| } |
| |
| ast::expr_mac(*) => { |
| tcx.sess.span_bug( |
| expr.span, |
| ~"macro expression remains after expansion"); |
| } |
| } |
| } |
| |
| fn stmt_node_id(s: @ast::stmt) -> ast::node_id { |
| match s.node { |
| ast::stmt_decl(_, id) | stmt_expr(_, id) | stmt_semi(_, id) => { |
| return id; |
| } |
| } |
| } |
| |
| fn field_idx(id: ast::ident, fields: &[field]) -> Option<uint> { |
| let mut i = 0u; |
| for fields.each |f| { if f.ident == id { return Some(i); } i += 1u; } |
| return None; |
| } |
| |
| fn field_idx_strict(tcx: ty::ctxt, id: ast::ident, fields: &[field]) -> uint { |
| let mut i = 0u; |
| for fields.each |f| { if f.ident == id { return i; } i += 1u; } |
| tcx.sess.bug(fmt!( |
| "No field named `%s` found in the list of fields `%?`", |
| tcx.sess.str_of(id), |
| fields.map(|f| tcx.sess.str_of(f.ident)))); |
| } |
| |
| fn get_field(tcx: ctxt, rec_ty: t, id: ast::ident) -> field { |
| match vec::find(get_fields(rec_ty), |f| f.ident == id) { |
| Some(f) => f, |
| // Do we only call this when we know the field is legit? |
| None => fail (#fmt("get_field: ty doesn't have a field %s", |
| tcx.sess.str_of(id))) |
| } |
| } |
| |
| fn get_fields(rec_ty:t) -> ~[field] { |
| match get(rec_ty).sty { |
| ty_rec(fields) => fields, |
| // Can we check at the caller? |
| _ => fail ~"get_fields: not a record type" |
| } |
| } |
| |
| fn method_idx(id: ast::ident, meths: &[method]) -> Option<uint> { |
| let mut i = 0u; |
| for meths.each |m| { if m.ident == id { return Some(i); } i += 1u; } |
| return None; |
| } |
| |
| /// Returns a vector containing the indices of all type parameters that appear |
| /// in `ty`. The vector may contain duplicates. Probably should be converted |
| /// to a bitset or some other representation. |
| fn param_tys_in_type(ty: t) -> ~[param_ty] { |
| let mut rslt = ~[]; |
| do walk_ty(ty) |ty| { |
| match get(ty).sty { |
| ty_param(p) => { |
| rslt.push(p); |
| } |
| _ => () |
| } |
| } |
| rslt |
| } |
| |
| fn occurs_check(tcx: ctxt, sp: span, vid: TyVid, rt: t) { |
| |
| // Returns a vec of all the type variables occurring in `ty`. It may |
| // contain duplicates. (Integral type vars aren't counted.) |
| fn vars_in_type(ty: t) -> ~[TyVid] { |
| let mut rslt = ~[]; |
| do walk_ty(ty) |ty| { |
| match get(ty).sty { |
| ty_infer(TyVar(v)) => rslt.push(v), |
| _ => () |
| } |
| } |
| rslt |
| } |
| |
| // Fast path |
| if !type_needs_infer(rt) { return; } |
| |
| // 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<T:Copy cmp::Eq>(tbl: HashMap<ast::node_id, ast::inferable<T>>, |
| +m0: ast::inferable<T>) -> ast::inferable<T> { |
| match m0 { |
| ast::infer(id) => match tbl.find(id) { |
| None => m0, |
| Some(m1) => { |
| let cm1 = canon(tbl, m1); |
| // path compression: |
| if cm1 != m1 { tbl.insert(id, cm1); } |
| cm1 |
| } |
| }, |
| _ => m0 |
| } |
| } |
| |
| // Maintains a little union-set tree for inferred modes. `resolve_mode()` |
| // returns the current head value for `m0`. |
| fn canon_mode(cx: ctxt, m0: ast::mode) -> ast::mode { |
| canon(cx.inferred_modes, m0) |
| } |
| |
| // Returns the head value for mode, failing if `m` was a infer(_) that |
| // was never inferred. This should be safe for use after typeck. |
| fn resolved_mode(cx: ctxt, m: ast::mode) -> ast::rmode { |
| match canon_mode(cx, m) { |
| ast::infer(_) => { |
| cx.sess.bug(fmt!("mode %? was never resolved", m)); |
| } |
| ast::expl(m0) => m0 |
| } |
| } |
| |
| fn arg_mode(cx: ctxt, a: arg) -> ast::rmode { resolved_mode(cx, a.mode) } |
| |
| // Unifies `m1` and `m2`. Returns unified value or failure code. |
| fn unify_mode(cx: ctxt, modes: expected_found<ast::mode>) |
| -> Result<ast::mode, type_err> { |
| |
| let m1 = modes.expected; |
| let m2 = modes.found; |
| match (canon_mode(cx, m1), canon_mode(cx, m2)) { |
| (m1, m2) if (m1 == m2) => { |
| result::Ok(m1) |
| } |
| (ast::infer(_), ast::infer(id2)) => { |
| cx.inferred_modes.insert(id2, m1); |
| result::Ok(m1) |
| } |
| (ast::infer(id), m) | (m, ast::infer(id)) => { |
| cx.inferred_modes.insert(id, m); |
| result::Ok(m1) |
| } |
| (_, _) => { |
| result::Err(terr_mode_mismatch(modes)) |
| } |
| } |
| } |
| |
| // If `m` was never unified, unifies it with `m_def`. Returns the final value |
| // for `m`. |
| fn set_default_mode(cx: ctxt, m: ast::mode, m_def: ast::rmode) { |
| match canon_mode(cx, m) { |
| ast::infer(id) => { |
| cx.inferred_modes.insert(id, ast::expl(m_def)); |
| } |
| ast::expl(_) => () |
| } |
| } |
| |
| fn ty_sort_str(cx: ctxt, t: t) -> ~str { |
| match get(t).sty { |
| ty_nil | ty_bot | ty_bool | ty_int(_) | |
| ty_uint(_) | ty_float(_) | ty_estr(_) | |
| ty_type | ty_opaque_box | ty_opaque_closure_ptr(_) => { |
| ty_to_str(cx, t) |
| } |
| |
| ty_enum(id, _) => fmt!("enum %s", item_path_str(cx, id)), |
| ty_box(_) => ~"@-ptr", |
| ty_uniq(_) => ~"~-ptr", |
| ty_evec(_, _) => ~"vector", |
| ty_unboxed_vec(_) => ~"unboxed vector", |
| ty_ptr(_) => ~"*-ptr", |
| ty_rptr(_, _) => ~"&-ptr", |
| ty_rec(_) => ~"record", |
| ty_fn(_) => ~"fn", |
| ty_trait(id, _, _) => fmt!("trait %s", item_path_str(cx, id)), |
| ty_class(id, _) => fmt!("class %s", item_path_str(cx, id)), |
| ty_tup(_) => ~"tuple", |
| ty_infer(TyVar(_)) => ~"inferred type", |
| ty_infer(IntVar(_)) => ~"integral variable", |
| ty_param(_) => ~"type parameter", |
| ty_self => ~"self" |
| } |
| } |
| |
| fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str { |
| /*! |
| * |
| * Explains the source of a type err in a short, |
| * human readable way. This is meant to be placed in |
| * parentheses after some larger message. You should |
| * also invoke `note_and_explain_type_err()` afterwards |
| * to present additional details, particularly when |
| * it comes to lifetime-related errors. */ |
| |
| fn terr_vstore_kind_to_str(k: terr_vstore_kind) -> ~str { |
| match k { |
| terr_vec => ~"[]", |
| terr_str => ~"str", |
| terr_fn => ~"fn", |
| terr_trait => ~"trait" |
| } |
| } |
| |
| match *err { |
| terr_mismatch => ~"types differ", |
| terr_ret_style_mismatch(values) => { |
| fn to_str(s: ast::ret_style) -> ~str { |
| match s { |
| ast::noreturn => ~"non-returning", |
| ast::return_val => ~"return-by-value" |
| } |
| } |
| fmt!("expected %s function, found %s function", |
| to_str(values.expected), |
| to_str(values.expected)) |
| } |
| terr_purity_mismatch(values) => { |
| fmt!("expected %s fn but found %s fn", |
| purity_to_str(values.expected), |
| purity_to_str(values.found)) |
| } |
| terr_proto_mismatch(values) => { |
| fmt!("expected %s closure, found %s closure", |
| proto_ty_to_str(cx, values.expected), |
| proto_ty_to_str(cx, values.found)) |
| } |
| terr_mutability => ~"values differ in mutability", |
| terr_box_mutability => ~"boxed values differ in mutability", |
| terr_vec_mutability => ~"vectors differ in mutability", |
| terr_ptr_mutability => ~"pointers differ in mutability", |
| terr_ref_mutability => ~"references differ in mutability", |
| terr_ty_param_size(values) => { |
| fmt!("expected a type with %? type params \ |
| but found one with %? type params", |
| values.expected, values.found) |
| } |
| terr_tuple_size(values) => { |
| fmt!("expected a tuple with %? elements \ |
| but found one with %? elements", |
| values.expected, values.found) |
| } |
| terr_record_size(values) => { |
| fmt!("expected a record with %? fields \ |
| but found one with %? fields", |
| values.expected, values.found) |
| } |
| terr_record_mutability => { |
| ~"record elements differ in mutability" |
| } |
| terr_record_fields(values) => { |
| fmt!("expected a record with field `%s` but found one with field \ |
| `%s`", |
| cx.sess.str_of(values.expected), cx.sess.str_of(values.found)) |
| } |
| terr_arg_count => ~"incorrect number of function parameters", |
| terr_mode_mismatch(values) => { |
| fmt!("expected argument mode %s, but found %s", |
| mode_to_str(values.expected), mode_to_str(values.found)) |
| } |
| terr_regions_does_not_outlive(*) => { |
| fmt!("lifetime mismatch") |
| } |
| terr_regions_not_same(*) => { |
| fmt!("lifetimes are not the same") |
| } |
| terr_regions_no_overlap(*) => { |
| fmt!("lifetimes do not intersect") |
| } |
| terr_vstores_differ(k, values) => { |
| fmt!("%s storage differs: expected %s but found %s", |
| terr_vstore_kind_to_str(k), |
| vstore_to_str(cx, values.expected), |
| vstore_to_str(cx, values.found)) |
| } |
| terr_in_field(err, fname) => { |
| fmt!("in field `%s`, %s", cx.sess.str_of(fname), |
| type_err_to_str(cx, err)) |
| } |
| terr_sorts(values) => { |
| fmt!("expected %s but found %s", |
| ty_sort_str(cx, values.expected), |
| ty_sort_str(cx, values.found)) |
| } |
| terr_self_substs => { |
| ~"inconsistent self substitution" // XXX this is more of a bug |
| } |
| terr_no_integral_type => { |
| ~"couldn't determine an appropriate integral type for integer \ |
| literal" |
| } |
| } |
| } |
| |
| fn note_and_explain_type_err(cx: ctxt, err: &type_err) { |
| match *err { |
| terr_regions_does_not_outlive(subregion, superregion) => { |
| note_and_explain_region(cx, ~"", subregion, ~"..."); |
| note_and_explain_region(cx, ~"...does not necessarily outlive ", |
| superregion, ~""); |
| } |
| terr_regions_not_same(region1, region2) => { |
| note_and_explain_region(cx, ~"", region1, ~"..."); |
| note_and_explain_region(cx, ~"...is not the same lifetime as ", |
| region2, ~""); |
| } |
| terr_regions_no_overlap(region1, region2) => { |
| note_and_explain_region(cx, ~"", region1, ~"..."); |
| note_and_explain_region(cx, ~"...does not overlap ", |
| region2, ~""); |
| } |
| _ => {} |
| } |
| } |
| |
| fn def_has_ty_params(def: ast::def) -> bool { |
| match def { |
| ast::def_fn(_, _) | ast::def_variant(_, _) | ast::def_class(_, _) |
| => true, |
| _ => false |
| } |
| } |
| |
| fn store_trait_methods(cx: ctxt, id: ast::node_id, ms: @~[method]) { |
| cx.trait_method_cache.insert(ast_util::local_def(id), ms); |
| } |
| |
| fn provided_trait_methods(cx: ctxt, id: ast::def_id) -> ~[@ast::method] { |
| if is_local(id) { |
| match cx.items.find(id.node) { |
| Some(ast_map::node_item(@{node: item_trait(_, _, ms),_}, _)) => |
| match ast_util::split_trait_methods(ms) { |
| (_, p) => p |
| }, |
| _ => cx.sess.bug(#fmt("provided_trait_methods: %? is not a trait", |
| id)) |
| } |
| } |
| else { |
| // FIXME #2794: default methods for traits don't work cross-crate |
| ~[] |
| } |
| } |
| |
| |
| fn trait_methods(cx: ctxt, id: ast::def_id) -> @~[method] { |
| match cx.trait_method_cache.find(id) { |
| // Local traits are supposed to have been added explicitly. |
| Some(ms) => ms, |
| _ => { |
| // If the lookup in trait_method_cache fails, assume that the trait |
| // method we're trying to look up is in a different crate, and look |
| // for it there. |
| assert id.crate != ast::local_crate; |
| let result = csearch::get_trait_methods(cx, id); |
| |
| // Store the trait method in the local trait_method_cache so that |
| // future lookups succeed. |
| cx.trait_method_cache.insert(id, result); |
| result |
| } |
| } |
| } |
| |
| /* |
| Could this return a list of (def_id, substs) pairs? |
| */ |
| fn impl_traits(cx: ctxt, id: ast::def_id, vstore: vstore) -> ~[t] { |
| fn vstoreify(cx: ctxt, ty: t, vstore: vstore) -> t { |
| match ty::get(ty).sty { |
| ty::ty_trait(_, _, trait_vstore) if vstore == trait_vstore => ty, |
| ty::ty_trait(did, substs, _) => mk_trait(cx, did, substs, vstore), |
| _ => cx.sess.bug(~"impl_traits: not a trait") |
| } |
| } |
| |
| if id.crate == ast::local_crate { |
| debug!("(impl_traits) searching for trait impl %?", id); |
| match cx.items.find(id.node) { |
| Some(ast_map::node_item(@{ |
| node: ast::item_impl(_, opt_trait, _, _), |
| _}, |
| _)) => { |
| |
| do option::map_default(&opt_trait, ~[]) |trait_ref| { |
| ~[vstoreify(cx, |
| node_id_to_type(cx, trait_ref.ref_id), |
| vstore)] |
| } |
| } |
| Some(ast_map::node_item(@{node: ast::item_class(sd,_), |
| _},_)) => { |
| do vec::map(sd.traits) |trait_ref| { |
| vstoreify(cx, node_id_to_type(cx, trait_ref.ref_id), |
| vstore) |
| } |
| } |
| _ => ~[] |
| } |
| } else { |
| vec::map(csearch::get_impl_traits(cx, id), |
| |x| vstoreify(cx, *x, vstore)) |
| } |
| } |
| |
| fn ty_to_def_id(ty: t) -> Option<ast::def_id> { |
| match get(ty).sty { |
| ty_trait(id, _, _) | ty_class(id, _) | ty_enum(id, _) => Some(id), |
| _ => None |
| } |
| } |
| |
| // Enum information |
| type variant_info = @{args: ~[t], ctor_ty: t, name: ast::ident, |
| id: ast::def_id, disr_val: int}; |
| |
| fn substd_enum_variants(cx: ctxt, |
| id: ast::def_id, |
| substs: &substs) -> ~[variant_info] { |
| do vec::map(*enum_variants(cx, id)) |variant_info| { |
| let substd_args = vec::map(variant_info.args, |
| |aty| subst(cx, substs, *aty)); |
| |
| let substd_ctor_ty = subst(cx, substs, variant_info.ctor_ty); |
| |
| @{args: substd_args, ctor_ty: substd_ctor_ty, ..**variant_info} |
| } |
| } |
| |
| fn item_path_str(cx: ctxt, id: ast::def_id) -> ~str { |
| ast_map::path_to_str(item_path(cx, id), cx.sess.parse_sess.interner) |
| } |
| |
| /* If class_id names a class with a dtor, return Some(the dtor's id). |
| Otherwise return none. */ |
| fn ty_dtor(cx: ctxt, class_id: def_id) -> Option<def_id> { |
| if is_local(class_id) { |
| match cx.items.find(class_id.node) { |
| Some(ast_map::node_item(@{ |
| node: ast::item_class(@{ dtor: Some(dtor), _ }, _), |
| _ |
| }, _)) => |
| Some(local_def(dtor.node.id)), |
| _ => |
| None |
| } |
| } |
| else { |
| csearch::class_dtor(cx.sess.cstore, class_id) |
| } |
| } |
| |
| fn has_dtor(cx: ctxt, class_id: def_id) -> bool { |
| ty_dtor(cx, class_id).is_some() |
| } |
| |
| fn item_path(cx: ctxt, id: ast::def_id) -> ast_map::path { |
| if id.crate != ast::local_crate { |
| csearch::get_item_path(cx, id) |
| } else { |
| let node = cx.items.get(id.node); |
| match node { |
| ast_map::node_item(item, path) => { |
| let item_elt = match item.node { |
| item_mod(_) | item_foreign_mod(_) => { |
| ast_map::path_mod(item.ident) |
| } |
| _ => { |
| ast_map::path_name(item.ident) |
| } |
| }; |
| vec::append_one(*path, item_elt) |
| } |
| |
| ast_map::node_foreign_item(nitem, _, path) => { |
| vec::append_one(*path, ast_map::path_name(nitem.ident)) |
| } |
| |
| ast_map::node_method(method, _, path) => { |
| vec::append_one(*path, ast_map::path_name(method.ident)) |
| } |
| ast_map::node_trait_method(trait_method, _, path) => { |
| let method = ast_util::trait_method_to_ty_method(*trait_method); |
| vec::append_one(*path, ast_map::path_name(method.ident)) |
| } |
| |
| ast_map::node_variant(variant, _, path) => { |
| vec::append_one(vec::init(*path), |
| ast_map::path_name(variant.node.name)) |
| } |
| |
| ast_map::node_ctor(nm, _, _, _, path) => { |
| vec::append_one(*path, ast_map::path_name(nm)) |
| } |
| ast_map::node_dtor(_, _, _, path) => { |
| vec::append_one(*path, ast_map::path_name( |
| syntax::parse::token::special_idents::literally_dtor)) |
| } |
| |
| ast_map::node_stmt(*) | ast_map::node_expr(*) | |
| ast_map::node_arg(*) | ast_map::node_local(*) | |
| ast_map::node_export(*) | ast_map::node_block(*) => { |
| cx.sess.bug(fmt!("cannot find item_path for node %?", node)); |
| } |
| } |
| } |
| } |
| |
| fn enum_is_univariant(cx: ctxt, id: ast::def_id) -> bool { |
| vec::len(*enum_variants(cx, id)) == 1u |
| } |
| |
| fn type_is_empty(cx: ctxt, t: t) -> bool { |
| match ty::get(t).sty { |
| ty_enum(did, _) => (*enum_variants(cx, did)).is_empty(), |
| _ => false |
| } |
| } |
| |
| fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[variant_info] { |
| match cx.enum_var_cache.find(id) { |
| Some(variants) => return variants, |
| _ => { /* fallthrough */ } |
| } |
| |
| let result = if ast::local_crate != id.crate { |
| @csearch::get_enum_variants(cx, id) |
| } else { |
| /* |
| Although both this code and check_enum_variants in typeck/check |
| call eval_const_expr, it should never get called twice for the same |
| expr, since check_enum_variants also updates the enum_var_cache |
| */ |
| match cx.items.get(id.node) { |
| ast_map::node_item(@{node: ast::item_enum(enum_definition, _), _}, |
| _) => { |
| let variants = enum_definition.variants; |
| let mut disr_val = -1; |
| @vec::map(variants, |variant| { |
| match variant.node.kind { |
| ast::tuple_variant_kind(args) => { |
| let ctor_ty = node_id_to_type(cx, variant.node.id); |
| let arg_tys = { |
| if vec::len(args) > 0u { |
| ty_fn_args(ctor_ty).map(|a| a.ty) |
| } else { |
| ~[] |
| } |
| }; |
| match variant.node.disr_expr { |
| Some (ex) => { |
| disr_val = match const_eval::eval_const_expr(cx, |
| ex) { |
| const_eval::const_int(val) => val as int, |
| _ => cx.sess.bug(~"tag_variants: bad disr expr") |
| } |
| } |
| _ => disr_val += 1 |
| } |
| @{args: arg_tys, |
| ctor_ty: ctor_ty, |
| name: variant.node.name, |
| id: ast_util::local_def(variant.node.id), |
| disr_val: disr_val |
| } |
| } |
| ast::struct_variant_kind(_) => { |
| fail ~"struct variant kinds unimpl in enum_variants" |
| } |
| ast::enum_variant_kind(_) => { |
| fail ~"enum variant kinds unimpl in enum_variants" |
| } |
| } |
| }) |
| } |
| _ => cx.sess.bug(~"tag_variants: id not bound to an enum") |
| } |
| }; |
| cx.enum_var_cache.insert(id, result); |
| result |
| } |
| |
| |
| // Returns information about the enum variant with the given ID: |
| fn enum_variant_with_id(cx: ctxt, enum_id: ast::def_id, |
| variant_id: ast::def_id) -> variant_info { |
| let variants = enum_variants(cx, enum_id); |
| let mut i = 0u; |
| while i < vec::len::<variant_info>(*variants) { |
| let variant = variants[i]; |
| if variant.id == variant_id { return variant; } |
| i += 1u; |
| } |
| cx.sess.bug(~"enum_variant_with_id(): no variant exists with that ID"); |
| } |
| |
| |
| // If the given item is in an external crate, looks up its type and adds it to |
| // the type cache. Returns the type parameters and type. |
| fn lookup_item_type(cx: ctxt, did: ast::def_id) -> ty_param_bounds_and_ty { |
| match cx.tcache.find(did) { |
| Some(tpt) => return tpt, |
| None => { |
| // The item is in this crate. The caller should have added it to the |
| // type cache already |
| assert did.crate != ast::local_crate; |
| let tyt = csearch::get_type(cx, did); |
| cx.tcache.insert(did, tyt); |
| return tyt; |
| } |
| } |
| } |
| |
| // Look up a field ID, whether or not it's local |
| // Takes a list of type substs in case the class is generic |
| fn lookup_field_type(tcx: ctxt, class_id: def_id, id: def_id, |
| substs: &substs) -> ty::t { |
| |
| let t = if id.crate == ast::local_crate { |
| node_id_to_type(tcx, id.node) |
| } |
| else { |
| match tcx.tcache.find(id) { |
| Some(tpt) => tpt.ty, |
| None => { |
| let tpt = csearch::get_field_type(tcx, class_id, id); |
| tcx.tcache.insert(id, tpt); |
| tpt.ty |
| } |
| } |
| }; |
| subst(tcx, substs, t) |
| } |
| |
| // Look up the list of field names and IDs for a given class |
| // Fails if the id is not bound to a class. |
| fn lookup_class_fields(cx: ctxt, did: ast::def_id) -> ~[field_ty] { |
| if did.crate == ast::local_crate { |
| match cx.items.find(did.node) { |
| Some(ast_map::node_item(i,_)) => { |
| match i.node { |
| ast::item_class(struct_def, _) => { |
| class_field_tys(struct_def.fields) |
| } |
| _ => cx.sess.bug(~"class ID bound to non-class") |
| } |
| } |
| _ => { |
| cx.sess.bug( |
| fmt!("class ID not bound to an item: %s", |
| ast_map::node_id_to_str(cx.items, did.node, |
| cx.sess.parse_sess.interner))); |
| } |
| } |
| } |
| else { |
| return csearch::get_class_fields(cx, did); |
| } |
| } |
| |
| fn lookup_class_field(cx: ctxt, parent: ast::def_id, field_id: ast::def_id) |
| -> field_ty { |
| match vec::find(lookup_class_fields(cx, parent), |
| |f| f.id.node == field_id.node) { |
| Some(t) => t, |
| None => cx.sess.bug(~"class ID not found in parent's fields") |
| } |
| } |
| |
| pure fn is_public(f: field_ty) -> bool { |
| // XXX: This is wrong. |
| match f.vis { |
| public | inherited => true, |
| private => false |
| } |
| } |
| |
| /* Given a class def_id and a method name, return the method's |
| def_id. Needed so we can do static dispatch for methods |
| Doesn't care about the method's privacy. (It's assumed that |
| the caller already checked that.) |
| */ |
| fn lookup_class_method_by_name(cx:ctxt, did: ast::def_id, name: ident, |
| sp: span) -> def_id { |
| |
| // Look up the list of method names and IDs for a given class |
| // Fails if the id is not bound to a class. |
| fn lookup_class_method_ids(cx: ctxt, did: ast::def_id) |
| -> ~[{name: ident, id: node_id, vis: visibility}] { |
| |
| assert is_local(did); |
| match cx.items.find(did.node) { |
| Some(ast_map::node_item(@{ |
| node: item_class(struct_def, _), _ |
| }, _)) => { |
| vec::map(struct_def.methods, |m| {name: m.ident, |
| id: m.id, |
| vis: m.vis}) |
| } |
| _ => { |
| cx.sess.bug(~"lookup_class_method_ids: id not bound to a class"); |
| } |
| } |
| } |
| |
| if is_local(did) { |
| let ms = lookup_class_method_ids(cx, did); |
| for ms.each |m| { |
| if m.name == name { |
| return ast_util::local_def(m.id); |
| } |
| } |
| cx.sess.span_fatal(sp, fmt!("Class doesn't have a method \ |
| named %s", cx.sess.str_of(name))); |
| } |
| else { |
| csearch::get_class_method(cx.sess.cstore, did, name) |
| } |
| } |
| |
| fn class_field_tys(fields: ~[@struct_field]) -> ~[field_ty] { |
| let mut rslt = ~[]; |
| for fields.each |field| { |
| match field.node.kind { |
| named_field(ident, mutability, visibility) => { |
| rslt.push({ident: ident, |
| id: ast_util::local_def(field.node.id), |
| vis: visibility, |
| mutability: mutability}); |
| } |
| unnamed_field => {} |
| } |
| } |
| rslt |
| } |
| |
| // Return a list of fields corresponding to the class's items |
| // (as if the class was a record). trans uses this |
| // Takes a list of substs with which to instantiate field types |
| // Keep in mind that this function reports that all fields are |
| // mutable, regardless of how they were declared. It's meant to |
| // be used in trans. |
| fn class_items_as_mutable_fields(cx:ctxt, |
| did: ast::def_id, |
| substs: &substs) -> ~[field] { |
| class_item_fields(cx, did, substs, |_mt| m_mutbl) |
| } |
| |
| // Same as class_items_as_mutable_fields, but doesn't change |
| // mutability. |
| fn class_items_as_fields(cx:ctxt, |
| did: ast::def_id, |
| substs: &substs) -> ~[field] { |
| class_item_fields(cx, did, substs, |mt| match mt { |
| class_mutable => m_mutbl, |
| class_immutable => m_imm }) |
| } |
| |
| |
| fn class_item_fields(cx:ctxt, |
| did: ast::def_id, |
| substs: &substs, |
| frob_mutability: fn(class_mutability) -> mutability) |
| -> ~[field] { |
| let mut rslt = ~[]; |
| for lookup_class_fields(cx, did).each |f| { |
| // consider all instance vars mut, because the |
| // constructor may mutate all vars |
| rslt.push({ident: f.ident, mt: |
| {ty: lookup_field_type(cx, did, f.id, substs), |
| mutbl: frob_mutability(f.mutability)}}); |
| } |
| rslt |
| } |
| |
| fn is_binopable(_cx: ctxt, ty: t, op: ast::binop) -> bool { |
| const tycat_other: int = 0; |
| const tycat_bool: int = 1; |
| const tycat_int: int = 2; |
| const tycat_float: int = 3; |
| const tycat_struct: int = 4; |
| const tycat_bot: int = 5; |
| |
| const opcat_add: int = 0; |
| const opcat_sub: int = 1; |
| const opcat_mult: int = 2; |
| const opcat_shift: int = 3; |
| const opcat_rel: int = 4; |
| const opcat_eq: int = 5; |
| const opcat_bit: int = 6; |
| const opcat_logic: int = 7; |
| |
| fn opcat(op: ast::binop) -> int { |
| match op { |
| ast::add => opcat_add, |
| ast::subtract => opcat_sub, |
| ast::mul => opcat_mult, |
| ast::div => opcat_mult, |
| ast::rem => opcat_mult, |
| ast::and => opcat_logic, |
| ast::or => opcat_logic, |
| ast::bitxor => opcat_bit, |
| ast::bitand => opcat_bit, |
| ast::bitor => opcat_bit, |
| ast::shl => opcat_shift, |
| ast::shr => opcat_shift, |
| ast::eq => opcat_eq, |
| ast::ne => opcat_eq, |
| ast::lt => opcat_rel, |
| ast::le => opcat_rel, |
| ast::ge => opcat_rel, |
| ast::gt => opcat_rel |
| } |
| } |
| |
| fn tycat(ty: t) -> int { |
| match get(ty).sty { |
| ty_bool => tycat_bool, |
| ty_int(_) | ty_uint(_) | ty_infer(IntVar(_)) => tycat_int, |
| ty_float(_) => tycat_float, |
| ty_rec(_) | ty_tup(_) | ty_enum(_, _) => tycat_struct, |
| ty_bot => tycat_bot, |
| _ => tycat_other |
| } |
| } |
| |
| const t: bool = true; |
| const f: bool = false; |
| |
| let tbl = ~[ |
| /*. add, shift, bit |
| . sub, rel, logic |
| . mult, eq, */ |
| /*other*/ ~[f, f, f, f, f, f, f, f], |
| /*bool*/ ~[f, f, f, f, t, t, t, t], |
| /*int*/ ~[t, t, t, t, t, t, t, f], |
| /*float*/ ~[t, t, t, f, t, t, f, f], |
| /*bot*/ ~[f, f, f, f, f, f, f, f], |
| /*struct*/ ~[t, t, t, t, f, f, t, t]]; |
| |
| return tbl[tycat(ty)][opcat(op)]; |
| } |
| |
| fn ty_params_to_tys(tcx: ty::ctxt, tps: ~[ast::ty_param]) -> ~[t] { |
| vec::from_fn(tps.len(), |i| { |
| ty::mk_param(tcx, i, ast_util::local_def(tps[i].id)) |
| }) |
| } |
| |
| /// Returns an equivalent type with all the typedefs and self regions removed. |
| fn normalize_ty(cx: ctxt, t: t) -> t { |
| fn normalize_mt(cx: ctxt, mt: mt) -> mt { |
| { ty: normalize_ty(cx, mt.ty), mutbl: mt.mutbl } |
| } |
| fn normalize_vstore(vstore: vstore) -> vstore { |
| match vstore { |
| vstore_fixed(*) | vstore_uniq | vstore_box => vstore, |
| vstore_slice(_) => vstore_slice(re_static) |
| } |
| } |
| |
| match cx.normalized_cache.find(t) { |
| Some(t) => return t, |
| None => () |
| } |
| |
| let t = match get(t).sty { |
| ty_evec(mt, vstore) => |
| // This type has a vstore. Get rid of it |
| mk_evec(cx, normalize_mt(cx, mt), normalize_vstore(vstore)), |
| |
| ty_estr(vstore) => |
| // This type has a vstore. Get rid of it |
| mk_estr(cx, normalize_vstore(vstore)), |
| |
| ty_rptr(_, mt) => |
| // This type has a region. Get rid of it |
| mk_rptr(cx, re_static, normalize_mt(cx, mt)), |
| |
| ty_fn(ref fn_ty) => { |
| let proto = match fn_ty.meta.proto { |
| proto_bare => proto_bare, |
| proto_vstore(vstore) => proto_vstore(normalize_vstore(vstore)) |
| }; |
| mk_fn(cx, FnTyBase { |
| meta: FnMeta {proto: proto, ..fn_ty.meta}, |
| sig: fn_ty.sig |
| }) |
| } |
| |
| ty_enum(did, r) => |
| match r.self_r { |
| Some(_) => |
| // This enum has a self region. Get rid of it |
| mk_enum(cx, did, |
| {self_r: None, self_ty: None, tps: r.tps}), |
| None => |
| t |
| }, |
| |
| ty_class(did, r) => |
| match r.self_r { |
| Some(_) => |
| // Ditto. |
| mk_class(cx, did, {self_r: None, self_ty: None, tps: r.tps}), |
| None => |
| t |
| }, |
| |
| _ => |
| t |
| }; |
| |
| let sty = fold_sty(&get(t).sty, |t| { normalize_ty(cx, t) }); |
| let t_norm = mk_t(cx, sty); |
| cx.normalized_cache.insert(t, t_norm); |
| return t_norm; |
| } |
| |
| // Returns the repeat count for a repeating vector expression. |
| fn eval_repeat_count(tcx: ctxt, count_expr: @ast::expr, span: span) -> uint { |
| match const_eval::eval_const_expr(tcx, count_expr) { |
| const_eval::const_int(count) => return count as uint, |
| const_eval::const_uint(count) => return count as uint, |
| const_eval::const_float(count) => { |
| tcx.sess.span_err(span, |
| ~"expected signed or unsigned integer for \ |
| repeat count but found float"); |
| return count as uint; |
| } |
| const_eval::const_str(_) => { |
| tcx.sess.span_err(span, |
| ~"expected signed or unsigned integer for \ |
| repeat count but found string"); |
| return 0; |
| } |
| const_eval::const_bool(_) => { |
| tcx.sess.span_err(span, |
| ~"expected signed or unsigned integer for \ |
| repeat count but found boolean"); |
| return 0; |
| } |
| |
| } |
| } |
| |
| pure fn is_blockish(proto: fn_proto) -> bool { |
| match proto { |
| proto_vstore(vstore_slice(_)) => |
| true, |
| proto_vstore(vstore_box) | proto_vstore(vstore_uniq) | proto_bare => |
| false, |
| proto_vstore(vstore_fixed(_)) => |
| fail ~"fixed vstore not allowed here" |
| } |
| } |
| |
| // Determine what purity to check a nested function under |
| pure fn determine_inherited_purity(parent_purity: ast::purity, |
| child_purity: ast::purity, |
| child_proto: ty::fn_proto) -> ast::purity { |
| // If the closure is a stack closure and hasn't had some non-standard |
| // purity inferred for it, then check it under its parent's purity. |
| // Otherwise, use its own |
| if ty::is_blockish(child_proto) && child_purity == ast::impure_fn { |
| parent_purity |
| } else { child_purity } |
| } |
| |
| impl mt : cmp::Eq { |
| pure fn eq(other: &mt) -> bool { |
| self.ty == (*other).ty && self.mutbl == (*other).mutbl |
| } |
| pure fn ne(other: &mt) -> bool { !self.eq(other) } |
| } |
| |
| impl arg : cmp::Eq { |
| pure fn eq(other: &arg) -> bool { |
| self.mode == (*other).mode && self.ty == (*other).ty |
| } |
| pure fn ne(other: &arg) -> bool { !self.eq(other) } |
| } |
| |
| impl field : cmp::Eq { |
| pure fn eq(other: &field) -> bool { |
| self.ident == (*other).ident && self.mt == (*other).mt |
| } |
| pure fn ne(other: &field) -> bool { !self.eq(other) } |
| } |
| |
| impl vstore : cmp::Eq { |
| pure fn eq(other: &vstore) -> bool { |
| match self { |
| vstore_fixed(e0a) => { |
| match (*other) { |
| vstore_fixed(e0b) => e0a == e0b, |
| _ => false |
| } |
| } |
| vstore_uniq => { |
| match (*other) { |
| vstore_uniq => true, |
| _ => false |
| } |
| } |
| vstore_box => { |
| match (*other) { |
| vstore_box => true, |
| _ => false |
| } |
| } |
| vstore_slice(e0a) => { |
| match (*other) { |
| vstore_slice(e0b) => e0a == e0b, |
| _ => false |
| } |
| } |
| } |
| } |
| pure fn ne(other: &vstore) -> bool { !self.eq(other) } |
| } |
| |
| impl FnMeta : cmp::Eq { |
| pure fn eq(other: &FnMeta) -> bool { |
| self.purity == (*other).purity && |
| self.proto == (*other).proto && |
| self.bounds == (*other).bounds && |
| self.ret_style == (*other).ret_style |
| } |
| pure fn ne(other: &FnMeta) -> bool { !self.eq(other) } |
| } |
| |
| impl FnSig : cmp::Eq { |
| pure fn eq(other: &FnSig) -> bool { |
| self.inputs == (*other).inputs && |
| self.output == (*other).output |
| } |
| pure fn ne(other: &FnSig) -> bool { !self.eq(other) } |
| } |
| |
| impl<M: cmp::Eq> FnTyBase<M> : cmp::Eq { |
| pure fn eq(other: &FnTyBase<M>) -> bool { |
| self.meta == (*other).meta && self.sig == (*other).sig |
| } |
| pure fn ne(other: &FnTyBase<M>) -> bool { !self.eq(other) } |
| } |
| |
| impl TyVid : cmp::Eq { |
| pure fn eq(other: &TyVid) -> bool { *self == *(*other) } |
| pure fn ne(other: &TyVid) -> bool { *self != *(*other) } |
| } |
| |
| impl IntVid : cmp::Eq { |
| pure fn eq(other: &IntVid) -> bool { *self == *(*other) } |
| pure fn ne(other: &IntVid) -> bool { *self != *(*other) } |
| } |
| |
| impl FnVid : cmp::Eq { |
| pure fn eq(other: &FnVid) -> bool { *self == *(*other) } |
| pure fn ne(other: &FnVid) -> bool { *self != *(*other) } |
| } |
| |
| impl RegionVid : cmp::Eq { |
| pure fn eq(other: &RegionVid) -> bool { *self == *(*other) } |
| pure fn ne(other: &RegionVid) -> bool { *self != *(*other) } |
| } |
| |
| impl region : cmp::Eq { |
| pure fn eq(other: ®ion) -> bool { |
| match self { |
| re_bound(e0a) => { |
| match (*other) { |
| re_bound(e0b) => e0a == e0b, |
| _ => false |
| } |
| } |
| re_free(e0a, e1a) => { |
| match (*other) { |
| re_free(e0b, e1b) => e0a == e0b && e1a == e1b, |
| _ => false |
| } |
| } |
| re_scope(e0a) => { |
| match (*other) { |
| re_scope(e0b) => e0a == e0b, |
| _ => false |
| } |
| } |
| re_static => { |
| match (*other) { |
| re_static => true, |
| _ => false |
| } |
| } |
| re_var(e0a) => { |
| match (*other) { |
| re_var(e0b) => e0a == e0b, |
| _ => false |
| } |
| } |
| } |
| } |
| pure fn ne(other: ®ion) -> bool { !self.eq(other) } |
| } |
| |
| impl bound_region : cmp::Eq { |
| pure fn eq(other: &bound_region) -> bool { |
| match self { |
| br_self => { |
| match (*other) { |
| br_self => true, |
| _ => false |
| } |
| } |
| br_anon(e0a) => { |
| match (*other) { |
| br_anon(e0b) => e0a == e0b, |
| _ => false |
| } |
| } |
| br_named(e0a) => { |
| match (*other) { |
| br_named(e0b) => e0a == e0b, |
| _ => false |
| } |
| } |
| br_cap_avoid(e0a, e1a) => { |
| match (*other) { |
| br_cap_avoid(e0b, e1b) => e0a == e0b && e1a == e1b, |
| _ => false |
| } |
| } |
| } |
| } |
| pure fn ne(other: &bound_region) -> bool { !self.eq(other) } |
| } |
| |
| impl substs : cmp::Eq { |
| pure fn eq(other: &substs) -> bool { |
| self.self_r == (*other).self_r && |
| self.self_ty == (*other).self_ty && |
| self.tps == (*other).tps |
| } |
| pure fn ne(other: &substs) -> bool { !self.eq(other) } |
| } |
| |
| impl InferTy : cmp::Eq { |
| pure fn eq(other: &InferTy) -> bool { |
| self.to_hash() == (*other).to_hash() |
| } |
| pure fn ne(other: &InferTy) -> bool { !self.eq(other) } |
| } |
| |
| impl sty : cmp::Eq { |
| pure fn eq(other: &sty) -> bool { |
| match self { |
| ty_nil => { |
| match (*other) { |
| ty_nil => true, |
| _ => false |
| } |
| } |
| ty_bot => { |
| match (*other) { |
| ty_bot => true, |
| _ => false |
| } |
| } |
| ty_bool => { |
| match (*other) { |
| ty_bool => true, |
| _ => false |
| } |
| } |
| ty_int(e0a) => { |
| match (*other) { |
| ty_int(e0b) => e0a == e0b, |
| _ => false |
| } |
| } |
| ty_uint(e0a) => { |
| match (*other) { |
| ty_uint(e0b) => e0a == e0b, |
| _ => false |
| } |
| } |
| ty_float(e0a) => { |
| match (*other) { |
| ty_float(e0b) => e0a == e0b, |
| _ => false |
| } |
| } |
| ty_estr(e0a) => { |
| match (*other) { |
| ty_estr(e0b) => e0a == e0b, |
| _ => false |
| } |
| } |
| ty_enum(e0a, e1a) => { |
| match (*other) { |
| ty_enum(e0b, e1b) => e0a == e0b && e1a == e1b, |
| _ => false |
| } |
| } |
| ty_box(e0a) => { |
| match (*other) { |
| ty_box(e0b) => e0a == e0b, |
| _ => false |
| } |
| } |
| ty_uniq(e0a) => { |
| match (*other) { |
| ty_uniq(e0b) => e0a == e0b, |
| _ => false |
| } |
| } |
| ty_evec(e0a, e1a) => { |
| match (*other) { |
| ty_evec(e0b, e1b) => e0a == e0b && e1a == e1b, |
| _ => false |
| } |
| } |
| ty_ptr(e0a) => { |
| match (*other) { |
| ty_ptr(e0b) => e0a == e0b, |
| _ => false |
| } |
| } |
| ty_rptr(e0a, e1a) => { |
| match (*other) { |
| ty_rptr(e0b, e1b) => e0a == e0b && e1a == e1b, |
| _ => false |
| } |
| } |
| ty_rec(e0a) => { |
| match (*other) { |
| ty_rec(e0b) => e0a == e0b, |
| _ => false |
| } |
| } |
| ty_fn(e0a) => { |
| match (*other) { |
| ty_fn(e0b) => e0a == e0b, |
| _ => false |
| } |
| } |
| ty_trait(e0a, e1a, e2a) => { |
| match (*other) { |
| ty_trait(e0b, e1b, e2b) => |
| e0a == e0b && e1a == e1b && e2a == e2b, |
| _ => false |
| } |
| } |
| ty_class(e0a, e1a) => { |
| match (*other) { |
| ty_class(e0b, e1b) => e0a == e0b && e1a == e1b, |
| _ => false |
| } |
| } |
| ty_tup(e0a) => { |
| match (*other) { |
| ty_tup(e0b) => e0a == e0b, |
| _ => false |
| } |
| } |
| ty_infer(e0a) => { |
| match (*other) { |
| ty_infer(e0b) => e0a == e0b, |
| _ => false |
| } |
| } |
| ty_param(e0a) => { |
| match (*other) { |
| ty_param(e0b) => e0a == e0b, |
| _ => false |
| } |
| } |
| ty_self => { |
| match (*other) { |
| ty_self => true, |
| _ => false |
| } |
| } |
| ty_type => { |
| match (*other) { |
| ty_type => true, |
| _ => false |
| } |
| } |
| ty_opaque_box => { |
| match (*other) { |
| ty_opaque_box => true, |
| _ => false |
| } |
| } |
| ty_opaque_closure_ptr(e0a) => { |
| match (*other) { |
| ty_opaque_closure_ptr(e0b) => e0a == e0b, |
| _ => false |
| } |
| } |
| ty_unboxed_vec(e0a) => { |
| match (*other) { |
| ty_unboxed_vec(e0b) => e0a == e0b, |
| _ => false |
| } |
| } |
| } |
| } |
| pure fn ne(other: &sty) -> bool { !self.eq(other) } |
| } |
| |
| impl param_bound : cmp::Eq { |
| pure fn eq(other: ¶m_bound) -> bool { |
| match self { |
| bound_copy => { |
| match (*other) { |
| bound_copy => true, |
| _ => false |
| } |
| } |
| bound_owned => { |
| match (*other) { |
| bound_owned => true, |
| _ => false |
| } |
| } |
| bound_send => { |
| match (*other) { |
| bound_send => true, |
| _ => false |
| } |
| } |
| bound_const => { |
| match (*other) { |
| bound_const => true, |
| _ => false |
| } |
| } |
| bound_trait(e0a) => { |
| match (*other) { |
| bound_trait(e0b) => e0a == e0b, |
| _ => false |
| } |
| } |
| } |
| } |
| pure fn ne(other: ¶m_bound) -> bool { !self.eq(other) } |
| } |
| |
| impl kind : cmp::Eq { |
| pure fn eq(other: &kind) -> bool { *self == *(*other) } |
| pure fn ne(other: &kind) -> bool { *self != *(*other) } |
| } |
| |
| |
| // Local Variables: |
| // mode: rust |
| // fill-column: 78; |
| // indent-tabs-mode: nil |
| // c-basic-offset: 4 |
| // buffer-file-coding-system: utf-8-unix |
| // End: |