ty.rs 137.5 KB
Newer Older
1
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 3 4 5 6 7 8 9 10
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

11
use core::prelude::*;
12

P
Patrick Walton 已提交
13 14
use driver::session;
use metadata::csearch;
15 16 17 18 19 20
use metadata;
use middle::const_eval;
use middle::freevars;
use middle::resolve::{Impl, MethodInfo};
use middle::resolve;
use middle::ty;
21
use middle::subst::Subst;
22 23
use middle::typeck;
use middle;
24
use util::ppaux::{note_and_explain_region, bound_region_to_str, bound_region_ptr_to_str};
25
use util::ppaux::{trait_store_to_str, ty_to_str, vstore_to_str};
26
use util::ppaux::{Repr, UserString};
27
use util::common::{indenter};
28
use util::enum_set::{EnumSet, CLike};
29

30 31 32 33 34
use core::cast;
use core::cmp;
use core::hashmap::{HashMap, HashSet};
use core::iter;
use core::ops;
35
use core::ptr::to_unsafe_ptr;
36
use core::to_bytes;
37 38 39
use core::u32;
use core::uint;
use core::vec;
P
Patrick Walton 已提交
40
use syntax::ast::*;
T
Tim Chevalier 已提交
41
use syntax::ast_util::is_local;
42
use syntax::ast_util;
43
use syntax::attr;
44
use syntax::codemap::span;
J
John Clements 已提交
45
use syntax::codemap;
J
John Clements 已提交
46
use syntax::parse::token;
47
use syntax::parse::token::special_idents;
48
use syntax::{ast, ast_map};
49 50
use syntax::opt_vec::OptVec;
use syntax::opt_vec;
51
use syntax::abi::AbiSet;
52
use syntax;
53

54
// Data types
55

56
#[deriving(Eq)]
57
pub struct field {
58 59 60
    ident: ast::ident,
    mt: mt
}
61

62
pub struct Method {
63
    ident: ast::ident,
64
    generics: ty::Generics,
65
    transformed_self_ty: Option<ty::t>,
66
    fty: BareFnTy,
67
    explicit_self: ast::explicit_self_,
68 69
    vis: ast::visibility,
    def_id: ast::def_id
70
}
71

72 73 74 75 76 77 78 79 80
impl Method {
    pub fn new(ident: ast::ident,
               generics: ty::Generics,
               transformed_self_ty: Option<ty::t>,
               fty: BareFnTy,
               explicit_self: ast::explicit_self_,
               vis: ast::visibility,
               def_id: ast::def_id)
               -> Method {
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
        // Check the invariants.
        if explicit_self == ast::sty_static {
            assert!(transformed_self_ty.is_none());
        } else {
            assert!(transformed_self_ty.is_some());
        }

       Method {
            ident: ident,
            generics: generics,
            transformed_self_ty: transformed_self_ty,
            fty: fty,
            explicit_self: explicit_self,
            vis: vis,
            def_id: def_id
        }
    }
}

100
#[deriving(Eq)]
101
pub struct mt {
102 103 104
    ty: t,
    mutbl: ast::mutability,
}
105

106
#[deriving(Eq, Encodable, Decodable)]
107
pub enum vstore {
108 109 110
    vstore_fixed(uint),
    vstore_uniq,
    vstore_box,
111
    vstore_slice(Region)
112 113
}

114
#[deriving(Eq, IterBytes, Encodable, Decodable)]
115 116 117 118 119 120
pub enum TraitStore {
    BoxTraitStore,              // @Trait
    UniqTraitStore,             // ~Trait
    RegionTraitStore(Region),   // &Trait
}

121 122
// XXX: This should probably go away at some point. Maybe after destructors
// do?
123
#[deriving(Eq, Encodable, Decodable)]
124 125 126 127 128
pub enum SelfMode {
    ByCopy,
    ByRef,
}

129
pub struct field_ty {
130 131 132
    ident: ident,
    id: def_id,
    vis: ast::visibility,
133
}
T
Tim Chevalier 已提交
134

135 136
// Contains information needed to resolve types and (in the future) look up
// the types of AST nodes.
137
#[deriving(Eq)]
138
pub struct creader_cache_key {
139 140 141
    cnum: int,
    pos: uint,
    len: uint
142
}
143

144
type creader_cache = @mut HashMap<creader_cache_key, t>;
145

146 147
impl to_bytes::IterBytes for creader_cache_key {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
148 149 150
        self.cnum.iter_bytes(lsb0, f) &&
        self.pos.iter_bytes(lsb0, f) &&
        self.len.iter_bytes(lsb0, f)
151 152
    }
}
153

154 155 156
struct intern_key {
    sty: *sty,
}
157

158
// NB: Do not replace this with #[deriving(Eq)]. The automatically-derived
159 160
// implementation will not recurse through sty and you will get stack
// exhaustion.
161
impl cmp::Eq for intern_key {
162
    fn eq(&self, other: &intern_key) -> bool {
163
        unsafe {
164
            *self.sty == *other.sty
165
        }
166
    }
167
    fn ne(&self, other: &intern_key) -> bool {
168 169
        !self.eq(other)
    }
170
}
171

172 173 174 175 176 177 178
impl to_bytes::IterBytes for intern_key {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
        unsafe {
            (*self.sty).iter_bytes(lsb0, f)
        }
    }
}
179

180
pub enum ast_ty_to_ty_cache_entry {
181
    atttce_unresolved,  /* not resolved yet */
182
    atttce_resolved(t)  /* resolved to a type, irrespective of region */
183 184
}

185
pub type opt_region_variance = Option<region_variance>;
186

187
#[deriving(Eq, Decodable, Encodable)]
188
pub enum region_variance { rv_covariant, rv_invariant, rv_contravariant }
189

190
#[deriving(Decodable, Encodable)]
191 192 193 194 195
pub enum AutoAdjustment {
    AutoAddEnv(ty::Region, ast::Sigil),
    AutoDerefRef(AutoDerefRef)
}

196
#[deriving(Decodable, Encodable)]
197
pub struct AutoDerefRef {
198 199
    autoderefs: uint,
    autoref: Option<AutoRef>
200
}
201

202
#[deriving(Decodable, Encodable)]
N
Niko Matsakis 已提交
203
pub enum AutoRef {
204
    /// Convert from T to &T
N
Niko Matsakis 已提交
205
    AutoPtr(Region, ast::mutability),
206

207
    /// Convert from @[]/~[]/&[] to &[] (or str)
N
Niko Matsakis 已提交
208
    AutoBorrowVec(Region, ast::mutability),
209

210
    /// Convert from @[]/~[]/&[] to &&[] (or str)
N
Niko Matsakis 已提交
211
    AutoBorrowVecRef(Region, ast::mutability),
212

213
    /// Convert from @fn()/~fn()/&fn() to &fn()
N
Niko Matsakis 已提交
214 215 216 217
    AutoBorrowFn(Region),

    /// Convert from T to *T
    AutoUnsafe(ast::mutability)
218 219
}

220 221 222 223
// Stores information about provided methods (a.k.a. default methods) in
// implementations.
//
// This is a map from ID of each implementation to the method info and trait
224
// method ID of each of the default methods belonging to the trait that
225
// implementation implements.
226
pub type ProvidedMethodsMap = @mut HashMap<def_id,@mut ~[@ProvidedMethodInfo]>;
227 228 229

// Stores the method info and definition ID of the associated trait method for
// each instantiation of each provided method.
230
pub struct ProvidedMethodInfo {
231 232 233 234
    method_info: @MethodInfo,
    trait_method_def_id: def_id
}

235
pub struct ProvidedMethodSource {
236 237 238 239
    method_id: ast::def_id,
    impl_id: ast::def_id
}

240 241 242
pub type ctxt = @ctxt_;

struct ctxt_ {
243
    diag: @syntax::diagnostic::span_handler,
244
    interner: @mut HashMap<intern_key, ~t_box_>,
245
    next_id: @mut uint,
246
    cstore: @mut metadata::cstore::CStore,
247 248 249
    sess: session::Session,
    def_map: resolve::DefMap,

250
    region_maps: @mut middle::region::RegionMaps,
251 252 253 254 255 256 257 258 259 260 261
    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.
262
    node_type_substs: @mut HashMap<node_id, ~[t]>,
263

264
    // Maps from a method to the method "descriptor"
265
    methods: @mut HashMap<def_id, @Method>,
266 267 268 269 270

    // Maps from a trait def-id to a list of the def-ids of its methods
    trait_method_def_ids: @mut HashMap<def_id, @~[def_id]>,

    // A cache for the trait_methods() routine
271
    trait_methods_cache: @mut HashMap<def_id, @~[@Method]>,
272

273 274
    impl_trait_cache: @mut HashMap<ast::def_id, Option<@ty::TraitRef>>,

275 276 277
    trait_refs: @mut HashMap<node_id, @TraitRef>,
    trait_defs: @mut HashMap<def_id, @TraitDef>,

278
    items: ast_map::map,
279
    intrinsic_defs: @mut HashMap<ast::ident, (ast::def_id, t)>,
280
    intrinsic_traits: @mut HashMap<ast::ident, @TraitRef>,
281 282 283 284
    freevars: freevars::freevar_map,
    tcache: type_cache,
    rcache: creader_cache,
    ccache: constness_cache,
285
    short_names_cache: @mut HashMap<t, @str>,
286 287 288 289
    needs_unwind_cleanup_cache: @mut HashMap<t, bool>,
    tc_cache: @mut HashMap<uint, TypeContents>,
    ast_ty_to_ty_cache: @mut HashMap<node_id, ast_ty_to_ty_cache_entry>,
    enum_var_cache: @mut HashMap<def_id, @~[VariantInfo]>,
290
    ty_param_defs: @mut HashMap<ast::node_id, TypeParameterDef>,
291 292
    adjustments: @mut HashMap<ast::node_id, @AutoAdjustment>,
    normalized_cache: @mut HashMap<t, t>,
293 294 295 296 297
    lang_items: middle::lang_items::LanguageItems,
    // A mapping from an implementation ID to the method info and trait
    // method ID of the provided (a.k.a. default) methods in the traits that
    // that implementation implements.
    provided_methods: ProvidedMethodsMap,
298
    provided_method_sources: @mut HashMap<ast::def_id, ProvidedMethodSource>,
299
    supertraits: @mut HashMap<ast::def_id, @~[@TraitRef]>,
300 301 302 303 304

    // A mapping from the def ID of an enum or struct type to the def ID
    // of the method that implements its destructor. If the type is not
    // present in this map, it does not have a destructor. This map is
    // populated during the coherence phase of typechecking.
305
    destructor_for_type: @mut HashMap<ast::def_id, ast::def_id>,
306 307

    // A method will be in this list if and only if it is a destructor.
308
    destructors: @mut HashSet<ast::def_id>,
309 310

    // Maps a trait onto a mapping from self-ty to impl
311 312
    trait_impls: @mut HashMap<ast::def_id, @mut HashMap<t, @Impl>>,

313 314 315
    // Maps a base type to its impl
    base_impls: @mut HashMap<ast::def_id, @mut ~[@Impl]>,

316 317 318
    // Set of used unsafe nodes (functions or blocks). Unsafe nodes not
    // present in this set can be warned about.
    used_unsafe: @mut HashSet<ast::node_id>,
319 320 321 322 323

    // Set of nodes which mark locals as mutable which end up getting used at
    // some point. Local variable definitions not in this set can be warned
    // about.
    used_mut_nodes: @mut HashSet<ast::node_id>,
324
}
325

326
pub enum tbox_flag {
327 328 329 330
    has_params = 1,
    has_self = 2,
    needs_infer = 4,
    has_regions = 8,
331
    has_ty_err = 16,
T
Tim Chevalier 已提交
332
    has_ty_bot = 32,
333 334 335 336 337 338

    // a meta-flag: subst may be required if the type has parameters, a self
    // type, or references bound regions
    needs_subst = 1 | 2 | 8
}

339
pub type t_box = &'static t_box_;
340

341
pub struct t_box_ {
342 343 344 345
    sty: sty,
    id: uint,
    flags: uint,
}
346

347 348 349 350 351 352
// 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 {}
353
pub type t = *t_opaque;
354

355
pub fn get(t: t) -> t_box {
356
    unsafe {
357 358
        let t2: t_box = cast::transmute(t);
        t2
359
    }
360 361
}

362
pub fn tbox_has_flag(tb: t_box, flag: tbox_flag) -> bool {
363 364
    (tb.flags & (flag as uint)) != 0u
}
365
pub fn type_has_params(t: t) -> bool {
P
Patrick Walton 已提交
366 367
    tbox_has_flag(get(t), has_params)
}
368 369
pub fn type_has_self(t: t) -> bool { tbox_has_flag(get(t), has_self) }
pub fn type_needs_infer(t: t) -> bool {
370 371
    tbox_has_flag(get(t), needs_infer)
}
372
pub fn type_has_regions(t: t) -> bool {
373 374
    tbox_has_flag(get(t), has_regions)
}
375
pub fn type_id(t: t) -> uint { get(t).id }
376

377
#[deriving(Eq)]
378 379
pub struct BareFnTy {
    purity: ast::purity,
380
    abis: AbiSet,
381 382 383
    sig: FnSig
}

384
#[deriving(Eq)]
385
pub struct ClosureTy {
386
    purity: ast::purity,
387
    sigil: ast::Sigil,
388
    onceness: ast::Onceness,
389
    region: Region,
390 391
    bounds: BuiltinBounds,
    sig: FnSig,
392 393 394 395 396 397
}

/**
 * Signature of a function type, which I have arbitrarily
 * decided to use to refer to the input/output types.
 *
398
 * - `lifetimes` is the list of region names bound in this fn.
399 400
 * - `inputs` is the list of arguments and their modes.
 * - `output` is the return type. */
401
#[deriving(Eq)]
402
pub struct FnSig {
403
    bound_lifetime_names: OptVec<ast::ident>,
E
Erick Tryzelaar 已提交
404
    inputs: ~[t],
405
    output: t
406 407
}

408 409
impl to_bytes::IterBytes for BareFnTy {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
410 411 412
        self.purity.iter_bytes(lsb0, f) &&
        self.abis.iter_bytes(lsb0, f) &&
        self.sig.iter_bytes(lsb0, f)
413 414
    }
}
415

416 417
impl to_bytes::IterBytes for ClosureTy {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
418 419 420 421
        self.purity.iter_bytes(lsb0, f) &&
        self.sigil.iter_bytes(lsb0, f) &&
        self.onceness.iter_bytes(lsb0, f) &&
        self.region.iter_bytes(lsb0, f) &&
422 423
        self.sig.iter_bytes(lsb0, f) &&
        self.bounds.iter_bytes(lsb0, f)
424 425
    }
}
426

427
#[deriving(Eq, IterBytes)]
428
pub struct param_ty {
429 430
    idx: uint,
    def_id: def_id
431
}
432

433
/// Representation of regions:
434
#[deriving(Eq, IterBytes, Encodable, Decodable)]
435
pub enum Region {
436 437 438 439 440 441 442 443 444
    /// 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.
N
Niko Matsakis 已提交
445
    re_bound(bound_region),
446 447 448 449

    /// 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.
450
    re_free(FreeRegion),
451 452

    /// A concrete region naming some expression within the current function.
N
Niko Matsakis 已提交
453
    re_scope(node_id),
454

N
Niko Matsakis 已提交
455
    /// Static data that has an "infinite" lifetime. Top in the region lattice.
456 457 458
    re_static,

    /// A region variable.  Should not exist after typeck.
N
Niko Matsakis 已提交
459 460 461 462 463 464 465 466 467 468
    re_infer(InferRegion),

    /// Empty lifetime is for data that is never accessed.
    /// Bottom in the region lattice. We treat re_empty somewhat
    /// specially; at least right now, we do not generate instances of
    /// it during the GLB computations, but rather
    /// generate an error instead. This is to improve error messages.
    /// The only way to get an instance of re_empty is to have a region
    /// variable with no constraints.
    re_empty,
N
Niko Matsakis 已提交
469 470
}

471 472
impl Region {
    pub fn is_bound(&self) -> bool {
473 474 475 476 477 478 479
        match self {
            &re_bound(*) => true,
            _ => false
        }
    }
}

480
#[deriving(Eq, IterBytes, Encodable, Decodable)]
481 482 483 484 485
pub struct FreeRegion {
    scope_id: node_id,
    bound_region: bound_region
}

486
#[deriving(Eq, IterBytes, Encodable, Decodable)]
487
pub enum bound_region {
488
    /// The self region for structs, impls (&T in a type defn or &'self T)
489 490
    br_self,

491 492
    /// An anonymous region parameter for a given fn (&T)
    br_anon(uint),
493

494
    /// Named region parameters for functions (a in &'a T)
495 496
    br_named(ast::ident),

497 498 499
    /// Fresh bound identifiers created during GLB computations.
    br_fresh(uint),

500 501 502 503 504 505 506 507 508
    /**
     * 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. */
509
    br_cap_avoid(ast::node_id, @bound_region),
510 511
}

512
type opt_region = Option<Region>;
513

514 515 516 517 518 519 520 521 522
/**
 * 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
523
 *   types (enums, structs) declared as having a region parameter.  `self_r`
524 525 526 527 528 529 530
 *   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. */
531
#[deriving(Eq)]
532
pub struct substs {
533
    self_r: opt_region,
B
Brian Anderson 已提交
534
    self_ty: Option<ty::t>,
535
    tps: ~[t]
536
}
537

538
mod primitives {
539
    use super::t_box_;
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584

    use syntax::ast;

    macro_rules! def_prim_ty(
        ($name:ident, $sty:expr, $id:expr) => (
            pub static $name: t_box_ = t_box_ {
                sty: $sty,
                id: $id,
                flags: 0,
            };
        )
    )

    def_prim_ty!(TY_NIL,    super::ty_nil,                  0)
    def_prim_ty!(TY_BOOL,   super::ty_bool,                 1)
    def_prim_ty!(TY_INT,    super::ty_int(ast::ty_i),       2)
    def_prim_ty!(TY_CHAR,   super::ty_int(ast::ty_char),    3)
    def_prim_ty!(TY_I8,     super::ty_int(ast::ty_i8),      4)
    def_prim_ty!(TY_I16,    super::ty_int(ast::ty_i16),     5)
    def_prim_ty!(TY_I32,    super::ty_int(ast::ty_i32),     6)
    def_prim_ty!(TY_I64,    super::ty_int(ast::ty_i64),     7)
    def_prim_ty!(TY_UINT,   super::ty_uint(ast::ty_u),      8)
    def_prim_ty!(TY_U8,     super::ty_uint(ast::ty_u8),     9)
    def_prim_ty!(TY_U16,    super::ty_uint(ast::ty_u16),    10)
    def_prim_ty!(TY_U32,    super::ty_uint(ast::ty_u32),    11)
    def_prim_ty!(TY_U64,    super::ty_uint(ast::ty_u64),    12)
    def_prim_ty!(TY_FLOAT,  super::ty_float(ast::ty_f),     13)
    def_prim_ty!(TY_F32,    super::ty_float(ast::ty_f32),   14)
    def_prim_ty!(TY_F64,    super::ty_float(ast::ty_f64),   15)

    pub static TY_BOT: t_box_ = t_box_ {
        sty: super::ty_bot,
        id: 16,
        flags: super::has_ty_bot as uint,
    };

    pub static TY_ERR: t_box_ = t_box_ {
        sty: super::ty_err,
        id: 17,
        flags: super::has_ty_err as uint,
    };

    pub static LAST_PRIMITIVE_ID: uint = 18;
}

585
// NB: If you change this, you'll probably want to change the corresponding
586
// AST structure in libsyntax/ast.rs as well.
587
#[deriving(Eq)]
588
pub enum sty {
P
Patrick Walton 已提交
589 590 591 592 593 594
    ty_nil,
    ty_bot,
    ty_bool,
    ty_int(ast::int_ty),
    ty_uint(ast::uint_ty),
    ty_float(ast::float_ty),
595
    ty_estr(vstore),
596
    ty_enum(def_id, substs),
P
Patrick Walton 已提交
597 598
    ty_box(mt),
    ty_uniq(mt),
599
    ty_evec(mt, vstore),
P
Patrick Walton 已提交
600
    ty_ptr(mt),
601
    ty_rptr(Region, mt),
602 603
    ty_bare_fn(BareFnTy),
    ty_closure(ClosureTy),
604
    ty_trait(def_id, substs, TraitStore, ast::mutability, BuiltinBounds),
605
    ty_struct(def_id, substs),
606
    ty_tup(~[t]),
P
Patrick Walton 已提交
607

608
    ty_param(param_ty), // type parameter
609 610
    ty_self(def_id), /* special, implicit `self` type parameter;
                      * def_id is the id of the trait */
P
Patrick Walton 已提交
611

612
    ty_infer(InferTy), // something used only during inference/typeck
613 614 615
    ty_err, // Also only used during inference/typeck, to represent
            // the type of an erroneous expression (helps cut down
            // on non-useful type error messages)
616

M
Michael Sullivan 已提交
617
    // "Fake" types, used for trans purposes
P
Patrick Walton 已提交
618
    ty_type, // type_desc*
619
    ty_opaque_box, // used by monomorphizer to represent any @ box
620
    ty_opaque_closure_ptr(Sigil), // ptr to env for &fn, @fn, ~fn
M
Michael Sullivan 已提交
621
    ty_unboxed_vec(mt),
622 623
}

624 625 626 627 628 629
#[deriving(Eq, IterBytes)]
pub struct TraitRef {
    def_id: def_id,
    substs: substs
}

630
#[deriving(Eq)]
631
pub enum IntVarValue {
632 633 634 635
    IntType(ast::int_ty),
    UintType(ast::uint_ty),
}

636
pub enum terr_vstore_kind {
637
    terr_vec, terr_str, terr_fn, terr_trait
638 639
}

640
pub struct expected_found<T> {
641 642
    expected: T,
    found: T
643 644
}

