ty.rs 139.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// 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 12
use core::prelude::*;

P
Patrick Walton 已提交
13 14
use driver::session;
use metadata::csearch;
15 16 17
use metadata;
use middle::const_eval;
use middle::freevars;
P
Patrick Walton 已提交
18
use middle::lint::{get_lint_level, allow};
19 20 21 22 23 24 25 26 27
use middle::lint;
use middle::resolve::{Impl, MethodInfo};
use middle::resolve;
use middle::ty;
use middle::typeck;
use middle;
use session::Session;
use util::ppaux::{note_and_explain_region, bound_region_to_str};
use util::ppaux::{region_to_str, explain_region, vstore_to_str};
28
use util::ppaux::{ty_to_str, tys_to_str};
29
use util::common::{indenter};
30 31 32 33 34 35 36

use core::cast;
use core::cmp;
use core::dvec::DVec;
use core::dvec;
use core::ops;
use core::option;
37
use core::ptr::to_unsafe_ptr;
38 39 40 41 42
use core::result::Result;
use core::result;
use core::to_bytes;
use core::uint;
use core::vec;
43
use core::hashmap::linear::LinearMap;
44 45
use std::oldmap::HashMap;
use std::{oldmap, oldsmallintmap};
P
Patrick Walton 已提交
46
use syntax::ast::*;
47 48 49
use syntax::ast_util::{is_local, local_def};
use syntax::ast_util;
use syntax::codemap::span;
J
John Clements 已提交
50
use syntax::codemap;
51
use syntax::print::pprust;
52 53
use syntax::{ast, ast_map};
use syntax;
54

55
// Data types
56

57 58
// Note: after typeck, you should use resolved_mode() to convert this mode
// into an rmode, which will take into account the results of mode inference.
59
#[deriving_eq]
60
pub struct arg {
61 62 63
    mode: ast::mode,
    ty: t
}
64

65
#[deriving_eq]
66
pub struct field {
67 68 69
    ident: ast::ident,
    mt: mt
}
70

71
pub type param_bounds = @~[param_bound];
72

73 74 75
pub type method = {
    ident: ast::ident,
    tps: @~[param_bounds],
76
    fty: BareFnTy,
77 78 79 80 81 82
    self_ty: ast::self_ty_,
    vis: ast::visibility,
    def_id: ast::def_id
};

pub struct mt {
83 84 85
    ty: t,
    mutbl: ast::mutability,
}
86

87 88
#[auto_encode]
#[auto_decode]
89
pub enum vstore {
90 91 92
    vstore_fixed(uint),
    vstore_uniq,
    vstore_box,
93
    vstore_slice(Region)
94 95
}

96
pub struct field_ty {
T
Tim Chevalier 已提交
97
  ident: ident,
T
Tim Chevalier 已提交
98
  id: def_id,
99
  vis: ast::visibility,
100 101
  mutability: ast::struct_mutability,
}
T
Tim Chevalier 已提交
102

103 104
// Contains information needed to resolve types and (in the future) look up
// the types of AST nodes.
105
#[deriving_eq]
106
pub struct creader_cache_key {
107 108 109
    cnum: int,
    pos: uint,
    len: uint
110
}
111

112 113
type creader_cache = HashMap<creader_cache_key, t>;

114
impl to_bytes::IterBytes for creader_cache_key {
115 116 117 118
    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
        to_bytes::iter_bytes_3(&self.cnum, &self.pos, &self.len, lsb0, f);
    }
}
119

120 121 122 123
struct intern_key {
    sty: *sty,
    o_def_id: Option<ast::def_id>
}
124

125 126 127
// NB: Do not replace this with #[deriving_eq]. The automatically-derived
// implementation will not recurse through sty and you will get stack
// exhaustion.
128
impl cmp::Eq for intern_key {
129
    pure fn eq(&self, other: &intern_key) -> bool {
130 131 132
        unsafe {
            *self.sty == *other.sty && self.o_def_id == other.o_def_id
        }
133
    }
134 135 136
    pure fn ne(&self, other: &intern_key) -> bool {
        !self.eq(other)
    }
137
}
138

139
impl to_bytes::IterBytes for intern_key {
140
    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
141 142 143
        unsafe {
            to_bytes::iter_bytes_2(&*self.sty, &self.o_def_id, lsb0, f);
        }
144 145
    }
}
146

147
pub enum ast_ty_to_ty_cache_entry {
148
    atttce_unresolved,  /* not resolved yet */
149
    atttce_resolved(t)  /* resolved to a type, irrespective of region */
150 151
}

152
pub type opt_region_variance = Option<region_variance>;
153

154 155
#[auto_encode]
#[auto_decode]
156
pub enum region_variance { rv_covariant, rv_invariant, rv_contravariant }
157

158
impl cmp::Eq for region_variance {
159 160 161 162 163 164 165 166 167 168 169
    pure fn eq(&self, other: &region_variance) -> bool {
        match ((*self), (*other)) {
            (rv_covariant, rv_covariant) => true,
            (rv_invariant, rv_invariant) => true,
            (rv_contravariant, rv_contravariant) => true,
            (rv_covariant, _) => false,
            (rv_invariant, _) => false,
            (rv_contravariant, _) => false
        }
    }
    pure fn ne(&self, other: &region_variance) -> bool { !(*self).eq(other) }
170
}
171

172 173
#[auto_encode]
#[auto_decode]
174
pub struct AutoAdjustment {
175 176
    autoderefs: uint,
    autoref: Option<AutoRef>
177
}
178

179 180
#[auto_encode]
#[auto_decode]
181
pub struct AutoRef {
182
    kind: AutoRefKind,
183
    region: Region,
184
    mutbl: ast::mutability
185
}
186

187 188
#[auto_encode]
#[auto_decode]
189
pub enum AutoRefKind {
190 191 192
    /// Convert from T to &T
    AutoPtr,

193
    /// Convert from @[]/~[] to &[] (or str)
194
    AutoBorrowVec,
195

196 197 198
    /// Convert from @[]/~[] to &&[] (or str)
    AutoBorrowVecRef,

199 200
    /// Convert from @fn()/~fn() to &fn()
    AutoBorrowFn,
201 202
}

203 204 205 206 207 208
// 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
// method ID of each of the default methods belonging to the trait that that
// implementation implements.
209
pub type ProvidedMethodsMap = HashMap<def_id,@DVec<@ProvidedMethodInfo>>;
210 211 212

// Stores the method info and definition ID of the associated trait method for
// each instantiation of each provided method.
213
pub struct ProvidedMethodInfo {
214 215 216 217
    method_info: @MethodInfo,
    trait_method_def_id: def_id
}

218
pub struct ProvidedMethodSource {
219 220 221 222
    method_id: ast::def_id,
    impl_id: ast::def_id
}

223
pub struct InstantiatedTraitRef {
224 225 226 227
    def_id: ast::def_id,
    tpt: ty_param_substs_and_ty
}

228 229 230 231 232 233 234 235 236
pub type ctxt = @ctxt_;

struct ctxt_ {
    diag: syntax::diagnostic::span_handler,
    interner: HashMap<intern_key, t_box>,
    mut next_id: uint,
    vecs_implicitly_copyable: bool,
    legacy_modes: bool,
    legacy_records: bool,
237
    cstore: @mut metadata::cstore::CStore,
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
    sess: session::Session,
    def_map: resolve::DefMap,

    region_map: middle::region::region_map,
    region_paramd_items: middle::region::region_paramd_items,

    // Stores the types for various nodes in the AST.  Note that this table
    // is not guaranteed to be populated until after typeck.  See
    // typeck::check::fn_ctxt for details.
    node_types: node_type_table,

    // Stores the type parameters which were substituted to obtain the type
    // of this node.  This only applies to nodes that refer to entities
    // parameterized by type parameters, such as generic fns, types, or
    // other items.
    node_type_substs: HashMap<node_id, ~[t]>,

    items: ast_map::map,
    intrinsic_defs: HashMap<ast::ident, (ast::def_id, t)>,
    freevars: freevars::freevar_map,
    tcache: type_cache,
    rcache: creader_cache,
    ccache: constness_cache,
    short_names_cache: HashMap<t, @~str>,
    needs_drop_cache: HashMap<t, bool>,
    needs_unwind_cleanup_cache: HashMap<t, bool>,
264
    mut tc_cache: LinearMap<uint, TypeContents>,
265
    ast_ty_to_ty_cache: HashMap<node_id, ast_ty_to_ty_cache_entry>,
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
    enum_var_cache: HashMap<def_id, @~[VariantInfo]>,
    trait_method_cache: HashMap<def_id, @~[method]>,
    ty_param_bounds: HashMap<ast::node_id, param_bounds>,
    inferred_modes: HashMap<ast::node_id, ast::mode>,
    adjustments: HashMap<ast::node_id, @AutoAdjustment>,
    normalized_cache: HashMap<t, t>,
    lang_items: middle::lang_items::LanguageItems,
    legacy_boxed_traits: HashMap<node_id, ()>,
    // 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,
    provided_method_sources: HashMap<ast::def_id, ProvidedMethodSource>,
    supertraits: HashMap<ast::def_id, @~[InstantiatedTraitRef]>,

    // 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.
    destructor_for_type: HashMap<ast::def_id, ast::def_id>,

    // A method will be in this list if and only if it is a destructor.
    destructors: HashMap<ast::def_id, ()>,

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

294 295 296 297 298
enum tbox_flag {
    has_params = 1,
    has_self = 2,
    needs_infer = 4,
    has_regions = 8,
299
    has_ty_err = 16,
300 301 302 303 304 305

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

306
type t_box = @{sty: sty,
307
               id: uint,
308
               flags: uint,
B
Brian Anderson 已提交
309
               o_def_id: Option<ast::def_id>};
310

311 312 313 314 315 316
// 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 {}
317
pub type t = *t_opaque;
318

319
pub pure fn get(t: t) -> t_box {
320 321 322
    unsafe {
        let t2 = cast::reinterpret_cast::<t, t_box>(&t);
        let t3 = t2;
L
Luqman Aden 已提交
323
        cast::forget(t2);
324 325
        t3
    }
326 327
}

328
pub pure fn tbox_has_flag(tb: t_box, flag: tbox_flag) -> bool {
329 330
    (tb.flags & (flag as uint)) != 0u
}
P
Patrick Walton 已提交
331 332 333
pub pure fn type_has_params(t: t) -> bool {
    tbox_has_flag(get(t), has_params)
}
334 335 336 337 338 339 340 341 342 343 344 345
pub pure fn type_has_self(t: t) -> bool { tbox_has_flag(get(t), has_self) }
pub pure fn type_needs_infer(t: t) -> bool {
    tbox_has_flag(get(t), needs_infer)
}
pub pure fn type_has_regions(t: t) -> bool {
    tbox_has_flag(get(t), has_regions)
}
pub pure fn type_contains_err(t: t) -> bool {
    tbox_has_flag(get(t), has_ty_err)
}
pub pure fn type_def_id(t: t) -> Option<ast::def_id> { get(t).o_def_id }
pub pure fn type_id(t: t) -> uint { get(t).id }
346

347
#[deriving_eq]
348 349 350 351 352 353 354 355
pub struct BareFnTy {
    purity: ast::purity,
    abi: Abi,
    sig: FnSig
}

#[deriving_eq]
pub struct ClosureTy {
356
    purity: ast::purity,
357
    sigil: ast::Sigil,
358
    onceness: ast::Onceness,
359
    region: Region,
360
    sig: FnSig
361 362 363 364 365 366 367 368
}

/**
 * Signature of a function type, which I have arbitrarily
 * decided to use to refer to the input/output types.
 *
 * - `inputs` is the list of arguments and their modes.
 * - `output` is the return type. */
369
#[deriving_eq]
370
pub struct FnSig {
371 372
    inputs: ~[arg],
    output: t
373 374
}

375
impl to_bytes::IterBytes for BareFnTy {
376 377 378
    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
        to_bytes::iter_bytes_3(&self.purity, &self.abi, &self.sig, lsb0, f)
    }
379 380
}

381
impl to_bytes::IterBytes for ClosureTy {
382
    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
383 384
        to_bytes::iter_bytes_5(&self.purity, &self.sigil, &self.onceness,
                               &self.region, &self.sig, lsb0, f)
385
    }
386 387
}

388
#[deriving_eq]
389
pub struct param_ty {
390 391
    idx: uint,
    def_id: def_id
392
}
393

394
impl to_bytes::IterBytes for param_ty {
395 396 397 398
    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
        to_bytes::iter_bytes_2(&self.idx, &self.def_id, lsb0, f)
    }
}
399 400


401
/// Representation of regions:
402 403
#[auto_encode]
#[auto_decode]
404
pub enum Region {
405 406 407 408 409 410 411 412 413
    /// 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 已提交
414
    re_bound(bound_region),
415 416 417 418

    /// 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.
N
Niko Matsakis 已提交
419
    re_free(node_id, bound_region),
420 421

    /// A concrete region naming some expression within the current function.
N
Niko Matsakis 已提交
422
    re_scope(node_id),
423 424 425 426 427

    /// Static data that has an "infinite" lifetime.
    re_static,

    /// A region variable.  Should not exist after typeck.
428
    re_infer(InferRegion)
N
Niko Matsakis 已提交
429 430
}

431 432
#[auto_encode]
#[auto_decode]
433
pub enum bound_region {
434
    /// The self region for structs, impls (&T in a type defn or &self/T)
435 436
    br_self,

437 438
    /// An anonymous region parameter for a given fn (&T)
    br_anon(uint),
439 440 441 442

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

443 444 445
    /// Fresh bound identifiers created during GLB computations.
    br_fresh(uint),

446 447 448 449 450 451 452 453 454
    /**
     * 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. */
455
    br_cap_avoid(ast::node_id, @bound_region),
456 457
}

458
type opt_region = Option<Region>;
459

460 461 462 463 464 465 466 467 468
/**
 * 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
469
 *   types (enums, structs) declared as having a region parameter.  `self_r`
470 471 472 473 474 475 476
 *   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. */
477
#[deriving_eq]
478
pub struct substs {
479
    self_r: opt_region,
B
Brian Anderson 已提交
480
    self_ty: Option<ty::t>,
481
    tps: ~[t]
482
}
483

484
// NB: If you change this, you'll probably want to change the corresponding
485
// AST structure in libsyntax/ast.rs as well.
486
#[deriving_eq]
487
pub enum sty {
P
Patrick Walton 已提交
488 489 490 491 492 493
    ty_nil,
    ty_bot,
    ty_bool,
    ty_int(ast::int_ty),
    ty_uint(ast::uint_ty),
    ty_float(ast::float_ty),
494
    ty_estr(vstore),
495
    ty_enum(def_id, substs),
P
Patrick Walton 已提交
496 497
    ty_box(mt),
    ty_uniq(mt),
498
    ty_evec(mt, vstore),
P
Patrick Walton 已提交
499
    ty_ptr(mt),
500
    ty_rptr(Region, mt),
501
    ty_rec(~[field]),
502 503
    ty_bare_fn(BareFnTy),
    ty_closure(ClosureTy),
504
    ty_trait(def_id, substs, vstore),
505
    ty_struct(def_id, substs),
506
    ty_tup(~[t]),
P
Patrick Walton 已提交
507

508
    ty_param(param_ty), // type parameter
509
    ty_self, // special, implicit `self` type parameter
P
Patrick Walton 已提交
510

511
    ty_infer(InferTy), // something used only during inference/typeck
512 513 514
    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)
515

M
Michael Sullivan 已提交
516
    // "Fake" types, used for trans purposes
P
Patrick Walton 已提交
517
    ty_type, // type_desc*
518
    ty_opaque_box, // used by monomorphizer to represent any @ box
519
    ty_opaque_closure_ptr(Sigil), // ptr to env for fn, fn@, fn~
M
Michael Sullivan 已提交
520
    ty_unboxed_vec(mt),
521 522
}

523
#[deriving_eq]
524
pub enum IntVarValue {
525 526 527 528
    IntType(ast::int_ty),
    UintType(ast::uint_ty),
}

529
pub enum terr_vstore_kind {
530
    terr_vec, terr_str, terr_fn, terr_trait
531 532
}

533
pub struct expected_found<T> {
534 535
    expected: T,
    found: T
536 537
}

538
// Data structures used in type unification
539
pub enum type_err {
P
Patrick Walton 已提交
540
    terr_mismatch,
541
    terr_purity_mismatch(expected_found<purity>),
542
    terr_onceness_mismatch(expected_found<Onceness>),
543
    terr_abi_mismatch(expected_found<ast::Abi>),
544
    terr_mutability,
545
    terr_sigil_mismatch(expected_found<ast::Sigil>),
P
Patrick Walton 已提交
546
    terr_box_mutability,
M
Marijn Haverbeke 已提交
547
    terr_ptr_mutability,
548
    terr_ref_mutability,
P
Patrick Walton 已提交
549
    terr_vec_mutability,
550 551 552
    terr_tuple_size(expected_found<uint>),
    terr_ty_param_size(expected_found<uint>),
    terr_record_size(expected_found<uint>),
P
Patrick Walton 已提交
553
    terr_record_mutability,
554
    terr_record_fields(expected_found<ident>),
P
Patrick Walton 已提交
555
    terr_arg_count,
556
    terr_mode_mismatch(expected_found<mode>),
557 558 559
    terr_regions_does_not_outlive(Region, Region),
    terr_regions_not_same(Region, Region),
    terr_regions_no_overlap(Region, Region),
560 561
    terr_regions_insufficiently_polymorphic(bound_region, Region),
    terr_regions_overly_polymorphic(bound_region, Region),
562
    terr_vstores_differ(terr_vstore_kind, expected_found<vstore>),
B
Brian Anderson 已提交
563
    terr_in_field(@type_err, ast::ident),
564
    terr_sorts(expected_found<t>),
565
    terr_self_substs,
566
    terr_integer_as_char,
567 568
    terr_int_mismatch(expected_found<IntVarValue>),
    terr_float_mismatch(expected_found<ast::float_ty>)
569 570
}

571
pub enum param_bound {
P
Patrick Walton 已提交
572
    bound_copy,
B
Brian Anderson 已提交
573
    bound_durable,
B
Brian Anderson 已提交
574
    bound_owned,
575
    bound_const,
576
    bound_trait(t),
577 578
}

579
#[deriving_eq]
580
pub enum TyVid = uint;
581 582

#[deriving_eq]
583
pub enum IntVid = uint;
584 585

#[deriving_eq]
586
pub enum FloatVid = uint;
587 588

#[deriving_eq]
589 590
#[auto_encode]
#[auto_decode]
591
pub enum RegionVid = uint;
N
Niko Matsakis 已提交
592

593
#[deriving_eq]
594
pub enum InferTy {
595
    TyVar(TyVid),
596 597
    IntVar(IntVid),
    FloatVar(FloatVid)
598 599
}

600
impl to_bytes::IterBytes for InferTy {
601 602 603 604
    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
        match *self {
          TyVar(ref tv) => to_bytes::iter_bytes_2(&0u8, tv, lsb0, f),
          IntVar(ref iv) => to_bytes::iter_bytes_2(&1u8, iv, lsb0, f),
605
          FloatVar(ref fv) => to_bytes::iter_bytes_2(&2u8, fv, lsb0, f),
606 607 608
        }
    }
}
609

610 611
#[auto_encode]
#[auto_decode]
612
pub enum InferRegion {
613 614 615 616
    ReVar(RegionVid),
    ReSkolemized(uint, bound_region)
}

617
impl to_bytes::IterBytes for InferRegion {
618 619 620 621 622 623 624
    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
        match *self {
            ReVar(ref rv) => to_bytes::iter_bytes_2(&0u8, rv, lsb0, f),
            ReSkolemized(ref v, _) => to_bytes::iter_bytes_2(&1u8, v, lsb0, f)
        }
    }
}
625

626
impl cmp::Eq for InferRegion {
627 628 629 630 631 632 633 634 635 636 637 638 639 640
    pure fn eq(&self, other: &InferRegion) -> bool {
        match ((*self), *other) {
            (ReVar(rva), ReVar(rvb)) => {
                rva == rvb
            }
            (ReSkolemized(rva, _), ReSkolemized(rvb, _)) => {
                rva == rvb
            }
            _ => false
        }
    }
    pure fn ne(&self, other: &InferRegion) -> bool {
        !((*self) == (*other))
    }
641 642
}

643
impl to_bytes::IterBytes for param_bound {
644 645 646
    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
        match *self {
          bound_copy => 0u8.iter_bytes(lsb0, f),
B
Brian Anderson 已提交
647
          bound_durable => 1u8.iter_bytes(lsb0, f),
B
Brian Anderson 已提交
648
          bound_owned => 2u8.iter_bytes(lsb0, f),
649 650 651 652 653 654
          bound_const => 3u8.iter_bytes(lsb0, f),
          bound_trait(ref t) =>
          to_bytes::iter_bytes_2(&4u8, t, lsb0, f)
        }
    }
}
655

656
pub trait Vid {
657
    pure fn to_uint() -> uint;
N
Niko Matsakis 已提交
658 659
}

660
pub impl Vid for TyVid {
661
    pure fn to_uint() -> uint { *self }
662 663
}

664
pub impl ToStr for TyVid {
665
    pure fn to_str(&self) -> ~str { fmt!("<V%u>", self.to_uint()) }
N
Niko Matsakis 已提交
666 667
}

668
pub impl Vid for IntVid {
669
    pure fn to_uint() -> uint { *self }
670 671
}

672
pub impl ToStr for IntVid {
673
    pure fn to_str(&self) -> ~str { fmt!("<VI%u>", self.to_uint()) }
674 675
}

676
pub impl Vid for FloatVid {
677
    pure fn to_uint() -> uint { *self }
678 679
}

680
pub impl ToStr for FloatVid {
681
    pure fn to_str(&self) -> ~str { fmt!("<VF%u>", self.to_uint()) }
682 683
}

684
pub impl Vid for RegionVid {
685
    pure fn to_uint() -> uint { *self }
N
Niko Matsakis 已提交
686 687
}

688
pub impl ToStr for RegionVid {
689
    pure fn to_str(&self) -> ~str { fmt!("%?", self) }
690
}
691

692
pub impl ToStr for FnSig {
693
    pure fn to_str(&self) -> ~str {
694 695
        // grr, without tcx not much we can do.
        return ~"(...)";
696 697 698
    }
}

699
pub impl ToStr for InferTy {
700 701
    pure fn to_str(&self) -> ~str {
        match *self {
702 703 704 705
            TyVar(ref v) => v.to_str(),
            IntVar(ref v) => v.to_str(),
            FloatVar(ref v) => v.to_str()
        }
N
Niko Matsakis 已提交
706 707 708
    }
}

709
pub impl ToStr for IntVarValue {
710 711
    pure fn to_str(&self) -> ~str {
        match *self {
712 713 714
            IntType(ref v) => v.to_str(),
            UintType(ref v) => v.to_str(),
        }
715 716
    }
}
717

718
pub impl to_bytes::IterBytes for TyVid {
719
    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
720
        self.to_uint().iter_bytes(lsb0, f)
721 722
    }
}
723

724
pub impl to_bytes::IterBytes for IntVid {
725
    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
726
        self.to_uint().iter_bytes(lsb0, f)
727 728
    }
}
729

730
pub impl to_bytes::IterBytes for FloatVid {
731
    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
732
        self.to_uint().iter_bytes(lsb0, f)
733 734
    }
}
735

736
pub impl to_bytes::IterBytes for RegionVid {
737
    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
738
        self.to_uint().iter_bytes(lsb0, f)
739 740
    }
}
741

742 743 744 745 746 747 748 749 750 751
/// 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
752 753 754
pub type ty_param_bounds_and_ty = {bounds: @~[param_bounds],
                                   region_param: Option<region_variance>,
                                   ty: t};
755

756
pub type ty_param_substs_and_ty = {substs: ty::substs, ty: ty::t};
757

B
Brian Anderson 已提交
758
type type_cache = HashMap<ast::def_id, ty_param_bounds_and_ty>;
759

B
Brian Anderson 已提交
760
type constness_cache = HashMap<ast::def_id, const_eval::constness>;
761

762
pub type node_type_table = @oldsmallintmap::SmallIntMap<t>;
763

764
fn mk_rcache() -> creader_cache {
M
Marijn Haverbeke 已提交
765
    type val = {cnum: int, pos: uint, len: uint};
766
    return oldmap::HashMap();
767
}
768

769 770
pub fn new_ty_hash<V: Copy>() -> oldmap::HashMap<t, V> {
    oldmap::HashMap()
771
}
772

773 774 775 776 777 778 779 780 781
pub fn mk_ctxt(s: session::Session,
               dm: resolve::DefMap,
               amap: ast_map::map,
               freevars: freevars::freevar_map,
               region_map: middle::region::region_map,
               region_paramd_items: middle::region::region_paramd_items,
               +lang_items: middle::lang_items::LanguageItems,
               crate: @ast::crate)
            -> ctxt {
782
    let mut legacy_modes = false;
783
    let mut legacy_records = false;
784 785
    for crate.node.attrs.each |attribute| {
        match attribute.node.value.node {
786
            ast::meta_word(w) if *w == ~"legacy_modes" => {
787
                legacy_modes = true;
788 789
                if legacy_records { break; }
            }
790
            ast::meta_word(w) if *w == ~"legacy_records" => {
791 792
                legacy_records = true;
                if legacy_modes { break; }
793 794 795 796 797
            }
            _ => {}
        }
    }

798
    let interner = oldmap::HashMap();
799
    let vecs_implicitly_copyable =
800 801
        get_lint_level(s.lint_settings.default_settings,
                       lint::vecs_implicitly_copyable) == allow;
802 803 804 805 806 807 808 809 810 811 812 813
    @ctxt_ {
        diag: s.diagnostic(),
        interner: interner,
        mut next_id: 0u,
        vecs_implicitly_copyable: vecs_implicitly_copyable,
        legacy_modes: legacy_modes,
        legacy_records: legacy_records,
        cstore: s.cstore,
        sess: s,
        def_map: dm,
        region_map: region_map,
        region_paramd_items: region_paramd_items,
814
        node_types: @oldsmallintmap::mk(),
815
        node_type_substs: oldmap::HashMap(),
816
        items: amap,
817
        intrinsic_defs: oldmap::HashMap(),
818 819 820 821 822 823 824
        freevars: freevars,
        tcache: HashMap(),
        rcache: mk_rcache(),
        ccache: HashMap(),
        short_names_cache: new_ty_hash(),
        needs_drop_cache: new_ty_hash(),
        needs_unwind_cleanup_cache: new_ty_hash(),
825
        tc_cache: LinearMap::new(),
826 827 828 829 830 831 832
        ast_ty_to_ty_cache: HashMap(),
        enum_var_cache: HashMap(),
        trait_method_cache: HashMap(),
        ty_param_bounds: HashMap(),
        inferred_modes: HashMap(),
        adjustments: HashMap(),
        normalized_cache: new_ty_hash(),
L
Luqman Aden 已提交
833
        lang_items: lang_items,
834 835 836 837 838 839 840
        legacy_boxed_traits: HashMap(),
        provided_methods: HashMap(),
        provided_method_sources: HashMap(),
        supertraits: HashMap(),
        destructor_for_type: HashMap(),
        destructors: HashMap(),
        trait_impls: HashMap()
841
     }
842
}
843 844


845
// Type constructors
B
Brian Anderson 已提交
846
fn mk_t(cx: ctxt, +st: sty) -> t { mk_t_with_id(cx, st, None) }
847 848 849

// 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).
B
Brian Anderson 已提交
850
fn mk_t_with_id(cx: ctxt, +st: sty, o_def_id: Option<ast::def_id>) -> t {
851
    let key = intern_key { sty: to_unsafe_ptr(&st), o_def_id: o_def_id };
852
    match cx.interner.find(&key) {
853
      Some(t) => unsafe { return cast::reinterpret_cast(&t); },
B
Brian Anderson 已提交
854
      _ => ()
855
    }
856

857
    let mut flags = 0u;
858
    fn rflags(r: Region) -> uint {
859
        (has_regions as uint) | {
860
            match r {
861
              ty::re_infer(_) => needs_infer as uint,
B
Brian Anderson 已提交
862
              _ => 0u
863
            }
N
Niko Matsakis 已提交
864 865
        }
    }
N
Niko Matsakis 已提交
866
    fn sflags(substs: &substs) -> uint {
867
        let mut f = 0u;
868
        for substs.tps.each |tt| { f |= get(*tt).flags; }
B
Brian Anderson 已提交
869
        substs.self_r.iter(|r| f |= rflags(*r));
B
Brian Anderson 已提交
870
        return f;
N
Niko Matsakis 已提交
871
    }
872 873
    match &st {
      &ty_estr(vstore_slice(r)) => {
874
        flags |= rflags(r);
875
      }
876
      &ty_evec(ref mt, vstore_slice(r)) => {
877 878
        flags |= rflags(r);
        flags |= get(mt.ty).flags;
879
      }
880 881
      &ty_nil | &ty_bot | &ty_bool | &ty_int(_) | &ty_float(_) | &ty_uint(_) |
      &ty_estr(_) | &ty_type | &ty_opaque_closure_ptr(_) |
882 883
      &ty_opaque_box => (),
      &ty_err => flags |= has_ty_err as uint,
884 885 886 887 888
      &ty_param(_) => flags |= has_params as uint,
      &ty_infer(_) => flags |= needs_infer as uint,
      &ty_self => flags |= has_self as uint,
      &ty_enum(_, ref substs) | &ty_struct(_, ref substs) |
      &ty_trait(_, ref substs, _) => {
889
        flags |= sflags(substs);
890
      }
891 892
      &ty_box(ref m) | &ty_uniq(ref m) | &ty_evec(ref m, _) |
      &ty_ptr(ref m) | &ty_unboxed_vec(ref m) => {
893
        flags |= get(m.ty).flags;
894
      }
895
      &ty_rptr(r, ref m) => {
896 897
        flags |= rflags(r);
        flags |= get(m.ty).flags;
M
Marijn Haverbeke 已提交
898
      }
899 900
      &ty_rec(ref flds) => for flds.each |f| { flags |= get(f.mt.ty).flags; },
      &ty_tup(ref ts) => for ts.each |tt| { flags |= get(*tt).flags; },
901 902 903 904 905 906
      &ty_bare_fn(ref f) => {
        for f.sig.inputs.each |a| { flags |= get(a.ty).flags; }
        flags |= get(f.sig.output).flags;
      }
      &ty_closure(ref f) => {
        flags |= rflags(f.region);
907 908
        for f.sig.inputs.each |a| { flags |= get(a.ty).flags; }
        flags |= get(f.sig.output).flags;
M
Marijn Haverbeke 已提交
909
      }
910
    }
911

L
Luqman Aden 已提交
912
    let t = @{sty: st, id: cx.next_id, flags: flags, o_def_id: o_def_id};
913

914
    let key = intern_key {sty: to_unsafe_ptr(&t.sty), o_def_id: o_def_id};
L
Luqman Aden 已提交
915
    cx.interner.insert(key, t);
916

917
    cx.next_id += 1u;
918
    unsafe { cast::reinterpret_cast(&t) }
919 920
}

921
pub fn mk_nil(cx: ctxt) -> t { mk_t(cx, ty_nil) }
P
Patrick Walton 已提交
922

923
pub fn mk_err(cx: ctxt) -> t { mk_t(cx, ty_err) }
924

925
pub fn mk_bot(cx: ctxt) -> t { mk_t(cx, ty_bot) }
926

927
pub fn mk_bool(cx: ctxt) -> t { mk_t(cx, ty_bool) }
928

929
pub fn mk_int(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_i)) }
930

931
pub fn mk_i8(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_i8)) }
932

933
pub fn mk_i16(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_i16)) }
934

935
pub fn mk_i32(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_i32)) }
936

937
pub fn mk_i64(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_i64)) }
938

939
pub fn mk_float(cx: ctxt) -> t { mk_t(cx, ty_float(ast::ty_f)) }
940

941
pub fn mk_uint(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u)) }
942

943
pub fn mk_u8(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u8)) }
944

945
pub fn mk_u16(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u16)) }
946

947
pub fn mk_u32(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u32)) }
948

949
pub fn mk_u64(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u64)) }
950

951
pub fn mk_f32(cx: ctxt) -> t { mk_t(cx, ty_float(ast::ty_f32)) }
952

953
pub fn mk_f64(cx: ctxt) -> t { mk_t(cx, ty_float(ast::ty_f64)) }
954

955
pub fn mk_mach_int(cx: ctxt, tm: ast::int_ty) -> t { mk_t(cx, ty_int(tm)) }
956

957
pub fn mk_mach_uint(cx: ctxt, tm: ast::uint_ty) -> t { mk_t(cx, ty_uint(tm)) }
958

959 960 961
pub fn mk_mach_float(cx: ctxt, tm: ast::float_ty) -> t {
    mk_t(cx, ty_float(tm))
}
962

963
pub fn mk_char(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_char)) }
964

965
pub fn mk_estr(cx: ctxt, t: vstore) -> t {
966 967 968
    mk_t(cx, ty_estr(t))
}

969
pub fn mk_enum(cx: ctxt, did: ast::def_id, +substs: substs) -> t {
N
Niko Matsakis 已提交
970
    // take a copy of substs so that we own the vectors inside
971
    mk_t(cx, ty_enum(did, substs))
972
}
973

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

976
pub fn mk_imm_box(cx: ctxt, ty: t) -> t {
977 978
    mk_box(cx, mt {ty: ty, mutbl: ast::m_imm})
}
979

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

982
pub fn mk_imm_uniq(cx: ctxt, ty: t) -> t {
983 984
    mk_uniq(cx, mt {ty: ty, mutbl: ast::m_imm})
}
985

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

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

990
pub fn mk_mut_rptr(cx: ctxt, r: Region, ty: t) -> t {
991
    mk_rptr(cx, r, mt {ty: ty, mutbl: ast::m_mutbl})
992
}
993
pub fn mk_imm_rptr(cx: ctxt, r: Region, ty: t) -> t {
994
    mk_rptr(cx, r, mt {ty: ty, mutbl: ast::m_imm})
995 996
}

997
pub fn mk_mut_ptr(cx: ctxt, ty: t) -> t {
998 999
    mk_ptr(cx, mt {ty: ty, mutbl: ast::m_mutbl})
}
1000

1001
pub fn mk_imm_ptr(cx: ctxt, ty: t) -> t {
1002
    mk_ptr(cx, mt {ty: ty, mutbl: ast::m_imm})
1003 1004
}

1005
pub fn mk_nil_ptr(cx: ctxt) -> t {
1006
    mk_ptr(cx, mt {ty: mk_nil(cx), mutbl: ast::m_imm})
1007 1008
}

1009
pub fn mk_evec(cx: ctxt, tm: mt, t: vstore) -> t {
1010 1011 1012
    mk_t(cx, ty_evec(tm, t))
}

1013
pub fn mk_unboxed_vec(cx: ctxt, tm: mt) -> t {
M
Michael Sullivan 已提交
1014 1015
    mk_t(cx, ty_unboxed_vec(tm))
}
1016
pub fn mk_mut_unboxed_vec(cx: ctxt, ty: t) -> t {
1017
    mk_t(cx, ty_unboxed_vec(mt {ty: ty, mutbl: ast::m_imm}))
1018
}
M
Michael Sullivan 已提交
1019

1020
pub fn mk_rec(cx: ctxt, +fs: ~[field]) -> t { mk_t(cx, ty_rec(fs)) }
1021

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

1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
pub fn mk_closure(cx: ctxt, +fty: ClosureTy) -> t {
    mk_t(cx, ty_closure(fty))
}

pub fn mk_bare_fn(cx: ctxt, +fty: BareFnTy) -> t {
    mk_t(cx, ty_bare_fn(fty))
}

pub fn mk_ctor_fn(cx: ctxt, input_tys: &[ty::t], output: ty::t) -> t {
    let input_args = input_tys.map(|t| arg {mode: ast::expl(ast::by_copy),
                                            ty: *t});
    mk_bare_fn(cx,
               BareFnTy {
                   purity: ast::pure_fn,
                   abi: ast::RustAbi,
                   sig: FnSig {inputs: input_args,
                               output: output}})
}

1043

1044
pub fn mk_trait(cx: ctxt, did: ast::def_id, +substs: substs, vstore: vstore)
1045
         -> t {
N
Niko Matsakis 已提交
1046
    // take a copy of substs so that we own the vectors inside
1047
    mk_t(cx, ty_trait(did, substs, vstore))
1048 1049
}

1050
pub fn mk_struct(cx: ctxt, struct_id: ast::def_id, +substs: substs) -> t {
N
Niko Matsakis 已提交
1051
    // take a copy of substs so that we own the vectors inside
1052
    mk_t(cx, ty_struct(struct_id, substs))
T
Tim Chevalier 已提交
1053 1054
}

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

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

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

1061
pub fn mk_infer(cx: ctxt, +it: InferTy) -> t { mk_t(cx, ty_infer(it)) }
1062

1063
pub fn mk_self(cx: ctxt) -> t { mk_t(cx, ty_self) }
M
Marijn Haverbeke 已提交
1064

1065
pub fn mk_param(cx: ctxt, n: uint, k: def_id) -> t {
1066
    mk_t(cx, ty_param(param_ty { idx: n, def_id: k }))
1067
}
1068

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

1071 1072
pub fn mk_opaque_closure_ptr(cx: ctxt, sigil: ast::Sigil) -> t {
    mk_t(cx, ty_opaque_closure_ptr(sigil))
1073 1074
}

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

1077
pub fn mk_with_id(cx: ctxt, base: t, def_id: ast::def_id) -> t {
1078
    mk_t_with_id(cx, /*bad*/copy get(base).sty, Some(def_id))
1079 1080 1081
}

// Converts s to its machine type equivalent
1082
pub pure fn mach_sty(cfg: @session::config, t: t) -> sty {
1083
    match get(t).sty {
B
Brian Anderson 已提交
1084 1085 1086
      ty_int(ast::ty_i) => ty_int(cfg.int_type),
      ty_uint(ast::ty_u) => ty_uint(cfg.uint_type),
      ty_float(ast::ty_f) => ty_float(cfg.float_type),
1087
      ref s => (/*bad*/copy *s)
1088 1089 1090
    }
}

1091
pub fn default_arg_mode_for_ty(tcx: ctxt, ty: ty::t) -> ast::rmode {
1092 1093
        // FIXME(#2202) --- We retain by-ref for fn& things to workaround a
        // memory leak that otherwise results when @fn is upcast to &fn.
1094 1095 1096
    match ty::get(ty).sty {
        ty::ty_closure(ClosureTy {sigil: ast::BorrowedSigil, _}) => {
            return ast::by_ref;
1097
        }
1098
        _ => {}
1099 1100
    }
    return if tcx.legacy_modes {
1101 1102 1103 1104 1105 1106 1107 1108 1109
        if type_is_borrowed(ty) {
            // the old mode default was ++ for things like &ptr, but to be
            // forward-compatible with non-legacy, we should use +
            ast::by_copy
        } else if ty::type_is_immediate(ty) {
            ast::by_val
        } else {
            ast::by_ref
        }
1110 1111
    } else {
        ast::by_copy
1112 1113
    };

1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124
    fn type_is_borrowed(ty: t) -> bool {
        match ty::get(ty).sty {
            ty::ty_rptr(*) => true,
            ty_evec(_, vstore_slice(_)) => true,
            ty_estr(vstore_slice(_)) => true,

            // technically, we prob ought to include
            // &fn(), but that is treated specially due to #2202
            _ => false
        }
    }
1125 1126
}

1127 1128
// Returns the narrowest lifetime enclosing the evaluation of the expression
// with id `id`.
1129
pub fn encl_region(cx: ctxt, id: ast::node_id) -> ty::Region {
1130
    match cx.region_map.find(&id) {
B
Brian Anderson 已提交
1131 1132
      Some(encl_scope) => ty::re_scope(encl_scope),
      None => ty::re_static
1133 1134 1135
    }
}

1136
pub fn walk_ty(ty: t, f: fn(t)) {
B
Brian Anderson 已提交
1137
    maybe_walk_ty(ty, |t| { f(t); true });
1138 1139
}

1140
pub fn maybe_walk_ty(ty: t, f: fn(t) -> bool) {
B
Brian Anderson 已提交
1141
    if !f(ty) { return; }
1142
    match /*bad*/copy get(ty).sty {
1143
      ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
M
Michael Sullivan 已提交
1144
      ty_estr(_) | ty_type | ty_opaque_box | ty_self |
1145
      ty_opaque_closure_ptr(_) | ty_infer(_) | ty_param(_) | ty_err => {
1146
      }
M
Michael Sullivan 已提交
1147
      ty_box(tm) | ty_evec(tm, _) | ty_unboxed_vec(tm) |
B
Brian Anderson 已提交
1148
      ty_ptr(tm) | ty_rptr(_, tm) => {
1149
        maybe_walk_ty(tm.ty, f);
1150
      }
1151
      ty_enum(_, ref substs) | ty_struct(_, ref substs) |
1152 1153
      ty_trait(_, ref substs, _) => {
        for (*substs).tps.each |subty| { maybe_walk_ty(*subty, f); }
1154
      }
B
Brian Anderson 已提交
1155
      ty_rec(fields) => {
B
Brian Anderson 已提交
1156
        for fields.each |fl| { maybe_walk_ty(fl.mt.ty, f); }
M
Marijn Haverbeke 已提交
1157
      }
1158
      ty_tup(ts) => { for ts.each |tt| { maybe_walk_ty(*tt, f); } }
1159 1160 1161 1162 1163
      ty_bare_fn(ref ft) => {
        for ft.sig.inputs.each |a| { maybe_walk_ty(a.ty, f); }
        maybe_walk_ty(ft.sig.output, f);
      }
      ty_closure(ref ft) => {
1164 1165
        for ft.sig.inputs.each |a| { maybe_walk_ty(a.ty, f); }
        maybe_walk_ty(ft.sig.output, f);
M
Marijn Haverbeke 已提交
1166
      }
B
Brian Anderson 已提交
1167
      ty_uniq(tm) => { maybe_walk_ty(tm.ty, f); }
1168 1169 1170
    }
}

1171
pub fn fold_sty_to_ty(tcx: ty::ctxt, sty: &sty, foldop: fn(t) -> t) -> t {
N
Niko Matsakis 已提交
1172
    mk_t(tcx, fold_sty(sty, foldop))
1173
}
1174

1175
pub fn fold_sig(sig: &FnSig, fldop: fn(t) -> t) -> FnSig {
1176
    let args = do sig.inputs.map |arg| {
1177
        arg { mode: arg.mode, ty: fldop(arg.ty) }
1178 1179 1180
    };

    FnSig {
L
Luqman Aden 已提交
1181
        inputs: args,
1182 1183 1184 1185
        output: fldop(sig.output)
    }
}