645
// Data structures used in type unification
646
pub enum type_err {
P
Patrick Walton 已提交
647
    terr_mismatch,
648
    terr_purity_mismatch(expected_found<purity>),
649
    terr_onceness_mismatch(expected_found<Onceness>),
650
    terr_abi_mismatch(expected_found<AbiSet>),
651
    terr_mutability,
652
    terr_sigil_mismatch(expected_found<ast::Sigil>),
P
Patrick Walton 已提交
653
    terr_box_mutability,
M
Marijn Haverbeke 已提交
654
    terr_ptr_mutability,
655
    terr_ref_mutability,
P
Patrick Walton 已提交
656
    terr_vec_mutability,
657 658 659
    terr_tuple_size(expected_found<uint>),
    terr_ty_param_size(expected_found<uint>),
    terr_record_size(expected_found<uint>),
P
Patrick Walton 已提交
660
    terr_record_mutability,
661
    terr_record_fields(expected_found<ident>),
P
Patrick Walton 已提交
662
    terr_arg_count,
663 664 665
    terr_regions_does_not_outlive(Region, Region),
    terr_regions_not_same(Region, Region),
    terr_regions_no_overlap(Region, Region),
666 667
    terr_regions_insufficiently_polymorphic(bound_region, Region),
    terr_regions_overly_polymorphic(bound_region, Region),
668
    terr_vstores_differ(terr_vstore_kind, expected_found<vstore>),
669
    terr_trait_stores_differ(terr_vstore_kind, expected_found<TraitStore>),
B
Brian Anderson 已提交
670
    terr_in_field(@type_err, ast::ident),
671
    terr_sorts(expected_found<t>),
672
    terr_integer_as_char,
673
    terr_int_mismatch(expected_found<IntVarValue>),
674 675
    terr_float_mismatch(expected_found<ast::float_ty>),
    terr_traits(expected_found<ast::def_id>),
676
    terr_builtin_bounds(expected_found<BuiltinBounds>),
677 678
}

679
#[deriving(Eq, IterBytes)]
680 681 682 683 684 685 686 687 688 689 690 691 692
pub struct ParamBounds {
    builtin_bounds: BuiltinBounds,
    trait_bounds: ~[@TraitRef]
}

pub type BuiltinBounds = EnumSet<BuiltinBound>;

#[deriving(Eq, IterBytes)]
pub enum BuiltinBound {
    BoundCopy,
    BoundStatic,
    BoundOwned,
    BoundConst,
693
    BoundSized,
694 695 696 697 698 699
}

pub fn EmptyBuiltinBounds() -> BuiltinBounds {
    EnumSet::empty()
}

700 701 702 703 704 705
pub fn AllBuiltinBounds() -> BuiltinBounds {
    let mut set = EnumSet::empty();
    set.add(BoundCopy);
    set.add(BoundStatic);
    set.add(BoundOwned);
    set.add(BoundConst);
706
    set.add(BoundSized);
707 708 709
    set
}

710 711 712 713 714 715 716
impl CLike for BuiltinBound {
    pub fn to_uint(&self) -> uint {
        *self as uint
    }
    pub fn from_uint(v: uint) -> BuiltinBound {
        unsafe { cast::transmute(v) }
    }
717 718
}

719
#[deriving(Eq)]
720
pub struct TyVid(uint);
721

722
#[deriving(Eq)]
723
pub struct IntVid(uint);
724

725
#[deriving(Eq)]
726
pub struct FloatVid(uint);
727

728
#[deriving(Eq, Encodable, Decodable)]
729 730 731
pub struct RegionVid {
    id: uint
}
N
Niko Matsakis 已提交
732

733
#[deriving(Eq)]
734
pub enum InferTy {
735
    TyVar(TyVid),
736 737
    IntVar(IntVid),
    FloatVar(FloatVid)
738 739
}

740 741 742
impl to_bytes::IterBytes for InferTy {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
        match *self {
743 744 745 746 747 748 749 750 751
            TyVar(ref tv) => {
                0u8.iter_bytes(lsb0, f) && tv.iter_bytes(lsb0, f)
            }
            IntVar(ref iv) => {
                1u8.iter_bytes(lsb0, f) && iv.iter_bytes(lsb0, f)
            }
            FloatVar(ref fv) => {
                2u8.iter_bytes(lsb0, f) && fv.iter_bytes(lsb0, f)
            }
752 753 754
        }
    }
}
755

756
#[deriving(Encodable, Decodable)]
757
pub enum InferRegion {
758 759 760 761
    ReVar(RegionVid),
    ReSkolemized(uint, bound_region)
}

762 763 764
impl to_bytes::IterBytes for InferRegion {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
        match *self {
765 766 767 768 769 770
            ReVar(ref rv) => {
                0u8.iter_bytes(lsb0, f) && rv.iter_bytes(lsb0, f)
            }
            ReSkolemized(ref v, _) => {
                1u8.iter_bytes(lsb0, f) && v.iter_bytes(lsb0, f)
            }
771 772 773
        }
    }
}
774

775
impl cmp::Eq for InferRegion {
776
    fn eq(&self, other: &InferRegion) -> bool {
777 778 779 780 781 782 783 784 785 786
        match ((*self), *other) {
            (ReVar(rva), ReVar(rvb)) => {
                rva == rvb
            }
            (ReSkolemized(rva, _), ReSkolemized(rvb, _)) => {
                rva == rvb
            }
            _ => false
        }
    }
787
    fn ne(&self, other: &InferRegion) -> bool {
788 789
        !((*self) == (*other))
    }
790 791
}

792
pub trait Vid {
793
    fn to_uint(&self) -> uint;
N
Niko Matsakis 已提交
794 795
}

796
impl Vid for TyVid {
797
    fn to_uint(&self) -> uint { **self }
798 799
}

800
impl ToStr for TyVid {
801
    fn to_str(&self) -> ~str { fmt!("<V%u>", self.to_uint()) }
N
Niko Matsakis 已提交
802 803
}

804
impl Vid for IntVid {
805
    fn to_uint(&self) -> uint { **self }
806 807
}

808
impl ToStr for IntVid {
809
    fn to_str(&self) -> ~str { fmt!("<VI%u>", self.to_uint()) }
810 811
}

812
impl Vid for FloatVid {
813
    fn to_uint(&self) -> uint { **self }
814 815
}

816
impl ToStr for FloatVid {
817
    fn to_str(&self) -> ~str { fmt!("<VF%u>", self.to_uint()) }
818 819
}

820
impl Vid for RegionVid {
821
    fn to_uint(&self) -> uint { self.id }
N
Niko Matsakis 已提交
822 823
}

824
impl ToStr for RegionVid {
825
    fn to_str(&self) -> ~str { fmt!("%?", self.id) }
826
}
827

828
impl ToStr for FnSig {
829
    fn to_str(&self) -> ~str {
830 831
        // grr, without tcx not much we can do.
        return ~"(...)";
832 833 834
    }
}

835
impl ToStr for InferTy {
836
    fn to_str(&self) -> ~str {
837
        match *self {
838 839 840 841
            TyVar(ref v) => v.to_str(),
            IntVar(ref v) => v.to_str(),
            FloatVar(ref v) => v.to_str()
        }
N
Niko Matsakis 已提交
842 843 844
    }
}

845
impl ToStr for IntVarValue {
846
    fn to_str(&self) -> ~str {
847
        match *self {
848 849 850
            IntType(ref v) => v.to_str(),
            UintType(ref v) => v.to_str(),
        }
851 852
    }
}
853

854 855 856 857 858
impl to_bytes::IterBytes for TyVid {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
        self.to_uint().iter_bytes(lsb0, f)
    }
}
859

860 861 862 863 864
impl to_bytes::IterBytes for IntVid {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
        self.to_uint().iter_bytes(lsb0, f)
    }
}
865

866 867 868 869 870
impl to_bytes::IterBytes for FloatVid {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
        self.to_uint().iter_bytes(lsb0, f)
    }
}
871

872 873 874 875 876
impl to_bytes::IterBytes for RegionVid {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
        self.to_uint().iter_bytes(lsb0, f)
    }
}
877

878 879
pub struct TypeParameterDef {
    def_id: ast::def_id,
880
    bounds: @ParamBounds
881 882
}

883 884 885
/// Information about the type/lifetime parametesr associated with an item.
/// Analogous to ast::Generics.
pub struct Generics {
886
    type_param_defs: @~[TypeParameterDef],
887 888 889
    region_param: Option<region_variance>,
}

890 891
impl Generics {
    pub fn has_type_params(&self) -> bool {
892 893 894 895
        !self.type_param_defs.is_empty()
    }
}

896 897 898 899 900 901 902 903 904 905
/// 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
906
pub struct ty_param_bounds_and_ty {
907
    generics: Generics,
908 909
    ty: t
}
910

911 912 913 914 915 916
/// As `ty_param_bounds_and_ty` but for a trait ref.
pub struct TraitDef {
    generics: Generics,
    trait_ref: @ty::TraitRef,
}

917 918 919 920
pub struct ty_param_substs_and_ty {
    substs: ty::substs,
    ty: ty::t
}
921

922
type type_cache = @mut HashMap<ast::def_id, ty_param_bounds_and_ty>;
923

924
type constness_cache = @mut HashMap<ast::def_id, const_eval::constness>;
925

926
pub type node_type_table = @mut HashMap<uint,t>;
927

928
fn mk_rcache() -> creader_cache {
929
    return @mut HashMap::new();
930
}
931

932 933
pub fn new_ty_hash<V:Copy>() -> @mut HashMap<t, V> {
    @mut HashMap::new()
934
}
935

936 937 938 939
pub fn mk_ctxt(s: session::Session,
               dm: resolve::DefMap,
               amap: ast_map::map,
               freevars: freevars::freevar_map,
940
               region_maps: @mut middle::region::RegionMaps,
941
               region_paramd_items: middle::region::region_paramd_items,
S
Seo Sanghyeon 已提交
942
               lang_items: middle::lang_items::LanguageItems)
943
            -> ctxt {
944 945
    @ctxt_ {
        diag: s.diagnostic(),
946
        interner: @mut HashMap::new(),
947
        next_id: @mut primitives::LAST_PRIMITIVE_ID,
948 949 950
        cstore: s.cstore,
        sess: s,
        def_map: dm,
951
        region_maps: region_maps,
952
        region_paramd_items: region_paramd_items,
953
        node_types: @mut HashMap::new(),
954
        node_type_substs: @mut HashMap::new(),
955 956 957
        trait_refs: @mut HashMap::new(),
        trait_defs: @mut HashMap::new(),
        intrinsic_traits: @mut HashMap::new(),
958
        items: amap,
959
        intrinsic_defs: @mut HashMap::new(),
960
        freevars: freevars,
961
        tcache: @mut HashMap::new(),
962
        rcache: mk_rcache(),
963
        ccache: @mut HashMap::new(),
964 965
        short_names_cache: new_ty_hash(),
        needs_unwind_cleanup_cache: new_ty_hash(),
966 967 968
        tc_cache: @mut HashMap::new(),
        ast_ty_to_ty_cache: @mut HashMap::new(),
        enum_var_cache: @mut HashMap::new(),
969 970 971
        methods: @mut HashMap::new(),
        trait_method_def_ids: @mut HashMap::new(),
        trait_methods_cache: @mut HashMap::new(),
972
        impl_trait_cache: @mut HashMap::new(),
973
        ty_param_defs: @mut HashMap::new(),
974
        adjustments: @mut HashMap::new(),
975
        normalized_cache: new_ty_hash(),
L
Luqman Aden 已提交
976
        lang_items: lang_items,
977 978 979 980 981
        provided_methods: @mut HashMap::new(),
        provided_method_sources: @mut HashMap::new(),
        supertraits: @mut HashMap::new(),
        destructor_for_type: @mut HashMap::new(),
        destructors: @mut HashSet::new(),
982
        trait_impls: @mut HashMap::new(),
983
        base_impls:  @mut HashMap::new(),
984
        used_unsafe: @mut HashSet::new(),
985
        used_mut_nodes: @mut HashSet::new(),
986
     }
987
}
988

989
// Type constructors
990 991 992

// 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).
993
fn mk_t(cx: ctxt, st: sty) -> t {
994 995
    // Check for primitive types.
    match st {
T
Tim Chevalier 已提交
996 997 998 999 1000 1001
        ty_nil => return mk_nil(),
        ty_err => return mk_err(),
        ty_bool => return mk_bool(),
        ty_int(i) => return mk_mach_int(i),
        ty_uint(u) => return mk_mach_uint(u),
        ty_float(f) => return mk_mach_float(f),
1002 1003 1004
        _ => {}
    };

1005
    let key = intern_key { sty: to_unsafe_ptr(&st) };
1006
    match cx.interner.find(&key) {
1007
      Some(t) => unsafe { return cast::transmute(&t.sty); },
B
Brian Anderson 已提交
1008
      _ => ()
1009
    }
1010

1011
    let mut flags = 0u;
1012
    fn rflags(r: Region) -> uint {
1013
        (has_regions as uint) | {
1014
            match r {
1015
              ty::re_infer(_) => needs_infer as uint,
B
Brian Anderson 已提交
1016
              _ => 0u
1017
            }
N
Niko Matsakis 已提交
1018 1019
        }
    }
N
Niko Matsakis 已提交
1020
    fn sflags(substs: &substs) -> uint {
1021
        let mut f = 0u;
1022
        for substs.tps.iter().advance |tt| { f |= get(*tt).flags; }
1023
        for substs.self_r.iter().advance |r| { f |= rflags(*r) }
B
Brian Anderson 已提交
1024
        return f;
N
Niko Matsakis 已提交
1025
    }
1026 1027
    match &st {
      &ty_estr(vstore_slice(r)) => {
1028
        flags |= rflags(r);
1029
      }
1030
      &ty_evec(ref mt, vstore_slice(r)) => {
1031 1032
        flags |= rflags(r);
        flags |= get(mt.ty).flags;
1033
      }
T
Tim Chevalier 已提交
1034
      &ty_nil | &ty_bool | &ty_int(_) | &ty_float(_) | &ty_uint(_) |
1035
      &ty_estr(_) | &ty_type | &ty_opaque_closure_ptr(_) |
1036
      &ty_opaque_box => (),
T
Tim Chevalier 已提交
1037 1038 1039 1040 1041 1042 1043 1044
      // You might think that we could just return ty_err for
      // any type containing ty_err as a component, and get
      // rid of the has_ty_err flag -- likewise for ty_bot (with
      // the exception of function types that return bot).
      // But doing so caused sporadic memory corruption, and
      // neither I (tjc) nor nmatsakis could figure out why,
      // so we're doing it this way.
      &ty_bot => flags |= has_ty_bot as uint,
1045
      &ty_err => flags |= has_ty_err as uint,
1046 1047
      &ty_param(_) => flags |= has_params as uint,
      &ty_infer(_) => flags |= needs_infer as uint,
1048
      &ty_self(_) => flags |= has_self as uint,
1049
      &ty_enum(_, ref substs) | &ty_struct(_, ref substs) |
1050
      &ty_trait(_, ref substs, _, _, _) => {
1051
        flags |= sflags(substs);
1052
      }
1053 1054
      &ty_box(ref m) | &ty_uniq(ref m) | &ty_evec(ref m, _) |
      &ty_ptr(ref m) | &ty_unboxed_vec(ref m) => {
1055
        flags |= get(m.ty).flags;
1056
      }
1057
      &ty_rptr(r, ref m) => {
1058 1059
        flags |= rflags(r);
        flags |= get(m.ty).flags;
M
Marijn Haverbeke 已提交
1060
      }
1061
      &ty_tup(ref ts) => for ts.iter().advance |tt| { flags |= get(*tt).flags; },
1062
      &ty_bare_fn(ref f) => {
1063
        for f.sig.inputs.iter().advance |a| { flags |= get(*a).flags; }
T
Tim Chevalier 已提交
1064 1065 1066
         flags |= get(f.sig.output).flags;
         // T -> _|_ is *not* _|_ !
         flags &= !(has_ty_bot as uint);
1067 1068 1069
      }
      &ty_closure(ref f) => {
        flags |= rflags(f.region);
1070
        for f.sig.inputs.iter().advance |a| { flags |= get(*a).flags; }
1071
        flags |= get(f.sig.output).flags;
T
Tim Chevalier 已提交
1072 1073
        // T -> _|_ is *not* _|_ !
        flags &= !(has_ty_bot as uint);
M
Marijn Haverbeke 已提交
1074
      }
1075
    }
1076

1077
    let t = ~t_box_ {
1078
        sty: st,
1079
        id: *cx.next_id,
1080 1081
        flags: flags,
    };
1082 1083 1084

    let sty_ptr = to_unsafe_ptr(&t.sty);

1085
    let key = intern_key {
1086
        sty: sty_ptr,
1087
    };
1088

L
Luqman Aden 已提交
1089
    cx.interner.insert(key, t);
1090

1091
    *cx.next_id += 1;
1092 1093 1094 1095

    unsafe {
        cast::transmute::<*sty, t>(sty_ptr)
    }
1096 1097
}

1098
#[inline]
T
Tim Chevalier 已提交
1099
pub fn mk_prim_t(primitive: &'static t_box_) -> t {
1100 1101 1102 1103
    unsafe {
        cast::transmute::<&'static t_box_, t>(primitive)
    }
}
P
Patrick Walton 已提交
1104

1105
#[inline]
T
Tim Chevalier 已提交
1106
pub fn mk_nil() -> t { mk_prim_t(&primitives::TY_NIL) }
1107

1108
#[inline]
T
Tim Chevalier 已提交
1109
pub fn mk_err() -> t { mk_prim_t(&primitives::TY_ERR) }
1110

1111
#[inline]
T
Tim Chevalier 已提交
1112
pub fn mk_bot() -> t { mk_prim_t(&primitives::TY_BOT) }
1113

1114
#[inline]
T
Tim Chevalier 已提交
1115
pub fn mk_bool() -> t { mk_prim_t(&primitives::TY_BOOL) }
1116

1117
#[inline]
T
Tim Chevalier 已提交
1118
pub fn mk_int() -> t { mk_prim_t(&primitives::TY_INT) }
1119

1120
#[inline]
T
Tim Chevalier 已提交
1121
pub fn mk_i8() -> t { mk_prim_t(&primitives::TY_I8) }
1122

1123
#[inline]
T
Tim Chevalier 已提交
1124
pub fn mk_i16() -> t { mk_prim_t(&primitives::TY_I16) }
1125

1126
#[inline]
T
Tim Chevalier 已提交
1127
pub fn mk_i32() -> t { mk_prim_t(&primitives::TY_I32) }
1128

1129
#[inline]
T
Tim Chevalier 已提交
1130
pub fn mk_i64() -> t { mk_prim_t(&primitives::TY_I64) }
1131

1132
#[inline]
T
Tim Chevalier 已提交
1133
pub fn mk_float() -> t { mk_prim_t(&primitives::TY_FLOAT) }
1134

1135
#[inline]
T
Tim Chevalier 已提交
1136
pub fn mk_f32() -> t { mk_prim_t(&primitives::TY_F32) }
1137

1138
#[inline]
T
Tim Chevalier 已提交
1139
pub fn mk_f64() -> t { mk_prim_t(&primitives::TY_F64) }
1140

1141
#[inline]
T
Tim Chevalier 已提交
1142
pub fn mk_uint() -> t { mk_prim_t(&primitives::TY_UINT) }
1143

1144
#[inline]
T
Tim Chevalier 已提交
1145
pub fn mk_u8() -> t { mk_prim_t(&primitives::TY_U8) }
1146

1147
#[inline]
T
Tim Chevalier 已提交
1148
pub fn mk_u16() -> t { mk_prim_t(&primitives::TY_U16) }
1149

1150
#[inline]
T
Tim Chevalier 已提交
1151
pub fn mk_u32() -> t { mk_prim_t(&primitives::TY_U32) }
1152

1153
#[inline]
T
Tim Chevalier 已提交
1154
pub fn mk_u64() -> t { mk_prim_t(&primitives::TY_U64) }
1155

T
Tim Chevalier 已提交
1156
pub fn mk_mach_int(tm: ast::int_ty) -> t {
1157
    match tm {
T
Tim Chevalier 已提交
1158 1159 1160 1161 1162 1163
        ast::ty_i    => mk_int(),
        ast::ty_char => mk_char(),
        ast::ty_i8   => mk_i8(),
        ast::ty_i16  => mk_i16(),
        ast::ty_i32  => mk_i32(),
        ast::ty_i64  => mk_i64(),
1164 1165
    }
}
1166

T
Tim Chevalier 已提交
1167
pub fn mk_mach_uint(tm: ast::uint_ty) -> t {
1168
    match tm {
T
Tim Chevalier 已提交
1169 1170 1171 1172 1173
        ast::ty_u    => mk_uint(),
        ast::ty_u8   => mk_u8(),
        ast::ty_u16  => mk_u16(),
        ast::ty_u32  => mk_u32(),
        ast::ty_u64  => mk_u64(),
1174 1175
    }
}
1176

T
Tim Chevalier 已提交
1177
pub fn mk_mach_float(tm: ast::float_ty) -> t {
1178
    match tm {
T
Tim Chevalier 已提交
1179 1180 1181
        ast::ty_f    => mk_float(),
        ast::ty_f32  => mk_f32(),
        ast::ty_f64  => mk_f64(),
1182
    }
1183
}
1184

1185
#[inline]
T
Tim Chevalier 已提交
1186
pub fn mk_char() -> t { mk_prim_t(&primitives::TY_CHAR) }
1187

1188
pub fn mk_estr(cx: ctxt, t: vstore) -> t {
1189 1190 1191
    mk_t(cx, ty_estr(t))
}

1192
pub fn mk_enum(cx: ctxt, did: ast::def_id, substs: substs) -> t {
N
Niko Matsakis 已提交
1193
    // take a copy of substs so that we own the vectors inside
1194
    mk_t(cx, ty_enum(did, substs))
1195
}
1196

1197
pub fn mk_box(cx: ctxt, tm: mt) -> t { mk_t(cx, ty_box(tm)) }
1198

1199
pub fn mk_imm_box(cx: ctxt, ty: t) -> t {
1200 1201
    mk_box(cx, mt {ty: ty, mutbl: ast::m_imm})
}
1202

1203
pub fn mk_uniq(cx: ctxt, tm: mt) -> t { mk_t(cx, ty_uniq(tm)) }
1204

1205
pub fn mk_imm_uniq(cx: ctxt, ty: t) -> t {
1206 1207
    mk_uniq(cx, mt {ty: ty, mutbl: ast::m_imm})
}
1208

1209
pub fn mk_ptr(cx: ctxt, tm: mt) -> t { mk_t(cx, ty_ptr(tm)) }
1210

1211
pub fn mk_rptr(cx: ctxt, r: Region, tm: mt) -> t { mk_t(cx, ty_rptr(r, tm)) }
1212