N
Niko Matsakis 已提交
1186 1187
fn fold_sty(sty: &sty, fldop: fn(t) -> t) -> sty {
    fn fold_substs(substs: &substs, fldop: fn(t) -> t) -> substs {
1188 1189 1190
        substs {self_r: substs.self_r,
                self_ty: substs.self_ty.map(|t| fldop(*t)),
                tps: substs.tps.map(|t| fldop(*t))}
1191 1192
    }

1193
    match /*bad*/copy *sty {
1194
        ty_box(tm) => {
1195
            ty_box(mt {ty: fldop(tm.ty), mutbl: tm.mutbl})
1196 1197
        }
        ty_uniq(tm) => {
1198
            ty_uniq(mt {ty: fldop(tm.ty), mutbl: tm.mutbl})
1199 1200
        }
        ty_ptr(tm) => {
1201
            ty_ptr(mt {ty: fldop(tm.ty), mutbl: tm.mutbl})
1202 1203
        }
        ty_unboxed_vec(tm) => {
1204
            ty_unboxed_vec(mt {ty: fldop(tm.ty), mutbl: tm.mutbl})
1205 1206
        }
        ty_evec(tm, vst) => {
1207
            ty_evec(mt {ty: fldop(tm.ty), mutbl: tm.mutbl}, vst)
1208 1209 1210 1211 1212 1213 1214 1215 1216 1217
        }
        ty_enum(tid, ref substs) => {
            ty_enum(tid, fold_substs(substs, fldop))
        }
        ty_trait(did, ref substs, vst) => {
            ty_trait(did, fold_substs(substs, fldop), vst)
        }
        ty_rec(fields) => {
            let new_fields = do vec::map(fields) |fl| {
                let new_ty = fldop(fl.mt.ty);
1218 1219
                let new_mt = mt { ty: new_ty, mutbl: fl.mt.mutbl };
                field { ident: fl.ident, mt: new_mt }
1220 1221 1222 1223
            };
            ty_rec(new_fields)
        }
        ty_tup(ts) => {
1224
            let new_ts = vec::map(ts, |tt| fldop(*tt));
1225 1226
            ty_tup(new_ts)
        }
1227 1228 1229 1230 1231
        ty_bare_fn(ref f) => {
            let sig = fold_sig(&f.sig, fldop);
            ty_bare_fn(BareFnTy {sig: sig, abi: f.abi, purity: f.purity})
        }
        ty_closure(ref f) => {
1232
            let sig = fold_sig(&f.sig, fldop);
1233
            ty_closure(ClosureTy {sig: sig, ..copy *f})
1234 1235
        }
        ty_rptr(r, tm) => {
1236
            ty_rptr(r, mt {ty: fldop(tm.ty), mutbl: tm.mutbl})
1237
        }
1238 1239
        ty_struct(did, ref substs) => {
            ty_struct(did, fold_substs(substs, fldop))
1240 1241
        }
        ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
1242
        ty_estr(_) | ty_type | ty_opaque_closure_ptr(_) | ty_err |
1243
        ty_opaque_box | ty_infer(_) | ty_param(*) | ty_self => {
1244
            /*bad*/copy *sty
1245
        }
N
Niko Matsakis 已提交
1246 1247
    }
}
1248

N
Niko Matsakis 已提交
1249
// Folds types from the bottom up.
1250
pub fn fold_ty(cx: ctxt, t0: t, fldop: fn(t) -> t) -> t {
1251
    let sty = fold_sty(&get(t0).sty, |t| fold_ty(cx, fldop(t), fldop));
N
Niko Matsakis 已提交
1252 1253
    fldop(mk_t(cx, sty))
}
1254

1255
pub fn walk_regions_and_ty(
1256 1257
    cx: ctxt,
    ty: t,
1258
    walkr: fn(r: Region),
1259 1260 1261 1262 1263
    walkt: fn(t: t) -> bool) {

    if (walkt(ty)) {
        fold_regions_and_ty(
            cx, ty,
B
Brian Anderson 已提交
1264 1265 1266
            |r| { walkr(r); r },
            |t| { walkt(t); walk_regions_and_ty(cx, t, walkr, walkt); t },
            |t| { walkt(t); walk_regions_and_ty(cx, t, walkr, walkt); t });
1267 1268 1269
    }
}

1270
pub fn fold_regions_and_ty(
1271 1272
    cx: ctxt,
    ty: t,
1273
    fldr: fn(r: Region) -> Region,
1274 1275 1276 1277
    fldfnt: fn(t: t) -> t,
    fldt: fn(t: t) -> t) -> t {

    fn fold_substs(
N
Niko Matsakis 已提交
1278
        substs: &substs,
1279
        fldr: fn(r: Region) -> Region,
1280 1281 1282 1283 1284 1285 1286
        fldt: fn(t: t) -> t)
     -> 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))
        }
1287 1288 1289
    }

    let tb = ty::get(ty);
1290
    match tb.sty {
B
Brian Anderson 已提交
1291
      ty::ty_rptr(r, mt) => {
1292 1293
        let m_r = fldr(r);
        let m_t = fldt(mt.ty);
1294
        ty::mk_rptr(cx, m_r, mt {ty: m_t, mutbl: mt.mutbl})
1295
      }
B
Brian Anderson 已提交
1296
      ty_estr(vstore_slice(r)) => {
1297 1298 1299
        let m_r = fldr(r);
        ty::mk_estr(cx, vstore_slice(m_r))
      }
B
Brian Anderson 已提交
1300
      ty_evec(mt, vstore_slice(r)) => {
1301 1302
        let m_r = fldr(r);
        let m_t = fldt(mt.ty);
1303
        ty::mk_evec(cx, mt {ty: m_t, mutbl: mt.mutbl}, vstore_slice(m_r))
1304
      }
N
Niko Matsakis 已提交
1305
      ty_enum(def_id, ref substs) => {
1306 1307
        ty::mk_enum(cx, def_id, fold_substs(substs, fldr, fldt))
      }
1308 1309
      ty_struct(def_id, ref substs) => {
        ty::mk_struct(cx, def_id, fold_substs(substs, fldr, fldt))
1310
      }
1311 1312
      ty_trait(def_id, ref substs, vst) => {
        ty::mk_trait(cx, def_id, fold_substs(substs, fldr, fldt), vst)
1313
      }
1314 1315 1316 1317 1318 1319 1320 1321
      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})
1322
      }
N
Niko Matsakis 已提交
1323
      ref sty => {
B
Brian Anderson 已提交
1324
        fold_sty_to_ty(cx, sty, |t| fldt(t))
1325 1326 1327 1328
      }
    }
}

1329 1330
// n.b. this function is intended to eventually replace fold_region() below,
// that is why its name is so similar.
1331
pub fn fold_regions(
1332 1333
    cx: ctxt,
    ty: t,
1334
    fldr: fn(r: Region, in_fn: bool) -> Region) -> t {
1335
    fn do_fold(cx: ctxt, ty: t, in_fn: bool,
1336
               fldr: fn(Region, bool) -> Region) -> t {
1337
        debug!("do_fold(ty=%s, in_fn=%b)", ty_to_str(cx, ty), in_fn);
B
Brian Anderson 已提交
1338
        if !type_has_regions(ty) { return ty; }
1339 1340
        fold_regions_and_ty(
            cx, ty,
B
Brian Anderson 已提交
1341 1342 1343
            |r| fldr(r, in_fn),
            |t| do_fold(cx, t, true, fldr),
            |t| do_fold(cx, t, in_fn, fldr))
1344 1345 1346 1347
    }
    do_fold(cx, ty, false, fldr)
}

1348
// Substitute *only* type parameters.  Used in trans where regions are erased.
1349
pub fn subst_tps(cx: ctxt, tps: &[t], self_ty_opt: Option<t>, typ: t) -> t {
1350
    if tps.len() == 0u && self_ty_opt.is_none() { return typ; }
1351
    let tb = ty::get(typ);
1352
    if self_ty_opt.is_none() && !tbox_has_flag(tb, has_params) { return typ; }
1353
    match tb.sty {
1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365
        ty_param(p) => tps[p.idx],
        ty_self => {
            match self_ty_opt {
                None => cx.sess.bug(~"ty_self unexpected here"),
                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))
        }
1366 1367 1368
    }
}

1369
pub fn substs_is_noop(substs: &substs) -> bool {
1370 1371 1372
    substs.tps.len() == 0u &&
        substs.self_r.is_none() &&
        substs.self_ty.is_none()
1373 1374
}

1375
pub fn substs_to_str(cx: ctxt, substs: &substs) -> ~str {
P
Paul Stansifer 已提交
1376
    fmt!("substs(self_r=%s, self_ty=%s, tps=%?)",
1377
         substs.self_r.map_default(~"none", |r| region_to_str(cx, *r)),
1378 1379
         substs.self_ty.map_default(~"none",
                                    |t| ::util::ppaux::ty_to_str(cx, *t)),
1380
         tys_to_str(cx, substs.tps))
1381 1382
}

1383
pub fn param_bound_to_str(cx: ctxt, pb: &param_bound) -> ~str {
1384 1385
    match *pb {
        bound_copy => ~"copy",
1386
        bound_durable => ~"&static",
B
Brian Anderson 已提交
1387
        bound_owned => ~"owned",
1388
        bound_const => ~"const",
1389
        bound_trait(t) => ::util::ppaux::ty_to_str(cx, t)
1390 1391 1392
    }
}

1393
pub fn param_bounds_to_str(cx: ctxt, pbs: param_bounds) -> ~str {
1394
    fmt!("%?", pbs.map(|pb| param_bound_to_str(cx, pb)))
1395 1396
}

1397 1398 1399 1400
pub fn subst(cx: ctxt,
             substs: &substs,
             typ: t)
          -> t {
P
Paul Stansifer 已提交
1401
    debug!("subst(substs=%s, typ=%s)",
1402
           substs_to_str(cx, substs),
1403
           ::util::ppaux::ty_to_str(cx, typ));
N
Niko Matsakis 已提交
1404

B
Brian Anderson 已提交
1405
    if substs_is_noop(substs) { return typ; }
1406
    let r = do_subst(cx, substs, typ);
1407
    debug!("  r = %s", ::util::ppaux::ty_to_str(cx, r));
B
Brian Anderson 已提交
1408
    return r;
1409 1410

    fn do_subst(cx: ctxt,
N
Niko Matsakis 已提交
1411
                substs: &substs,
1412 1413
                typ: t) -> t {
        let tb = get(typ);
B
Brian Anderson 已提交
1414
        if !tbox_has_flag(tb, needs_subst) { return typ; }
1415
        match tb.sty {
B
Brian Anderson 已提交
1416 1417 1418
          ty_param(p) => substs.tps[p.idx],
          ty_self => substs.self_ty.get(),
          _ => {
1419 1420
            fold_regions_and_ty(
                cx, typ,
1421
                |r| match r {
1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433
                    re_bound(br_self) => {
                        match substs.self_r {
                            None => {
                                cx.sess.bug(
                                    fmt!("ty::subst: \
                                  Reference to self region when given substs \
                                  with no self region, ty = %s",
                                  ::util::ppaux::ty_to_str(cx, typ)))
                            }
                            Some(self_r) => self_r
                        }
                    }
B
Brian Anderson 已提交
1434
                    _ => r
1435
                },
B
Brian Anderson 已提交
1436 1437
                |t| do_subst(cx, substs, t),
                |t| do_subst(cx, substs, t))
1438 1439
          }
        }
N
Niko Matsakis 已提交
1440 1441
    }
}
1442

Y
Youngsoo Son 已提交
1443
// Performs substitutions on a set of substitutions (result = sup(sub)) to
1444
// yield a new set of substitutions. This is used in trait inheritance.
1445
pub fn subst_substs(cx: ctxt, sup: &substs, sub: &substs) -> substs {
1446
    substs {
Y
Youngsoo Son 已提交
1447 1448 1449
        self_r: sup.self_r,
        self_ty: sup.self_ty.map(|typ| subst(cx, sub, *typ)),
        tps: sup.tps.map(|typ| subst(cx, sub, *typ))
1450 1451 1452
    }
}

1453
// Type utilities
1454

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

1457
pub fn type_is_bot(ty: t) -> bool { get(ty).sty == ty_bot }
1458

1459
pub fn type_is_ty_var(ty: t) -> bool {
1460
    match get(ty).sty {
1461
      ty_infer(TyVar(_)) => true,
B
Brian Anderson 已提交
1462
      _ => false
1463 1464 1465
    }
}

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

1468
pub fn type_is_structural(ty: t) -> bool {
1469
    match get(ty).sty {
1470 1471 1472
      ty_rec(_) | ty_struct(*) | ty_tup(_) | ty_enum(*) |
      ty_closure(_) |
      ty_bare_fn(_) | // FIXME(#4804) Bare fn repr
1473 1474 1475
      ty_trait(*) |
      ty_evec(_, vstore_fixed(_)) | ty_estr(vstore_fixed(_)) |
      ty_evec(_, vstore_slice(_)) | ty_estr(vstore_slice(_))
B
Brian Anderson 已提交
1476 1477
      => true,
      _ => false
1478 1479 1480
    }
}

1481
pub fn type_is_sequence(ty: t) -> bool {
1482
    match get(ty).sty {
B
Brian Anderson 已提交
1483 1484
      ty_estr(_) | ty_evec(_, _) => true,
      _ => false
1485 1486 1487
    }
}

1488
pub fn type_is_str(ty: t) -> bool {
1489
    match get(ty).sty {
B
Brian Anderson 已提交
1490 1491
      ty_estr(_) => true,
      _ => false
1492 1493
    }
}
1494

1495
pub fn sequence_element_type(cx: ctxt, ty: t) -> t {
1496
    match get(ty).sty {
B
Brian Anderson 已提交
1497 1498 1499 1500
      ty_estr(_) => return mk_mach_uint(cx, ast::ty_u8),
      ty_evec(mt, _) | ty_unboxed_vec(mt) => return mt.ty,
      _ => cx.sess.bug(
          ~"sequence_element_type called on non-sequence value"),
1501 1502 1503
    }
}

1504
pub fn get_element_type(ty: t, i: uint) -> t {
1505
    match /*bad*/copy get(ty).sty {
B
Brian Anderson 已提交
1506 1507
      ty_rec(flds) => return flds[i].mt.ty,
      ty_tup(ts) => return ts[i],
1508
      _ => fail!(~"get_element_type called on invalid type")
1509 1510 1511
    }
}

1512
pub pure fn type_is_box(ty: t) -> bool {
1513
    match get(ty).sty {
B
Brian Anderson 已提交
1514 1515
      ty_box(_) => return true,
      _ => return false
1516
    }
M
Marijn Haverbeke 已提交
1517 1518
}

1519
pub pure fn type_is_boxed(ty: t) -> bool {
1520
    match get(ty).sty {
1521
      ty_box(_) | ty_opaque_box |
B
Brian Anderson 已提交
1522 1523
      ty_evec(_, vstore_box) | ty_estr(vstore_box) => true,
      _ => false
1524 1525 1526
    }
}

1527
pub pure fn type_is_region_ptr(ty: t) -> bool {
1528
    match get(ty).sty {
B
Brian Anderson 已提交
1529 1530
      ty_rptr(_, _) => true,
      _ => false
1531 1532 1533
    }
}

1534
pub pure fn type_is_slice(ty: t) -> bool {
1535
    match get(ty).sty {
B
Brian Anderson 已提交
1536 1537
      ty_evec(_, vstore_slice(_)) | ty_estr(vstore_slice(_)) => true,
      _ => return false
1538 1539 1540
    }
}

1541
pub pure fn type_is_unique_box(ty: t) -> bool {
1542
    match get(ty).sty {
B
Brian Anderson 已提交
1543 1544
      ty_uniq(_) => return true,
      _ => return false
1545
    }
M
Marijn Haverbeke 已提交
1546
}
1547

1548
pub pure fn type_is_unsafe_ptr(ty: t) -> bool {
1549
    match get(ty).sty {
B
Brian Anderson 已提交
1550 1551
      ty_ptr(_) => return true,
      _ => return false
1552 1553 1554
    }
}

1555
pub pure fn type_is_vec(ty: t) -> bool {
1556
    return match get(ty).sty {
B
Brian Anderson 已提交
1557 1558 1559
          ty_evec(_, _) | ty_unboxed_vec(_) => true,
          ty_estr(_) => true,
          _ => false
B
Brian Anderson 已提交
1560
        };
M
Marijn Haverbeke 已提交
1561 1562
}

1563
pub pure fn type_is_unique(ty: t) -> bool {
1564
    match get(ty).sty {
B
Brian Anderson 已提交
1565 1566 1567 1568
      ty_uniq(_) => return true,
      ty_evec(_, vstore_uniq) => true,
      ty_estr(vstore_uniq) => true,
      _ => return false
B
Brian Anderson 已提交
1569
    }
1570 1571
}

1572 1573 1574 1575 1576
/*
 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.)
*/
1577
pub pure fn type_is_scalar(ty: t) -> bool {
1578
    match get(ty).sty {
1579
      ty_nil | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) |
1580 1581
      ty_infer(IntVar(_)) | ty_infer(FloatVar(_)) | ty_type |
      ty_ptr(_) => true,
B
Brian Anderson 已提交
1582
      _ => false
M
Marijn Haverbeke 已提交
1583
    }
1584 1585
}

1586
pub fn type_is_immediate(ty: t) -> bool {
B
Brian Anderson 已提交
1587
    return type_is_scalar(ty) || type_is_boxed(ty) ||
1588
        type_is_unique(ty) || type_is_region_ptr(ty);
1589 1590
}

1591
pub fn type_needs_drop(cx: ctxt, ty: t) -> bool {
1592
    match cx.needs_drop_cache.find(&ty) {
B
Brian Anderson 已提交
1593 1594
      Some(result) => return result,
      None => {/* fall through */ }
M
Marijn Haverbeke 已提交
1595 1596
    }

1597
    let mut accum = false;
1598
    let result = match /*bad*/copy get(ty).sty {
M
Marijn Haverbeke 已提交
1599
      // scalar types
1600
      ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) |
1601
      ty_type | ty_ptr(_) | ty_rptr(_, _) |
1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613
      ty_estr(vstore_fixed(_)) |
      ty_estr(vstore_slice(_)) |
      ty_evec(_, vstore_slice(_)) |
      ty_self => false,

      ty_box(_) | ty_uniq(_) |
      ty_opaque_box | ty_opaque_closure_ptr(*) |
      ty_estr(vstore_uniq) |
      ty_estr(vstore_box) |
      ty_evec(_, vstore_uniq) |
      ty_evec(_, vstore_box) => true,

1614 1615 1616 1617
      ty_trait(_, _, vstore_box) |
      ty_trait(_, _, vstore_uniq) => true,
      ty_trait(_, _, vstore_fixed(_)) |
      ty_trait(_, _, vstore_slice(_)) => false,
1618

1619
      ty_param(*) | ty_infer(*) | ty_err => true,
1620

B
Brian Anderson 已提交
1621 1622 1623
      ty_evec(mt, vstore_fixed(_)) => type_needs_drop(cx, mt.ty),
      ty_unboxed_vec(mt) => type_needs_drop(cx, mt.ty),
      ty_rec(flds) => {
B
Brian Anderson 已提交
1624 1625 1626
        for flds.each |f| {
            if type_needs_drop(cx, f.mt.ty) { accum = true; }
        }
1627
        accum
M
Marijn Haverbeke 已提交
1628
      }
1629 1630
      ty_struct(did, ref substs) => {
         // Any struct with a dtor needs a drop
1631
         ty_dtor(cx, did).is_present() || {
1632
             for vec::each(ty::struct_fields(cx, did, substs)) |f| {
1633 1634 1635
                 if type_needs_drop(cx, f.mt.ty) { accum = true; }
             }
             accum
1636
         }
1637
      }
B
Brian Anderson 已提交
1638
      ty_tup(elts) => {
1639
          for elts.each |m| { if type_needs_drop(cx, *m) { accum = true; } }
1640
        accum
1641
      }
N
Niko Matsakis 已提交
1642
      ty_enum(did, ref substs) => {
1643
        let variants = enum_variants(cx, did);
1644
          for vec::each(*variants) |variant| {
B
Brian Anderson 已提交
1645
              for variant.args.each |aty| {
M
Marijn Haverbeke 已提交
1646
                // Perform any type parameter substitutions.
1647
                let arg_ty = subst(cx, substs, *aty);
1648
                if type_needs_drop(cx, arg_ty) { accum = true; }
1649
            }
1650
            if accum { break; }
1651
        }
1652
        accum
M
Marijn Haverbeke 已提交
1653
      }
1654 1655 1656 1657 1658
      ty_bare_fn(*) => false,
      ty_closure(ref fty) => {
        match fty.sigil {
          ast::BorrowedSigil => false,
          ast::ManagedSigil | ast::OwnedSigil => true,
1659 1660
        }
      }
1661
    };
1662

1663
    cx.needs_drop_cache.insert(ty, result);
B
Brian Anderson 已提交
1664
    return result;
1665 1666
}

1667 1668 1669 1670
// 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.
1671
pub fn type_needs_unwind_cleanup(cx: ctxt, ty: t) -> bool {
1672
    match cx.needs_unwind_cleanup_cache.find(&ty) {
B
Brian Anderson 已提交
1673 1674
      Some(result) => return result,
      None => ()
1675 1676
    }

1677 1678 1679 1680
    let tycache = new_ty_hash();
    let needs_unwind_cleanup =
        type_needs_unwind_cleanup_(cx, ty, tycache, false);
    cx.needs_unwind_cleanup_cache.insert(ty, needs_unwind_cleanup);
B
Brian Anderson 已提交
1681
    return needs_unwind_cleanup;
1682 1683 1684
}