1213
pub fn mk_mut_rptr(cx: ctxt, r: Region, ty: t) -> t {
1214
    mk_rptr(cx, r, mt {ty: ty, mutbl: ast::m_mutbl})
1215
}
1216
pub fn mk_imm_rptr(cx: ctxt, r: Region, ty: t) -> t {
1217
    mk_rptr(cx, r, mt {ty: ty, mutbl: ast::m_imm})
1218 1219
}

1220
pub fn mk_mut_ptr(cx: ctxt, ty: t) -> t {
1221 1222
    mk_ptr(cx, mt {ty: ty, mutbl: ast::m_mutbl})
}
1223

1224
pub fn mk_imm_ptr(cx: ctxt, ty: t) -> t {
1225
    mk_ptr(cx, mt {ty: ty, mutbl: ast::m_imm})
1226 1227
}

1228
pub fn mk_nil_ptr(cx: ctxt) -> t {
T
Tim Chevalier 已提交
1229
    mk_ptr(cx, mt {ty: mk_nil(), mutbl: ast::m_imm})
1230 1231
}

1232
pub fn mk_evec(cx: ctxt, tm: mt, t: vstore) -> t {
1233 1234 1235
    mk_t(cx, ty_evec(tm, t))
}

1236
pub fn mk_unboxed_vec(cx: ctxt, tm: mt) -> t {
M
Michael Sullivan 已提交
1237 1238
    mk_t(cx, ty_unboxed_vec(tm))
}
1239
pub fn mk_mut_unboxed_vec(cx: ctxt, ty: t) -> t {
1240
    mk_t(cx, ty_unboxed_vec(mt {ty: ty, mutbl: ast::m_imm}))
1241
}
M
Michael Sullivan 已提交
1242

1243
pub fn mk_tup(cx: ctxt, ts: ~[t]) -> t { mk_t(cx, ty_tup(ts)) }
1244

1245
pub fn mk_closure(cx: ctxt, fty: ClosureTy) -> t {
1246 1247 1248
    mk_t(cx, ty_closure(fty))
}

1249
pub fn mk_bare_fn(cx: ctxt, fty: BareFnTy) -> t {
1250 1251 1252 1253
    mk_t(cx, ty_bare_fn(fty))
}

pub fn mk_ctor_fn(cx: ctxt, input_tys: &[ty::t], output: ty::t) -> t {
E
Erick Tryzelaar 已提交
1254
    let input_args = input_tys.map(|t| *t);
1255 1256 1257
    mk_bare_fn(cx,
               BareFnTy {
                   purity: ast::pure_fn,
1258
                   abis: AbiSet::Rust(),
1259 1260 1261 1262 1263 1264
                   sig: FnSig {
                    bound_lifetime_names: opt_vec::Empty,
                    inputs: input_args,
                    output: output
                   }
                })
1265 1266
}

1267

1268 1269
pub fn mk_trait(cx: ctxt,
                did: ast::def_id,
1270
                substs: substs,
1271
                store: TraitStore,
1272 1273
                mutability: ast::mutability,
                bounds: BuiltinBounds)
1274
             -> t {
N
Niko Matsakis 已提交
1275
    // take a copy of substs so that we own the vectors inside
1276
    mk_t(cx, ty_trait(did, substs, store, mutability, bounds))
1277 1278
}

1279
pub fn mk_struct(cx: ctxt, struct_id: ast::def_id, substs: substs) -> t {
N
Niko Matsakis 已提交
1280
    // take a copy of substs so that we own the vectors inside
1281
    mk_t(cx, ty_struct(struct_id, substs))
T
Tim Chevalier 已提交
1282 1283
}

1284
pub fn mk_var(cx: ctxt, v: TyVid) -> t { mk_infer(cx, TyVar(v)) }
1285

1286
pub fn mk_int_var(cx: ctxt, v: IntVid) -> t { mk_infer(cx, IntVar(v)) }
1287

1288
pub fn mk_float_var(cx: ctxt, v: FloatVid) -> t { mk_infer(cx, FloatVar(v)) }
1289

1290
pub fn mk_infer(cx: ctxt, it: InferTy) -> t { mk_t(cx, ty_infer(it)) }
1291

1292
pub fn mk_self(cx: ctxt, did: ast::def_id) -> t { mk_t(cx, ty_self(did)) }
M
Marijn Haverbeke 已提交
1293

1294
pub fn mk_param(cx: ctxt, n: uint, k: def_id) -> t {
1295
    mk_t(cx, ty_param(param_ty { idx: n, def_id: k }))
1296
}
1297

1298
pub fn mk_type(cx: ctxt) -> t { mk_t(cx, ty_type) }
1299

1300 1301
pub fn mk_opaque_closure_ptr(cx: ctxt, sigil: ast::Sigil) -> t {
    mk_t(cx, ty_opaque_closure_ptr(sigil))
1302 1303
}

1304
pub fn mk_opaque_box(cx: ctxt) -> t { mk_t(cx, ty_opaque_box) }
1305

1306
pub fn walk_ty(ty: t, f: &fn(t)) {
B
Brian Anderson 已提交
1307
    maybe_walk_ty(ty, |t| { f(t); true });
1308 1309
}

1310
pub fn maybe_walk_ty(ty: t, f: &fn(t) -> bool) {
1311 1312 1313
    if !f(ty) {
        return;
    }
1314
    match get(ty).sty {
1315
      ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
1316
      ty_estr(_) | ty_type | ty_opaque_box | ty_self(_) |
1317
      ty_opaque_closure_ptr(_) | ty_infer(_) | ty_param(_) | ty_err => {
1318
      }
1319 1320
      ty_box(ref tm) | ty_evec(ref tm, _) | ty_unboxed_vec(ref tm) |
      ty_ptr(ref tm) | ty_rptr(_, ref tm) | ty_uniq(ref tm) => {
1321
        maybe_walk_ty(tm.ty, f);
1322
      }
1323
      ty_enum(_, ref substs) | ty_struct(_, ref substs) |
1324
      ty_trait(_, ref substs, _, _, _) => {
1325
        for (*substs).tps.iter().advance |subty| { maybe_walk_ty(*subty, f); }
1326
      }
1327
      ty_tup(ref ts) => { for ts.iter().advance |tt| { maybe_walk_ty(*tt, f); } }
1328
      ty_bare_fn(ref ft) => {
1329
        for ft.sig.inputs.iter().advance |a| { maybe_walk_ty(*a, f); }
1330 1331 1332
        maybe_walk_ty(ft.sig.output, f);
      }
      ty_closure(ref ft) => {
1333
        for ft.sig.inputs.iter().advance |a| { maybe_walk_ty(*a, f); }
1334
        maybe_walk_ty(ft.sig.output, f);
M
Marijn Haverbeke 已提交
1335
      }
1336 1337 1338
    }
}

1339
pub fn fold_sty_to_ty(tcx: ty::ctxt, sty: &sty, foldop: &fn(t) -> t) -> t {
N
Niko Matsakis 已提交
1340
    mk_t(tcx, fold_sty(sty, foldop))
1341
}
1342

1343
pub fn fold_sig(sig: &FnSig, fldop: &fn(t) -> t) -> FnSig {
1344
    let args = sig.inputs.map(|arg| fldop(*arg));
1345 1346

    FnSig {
1347
        bound_lifetime_names: copy sig.bound_lifetime_names,
L
Luqman Aden 已提交
1348
        inputs: args,
1349 1350 1351 1352
        output: fldop(sig.output)
    }
}

1353 1354 1355 1356 1357 1358
pub fn fold_bare_fn_ty(fty: &BareFnTy, fldop: &fn(t) -> t) -> BareFnTy {
    BareFnTy {sig: fold_sig(&fty.sig, fldop),
              abis: fty.abis,
              purity: fty.purity}
}

1359 1360
fn fold_sty(sty: &sty, fldop: &fn(t) -> t) -> sty {
    fn fold_substs(substs: &substs, fldop: &fn(t) -> t) -> substs {
1361 1362 1363
        substs {self_r: substs.self_r,
                self_ty: substs.self_ty.map(|t| fldop(*t)),
                tps: substs.tps.map(|t| fldop(*t))}
1364 1365
    }

1366 1367
    match *sty {
        ty_box(ref tm) => {
1368
            ty_box(mt {ty: fldop(tm.ty), mutbl: tm.mutbl})
1369
        }
1370
        ty_uniq(ref tm) => {
1371
            ty_uniq(mt {ty: fldop(tm.ty), mutbl: tm.mutbl})
1372
        }
1373
        ty_ptr(ref tm) => {
1374
            ty_ptr(mt {ty: fldop(tm.ty), mutbl: tm.mutbl})
1375
        }
1376
        ty_unboxed_vec(ref tm) => {
1377
            ty_unboxed_vec(mt {ty: fldop(tm.ty), mutbl: tm.mutbl})
1378
        }
1379
        ty_evec(ref tm, vst) => {
1380
            ty_evec(mt {ty: fldop(tm.ty), mutbl: tm.mutbl}, vst)
1381 1382 1383 1384
        }
        ty_enum(tid, ref substs) => {
            ty_enum(tid, fold_substs(substs, fldop))
        }
1385 1386
        ty_trait(did, ref substs, st, mutbl, bounds) => {
            ty_trait(did, fold_substs(substs, fldop), st, mutbl, bounds)
1387
        }
1388 1389
        ty_tup(ref ts) => {
            let new_ts = ts.map(|tt| fldop(*tt));
1390 1391
            ty_tup(new_ts)
        }
1392
        ty_bare_fn(ref f) => {
1393
            ty_bare_fn(fold_bare_fn_ty(f, fldop))
1394 1395
        }
        ty_closure(ref f) => {
1396
            let sig = fold_sig(&f.sig, fldop);
1397
            ty_closure(ClosureTy {sig: sig, ..copy *f})
1398
        }
1399
        ty_rptr(r, ref tm) => {
1400
            ty_rptr(r, mt {ty: fldop(tm.ty), mutbl: tm.mutbl})
1401
        }
1402 1403
        ty_struct(did, ref substs) => {
            ty_struct(did, fold_substs(substs, fldop))
1404 1405
        }
        ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
1406
        ty_estr(_) | ty_type | ty_opaque_closure_ptr(_) | ty_err |
1407
        ty_opaque_box | ty_infer(_) | ty_param(*) | ty_self(_) => {
1408
            /*bad*/copy *sty
1409
        }
N
Niko Matsakis 已提交
1410 1411
    }
}
1412

N
Niko Matsakis 已提交
1413
// Folds types from the bottom up.
1414
pub fn fold_ty(cx: ctxt, t0: t, fldop: &fn(t) -> t) -> t {
1415
    let sty = fold_sty(&get(t0).sty, |t| fold_ty(cx, fldop(t), fldop));
N
Niko Matsakis 已提交
1416 1417
    fldop(mk_t(cx, sty))
}
1418

1419
pub fn walk_regions_and_ty(
1420 1421
    cx: ctxt,
    ty: t,
1422 1423
    walkr: &fn(r: Region),
    walkt: &fn(t: t) -> bool) {
1424 1425 1426 1427

    if (walkt(ty)) {
        fold_regions_and_ty(
            cx, ty,
B
Brian Anderson 已提交
1428
            |r| { walkr(r); r },
1429 1430
            |t| { walk_regions_and_ty(cx, t, walkr, walkt); t },
            |t| { walk_regions_and_ty(cx, t, walkr, walkt); t });
1431 1432 1433
    }
}

1434
pub fn fold_regions_and_ty(
1435 1436
    cx: ctxt,
    ty: t,
1437 1438 1439
    fldr: &fn(r: Region) -> Region,
    fldfnt: &fn(t: t) -> t,
    fldt: &fn(t: t) -> t) -> t {
1440 1441

    fn fold_substs(
N
Niko Matsakis 已提交
1442
        substs: &substs,
1443 1444
        fldr: &fn(r: Region) -> Region,
        fldt: &fn(t: t) -> t)
1445 1446 1447 1448 1449 1450
     -> substs {
        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))
        }
1451 1452 1453
    }

    let tb = ty::get(ty);
1454
    match tb.sty {
B
Brian Anderson 已提交
1455
      ty::ty_rptr(r, mt) => {
1456 1457
        let m_r = fldr(r);
        let m_t = fldt(mt.ty);
1458
        ty::mk_rptr(cx, m_r, mt {ty: m_t, mutbl: mt.mutbl})
1459
      }
B
Brian Anderson 已提交
1460
      ty_estr(vstore_slice(r)) => {
1461 1462 1463
        let m_r = fldr(r);
        ty::mk_estr(cx, vstore_slice(m_r))
      }
B
Brian Anderson 已提交
1464
      ty_evec(mt, vstore_slice(r)) => {
1465 1466
        let m_r = fldr(r);
        let m_t = fldt(mt.ty);
1467
        ty::mk_evec(cx, mt {ty: m_t, mutbl: mt.mutbl}, vstore_slice(m_r))
1468
      }
N
Niko Matsakis 已提交
1469
      ty_enum(def_id, ref substs) => {
1470 1471
        ty::mk_enum(cx, def_id, fold_substs(substs, fldr, fldt))
      }
1472 1473
      ty_struct(def_id, ref substs) => {
        ty::mk_struct(cx, def_id, fold_substs(substs, fldr, fldt))
1474
      }
1475 1476 1477 1478 1479 1480
      ty_trait(def_id, ref substs, st, mutbl, bounds) => {
        let st = match st {
            RegionTraitStore(region) => RegionTraitStore(fldr(region)),
            st => st,
        };
        ty::mk_trait(cx, def_id, fold_substs(substs, fldr, fldt), st, mutbl, bounds)
1481
      }
1482 1483 1484 1485 1486 1487 1488 1489
      ty_bare_fn(ref f) => {
          ty::mk_bare_fn(cx, BareFnTy {sig: fold_sig(&f.sig, fldfnt),
                                       ..copy *f})
      }
      ty_closure(ref f) => {
          ty::mk_closure(cx, ClosureTy {region: fldr(f.region),
                                        sig: fold_sig(&f.sig, fldfnt),
                                        ..copy *f})
1490
      }
N
Niko Matsakis 已提交
1491
      ref sty => {
B
Brian Anderson 已提交
1492
        fold_sty_to_ty(cx, sty, |t| fldt(t))
1493 1494 1495 1496
      }
    }
}

1497 1498
// n.b. this function is intended to eventually replace fold_region() below,
// that is why its name is so similar.
1499
pub fn fold_regions(
1500 1501
    cx: ctxt,
    ty: t,
1502
    fldr: &fn(r: Region, in_fn: bool) -> Region) -> t {
1503
    fn do_fold(cx: ctxt, ty: t, in_fn: bool,
1504
               fldr: &fn(Region, bool) -> Region) -> t {
1505
        debug!("do_fold(ty=%s, in_fn=%b)", ty_to_str(cx, ty), in_fn);
B
Brian Anderson 已提交
1506
        if !type_has_regions(ty) { return ty; }
1507 1508
        fold_regions_and_ty(
            cx, ty,
B
Brian Anderson 已提交
1509 1510 1511
            |r| fldr(r, in_fn),
            |t| do_fold(cx, t, true, fldr),
            |t| do_fold(cx, t, in_fn, fldr))
1512 1513 1514 1515
    }
    do_fold(cx, ty, false, fldr)
}

1516
// Substitute *only* type parameters.  Used in trans where regions are erased.
1517
pub fn subst_tps(cx: ctxt, tps: &[t], self_ty_opt: Option<t>, typ: t) -> t {
1518
    if tps.len() == 0u && self_ty_opt.is_none() { return typ; }
1519
    let tb = ty::get(typ);
1520
    if self_ty_opt.is_none() && !tbox_has_flag(tb, has_params) { return typ; }
1521
    match tb.sty {
1522
        ty_param(p) => tps[p.idx],
1523
        ty_self(_) => {
1524
            match self_ty_opt {
1525
                None => cx.sess.bug("ty_self unexpected here"),
1526 1527 1528 1529 1530 1531 1532 1533
                Some(self_ty) => {
                    subst_tps(cx, tps, self_ty_opt, self_ty)
                }
            }
        }
        ref sty => {
            fold_sty_to_ty(cx, sty, |t| subst_tps(cx, tps, self_ty_opt, t))
        }
1534 1535 1536
    }
}

1537
pub fn substs_is_noop(substs: &substs) -> bool {
1538 1539 1540
    substs.tps.len() == 0u &&
        substs.self_r.is_none() &&
        substs.self_ty.is_none()
1541 1542
}

1543
pub fn substs_to_str(cx: ctxt, substs: &substs) -> ~str {
1544
    substs.repr(cx)
1545 1546
}

1547 1548 1549 1550
pub fn subst(cx: ctxt,
             substs: &substs,
             typ: t)
          -> t {
1551
    typ.subst(cx, substs)
1552 1553
}

1554
// Type utilities
1555

1556
pub fn type_is_nil(ty: t) -> bool { get(ty).sty == ty_nil }
1557

T
Tim Chevalier 已提交
1558 1559 1560 1561 1562 1563 1564
pub fn type_is_bot(ty: t) -> bool {
    (get(ty).flags & (has_ty_bot as uint)) != 0
}

pub fn type_is_error(ty: t) -> bool {
    (get(ty).flags & (has_ty_err as uint)) != 0
}
1565

1566 1567 1568 1569
pub fn type_needs_subst(ty: t) -> bool {
    tbox_has_flag(get(ty), needs_subst)
}

1570
pub fn trait_ref_contains_error(tref: &ty::TraitRef) -> bool {
1571 1572
    tref.substs.self_ty.iter().any_(|&t| type_is_error(t)) ||
        tref.substs.tps.iter().any_(|&t| type_is_error(t))
1573 1574
}

1575
pub fn type_is_ty_var(ty: t) -> bool {
1576
    match get(ty).sty {
1577
      ty_infer(TyVar(_)) => true,
B
Brian Anderson 已提交
1578
      _ => false
1579 1580 1581
    }
}

1582
pub fn type_is_bool(ty: t) -> bool { get(ty).sty == ty_bool }
1583

1584 1585 1586 1587 1588 1589 1590
pub fn type_is_self(ty: t) -> bool {
    match get(ty).sty {
        ty_self(*) => true,
        _ => false
    }
}

1591
pub fn type_is_structural(ty: t) -> bool {
1592
    match get(ty).sty {
1593
      ty_struct(*) | ty_tup(_) | ty_enum(*) | ty_closure(_) | ty_trait(*) |
1594 1595
      ty_evec(_, vstore_fixed(_)) | ty_estr(vstore_fixed(_)) |
      ty_evec(_, vstore_slice(_)) | ty_estr(vstore_slice(_))
B
Brian Anderson 已提交
1596 1597
      => true,
      _ => false
1598 1599 1600
    }
}

1601
pub fn type_is_sequence(ty: t) -> bool {
1602
    match get(ty).sty {
B
Brian Anderson 已提交
1603 1604
      ty_estr(_) | ty_evec(_, _) => true,
      _ => false
1605 1606 1607
    }
}

S
Seo Sanghyeon 已提交
1608 1609 1610 1611 1612 1613 1614
pub fn type_is_simd(cx: ctxt, ty: t) -> bool {
    match get(ty).sty {
        ty_struct(did, _) => lookup_simd(cx, did),
        _ => false
    }
}

1615
pub fn type_is_str(ty: t) -> bool {
1616
    match get(ty).sty {
B
Brian Anderson 已提交
1617 1618
      ty_estr(_) => true,
      _ => false
1619 1620
    }
}
1621

1622
pub fn sequence_element_type(cx: ctxt, ty: t) -> t {
1623
    match get(ty).sty {
T
Tim Chevalier 已提交
1624
      ty_estr(_) => return mk_mach_uint(ast::ty_u8),
B
Brian Anderson 已提交
1625
      ty_evec(mt, _) | ty_unboxed_vec(mt) => return mt.ty,
1626
      _ => cx.sess.bug("sequence_element_type called on non-sequence value"),
1627 1628 1629
    }
}

S
Seo Sanghyeon 已提交
1630 1631 1632 1633 1634 1635
pub fn simd_type(cx: ctxt, ty: t) -> t {
    match get(ty).sty {
        ty_struct(did, ref substs) => {
            let fields = lookup_struct_fields(cx, did);
            lookup_field_type(cx, did, fields[0].id, substs)
        }
1636
        _ => fail!("simd_type called on invalid type")
S
Seo Sanghyeon 已提交
1637 1638 1639 1640 1641 1642 1643 1644 1645
    }
}

pub fn simd_size(cx: ctxt, ty: t) -> uint {
    match get(ty).sty {
        ty_struct(did, _) => {
            let fields = lookup_struct_fields(cx, did);
            fields.len()
        }
1646
        _ => fail!("simd_size called on invalid type")
S
Seo Sanghyeon 已提交
1647 1648 1649
    }
}

1650
pub fn get_element_type(ty: t, i: uint) -> t {
1651 1652
    match get(ty).sty {
      ty_tup(ref ts) => return ts[i],
1653
      _ => fail!("get_element_type called on invalid type")
1654 1655 1656
    }
}

1657
pub fn type_is_box(ty: t) -> bool {
1658
    match get(ty).sty {
B
Brian Anderson 已提交
1659 1660
      ty_box(_) => return true,
      _ => return false
1661
    }
M
Marijn Haverbeke 已提交
1662 1663
}

1664
pub fn type_is_boxed(ty: t) -> bool {
1665
    match get(ty).sty {
1666
      ty_box(_) | ty_opaque_box |
B
Brian Anderson 已提交
1667 1668
      ty_evec(_, vstore_box) | ty_estr(vstore_box) => true,
      _ => false
1669 1670 1671
    }
}

1672
pub fn type_is_region_ptr(ty: t) -> bool {
1673
    match get(ty).sty {
B
Brian Anderson 已提交
1674 1675
      ty_rptr(_, _) => true,
      _ => false
1676 1677 1678
    }
}

1679
pub fn type_is_slice(ty: t) -> bool {
1680
    match get(ty).sty {
B
Brian Anderson 已提交
1681 1682
      ty_evec(_, vstore_slice(_)) | ty_estr(vstore_slice(_)) => true,
      _ => return false
1683 1684 1685
    }
}

1686
pub fn type_is_unique_box(ty: t) -> bool {
1687
    match get(ty).sty {
B
Brian Anderson 已提交
1688 1689
      ty_uniq(_) => return true,
      _ => return false
1690
    }
M
Marijn Haverbeke 已提交
1691
}
1692

1693
pub fn type_is_unsafe_ptr(ty: t) -> bool {
1694
    match get(ty).sty {
B
Brian Anderson 已提交
1695 1696
      ty_ptr(_) => return true,
      _ => return false
1697 1698 1699
    }
}

1700
pub fn type_is_vec(ty: t) -> bool {
1701
    return match get(ty).sty {
B
Brian Anderson 已提交
1702 1703 1704
          ty_evec(_, _) | ty_unboxed_vec(_) => true,
          ty_estr(_) => true,
          _ => false
B
Brian Anderson 已提交
1705
        };
M
Marijn Haverbeke 已提交
1706 1707
}

1708
pub fn type_is_unique(ty: t) -> bool {
1709
    match get(ty).sty {
1710 1711 1712 1713 1714
        ty_uniq(_) |
        ty_evec(_, vstore_uniq) |
        ty_estr(vstore_uniq) |
        ty_opaque_closure_ptr(ast::OwnedSigil) => true,
        _ => return false
B
Brian Anderson 已提交
1715
    }
1716 1717
}

1718 1719 1720 1721 1722
/*
 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.)
*/
1723
pub fn type_is_scalar(ty: t) -> bool {
1724
    match get(ty).sty {
1725
      ty_nil | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) |
1726
      ty_infer(IntVar(_)) | ty_infer(FloatVar(_)) | ty_type |
1727
      ty_bare_fn(*) | ty_ptr(_) => true,
B
Brian Anderson 已提交
1728
      _ => false
M
Marijn Haverbeke 已提交
1729
    }
1730 1731
}

1732
pub fn type_is_immediate(ty: t) -> bool {
B
Brian Anderson 已提交
1733
    return type_is_scalar(ty) || type_is_boxed(ty) ||
1734
        type_is_unique(ty) || type_is_region_ptr(ty);
1735 1736
}

1737
pub fn type_needs_drop(cx: ctxt, ty: t) -> bool {
1738
    type_contents(cx, ty).needs_drop(cx)
1739 1740
}

1741 1742 1743 1744
// 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.
1745
pub fn type_needs_unwind_cleanup(cx: ctxt, ty: t) -> bool {
1746
    match cx.needs_unwind_cleanup_cache.find(&ty) {
1747
      Some(&result) => return result,
B
Brian Anderson 已提交
1748
      None => ()
1749 1750
    }

1751
    let mut tycache = HashSet::new();
1752
    let needs_unwind_cleanup =
1753
        type_needs_unwind_cleanup_(cx, ty, &mut tycache, false);
1754
    cx.needs_unwind_cleanup_cache.insert(ty, needs_unwind_cleanup);
B
Brian Anderson 已提交
1755
    return needs_unwind_cleanup;
1756 1757 1758
}

fn type_needs_unwind_cleanup_(cx: ctxt, ty: t,
1759
                              tycache: &mut HashSet<t>,
1760 1761
                              encountered_box: bool) -> bool {

1762
    // Prevent infinite recursion
1763 1764
    if !tycache.insert(ty) {
        return false;
1765
    }
1766

1767
    let mut encountered_box = encountered_box;
1768
    let mut needs_unwind_cleanup = false;
B
Brian Anderson 已提交
1769
    do maybe_walk_ty(ty) |ty| {
1770
        let old_encountered_box = encountered_box;
1771
        let result = match get(ty).sty {
B
Brian Anderson 已提交
1772
          ty_box(_) | ty_opaque_box => {
1773 1774 1775
            encountered_box = true;
            true
          }
1776 1777
          ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
          ty_tup(_) | ty_ptr(_) => {
1778 1779
            true
          }
N
Niko Matsakis 已提交
1780
          ty_enum(did, ref substs) => {
1781 1782
            for (*enum_variants(cx, did)).iter().advance |v| {
                for v.args.iter().advance |aty| {
1783
                    let t = subst(cx, substs, *aty);
1784 1785 1786
                    needs_unwind_cleanup |=
                        type_needs_unwind_cleanup_(cx, t, tycache,
                                                   encountered_box);
1787 1788 1789 1790
                }
            }
            !needs_unwind_cleanup
          }
M
Michael Sullivan 已提交
1791
          ty_uniq(_) |
1792 1793 1794 1795
          ty_estr(vstore_uniq) |
          ty_estr(vstore_box) |
          ty_evec(_, vstore_uniq) |
          ty_evec(_, vstore_box)
B
Brian Anderson 已提交
1796
          => {
1797 1798 1799 1800 1801 1802 1803 1804 1805
            // Once we're inside a box, the annihilator will find
            // it and destroy it.
            if !encountered_box {
                needs_unwind_cleanup = true;
                false
            } else {
                true
            }
          }
B
Brian Anderson 已提交
1806
          _ => {
1807 1808 1809
            needs_unwind_cleanup = true;
            false
          }
1810 1811 1812 1813
        };

        encountered_box = old_encountered_box;
        result
1814 1815
    }

B
Brian Anderson 已提交
1816
    return needs_unwind_cleanup;
1817 1818
}

1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833
/**
 * Type contents is how the type checker reasons about kinds.
 * They track what kinds of things are found within a type.  You can
 * think of them as kind of an "anti-kind".  They track the kinds of values
 * and thinks that are contained in types.  Having a larger contents for
 * a type tends to rule that type *out* from various kinds.  For example,
 * a type that contains a borrowed pointer is not sendable.
 *
 * The reason we compute type contents and not kinds is that it is
 * easier for me (nmatsakis) to think about what is contained within
 * a type than to think about what is *not* contained within a type.
 */
pub struct TypeContents {
    bits: u32
}
1834

1835 1836
impl TypeContents {
    pub fn meets_bounds(&self, cx: ctxt, bbs: BuiltinBounds) -> bool {
1837 1838 1839
        iter::all(|bb| self.meets_bound(cx, bb), |f| bbs.each(f))
    }

1840
    pub fn meets_bound(&self, cx: ctxt, bb: BuiltinBound) -> bool {
1841 1842 1843 1844
        match bb {
            BoundCopy => self.is_copy(cx),
            BoundStatic => self.is_static(cx),
            BoundConst => self.is_const(cx),
1845 1846
            BoundOwned => self.is_owned(cx),
            BoundSized => self.is_sized(cx),
1847 1848 1849
        }
    }

1850
    pub fn intersects(&self, tc: TypeContents) -> bool {
1851 1852
        (self.bits & tc.bits) != 0
    }
1853

1854
    pub fn is_copy(&self, cx: ctxt) -> bool {
1855 1856
        !self.intersects(TypeContents::noncopyable(cx))
    }
1857

1858
    pub fn noncopyable(_cx: ctxt) -> TypeContents {
1859 1860 1861
        TC_DTOR + TC_BORROWED_MUT + TC_ONCE_CLOSURE + TC_OWNED_CLOSURE +
            TC_EMPTY_ENUM
    }
1862

1863
    pub fn is_static(&self, cx: ctxt) -> bool {
1864
        !self.intersects(TypeContents::nonstatic(cx))
1865
    }
1866

1867
    pub fn nonstatic(_cx: ctxt) -> TypeContents {
1868 1869
        TC_BORROWED_POINTER
    }
1870

1871
    pub fn is_owned(&self, cx: ctxt) -> bool {
1872 1873
        !self.intersects(TypeContents::nonowned(cx))
    }
1874

1875
    pub fn nonowned(_cx: ctxt) -> TypeContents {
1876
        TC_MANAGED + TC_BORROWED_POINTER + TC_NON_OWNED
1877
    }
1878

1879
    pub fn contains_managed(&self) -> bool {
1880 1881 1882
        self.intersects(TC_MANAGED)
    }

1883
    pub fn is_const(&self, cx: ctxt) -> bool {
1884 1885
        !self.intersects(TypeContents::nonconst(cx))
    }
1886

1887
    pub fn nonconst(_cx: ctxt) -> TypeContents {
1888 1889
        TC_MUTABLE
    }
1890

1891
    pub fn is_sized(&self, cx: ctxt) -> bool {
1892 1893 1894
        !self.intersects(TypeContents::dynamically_sized(cx))
    }

1895
    pub fn dynamically_sized(_cx: ctxt) -> TypeContents {
1896 1897 1898
        TC_DYNAMIC_SIZE
    }

1899
    pub fn moves_by_default(&self, cx: ctxt) -> bool {
1900 1901
        self.intersects(TypeContents::nonimplicitly_copyable(cx))
    }
1902

1903
    pub fn nonimplicitly_copyable(cx: ctxt) -> TypeContents {
1904
        TypeContents::noncopyable(cx) + TC_OWNED_POINTER + TC_OWNED_VEC
1905
    }
1906

1907
    pub fn needs_drop(&self, cx: ctxt) -> bool {
1908 1909 1910 1911
        let tc = TC_MANAGED + TC_DTOR + TypeContents::owned(cx);
        self.intersects(tc)
    }

1912
    pub fn owned(_cx: ctxt) -> TypeContents {
1913 1914
        //! Any kind of owned contents.
        TC_OWNED_CLOSURE + TC_OWNED_POINTER + TC_OWNED_VEC
1915
    }
1916
}
1917

1918
impl ops::Add<TypeContents,TypeContents> for TypeContents {
1919
    fn add(&self, other: &TypeContents) -> TypeContents {
1920 1921
        TypeContents {bits: self.bits | other.bits}
    }
1922 1923
}

1924
impl ops::Sub<TypeContents,TypeContents> for TypeContents {
1925
    fn sub(&self, other: &TypeContents) -> TypeContents {
1926 1927
        TypeContents {bits: self.bits & !other.bits}
    }
1928 1929
}

1930
impl ToStr for TypeContents {
1931
    fn to_str(&self) -> ~str {
1932 1933
        fmt!("TypeContents(%s)", u32::to_str_radix(self.bits, 2))
    }
1934 1935
}

1936
/// Constant for a type containing nothing of interest.
1937
static TC_NONE: TypeContents =             TypeContents{bits: 0b0000_0000_0000};
1938

1939
/// Contains a borrowed value with a lifetime other than static
1940
static TC_BORROWED_POINTER: TypeContents = TypeContents{bits: 0b0000_0000_0001};
1941

1942
/// Contains an owned pointer (~T) but not slice of some kind
1943
static TC_OWNED_POINTER: TypeContents =    TypeContents{bits: 0b0000_0000_0010};
1944

1945
/// Contains an owned vector ~[] or owned string ~str
1946
static TC_OWNED_VEC: TypeContents =        TypeContents{bits: 0b0000_0000_0100};
1947

1948
/// Contains a ~fn() or a ~Trait, which is non-copyable.
1949
static TC_OWNED_CLOSURE: TypeContents =    TypeContents{bits: 0b0000_0000_1000};
1950

1951
/// Type with a destructor
1952
static TC_DTOR: TypeContents =             TypeContents{bits: 0b0000_0001_0000};
1953

1954
/// Contains a managed value
1955
static TC_MANAGED: TypeContents =          TypeContents{bits: 0b0000_0010_0000};
1956

1957
/// &mut with any region
1958
static TC_BORROWED_MUT: TypeContents =     TypeContents{bits: 0b0000_0100_0000};
1959

1960
/// Mutable content, whether owned or by ref
1961
static TC_MUTABLE: TypeContents =          TypeContents{bits: 0b0000_1000_0000};
1962

1963 1964
/// One-shot closure
static TC_ONCE_CLOSURE: TypeContents =     TypeContents{bits: 0b0001_0000_0000};
1965

1966
/// An enum with no variants.
1967 1968 1969 1970
static TC_EMPTY_ENUM: TypeContents =       TypeContents{bits: 0b0010_0000_0000};

/// Contains a type marked with `#[non_owned]`
static TC_NON_OWNED: TypeContents =        TypeContents{bits: 0b0100_0000_0000};
1971

1972 1973 1974
/// Is a bare vector, str, function, trait, etc (only relevant at top level).
static TC_DYNAMIC_SIZE: TypeContents =     TypeContents{bits: 0b1000_0000_0000};

1975
/// All possible contents.
1976
static TC_ALL: TypeContents =              TypeContents{bits: 0b1111_1111_1111};
1977

1978 1979
pub fn type_is_copyable(cx: ctxt, t: ty::t) -> bool {
    type_contents(cx, t).is_copy(cx)
1980 1981
}

1982 1983
pub fn type_is_static(cx: ctxt, t: ty::t) -> bool {
    type_contents(cx, t).is_static(cx)
1984 1985
}

1986 1987 1988
pub fn type_is_owned(cx: ctxt, t: ty::t) -> bool {
    type_contents(cx, t).is_owned(cx)
}
1989

1990 1991 1992
pub fn type_is_const(cx: ctxt, t: ty::t) -> bool {
    type_contents(cx, t).is_const(cx)
}
1993

1994 1995 1996 1997 1998
pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
    let ty_id = type_id(ty);
    match cx.tc_cache.find(&ty_id) {
        Some(tc) => { return *tc; }
        None => {}
1999 2000
    }

2001
    let mut cache = HashMap::new();
2002 2003 2004
    let result = tc_ty(cx, ty, &mut cache);
    cx.tc_cache.insert(ty_id, result);
    return result;
M
Marijn Haverbeke 已提交
2005

2006 2007
    fn tc_ty(cx: ctxt,
             ty: t,
2008
             cache: &mut HashMap<uint, TypeContents>) -> TypeContents
2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035
    {
        // Subtle: Note that we are *not* using cx.tc_cache here but rather a
        // private cache for this walk.  This is needed in the case of cyclic
        // types like:
        //
        //     struct List { next: ~Option<List>, ... }
        //
        // When computing the type contents of such a type, we wind up deeply
        // recursing as we go.  So when we encounter the recursive reference
        // to List, we temporarily use TC_NONE as its contents.  Later we'll
        // patch up the cache with the correct value, once we've computed it
        // (this is basically a co-inductive process, if that helps).  So in
        // the end we'll compute TC_OWNED_POINTER, in this case.
        //
        // The problem is, as we are doing the computation, we will also
        // compute an *intermediate* contents for, e.g., Option<List> of
        // TC_NONE.  This is ok during the computation of List itself, but if
        // we stored this intermediate value into cx.tc_cache, then later
        // requests for the contents of Option<List> would also yield TC_NONE
        // which is incorrect.  This value was computed based on the crutch
        // value for the type contents of list.  The correct value is
        // TC_OWNED_POINTER.  This manifested as issue #4821.
        let ty_id = type_id(ty);
        match cache.find(&ty_id) {
            Some(tc) => { return *tc; }
            None => {}
        }
2036 2037 2038 2039
        match cx.tc_cache.find(&ty_id) {    // Must check both caches!
            Some(tc) => { return *tc; }
            None => {}
        }
2040 2041 2042 2043
        cache.insert(ty_id, TC_NONE);

        let _i = indenter();

2044
        let result = match get(ty).sty {
2045 2046 2047 2048 2049
            // Scalar and unique types are sendable, constant, and owned
            ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
            ty_bare_fn(_) | ty_ptr(_) => {
                TC_NONE
            }
2050

2051
            ty_estr(vstore_uniq) => {
2052
                TC_OWNED_VEC
2053
            }
M
Marijn Haverbeke 已提交
2054

2055 2056 2057
            ty_closure(ref c) => {
                closure_contents(c)
            }
2058

2059
            ty_box(mt) => {
2060
                TC_MANAGED + statically_sized(nonowned(tc_mt(cx, mt, cache)))
2061
            }
2062

2063
            ty_trait(_, _, UniqTraitStore, _, _bounds) => {
2064 2065
                TC_OWNED_CLOSURE
            }
2066

2067
            ty_trait(_, _, BoxTraitStore, mutbl, _bounds) => {
2068 2069 2070 2071
                match mutbl {
                    ast::m_mutbl => TC_MANAGED + TC_MUTABLE,
                    _ => TC_MANAGED
                }
2072
            }
2073

2074
            ty_trait(_, _, RegionTraitStore(r), mutbl, _bounds) => {
2075
                borrowed_contents(r, mutbl)
2076
            }
2077

2078 2079
            ty_rptr(r, mt) => {
                borrowed_contents(r, mt.mutbl) +
2080
                    statically_sized(nonowned(tc_mt(cx, mt, cache)))
2081
            }
2082

2083
            ty_uniq(mt) => {
2084
                TC_OWNED_POINTER + statically_sized(tc_mt(cx, mt, cache))
2085
            }
2086

2087
            ty_evec(mt, vstore_uniq) => {
2088
                TC_OWNED_VEC + statically_sized(tc_mt(cx, mt, cache))
2089
            }
2090

2091
            ty_evec(mt, vstore_box) => {
2092
                TC_MANAGED + statically_sized(nonowned(tc_mt(cx, mt, cache)))
2093
            }
2094

2095 2096
            ty_evec(mt, vstore_slice(r)) => {
                borrowed_contents(r, mt.mutbl) +
2097
                    statically_sized(nonowned(tc_mt(cx, mt, cache)))
2098
            }
2099

2100
            ty_evec(mt, vstore_fixed(_)) => {
2101 2102 2103 2104 2105 2106 2107 2108
                let contents = tc_mt(cx, mt, cache);
                // FIXME(#6308) Uncomment this when construction of such
                // vectors is prevented earlier in compilation.
                // if !contents.is_sized(cx) {
                //     cx.sess.bug("Fixed-length vector of unsized type \
                //                  should be impossible");
                // }
                contents
2109
            }
2110

2111 2112 2113
            ty_estr(vstore_box) => {
                TC_MANAGED
            }
2114

2115 2116 2117
            ty_estr(vstore_slice(r)) => {
                borrowed_contents(r, m_imm)
            }
2118

2119 2120 2121
            ty_estr(vstore_fixed(_)) => {
                TC_NONE
            }
2122

2123 2124
            ty_struct(did, ref substs) => {
                let flds = struct_fields(cx, did, substs);
2125
                let mut res = flds.iter().fold(
2126 2127 2128
                    TC_NONE,
                    |tc, f| tc + tc_mt(cx, f.mt, cache));
                if ty::has_dtor(cx, did) {
2129
                    res += TC_DTOR;
2130
                }
D
Daniel Micay 已提交
2131
                apply_tc_attr(cx, did, res)
2132
            }
2133

2134
            ty_tup(ref tys) => {
2135
                tys.iter().fold(TC_NONE, |tc, ty| tc + tc_ty(cx, *ty, cache))
2136
            }
2137

2138 2139
            ty_enum(did, ref substs) => {
                let variants = substd_enum_variants(cx, did, substs);
D
Daniel Micay 已提交
2140
                let res = if variants.is_empty() {
2141 2142 2143 2144
                    // we somewhat arbitrary declare that empty enums
                    // are non-copyable
                    TC_EMPTY_ENUM
                } else {
2145 2146 2147
                    variants.iter().fold(TC_NONE, |tc, variant| {
                        variant.args.iter().fold(tc,
                            |tc, arg_ty| tc + tc_ty(cx, *arg_ty, cache))
2148
                    })
2149
                };
D
Daniel Micay 已提交
2150
                apply_tc_attr(cx, did, res)
2151
            }
2152

2153 2154 2155 2156 2157 2158 2159
            ty_param(p) => {
                // We only ever ask for the kind of types that are defined in
                // the current crate; therefore, the only type parameters that
                // could be in scope are those defined in the current crate.
                // If this assertion failures, it is likely because of a
                // failure in the cross-crate inlining code to translate a
                // def-id.
2160
                assert_eq!(p.def_id.crate, ast::local_crate);
2161

2162 2163
                type_param_def_to_contents(
                    cx, cx.ty_param_defs.get(&p.def_id.node))
2164
            }
2165

2166
            ty_self(_) => {
2167 2168 2169 2170 2171 2172 2173
                // Currently, self is not bounded, so we must assume the
                // worst.  But in the future we should examine the super
                // traits.
                //
                // FIXME(#4678)---self should just be a ty param
                TC_ALL
            }
2174

2175 2176 2177 2178 2179 2180
            ty_infer(_) => {
                // This occurs during coherence, but shouldn't occur at other
                // times.
                TC_ALL
            }

2181
            ty_opaque_box => TC_MANAGED,
2182
            ty_unboxed_vec(mt) => TC_DYNAMIC_SIZE + tc_mt(cx, mt, cache),
2183 2184 2185 2186 2187 2188 2189 2190 2191 2192
            ty_opaque_closure_ptr(sigil) => {
                match sigil {
                    ast::BorrowedSigil => TC_BORROWED_POINTER,
                    ast::ManagedSigil => TC_MANAGED,
                    ast::OwnedSigil => TC_OWNED_CLOSURE
                }
            }

            ty_type => TC_NONE,

2193
            ty_err => {
2194
                cx.sess.bug("Asked to compute contents of fictitious type");
2195
            }
2196 2197 2198 2199 2200
        };

        cache.insert(ty_id, result);
        return result;
    }
2201

2202 2203
    fn tc_mt(cx: ctxt,
             mt: mt,
2204
             cache: &mut HashMap<uint, TypeContents>) -> TypeContents
2205 2206 2207 2208
    {
        let mc = if mt.mutbl == m_mutbl {TC_MUTABLE} else {TC_NONE};
        mc + tc_ty(cx, mt.ty, cache)
    }
2209

D
Daniel Micay 已提交
2210 2211 2212 2213 2214 2215 2216 2217 2218 2219
    fn apply_tc_attr(cx: ctxt, did: def_id, mut tc: TypeContents) -> TypeContents {
        if has_attr(cx, did, "mutable") {
            tc += TC_MUTABLE;
        }
        if has_attr(cx, did, "non_owned") {
            tc += TC_NON_OWNED;
        }
        tc
    }

2220 2221 2222 2223 2224
    fn borrowed_contents(region: ty::Region,
                         mutbl: ast::mutability) -> TypeContents
    {
        let mc = if mutbl == m_mutbl {
            TC_MUTABLE + TC_BORROWED_MUT
2225
        } else {
2226 2227 2228 2229 2230 2231 2232 2233 2234
            TC_NONE
        };
        let rc = if region != ty::re_static {
            TC_BORROWED_POINTER
        } else {
            TC_NONE
        };
        mc + rc
    }
2235

2236 2237 2238 2239 2240 2241 2242 2243
    fn nonowned(pointee: TypeContents) -> TypeContents {
        /*!
         *
         * Given a non-owning pointer to some type `T` with
         * contents `pointee` (like `@T` or
         * `&T`), returns the relevant bits that
         * apply to the owner of the pointer.
         */
2244

2245 2246
        let mask = TC_MUTABLE.bits | TC_BORROWED_POINTER.bits;
        TypeContents {bits: pointee.bits & mask}
2247 2248
    }