fn type_needs_unwind_cleanup_(cx: ctxt, ty: t,
1685
                              tycache: oldmap::HashMap<t, ()>,
1686 1687
                              encountered_box: bool) -> bool {

1688
    // Prevent infinite recursion
1689
    match tycache.find(&ty) {
B
Brian Anderson 已提交
1690 1691
      Some(_) => return false,
      None => { tycache.insert(ty, ()); }
1692
    }
1693

1694
    let mut encountered_box = encountered_box;
1695
    let mut needs_unwind_cleanup = false;
B
Brian Anderson 已提交
1696
    do maybe_walk_ty(ty) |ty| {
1697
        let old_encountered_box = encountered_box;
1698
        let result = match get(ty).sty {
B
Brian Anderson 已提交
1699
          ty_box(_) | ty_opaque_box => {
1700 1701 1702
            encountered_box = true;
            true
          }
1703 1704
          ty_nil | ty_bot | ty_bool |
          ty_int(_) | ty_uint(_) | ty_float(_) |
B
Brian Anderson 已提交
1705
          ty_rec(_) | ty_tup(_) | ty_ptr(_) => {
1706 1707
            true
          }
N
Niko Matsakis 已提交
1708
          ty_enum(did, ref substs) => {
1709
            for vec::each(*enum_variants(cx, did)) |v| {
B
Brian Anderson 已提交
1710
                for v.args.each |aty| {
1711
                    let t = subst(cx, substs, *aty);
1712 1713 1714
                    needs_unwind_cleanup |=
                        type_needs_unwind_cleanup_(cx, t, tycache,
                                                   encountered_box);
1715 1716 1717 1718
                }
            }
            !needs_unwind_cleanup
          }
M
Michael Sullivan 已提交
1719
          ty_uniq(_) |
1720 1721 1722 1723
          ty_estr(vstore_uniq) |
          ty_estr(vstore_box) |
          ty_evec(_, vstore_uniq) |
          ty_evec(_, vstore_box)
B
Brian Anderson 已提交
1724
          => {
1725 1726 1727 1728 1729 1730 1731 1732 1733
            // 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 已提交
1734
          _ => {
1735 1736 1737
            needs_unwind_cleanup = true;
            false
          }
1738 1739 1740 1741
        };

        encountered_box = old_encountered_box;
        result
1742 1743
    }

B
Brian Anderson 已提交
1744
    return needs_unwind_cleanup;
1745 1746
}

1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761
/**
 * 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
}
1762

1763 1764 1765 1766
pub impl TypeContents {
    fn intersects(&self, tc: TypeContents) -> bool {
        (self.bits & tc.bits) != 0
    }
1767

1768 1769 1770
    fn is_copy(&self, cx: ctxt) -> bool {
        !self.intersects(TypeContents::noncopyable(cx))
    }
1771

1772 1773 1774 1775
    static fn noncopyable(_cx: ctxt) -> TypeContents {
        TC_DTOR + TC_BORROWED_MUT + TC_ONCE_CLOSURE + TC_OWNED_CLOSURE +
            TC_EMPTY_ENUM
    }
1776

1777 1778 1779
    fn is_durable(&self, cx: ctxt) -> bool {
        !self.intersects(TypeContents::nondurable(cx))
    }
1780

1781 1782 1783
    static fn nondurable(_cx: ctxt) -> TypeContents {
        TC_BORROWED_POINTER
    }
1784

1785 1786 1787
    fn is_owned(&self, cx: ctxt) -> bool {
        !self.intersects(TypeContents::nonowned(cx))
    }
1788

1789 1790 1791
    static fn nonowned(_cx: ctxt) -> TypeContents {
        TC_MANAGED + TC_BORROWED_POINTER
    }
1792

1793 1794 1795
    fn is_const(&self, cx: ctxt) -> bool {
        !self.intersects(TypeContents::nonconst(cx))
    }
1796

1797 1798 1799
    static fn nonconst(_cx: ctxt) -> TypeContents {
        TC_MUTABLE
    }
1800

1801 1802 1803
    fn moves_by_default(&self, cx: ctxt) -> bool {
        self.intersects(TypeContents::nonimplicitly_copyable(cx))
    }
1804

1805 1806 1807 1808
    static fn nonimplicitly_copyable(cx: ctxt) -> TypeContents {
        let base = TypeContents::noncopyable(cx) + TC_OWNED_POINTER;
        if cx.vecs_implicitly_copyable {base} else {base + TC_OWNED_SLICE}
    }
1809

1810 1811 1812
    fn is_safe_for_default_mode(&self, cx: ctxt) -> bool {
        !self.intersects(TypeContents::nondefault_mode(cx))
    }
1813

1814 1815 1816 1817
    static fn nondefault_mode(cx: ctxt) -> TypeContents {
        let tc = TypeContents::nonimplicitly_copyable(cx);
        tc + TC_BIG + TC_OWNED_SLICE // disregard cx.vecs_implicitly_copyable
    }
1818
}
1819

1820
impl ops::Add<TypeContents,TypeContents> for TypeContents {
1821 1822 1823
    pure fn add(&self, other: &TypeContents) -> TypeContents {
        TypeContents {bits: self.bits | other.bits}
    }
1824 1825
}

1826
impl ops::Sub<TypeContents,TypeContents> for TypeContents {
1827 1828 1829
    pure fn sub(&self, other: &TypeContents) -> TypeContents {
        TypeContents {bits: self.bits & !other.bits}
    }
1830 1831
}

1832
impl ToStr for TypeContents {
1833 1834 1835
    pure fn to_str(&self) -> ~str {
        fmt!("TypeContents(%s)", u32::to_str_radix(self.bits, 2))
    }
1836 1837
}

1838 1839
/// Constant for a type containing nothing of interest.
const TC_NONE: TypeContents =             TypeContents{bits:0b0000_00000000};
1840

1841 1842
/// Contains a borrowed value with a lifetime other than static
const TC_BORROWED_POINTER: TypeContents = TypeContents{bits:0b0000_00000001};
1843

1844 1845
/// Contains an owned pointer (~T) but not slice of some kind
const TC_OWNED_POINTER: TypeContents =    TypeContents{bits:0b000000000010};
1846

1847 1848
/// Contains an owned slice
const TC_OWNED_SLICE: TypeContents =      TypeContents{bits:0b000000000100};
1849

1850 1851
/// Contains a ~fn() or a ~Trait, which is non-copyable.
const TC_OWNED_CLOSURE: TypeContents =    TypeContents{bits:0b000000001000};
1852

1853 1854
/// Type with a destructor
const TC_DTOR: TypeContents =             TypeContents{bits:0b000000010000};
1855

1856 1857
/// Contains a managed value
const TC_MANAGED: TypeContents =          TypeContents{bits:0b000000100000};
1858

1859 1860
/// &mut with any region
const TC_BORROWED_MUT: TypeContents =     TypeContents{bits:0b000001000000};
1861

1862 1863
/// Mutable content, whether owned or by ref
const TC_MUTABLE: TypeContents =          TypeContents{bits:0b000010000000};
1864

1865 1866
/// Mutable content, whether owned or by ref
const TC_ONCE_CLOSURE: TypeContents =     TypeContents{bits:0b000100000000};
1867

1868 1869
/// Something we estimate to be "big"
const TC_BIG: TypeContents =              TypeContents{bits:0b001000000000};
1870

1871 1872
/// An enum with no variants.
const TC_EMPTY_ENUM: TypeContents =       TypeContents{bits:0b010000000000};
1873

1874 1875
/// All possible contents.
const TC_ALL: TypeContents =              TypeContents{bits:0b011111111111};
1876

1877 1878
pub fn type_is_copyable(cx: ctxt, t: ty::t) -> bool {
    type_contents(cx, t).is_copy(cx)
1879 1880
}

1881 1882
pub fn type_is_durable(cx: ctxt, t: ty::t) -> bool {
    type_contents(cx, t).is_durable(cx)
1883 1884
}

1885 1886 1887
pub fn type_is_owned(cx: ctxt, t: ty::t) -> bool {
    type_contents(cx, t).is_owned(cx)
}
1888

1889 1890 1891
pub fn type_is_const(cx: ctxt, t: ty::t) -> bool {
    type_contents(cx, t).is_const(cx)
}
1892

1893 1894 1895 1896 1897
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 => {}
1898 1899
    }

1900 1901 1902 1903
    let mut cache = LinearMap::new();
    let result = tc_ty(cx, ty, &mut cache);
    cx.tc_cache.insert(ty_id, result);
    return result;
M
Marijn Haverbeke 已提交
1904

1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934
    fn tc_ty(cx: ctxt,
             ty: t,
             cache: &mut LinearMap<uint, TypeContents>) -> TypeContents
    {
        // 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 => {}
        }
1935 1936 1937 1938
        match cx.tc_cache.find(&ty_id) {    // Must check both caches!
            Some(tc) => { return *tc; }
            None => {}
        }
1939 1940 1941 1942 1943 1944 1945 1946 1947 1948
        cache.insert(ty_id, TC_NONE);

        let _i = indenter();

        let mut result = match get(ty).sty {
            // Scalar and unique types are sendable, constant, and owned
            ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
            ty_bare_fn(_) | ty_ptr(_) => {
                TC_NONE
            }
1949

1950 1951 1952
            ty_estr(vstore_uniq) => {
                TC_OWNED_SLICE
            }
M
Marijn Haverbeke 已提交
1953

1954 1955 1956
            ty_closure(ref c) => {
                closure_contents(c)
            }
1957

1958 1959 1960
            ty_box(mt) => {
                TC_MANAGED + nonowned(tc_mt(cx, mt, cache))
            }
1961

1962 1963 1964
            ty_trait(_, _, vstore_uniq) => {
                TC_OWNED_CLOSURE
            }
1965

1966 1967 1968
            ty_trait(_, _, vstore_box) => {
                TC_MANAGED
            }
1969

1970 1971 1972
            ty_trait(_, _, vstore_slice(r)) => {
                borrowed_contents(r, m_imm)
            }
1973

1974 1975 1976 1977
            ty_rptr(r, mt) => {
                borrowed_contents(r, mt.mutbl) +
                    nonowned(tc_mt(cx, mt, cache))
            }
1978

1979 1980 1981
            ty_uniq(mt) => {
                TC_OWNED_POINTER + tc_mt(cx, mt, cache)
            }
1982

1983 1984 1985
            ty_evec(mt, vstore_uniq) => {
                TC_OWNED_SLICE + tc_mt(cx, mt, cache)
            }
1986

1987 1988 1989
            ty_evec(mt, vstore_box) => {
                TC_MANAGED + nonowned(tc_mt(cx, mt, cache))
            }
1990

1991 1992 1993 1994
            ty_evec(mt, vstore_slice(r)) => {
                borrowed_contents(r, mt.mutbl) +
                    nonowned(tc_mt(cx, mt, cache))
            }
1995

1996 1997 1998
            ty_evec(mt, vstore_fixed(_)) => {
                tc_mt(cx, mt, cache)
            }
1999

2000 2001 2002
            ty_estr(vstore_box) => {
                TC_MANAGED
            }
2003

2004 2005 2006
            ty_estr(vstore_slice(r)) => {
                borrowed_contents(r, m_imm)
            }
2007

2008 2009 2010
            ty_estr(vstore_fixed(_)) => {
                TC_NONE
            }
2011

2012 2013 2014 2015 2016
            ty_rec(ref flds) => {
                flds.foldl(
                    TC_NONE,
                    |tc, f| tc + tc_mt(cx, f.mt, cache))
            }
2017

2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028
            ty_struct(did, ref substs) => {
                let flds = struct_fields(cx, did, substs);
                let flds_tc = flds.foldl(
                    TC_NONE,
                    |tc, f| tc + tc_mt(cx, f.mt, cache));
                if ty::has_dtor(cx, did) {
                    flds_tc + TC_DTOR
                } else {
                    flds_tc
                }
            }
2029

2030 2031 2032
            ty_tup(ref tys) => {
                tys.foldl(TC_NONE, |tc, ty| *tc + tc_ty(cx, *ty, cache))
            }
2033

2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047
            ty_enum(did, ref substs) => {
                let variants = substd_enum_variants(cx, did, substs);
                if variants.is_empty() {
                    // we somewhat arbitrary declare that empty enums
                    // are non-copyable
                    TC_EMPTY_ENUM
                } else {
                    variants.foldl(TC_NONE, |tc, variant| {
                        variant.args.foldl(
                            *tc,
                            |tc, arg_ty| *tc + tc_ty(cx, *arg_ty, cache))
                    })
                }
            }
2048

2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060
            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.
                assert p.def_id.crate == ast::local_crate;

                param_bounds_to_contents(
                    cx, cx.ty_param_bounds.get(&p.def_id.node))
            }
2061

2062 2063 2064 2065 2066 2067 2068 2069
            ty_self => {
                // 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
            }
2070

2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083
            ty_infer(_) => {
                // This occurs during coherence, but shouldn't occur at other
                // times.
                TC_ALL
            }

            ty_trait(_, _, vstore_fixed(_)) |
            ty_type |
            ty_opaque_closure_ptr(_) |
            ty_opaque_box |
            ty_unboxed_vec(_) |
            ty_err => {
                cx.sess.bug(~"Asked to compute contents of fictitious type");
2084
            }
2085 2086 2087 2088
        };

        if type_size(cx, ty) > 4 {
            result = result + TC_BIG;
2089
        }
2090

2091 2092 2093
        cache.insert(ty_id, result);
        return result;
    }
2094

2095 2096 2097 2098 2099 2100 2101
    fn tc_mt(cx: ctxt,
             mt: mt,
             cache: &mut LinearMap<uint, TypeContents>) -> TypeContents
    {
        let mc = if mt.mutbl == m_mutbl {TC_MUTABLE} else {TC_NONE};
        mc + tc_ty(cx, mt.ty, cache)
    }
2102

2103 2104 2105 2106 2107
    fn borrowed_contents(region: ty::Region,
                         mutbl: ast::mutability) -> TypeContents
    {
        let mc = if mutbl == m_mutbl {
            TC_MUTABLE + TC_BORROWED_MUT
2108
        } else {
2109 2110 2111 2112 2113 2114 2115 2116 2117
            TC_NONE
        };
        let rc = if region != ty::re_static {
            TC_BORROWED_POINTER
        } else {
            TC_NONE
        };
        mc + rc
    }
2118

2119 2120 2121 2122 2123 2124 2125 2126
    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.
         */
2127

2128 2129
        let mask = TC_MUTABLE.bits | TC_BORROWED_POINTER.bits;
        TypeContents {bits: pointee.bits & mask}
2130 2131
    }

2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161
    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
    }

    fn param_bounds_to_contents(cx: ctxt,
                                bounds: param_bounds) -> TypeContents
    {
        debug!("param_bounds_to_contents()");
        let _i = indenter();

        let r = bounds.foldl(TC_ALL, |tc, bound| {
            debug!("tc = %s, bound = %?", tc.to_str(), bound);
            match *bound {
                bound_copy => tc - TypeContents::nonimplicitly_copyable(cx),
                bound_durable => tc - TypeContents::nondurable(cx),
                bound_owned => tc - TypeContents::nonowned(cx),
                bound_const => tc - TypeContents::nonconst(cx),
                bound_trait(_) => *tc
            }
        });
2162

2163 2164 2165
        debug!("result = %s", r.to_str());
        return r;
    }
2166

2167 2168 2169 2170 2171 2172 2173 2174 2175 2176
    /// gives a rough estimate of how much space it takes to represent
    /// an instance of `ty`.  Used for the mode transition.
    fn type_size(cx: ctxt, ty: t) -> uint {
        match /*bad*/copy get(ty).sty {
          ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
          ty_ptr(_) | ty_box(_) | ty_uniq(_) | ty_estr(vstore_uniq) |
          ty_trait(*) | ty_rptr(*) | ty_evec(_, vstore_uniq) |
          ty_evec(_, vstore_box) | ty_estr(vstore_box) => {
            1
          }
2177

2178 2179 2180 2181 2182 2183
          ty_evec(_, vstore_slice(_)) |
          ty_estr(vstore_slice(_)) |
          ty_bare_fn(*) |
          ty_closure(*) => {
            2
          }
2184

2185 2186 2187
          ty_evec(t, vstore_fixed(n)) => {
            type_size(cx, t.ty) * n
          }
2188

2189 2190 2191
          ty_estr(vstore_fixed(n)) => {
            n
          }
2192

2193 2194 2195
          ty_rec(flds) => {
            flds.foldl(0, |s, f| *s + type_size(cx, f.mt.ty))
          }
2196

2197 2198 2199 2200
          ty_struct(did, ref substs) => {
            let flds = struct_fields(cx, did, substs);
            flds.foldl(0, |s, f| *s + type_size(cx, f.mt.ty))
          }
2201

2202 2203 2204
          ty_tup(tys) => {
            tys.foldl(0, |s, t| *s + type_size(cx, *t))
          }
2205

2206 2207 2208 2209 2210 2211 2212 2213 2214
          ty_enum(did, ref substs) => {
            let variants = substd_enum_variants(cx, did, substs);
            variants.foldl( // find max size of any variant
                0,
                |m, v| uint::max(
                    *m,
                    // find size of this variant:
                    v.args.foldl(0, |s, a| *s + type_size(cx, *a))))
          }
2215

2216 2217 2218
          ty_param(_) | ty_self => {
            1
          }
2219

2220 2221 2222 2223 2224 2225 2226 2227
          ty_infer(_) => {
            cx.sess.bug(~"Asked to compute kind of a type variable");
          }
          ty_type | ty_opaque_closure_ptr(_)
          | ty_opaque_box | ty_unboxed_vec(_) | ty_err => {
            cx.sess.bug(~"Asked to compute kind of fictitious type");
          }
        }
2228 2229 2230
    }
}

2231 2232 2233 2234
pub fn type_moves_by_default(cx: ctxt, ty: t) -> bool {
    type_contents(cx, ty).moves_by_default(cx)
}

2235
// True if instantiating an instance of `r_ty` requires an instance of `r_ty`.
2236
pub fn is_instantiable(cx: ctxt, r_ty: t) -> bool {
2237
    fn type_requires(cx: ctxt, seen: @mut ~[def_id],
2238
                     r_ty: t, ty: t) -> bool {
P
Paul Stansifer 已提交
2239
        debug!("type_requires(%s, %s)?",
2240 2241
               ::util::ppaux::ty_to_str(cx, r_ty),
               ::util::ppaux::ty_to_str(cx, ty));
2242 2243

        let r = {
2244
            get(r_ty).sty == get(ty).sty ||
2245 2246 2247
                subtypes_require(cx, seen, r_ty, ty)
        };

P
Paul Stansifer 已提交
2248
        debug!("type_requires(%s, %s)? %b",
2249 2250
               ::util::ppaux::ty_to_str(cx, r_ty),
               ::util::ppaux::ty_to_str(cx, ty),
P
Paul Stansifer 已提交
2251
               r);
B
Brian Anderson 已提交
2252
        return r;
2253 2254
    }

2255
    fn subtypes_require(cx: ctxt, seen: @mut ~[def_id],
2256
                        r_ty: t, ty: t) -> bool {
P
Paul Stansifer 已提交
2257
        debug!("subtypes_require(%s, %s)?",
2258 2259
               ::util::ppaux::ty_to_str(cx, r_ty),
               ::util::ppaux::ty_to_str(cx, ty));
2260

2261
        let r = match /*bad*/copy get(ty).sty {
2262 2263 2264 2265 2266 2267
          ty_nil |
          ty_bot |
          ty_bool |
          ty_int(_) |
          ty_uint(_) |
          ty_float(_) |
2268
          ty_estr(_) |
2269 2270
          ty_bare_fn(_) |
          ty_closure(_) |
2271
          ty_infer(_) |
2272
          ty_err |
2273
          ty_param(_) |
2274
          ty_self |
2275 2276 2277
          ty_type |
          ty_opaque_box |
          ty_opaque_closure_ptr(_) |
2278
          ty_evec(_, _) |
B
Brian Anderson 已提交
2279
          ty_unboxed_vec(_) => {
2280 2281 2282 2283
            false
          }
          ty_box(mt) |
          ty_uniq(mt) |
B
Brian Anderson 已提交
2284
          ty_rptr(_, mt) => {
B
Brian Anderson 已提交
2285
            return type_requires(cx, seen, r_ty, mt.ty);
2286 2287
          }

2288
          ty_ptr(*) => {
2289 2290 2291
            false           // unsafe ptrs can always be NULL
          }

B
Brian Anderson 已提交
2292
          ty_rec(fields) => {
B
Brian Anderson 已提交
2293
            do vec::any(fields) |field| {
2294 2295 2296 2297
                type_requires(cx, seen, r_ty, field.mt.ty)
            }
          }

2298
          ty_trait(_, _, _) => {
2299 2300 2301
            false
          }

2302
          ty_struct(ref did, _) if vec::contains(*seen, did) => {
2303 2304 2305
            false
          }

2306
          ty_struct(did, ref substs) => {
2307
              seen.push(did);
2308
              let r = vec::any(struct_fields(cx, did, substs),
2309
                               |f| type_requires(cx, seen, r_ty, f.mt.ty));
N
Niko Matsakis 已提交
2310
              seen.pop();
2311 2312 2313
            r
          }

B
Brian Anderson 已提交
2314
          ty_tup(ts) => {
N
Niko Matsakis 已提交
2315
            vec::any(ts, |t| type_requires(cx, seen, r_ty, *t))
2316 2317
          }

N
Niko Matsakis 已提交
2318
          ty_enum(ref did, _) if vec::contains(*seen, did) => {
2319 2320 2321
            false
          }

2322 2323 2324 2325 2326
            ty_enum(did, ref substs) => {
                seen.push(did);
                let vs = enum_variants(cx, did);
                let r = vec::len(*vs) > 0u && vec::all(*vs, |variant| {
                    vec::any(variant.args, |aty| {
N
Niko Matsakis 已提交
2327
                        let sty = subst(cx, substs, *aty);
2328 2329 2330
                        type_requires(cx, seen, r_ty, sty)
                    })
                });
N
Niko Matsakis 已提交
2331
                seen.pop();
2332 2333
                r
            }
2334 2335
        };

P
Paul Stansifer 已提交
2336
        debug!("subtypes_require(%s, %s)? %b",
2337 2338
               ::util::ppaux::ty_to_str(cx, r_ty),
               ::util::ppaux::ty_to_str(cx, ty),
P
Paul Stansifer 已提交
2339
               r);
2340

B
Brian Anderson 已提交
2341
        return r;
2342 2343
    }

2344
    let seen = @mut ~[];
2345 2346 2347
    !subtypes_require(cx, seen, r_ty, r_ty)
}

2348 2349 2350 2351
pub fn type_structurally_contains(cx: ctxt,
                                  ty: t,
                                  test: fn(x: &sty) -> bool)
                               -> bool {
2352
    let sty = &get(ty).sty;
2353 2354
    debug!("type_structurally_contains: %s",
           ::util::ppaux::ty_to_str(cx, ty));
B
Brian Anderson 已提交
2355
    if test(sty) { return true; }
2356
    match /*bad*/copy *sty {
N
Niko Matsakis 已提交
2357
      ty_enum(did, ref substs) => {
2358
        for vec::each(*enum_variants(cx, did)) |variant| {
B
Brian Anderson 已提交
2359
            for variant.args.each |aty| {
2360
                let sty = subst(cx, substs, *aty);
B
Brian Anderson 已提交
2361
                if type_structurally_contains(cx, sty, test) { return true; }
2362
            }
2363
        }
B
Brian Anderson 已提交
2364
        return false;
M
Marijn Haverbeke 已提交
2365
      }
B
Brian Anderson 已提交
2366
      ty_rec(fields) => {
B
Brian Anderson 已提交
2367
        for fields.each |field| {
B
Brian Anderson 已提交
2368 2369 2370
            if type_structurally_contains(cx, field.mt.ty, test) {
                return true;
            }
2371
        }
B
Brian Anderson 已提交
2372
        return false;
M
Marijn Haverbeke 已提交
2373
      }
2374 2375
      ty_struct(did, ref substs) => {
        for lookup_struct_fields(cx, did).each |field| {
2376
            let ft = lookup_field_type(cx, did, field.id, substs);
B
Brian Anderson 已提交
2377
            if type_structurally_contains(cx, ft, test) { return true; }
2378
        }
B
Brian Anderson 已提交
2379
        return false;
2380 2381
      }

B
Brian Anderson 已提交
2382
      ty_tup(ts) => {
B
Brian Anderson 已提交
2383
        for ts.each |tt| {
2384
            if type_structurally_contains(cx, *tt, test) { return true; }
2385
        }
B
Brian Anderson 已提交
2386
        return false;
2387
      }
B
Brian Anderson 已提交
2388
      ty_evec(mt, vstore_fixed(_)) => {
B
Brian Anderson 已提交
2389
        return type_structurally_contains(cx, mt.ty, test);
2390
      }
B
Brian Anderson 已提交
2391
      _ => return false
M
Marijn Haverbeke 已提交
2392 2393 2394
    }
}

2395
pub fn type_structurally_contains_uniques(cx: ctxt, ty: t) -> bool {
B
Brian Anderson 已提交
2396
    return type_structurally_contains(cx, ty, |sty| {
N
Niko Matsakis 已提交
2397
        match *sty {
2398 2399
          ty_uniq(_) |
          ty_evec(_, vstore_uniq) |
B
Brian Anderson 已提交
2400 2401
          ty_estr(vstore_uniq) => true,
          _ => false,
2402
        }
2403
    });
2404 2405
}

2406
pub fn type_is_integral(ty: t) -> bool {
2407
    match get(ty).sty {
2408
      ty_infer(IntVar(_)) | ty_int(_) | ty_uint(_) => true,
B
Brian Anderson 已提交
2409
      _ => false
M
Marijn Haverbeke 已提交
2410 2411 2412
    }
}

2413
pub fn type_is_char(ty: t) -> bool {
2414 2415 2416 2417 2418 2419
    match get(ty).sty {
        ty_int(ty_char) => true,
        _ => false
    }
}

2420
pub fn type_is_fp(ty: t) -> bool {
2421
    match get(ty).sty {
2422
      ty_infer(FloatVar(_)) | ty_float(_) => true,
B
Brian Anderson 已提交
2423
      _ => false
M
Marijn Haverbeke 已提交
2424 2425 2426
    }
}

2427
pub fn type_is_numeric(ty: t) -> bool {
B
Brian Anderson 已提交
2428
    return type_is_integral(ty) || type_is_fp(ty);
2429 2430
}

2431
pub fn type_is_signed(ty: t) -> bool {
2432
    match get(ty).sty {
B
Brian Anderson 已提交
2433 2434
      ty_int(_) => true,
      _ => false
M
Marijn Haverbeke 已提交
2435 2436 2437
    }
}

2438 2439
// Whether a type is Plain Old Data -- meaning it does not contain pointers
// that the cycle collector might care about.
2440
pub fn type_is_pod(cx: ctxt, ty: t) -> bool {
2441
    let mut result = true;
2442
    match /*bad*/copy get(ty).sty {
B
Brian Anderson 已提交
2443
      // Scalar types
2444
      ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) |
2445
      ty_type | ty_ptr(_) | ty_bare_fn(_) => result = true,
B
Brian Anderson 已提交
2446
      // Boxed types
2447
      ty_box(_) | ty_uniq(_) | ty_closure(_) |
2448 2449
      ty_estr(vstore_uniq) | ty_estr(vstore_box) |
      ty_evec(_, vstore_uniq) | ty_evec(_, vstore_box) |
2450
      ty_trait(_, _, _) | ty_rptr(_,_) | ty_opaque_box => result = false,
B
Brian Anderson 已提交
2451
      // Structural types
N
Niko Matsakis 已提交
2452
      ty_enum(did, ref substs) => {
2453
        let variants = enum_variants(cx, did);
2454
        for vec::each(*variants) |variant| {
2455
            let tup_ty = mk_tup(cx, /*bad*/copy variant.args);
B
Brian Anderson 已提交
2456 2457

            // Perform any type parameter substitutions.
2458
            let tup_ty = subst(cx, substs, tup_ty);
B
Brian Anderson 已提交
2459
            if !type_is_pod(cx, tup_ty) { result = false; }
2460
        }
B
Brian Anderson 已提交
2461
      }
B
Brian Anderson 已提交
2462
      ty_rec(flds) => {
B
Brian Anderson 已提交
2463
        for flds.each |f| {
B
Brian Anderson 已提交
2464
            if !type_is_pod(cx, f.mt.ty) { result = false; }
P
Patrick Walton 已提交
2465
        }
B
Brian Anderson 已提交
2466
      }
B
Brian Anderson 已提交
2467
      ty_tup(elts) => {
2468
        for elts.each |elt| { if !type_is_pod(cx, *elt) { result = false; } }
B
Brian Anderson 已提交
2469
      }
B
Brian Anderson 已提交
2470 2471
      ty_estr(vstore_fixed(_)) => result = true,
      ty_evec(mt, vstore_fixed(_)) | ty_unboxed_vec(mt) => {
2472 2473
        result = type_is_pod(cx, mt.ty);
      }
B
Brian Anderson 已提交
2474 2475
      ty_param(_) => result = false,
      ty_opaque_closure_ptr(_) => result = true,
2476 2477
      ty_struct(did, ref substs) => {
        result = vec::any(lookup_struct_fields(cx, did), |f| {
2478 2479 2480
            let fty = ty::lookup_item_type(cx, f.id);
            let sty = subst(cx, substs, fty.ty);
            type_is_pod(cx, sty)
2481
        });
2482
      }
2483

B
Brian Anderson 已提交
2484
      ty_estr(vstore_slice(*)) | ty_evec(_, vstore_slice(*)) => {
2485 2486 2487
        result = false;
      }

2488
      ty_infer(*) | ty_self(*) | ty_err => {
2489
        cx.sess.bug(~"non concrete type in type_is_pod");
2490
      }
P
Patrick Walton 已提交
2491 2492
    }

B
Brian Anderson 已提交
2493
    return result;
P
Patrick Walton 已提交
2494 2495
}

2496
pub fn type_is_enum(ty: t) -> bool {
2497
    match get(ty).sty {
B
Brian Anderson 已提交
2498 2499
      ty_enum(_, _) => return true,
      _ => return false
2500 2501 2502
    }
}

P
Patrick Walton 已提交
2503
// Whether a type is enum like, that is a enum type with only nullary
2504
// constructors
2505
pub fn type_is_c_like_enum(cx: ctxt, ty: t) -> bool {
2506
    match get(ty).sty {
2507
      ty_enum(did, _) => {
2508
        let variants = enum_variants(cx, did);
B
Brian Anderson 已提交
2509
        let some_n_ary = vec::any(*variants, |v| vec::len(v.args) > 0u);
B
Brian Anderson 已提交
2510
        return !some_n_ary;
2511
      }
B
Brian Anderson 已提交
2512
      _ => return false
2513 2514 2515
    }
}

2516
pub fn type_param(ty: t) -> Option<uint> {
2517
    match get(ty).sty {
B
Brian Anderson 已提交
2518
      ty_param(p) => return Some(p.idx),
B
Brian Anderson 已提交
2519
      _ => {/* fall through */ }
2520
    }
B
Brian Anderson 已提交
2521
    return None;
2522 2523
}

2524 2525
// Returns the type and mutability of *t.
//
2526 2527
// The parameter `explicit` indicates if this is an *explicit* dereference.
// Some types---notably unsafe ptrs---can only be dereferenced explicitly.
2528
pub fn deref(cx: ctxt, t: t, explicit: bool) -> Option<mt> {
2529
    deref_sty(cx, &get(t).sty, explicit)
2530
}
2531

2532
pub fn deref_sty(cx: ctxt, sty: &sty, explicit: bool) -> Option<mt> {
N
Niko Matsakis 已提交
2533
    match *sty {
B
Brian Anderson 已提交
2534
      ty_rptr(_, mt) | ty_box(mt) | ty_uniq(mt) => {
B
Brian Anderson 已提交
2535
        Some(mt)
2536 2537
      }

2538
      ty_ptr(mt) if explicit => {
B
Brian Anderson 已提交
2539
        Some(mt)
2540 2541
      }

N
Niko Matsakis 已提交
2542
      ty_enum(did, ref substs) => {
2543 2544 2545
        let variants = enum_variants(cx, did);
        if vec::len(*variants) == 1u && vec::len(variants[0].args) == 1u {
            let v_t = subst(cx, substs, variants[0].args[0]);
2546
            Some(mt {ty: v_t, mutbl: ast::m_imm})
2547
        } else {
B
Brian Anderson 已提交
2548
            None
2549 2550 2551
        }
      }

2552 2553
      ty_struct(did, ref substs) => {
        let fields = struct_fields(cx, did, substs);
2554 2555
        if fields.len() == 1 && fields[0].ident ==
                syntax::parse::token::special_idents::unnamed_field {
2556
            Some(mt {ty: fields[0].mt.ty, mutbl: ast::m_imm})
2557 2558 2559 2560 2561
        } else {
            None
        }
      }

B
Brian Anderson 已提交
2562
      _ => None
2563 2564 2565
    }
}

2566
pub fn type_autoderef(cx: ctxt, t: t) -> t {
2567
    let mut t = t;
2568
    loop {
2569
        match deref(cx, t, false) {
B
Brian Anderson 已提交
2570 2571
          None => return t,
          Some(mt) => t = mt.ty
2572 2573
        }
    }
2574 2575 2576
}

// Returns the type and mutability of t[i]
2577
pub fn index(cx: ctxt, t: t) -> Option<mt> {
2578
    index_sty(cx, &get(t).sty)
2579 2580
}

2581
pub fn index_sty(cx: ctxt, sty: &sty) -> Option<mt> {
N
Niko Matsakis 已提交
2582
    match *sty {
B
Brian Anderson 已提交
2583
      ty_evec(mt, _) => Some(mt),
2584
      ty_estr(_) => Some(mt {ty: mk_u8(cx), mutbl: ast::m_imm}),
B
Brian Anderson 已提交
2585
      _ => None
2586
    }
2587 2588
}

2589
impl to_bytes::IterBytes for bound_region {
2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600
    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
        match *self {
          ty::br_self => 0u8.iter_bytes(lsb0, f),

          ty::br_anon(ref idx) =>
          to_bytes::iter_bytes_2(&1u8, idx, lsb0, f),

          ty::br_named(ref ident) =>
          to_bytes::iter_bytes_2(&2u8, ident, lsb0, f),

          ty::br_cap_avoid(ref id, ref br) =>
2601 2602 2603 2604
          to_bytes::iter_bytes_3(&3u8, id, br, lsb0, f),

          ty::br_fresh(ref x) =>
          to_bytes::iter_bytes_2(&4u8, x, lsb0, f)
2605 2606 2607
        }
    }
}
2608

2609
impl to_bytes::IterBytes for Region {
2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622
    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
        match *self {
          re_bound(ref br) =>
          to_bytes::iter_bytes_2(&0u8, br, lsb0, f),

          re_free(ref id, ref br) =>
          to_bytes::iter_bytes_3(&1u8, id, br, lsb0, f),

          re_scope(ref id) =>
          to_bytes::iter_bytes_2(&2u8, id, lsb0, f),

          re_infer(ref id) =>
          to_bytes::iter_bytes_2(&3u8, id, lsb0, f),
2623

2624 2625 2626 2627 2628
          re_static => 4u8.iter_bytes(lsb0, f)
        }
    }
}

2629
impl to_bytes::IterBytes for vstore {
2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642
    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
        match *self {
          vstore_fixed(ref u) =>
          to_bytes::iter_bytes_2(&0u8, u, lsb0, f),

          vstore_uniq => 1u8.iter_bytes(lsb0, f),
          vstore_box => 2u8.iter_bytes(lsb0, f),

          vstore_slice(ref r) =>
          to_bytes::iter_bytes_2(&3u8, r, lsb0, f),
        }
    }
}
2643

2644
impl to_bytes::IterBytes for substs {
2645 2646 2647 2648 2649 2650
    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
          to_bytes::iter_bytes_3(&self.self_r,
                                 &self.self_ty,
                                 &self.tps, lsb0, f)
    }
}
2651

2652
impl to_bytes::IterBytes for mt {
2653 2654 2655 2656 2657
    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
          to_bytes::iter_bytes_2(&self.ty,
                                 &self.mutbl, lsb0, f)
    }
}
2658

2659
impl to_bytes::IterBytes for field {
2660 2661 2662 2663 2664
    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
          to_bytes::iter_bytes_2(&self.ident,
                                 &self.mt, lsb0, f)
    }
}
2665

2666
impl to_bytes::IterBytes for arg {
2667 2668 2669 2670 2671
    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
        to_bytes::iter_bytes_2(&self.mode,
                               &self.ty, lsb0, f)
    }
}
2672

2673
impl to_bytes::IterBytes for FnSig {
2674 2675 2676 2677 2678 2679
    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
        to_bytes::iter_bytes_2(&self.inputs,
                               &self.output,
                               lsb0, f);
    }
}
2680

2681
impl to_bytes::IterBytes for sty {
2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706
    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
        match *self {
          ty_nil => 0u8.iter_bytes(lsb0, f),
          ty_bool => 1u8.iter_bytes(lsb0, f),

          ty_int(ref t) =>
          to_bytes::iter_bytes_2(&2u8, t, lsb0, f),

          ty_uint(ref t) =>
          to_bytes::iter_bytes_2(&3u8, t, lsb0, f),

          ty_float(ref t) =>
          to_bytes::iter_bytes_2(&4u8, t, lsb0, f),

          ty_estr(ref v) =>
          to_bytes::iter_bytes_2(&5u8, v, lsb0, f),

          ty_enum(ref did, ref substs) =>
          to_bytes::iter_bytes_3(&6u8, did, substs, lsb0, f),

          ty_box(ref mt) =>
          to_bytes::iter_bytes_2(&7u8, mt, lsb0, f),

          ty_evec(ref mt, ref v) =>
          to_bytes::iter_bytes_3(&8u8, mt, v, lsb0, f),
2707 2708 2709 2710 2711 2712 2713 2714 2715 2716

          ty_unboxed_vec(ref mt) =>
          to_bytes::iter_bytes_2(&9u8, mt, lsb0, f),

          ty_tup(ref ts) =>
          to_bytes::iter_bytes_2(&10u8, ts, lsb0, f),

          ty_rec(ref fs) =>
          to_bytes::iter_bytes_2(&11u8, fs, lsb0, f),

2717
          ty_bare_fn(ref ft) =>
2718
          to_bytes::iter_bytes_2(&12u8, ft, lsb0, f),
2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744

          ty_self => 13u8.iter_bytes(lsb0, f),

          ty_infer(ref v) =>
          to_bytes::iter_bytes_2(&14u8, v, lsb0, f),

          ty_param(ref p) =>
          to_bytes::iter_bytes_2(&15u8, p, lsb0, f),

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

          ty_ptr(ref mt) =>
          to_bytes::iter_bytes_2(&18u8, mt, lsb0, f),

          ty_uniq(ref mt) =>
          to_bytes::iter_bytes_2(&19u8, mt, lsb0, f),

          ty_trait(ref did, ref substs, ref v) =>
          to_bytes::iter_bytes_4(&20u8, did, substs, v, lsb0, f),

          ty_opaque_closure_ptr(ref ck) =>
          to_bytes::iter_bytes_2(&21u8, ck, lsb0, f),

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

2745
          ty_struct(ref did, ref substs) =>
2746 2747 2748 2749
          to_bytes::iter_bytes_3(&23u8, did, substs, lsb0, f),

          ty_rptr(ref r, ref mt) =>
          to_bytes::iter_bytes_3(&24u8, r, mt, lsb0, f),
2750

2751 2752 2753 2754
          ty_err => 25u8.iter_bytes(lsb0, f),

          ty_closure(ref ct) =>
          to_bytes::iter_bytes_2(&26u8, ct, lsb0, f),
2755 2756 2757 2758
        }
    }
}

2759
pub fn br_hashmap<V:Copy>() -> HashMap<bound_region, V> {
2760
    oldmap::HashMap()
N
Niko Matsakis 已提交
2761 2762
}

2763
pub fn node_id_to_type(cx: ctxt, id: ast::node_id) -> t {
2764
    //io::println(fmt!("%?/%?", id, cx.node_types.len()));
2765
    match oldsmallintmap::find(*cx.node_types, id as uint) {
B
Brian Anderson 已提交
2766 2767
       Some(t) => t,
       None => cx.sess.bug(
2768
           fmt!("node_id_to_type: no type for node `%s`",
P
Paul Stansifer 已提交
2769
                ast_map::node_id_to_str(cx.items, id,
P
Paul Stansifer 已提交
2770
                                        cx.sess.parse_sess.interner)))
T
Tim Chevalier 已提交
2771
    }
2772 2773
}

2774
pub fn node_id_to_type_params(cx: ctxt, id: ast::node_id) -> ~[t] {
2775
    match cx.node_type_substs.find(&id) {
B
Brian Anderson 已提交
2776 2777
      None => return ~[],
      Some(ts) => return ts
2778 2779 2780
    }
}

2781
fn node_id_has_type_params(cx: ctxt, id: ast::node_id) -> bool {
2782
    cx.node_type_substs.contains_key(&id)
2783 2784
}

2785
// Type accessors for substructures of types
2786
pub fn ty_fn_args(fty: t) -> ~[arg] {
2787
    match get(fty).sty {
2788 2789 2790
        ty_bare_fn(ref f) => copy f.sig.inputs,
        ty_closure(ref f) => copy f.sig.inputs,
        ref s => {
2791
            fail!(fmt!("ty_fn_args() called on non-fn type: %?", s))
2792
        }
2793 2794 2795
    }
}

2796
pub fn ty_closure_sigil(fty: t) -> Sigil {
2797
    match get(fty).sty {
2798 2799
        ty_closure(ref f) => f.sigil,
        ref s => {
2800 2801
            fail!(fmt!("ty_closure_sigil() called on non-closure type: %?",
                       s))
2802
        }
M
Marijn Haverbeke 已提交
2803
    }
G
Graydon Hoare 已提交
2804 2805
}

2806
pub fn ty_fn_purity(fty: t) -> ast::purity {
2807
    match get(fty).sty {
2808 2809 2810
        ty_bare_fn(ref f) => f.purity,
        ty_closure(ref f) => f.purity,
        ref s => {
2811
            fail!(fmt!("ty_fn_purity() called on non-fn type: %?", s))
2812
        }
2813 2814 2815
    }
}

2816
pub pure fn ty_fn_ret(fty: t) -> t {
2817
    match get(fty).sty {
2818 2819 2820
        ty_bare_fn(ref f) => f.sig.output,
        ty_closure(ref f) => f.sig.output,
        ref s => {
2821
            fail!(fmt!("ty_fn_ret() called on non-fn type: %?", s))
2822
        }
2823
    }
G
Graydon Hoare 已提交
2824 2825
}