2249 2250 2251 2252 2253 2254 2255 2256
    fn statically_sized(pointee: TypeContents) -> TypeContents {
        /*!
         * If a dynamically-sized type is found behind a pointer, we should
         * restore the 'Sized' kind to the pointer and things that contain it.
         */
        TypeContents {bits: pointee.bits & !TC_DYNAMIC_SIZE.bits}
    }

2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270
    fn closure_contents(cty: &ClosureTy) -> TypeContents {
        let st = match cty.sigil {
            ast::BorrowedSigil => TC_BORROWED_POINTER,
            ast::ManagedSigil => TC_MANAGED,
            ast::OwnedSigil => TC_OWNED_CLOSURE
        };
        let rt = borrowed_contents(cty.region, m_imm);
        let ot = match cty.onceness {
            ast::Once => TC_ONCE_CLOSURE,
            ast::Many => TC_NONE
        };
        st + rt + ot
    }

2271 2272
    fn type_param_def_to_contents(cx: ctxt,
                                  type_param_def: &TypeParameterDef) -> TypeContents
2273
    {
2274
        debug!("type_param_def_to_contents(%s)", type_param_def.repr(cx));
2275 2276
        let _i = indenter();

2277 2278
        let mut tc = TC_ALL;
        for type_param_def.bounds.builtin_bounds.each |bound| {
2279
            debug!("tc = %s, bound = %?", tc.to_str(), bound);
2280
            tc = tc - match bound {
2281
                BoundCopy => TypeContents::noncopyable(cx),
2282 2283 2284
                BoundStatic => TypeContents::nonstatic(cx),
                BoundOwned => TypeContents::nonowned(cx),
                BoundConst => TypeContents::nonconst(cx),
2285 2286
                // The dynamic-size bit can be removed at pointer-level, etc.
                BoundSized => TypeContents::dynamically_sized(cx),
2287 2288
            };
        }
2289

2290 2291
        debug!("result = %s", tc.to_str());
        return tc;
2292
    }
2293 2294
}

2295 2296 2297 2298
pub fn type_moves_by_default(cx: ctxt, ty: t) -> bool {
    type_contents(cx, ty).moves_by_default(cx)
}

2299
// True if instantiating an instance of `r_ty` requires an instance of `r_ty`.
2300
pub fn is_instantiable(cx: ctxt, r_ty: t) -> bool {
2301
    fn type_requires(cx: ctxt, seen: &mut ~[def_id],
2302
                     r_ty: t, ty: t) -> bool {
P
Paul Stansifer 已提交
2303
        debug!("type_requires(%s, %s)?",
2304 2305
               ::util::ppaux::ty_to_str(cx, r_ty),
               ::util::ppaux::ty_to_str(cx, ty));
2306 2307

        let r = {
2308
            get(r_ty).sty == get(ty).sty ||
2309 2310 2311
                subtypes_require(cx, seen, r_ty, ty)
        };

P
Paul Stansifer 已提交
2312
        debug!("type_requires(%s, %s)? %b",
2313 2314
               ::util::ppaux::ty_to_str(cx, r_ty),
               ::util::ppaux::ty_to_str(cx, ty),
P
Paul Stansifer 已提交
2315
               r);
B
Brian Anderson 已提交
2316
        return r;
2317 2318
    }

2319
    fn subtypes_require(cx: ctxt, seen: &mut ~[def_id],
2320
                        r_ty: t, ty: t) -> bool {
P
Paul Stansifer 已提交
2321
        debug!("subtypes_require(%s, %s)?",
2322 2323
               ::util::ppaux::ty_to_str(cx, r_ty),
               ::util::ppaux::ty_to_str(cx, ty));
2324

2325
        let r = match get(ty).sty {
2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350
            ty_nil |
            ty_bot |
            ty_bool |
            ty_int(_) |
            ty_uint(_) |
            ty_float(_) |
            ty_estr(_) |
            ty_bare_fn(_) |
            ty_closure(_) |
            ty_infer(_) |
            ty_err |
            ty_param(_) |
            ty_self(_) |
            ty_type |
            ty_opaque_box |
            ty_opaque_closure_ptr(_) |
            ty_evec(_, _) |
            ty_unboxed_vec(_) => {
                false
            }
            ty_box(ref mt) |
            ty_uniq(ref mt) |
            ty_rptr(_, ref mt) => {
                type_requires(cx, seen, r_ty, mt.ty)
            }
2351

2352 2353 2354
            ty_ptr(*) => {
                false           // unsafe ptrs can always be NULL
            }
2355

2356
            ty_trait(_, _, _, _, _) => {
2357 2358
                false
            }
2359

2360 2361 2362
            ty_struct(ref did, _) if vec::contains(*seen, did) => {
                false
            }
2363

2364 2365 2366
            ty_struct(did, ref substs) => {
                seen.push(did);
                let fields = struct_fields(cx, did, substs);
2367
                let r = fields.iter().any_(|f| type_requires(cx, seen, r_ty, f.mt.ty));
2368 2369 2370
                seen.pop();
                r
            }
2371

2372
            ty_tup(ref ts) => {
2373
                ts.iter().any_(|t| type_requires(cx, seen, r_ty, *t))
2374
            }
2375

2376 2377 2378
            ty_enum(ref did, _) if vec::contains(*seen, did) => {
                false
            }
2379

2380 2381 2382
            ty_enum(did, ref substs) => {
                seen.push(did);
                let vs = enum_variants(cx, did);
2383
                let r = !vs.is_empty() && do vs.iter().all |variant| {
2384
                    do variant.args.iter().any_ |aty| {
N
Niko Matsakis 已提交
2385
                        let sty = subst(cx, substs, *aty);
2386
                        type_requires(cx, seen, r_ty, sty)
2387 2388
                    }
                };
N
Niko Matsakis 已提交
2389
                seen.pop();
2390 2391
                r
            }
2392 2393
        };

P
Paul Stansifer 已提交
2394
        debug!("subtypes_require(%s, %s)? %b",
2395 2396
               ::util::ppaux::ty_to_str(cx, r_ty),
               ::util::ppaux::ty_to_str(cx, ty),
P
Paul Stansifer 已提交
2397
               r);
2398

B
Brian Anderson 已提交
2399
        return r;
2400 2401
    }

2402 2403
    let mut seen = ~[];
    !subtypes_require(cx, &mut seen, r_ty, r_ty)
2404 2405
}

2406 2407
pub fn type_structurally_contains(cx: ctxt,
                                  ty: t,
2408
                                  test: &fn(x: &sty) -> bool)
2409
                               -> bool {
2410
    let sty = &get(ty).sty;
2411 2412
    debug!("type_structurally_contains: %s",
           ::util::ppaux::ty_to_str(cx, ty));
B
Brian Anderson 已提交
2413
    if test(sty) { return true; }
2414
    match *sty {
N
Niko Matsakis 已提交
2415
      ty_enum(did, ref substs) => {
2416 2417
        for (*enum_variants(cx, did)).iter().advance |variant| {
            for variant.args.iter().advance |aty| {
2418
                let sty = subst(cx, substs, *aty);
B
Brian Anderson 已提交
2419
                if type_structurally_contains(cx, sty, test) { return true; }
2420
            }
2421
        }
B
Brian Anderson 已提交
2422
        return false;
M
Marijn Haverbeke 已提交
2423
      }
2424
      ty_struct(did, ref substs) => {
2425 2426
        let r = lookup_struct_fields(cx, did);
        for r.iter().advance |field| {
2427
            let ft = lookup_field_type(cx, did, field.id, substs);
B
Brian Anderson 已提交
2428
            if type_structurally_contains(cx, ft, test) { return true; }
2429
        }
B
Brian Anderson 已提交
2430
        return false;
2431 2432
      }

2433
      ty_tup(ref ts) => {
2434
        for ts.iter().advance |tt| {
2435
            if type_structurally_contains(cx, *tt, test) { return true; }
2436
        }
B
Brian Anderson 已提交
2437
        return false;
2438
      }
2439
      ty_evec(ref mt, vstore_fixed(_)) => {
B
Brian Anderson 已提交
2440
        return type_structurally_contains(cx, mt.ty, test);
2441
      }
B
Brian Anderson 已提交
2442
      _ => return false
M
Marijn Haverbeke 已提交
2443 2444 2445
    }
}

2446
pub fn type_structurally_contains_uniques(cx: ctxt, ty: t) -> bool {
B
Brian Anderson 已提交
2447
    return type_structurally_contains(cx, ty, |sty| {
N
Niko Matsakis 已提交
2448
        match *sty {
2449 2450
          ty_uniq(_) |
          ty_evec(_, vstore_uniq) |
B
Brian Anderson 已提交
2451 2452
          ty_estr(vstore_uniq) => true,
          _ => false,
2453
        }
2454
    });
2455 2456
}

2457
pub fn type_is_integral(ty: t) -> bool {
2458
    match get(ty).sty {
2459
      ty_infer(IntVar(_)) | ty_int(_) | ty_uint(_) => true,
B
Brian Anderson 已提交
2460
      _ => false
M
Marijn Haverbeke 已提交
2461 2462 2463
    }
}

2464
pub fn type_is_char(ty: t) -> bool {
2465 2466 2467 2468 2469 2470
    match get(ty).sty {
        ty_int(ty_char) => true,
        _ => false
    }
}

2471
pub fn type_is_fp(ty: t) -> bool {
2472
    match get(ty).sty {
2473
      ty_infer(FloatVar(_)) | ty_float(_) => true,
B
Brian Anderson 已提交
2474
      _ => false
M
Marijn Haverbeke 已提交
2475 2476 2477
    }
}

2478
pub fn type_is_numeric(ty: t) -> bool {
B
Brian Anderson 已提交
2479
    return type_is_integral(ty) || type_is_fp(ty);
2480 2481
}

2482
pub fn type_is_signed(ty: t) -> bool {
2483
    match get(ty).sty {
B
Brian Anderson 已提交
2484 2485
      ty_int(_) => true,
      _ => false
M
Marijn Haverbeke 已提交
2486 2487 2488
    }
}

S
Seo Sanghyeon 已提交
2489 2490 2491 2492 2493 2494 2495 2496
pub fn type_is_machine(ty: t) -> bool {
    match get(ty).sty {
        ty_int(ast::ty_i) | ty_uint(ast::ty_u) | ty_float(ast::ty_f) => false,
        ty_int(*) | ty_uint(*) | ty_float(*) => true,
        _ => false
    }
}

2497 2498
// Whether a type is Plain Old Data -- meaning it does not contain pointers
// that the cycle collector might care about.
2499
pub fn type_is_pod(cx: ctxt, ty: t) -> bool {
2500
    let mut result = true;
2501
    match get(ty).sty {
B
Brian Anderson 已提交
2502
      // Scalar types
2503
      ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) |
2504
      ty_type | ty_ptr(_) | ty_bare_fn(_) => result = true,
B
Brian Anderson 已提交
2505
      // Boxed types
2506
      ty_box(_) | ty_uniq(_) | ty_closure(_) |
2507 2508
      ty_estr(vstore_uniq) | ty_estr(vstore_box) |
      ty_evec(_, vstore_uniq) | ty_evec(_, vstore_box) |
2509
      ty_trait(_, _, _, _, _) | ty_rptr(_,_) | ty_opaque_box => result = false,
B
Brian Anderson 已提交
2510
      // Structural types
N
Niko Matsakis 已提交
2511
      ty_enum(did, ref substs) => {
2512
        let variants = enum_variants(cx, did);
2513
        for (*variants).iter().advance |variant| {
2514
            let tup_ty = mk_tup(cx, /*bad*/copy variant.args);
B
Brian Anderson 已提交
2515 2516

            // Perform any type parameter substitutions.
2517
            let tup_ty = subst(cx, substs, tup_ty);
B
Brian Anderson 已提交
2518
            if !type_is_pod(cx, tup_ty) { result = false; }
2519
        }
B
Brian Anderson 已提交
2520
      }
2521
      ty_tup(ref elts) => {
2522
        for elts.iter().advance |elt| { if !type_is_pod(cx, *elt) { result = false; } }
B
Brian Anderson 已提交
2523
      }
B
Brian Anderson 已提交
2524
      ty_estr(vstore_fixed(_)) => result = true,
2525
      ty_evec(ref mt, vstore_fixed(_)) | ty_unboxed_vec(ref mt) => {
2526 2527
        result = type_is_pod(cx, mt.ty);
      }
B
Brian Anderson 已提交
2528 2529
      ty_param(_) => result = false,
      ty_opaque_closure_ptr(_) => result = true,
2530
      ty_struct(did, ref substs) => {
2531 2532
        let fields = lookup_struct_fields(cx, did);
        result = do fields.iter().all |f| {
2533 2534 2535
            let fty = ty::lookup_item_type(cx, f.id);
            let sty = subst(cx, substs, fty.ty);
            type_is_pod(cx, sty)
2536
        };
2537
      }
2538

B
Brian Anderson 已提交
2539
      ty_estr(vstore_slice(*)) | ty_evec(_, vstore_slice(*)) => {
2540 2541 2542
        result = false;
      }

2543
      ty_infer(*) | ty_self(*) | ty_err => {
2544
        cx.sess.bug("non concrete type in type_is_pod");
2545
      }
P
Patrick Walton 已提交
2546 2547
    }

B
Brian Anderson 已提交
2548
    return result;
P
Patrick Walton 已提交
2549 2550
}

2551
pub fn type_is_enum(ty: t) -> bool {
2552
    match get(ty).sty {
B
Brian Anderson 已提交
2553 2554
      ty_enum(_, _) => return true,
      _ => return false
2555 2556 2557
    }
}

2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572
// Is the type's representation size known at compile time?
pub fn type_is_sized(cx: ctxt, ty: ty::t) -> bool {
    match get(ty).sty {
        // FIXME(#6308) add trait, vec, str, etc here.
        ty_param(p) => {
            let param_def = cx.ty_param_defs.get(&p.def_id.node);
            if param_def.bounds.builtin_bounds.contains_elem(BoundSized) {
                return true;
            }
            return false;
        },
        _ => return true,
    }
}

P
Patrick Walton 已提交
2573
// Whether a type is enum like, that is a enum type with only nullary
2574
// constructors
2575
pub fn type_is_c_like_enum(cx: ctxt, ty: t) -> bool {
2576
    match get(ty).sty {
2577 2578 2579 2580 2581
        ty_enum(did, _) => {
            let variants = enum_variants(cx, did);
            if variants.len() == 0 {
                false
            } else {
2582
                variants.iter().all(|v| v.args.len() == 0)
2583 2584 2585
            }
        }
        _ => false
2586 2587 2588
    }
}

2589
pub fn type_param(ty: t) -> Option<uint> {
2590
    match get(ty).sty {
B
Brian Anderson 已提交
2591
      ty_param(p) => return Some(p.idx),
B
Brian Anderson 已提交
2592
      _ => {/* fall through */ }
2593
    }
B
Brian Anderson 已提交
2594
    return None;
2595 2596
}

2597 2598
// Returns the type and mutability of *t.
//
2599 2600
// The parameter `explicit` indicates if this is an *explicit* dereference.
// Some types---notably unsafe ptrs---can only be dereferenced explicitly.
2601
pub fn deref(cx: ctxt, t: t, explicit: bool) -> Option<mt> {
2602
    deref_sty(cx, &get(t).sty, explicit)
2603
}
2604

2605
pub fn deref_sty(cx: ctxt, sty: &sty, explicit: bool) -> Option<mt> {
N
Niko Matsakis 已提交
2606
    match *sty {
B
Brian Anderson 已提交
2607
      ty_rptr(_, mt) | ty_box(mt) | ty_uniq(mt) => {
B
Brian Anderson 已提交
2608
        Some(mt)
2609 2610
      }

2611
      ty_ptr(mt) if explicit => {
B
Brian Anderson 已提交
2612
        Some(mt)
2613 2614
      }

N
Niko Matsakis 已提交
2615
      ty_enum(did, ref substs) => {
2616
        let variants = enum_variants(cx, did);
Y
Youngmin Yoo 已提交
2617
        if (*variants).len() == 1u && variants[0].args.len() == 1u {
2618
            let v_t = subst(cx, substs, variants[0].args[0]);
2619
            Some(mt {ty: v_t, mutbl: ast::m_imm})
2620
        } else {
B
Brian Anderson 已提交
2621
            None
2622 2623 2624
        }
      }

2625 2626
      ty_struct(did, ref substs) => {
        let fields = struct_fields(cx, did, substs);
2627 2628
        if fields.len() == 1 && fields[0].ident ==
                syntax::parse::token::special_idents::unnamed_field {
2629
            Some(mt {ty: fields[0].mt.ty, mutbl: ast::m_imm})
2630 2631 2632 2633 2634
        } else {
            None
        }
      }

B
Brian Anderson 已提交
2635
      _ => None
2636 2637 2638
    }
}

2639
pub fn type_autoderef(cx: ctxt, t: t) -> t {
2640
    let mut t = t;
2641
    loop {
2642
        match deref(cx, t, false) {
B
Brian Anderson 已提交
2643 2644
          None => return t,
          Some(mt) => t = mt.ty
2645 2646
        }
    }
2647 2648 2649
}

// Returns the type and mutability of t[i]
T
Tim Chevalier 已提交
2650 2651
pub fn index(t: t) -> Option<mt> {
    index_sty(&get(t).sty)
2652 2653
}

T
Tim Chevalier 已提交
2654
pub fn index_sty(sty: &sty) -> Option<mt> {
N
Niko Matsakis 已提交
2655
    match *sty {
B
Brian Anderson 已提交
2656
      ty_evec(mt, _) => Some(mt),
T
Tim Chevalier 已提交
2657
      ty_estr(_) => Some(mt {ty: mk_u8(), mutbl: ast::m_imm}),
B
Brian Anderson 已提交
2658
      _ => None
2659
    }
2660 2661
}

2662 2663 2664 2665 2666 2667 2668 2669 2670 2671
/**
 * Enforces an arbitrary but consistent total ordering over
 * free regions.  This is needed for establishing a consistent
 * LUB in region_inference. */
impl cmp::TotalOrd for FreeRegion {
    fn cmp(&self, other: &FreeRegion) -> Ordering {
        cmp::cmp2(&self.scope_id, &self.bound_region,
                  &other.scope_id, &other.bound_region)
    }
}
2672

2673 2674 2675 2676 2677
impl cmp::TotalEq for FreeRegion {
    fn equals(&self, other: &FreeRegion) -> bool {
        *self == *other
    }
}
2678

2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691
/**
 * Enforces an arbitrary but consistent total ordering over
 * bound regions.  This is needed for establishing a consistent
 * LUB in region_inference. */
impl cmp::TotalOrd for bound_region {
    fn cmp(&self, other: &bound_region) -> Ordering {
        match (self, other) {
            (&ty::br_self, &ty::br_self) => cmp::Equal,
            (&ty::br_self, _) => cmp::Less,

            (&ty::br_anon(ref a1), &ty::br_anon(ref a2)) => a1.cmp(a2),
            (&ty::br_anon(*), _) => cmp::Less,

J
John Clements 已提交
2692
            (&ty::br_named(ref a1), &ty::br_named(ref a2)) => a1.name.cmp(&a2.name),
2693 2694 2695 2696 2697 2698 2699 2700
            (&ty::br_named(*), _) => cmp::Less,

            (&ty::br_cap_avoid(ref a1, @ref b1),
             &ty::br_cap_avoid(ref a2, @ref b2)) => cmp::cmp2(a1, b1, a2, b2),
            (&ty::br_cap_avoid(*), _) => cmp::Less,

            (&ty::br_fresh(ref a1), &ty::br_fresh(ref a2)) => a1.cmp(a2),
            (&ty::br_fresh(*), _) => cmp::Less,
2701 2702 2703
        }
    }
}
2704

2705 2706 2707
impl cmp::TotalEq for bound_region {
    fn equals(&self, other: &bound_region) -> bool {
        *self == *other
2708 2709 2710
    }
}

2711 2712 2713
impl to_bytes::IterBytes for vstore {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
        match *self {
2714 2715 2716 2717 2718
            vstore_fixed(ref u) => {
                0u8.iter_bytes(lsb0, f) && u.iter_bytes(lsb0, f)
            }
            vstore_uniq => 1u8.iter_bytes(lsb0, f),
            vstore_box => 2u8.iter_bytes(lsb0, f),
2719

2720 2721 2722
            vstore_slice(ref r) => {
                3u8.iter_bytes(lsb0, f) && r.iter_bytes(lsb0, f)
            }
2723 2724 2725 2726 2727 2728
        }
    }
}

impl to_bytes::IterBytes for substs {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
2729 2730 2731
        self.self_r.iter_bytes(lsb0, f) &&
        self.self_ty.iter_bytes(lsb0, f) &&
        self.tps.iter_bytes(lsb0, f)
2732 2733
    }
}
2734

2735 2736
impl to_bytes::IterBytes for mt {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
2737
        self.ty.iter_bytes(lsb0, f) && self.mutbl.iter_bytes(lsb0, f)
2738 2739
    }
}
2740

2741 2742
impl to_bytes::IterBytes for field {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
2743
        self.ident.iter_bytes(lsb0, f) && self.mt.iter_bytes(lsb0, f)
2744 2745
    }
}
2746

2747 2748
impl to_bytes::IterBytes for FnSig {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
2749
        self.inputs.iter_bytes(lsb0, f) && self.output.iter_bytes(lsb0, f)
2750 2751
    }
}
2752