2826
fn is_fn_ty(fty: t) -> bool {
2827
    match get(fty).sty {
2828 2829 2830
        ty_bare_fn(_) => true,
        ty_closure(_) => true,
        _ => false
2831 2832 2833
    }
}

2834
pub pure fn ty_vstore(ty: t) -> vstore {
2835 2836 2837
    match get(ty).sty {
        ty_evec(_, vstore) => vstore,
        ty_estr(vstore) => vstore,
2838
        ref s => fail!(fmt!("ty_vstore() called on invalid sty: %?", s))
2839 2840 2841
    }
}

2842
pub fn ty_region(ty: t) -> Region {
2843
    match get(ty).sty {
2844
      ty_rptr(r, _) => r,
2845 2846
      ty_evec(_, vstore_slice(r)) => r,
      ty_estr(vstore_slice(r)) => r,
2847
      ref s => fail!(fmt!("ty_region() invoked on in appropriate ty: %?",
2848
          (*s)))
2849
    }
G
Graydon Hoare 已提交
2850 2851
}

2852
pub fn replace_closure_return_type(tcx: ctxt, fn_type: t, ret_type: t) -> t {
2853 2854 2855 2856 2857 2858
    /*!
     *
     * Returns a new function type based on `fn_type` but returning a value of
     * type `ret_type` instead. */

    match ty::get(fn_type).sty {
2859 2860 2861 2862
        ty::ty_closure(ref fty) => {
            ty::mk_closure(tcx, ClosureTy {
                sig: FnSig {output: ret_type, ..copy fty.sig},
                ..copy *fty
2863 2864 2865 2866 2867 2868 2869 2870 2871 2872
            })
        }
        _ => {
            tcx.sess.bug(fmt!(
                "replace_fn_ret() invoked with non-fn-type: %s",
                ty_to_str(tcx, fn_type)));
        }
    }
}

2873
// Returns a vec of all the input and output types of fty.
2874
pub fn tys_in_fn_sig(sig: &FnSig) -> ~[t] {
2875
    vec::append_one(sig.inputs.map(|a| a.ty), sig.output)
2876 2877
}

2878
// Type accessors for AST nodes
2879
pub fn block_ty(cx: ctxt, b: &ast::blk) -> t {
B
Brian Anderson 已提交
2880
    return node_id_to_type(cx, b.node.id);
2881
}
2882 2883


2884 2885
// Returns the type of a pattern as a monotype. Like @expr_ty, this function
// doesn't provide type parameter substitutions.
2886
pub fn pat_ty(cx: ctxt, pat: @ast::pat) -> t {
B
Brian Anderson 已提交
2887
    return node_id_to_type(cx, pat.id);
2888 2889
}

2890

2891 2892
// Returns the type of an expression as a monotype.
//
2893 2894 2895 2896 2897 2898
// 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
2899
// ask for the type of "id" in "id(3)", it will return "fn(&int) -> int"
2900
// instead of "fn(t) -> T with T = int". If this isn't what you want, see
2901
// expr_ty_params_and_ty() below.
2902
pub fn expr_ty(cx: ctxt, expr: @ast::expr) -> t {
B
Brian Anderson 已提交
2903
    return node_id_to_type(cx, expr.id);
2904 2905
}

2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921
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);

2922
    return match cx.adjustments.find(&expr.id) {
2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994
        None => unadjusted_ty,

        Some(adj) => {
            let mut adjusted_ty = unadjusted_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(
                            expr.span,
                            fmt!("The %uth autoderef failed: %s",
                                 i, ty_to_str(cx,
                                              adjusted_ty)));
                    }
                }
            }

            match adj.autoref {
                None => adjusted_ty,
                Some(ref autoref) => {
                    match autoref.kind {
                        AutoPtr => {
                            mk_rptr(cx, autoref.region,
                                    mt {ty: adjusted_ty,
                                        mutbl: autoref.mutbl})
                        }

                        AutoBorrowVec => {
                            borrow_vec(cx, expr, autoref, adjusted_ty)
                        }

                        AutoBorrowVecRef => {
                            adjusted_ty = borrow_vec(cx, expr, autoref,
                                                     adjusted_ty);
                            mk_rptr(cx, autoref.region,
                                    mt {ty: adjusted_ty, mutbl: ast::m_imm})
                        }

                        AutoBorrowFn => {
                            borrow_fn(cx, expr, autoref, adjusted_ty)
                        }
                    }
                }
            }
        }
    };

    fn borrow_vec(cx: ctxt, expr: @ast::expr,
                  autoref: &AutoRef, ty: ty::t) -> ty::t {
        match get(ty).sty {
            ty_evec(mt, _) => {
                ty::mk_evec(cx, mt {ty: mt.ty, mutbl: autoref.mutbl},
                            vstore_slice(autoref.region))
            }

            ty_estr(_) => {
                ty::mk_estr(cx, vstore_slice(autoref.region))
            }

            ref s => {
                cx.sess.span_bug(
                    expr.span,
                    fmt!("borrow-vec associated with bad sty: %?",
                         s));
            }
        }
    }

    fn borrow_fn(cx: ctxt, expr: @ast::expr,
                 autoref: &AutoRef, ty: ty::t) -> ty::t {
        match get(ty).sty {
2995 2996 2997 2998 2999 3000
            ty_closure(ref fty) => {
                ty::mk_closure(cx, ClosureTy {
                    sigil: BorrowedSigil,
                    region: autoref.region,
                    ..copy *fty
                })
3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012
            }

            ref s => {
                cx.sess.span_bug(
                    expr.span,
                    fmt!("borrow-fn associated with bad sty: %?",
                         s));
            }
        }
    }
}

3013 3014 3015
pub fn expr_ty_params_and_ty(cx: ctxt,
                             expr: @ast::expr)
                          -> {params: ~[t], ty: t} {
B
Brian Anderson 已提交
3016
    return {params: node_id_to_type_params(cx, expr.id),
M
Marijn Haverbeke 已提交
3017
         ty: node_id_to_type(cx, expr.id)};
3018 3019
}

3020
pub fn expr_has_ty_params(cx: ctxt, expr: @ast::expr) -> bool {
B
Brian Anderson 已提交
3021
    return node_id_has_type_params(cx, expr.id);
3022 3023
}

3024 3025
pub fn method_call_bounds(tcx: ctxt, method_map: typeck::method_map,
                          id: ast::node_id)
B
Brian Anderson 已提交
3026
    -> Option<@~[param_bounds]> {
3027
    do method_map.find(&id).map |method| {
3028 3029
        match method.origin {
          typeck::method_static(did) => {
3030 3031
            // n.b.: When we encode impl methods, the bounds
            // that we encode include both the impl bounds
3032 3033 3034
            // and then the method bounds themselves...
            ty::lookup_item_type(tcx, did).bounds
          }
3035 3036 3037
          typeck::method_param(typeck::method_param {
              trait_id: trt_id,
              method_num: n_mth, _}) |
3038
          typeck::method_trait(trt_id, n_mth, _) |
3039 3040
          typeck::method_self(trt_id, n_mth) |
          typeck::method_super(trt_id, n_mth) => {
3041 3042 3043 3044 3045
            // ...trait methods bounds, in contrast, include only the
            // method bounds, so we must preprend the tps from the
            // trait itself.  This ought to be harmonized.
            let trt_bounds =
                ty::lookup_item_type(tcx, trt_id).bounds;
3046 3047
            let mth = /*bad*/copy ty::trait_methods(tcx, trt_id)[n_mth];
            @(vec::append(/*bad*/copy *trt_bounds, *mth.tps))
3048 3049 3050 3051 3052
          }
        }
    }
}

3053
fn resolve_expr(tcx: ctxt, expr: @ast::expr) -> ast::def {
3054
    match tcx.def_map.find(&expr.id) {
3055 3056 3057 3058 3059 3060 3061 3062
        Some(def) => def,
        None => {
            tcx.sess.span_bug(expr.span, fmt!(
                "No def-map entry for expr %?", expr.id));
        }
    }
}

3063 3064 3065
pub fn expr_is_lval(tcx: ctxt,
                    method_map: typeck::method_map,
                    e: @ast::expr) -> bool {
3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076
    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.
3077
pub enum ExprKind {
3078 3079 3080 3081 3082 3083
    LvalueExpr,
    RvalueDpsExpr,
    RvalueDatumExpr,
    RvalueStmtExpr
}

3084 3085 3086
pub fn expr_kind(tcx: ctxt,
                 method_map: typeck::method_map,
                 expr: @ast::expr) -> ExprKind {
3087
    if method_map.contains_key(&expr.id) {
3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100
        // Overloaded operations are generally calls, and hence they are
        // generated via DPS.  However, assign_op (e.g., `x += y`) is an
        // exception, as its result is always unit.
        return match expr.node {
            ast::expr_assign_op(*) => RvalueStmtExpr,
            _ => RvalueDpsExpr
        };
    }

    match expr.node {
        ast::expr_path(*) => {
            match resolve_expr(tcx, expr) {
                ast::def_fn(*) | ast::def_static_method(*) |
3101
                ast::def_variant(*) | ast::def_struct(*) => RvalueDpsExpr,
3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112

                // 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 已提交
3113
                def => {
3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127
                    tcx.sess.span_bug(expr.span, fmt!(
                        "Uncategorized def for expr %?: %?",
                        expr.id, def));
                }
            }
        }

        ast::expr_unary(ast::deref, _) |
        ast::expr_field(*) |
        ast::expr_index(*) => {
            LvalueExpr
        }

        ast::expr_call(*) |
3128
        ast::expr_method_call(*) |
3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140
        ast::expr_rec(*) |
        ast::expr_struct(*) |
        ast::expr_tup(*) |
        ast::expr_if(*) |
        ast::expr_match(*) |
        ast::expr_fn(*) |
        ast::expr_fn_block(*) |
        ast::expr_loop_body(*) |
        ast::expr_do_body(*) |
        ast::expr_block(*) |
        ast::expr_copy(*) |
        ast::expr_repeat(*) |
J
John Clements 已提交
3141
        ast::expr_lit(@codemap::spanned {node: lit_str(_), _}) |
3142
        ast::expr_vstore(_, ast::expr_vstore_slice) |
3143
        ast::expr_vstore(_, ast::expr_vstore_mut_slice) |
3144
        ast::expr_vstore(_, ast::expr_vstore_fixed(_)) |
3145 3146 3147 3148 3149
        ast::expr_vec(*) => {
            RvalueDpsExpr
        }

        ast::expr_cast(*) => {
3150
            match oldsmallintmap::find(*tcx.node_types, expr.id as uint) {
3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191
                Some(t) => {
                    if ty::type_is_immediate(t) {
                        RvalueDatumExpr
                    } else {
                        RvalueDpsExpr
                    }
                }
                None => {
                    // Technically, it should not happen that the expr is not
                    // present within the table.  However, it DOES happen
                    // during type check, because the final types from the
                    // expressions are not yet recorded in the tcx.  At that
                    // time, though, we are only interested in knowing lvalue
                    // vs rvalue.  It would be better to base this decision on
                    // the AST type in cast node---but (at the time of this
                    // writing) it's not easy to distinguish casts to traits
                    // from other casts based on the AST.  This should be
                    // easier in the future, when casts to traits would like
                    // like @Foo, ~Foo, or &Foo.
                    RvalueDatumExpr
                }
            }
        }

        ast::expr_break(*) |
        ast::expr_again(*) |
        ast::expr_ret(*) |
        ast::expr_log(*) |
        ast::expr_assert(*) |
        ast::expr_while(*) |
        ast::expr_loop(*) |
        ast::expr_assign(*) |
        ast::expr_swap(*) |
        ast::expr_assign_op(*) => {
            RvalueStmtExpr
        }

        ast::expr_lit(_) | // Note: lit_str is carved out above
        ast::expr_unary(*) |
        ast::expr_addr_of(*) |
        ast::expr_binary(*) |
3192
        ast::expr_vstore(_, ast::expr_vstore_box) |
3193
        ast::expr_vstore(_, ast::expr_vstore_mut_box) |
3194
        ast::expr_vstore(_, ast::expr_vstore_uniq) => {
3195 3196 3197
            RvalueDatumExpr
        }

3198 3199
        ast::expr_paren(e) => expr_kind(tcx, method_map, e),

3200 3201 3202 3203 3204
        ast::expr_mac(*) => {
            tcx.sess.span_bug(
                expr.span,
                ~"macro expression remains after expansion");
        }
M
Marijn Haverbeke 已提交
3205 3206 3207
    }
}

3208
pub fn stmt_node_id(s: @ast::stmt) -> ast::node_id {
3209
    match s.node {
B
Brian Anderson 已提交
3210
      ast::stmt_decl(_, id) | stmt_expr(_, id) | stmt_semi(_, id) => {
B
Brian Anderson 已提交
3211
        return id;
3212
      }
3213
      ast::stmt_mac(*) => fail!(~"unexpanded macro in trans")
3214 3215 3216
    }
}

3217
pub fn field_idx(id: ast::ident, fields: &[field]) -> Option<uint> {
3218
    let mut i = 0u;
B
Brian Anderson 已提交
3219 3220
    for fields.each |f| { if f.ident == id { return Some(i); } i += 1u; }
    return None;
3221 3222
}

3223 3224
pub fn field_idx_strict(tcx: ty::ctxt, id: ast::ident, fields: &[field])
                     -> uint {
3225 3226 3227 3228 3229 3230 3231 3232
    let mut i = 0u;
    for fields.each |f| { if f.ident == id { return i; } i += 1u; }
    tcx.sess.bug(fmt!(
        "No field named `%s` found in the list of fields `%?`",
        tcx.sess.str_of(id),
        fields.map(|f| tcx.sess.str_of(f.ident))));
}

3233
pub fn get_field(tcx: ctxt, rec_ty: t, id: ast::ident) -> field {
3234
    match vec::find(get_fields(rec_ty), |f| f.ident == id) {
B
Brian Anderson 已提交
3235
      Some(f) => f,
3236
      // Do we only call this when we know the field is legit?
3237
      None => fail!(fmt!("get_field: ty doesn't have a field %s",
3238
                         tcx.sess.str_of(id)))
T
Tim Chevalier 已提交
3239 3240 3241
    }
}

3242
pub fn get_fields(rec_ty:t) -> ~[field] {
3243
    match /*bad*/copy get(rec_ty).sty {
3244 3245
      ty_rec(fields) => fields,
      // Can we check at the caller?
3246
      _ => fail!(~"get_fields: not a record type")
3247 3248 3249
    }
}

3250
pub fn method_idx(id: ast::ident, meths: &[method]) -> Option<uint> {
3251
    let mut i = 0u;
B
Brian Anderson 已提交
3252 3253
    for meths.each |m| { if m.ident == id { return Some(i); } i += 1u; }
    return None;
3254 3255
}

3256 3257 3258
/// 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.
3259
pub fn param_tys_in_type(ty: t) -> ~[param_ty] {
3260 3261
    let mut rslt = ~[];
    do walk_ty(ty) |ty| {
3262
        match get(ty).sty {
B
Brian Anderson 已提交
3263
          ty_param(p) => {
3264
            rslt.push(p);
3265
          }
B
Brian Anderson 已提交
3266
          _ => ()
3267 3268 3269 3270 3271
        }
    }
    rslt
}

3272
pub fn occurs_check(tcx: ctxt, sp: span, vid: TyVid, rt: t) {
3273 3274
    // Returns a vec of all the type variables occurring in `ty`. It may
    // contain duplicates.  (Integral type vars aren't counted.)
3275
    fn vars_in_type(ty: t) -> ~[TyVid] {
3276
        let mut rslt = ~[];
B
Brian Anderson 已提交
3277
        do walk_ty(ty) |ty| {
3278
            match get(ty).sty {
3279
              ty_infer(TyVar(v)) => rslt.push(v),
B
Brian Anderson 已提交
3280 3281
              _ => ()
            }
3282 3283 3284 3285
        }
        rslt
    }

3286
    // Fast path
B
Brian Anderson 已提交
3287
    if !type_needs_infer(rt) { return; }
B
Brian Anderson 已提交
3288

T
Tim Chevalier 已提交
3289
    // Occurs check!
N
Niko Matsakis 已提交
3290
    if vec::contains(vars_in_type(rt), &vid) {
T
Tim Chevalier 已提交
3291 3292 3293
            // 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.
3294
            tcx.sess.span_fatal
3295
                (sp, ~"type inference failed because I \
3296
                     could not find a type\n that's both of the form "
3297 3298
                 + ::util::ppaux::ty_to_str(tcx, mk_var(tcx, vid)) +
                 ~" and of the form " + ::util::ppaux::ty_to_str(tcx, rt) +
3299
                 ~" - such a type would have to be infinitely large.");
3300
    }
T
Tim Chevalier 已提交
3301
}
3302

3303 3304
// Maintains a little union-set tree for inferred modes.  `canon()` returns
// the current head value for `m0`.
B
Brian Anderson 已提交
3305
fn canon<T:Copy cmp::Eq>(tbl: HashMap<ast::node_id, ast::inferable<T>>,
3306
                         +m0: ast::inferable<T>) -> ast::inferable<T> {
3307
    match m0 {
3308
      ast::infer(id) => match tbl.find(&id) {
B
Brian Anderson 已提交
3309
        None => m0,
3310 3311
        Some(ref m1) => {
            let cm1 = canon(tbl, (*m1));
3312
            // path compression:
3313
            if cm1 != (*m1) { tbl.insert(id, cm1); }
3314 3315
            cm1
        }
3316
      },
B
Brian Anderson 已提交
3317
      _ => m0
3318 3319 3320 3321 3322
    }
}

// Maintains a little union-set tree for inferred modes.  `resolve_mode()`
// returns the current head value for `m0`.
3323
pub fn canon_mode(cx: ctxt, m0: ast::mode) -> ast::mode {
3324 3325 3326 3327 3328
    canon(cx.inferred_modes, m0)
}

// Returns the head value for mode, failing if `m` was a infer(_) that
// was never inferred.  This should be safe for use after typeck.
3329
pub fn resolved_mode(cx: ctxt, m: ast::mode) -> ast::rmode {
3330
    match canon_mode(cx, m) {
B
Brian Anderson 已提交
3331
      ast::infer(_) => {
P
Paul Stansifer 已提交
3332
        cx.sess.bug(fmt!("mode %? was never resolved", m));
3333
      }
B
Brian Anderson 已提交
3334
      ast::expl(m0) => m0
3335 3336 3337
    }
}

3338
pub fn arg_mode(cx: ctxt, a: arg) -> ast::rmode { resolved_mode(cx, a.mode) }
3339 3340

// Unifies `m1` and `m2`.  Returns unified value or failure code.
3341 3342
pub fn unify_mode(cx: ctxt, modes: expected_found<ast::mode>)
               -> Result<ast::mode, type_err> {
3343 3344
    let m1 = modes.expected;
    let m2 = modes.found;
3345
    match (canon_mode(cx, m1), canon_mode(cx, m2)) {
B
Brian Anderson 已提交
3346
      (m1, m2) if (m1 == m2) => {
3347
        result::Ok(m1)
3348
      }
E
Erick Tryzelaar 已提交
3349
      (ast::infer(_), ast::infer(id2)) => {
3350
        cx.inferred_modes.insert(id2, m1);
3351
        result::Ok(m1)
3352
      }
B
Brian Anderson 已提交
3353
      (ast::infer(id), m) | (m, ast::infer(id)) => {
3354
        cx.inferred_modes.insert(id, m);
3355
        result::Ok(m1)
3356
      }
E
Erick Tryzelaar 已提交
3357
      (_, _) => {
3358
        result::Err(terr_mode_mismatch(modes))
3359 3360 3361 3362 3363 3364
      }
    }
}

// If `m` was never unified, unifies it with `m_def`.  Returns the final value
// for `m`.
3365
pub fn set_default_mode(cx: ctxt, m: ast::mode, m_def: ast::rmode) {
3366
    match canon_mode(cx, m) {
B
Brian Anderson 已提交
3367
      ast::infer(id) => {
3368 3369
        cx.inferred_modes.insert(id, ast::expl(m_def));
      }
B
Brian Anderson 已提交
3370
      ast::expl(_) => ()
3371 3372 3373
    }
}

3374
pub fn ty_sort_str(cx: ctxt, t: t) -> ~str {
3375
    match get(t).sty {
N
Niko Matsakis 已提交
3376
      ty_nil | ty_bot | ty_bool | ty_int(_) |
M
Michael Sullivan 已提交
3377
      ty_uint(_) | ty_float(_) | ty_estr(_) |
B
Brian Anderson 已提交
3378
      ty_type | ty_opaque_box | ty_opaque_closure_ptr(_) => {
3379
        ::util::ppaux::ty_to_str(cx, t)
N
Niko Matsakis 已提交
3380 3381
      }

P
Paul Stansifer 已提交
3382
      ty_enum(id, _) => fmt!("enum %s", item_path_str(cx, id)),
B
Brian Anderson 已提交
3383 3384 3385 3386 3387 3388 3389
      ty_box(_) => ~"@-ptr",
      ty_uniq(_) => ~"~-ptr",
      ty_evec(_, _) => ~"vector",
      ty_unboxed_vec(_) => ~"unboxed vector",
      ty_ptr(_) => ~"*-ptr",
      ty_rptr(_, _) => ~"&-ptr",
      ty_rec(_) => ~"record",
3390 3391
      ty_bare_fn(_) => ~"extern fn",
      ty_closure(_) => ~"fn",
P
Paul Stansifer 已提交
3392
      ty_trait(id, _, _) => fmt!("trait %s", item_path_str(cx, id)),
3393
      ty_struct(id, _) => fmt!("struct %s", item_path_str(cx, id)),
B
Brian Anderson 已提交
3394
      ty_tup(_) => ~"tuple",
3395 3396
      ty_infer(TyVar(_)) => ~"inferred type",
      ty_infer(IntVar(_)) => ~"integral variable",
3397
      ty_infer(FloatVar(_)) => ~"floating-point variable",
B
Brian Anderson 已提交
3398
      ty_param(_) => ~"type parameter",
3399 3400
      ty_self => ~"self",
      ty_err => ~"type error"
N
Niko Matsakis 已提交
3401 3402 3403
    }
}

3404
pub fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str {
3405 3406 3407 3408 3409 3410 3411 3412 3413
    /*!
     *
     * 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. */

3414
    fn terr_vstore_kind_to_str(k: terr_vstore_kind) -> ~str {
3415 3416 3417
        match k {
            terr_vec => ~"[]",
            terr_str => ~"str",
3418 3419
            terr_fn => ~"fn",
            terr_trait => ~"trait"
3420
        }
3421 3422
    }

N
Niko Matsakis 已提交
3423
    match *err {
3424 3425 3426
        terr_mismatch => ~"types differ",
        terr_purity_mismatch(values) => {
            fmt!("expected %s fn but found %s fn",
3427
                 values.expected.to_str(), values.found.to_str())
3428
        }
3429 3430 3431 3432
        terr_abi_mismatch(values) => {
            fmt!("expected %s fn but found %s fn",
                 values.expected.to_str(), values.found.to_str())
        }
3433 3434
        terr_onceness_mismatch(values) => {
            fmt!("expected %s fn but found %s fn",
3435
                 values.expected.to_str(), values.found.to_str())
3436
        }
3437
        terr_sigil_mismatch(values) => {
3438
            fmt!("expected %s closure, found %s closure",
3439 3440
                 values.expected.to_str(),
                 values.found.to_str())
3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473
        }
        terr_mutability => ~"values differ in mutability",
        terr_box_mutability => ~"boxed values differ in mutability",
        terr_vec_mutability => ~"vectors differ in mutability",
        terr_ptr_mutability => ~"pointers differ in mutability",
        terr_ref_mutability => ~"references differ in mutability",
        terr_ty_param_size(values) => {
            fmt!("expected a type with %? type params \
                  but found one with %? type params",
                 values.expected, values.found)
        }
        terr_tuple_size(values) => {
            fmt!("expected a tuple with %? elements \
                  but found one with %? elements",
                 values.expected, values.found)
        }
        terr_record_size(values) => {
            fmt!("expected a record with %? fields \
                  but found one with %? fields",
                 values.expected, values.found)
        }
        terr_record_mutability => {
            ~"record elements differ in mutability"
        }
        terr_record_fields(values) => {
            fmt!("expected a record with field `%s` but found one with field \
                  `%s`",
                 cx.sess.str_of(values.expected),
                 cx.sess.str_of(values.found))
        }
        terr_arg_count => ~"incorrect number of function parameters",
        terr_mode_mismatch(values) => {
            fmt!("expected argument mode %s, but found %s",
3474 3475
                 pprust::mode_to_str(values.expected),
                 pprust::mode_to_str(values.found))
3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495
        }
        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",
                 bound_region_to_str(cx, br))
        }
        terr_regions_overly_polymorphic(br, _) => {
            fmt!("expected concrete lifetime, \
                  but found bound lifetime parameter %s",
                 bound_region_to_str(cx, br))
        }
3496
        terr_vstores_differ(k, ref values) => {
3497 3498
            fmt!("%s storage differs: expected %s but found %s",
                 terr_vstore_kind_to_str(k),
3499 3500
                 vstore_to_str(cx, (*values).expected),
                 vstore_to_str(cx, (*values).found))
3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513
        }
        terr_in_field(err, fname) => {
            fmt!("in field `%s`, %s", cx.sess.str_of(fname),
                 type_err_to_str(cx, err))
        }
        terr_sorts(values) => {
            fmt!("expected %s but found %s",
                 ty_sort_str(cx, values.expected),
                 ty_sort_str(cx, values.found))
        }
        terr_self_substs => {
            ~"inconsistent self substitution" // XXX this is more of a bug
        }
3514
        terr_integer_as_char => {
3515
            fmt!("expected an integral type but found char")
3516
        }
3517 3518 3519 3520 3521 3522 3523 3524 3525
        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())
3526
        }
3527 3528 3529
    }
}

3530
pub fn note_and_explain_type_err(cx: ctxt, err: &type_err) {
3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546
    match *err {
        terr_regions_does_not_outlive(subregion, superregion) => {
            note_and_explain_region(cx, ~"", subregion, ~"...");
            note_and_explain_region(cx, ~"...does not necessarily outlive ",
                                    superregion, ~"");
        }
        terr_regions_not_same(region1, region2) => {
            note_and_explain_region(cx, ~"", region1, ~"...");
            note_and_explain_region(cx, ~"...is not the same lifetime as ",
                                    region2, ~"");
        }
        terr_regions_no_overlap(region1, region2) => {
            note_and_explain_region(cx, ~"", region1, ~"...");
            note_and_explain_region(cx, ~"...does not overlap ",
                                    region2, ~"");
        }
3547 3548 3549 3550 3551 3552 3553 3554 3555 3556
        terr_regions_insufficiently_polymorphic(_, conc_region) => {
            note_and_explain_region(cx,
                                    ~"concrete lifetime that was found is ",
                                    conc_region, ~"");
        }
        terr_regions_overly_polymorphic(_, conc_region) => {
            note_and_explain_region(cx,
                                    ~"expected concrete lifetime is ",
                                    conc_region, ~"");
        }
3557 3558 3559 3560
        _ => {}
    }
}

3561
pub fn def_has_ty_params(def: ast::def) -> bool {
3562
    match def {
3563
      ast::def_fn(_, _) | ast::def_variant(_, _) | ast::def_struct(_)
B
Brian Anderson 已提交
3564 3565
        => true,
      _ => false
3566 3567 3568
    }
}

3569
pub fn store_trait_methods(cx: ctxt, id: ast::node_id, ms: @~[method]) {
3570
    cx.trait_method_cache.insert(ast_util::local_def(id), ms);
3571 3572
}

3573
pub fn provided_trait_methods(cx: ctxt, id: ast::def_id) -> ~[ast::ident] {
3574
    if is_local(id) {
3575
        match cx.items.find(&id.node) {
3576
            Some(ast_map::node_item(@ast::item {
P
Patrick Walton 已提交
3577 3578 3579
                        node: item_trait(_, _, ref ms),
                        _
                    }, _)) =>
3580
                match ast_util::split_trait_methods((/*bad*/copy *ms)) {
3581
                   (_, p) => p.map(|method| method.ident)
3582
                },
3583
            _ => cx.sess.bug(fmt!("provided_trait_methods: %? is not a trait",
3584 3585
                                  id))
        }
3586
    } else {
3587
        csearch::get_provided_trait_methods(cx, id).map(|ifo| ifo.ty.ident)
3588 3589 3590
    }
}

3591 3592 3593
pub fn trait_supertraits(cx: ctxt,
                         id: ast::def_id)
                      -> @~[InstantiatedTraitRef] {
3594
    // Check the cache.
3595
    match cx.supertraits.find(&id) {
3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608
        Some(instantiated_trait_info) => { return instantiated_trait_info; }
        None => {}  // Continue.
    }

    // Not in the cache. It had better be in the metadata, which means it
    // shouldn't be local.
    assert !is_local(id);

    // Get the supertraits out of the metadata and create the
    // InstantiatedTraitRef for each.
    let result = dvec::DVec();
    for csearch::get_supertraits(cx, id).each |trait_type| {
        match get(*trait_type).sty {
3609
            ty_trait(def_id, ref substs, _) => {
3610 3611
                result.push(InstantiatedTraitRef {
                    def_id: def_id,
3612
                    tpt: { substs: (/*bad*/copy *substs), ty: *trait_type }
3613 3614 3615 3616 3617 3618 3619
                });
            }
            _ => cx.sess.bug(~"trait_supertraits: trait ref wasn't a trait")
        }
    }

    // Unwrap and return the result.
L
Luqman Aden 已提交
3620
    return @dvec::unwrap(result);
3621
}
3622

3623
pub fn trait_methods(cx: ctxt, id: ast::def_id) -> @~[method] {
3624
    match cx.trait_method_cache.find(&id) {
3625
      // Local traits are supposed to have been added explicitly.
B
Brian Anderson 已提交
3626
      Some(ms) => ms,
3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638
      _ => {
        // If the lookup in trait_method_cache fails, assume that the trait
        // method we're trying to look up is in a different crate, and look
        // for it there.
        assert id.crate != ast::local_crate;
        let result = csearch::get_trait_methods(cx, id);

        // Store the trait method in the local trait_method_cache so that
        // future lookups succeed.
        cx.trait_method_cache.insert(id, result);
        result
      }
3639 3640
    }
}
3641

3642 3643 3644
/*
  Could this return a list of (def_id, substs) pairs?
 */
3645
pub fn impl_traits(cx: ctxt, id: ast::def_id, vstore: vstore) -> ~[t] {
3646 3647 3648
    fn vstoreify(cx: ctxt, ty: t, vstore: vstore) -> t {
        match ty::get(ty).sty {
            ty::ty_trait(_, _, trait_vstore) if vstore == trait_vstore => ty,
P
Patrick Walton 已提交
3649
            ty::ty_trait(did, ref substs, _) => {
3650
                mk_trait(cx, did, (/*bad*/copy *substs), vstore)
P
Patrick Walton 已提交
3651
            }
3652 3653 3654 3655
            _ => cx.sess.bug(~"impl_traits: not a trait")
        }
    }

3656
    if id.crate == ast::local_crate {
P
Paul Stansifer 已提交
3657
        debug!("(impl_traits) searching for trait impl %?", id);
3658
        match cx.items.find(&id.node) {
3659
           Some(ast_map::node_item(@ast::item {
3660
                        node: ast::item_impl(_, opt_trait, _, _),
3661
                        _},
B
Brian Anderson 已提交
3662
                    _)) => {
3663

B
Brian Anderson 已提交
3664
               do option::map_default(&opt_trait, ~[]) |trait_ref| {
3665 3666 3667
                       ~[vstoreify(cx,
                                   node_id_to_type(cx, trait_ref.ref_id),
                                   vstore)]
3668
                   }
3669
           }
B
Brian Anderson 已提交
3670
           _ => ~[]
3671
        }
3672
    } else {
3673 3674
        vec::map(csearch::get_impl_traits(cx, id),
                 |x| vstoreify(cx, *x, vstore))
3675 3676 3677
    }
}

3678
pub fn ty_to_def_id(ty: t) -> Option<ast::def_id> {
3679
    match get(ty).sty {
3680
      ty_trait(id, _, _) | ty_struct(id, _) | ty_enum(id, _) => Some(id),
B
Brian Anderson 已提交
3681
      _ => None
3682 3683 3684
    }
}

3685 3686 3687 3688 3689 3690 3691 3692 3693
/// 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.
        cx.sess.unimpl(~"constructor ID of cross-crate tuple structs");
    }

3694
    match cx.items.find(&struct_did.node) {
3695 3696
        Some(ast_map::node_item(item, _)) => {
            match item.node {
3697
                ast::item_struct(struct_def, _) => {
3698 3699 3700 3701 3702 3703 3704 3705 3706 3707
                    struct_def.ctor_id.map(|ctor_id|
                        ast_util::local_def(*ctor_id))
                }
                _ => cx.sess.bug(~"called struct_ctor_id on non-struct")
            }
        }
        _ => cx.sess.bug(~"called struct_ctor_id on non-struct")
    }
}

3708
// Enum information
3709
pub struct VariantInfo_ {
3710 3711 3712 3713 3714 3715 3716 3717
    args: ~[t],
    ctor_ty: t,
    name: ast::ident,
    id: ast::def_id,
    disr_val: int,
    vis: visibility
}

3718
pub type VariantInfo = @VariantInfo_;
M
Marijn Haverbeke 已提交
3719

3720 3721 3722 3723
pub fn substd_enum_variants(cx: ctxt,
                            id: ast::def_id,
                            substs: &substs)
                         -> ~[VariantInfo] {
B
Brian Anderson 已提交
3724 3725
    do vec::map(*enum_variants(cx, id)) |variant_info| {
        let substd_args = vec::map(variant_info.args,
3726
                                   |aty| subst(cx, substs, *aty));
3727

3728
        let substd_ctor_ty = subst(cx, substs, variant_info.ctor_ty);
3729

3730
        @VariantInfo_{args: substd_args, ctor_ty: substd_ctor_ty,
3731
                      ../*bad*/copy **variant_info}
3732 3733 3734
    }
}

3735
pub fn item_path_str(cx: ctxt, id: ast::def_id) -> ~str {
P
Paul Stansifer 已提交
3736
    ast_map::path_to_str(item_path(cx, id), cx.sess.parse_sess.interner)
3737 3738
}

3739
pub enum DtorKind {
3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756
    NoDtor,
    LegacyDtor(def_id),
    TraitDtor(def_id)
}

impl DtorKind {
    pure fn is_not_present(&const self) -> bool {
        match *self {
            NoDtor => true,
            _ => false
        }
    }
    pure fn is_present(&const self) -> bool {
        !self.is_not_present()
    }
}

3757
/* If struct_id names a struct with a dtor, return Some(the dtor's id).
3758
   Otherwise return none. */
3759
pub fn ty_dtor(cx: ctxt, struct_id: def_id) -> DtorKind {
3760
    match cx.destructor_for_type.find(&struct_id) {
3761
        Some(method_def_id) => return TraitDtor(method_def_id),
3762 3763 3764
        None => {}  // Continue.
    }

3765
    if is_local(struct_id) {
3766
       match cx.items.find(&struct_id.node) {
3767
           Some(ast_map::node_item(@ast::item {
3768 3769 3770
               node: ast::item_struct(@ast::struct_def { dtor: Some(ref dtor),
                                                         _ },
                                      _),
3771 3772
               _
           }, _)) =>
3773
               LegacyDtor(local_def((*dtor).node.id)),
3774
           _ =>
3775
               NoDtor
3776 3777 3778
       }
    }
    else {
3779
      match csearch::struct_dtor(cx.sess.cstore, struct_id) {
3780 3781 3782
        None => NoDtor,
        Some(did) => LegacyDtor(did),
      }
3783 3784 3785
    }
}

3786
pub fn has_dtor(cx: ctxt, struct_id: def_id) -> bool {
3787
    ty_dtor(cx, struct_id).is_present()
3788 3789
}

3790
pub fn item_path(cx: ctxt, id: ast::def_id) -> ast_map::path {
3791 3792 3793
    if id.crate != ast::local_crate {
        csearch::get_item_path(cx, id)
    } else {
3794
        let node = cx.items.get(&id.node);
3795
        match node {
B
Brian Anderson 已提交
3796
          ast_map::node_item(item, path) => {
3797
            let item_elt = match item.node {
B
Brian Anderson 已提交
3798
              item_mod(_) | item_foreign_mod(_) => {
3799 3800
                ast_map::path_mod(item.ident)
              }
B
Brian Anderson 已提交
3801
              _ => {
3802 3803 3804
                ast_map::path_name(item.ident)
              }
            };
3805
            vec::append_one(/*bad*/copy *path, item_elt)
3806 3807
          }

B
Brian Anderson 已提交
3808
          ast_map::node_foreign_item(nitem, _, path) => {
3809 3810
            vec::append_one(/*bad*/copy *path,
                            ast_map::path_name(nitem.ident))
3811 3812
          }

B
Brian Anderson 已提交
3813
          ast_map::node_method(method, _, path) => {
3814 3815
            vec::append_one(/*bad*/copy *path,
                            ast_map::path_name(method.ident))
3816
          }
B
Brian Anderson 已提交
3817
          ast_map::node_trait_method(trait_method, _, path) => {
3818
            let method = ast_util::trait_method_to_ty_method(*trait_method);
3819 3820
            vec::append_one(/*bad*/copy *path,
                            ast_map::path_name(method.ident))
3821
          }
3822

3823
          ast_map::node_variant(ref variant, _, path) => {
3824
            vec::append_one(vec::init(*path),
3825
                            ast_map::path_name((*variant).node.name))
3826 3827
          }

B
Brian Anderson 已提交
3828
          ast_map::node_dtor(_, _, _, path) => {
3829
            vec::append_one(/*bad*/copy *path, ast_map::path_name(
P
Paul Stansifer 已提交
3830
                syntax::parse::token::special_idents::literally_dtor))
T
Tim Chevalier 已提交
3831 3832
          }

3833
          ast_map::node_struct_ctor(_, item, path) => {
3834
            vec::append_one(/*bad*/copy *path, ast_map::path_name(item.ident))
3835 3836
          }

3837 3838
          ast_map::node_stmt(*) | ast_map::node_expr(*) |
          ast_map::node_arg(*) | ast_map::node_local(*) |
3839
          ast_map::node_block(*) => {
P
Paul Stansifer 已提交
3840
            cx.sess.bug(fmt!("cannot find item_path for node %?", node));
3841 3842 3843 3844 3845
          }
        }
    }
}

3846
pub fn enum_is_univariant(cx: ctxt, id: ast::def_id) -> bool {
3847
    enum_variants(cx, id).len() == 1
3848 3849
}

3850
pub fn type_is_empty(cx: ctxt, t: t) -> bool {
3851
    match ty::get(t).sty {
B
Brian Anderson 已提交
3852 3853
       ty_enum(did, _) => (*enum_variants(cx, did)).is_empty(),
       _ => false
3854 3855 3856
     }
}

3857
pub fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[VariantInfo] {
3858
    match cx.enum_var_cache.find(&id) {
B
Brian Anderson 已提交
3859
      Some(variants) => return variants,
B
Brian Anderson 已提交
3860
      _ => { /* fallthrough */ }
3861
    }
3862

3863
    let result = if ast::local_crate != id.crate {
3864
        @csearch::get_enum_variants(cx, id)
3865
    } else {
3866 3867 3868 3869 3870
        /*
          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
         */
3871
        match cx.items.get(&id.node) {
3872
          ast_map::node_item(@ast::item {
P
Patrick Walton 已提交
3873 3874 3875
                    node: ast::item_enum(ref enum_definition, _),
                    _
                }, _) => {
3876
            let variants = /*bad*/copy (*enum_definition).variants;
3877
            let mut disr_val = -1;
B
Brian Anderson 已提交
3878
            @vec::map(variants, |variant| {
3879
                match variant.node.kind {
3880
                    ast::tuple_variant_kind(ref args) => {
3881 3882
                        let ctor_ty = node_id_to_type(cx, variant.node.id);
                        let arg_tys = {
3883
                            if args.len() > 0u {
3884 3885 3886 3887 3888 3889
                                ty_fn_args(ctor_ty).map(|a| a.ty)
                            } else {
                                ~[]
                            }
                        };
                        match variant.node.disr_expr {
B
Brian Anderson 已提交
3890
                          Some (ex) => {
3891 3892 3893 3894 3895 3896 3897 3898
                            disr_val = match const_eval::eval_const_expr(cx,
                                                                         ex) {
                              const_eval::const_int(val) => val as int,
                              _ => cx.sess.bug(~"tag_variants: bad disr expr")
                            }
                          }
                          _ => disr_val += 1
                        }
3899
                        @VariantInfo_{args: arg_tys,
3900 3901 3902
                          ctor_ty: ctor_ty,
                          name: variant.node.name,
                          id: ast_util::local_def(variant.node.id),
3903 3904
                          disr_val: disr_val,
                          vis: variant.node.vis
3905
                         }
3906
                    }
3907
                    ast::struct_variant_kind(_) => {
3908
                        fail!(~"struct variant kinds unimpl in enum_variants")
3909 3910
                    }
                    ast::enum_variant_kind(_) => {
3911
                        fail!(~"enum variant kinds unimpl in enum_variants")
3912
                    }
3913
                }
3914
            })
M
Marijn Haverbeke 已提交
3915
          }
B
Brian Anderson 已提交
3916
          _ => cx.sess.bug(~"tag_variants: id not bound to an enum")
3917
        }
3918
    };
3919
    cx.enum_var_cache.insert(id, result);
3920
    result
3921 3922
}

3923

P
Patrick Walton 已提交
3924
// Returns information about the enum variant with the given ID:
3925 3926 3927 3928
pub fn enum_variant_with_id(cx: ctxt,
                            enum_id: ast::def_id,
                            variant_id: ast::def_id)
                         -> VariantInfo {
3929
    let variants = enum_variants(cx, enum_id);
3930 3931
    let mut i = 0;
    while i < variants.len() {
B
Brian Anderson 已提交
3932
        let variant = variants[i];
3933
        if variant.id == variant_id { return variant; }
3934
        i += 1;
3935
    }
3936
    cx.sess.bug(~"enum_variant_with_id(): no variant exists with that ID");
3937 3938
}

3939

3940 3941
// 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.
3942 3943 3944
pub fn lookup_item_type(cx: ctxt,
                        did: ast::def_id)
                     -> ty_param_bounds_and_ty {
3945
    match cx.tcache.find(&did) {
3946
      Some(tpt) => {
3947 3948
        // The item is in this crate. The caller should have added it to the
        // type cache already
3949 3950 3951
        return tpt;
      }
      None => {
3952
        assert did.crate != ast::local_crate;
M
Marijn Haverbeke 已提交
3953 3954
        let tyt = csearch::get_type(cx, did);
        cx.tcache.insert(did, tyt);
B
Brian Anderson 已提交
3955
        return tyt;
M
Marijn Haverbeke 已提交
3956
      }
3957
    }
T
Tim Chevalier 已提交
3958 3959
}