2753 2754 2755
impl to_bytes::IterBytes for sty {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
        match *self {
2756 2757
            ty_nil => 0u8.iter_bytes(lsb0, f),
            ty_bool => 1u8.iter_bytes(lsb0, f),
2758

2759
            ty_int(ref t) => 2u8.iter_bytes(lsb0, f) && t.iter_bytes(lsb0, f),
2760

2761
            ty_uint(ref t) => 3u8.iter_bytes(lsb0, f) && t.iter_bytes(lsb0, f),
2762

2763
            ty_float(ref t) => 4u8.iter_bytes(lsb0, f) && t.iter_bytes(lsb0, f),
2764

2765
            ty_estr(ref v) => 5u8.iter_bytes(lsb0, f) && v.iter_bytes(lsb0, f),
2766

2767 2768 2769 2770 2771
            ty_enum(ref did, ref substs) => {
                6u8.iter_bytes(lsb0, f) &&
                did.iter_bytes(lsb0, f) &&
                substs.iter_bytes(lsb0, f)
            }
2772

2773
            ty_box(ref mt) => 7u8.iter_bytes(lsb0, f) && mt.iter_bytes(lsb0, f),
2774

2775 2776 2777 2778 2779
            ty_evec(ref mt, ref v) => {
                8u8.iter_bytes(lsb0, f) &&
                mt.iter_bytes(lsb0, f) &&
                v.iter_bytes(lsb0, f)
            }
2780

2781
            ty_unboxed_vec(ref mt) => 9u8.iter_bytes(lsb0, f) && mt.iter_bytes(lsb0, f),
2782

2783
            ty_tup(ref ts) => 10u8.iter_bytes(lsb0, f) && ts.iter_bytes(lsb0, f),
2784

2785
            ty_bare_fn(ref ft) => 12u8.iter_bytes(lsb0, f) && ft.iter_bytes(lsb0, f),
2786

2787
            ty_self(ref did) => 13u8.iter_bytes(lsb0, f) && did.iter_bytes(lsb0, f),
2788

2789
            ty_infer(ref v) => 14u8.iter_bytes(lsb0, f) && v.iter_bytes(lsb0, f),
2790

2791
            ty_param(ref p) => 15u8.iter_bytes(lsb0, f) && p.iter_bytes(lsb0, f),
2792

2793 2794
            ty_type => 16u8.iter_bytes(lsb0, f),
            ty_bot => 17u8.iter_bytes(lsb0, f),
2795

2796
            ty_ptr(ref mt) => 18u8.iter_bytes(lsb0, f) && mt.iter_bytes(lsb0, f),
2797

2798
            ty_uniq(ref mt) => 19u8.iter_bytes(lsb0, f) && mt.iter_bytes(lsb0, f),
2799

2800
            ty_trait(ref did, ref substs, ref v, ref mutbl, bounds) => {
2801 2802 2803 2804
                20u8.iter_bytes(lsb0, f) &&
                did.iter_bytes(lsb0, f) &&
                substs.iter_bytes(lsb0, f) &&
                v.iter_bytes(lsb0, f) &&
2805 2806
                mutbl.iter_bytes(lsb0, f) &&
                bounds.iter_bytes(lsb0, f)
2807
            }
2808

2809
            ty_opaque_closure_ptr(ref ck) => 21u8.iter_bytes(lsb0, f) && ck.iter_bytes(lsb0, f),
2810

2811
            ty_opaque_box => 22u8.iter_bytes(lsb0, f),
2812

2813 2814 2815
            ty_struct(ref did, ref substs) => {
                23u8.iter_bytes(lsb0, f) && did.iter_bytes(lsb0, f) && substs.iter_bytes(lsb0, f)
            }
2816

2817 2818 2819
            ty_rptr(ref r, ref mt) => {
                24u8.iter_bytes(lsb0, f) && r.iter_bytes(lsb0, f) && mt.iter_bytes(lsb0, f)
            }
2820

2821
            ty_err => 25u8.iter_bytes(lsb0, f),
2822

2823
            ty_closure(ref ct) => 26u8.iter_bytes(lsb0, f) && ct.iter_bytes(lsb0, f),
2824 2825 2826
        }
    }
}
2827

2828 2829 2830 2831 2832 2833
pub fn node_id_to_trait_ref(cx: ctxt, id: ast::node_id) -> @ty::TraitRef {
    match cx.trait_refs.find(&id) {
       Some(&t) => t,
       None => cx.sess.bug(
           fmt!("node_id_to_trait_ref: no trait ref for node `%s`",
                ast_map::node_id_to_str(cx.items, id,
J
John Clements 已提交
2834
                                        token::get_ident_interner())))
2835 2836 2837
    }
}

2838
pub fn node_id_to_type(cx: ctxt, id: ast::node_id) -> t {
2839
    //io::println(fmt!("%?/%?", id, cx.node_types.len()));
D
Daniel Micay 已提交
2840 2841
    match cx.node_types.find(&(id as uint)) {
       Some(&t) => t,
B
Brian Anderson 已提交
2842
       None => cx.sess.bug(
2843
           fmt!("node_id_to_type: no type for node `%s`",
P
Paul Stansifer 已提交
2844
                ast_map::node_id_to_str(cx.items, id,
J
John Clements 已提交
2845
                                        token::get_ident_interner())))
T
Tim Chevalier 已提交
2846
    }
2847 2848
}

2849
pub fn node_id_to_type_params(cx: ctxt, id: ast::node_id) -> ~[t] {
2850
    match cx.node_type_substs.find(&id) {
B
Brian Anderson 已提交
2851
      None => return ~[],
2852
      Some(ts) => return /*bad*/ copy *ts
2853 2854 2855
    }
}

2856
fn node_id_has_type_params(cx: ctxt, id: ast::node_id) -> bool {
2857
    cx.node_type_substs.contains_key(&id)
2858 2859
}

2860 2861 2862 2863 2864
pub fn ty_fn_sig(fty: t) -> FnSig {
    match get(fty).sty {
        ty_bare_fn(ref f) => copy f.sig,
        ty_closure(ref f) => copy f.sig,
        ref s => {
2865
            fail!("ty_fn_sig() called on non-fn type: %?", s)
2866 2867 2868 2869
        }
    }
}

2870
// Type accessors for substructures of types
E
Erick Tryzelaar 已提交
2871
pub fn ty_fn_args(fty: t) -> ~[t] {
2872
    match get(fty).sty {
2873 2874 2875
        ty_bare_fn(ref f) => copy f.sig.inputs,
        ty_closure(ref f) => copy f.sig.inputs,
        ref s => {
2876
            fail!("ty_fn_args() called on non-fn type: %?", s)
2877
        }
2878 2879 2880
    }
}

2881
pub fn ty_closure_sigil(fty: t) -> Sigil {
2882
    match get(fty).sty {
2883 2884
        ty_closure(ref f) => f.sigil,
        ref s => {
2885
            fail!("ty_closure_sigil() called on non-closure type: %?", s)
2886
        }
M
Marijn Haverbeke 已提交
2887
    }
G
Graydon Hoare 已提交
2888 2889
}

2890
pub fn ty_fn_purity(fty: t) -> ast::purity {
2891
    match get(fty).sty {
2892 2893 2894
        ty_bare_fn(ref f) => f.purity,
        ty_closure(ref f) => f.purity,
        ref s => {
2895
            fail!("ty_fn_purity() called on non-fn type: %?", s)
2896
        }
2897 2898 2899
    }
}

2900
pub fn ty_fn_ret(fty: t) -> t {
2901
    match get(fty).sty {
2902 2903 2904
        ty_bare_fn(ref f) => f.sig.output,
        ty_closure(ref f) => f.sig.output,
        ref s => {
2905
            fail!("ty_fn_ret() called on non-fn type: %?", s)
2906
        }
2907
    }
G
Graydon Hoare 已提交
2908 2909
}

2910
pub fn is_fn_ty(fty: t) -> bool {
2911
    match get(fty).sty {
2912 2913 2914
        ty_bare_fn(_) => true,
        ty_closure(_) => true,
        _ => false
2915 2916 2917
    }
}

2918
pub fn ty_vstore(ty: t) -> vstore {
2919 2920 2921
    match get(ty).sty {
        ty_evec(_, vstore) => vstore,
        ty_estr(vstore) => vstore,
2922
        ref s => fail!("ty_vstore() called on invalid sty: %?", s)
2923 2924 2925
    }
}

2926 2927 2928
pub fn ty_region(tcx: ctxt,
                 span: span,
                 ty: t) -> Region {
2929
    match get(ty).sty {
2930 2931 2932 2933 2934 2935 2936 2937
        ty_rptr(r, _) => r,
        ty_evec(_, vstore_slice(r)) => r,
        ty_estr(vstore_slice(r)) => r,
        ref s => {
            tcx.sess.span_bug(
                span,
                fmt!("ty_region() invoked on in appropriate ty: %?", s));
        }
2938
    }
G
Graydon Hoare 已提交
2939 2940
}

N
Niko Matsakis 已提交
2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951
pub fn replace_fn_sig(cx: ctxt, fsty: &sty, new_sig: FnSig) -> t {
    match *fsty {
        ty_bare_fn(ref f) => mk_bare_fn(cx, BareFnTy {sig: new_sig, ..*f}),
        ty_closure(ref f) => mk_closure(cx, ClosureTy {sig: new_sig, ..*f}),
        ref s => {
            cx.sess.bug(
                fmt!("ty_fn_sig() called on non-fn type: %?", s));
        }
    }
}

2952
pub fn replace_closure_return_type(tcx: ctxt, fn_type: t, ret_type: t) -> t {
2953 2954 2955 2956 2957 2958
    /*!
     *
     * Returns a new function type based on `fn_type` but returning a value of
     * type `ret_type` instead. */

    match ty::get(fn_type).sty {
2959 2960 2961 2962
        ty::ty_closure(ref fty) => {
            ty::mk_closure(tcx, ClosureTy {
                sig: FnSig {output: ret_type, ..copy fty.sig},
                ..copy *fty
2963 2964 2965 2966 2967 2968 2969 2970 2971 2972
            })
        }
        _ => {
            tcx.sess.bug(fmt!(
                "replace_fn_ret() invoked with non-fn-type: %s",
                ty_to_str(tcx, fn_type)));
        }
    }
}

2973
// Returns a vec of all the input and output types of fty.
2974
pub fn tys_in_fn_sig(sig: &FnSig) -> ~[t] {
E
Erick Tryzelaar 已提交
2975
    vec::append_one(sig.inputs.map(|a| *a), sig.output)
2976 2977
}

2978
// Type accessors for AST nodes
2979
pub fn block_ty(cx: ctxt, b: &ast::blk) -> t {
B
Brian Anderson 已提交
2980
    return node_id_to_type(cx, b.node.id);
2981
}
2982 2983


2984 2985
// Returns the type of a pattern as a monotype. Like @expr_ty, this function
// doesn't provide type parameter substitutions.
2986
pub fn pat_ty(cx: ctxt, pat: @ast::pat) -> t {
B
Brian Anderson 已提交
2987
    return node_id_to_type(cx, pat.id);
2988 2989
}

2990

2991 2992
// Returns the type of an expression as a monotype.
//
2993 2994 2995 2996 2997 2998
// NB (1): This is the PRE-ADJUSTMENT TYPE for the expression.  That is, in
// some cases, we insert `AutoAdjustment` annotations such as auto-deref or
// auto-ref.  The type returned by this function does not consider such
// adjustments.  See `expr_ty_adjusted()` instead.
//
// NB (2): This type doesn't provide type parameter substitutions; e.g. if you
2999
// ask for the type of "id" in "id(3)", it will return "fn(&int) -> int"
3000
// instead of "fn(t) -> T with T = int". If this isn't what you want, see
3001
// expr_ty_params_and_ty() below.
3002
pub fn expr_ty(cx: ctxt, expr: @ast::expr) -> t {
B
Brian Anderson 已提交
3003
    return node_id_to_type(cx, expr.id);
3004 3005
}

3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020
pub fn expr_ty_adjusted(cx: ctxt, expr: @ast::expr) -> t {
    /*!
     *
     * Returns the type of `expr`, considering any `AutoAdjustment`
     * entry recorded for that expression.
     *
     * It would almost certainly be better to store the adjusted ty in with
     * the `AutoAdjustment`, but I opted not to do this because it would
     * require serializing and deserializing the type and, although that's not
     * hard to do, I just hate that code so much I didn't want to touch it
     * unless it was to fix it properly, which seemed a distraction from the
     * task at hand! -nmatsakis
     */

    let unadjusted_ty = expr_ty(cx, expr);
3021
    adjust_ty(cx, expr.span, unadjusted_ty, cx.adjustments.find_copy(&expr.id))
3022 3023 3024 3025 3026
}

pub fn adjust_ty(cx: ctxt,
                 span: span,
                 unadjusted_ty: ty::t,
3027
                 adjustment: Option<@AutoAdjustment>) -> ty::t
3028 3029
{
    /*! See `expr_ty_adjusted` */
3030

3031
    return match adjustment {
3032 3033
        None => unadjusted_ty,

3034
        Some(@AutoAddEnv(r, s)) => {
3035 3036 3037 3038 3039 3040 3041 3042
            match ty::get(unadjusted_ty).sty {
                ty::ty_bare_fn(ref b) => {
                    ty::mk_closure(
                        cx,
                        ty::ClosureTy {purity: b.purity,
                                       sigil: s,
                                       onceness: ast::Many,
                                       region: r,
3043
                                       bounds: ty::AllBuiltinBounds(),
3044 3045 3046 3047 3048 3049 3050 3051 3052
                                       sig: copy b.sig})
                }
                ref b => {
                    cx.sess.bug(
                        fmt!("add_env adjustment on non-bare-fn: %?", b));
                }
            }
        }

3053
        Some(@AutoDerefRef(ref adj)) => {
3054 3055
            let mut adjusted_ty = unadjusted_ty;

3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066
            if (!ty::type_is_error(adjusted_ty)) {
                for uint::range(0, adj.autoderefs) |i| {
                    match ty::deref(cx, adjusted_ty, true) {
                        Some(mt) => { adjusted_ty = mt.ty; }
                        None => {
                            cx.sess.span_bug(
                                span,
                                fmt!("The %uth autoderef failed: %s",
                                     i, ty_to_str(cx,
                                                  adjusted_ty)));
                        }
3067 3068 3069 3070 3071 3072 3073
                    }
                }
            }

            match adj.autoref {
                None => adjusted_ty,
                Some(ref autoref) => {
N
Niko Matsakis 已提交
3074 3075 3076
                    match *autoref {
                        AutoPtr(r, m) => {
                            mk_rptr(cx, r, mt {ty: adjusted_ty, mutbl: m})
3077 3078
                        }

N
Niko Matsakis 已提交
3079 3080
                        AutoBorrowVec(r, m) => {
                            borrow_vec(cx, span, r, m, adjusted_ty)
3081 3082
                        }

N
Niko Matsakis 已提交
3083 3084 3085
                        AutoBorrowVecRef(r, m) => {
                            adjusted_ty = borrow_vec(cx, span, r, m, adjusted_ty);
                            mk_rptr(cx, r, mt {ty: adjusted_ty, mutbl: ast::m_imm})
3086 3087
                        }

N
Niko Matsakis 已提交
3088 3089 3090 3091 3092 3093
                        AutoBorrowFn(r) => {
                            borrow_fn(cx, span, r, adjusted_ty)
                        }

                        AutoUnsafe(m) => {
                            mk_ptr(cx, mt {ty: adjusted_ty, mutbl: m})
3094 3095 3096 3097 3098 3099 3100
                        }
                    }
                }
            }
        }
    };

3101
    fn borrow_vec(cx: ctxt, span: span,
N
Niko Matsakis 已提交
3102 3103
                  r: Region, m: ast::mutability,
                  ty: ty::t) -> ty::t {
3104 3105
        match get(ty).sty {
            ty_evec(mt, _) => {
N
Niko Matsakis 已提交
3106
                ty::mk_evec(cx, mt {ty: mt.ty, mutbl: m}, vstore_slice(r))
3107 3108 3109
            }

            ty_estr(_) => {
N
Niko Matsakis 已提交
3110
                ty::mk_estr(cx, vstore_slice(r))
3111 3112 3113 3114
            }

            ref s => {
                cx.sess.span_bug(
3115
                    span,
3116 3117 3118 3119 3120 3121
                    fmt!("borrow-vec associated with bad sty: %?",
                         s));
            }
        }
    }

N
Niko Matsakis 已提交
3122
    fn borrow_fn(cx: ctxt, span: span, r: Region, ty: ty::t) -> ty::t {
3123
        match get(ty).sty {
3124 3125 3126
            ty_closure(ref fty) => {
                ty::mk_closure(cx, ClosureTy {
                    sigil: BorrowedSigil,
N
Niko Matsakis 已提交
3127
                    region: r,
3128 3129
                    ..copy *fty
                })
3130 3131 3132 3133
            }

            ref s => {
                cx.sess.span_bug(
3134
                    span,
3135 3136 3137 3138 3139 3140 3141
                    fmt!("borrow-fn associated with bad sty: %?",
                         s));
            }
        }
    }
}

3142 3143
impl AutoRef {
    pub fn map_region(&self, f: &fn(Region) -> Region) -> AutoRef {
N
Niko Matsakis 已提交
3144 3145 3146 3147 3148 3149 3150 3151 3152 3153
        match *self {
            ty::AutoPtr(r, m) => ty::AutoPtr(f(r), m),
            ty::AutoBorrowVec(r, m) => ty::AutoBorrowVec(f(r), m),
            ty::AutoBorrowVecRef(r, m) => ty::AutoBorrowVecRef(f(r), m),
            ty::AutoBorrowFn(r) => ty::AutoBorrowFn(f(r)),
            ty::AutoUnsafe(m) => ty::AutoUnsafe(m),
        }
    }
}

3154 3155 3156 3157 3158
pub struct ParamsTy {
    params: ~[t],
    ty: t
}

3159 3160
pub fn expr_ty_params_and_ty(cx: ctxt,
                             expr: @ast::expr)
3161 3162 3163 3164 3165
                          -> ParamsTy {
    ParamsTy {
        params: node_id_to_type_params(cx, expr.id),
        ty: node_id_to_type(cx, expr.id)
    }
3166 3167
}

3168
pub fn expr_has_ty_params(cx: ctxt, expr: @ast::expr) -> bool {
B
Brian Anderson 已提交
3169
    return node_id_has_type_params(cx, expr.id);
3170 3171
}

3172 3173 3174 3175 3176
pub fn method_call_type_param_defs(
    tcx: ctxt,
    method_map: typeck::method_map,
    id: ast::node_id) -> Option<@~[TypeParameterDef]>
{
3177
    do method_map.find(&id).map |method| {
3178 3179
        match method.origin {
          typeck::method_static(did) => {
3180 3181
            // n.b.: When we encode impl methods, the bounds
            // that we encode include both the impl bounds
3182
            // and then the method bounds themselves...
3183
            ty::lookup_item_type(tcx, did).generics.type_param_defs
3184
          }
3185 3186 3187
          typeck::method_param(typeck::method_param {
              trait_id: trt_id,
              method_num: n_mth, _}) |
3188
          typeck::method_trait(trt_id, n_mth, _) |
3189 3190
          typeck::method_self(trt_id, n_mth) |
          typeck::method_super(trt_id, n_mth) => {
3191 3192 3193
            // ...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.
3194 3195 3196 3197 3198
            let trait_type_param_defs =
                ty::lookup_trait_def(tcx, trt_id).generics.type_param_defs;
            @vec::append(
                copy *trait_type_param_defs,
                *ty::trait_method(tcx, trt_id, n_mth).generics.type_param_defs)
3199 3200 3201 3202 3203
          }
        }
    }
}

3204
pub fn resolve_expr(tcx: ctxt, expr: @ast::expr) -> ast::def {
3205
    match tcx.def_map.find(&expr.id) {
3206
        Some(&def) => def,
3207 3208 3209 3210 3211 3212 3213
        None => {
            tcx.sess.span_bug(expr.span, fmt!(
                "No def-map entry for expr %?", expr.id));
        }
    }
}

3214 3215 3216
pub fn expr_is_lval(tcx: ctxt,
                    method_map: typeck::method_map,
                    e: @ast::expr) -> bool {
3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227
    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.
3228
pub enum ExprKind {
3229 3230 3231 3232 3233 3234
    LvalueExpr,
    RvalueDpsExpr,
    RvalueDatumExpr,
    RvalueStmtExpr
}

3235 3236 3237
pub fn expr_kind(tcx: ctxt,
                 method_map: typeck::method_map,
                 expr: @ast::expr) -> ExprKind {
3238
    if method_map.contains_key(&expr.id) {
3239 3240 3241 3242 3243 3244 3245 3246 3247 3248
        // 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 {
3249
        ast::expr_path(*) | ast::expr_self => {
3250
            match resolve_expr(tcx, expr) {
3251
                ast::def_variant(*) | ast::def_struct(*) => RvalueDpsExpr,
3252

3253 3254 3255
                // Fn pointers are just scalar values.
                ast::def_fn(*) | ast::def_static_method(*) => RvalueDatumExpr,

3256 3257 3258 3259 3260 3261 3262 3263 3264 3265
                // 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,

L
Luqman Aden 已提交
3266
                def => {
3267 3268 3269 3270 3271 3272 3273
                    tcx.sess.span_bug(expr.span, fmt!(
                        "Uncategorized def for expr %?: %?",
                        expr.id, def));
                }
            }
        }

3274
        ast::expr_unary(_, ast::deref, _) |
3275 3276 3277 3278 3279 3280
        ast::expr_field(*) |
        ast::expr_index(*) => {
            LvalueExpr
        }

        ast::expr_call(*) |
3281
        ast::expr_method_call(*) |
3282 3283 3284 3285 3286 3287 3288 3289 3290 3291
        ast::expr_struct(*) |
        ast::expr_tup(*) |
        ast::expr_if(*) |
        ast::expr_match(*) |
        ast::expr_fn_block(*) |
        ast::expr_loop_body(*) |
        ast::expr_do_body(*) |
        ast::expr_block(*) |
        ast::expr_copy(*) |
        ast::expr_repeat(*) |
J
John Clements 已提交
3292
        ast::expr_lit(@codemap::spanned {node: lit_str(_), _}) |
3293
        ast::expr_vstore(_, ast::expr_vstore_slice) |
3294
        ast::expr_vstore(_, ast::expr_vstore_mut_slice) |
3295 3296 3297 3298 3299
        ast::expr_vec(*) => {
            RvalueDpsExpr
        }

        ast::expr_cast(*) => {
D
Daniel Micay 已提交
3300 3301
            match tcx.node_types.find(&(expr.id as uint)) {
                Some(&t) => {
3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331
                    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_while(*) |
        ast::expr_loop(*) |
        ast::expr_assign(*) |
3332
        ast::expr_inline_asm(*) |
3333 3334 3335 3336 3337 3338 3339 3340
        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(*) |
3341
        ast::expr_vstore(_, ast::expr_vstore_box) |
3342
        ast::expr_vstore(_, ast::expr_vstore_mut_box) |
3343
        ast::expr_vstore(_, ast::expr_vstore_uniq) => {
3344 3345 3346
            RvalueDatumExpr
        }

3347 3348
        ast::expr_paren(e) => expr_kind(tcx, method_map, e),

3349 3350 3351
        ast::expr_mac(*) => {
            tcx.sess.span_bug(
                expr.span,
S
Seo Sanghyeon 已提交
3352
                "macro expression remains after expansion");
3353
        }
M
Marijn Haverbeke 已提交
3354 3355 3356
    }
}

3357
pub fn stmt_node_id(s: @ast::stmt) -> ast::node_id {
3358
    match s.node {
B
Brian Anderson 已提交
3359
      ast::stmt_decl(_, id) | stmt_expr(_, id) | stmt_semi(_, id) => {
B
Brian Anderson 已提交
3360
        return id;
3361
      }
3362
      ast::stmt_mac(*) => fail!("unexpanded macro in trans")
3363 3364 3365
    }
}

3366
pub fn field_idx(id: ast::ident, fields: &[field]) -> Option<uint> {
3367
    let mut i = 0u;
3368
    for fields.iter().advance |f| { if f.ident == id { return Some(i); } i += 1u; }
B
Brian Anderson 已提交
3369
    return None;
3370 3371
}

3372 3373
pub fn field_idx_strict(tcx: ty::ctxt, id: ast::ident, fields: &[field])
                     -> uint {
3374
    let mut i = 0u;
3375
    for fields.iter().advance |f| { if f.ident == id { return i; } i += 1u; }
3376 3377
    tcx.sess.bug(fmt!(
        "No field named `%s` found in the list of fields `%?`",
3378
        tcx.sess.str_of(id),
3379 3380 3381
        fields.map(|f| tcx.sess.str_of(f.ident))));
}

3382
pub fn method_idx(id: ast::ident, meths: &[@Method]) -> Option<uint> {
3383
    meths.iter().position_(|m| m.ident == id)
3384 3385
}

3386 3387 3388
/// 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.
3389
pub fn param_tys_in_type(ty: t) -> ~[param_ty] {
3390 3391
    let mut rslt = ~[];
    do walk_ty(ty) |ty| {
3392
        match get(ty).sty {
B
Brian Anderson 已提交
3393
          ty_param(p) => {
3394
            rslt.push(p);
3395
          }
B
Brian Anderson 已提交
3396
          _ => ()
3397 3398 3399 3400 3401
        }
    }
    rslt
}

3402
pub fn occurs_check(tcx: ctxt, sp: span, vid: TyVid, rt: t) {
3403 3404
    // Returns a vec of all the type variables occurring in `ty`. It may
    // contain duplicates.  (Integral type vars aren't counted.)
3405
    fn vars_in_type(ty: t) -> ~[TyVid] {
3406
        let mut rslt = ~[];
B
Brian Anderson 已提交
3407
        do walk_ty(ty) |ty| {
3408
            match get(ty).sty {
3409
              ty_infer(TyVar(v)) => rslt.push(v),
B
Brian Anderson 已提交
3410 3411
              _ => ()
            }
3412 3413 3414 3415
        }
        rslt
    }

3416
    // Fast path
B
Brian Anderson 已提交
3417
    if !type_needs_infer(rt) { return; }
B
Brian Anderson 已提交
3418

T
Tim Chevalier 已提交
3419
    // Occurs check!
N
Niko Matsakis 已提交
3420
    if vec::contains(vars_in_type(rt), &vid) {
T
Tim Chevalier 已提交
3421 3422 3423
            // 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.
3424
            tcx.sess.span_fatal
3425
                (sp, ~"type inference failed because I \
3426
                     could not find a type\n that's both of the form "
3427
                 + ::util::ppaux::ty_to_str(tcx, mk_var(tcx, vid)) +
3428 3429
                 " and of the form " + ::util::ppaux::ty_to_str(tcx, rt) +
                 " - such a type would have to be infinitely large.");
3430
    }
T
Tim Chevalier 已提交
3431
}
3432

3433
pub fn ty_sort_str(cx: ctxt, t: t) -> ~str {
3434
    match get(t).sty {
N
Niko Matsakis 已提交
3435
      ty_nil | ty_bot | ty_bool | ty_int(_) |
M
Michael Sullivan 已提交
3436
      ty_uint(_) | ty_float(_) | ty_estr(_) |
B
Brian Anderson 已提交
3437
      ty_type | ty_opaque_box | ty_opaque_closure_ptr(_) => {
3438
        ::util::ppaux::ty_to_str(cx, t)
N
Niko Matsakis 已提交
3439 3440
      }

P
Paul Stansifer 已提交
3441
      ty_enum(id, _) => fmt!("enum %s", item_path_str(cx, id)),
B
Brian Anderson 已提交
3442 3443 3444 3445 3446 3447
      ty_box(_) => ~"@-ptr",
      ty_uniq(_) => ~"~-ptr",
      ty_evec(_, _) => ~"vector",
      ty_unboxed_vec(_) => ~"unboxed vector",
      ty_ptr(_) => ~"*-ptr",
      ty_rptr(_, _) => ~"&-ptr",
3448 3449
      ty_bare_fn(_) => ~"extern fn",
      ty_closure(_) => ~"fn",
3450
      ty_trait(id, _, _, _, _) => fmt!("trait %s", item_path_str(cx, id)),
3451
      ty_struct(id, _) => fmt!("struct %s", item_path_str(cx, id)),
B
Brian Anderson 已提交
3452
      ty_tup(_) => ~"tuple",
3453 3454
      ty_infer(TyVar(_)) => ~"inferred type",
      ty_infer(IntVar(_)) => ~"integral variable",
3455
      ty_infer(FloatVar(_)) => ~"floating-point variable",
B
Brian Anderson 已提交
3456
      ty_param(_) => ~"type parameter",
3457
      ty_self(_) => ~"self",
3458
      ty_err => ~"type error"
N
Niko Matsakis 已提交
3459 3460 3461
    }
}

3462
pub fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str {
3463 3464 3465 3466 3467 3468 3469 3470 3471
    /*!
     *
     * 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. */

3472
    fn terr_vstore_kind_to_str(k: terr_vstore_kind) -> ~str {
3473 3474 3475
        match k {
            terr_vec => ~"[]",
            terr_str => ~"str",
3476 3477
            terr_fn => ~"fn",
            terr_trait => ~"trait"
3478
        }
3479 3480
    }

N
Niko Matsakis 已提交
3481
    match *err {
3482 3483 3484
        terr_mismatch => ~"types differ",
        terr_purity_mismatch(values) => {
            fmt!("expected %s fn but found %s fn",
3485
                 values.expected.to_str(), values.found.to_str())
3486
        }
3487 3488 3489 3490
        terr_abi_mismatch(values) => {
            fmt!("expected %s fn but found %s fn",
                 values.expected.to_str(), values.found.to_str())
        }
3491 3492
        terr_onceness_mismatch(values) => {
            fmt!("expected %s fn but found %s fn",
3493
                 values.expected.to_str(), values.found.to_str())
3494
        }
3495
        terr_sigil_mismatch(values) => {
3496
            fmt!("expected %s closure, found %s closure",
3497 3498
                 values.expected.to_str(),
                 values.found.to_str())
3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525
        }
        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`",
3526 3527
                 cx.sess.str_of(values.expected),
                 cx.sess.str_of(values.found))
3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541
        }
        terr_arg_count => ~"incorrect number of function parameters",
        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_regions_insufficiently_polymorphic(br, _) => {
            fmt!("expected bound lifetime parameter %s, \
                  but found concrete lifetime",
3542
                 bound_region_ptr_to_str(cx, br))
3543 3544 3545 3546
        }
        terr_regions_overly_polymorphic(br, _) => {
            fmt!("expected concrete lifetime, \
                  but found bound lifetime parameter %s",
3547
                 bound_region_ptr_to_str(cx, br))
3548
        }
3549
        terr_vstores_differ(k, ref values) => {
3550 3551
            fmt!("%s storage differs: expected %s but found %s",
                 terr_vstore_kind_to_str(k),
3552 3553
                 vstore_to_str(cx, (*values).expected),
                 vstore_to_str(cx, (*values).found))
3554
        }
3555 3556 3557 3558 3559
        terr_trait_stores_differ(_, ref values) => {
            fmt!("trait storage differs: expected %s but found %s",
                 trait_store_to_str(cx, (*values).expected),
                 trait_store_to_str(cx, (*values).found))
        }
3560
        terr_in_field(err, fname) => {
3561
            fmt!("in field `%s`, %s", cx.sess.str_of(fname),
3562 3563 3564 3565 3566 3567 3568
                 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))
        }
3569 3570 3571 3572 3573
        terr_traits(values) => {
            fmt!("expected trait %s but found trait %s",
                 item_path_str(cx, values.expected),
                 item_path_str(cx, values.found))
        }
3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586
        terr_builtin_bounds(values) => {
            if values.expected.is_empty() {
                fmt!("expected no bounds but found `%s`",
                     values.found.user_string(cx))
            } else if values.found.is_empty() {
                fmt!("expected bounds `%s` but found no bounds",
                     values.expected.user_string(cx))
            } else {
                fmt!("expected bounds `%s` but found bounds `%s`",
                     values.expected.user_string(cx),
                     values.found.user_string(cx))
            }
        }
3587
        terr_integer_as_char => {
3588
            fmt!("expected an integral type but found char")
3589
        }
3590 3591 3592 3593 3594 3595 3596 3597 3598
        terr_int_mismatch(ref values) => {
            fmt!("expected %s but found %s",
                 values.expected.to_str(),
                 values.found.to_str())
        }
        terr_float_mismatch(ref values) => {
            fmt!("expected %s but found %s",
                 values.expected.to_str(),
                 values.found.to_str())
3599
        }
3600 3601 3602
    }
}

3603
pub fn note_and_explain_type_err(cx: ctxt, err: &type_err) {
3604 3605
    match *err {
        terr_regions_does_not_outlive(subregion, superregion) => {
3606 3607 3608
            note_and_explain_region(cx, "", subregion, "...");
            note_and_explain_region(cx, "...does not necessarily outlive ",
                                    superregion, "");
3609 3610
        }
        terr_regions_not_same(region1, region2) => {
3611 3612 3613
            note_and_explain_region(cx, "", region1, "...");
            note_and_explain_region(cx, "...is not the same lifetime as ",
                                    region2, "");
3614 3615
        }
        terr_regions_no_overlap(region1, region2) => {
3616 3617 3618
            note_and_explain_region(cx, "", region1, "...");
            note_and_explain_region(cx, "...does not overlap ",
                                    region2, "");
3619
        }
3620 3621
        terr_regions_insufficiently_polymorphic(_, conc_region) => {
            note_and_explain_region(cx,
3622 3623
                                    "concrete lifetime that was found is ",
                                    conc_region, "");
3624 3625 3626
        }
        terr_regions_overly_polymorphic(_, conc_region) => {
            note_and_explain_region(cx,
3627 3628
                                    "expected concrete lifetime is ",
                                    conc_region, "");
3629
        }
3630 3631 3632 3633
        _ => {}
    }
}

3634
pub fn def_has_ty_params(def: ast::def) -> bool {
3635
    match def {
3636
      ast::def_fn(_, _) | ast::def_variant(_, _) | ast::def_struct(_)
B
Brian Anderson 已提交
3637 3638
        => true,
      _ => false
3639 3640 3641
    }
}

3642
pub fn provided_trait_methods(cx: ctxt, id: ast::def_id) -> ~[ast::ident] {
3643
    if is_local(id) {
3644
        match cx.items.find(&id.node) {
A
Alex Crichton 已提交
3645
            Some(&ast_map::node_item(@ast::item {
P
Patrick Walton 已提交
3646 3647 3648
                        node: item_trait(_, _, ref ms),
                        _
                    }, _)) =>
3649
                match ast_util::split_trait_methods(*ms) {
3650
                   (_, p) => p.map(|method| method.ident)
3651
                },
3652
            _ => cx.sess.bug(fmt!("provided_trait_methods: %? is not a trait",
3653 3654
                                  id))
        }
3655
    } else {
3656
        csearch::get_provided_trait_methods(cx, id).map(|ifo| ifo.ty.ident)
3657 3658 3659
    }
}

3660
pub fn trait_supertraits(cx: ctxt,
3661 3662
                         id: ast::def_id) -> @~[@TraitRef]
{
3663
    // Check the cache.
3664
    match cx.supertraits.find(&id) {
3665
        Some(&trait_refs) => { return trait_refs; }
3666 3667 3668 3669 3670
        None => {}  // Continue.
    }

    // Not in the cache. It had better be in the metadata, which means it
    // shouldn't be local.
P
Patrick Walton 已提交
3671
    assert!(!is_local(id));
3672 3673

    // Get the supertraits out of the metadata and create the
3674 3675 3676 3677
    // TraitRef for each.
    let result = @csearch::get_supertraits(cx, id);
    cx.supertraits.insert(id, result);
    return result;
3678
}
3679

3680 3681 3682
pub fn trait_ref_supertraits(cx: ctxt, trait_ref: &ty::TraitRef) -> ~[@TraitRef] {
    let supertrait_refs = trait_supertraits(cx, trait_ref.def_id);
    supertrait_refs.map(
3683
        |supertrait_ref| supertrait_ref.subst(cx, &trait_ref.substs))
3684 3685
}

3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703
fn lookup_locally_or_in_crate_store<V:Copy>(
    descr: &str,
    def_id: ast::def_id,
    map: &mut HashMap<ast::def_id, V>,
    load_external: &fn() -> V) -> V
{
    /*!
     *
     * Helper for looking things up in the various maps
     * that are populated during typeck::collect (e.g.,
     * `cx.methods`, `cx.tcache`, etc).  All of these share
     * the pattern that if the id is local, it should have
     * been loaded into the map by the `typeck::collect` phase.
     * If the def-id is external, then we have to go consult
     * the crate loading code (and cache the result for the future).
     */

    match map.find(&def_id) {
3704
        Some(&ref v) => { return copy *v; }
3705 3706 3707 3708
        None => { }
    }

    if def_id.crate == ast::local_crate {
3709
        fail!("No def'n found for %? in tcx.%s", def_id, descr);
3710 3711
    }
    let v = load_external();
3712 3713
    map.insert(def_id, copy v);
    return copy v;
3714 3715
}

3716
pub fn trait_method(cx: ctxt, trait_did: ast::def_id, idx: uint) -> @Method {
3717 3718 3719 3720
    let method_def_id = ty::trait_method_def_ids(cx, trait_did)[idx];
    ty::method(cx, method_def_id)
}

3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735

pub fn add_base_impl(cx: ctxt, base_def_id: def_id, implementation: @Impl) {
    let implementations;
    match cx.base_impls.find(&base_def_id) {
        None => {
            implementations = @mut ~[];
            cx.base_impls.insert(base_def_id, implementations);
        }
        Some(&existing) => {
            implementations = existing;
        }
    }
    implementations.push(implementation);
}

3736
pub fn trait_methods(cx: ctxt, trait_did: ast::def_id) -> @~[@Method] {
3737 3738 3739 3740 3741 3742 3743 3744
    match cx.trait_methods_cache.find(&trait_did) {
        Some(&methods) => methods,
        None => {
            let def_ids = ty::trait_method_def_ids(cx, trait_did);
            let methods = @def_ids.map(|d| ty::method(cx, *d));
            cx.trait_methods_cache.insert(trait_did, methods);
            methods
        }
3745 3746
    }
}
3747

3748
pub fn method(cx: ctxt, id: ast::def_id) -> @Method {
3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759
    lookup_locally_or_in_crate_store(
        "methods", id, cx.methods,
        || @csearch::get_method(cx, id))
}

pub fn trait_method_def_ids(cx: ctxt, id: ast::def_id) -> @~[def_id] {
    lookup_locally_or_in_crate_store(
        "methods", id, cx.trait_method_def_ids,
        || @csearch::get_trait_method_def_ids(cx.cstore, id))
}

3760
pub fn impl_trait_ref(cx: ctxt, id: ast::def_id) -> Option<@TraitRef> {
3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777
    *do cx.impl_trait_cache.find_or_insert_with(id) |_| {
        if id.crate == ast::local_crate {
            debug!("(impl_trait_ref) searching for trait impl %?", id);
            match cx.items.find(&id.node) {
                Some(&ast_map::node_item(@ast::item {
                                         node: ast::item_impl(_, opt_trait, _, _),
                                         _},
                                         _)) => {
                    match opt_trait {
                        Some(t) => Some(ty::node_id_to_trait_ref(cx, t.ref_id)),
                        None => None
                    }
                }
                _ => None
            }
        } else {
            csearch::get_impl_trait(cx, id)
3778
        }
3779 3780 3781
    }
}

3782
pub fn ty_to_def_id(ty: t) -> Option<ast::def_id> {
3783
    match get(ty).sty {
3784
      ty_trait(id, _, _, _, _) | ty_struct(id, _) | ty_enum(id, _) => Some(id),
B
Brian Anderson 已提交
3785
      _ => None
3786 3787 3788
    }
}

3789 3790 3791 3792 3793 3794
/// Returns the def ID of the constructor for the given tuple-like struct, or
/// None if the struct is not tuple-like. Fails if the given def ID does not
/// refer to a struct at all.
fn struct_ctor_id(cx: ctxt, struct_did: ast::def_id) -> Option<ast::def_id> {
    if struct_did.crate != ast::local_crate {
        // XXX: Cross-crate functionality.
3795
        cx.sess.unimpl("constructor ID of cross-crate tuple structs");
3796 3797
    }

3798
    match cx.items.find(&struct_did.node) {
A
Alex Crichton 已提交
3799
        Some(&ast_map::node_item(item, _)) => {
3800
            match item.node {
3801
                ast::item_struct(struct_def, _) => {
3802 3803 3804
                    struct_def.ctor_id.map(|ctor_id|
                        ast_util::local_def(*ctor_id))
                }
3805
                _ => cx.sess.bug("called struct_ctor_id on non-struct")
3806 3807
            }
        }
3808
        _ => cx.sess.bug("called struct_ctor_id on non-struct")
3809 3810 3811
    }
}

3812
// Enum information
3813
pub struct VariantInfo_ {
3814 3815 3816 3817 3818 3819 3820 3821
    args: ~[t],
    ctor_ty: t,
    name: ast::ident,
    id: ast::def_id,
    disr_val: int,
    vis: visibility
}

3822
pub type VariantInfo = @VariantInfo_;
M
Marijn Haverbeke 已提交
3823

3824 3825 3826 3827
pub fn substd_enum_variants(cx: ctxt,
                            id: ast::def_id,
                            substs: &substs)
                         -> ~[VariantInfo] {
B
Brian Anderson 已提交
3828 3829
    do vec::map(*enum_variants(cx, id)) |variant_info| {
        let substd_args = vec::map(variant_info.args,
3830
                                   |aty| subst(cx, substs, *aty));
3831

3832
        let substd_ctor_ty = subst(cx, substs, variant_info.ctor_ty);
3833

3834
        @VariantInfo_{args: substd_args, ctor_ty: substd_ctor_ty,
3835
                      ../*bad*/copy **variant_info}
3836 3837 3838
    }
}

3839
pub fn item_path_str(cx: ctxt, id: ast::def_id) -> ~str {
J
John Clements 已提交
3840
    ast_map::path_to_str(item_path(cx, id), token::get_ident_interner())
3841 3842
}

3843
pub enum DtorKind {
3844 3845 3846 3847
    NoDtor,
    TraitDtor(def_id)
}

3848 3849
impl DtorKind {
    pub fn is_not_present(&const self) -> bool {
3850 3851 3852 3853 3854
        match *self {
            NoDtor => true,
            _ => false
        }
    }
3855 3856

    pub fn is_present(&const self) -> bool {
3857 3858 3859 3860
        !self.is_not_present()
    }
}

3861
/* If struct_id names a struct with a dtor, return Some(the dtor's id).
3862
   Otherwise return none. */
3863
pub fn ty_dtor(cx: ctxt, struct_id: def_id) -> DtorKind {
3864
    match cx.destructor_for_type.find(&struct_id) {
E
Erick Tryzelaar 已提交
3865
        Some(&method_def_id) => TraitDtor(method_def_id),
3866
        None => NoDtor,
3867 3868 3869
    }
}

3870
pub fn has_dtor(cx: ctxt, struct_id: def_id) -> bool {
3871
    ty_dtor(cx, struct_id).is_present()
3872 3873
}

3874
pub fn item_path(cx: ctxt, id: ast::def_id) -> ast_map::path {
3875 3876 3877
    if id.crate != ast::local_crate {
        csearch::get_item_path(cx, id)
    } else {
A
Alex Crichton 已提交
3878 3879 3880 3881 3882 3883
        // FIXME (#5521): uncomment this code and don't have a catch-all at the
        //                end of the match statement. Favor explicitly listing
        //                each variant.
        // let node = cx.items.get(&id.node);
        // match *node {
        match *cx.items.get(&id.node) {
B
Brian Anderson 已提交
3884
          ast_map::node_item(item, path) => {
3885
            let item_elt = match item.node {
B
Brian Anderson 已提交
3886
              item_mod(_) | item_foreign_mod(_) => {
3887 3888
                ast_map::path_mod(item.ident)
              }
B
Brian Anderson 已提交
3889
              _ => {
3890 3891 3892
                ast_map::path_name(item.ident)
              }
            };
3893
            vec::append_one(/*bad*/copy *path, item_elt)
3894 3895
          }

3896
          ast_map::node_foreign_item(nitem, _, _, path) => {
3897 3898
            vec::append_one(/*bad*/copy *path,
                            ast_map::path_name(nitem.ident))
3899 3900
          }

B
Brian Anderson 已提交
3901
          ast_map::node_method(method, _, path) => {
3902 3903
            vec::append_one(/*bad*/copy *path,
                            ast_map::path_name(method.ident))
3904
          }
B
Brian Anderson 已提交
3905
          ast_map::node_trait_method(trait_method, _, path) => {
3906
            let method = ast_util::trait_method_to_ty_method(&*trait_method);
3907 3908
            vec::append_one(/*bad*/copy *path,
                            ast_map::path_name(method.ident))
3909
          }
3910

3911
          ast_map::node_variant(ref variant, _, path) => {
3912
            vec::append_one(vec::to_owned(vec::init(*path)),
3913
                            ast_map::path_name((*variant).node.name))
3914 3915
          }

3916
          ast_map::node_struct_ctor(_, item, path) => {
3917
            vec::append_one(/*bad*/copy *path, ast_map::path_name(item.ident))
3918 3919
          }

A
Alex Crichton 已提交
3920
          ref node => {
P
Paul Stansifer 已提交
3921
            cx.sess.bug(fmt!("cannot find item_path for node %?", node));
3922 3923 3924 3925 3926
          }
        }
    }
}

3927
pub fn enum_is_univariant(cx: ctxt, id: ast::def_id) -> bool {
3928
    enum_variants(cx, id).len() == 1
3929 3930
}

3931
pub fn type_is_empty(cx: ctxt, t: t) -> bool {
3932
    match ty::get(t).sty {
B
Brian Anderson 已提交
3933 3934
       ty_enum(did, _) => (*enum_variants(cx, did)).is_empty(),
       _ => false
3935 3936 3937
     }
}

3938
pub fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[VariantInfo] {
3939
    match cx.enum_var_cache.find(&id) {
3940
      Some(&variants) => return variants,
B
Brian Anderson 已提交
3941
      _ => { /* fallthrough */ }
3942
    }
3943

3944
    let result = if ast::local_crate != id.crate {
3945
        @csearch::get_enum_variants(cx, id)
3946
    } else {
3947 3948 3949 3950 3951
        /*
          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
         */
3952
        match cx.items.get_copy(&id.node) {
3953
          ast_map::node_item(@ast::item {
P
Patrick Walton 已提交
3954 3955 3956
                    node: ast::item_enum(ref enum_definition, _),
                    _
                }, _) => {
3957
            let mut disr_val = -1;
3958
            @vec::map(enum_definition.variants, |variant| {
3959
                match variant.node.kind {
3960
                    ast::tuple_variant_kind(ref args) => {
3961 3962
                        let ctor_ty = node_id_to_type(cx, variant.node.id);
                        let arg_tys = {
3963
                            if args.len() > 0u {
E
Erick Tryzelaar 已提交
3964
                                ty_fn_args(ctor_ty).map(|a| *a)
3965 3966 3967 3968 3969
                            } else {
                                ~[]
                            }
                        };
                        match variant.node.disr_expr {
B
Brian Anderson 已提交
3970
                          Some (ex) => {
3971 3972 3973
                            disr_val = match const_eval::eval_const_expr(cx,
                                                                         ex) {
                              const_eval::const_int(val) => val as int,
3974
                              _ => cx.sess.bug("tag_variants: bad disr expr")
3975 3976 3977 3978
                            }
                          }
                          _ => disr_val += 1
                        }
3979
                        @VariantInfo_{args: arg_tys,
3980 3981 3982
                          ctor_ty: ctor_ty,
                          name: variant.node.name,
                          id: ast_util::local_def(variant.node.id),
3983 3984
                          disr_val: disr_val,
                          vis: variant.node.vis
3985
                         }
3986
                    }
3987
                    ast::struct_variant_kind(_) => {
3988
                        fail!("struct variant kinds unimpl in enum_variants")
3989
                    }
3990
                }
3991
            })
M
Marijn Haverbeke 已提交
3992
          }
3993
          _ => cx.sess.bug("tag_variants: id not bound to an enum")
3994
        }
3995
    };
3996
    cx.enum_var_cache.insert(id, result);
3997
    result
3998 3999
}

4000

P
Patrick Walton 已提交
4001
// Returns information about the enum variant with the given ID:
4002 4003 4004 4005
pub fn enum_variant_with_id(cx: ctxt,
                            enum_id: ast::def_id,
                            variant_id: ast::def_id)
                         -> VariantInfo {
4006
    let variants = enum_variants(cx, enum_id);
4007 4008
    let mut i = 0;
    while i < variants.len() {
B
Brian Anderson 已提交
4009
        let variant = variants[i];
4010
        if variant.id == variant_id { return variant; }
4011
        i += 1;
4012
    }
4013
    cx.sess.bug("enum_variant_with_id(): no variant exists with that ID");
4014 4015
}

4016

4017 4018
// 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.
4019 4020 4021
pub fn lookup_item_type(cx: ctxt,
                        did: ast::def_id)
                     -> ty_param_bounds_and_ty {
4022 4023 4024
    lookup_locally_or_in_crate_store(
        "tcache", did, cx.tcache,
        || csearch::get_type(cx, did))
T
Tim Chevalier 已提交
4025 4026
}

4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043
/// Given the did of a trait, returns its canonical trait ref.
pub fn lookup_trait_def(cx: ctxt, did: ast::def_id) -> @ty::TraitDef {
    match cx.trait_defs.find(&did) {
        Some(&trait_def) => {
            // The item is in this crate. The caller should have added it to the
            // type cache already
            return trait_def;
        }
        None => {
            assert!(did.crate != ast::local_crate);
            let trait_def = @csearch::get_trait_def(cx, did);
            cx.trait_defs.insert(did, trait_def);
            return trait_def;
        }
    }
}

4044 4045
/// Determine whether an item is annotated with an attribute
pub fn has_attr(tcx: ctxt, did: def_id, attr: &str) -> bool {
4046 4047 4048 4049 4050 4051
    if is_local(did) {
        match tcx.items.find(&did.node) {
            Some(
                &ast_map::node_item(@ast::item {
                    attrs: ref attrs,
                    _
4052
                }, _)) => attr::attrs_contains_name(*attrs, attr),
S
Seo Sanghyeon 已提交
4053
            _ => tcx.sess.bug(fmt!("has_attr: %? is not an item",
4054 4055 4056 4057 4058
                                   did))
        }
    } else {
        let mut ret = false;
        do csearch::get_item_attrs(tcx.cstore, did) |meta_items| {
4059
            ret = ret || attr::contains_name(meta_items, attr);
4060 4061 4062 4063 4064
        }
        ret
    }
}

S
Seo Sanghyeon 已提交
4065
/// Determine whether an item is annotated with `#[packed]`
4066 4067 4068 4069
pub fn lookup_packed(tcx: ctxt, did: def_id) -> bool {
    has_attr(tcx, did, "packed")
}

S
Seo Sanghyeon 已提交
4070
/// Determine whether an item is annotated with `#[simd]`
S
Seo Sanghyeon 已提交
4071 4072 4073 4074
pub fn lookup_simd(tcx: ctxt, did: def_id) -> bool {
    has_attr(tcx, did, "simd")
}

T
Tim Chevalier 已提交
4075
// Look up a field ID, whether or not it's local
4076
// Takes a list of type substs in case the struct is generic
4077 4078 4079 4080 4081
pub fn lookup_field_type(tcx: ctxt,
                         struct_id: def_id,
                         id: def_id,
                         substs: &substs)
                      -> ty::t {
4082
    let t = if id.crate == ast::local_crate {
T
Tim Chevalier 已提交
4083 4084 4085
        node_id_to_type(tcx, id.node)
    }
    else {
4086
        match tcx.tcache.find(&id) {
N
Niko Matsakis 已提交
4087
           Some(&ty_param_bounds_and_ty {ty, _}) => ty,
B
Brian Anderson 已提交
4088
           None => {
4089
               let tpt = csearch::get_field_type(tcx, struct_id, id);
T
Tim Chevalier 已提交
4090
               tcx.tcache.insert(id, tpt);
4091
               tpt.ty
T
Tim Chevalier 已提交
4092 4093
           }
        }
4094
    };
4095
    subst(tcx, substs, t)
T
Tim Chevalier 已提交
4096 4097
}

4098 4099
// Look up the list of field names and IDs for a given struct
// Fails if the id is not bound to a struct.
4100
pub fn lookup_struct_fields(cx: ctxt, did: ast::def_id) -> ~[field_ty] {
4101
  if did.crate == ast::local_crate {
4102
    match cx.items.find(&did.node) {
A
Alex Crichton 已提交
4103
       Some(&ast_map::node_item(i,_)) => {
4104
         match i.node {
4105
            ast::item_struct(struct_def, _) => {
4106
               struct_field_tys(struct_def.fields)
4107
            }
4108
            _ => cx.sess.bug("struct ID bound to non-struct")
T
Tim Chevalier 已提交
4109
         }
T
Tim Chevalier 已提交
4110
       }
A
Alex Crichton 已提交
4111
       Some(&ast_map::node_variant(ref variant, _, _)) => {
4112
          match (*variant).node.kind {
4113
            ast::struct_variant_kind(struct_def) => {
4114
              struct_field_tys(struct_def.fields)
4115 4116
            }
            _ => {
4117 4118
              cx.sess.bug("struct ID bound to enum variant that isn't \
                           struct-like")
4119 4120 4121
            }
          }
       }
B
Brian Anderson 已提交
4122
       _ => {
P
Paul Stansifer 已提交
4123
           cx.sess.bug(
4124
               fmt!("struct ID not bound to an item: %s",
P
Paul Stansifer 已提交
4125
                    ast_map::node_id_to_str(cx.items, did.node,
J
John Clements 已提交
4126
                                            token::get_ident_interner())));
4127
       }
T
Tim Chevalier 已提交
4128
    }
T
Tim Chevalier 已提交
4129
        }
4130
  else {
4131
        return csearch::get_struct_fields(cx.sess.cstore, did);
T
Tim Chevalier 已提交
4132 4133 4134
    }
}

4135 4136 4137 4138
pub fn lookup_struct_field(cx: ctxt,
                           parent: ast::def_id,
                           field_id: ast::def_id)
                        -> field_ty {
4139 4140
    let r = lookup_struct_fields(cx, parent);
    match r.iter().find_(
B
Brian Anderson 已提交
4141
                 |f| f.id.node == field_id.node) {
4142
        Some(t) => *t,
4143
        None => cx.sess.bug("struct ID not found in parent's fields")
4144 4145 4146
    }
}

4147
fn struct_field_tys(fields: &[@struct_field]) -> ~[field_ty] {
4148
    do fields.map |field| {
4149
        match field.node.kind {
4150
            named_field(ident, visibility) => {
4151 4152 4153 4154 4155
                field_ty {
                    ident: ident,
                    id: ast_util::local_def(field.node.id),
                    vis: visibility,
                }
4156
            }
4157
            unnamed_field => {
4158 4159 4160 4161 4162 4163
                field_ty {
                    ident:
                        syntax::parse::token::special_idents::unnamed_field,
                    id: ast_util::local_def(field.node.id),
                    vis: ast::public,
                }
4164
            }
4165
        }
T
Tim Chevalier 已提交
4166
    }
T
Tim Chevalier 已提交
4167 4168
}

4169 4170 4171 4172
// Returns a list of fields corresponding to the struct's items. trans uses
// this. Takes a list of substs with which to instantiate field types.
pub fn struct_fields(cx: ctxt, did: ast::def_id, substs: &substs)
                     -> ~[field] {
4173
    do lookup_struct_fields(cx, did).map |f| {
4174
       field {
4175
            ident: f.ident,
4176 4177
            mt: mt {
                ty: lookup_field_type(cx, did, f.id, substs),
4178
                mutbl: m_imm
4179 4180
            }
        }
T
Tim Chevalier 已提交
4181 4182 4183
    }
}

4184
pub fn is_binopable(_cx: ctxt, ty: t, op: ast::binop) -> bool {
4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199
    static tycat_other: int = 0;
    static tycat_bool: int = 1;
    static tycat_int: int = 2;
    static tycat_float: int = 3;
    static tycat_struct: int = 4;
    static tycat_bot: int = 5;

    static opcat_add: int = 0;
    static opcat_sub: int = 1;
    static opcat_mult: int = 2;
    static opcat_shift: int = 3;
    static opcat_rel: int = 4;
    static opcat_eq: int = 5;
    static opcat_bit: int = 6;
    static opcat_logic: int = 7;
M
Marijn Haverbeke 已提交
4200 4201

    fn opcat(op: ast::binop) -> int {
4202
        match op {
B
Brian Anderson 已提交
4203 4204 4205
          ast::add => opcat_add,
          ast::subtract => opcat_sub,
          ast::mul => opcat_mult,
4206
          ast::div => opcat_mult,
B
Brian Anderson 已提交
4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220
          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
M
Marijn Haverbeke 已提交
4221 4222 4223
        }
    }

4224
    fn tycat(ty: t) -> int {
4225
        match get(ty).sty {
B
Brian Anderson 已提交
4226
          ty_bool => tycat_bool,
4227
          ty_int(_) | ty_uint(_) | ty_infer(IntVar(_)) => tycat_int,
4228
          ty_float(_) | ty_infer(FloatVar(_)) => tycat_float,
4229
          ty_tup(_) | ty_enum(_, _) => tycat_struct,
B
Brian Anderson 已提交
4230 4231
          ty_bot => tycat_bot,
          _ => tycat_other
M
Marijn Haverbeke 已提交
4232 4233 4234
        }
    }

4235 4236
    static t: bool = true;
    static f: bool = false;
4237

4238
    let tbl = ~[
4239 4240 4241
    /*.          add,     shift,   bit
      .             sub,     rel,     logic
      .                mult,    eq,         */
4242
    /*other*/   ~[f, f, f, f, f, f, f, f],
4243 4244 4245
    /*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],
4246 4247
    /*bot*/     ~[f, f, f, f, f, f, f, f],
    /*struct*/  ~[t, t, t, t, f, f, t, t]];
B
Brian Anderson 已提交
4248

B
Brian Anderson 已提交
4249
    return tbl[tycat(ty)][opcat(op)];
4250 4251
}

4252 4253 4254 4255 4256
pub fn ty_params_to_tys(tcx: ty::ctxt, generics: &ast::Generics) -> ~[t] {
    vec::from_fn(generics.ty_params.len(), |i| {
        let id = generics.ty_params.get(i).id;
        ty::mk_param(tcx, i, ast_util::local_def(id))
    })
4257
}
4258

4259
/// Returns an equivalent type with all the typedefs and self regions removed.
4260
pub fn normalize_ty(cx: ctxt, t: t) -> t {
4261
    fn normalize_mt(cx: ctxt, mt: mt) -> mt {
4262
        mt { ty: normalize_ty(cx, mt.ty), mutbl: mt.mutbl }
4263 4264 4265 4266 4267 4268 4269 4270
    }
    fn normalize_vstore(vstore: vstore) -> vstore {
        match vstore {
            vstore_fixed(*) | vstore_uniq | vstore_box => vstore,
            vstore_slice(_) => vstore_slice(re_static)
        }
    }

4271
    match cx.normalized_cache.find(&t) {
4272
      Some(&t) => return t,
B
Brian Anderson 已提交
4273
      None => ()
B
Brian Anderson 已提交
4274 4275
    }

4276
    let t = match get(t).sty {
4277 4278 4279 4280
        ty_evec(mt, vstore) =>
            // This type has a vstore. Get rid of it
            mk_evec(cx, normalize_mt(cx, mt), normalize_vstore(vstore)),

4281 4282 4283 4284
        ty_estr(vstore) =>
            // This type has a vstore. Get rid of it
            mk_estr(cx, normalize_vstore(vstore)),

E
Erick Tryzelaar 已提交
4285
        ty_rptr(_, mt) =>
4286
            // This type has a region. Get rid of it
4287 4288
            mk_rptr(cx, re_static, normalize_mt(cx, mt)),

4289 4290 4291 4292
        ty_closure(ref closure_ty) => {
            mk_closure(cx, ClosureTy {
                region: ty::re_static,
                ..copy *closure_ty
4293 4294
            })
        }
4295

4296 4297
        ty_enum(did, ref r) =>
            match (*r).self_r {
B
Brian Anderson 已提交
4298
                Some(_) =>
4299
                    // Use re_static since trans doesn't care about regions
E
Eric Holk 已提交
4300
                    mk_enum(cx, did,
4301 4302 4303 4304 4305
                     substs {
                        self_r: Some(ty::re_static),
                        self_ty: None,
                        tps: /*bad*/copy (*r).tps
                     }),
B
Brian Anderson 已提交
4306
                None =>
4307 4308 4309
                    t
            },

4310
        ty_struct(did, ref r) =>
4311
            match (*r).self_r {
B
Brian Anderson 已提交
4312
              Some(_) =>
4313
                // Ditto.
4314 4315 4316
                mk_struct(cx, did, substs {self_r: Some(ty::re_static),
                                           self_ty: None,
                                           tps: /*bad*/copy (*r).tps}),
B
Brian Anderson 已提交
4317
              None =>
4318 4319 4320 4321 4322
                t
            },

        _ =>
            t
4323 4324
    };

4325
    let sty = fold_sty(&get(t).sty, |t| { normalize_ty(cx, t) });
B
Brian Anderson 已提交
4326 4327
    let t_norm = mk_t(cx, sty);
    cx.normalized_cache.insert(t, t_norm);
B
Brian Anderson 已提交
4328
    return t_norm;
4329 4330
}

4331
// Returns the repeat count for a repeating vector expression.
4332
pub fn eval_repeat_count(tcx: ctxt, count_expr: @ast::expr) -> uint {
4333 4334
    match const_eval::eval_const_expr_partial(tcx, count_expr) {
      Ok(ref const_val) => match *const_val {
4335 4336 4337 4338 4339 4340 4341 4342
        const_eval::const_int(count) => if count < 0 {
            tcx.sess.span_err(count_expr.span,
                              "expected positive integer for \
                               repeat count but found negative integer");
            return 0;
        } else {
            return count as uint
        },
4343 4344
        const_eval::const_uint(count) => return count as uint,
        const_eval::const_float(count) => {
4345
            tcx.sess.span_err(count_expr.span,
4346
                              "expected positive integer for \
S
Seo Sanghyeon 已提交
4347
                               repeat count but found float");
4348 4349 4350
            return count as uint;
        }
        const_eval::const_str(_) => {
4351
            tcx.sess.span_err(count_expr.span,
4352
                              "expected positive integer for \
S
Seo Sanghyeon 已提交
4353
                               repeat count but found string");
4354 4355
            return 0;
        }
4356
        const_eval::const_bool(_) => {
4357
            tcx.sess.span_err(count_expr.span,
4358
                              "expected positive integer for \
S
Seo Sanghyeon 已提交
4359
                               repeat count but found boolean");
4360 4361
            return 0;
        }
4362 4363
      },
      Err(*) => {
4364
        tcx.sess.span_err(count_expr.span,
S
Seo Sanghyeon 已提交
4365 4366
                          "expected constant integer for repeat count \
                           but found variable");
4367 4368
        return 0;
      }
4369 4370 4371
    }
}

4372
// Determine what purity to check a nested function under
4373 4374 4375 4376
pub fn determine_inherited_purity(parent: (ast::purity, ast::node_id),
                                  child: (ast::purity, ast::node_id),
                                  child_sigil: ast::Sigil)
                                    -> (ast::purity, ast::node_id) {
4377 4378 4379
    // 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
4380
    match child_sigil {
4381 4382
        ast::BorrowedSigil if child.first() == ast::impure_fn => parent,
        _ => child
4383
    }
4384 4385
}

4386 4387
// Iterate over a type parameter's bounded traits and any supertraits
// of those traits, ignoring kinds.
4388 4389 4390
// Here, the supertraits are the transitive closure of the supertrait
// relation on the supertraits from each bounded trait's constraint
// list.
4391
pub fn each_bound_trait_and_supertraits(tcx: ctxt,
A
Alex Crichton 已提交
4392 4393
                                        bounds: &ParamBounds,
                                        f: &fn(@TraitRef) -> bool) -> bool {
4394
    for bounds.trait_bounds.iter().advance |&bound_trait_ref| {
4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413
        let mut supertrait_set = HashMap::new();
        let mut trait_refs = ~[];
        let mut i = 0;

        // Seed the worklist with the trait from the bound
        supertrait_set.insert(bound_trait_ref.def_id, ());
        trait_refs.push(bound_trait_ref);

        // Add the given trait ty to the hash map
        while i < trait_refs.len() {
            debug!("each_bound_trait_and_supertraits(i=%?, trait_ref=%s)",
                   i, trait_refs[i].repr(tcx));

            if !f(trait_refs[i]) {
                return false;
            }

            // Add supertraits to supertrait_set
            let supertrait_refs = trait_ref_supertraits(tcx, trait_refs[i]);
4414
            for supertrait_refs.iter().advance |&supertrait_ref| {
4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430
                debug!("each_bound_trait_and_supertraits(supertrait_ref=%s)",
                       supertrait_ref.repr(tcx));

                let d_id = supertrait_ref.def_id;
                if !supertrait_set.contains_key(&d_id) {
                    // FIXME(#5527) Could have same trait multiple times
                    supertrait_set.insert(d_id, ());
                    trait_refs.push(supertrait_ref);
                }
            }

            i += 1;
        }
    }
    return true;
}
4431

4432
pub fn count_traits_and_supertraits(tcx: ctxt,
4433
                                    type_param_defs: &[TypeParameterDef]) -> uint {
4434
    let mut total = 0;
4435
    for type_param_defs.iter().advance |type_param_def| {
4436
        for each_bound_trait_and_supertraits(tcx, type_param_def.bounds) |_| {
4437 4438 4439 4440 4441 4442
            total += 1;
        }
    }
    return total;
}

4443
// Given a trait and a type, returns the impl of that type
4444
pub fn get_impl_id(tcx: ctxt, trait_id: def_id, self_ty: t) -> def_id {
4445 4446
    match tcx.trait_impls.find(&trait_id) {
        Some(ty_to_impl) => match ty_to_impl.find(&self_ty) {
4447 4448 4449 4450
            Some(the_impl) => the_impl.did,
            None => // try autoderef!
                match deref(tcx, self_ty, false) {
                    Some(some_ty) => get_impl_id(tcx, trait_id, some_ty.ty),
4451 4452
                    None => tcx.sess.bug("get_impl_id: no impl of trait for \
                                          this type")
4453 4454
            }
        },
4455
        None => tcx.sess.bug("get_impl_id: trait isn't in trait_impls")
4456 4457 4458
    }
}

4459 4460 4461
pub fn visitor_object_ty(tcx: ctxt) -> (@TraitRef, t) {
    let ty_visitor_name = special_idents::ty_visitor;
    assert!(tcx.intrinsic_traits.contains_key(&ty_visitor_name));
4462
    let trait_ref = tcx.intrinsic_traits.get_copy(&ty_visitor_name);
4463
    (trait_ref,
4464 4465
     mk_trait(tcx, trait_ref.def_id, copy trait_ref.substs,
              BoxTraitStore, ast::m_imm, EmptyBuiltinBounds()))
4466
}