T
Tim Chevalier 已提交
3960
// Look up a field ID, whether or not it's local
3961
// Takes a list of type substs in case the struct is generic
3962 3963 3964 3965 3966
pub fn lookup_field_type(tcx: ctxt,
                         struct_id: def_id,
                         id: def_id,
                         substs: &substs)
                      -> ty::t {
3967
    let t = if id.crate == ast::local_crate {
T
Tim Chevalier 已提交
3968 3969 3970
        node_id_to_type(tcx, id.node)
    }
    else {
3971
        match tcx.tcache.find(&id) {
B
Brian Anderson 已提交
3972 3973
           Some(tpt) => tpt.ty,
           None => {
3974
               let tpt = csearch::get_field_type(tcx, struct_id, id);
T
Tim Chevalier 已提交
3975
               tcx.tcache.insert(id, tpt);
3976
               tpt.ty
T
Tim Chevalier 已提交
3977 3978
           }
        }
3979
    };
3980
    subst(tcx, substs, t)
T
Tim Chevalier 已提交
3981 3982
}

3983 3984
// Look up the list of field names and IDs for a given struct
// Fails if the id is not bound to a struct.
3985
pub fn lookup_struct_fields(cx: ctxt, did: ast::def_id) -> ~[field_ty] {
3986
  if did.crate == ast::local_crate {
3987
    match cx.items.find(&did.node) {
B
Brian Anderson 已提交
3988
       Some(ast_map::node_item(i,_)) => {
3989
         match i.node {
3990
            ast::item_struct(struct_def, _) => {
3991
               struct_field_tys(/*bad*/copy struct_def.fields)
3992
            }
3993
            _ => cx.sess.bug(~"struct ID bound to non-struct")
T
Tim Chevalier 已提交
3994
         }
T
Tim Chevalier 已提交
3995
       }
3996 3997
       Some(ast_map::node_variant(ref variant, _, _)) => {
          match (*variant).node.kind {
3998
            ast::struct_variant_kind(struct_def) => {
3999
              struct_field_tys(/*bad*/copy struct_def.fields)
4000 4001 4002 4003 4004 4005 4006
            }
            _ => {
              cx.sess.bug(~"struct ID bound to enum variant that isn't \
                            struct-like")
            }
          }
       }
B
Brian Anderson 已提交
4007
       _ => {
P
Paul Stansifer 已提交
4008
           cx.sess.bug(
4009
               fmt!("struct ID not bound to an item: %s",
P
Paul Stansifer 已提交
4010
                    ast_map::node_id_to_str(cx.items, did.node,
P
Paul Stansifer 已提交
4011
                                            cx.sess.parse_sess.interner)));
4012
       }
T
Tim Chevalier 已提交
4013
    }
T
Tim Chevalier 已提交
4014
        }
4015
  else {
4016
        return csearch::get_struct_fields(cx.sess.cstore, did);
T
Tim Chevalier 已提交
4017 4018 4019
    }
}

4020 4021 4022 4023
pub fn lookup_struct_field(cx: ctxt,
                           parent: ast::def_id,
                           field_id: ast::def_id)
                        -> field_ty {
4024
    match vec::find(lookup_struct_fields(cx, parent),
B
Brian Anderson 已提交
4025
                 |f| f.id.node == field_id.node) {
B
Brian Anderson 已提交
4026
        Some(t) => t,
4027
        None => cx.sess.bug(~"struct ID not found in parent's fields")
4028 4029 4030
    }
}

4031
pure fn is_public(f: field_ty) -> bool {
4032 4033 4034 4035 4036
    // XXX: This is wrong.
    match f.vis {
        public | inherited => true,
        private => false
    }
4037 4038
}

4039
fn struct_field_tys(fields: ~[@struct_field]) -> ~[field_ty] {
4040
    do fields.map |field| {
4041 4042
        match field.node.kind {
            named_field(ident, mutability, visibility) => {
4043 4044 4045 4046 4047 4048
                field_ty {
                    ident: ident,
                    id: ast_util::local_def(field.node.id),
                    vis: visibility,
                    mutability: mutability,
                }
4049
            }
4050
            unnamed_field => {
4051 4052 4053 4054 4055 4056 4057
                field_ty {
                    ident:
                        syntax::parse::token::special_idents::unnamed_field,
                    id: ast_util::local_def(field.node.id),
                    vis: ast::public,
                    mutability: ast::struct_immutable,
                }
4058
            }
4059
        }
T
Tim Chevalier 已提交
4060
    }
T
Tim Chevalier 已提交
4061 4062
}

4063 4064
// Return a list of fields corresponding to the struct's items
// (as if the struct was a record). trans uses this
4065
// Takes a list of substs with which to instantiate field types
4066 4067 4068
// Keep in mind that this function reports that all fields are
// mutable, regardless of how they were declared. It's meant to
// be used in trans.
4069 4070 4071 4072
pub fn struct_mutable_fields(cx: ctxt,
                             did: ast::def_id,
                             substs: &substs)
                          -> ~[field] {
4073
    struct_item_fields(cx, did, substs, |_mt| m_mutbl)
4074 4075
}

4076
// Same as struct_mutable_fields, but doesn't change
4077
// mutability.
4078 4079 4080 4081
pub fn struct_fields(cx: ctxt,
                     did: ast::def_id,
                     substs: &substs)
                  -> ~[field] {
4082 4083 4084
    struct_item_fields(cx, did, substs, |mt| match mt {
      struct_mutable => m_mutbl,
        struct_immutable => m_imm })
4085 4086 4087
}


4088
fn struct_item_fields(cx:ctxt,
N
Niko Matsakis 已提交
4089 4090
                     did: ast::def_id,
                     substs: &substs,
4091
                     frob_mutability: fn(struct_mutability) -> mutability)
4092
    -> ~[field] {
4093
    do lookup_struct_fields(cx, did).map |f| {
G
Graydon Hoare 已提交
4094
       // consider all instance vars mut, because the
T
Tim Chevalier 已提交
4095
       // constructor may mutate all vars
4096
       field {
4097 4098 4099 4100 4101 4102
           ident: f.ident,
            mt: mt {
                ty: lookup_field_type(cx, did, f.id, substs),
                mutbl: frob_mutability(f.mutability)
            }
        }
T
Tim Chevalier 已提交
4103 4104 4105
    }
}

4106
pub fn is_binopable(_cx: ctxt, ty: t, op: ast::binop) -> bool {
M
Marijn Haverbeke 已提交
4107 4108 4109 4110
    const tycat_other: int = 0;
    const tycat_bool: int = 1;
    const tycat_int: int = 2;
    const tycat_float: int = 3;
M
Michael Sullivan 已提交
4111 4112
    const tycat_struct: int = 4;
    const tycat_bot: int = 5;
M
Marijn Haverbeke 已提交
4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123

    const opcat_add: int = 0;
    const opcat_sub: int = 1;
    const opcat_mult: int = 2;
    const opcat_shift: int = 3;
    const opcat_rel: int = 4;
    const opcat_eq: int = 5;
    const opcat_bit: int = 6;
    const opcat_logic: int = 7;

    fn opcat(op: ast::binop) -> int {
4124
        match op {
B
Brian Anderson 已提交
4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142
          ast::add => opcat_add,
          ast::subtract => opcat_sub,
          ast::mul => opcat_mult,
          ast::div => opcat_mult,
          ast::rem => opcat_mult,
          ast::and => opcat_logic,
          ast::or => opcat_logic,
          ast::bitxor => opcat_bit,
          ast::bitand => opcat_bit,
          ast::bitor => opcat_bit,
          ast::shl => opcat_shift,
          ast::shr => opcat_shift,
          ast::eq => opcat_eq,
          ast::ne => opcat_eq,
          ast::lt => opcat_rel,
          ast::le => opcat_rel,
          ast::ge => opcat_rel,
          ast::gt => opcat_rel
M
Marijn Haverbeke 已提交
4143 4144 4145
        }
    }

4146
    fn tycat(ty: t) -> int {
4147
        match get(ty).sty {
B
Brian Anderson 已提交
4148
          ty_bool => tycat_bool,
4149
          ty_int(_) | ty_uint(_) | ty_infer(IntVar(_)) => tycat_int,
4150
          ty_float(_) | ty_infer(FloatVar(_)) => tycat_float,
B
Brian Anderson 已提交
4151 4152 4153
          ty_rec(_) | ty_tup(_) | ty_enum(_, _) => tycat_struct,
          ty_bot => tycat_bot,
          _ => tycat_other
M
Marijn Haverbeke 已提交
4154 4155 4156 4157 4158
        }
    }

    const t: bool = true;
    const f: bool = false;
4159

4160
    let tbl = ~[
4161 4162 4163
    /*.          add,     shift,   bit
      .             sub,     rel,     logic
      .                mult,    eq,         */
4164
    /*other*/   ~[f, f, f, f, f, f, f, f],
4165 4166 4167
    /*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],
4168 4169
    /*bot*/     ~[f, f, f, f, f, f, f, f],
    /*struct*/  ~[t, t, t, t, f, f, t, t]];
B
Brian Anderson 已提交
4170

B
Brian Anderson 已提交
4171
    return tbl[tycat(ty)][opcat(op)];
4172 4173
}

4174
pub fn ty_params_to_tys(tcx: ty::ctxt, tps: ~[ast::ty_param]) -> ~[t] {
B
Brian Anderson 已提交
4175
    vec::from_fn(tps.len(), |i| {
4176 4177 4178
                ty::mk_param(tcx, i, ast_util::local_def(tps[i].id))
        })
}
4179

4180
/// Returns an equivalent type with all the typedefs and self regions removed.
4181
pub fn normalize_ty(cx: ctxt, t: t) -> t {
4182
    fn normalize_mt(cx: ctxt, mt: mt) -> mt {
4183
        mt { ty: normalize_ty(cx, mt.ty), mutbl: mt.mutbl }
4184 4185 4186 4187 4188 4189 4190 4191
    }
    fn normalize_vstore(vstore: vstore) -> vstore {
        match vstore {
            vstore_fixed(*) | vstore_uniq | vstore_box => vstore,
            vstore_slice(_) => vstore_slice(re_static)
        }
    }

4192
    match cx.normalized_cache.find(&t) {
B
Brian Anderson 已提交
4193 4194
      Some(t) => return t,
      None => ()
B
Brian Anderson 已提交
4195 4196
    }

4197
    let t = match get(t).sty {
4198 4199 4200 4201
        ty_evec(mt, vstore) =>
            // This type has a vstore. Get rid of it
            mk_evec(cx, normalize_mt(cx, mt), normalize_vstore(vstore)),

4202 4203 4204 4205
        ty_estr(vstore) =>
            // This type has a vstore. Get rid of it
            mk_estr(cx, normalize_vstore(vstore)),

E
Erick Tryzelaar 已提交
4206
        ty_rptr(_, mt) =>
4207
            // This type has a region. Get rid of it
4208 4209
            mk_rptr(cx, re_static, normalize_mt(cx, mt)),

4210 4211 4212 4213
        ty_closure(ref closure_ty) => {
            mk_closure(cx, ClosureTy {
                region: ty::re_static,
                ..copy *closure_ty
4214 4215
            })
        }
4216

4217 4218
        ty_enum(did, ref r) =>
            match (*r).self_r {
B
Brian Anderson 已提交
4219
                Some(_) =>
4220
                    // Use re_static since trans doesn't care about regions
E
Eric Holk 已提交
4221
                    mk_enum(cx, did,
4222 4223 4224 4225 4226
                     substs {
                        self_r: Some(ty::re_static),
                        self_ty: None,
                        tps: /*bad*/copy (*r).tps
                     }),
B
Brian Anderson 已提交
4227
                None =>
4228 4229 4230
                    t
            },

4231
        ty_struct(did, ref r) =>
4232
            match (*r).self_r {
B
Brian Anderson 已提交
4233
              Some(_) =>
4234
                // Ditto.
4235 4236 4237
                mk_struct(cx, did, substs {self_r: Some(ty::re_static),
                                           self_ty: None,
                                           tps: /*bad*/copy (*r).tps}),
B
Brian Anderson 已提交
4238
              None =>
4239 4240 4241 4242 4243
                t
            },

        _ =>
            t
4244 4245
    };

4246
    let sty = fold_sty(&get(t).sty, |t| { normalize_ty(cx, t) });
B
Brian Anderson 已提交
4247 4248
    let t_norm = mk_t(cx, sty);
    cx.normalized_cache.insert(t, t_norm);
B
Brian Anderson 已提交
4249
    return t_norm;
4250 4251
}

4252
// Returns the repeat count for a repeating vector expression.
4253 4254 4255 4256
pub fn eval_repeat_count(tcx: ctxt,
                         count_expr: @ast::expr,
                         span: span)
                      -> uint {
4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271
    match const_eval::eval_const_expr(tcx, count_expr) {
        const_eval::const_int(count) => return count as uint,
        const_eval::const_uint(count) => return count as uint,
        const_eval::const_float(count) => {
            tcx.sess.span_err(span,
                              ~"expected signed or unsigned integer for \
                                repeat count but found float");
            return count as uint;
        }
        const_eval::const_str(_) => {
            tcx.sess.span_err(span,
                              ~"expected signed or unsigned integer for \
                                repeat count but found string");
            return 0;
        }
4272 4273 4274 4275 4276 4277 4278
        const_eval::const_bool(_) => {
            tcx.sess.span_err(span,
                              ~"expected signed or unsigned integer for \
                                repeat count but found boolean");
            return 0;
        }

4279 4280 4281
    }
}

4282
// Determine what purity to check a nested function under
4283 4284
pub pure fn determine_inherited_purity(parent_purity: ast::purity,
                                       child_purity: ast::purity,
4285
                                       child_sigil: ast::Sigil)
4286
                                    -> ast::purity {
4287 4288 4289
    // 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
4290 4291
    match child_sigil {
        ast::BorrowedSigil if child_purity == ast::impure_fn => parent_purity,
4292 4293
        _ => child_purity
    }
4294 4295
}

4296 4297
// Iterate over a type parameter's bounded traits and any supertraits
// of those traits, ignoring kinds.
4298 4299 4300
// Here, the supertraits are the transitive closure of the supertrait
// relation on the supertraits from each bounded trait's constraint
// list.
4301 4302 4303
pub fn iter_bound_traits_and_supertraits(tcx: ctxt,
                                         bounds: param_bounds,
                                         f: &fn(t) -> bool) {
4304 4305
    let mut fin = false;

4306 4307 4308 4309 4310
    for bounds.each |bound| {

        let bound_trait_ty = match *bound {
            ty::bound_trait(bound_t) => bound_t,

B
Brian Anderson 已提交
4311
            ty::bound_copy | ty::bound_owned |
B
Brian Anderson 已提交
4312
            ty::bound_const | ty::bound_durable => {
4313 4314 4315 4316
                loop; // skip non-trait bounds
            }
        };

4317 4318
        let mut supertrait_map = HashMap();
        let mut seen_def_ids = ~[];
4319
        let mut i = 0;
4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333
        let trait_ty_id = ty_to_def_id(bound_trait_ty).expect(
            ~"iter_trait_ty_supertraits got a non-trait type");
        let mut trait_ty = bound_trait_ty;

        debug!("iter_bound_traits_and_supertraits: trait_ty = %s",
               ty_to_str(tcx, trait_ty));

        // Add the given trait ty to the hash map
        supertrait_map.insert(trait_ty_id, trait_ty);
        seen_def_ids.push(trait_ty_id);

        if f(trait_ty) {
            // Add all the supertraits to the hash map,
            // executing <f> on each of them
4334
            while i < supertrait_map.len() && !fin {
4335 4336 4337 4338 4339 4340 4341 4342
                let init_trait_id = seen_def_ids[i];
                i += 1;
                 // Add supertraits to supertrait_map
                let supertraits = trait_supertraits(tcx, init_trait_id);
                for supertraits.each |supertrait| {
                    let super_t = supertrait.tpt.ty;
                    let d_id = ty_to_def_id(super_t).expect("supertrait \
                        should be a trait ty");
4343
                    if !supertrait_map.contains_key(&d_id) {
4344 4345 4346 4347 4348 4349 4350 4351 4352
                        supertrait_map.insert(d_id, super_t);
                        trait_ty = super_t;
                        seen_def_ids.push(d_id);
                    }
                    debug!("A super_t = %s", ty_to_str(tcx, trait_ty));
                    if !f(trait_ty) {
                        fin = true;
                    }
                }
4353
            }
4354 4355
        };
        fin = false;
4356 4357 4358
    }
}

4359 4360
pub fn count_traits_and_supertraits(tcx: ctxt,
                                    boundses: &[param_bounds]) -> uint {
4361 4362 4363 4364 4365 4366 4367 4368 4369
    let mut total = 0;
    for boundses.each |bounds| {
        for iter_bound_traits_and_supertraits(tcx, *bounds) |_trait_ty| {
            total += 1;
        }
    }
    return total;
}

4370
// Given a trait and a type, returns the impl of that type
4371
pub fn get_impl_id(tcx: ctxt, trait_id: def_id, self_ty: t) -> def_id {
4372 4373
    match tcx.trait_impls.find(&trait_id) {
        Some(ty_to_impl) => match ty_to_impl.find(&self_ty) {
4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385
            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),
                    None => tcx.sess.bug(~"get_impl_id: no impl of trait for \
                                           this type")
            }
        },
        None => tcx.sess.bug(~"get_impl_id: trait isn't in trait_impls")
    }
}

4386
impl cmp::Eq for mt {
4387 4388 4389 4390
    pure fn eq(&self, other: &mt) -> bool {
        (*self).ty == (*other).ty && (*self).mutbl == (*other).mutbl
    }
    pure fn ne(&self, other: &mt) -> bool { !(*self).eq(other) }
4391
}
4392

4393
impl cmp::Eq for vstore {
4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422
    pure fn eq(&self, other: &vstore) -> bool {
        match (*self) {
            vstore_fixed(e0a) => {
                match (*other) {
                    vstore_fixed(e0b) => e0a == e0b,
                    _ => false
                }
            }
            vstore_uniq => {
                match (*other) {
                    vstore_uniq => true,
                    _ => false
                }
            }
            vstore_box => {
                match (*other) {
                    vstore_box => true,
                    _ => false
                }
            }
            vstore_slice(e0a) => {
                match (*other) {
                    vstore_slice(e0b) => e0a == e0b,
                    _ => false
                }
            }
        }
    }
    pure fn ne(&self, other: &vstore) -> bool { !(*self).eq(other) }
4423
}
4424

4425
impl cmp::Eq for Region {
4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460
    pure fn eq(&self, other: &Region) -> bool {
        match (*self) {
            re_bound(e0a) => {
                match (*other) {
                    re_bound(e0b) => e0a == e0b,
                    _ => false
                }
            }
            re_free(e0a, e1a) => {
                match (*other) {
                    re_free(e0b, e1b) => e0a == e0b && e1a == e1b,
                    _ => false
                }
            }
            re_scope(e0a) => {
                match (*other) {
                    re_scope(e0b) => e0a == e0b,
                    _ => false
                }
            }
            re_static => {
                match (*other) {
                    re_static => true,
                    _ => false
                }
            }
            re_infer(e0a) => {
                match (*other) {
                    re_infer(e0b) => e0a == e0b,
                    _ => false
                }
            }
        }
    }
    pure fn ne(&self, other: &Region) -> bool { !(*self).eq(other) }
4461
}
4462

4463
impl cmp::Eq for bound_region {
4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489
    pure fn eq(&self, other: &bound_region) -> bool {
        match (*self) {
            br_self => {
                match (*other) {
                    br_self => true,
                    _ => false
                }
            }
            br_anon(e0a) => {
                match (*other) {
                    br_anon(e0b) => e0a == e0b,
                    _ => false
                }
            }
            br_named(e0a) => {
                match (*other) {
                    br_named(e0b) => e0a == e0b,
                    _ => false
                }
            }
            br_cap_avoid(e0a, e1a) => {
                match (*other) {
                    br_cap_avoid(e0b, e1b) => e0a == e0b && e1a == e1b,
                    _ => false
                }
            }
4490 4491 4492 4493 4494 4495
            br_fresh(e0a) => {
                match (*other) {
                    br_fresh(e0b) => e0a == e0b,
                    _ => false
                }
            }
4496 4497 4498
        }
    }
    pure fn ne(&self, other: &bound_region) -> bool { !(*self).eq(other) }
4499
}
4500

4501
impl cmp::Eq for param_bound {
4502 4503 4504 4505 4506 4507 4508 4509
    pure fn eq(&self, other: &param_bound) -> bool {
        match (*self) {
            bound_copy => {
                match (*other) {
                    bound_copy => true,
                    _ => false
                }
            }
B
Brian Anderson 已提交
4510
            bound_durable => {
4511
                match (*other) {
B
Brian Anderson 已提交
4512
                    bound_durable => true,
4513 4514 4515
                    _ => false
                }
            }
B
Brian Anderson 已提交
4516
            bound_owned => {
4517
                match (*other) {
B
Brian Anderson 已提交
4518
                    bound_owned => true,
4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535
                    _ => false
                }
            }
            bound_const => {
                match (*other) {
                    bound_const => true,
                    _ => false
                }
            }
            bound_trait(e0a) => {
                match (*other) {
                    bound_trait(e0b) => e0a == e0b,
                    _ => false
                }
            }
        }
    }
B
Brian Anderson 已提交
4536
    pure fn ne(&self, other: &param_bound) -> bool { !self.eq(other) }
4537
}
4538

4539 4540 4541 4542 4543 4544 4545
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End: