use middle::ty::{TyVar};
use middle::ty::{IntType, UintType};
-use middle::ty::{self, Ty, TypeError};
+use middle::ty::{self, Ty};
+use middle::ty::error::TypeError;
use middle::ty::fold::{TypeFolder, TypeFoldable};
use middle::ty::relate::{Relate, RelateResult, TypeRelation};
pub trait RelateResultCompare<'tcx, T> {
fn compare<F>(&self, t: T, f: F) -> RelateResult<'tcx, T> where
- F: FnOnce() -> ty::TypeError<'tcx>;
+ F: FnOnce() -> TypeError<'tcx>;
}
impl<'tcx, T:Clone + PartialEq> RelateResultCompare<'tcx, T> for RelateResult<'tcx, T> {
fn compare<F>(&self, t: T, f: F) -> RelateResult<'tcx, T> where
- F: FnOnce() -> ty::TypeError<'tcx>,
+ F: FnOnce() -> TypeError<'tcx>,
{
self.clone().and_then(|s| {
if s == t {
}
fn int_unification_error<'tcx>(a_is_expected: bool, v: (ty::IntVarValue, ty::IntVarValue))
- -> ty::TypeError<'tcx>
+ -> TypeError<'tcx>
{
let (a, b) = v;
TypeError::IntMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b))
fn float_unification_error<'tcx>(a_is_expected: bool,
v: (hir::FloatTy, hir::FloatTy))
- -> ty::TypeError<'tcx>
+ -> TypeError<'tcx>
{
let (a, b) = v;
TypeError::FloatMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b))
use middle::infer;
use middle::region;
use middle::subst;
-use middle::ty::{self, Ty, TypeError, HasTypeFlags};
+use middle::ty::{self, Ty, HasTypeFlags};
use middle::ty::{Region, ReFree};
+use middle::ty::error::TypeError;
use std::cell::{Cell, RefCell};
use std::char::from_u32;
fn process_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>)
-> Vec<RegionResolutionError<'tcx>>;
- fn report_type_error(&self, trace: TypeTrace<'tcx>, terr: &ty::TypeError<'tcx>);
+ fn report_type_error(&self, trace: TypeTrace<'tcx>, terr: &TypeError<'tcx>);
- fn check_and_note_conflicting_crates(&self, terr: &ty::TypeError<'tcx>, sp: Span);
+ fn check_and_note_conflicting_crates(&self, terr: &TypeError<'tcx>, sp: Span);
fn report_and_explain_type_error(&self,
trace: TypeTrace<'tcx>,
- terr: &ty::TypeError<'tcx>);
+ terr: &TypeError<'tcx>);
fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<String>;
fn expected_found_str<T: fmt::Display + Resolvable<'tcx> + HasTypeFlags>(
&self,
- exp_found: &ty::ExpectedFound<T>)
+ exp_found: &ty::error::ExpectedFound<T>)
-> Option<String>;
fn report_concrete_failure(&self,
fn report_processed_errors(&self,
var_origin: &[RegionVariableOrigin],
- trace_origin: &[(TypeTrace<'tcx>, ty::TypeError<'tcx>)],
+ trace_origin: &[(TypeTrace<'tcx>, TypeError<'tcx>)],
same_regions: &[SameRegions]);
fn give_suggestion(&self, same_regions: &[SameRegions]);
}
}
- fn report_type_error(&self, trace: TypeTrace<'tcx>, terr: &ty::TypeError<'tcx>) {
+ fn report_type_error(&self, trace: TypeTrace<'tcx>, terr: &TypeError<'tcx>) {
let expected_found_str = match self.values_str(&trace.values) {
Some(v) => v,
None => {
}
/// Adds a note if the types come from similarly named crates
- fn check_and_note_conflicting_crates(&self, terr: &ty::TypeError<'tcx>, sp: Span) {
+ fn check_and_note_conflicting_crates(&self, terr: &TypeError<'tcx>, sp: Span) {
let report_path_match = |did1: DefId, did2: DefId| {
// Only external crates, if either is from a local
// module we could have false positives
}
};
match *terr {
- ty::TypeError::Sorts(ref exp_found) => {
+ TypeError::Sorts(ref exp_found) => {
// if they are both "path types", there's a chance of ambiguity
// due to different versions of the same crate
match (&exp_found.expected.sty, &exp_found.found.sty) {
_ => ()
}
},
- ty::TypeError::Traits(ref exp_found) => {
+ TypeError::Traits(ref exp_found) => {
self.tcx.sess.note("errrr0");
report_path_match(exp_found.expected, exp_found.found);
},
fn report_and_explain_type_error(&self,
trace: TypeTrace<'tcx>,
- terr: &ty::TypeError<'tcx>) {
+ terr: &TypeError<'tcx>) {
let span = trace.origin.span();
self.report_type_error(trace, terr);
self.tcx.note_and_explain_type_err(terr, span);
fn expected_found_str<T: fmt::Display + Resolvable<'tcx> + HasTypeFlags>(
&self,
- exp_found: &ty::ExpectedFound<T>)
+ exp_found: &ty::error::ExpectedFound<T>)
-> Option<String>
{
let expected = exp_found.expected.resolve(self);
fn report_processed_errors(&self,
var_origins: &[RegionVariableOrigin],
- trace_origins: &[(TypeTrace<'tcx>, ty::TypeError<'tcx>)],
+ trace_origins: &[(TypeTrace<'tcx>, TypeError<'tcx>)],
same_regions: &[SameRegions]) {
for vo in var_origins {
self.report_inference_failure(vo.clone());
use super::{CombinedSnapshot, InferCtxt, HigherRankedType, SkolemizationMap};
use super::combine::CombineFields;
-use middle::ty::{self, TypeError, Binder};
+use middle::ty::{self, Binder};
+use middle::ty::error::TypeError;
use middle::ty::fold::TypeFoldable;
use middle::ty::relate::{Relate, RelateResult, TypeRelation};
use syntax::codemap::Span;
where T: TypeFoldable<'tcx>,
F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region,
{
- ty::fold::fold_regions(tcx, unbound_value, &mut false, |region, current_depth| {
+ tcx.fold_regions(unbound_value, &mut false, |region, current_depth| {
// we should only be encountering "escaping" late-bound regions here,
// because the ones at the current level should have been replaced
// with fresh variables
let mut escaping_region_vars = FnvHashSet();
for ty in &escaping_types {
- ty::fold::collect_regions(self.tcx, ty, &mut escaping_region_vars);
+ self.tcx.collect_regions(ty, &mut escaping_region_vars);
}
region_vars.retain(|®ion_vid| {
* details.
*/
- let (result, map) = ty::fold::replace_late_bound_regions(infcx.tcx, binder, |br| {
+ let (result, map) = infcx.tcx.replace_late_bound_regions(binder, |br| {
infcx.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot)
});
// binder is that we encountered in `value`. The caller is
// responsible for ensuring that (a) `value` contains at least one
// binder and (b) that binder is the one we want to use.
- let result = ty::fold::fold_regions(infcx.tcx, &value, &mut false, |r, current_depth| {
+ let result = infcx.tcx.fold_regions(&value, &mut false, |r, current_depth| {
match inv_skol_map.get(&r) {
None => r,
Some(br) => {
use middle::subst::Subst;
use middle::traits::{self, FulfillmentContext, Normalized,
SelectionContext, ObligationCause};
-use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, UnconstrainedNumeric};
-use middle::ty::{self, Ty, TypeError, HasTypeFlags};
+use middle::ty::{TyVid, IntVid, FloatVid, RegionVid};
+use middle::ty::{self, Ty, HasTypeFlags};
+use middle::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
use middle::ty::fold::{TypeFolder, TypeFoldable};
use middle::ty::relate::{Relate, RelateResult, TypeRelation};
use rustc_data_structures::unify::{self, UnificationTable};
/// See `error_reporting.rs` for more details
#[derive(Clone, Debug)]
pub enum ValuePairs<'tcx> {
- Types(ty::ExpectedFound<Ty<'tcx>>),
- TraitRefs(ty::ExpectedFound<ty::TraitRef<'tcx>>),
- PolyTraitRefs(ty::ExpectedFound<ty::PolyTraitRef<'tcx>>),
+ Types(ExpectedFound<Ty<'tcx>>),
+ TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>),
+ PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>),
}
/// The trace designates the path through inference that we took to
fn expected_found<T>(a_is_expected: bool,
a: T,
b: T)
- -> ty::ExpectedFound<T>
+ -> ExpectedFound<T>
{
if a_is_expected {
- ty::ExpectedFound {expected: a, found: b}
+ ExpectedFound {expected: a, found: b}
} else {
- ty::ExpectedFound {expected: b, found: a}
+ ExpectedFound {expected: b, found: a}
}
}
}
pub fn type_is_unconstrained_numeric(&'a self, ty: Ty) -> UnconstrainedNumeric {
- use middle::ty::UnconstrainedNumeric::{Neither, UnconstrainedInt, UnconstrainedFloat};
+ use middle::ty::error::UnconstrainedNumeric::Neither;
+ use middle::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
match ty.sty {
ty::TyInfer(ty::IntVar(vid)) => {
if self.int_unification_table.borrow_mut().has_value(vid) {
sp: Span,
mk_msg: M,
actual_ty: String,
- err: Option<&ty::TypeError<'tcx>>) where
+ err: Option<&TypeError<'tcx>>) where
M: FnOnce(Option<String>, String) -> String,
{
self.type_error_message_str_with_expected(sp, mk_msg, None, actual_ty, err)
mk_msg: M,
expected_ty: Option<Ty<'tcx>>,
actual_ty: String,
- err: Option<&ty::TypeError<'tcx>>) where
+ err: Option<&TypeError<'tcx>>) where
M: FnOnce(Option<String>, String) -> String,
{
debug!("hi! expected_ty = {:?}, actual_ty = {}", expected_ty, actual_ty);
sp: Span,
mk_msg: M,
actual_ty: Ty<'tcx>,
- err: Option<&ty::TypeError<'tcx>>) where
+ err: Option<&TypeError<'tcx>>) where
M: FnOnce(String) -> String,
{
let actual_ty = self.resolve_type_vars_if_possible(&actual_ty);
span: Span,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
- err: &ty::TypeError<'tcx>) {
+ err: &TypeError<'tcx>) {
let trace = TypeTrace {
origin: Misc(span),
- values: Types(ty::ExpectedFound {
+ values: Types(ExpectedFound {
expected: expected,
found: actual
})
actual: type_variable::Default<'tcx>) {
let trace = TypeTrace {
origin: Misc(span),
- values: Types(ty::ExpectedFound {
+ values: Types(ExpectedFound {
expected: expected.ty,
found: actual.ty
})
};
self.report_and_explain_type_error(trace,
- &TypeError::TyParamDefaultMismatch(ty::ExpectedFound {
+ &TypeError::TyParamDefaultMismatch(ExpectedFound {
expected: expected,
found: actual
}));
-> (T, FnvHashMap<ty::BoundRegion,ty::Region>)
where T : TypeFoldable<'tcx>
{
- ty::fold::replace_late_bound_regions(
- self.tcx,
+ self.tcx.replace_late_bound_regions(
value,
|br| self.next_region_var(LateBoundRegion(span, br, lbrct)))
}
pub fn dummy(tcx: &ty::ctxt<'tcx>) -> TypeTrace<'tcx> {
TypeTrace {
origin: Misc(codemap::DUMMY_SP),
- values: Types(ty::ExpectedFound {
+ values: Types(ExpectedFound {
expected: tcx.types.err,
found: tcx.types.err,
})
use rustc_data_structures::graph::{self, Direction, NodeIndex};
use middle::free_region::FreeRegionMap;
use middle::region;
-use middle::ty::{self, Ty, TypeError};
+use middle::ty::{self, Ty};
use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid};
use middle::ty::{ReEmpty, ReStatic, ReFree, ReEarlyBound};
use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh};
+use middle::ty::error::TypeError;
use middle::ty::relate::RelateResult;
use util::common::indenter;
use util::nodemap::{FnvHashMap, FnvHashSet};
/// should put a lifetime. In those cases we process and put those errors
/// into `ProcessedErrors` before we do any reporting.
ProcessedErrors(Vec<RegionVariableOrigin>,
- Vec<(TypeTrace<'tcx>, ty::TypeError<'tcx>)>,
+ Vec<(TypeTrace<'tcx>, TypeError<'tcx>)>,
Vec<SameRegions>),
}
Unimplemented,
OutputTypeParameterMismatch(ty::PolyTraitRef<'tcx>,
ty::PolyTraitRef<'tcx>,
- ty::TypeError<'tcx>),
+ ty::error::TypeError<'tcx>),
TraitNotObjectSafe(DefId),
}
#[derive(Clone)]
pub struct MismatchedProjectionTypes<'tcx> {
- pub err: ty::TypeError<'tcx>
+ pub err: ty::error::TypeError<'tcx>
}
#[derive(PartialEq, Eq, Debug)]
// except according to those terms.
use middle::ty::{self, Ty};
+use middle::ty::error::TypeError;
use middle::ty::relate::{self, Relate, TypeRelation, RelateResult};
/// A type "A" *matches* "B" if the fresh types in B could be
(&ty::TyInfer(_), _) |
(_, &ty::TyInfer(_)) => {
- Err(ty::TypeError::Sorts(relate::expected_found(self, &a, &b)))
+ Err(TypeError::Sorts(relate::expected_found(self, &a, &b)))
}
(&ty::TyError, _) | (_, &ty::TyError) => {
--- /dev/null
+// Copyright 2012-2015 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.
+
+use middle::def_id::{DefId};
+use middle::ty::{self, Ty};
+use util::common::{memoized};
+use util::nodemap::FnvHashMap;
+
+use std::fmt;
+use std::ops;
+
+use rustc_front::hir;
+
+/// 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 reference 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.
+#[derive(Clone, Copy)]
+pub struct TypeContents {
+ pub bits: u64
+}
+
+macro_rules! def_type_content_sets {
+ (mod $mname:ident { $($name:ident = $bits:expr),+ }) => {
+ #[allow(non_snake_case)]
+ mod $mname {
+ use super::TypeContents;
+ $(
+ #[allow(non_upper_case_globals)]
+ pub const $name: TypeContents = TypeContents { bits: $bits };
+ )+
+ }
+ }
+}
+
+def_type_content_sets! {
+ mod TC {
+ None = 0b0000_0000__0000_0000__0000,
+
+ // Things that are interior to the value (first nibble):
+ InteriorUnsafe = 0b0000_0000__0000_0000__0010,
+ InteriorParam = 0b0000_0000__0000_0000__0100,
+ // InteriorAll = 0b00000000__00000000__1111,
+
+ // Things that are owned by the value (second and third nibbles):
+ OwnsOwned = 0b0000_0000__0000_0001__0000,
+ OwnsDtor = 0b0000_0000__0000_0010__0000,
+ OwnsAll = 0b0000_0000__1111_1111__0000,
+
+ // Things that mean drop glue is necessary
+ NeedsDrop = 0b0000_0000__0000_0111__0000,
+
+ // All bits
+ All = 0b1111_1111__1111_1111__1111
+ }
+}
+
+impl TypeContents {
+ pub fn when(&self, cond: bool) -> TypeContents {
+ if cond {*self} else {TC::None}
+ }
+
+ pub fn intersects(&self, tc: TypeContents) -> bool {
+ (self.bits & tc.bits) != 0
+ }
+
+ pub fn owns_owned(&self) -> bool {
+ self.intersects(TC::OwnsOwned)
+ }
+
+ pub fn interior_param(&self) -> bool {
+ self.intersects(TC::InteriorParam)
+ }
+
+ pub fn interior_unsafe(&self) -> bool {
+ self.intersects(TC::InteriorUnsafe)
+ }
+
+ pub fn needs_drop(&self, _: &ty::ctxt) -> bool {
+ self.intersects(TC::NeedsDrop)
+ }
+
+ /// Includes only those bits that still apply when indirected through a `Box` pointer
+ pub fn owned_pointer(&self) -> TypeContents {
+ TC::OwnsOwned | (*self & TC::OwnsAll)
+ }
+
+ pub fn union<T, F>(v: &[T], mut f: F) -> TypeContents where
+ F: FnMut(&T) -> TypeContents,
+ {
+ v.iter().fold(TC::None, |tc, ty| tc | f(ty))
+ }
+
+ pub fn has_dtor(&self) -> bool {
+ self.intersects(TC::OwnsDtor)
+ }
+}
+
+impl ops::BitOr for TypeContents {
+ type Output = TypeContents;
+
+ fn bitor(self, other: TypeContents) -> TypeContents {
+ TypeContents {bits: self.bits | other.bits}
+ }
+}
+
+impl ops::BitAnd for TypeContents {
+ type Output = TypeContents;
+
+ fn bitand(self, other: TypeContents) -> TypeContents {
+ TypeContents {bits: self.bits & other.bits}
+ }
+}
+
+impl ops::Sub for TypeContents {
+ type Output = TypeContents;
+
+ fn sub(self, other: TypeContents) -> TypeContents {
+ TypeContents {bits: self.bits & !other.bits}
+ }
+}
+
+impl fmt::Debug for TypeContents {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "TypeContents({:b})", self.bits)
+ }
+}
+
+impl<'tcx> ty::TyS<'tcx> {
+ pub fn type_contents(&'tcx self, cx: &ty::ctxt<'tcx>) -> TypeContents {
+ return memoized(&cx.tc_cache, self, |ty| {
+ tc_ty(cx, ty, &mut FnvHashMap())
+ });
+
+ fn tc_ty<'tcx>(cx: &ty::ctxt<'tcx>,
+ ty: Ty<'tcx>,
+ cache: &mut FnvHashMap<Ty<'tcx>, 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: Box<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::OwnsOwned, 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::OwnsOwned. This manifested as issue #4821.
+ match cache.get(&ty) {
+ Some(tc) => { return *tc; }
+ None => {}
+ }
+ match cx.tc_cache.borrow().get(&ty) { // Must check both caches!
+ Some(tc) => { return *tc; }
+ None => {}
+ }
+ cache.insert(ty, TC::None);
+
+ let result = match ty.sty {
+ // usize and isize are ffi-unsafe
+ ty::TyUint(hir::TyUs) | ty::TyInt(hir::TyIs) => {
+ TC::None
+ }
+
+ // Scalar and unique types are sendable, and durable
+ ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) |
+ ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) |
+ ty::TyBareFn(..) | ty::TyChar => {
+ TC::None
+ }
+
+ ty::TyBox(typ) => {
+ tc_ty(cx, typ, cache).owned_pointer()
+ }
+
+ ty::TyTrait(_) => {
+ TC::All - TC::InteriorParam
+ }
+
+ ty::TyRawPtr(_) => {
+ TC::None
+ }
+
+ ty::TyRef(_, _) => {
+ TC::None
+ }
+
+ ty::TyArray(ty, _) => {
+ tc_ty(cx, ty, cache)
+ }
+
+ ty::TySlice(ty) => {
+ tc_ty(cx, ty, cache)
+ }
+ ty::TyStr => TC::None,
+
+ ty::TyClosure(_, ref substs) => {
+ TypeContents::union(&substs.upvar_tys, |ty| tc_ty(cx, &ty, cache))
+ }
+
+ ty::TyTuple(ref tys) => {
+ TypeContents::union(&tys[..],
+ |ty| tc_ty(cx, *ty, cache))
+ }
+
+ ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
+ let mut res =
+ TypeContents::union(&def.variants, |v| {
+ TypeContents::union(&v.fields, |f| {
+ tc_ty(cx, f.ty(cx, substs), cache)
+ })
+ });
+
+ if def.has_dtor() {
+ res = res | TC::OwnsDtor;
+ }
+
+ apply_lang_items(cx, def.did, res)
+ }
+
+ ty::TyProjection(..) |
+ ty::TyParam(_) => {
+ TC::All
+ }
+
+ ty::TyInfer(_) |
+ ty::TyError => {
+ cx.sess.bug("asked to compute contents of error type");
+ }
+ };
+
+ cache.insert(ty, result);
+ result
+ }
+
+ fn apply_lang_items(cx: &ty::ctxt, did: DefId, tc: TypeContents)
+ -> TypeContents {
+ if Some(did) == cx.lang_items.unsafe_cell_type() {
+ tc | TC::InteriorUnsafe
+ } else {
+ tc
+ }
+ }
+ }
+}
--- /dev/null
+// Copyright 2012-2015 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.
+
+//! type context book-keeping
+
+// FIXME: (@jroesch) @eddyb should remove this when he renames ctxt
+#![allow(non_camel_case_types)]
+
+use front::map as ast_map;
+use session::Session;
+use lint;
+use middle;
+use middle::def::DefMap;
+use middle::def_id::DefId;
+use middle::free_region::FreeRegionMap;
+use middle::region::RegionMaps;
+use middle::resolve_lifetime;
+use middle::stability;
+use middle::subst::{self, Subst, Substs};
+use middle::traits;
+use middle::ty::{self, TraitRef, Ty, TypeAndMut};
+use middle::ty::{TyS, TypeVariants};
+use middle::ty::{AdtDef, ClosureSubsts, ExistentialBounds, Region};
+use middle::ty::{FreevarMap, GenericPredicates};
+use middle::ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitTy};
+use middle::ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
+use middle::ty::TypeVariants::*;
+use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
+use util::nodemap::FnvHashMap;
+
+use arena::TypedArena;
+use std::borrow::Borrow;
+use std::cell::{Cell, RefCell, Ref};
+use std::hash::{Hash, Hasher};
+use std::rc::Rc;
+use syntax::abi;
+use syntax::ast::{Name, NodeId};
+use syntax::parse::token::special_idents;
+
+use rustc_front::hir;
+use rustc_front::attr;
+
+/// Internal storage
+pub struct CtxtArenas<'tcx> {
+ // internings
+ type_: TypedArena<TyS<'tcx>>,
+ substs: TypedArena<Substs<'tcx>>,
+ bare_fn: TypedArena<BareFnTy<'tcx>>,
+ region: TypedArena<Region>,
+ stability: TypedArena<attr::Stability>,
+
+ // references
+ trait_defs: TypedArena<ty::TraitDef<'tcx>>,
+ adt_defs: TypedArena<ty::AdtDefData<'tcx, 'tcx>>,
+}
+
+impl<'tcx> CtxtArenas<'tcx> {
+ pub fn new() -> CtxtArenas<'tcx> {
+ CtxtArenas {
+ type_: TypedArena::new(),
+ substs: TypedArena::new(),
+ bare_fn: TypedArena::new(),
+ region: TypedArena::new(),
+ stability: TypedArena::new(),
+
+ trait_defs: TypedArena::new(),
+ adt_defs: TypedArena::new()
+ }
+ }
+}
+
+pub struct CommonTypes<'tcx> {
+ pub bool: Ty<'tcx>,
+ pub char: Ty<'tcx>,
+ pub isize: Ty<'tcx>,
+ pub i8: Ty<'tcx>,
+ pub i16: Ty<'tcx>,
+ pub i32: Ty<'tcx>,
+ pub i64: Ty<'tcx>,
+ pub usize: Ty<'tcx>,
+ pub u8: Ty<'tcx>,
+ pub u16: Ty<'tcx>,
+ pub u32: Ty<'tcx>,
+ pub u64: Ty<'tcx>,
+ pub f32: Ty<'tcx>,
+ pub f64: Ty<'tcx>,
+ pub err: Ty<'tcx>,
+}
+
+pub struct Tables<'tcx> {
+ /// 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.
+ pub node_types: NodeMap<Ty<'tcx>>,
+
+ /// 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.
+ pub item_substs: NodeMap<ty::ItemSubsts<'tcx>>,
+
+ pub adjustments: NodeMap<ty::AutoAdjustment<'tcx>>,
+
+ pub method_map: ty::MethodMap<'tcx>,
+
+ /// Borrows
+ pub upvar_capture_map: ty::UpvarCaptureMap,
+
+ /// Records the type of each closure. The def ID is the ID of the
+ /// expression defining the closure.
+ pub closure_tys: DefIdMap<ty::ClosureTy<'tcx>>,
+
+ /// Records the type of each closure. The def ID is the ID of the
+ /// expression defining the closure.
+ pub closure_kinds: DefIdMap<ty::ClosureKind>,
+}
+
+impl<'tcx> Tables<'tcx> {
+ pub fn empty() -> Tables<'tcx> {
+ Tables {
+ node_types: FnvHashMap(),
+ item_substs: NodeMap(),
+ adjustments: NodeMap(),
+ method_map: FnvHashMap(),
+ upvar_capture_map: FnvHashMap(),
+ closure_tys: DefIdMap(),
+ closure_kinds: DefIdMap(),
+ }
+ }
+}
+
+impl<'tcx> CommonTypes<'tcx> {
+ fn new(arena: &'tcx TypedArena<TyS<'tcx>>,
+ interner: &RefCell<FnvHashMap<InternedTy<'tcx>, Ty<'tcx>>>)
+ -> CommonTypes<'tcx>
+ {
+ let mk = |sty| ctxt::intern_ty(arena, interner, sty);
+ CommonTypes {
+ bool: mk(TyBool),
+ char: mk(TyChar),
+ err: mk(TyError),
+ isize: mk(TyInt(hir::TyIs)),
+ i8: mk(TyInt(hir::TyI8)),
+ i16: mk(TyInt(hir::TyI16)),
+ i32: mk(TyInt(hir::TyI32)),
+ i64: mk(TyInt(hir::TyI64)),
+ usize: mk(TyUint(hir::TyUs)),
+ u8: mk(TyUint(hir::TyU8)),
+ u16: mk(TyUint(hir::TyU16)),
+ u32: mk(TyUint(hir::TyU32)),
+ u64: mk(TyUint(hir::TyU64)),
+ f32: mk(TyFloat(hir::TyF32)),
+ f64: mk(TyFloat(hir::TyF64)),
+ }
+ }
+}
+
+/// The data structure to keep track of all the information that typechecker
+/// generates so that so that it can be reused and doesn't have to be redone
+/// later on.
+pub struct ctxt<'tcx> {
+ /// The arenas that types etc are allocated from.
+ arenas: &'tcx CtxtArenas<'tcx>,
+
+ /// Specifically use a speedy hash algorithm for this hash map, it's used
+ /// quite often.
+ // FIXME(eddyb) use a FnvHashSet<InternedTy<'tcx>> when equivalent keys can
+ // queried from a HashSet.
+ interner: RefCell<FnvHashMap<InternedTy<'tcx>, Ty<'tcx>>>,
+
+ // FIXME as above, use a hashset if equivalent elements can be queried.
+ substs_interner: RefCell<FnvHashMap<&'tcx Substs<'tcx>, &'tcx Substs<'tcx>>>,
+ bare_fn_interner: RefCell<FnvHashMap<&'tcx BareFnTy<'tcx>, &'tcx BareFnTy<'tcx>>>,
+ region_interner: RefCell<FnvHashMap<&'tcx Region, &'tcx Region>>,
+ stability_interner: RefCell<FnvHashMap<&'tcx attr::Stability, &'tcx attr::Stability>>,
+
+ /// Common types, pre-interned for your convenience.
+ pub types: CommonTypes<'tcx>,
+
+ pub sess: Session,
+ pub def_map: DefMap,
+
+ pub named_region_map: resolve_lifetime::NamedRegionMap,
+
+ pub region_maps: RegionMaps,
+
+ // For each fn declared in the local crate, type check stores the
+ // free-region relationships that were deduced from its where
+ // clauses and parameter types. These are then read-again by
+ // borrowck. (They are not used during trans, and hence are not
+ // serialized or needed for cross-crate fns.)
+ free_region_maps: RefCell<NodeMap<FreeRegionMap>>,
+ // FIXME: jroesch make this a refcell
+
+ pub tables: RefCell<Tables<'tcx>>,
+
+ /// Maps from a trait item to the trait item "descriptor"
+ pub impl_or_trait_items: RefCell<DefIdMap<ty::ImplOrTraitItem<'tcx>>>,
+
+ /// Maps from a trait def-id to a list of the def-ids of its trait items
+ pub trait_item_def_ids: RefCell<DefIdMap<Rc<Vec<ty::ImplOrTraitItemId>>>>,
+
+ /// A cache for the trait_items() routine
+ pub trait_items_cache: RefCell<DefIdMap<Rc<Vec<ty::ImplOrTraitItem<'tcx>>>>>,
+
+ pub impl_trait_refs: RefCell<DefIdMap<Option<TraitRef<'tcx>>>>,
+ pub trait_defs: RefCell<DefIdMap<&'tcx ty::TraitDef<'tcx>>>,
+ pub adt_defs: RefCell<DefIdMap<ty::AdtDefMaster<'tcx>>>,
+
+ /// Maps from the def-id of an item (trait/struct/enum/fn) to its
+ /// associated predicates.
+ pub predicates: RefCell<DefIdMap<GenericPredicates<'tcx>>>,
+
+ /// Maps from the def-id of a trait to the list of
+ /// super-predicates. This is a subset of the full list of
+ /// predicates. We store these in a separate map because we must
+ /// evaluate them even during type conversion, often before the
+ /// full predicates are available (note that supertraits have
+ /// additional acyclicity requirements).
+ pub super_predicates: RefCell<DefIdMap<GenericPredicates<'tcx>>>,
+
+ pub map: ast_map::Map<'tcx>,
+ pub freevars: RefCell<FreevarMap>,
+ pub tcache: RefCell<DefIdMap<ty::TypeScheme<'tcx>>>,
+ pub rcache: RefCell<FnvHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
+ pub tc_cache: RefCell<FnvHashMap<Ty<'tcx>, ty::contents::TypeContents>>,
+ pub ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
+ pub ty_param_defs: RefCell<NodeMap<ty::TypeParameterDef<'tcx>>>,
+ pub normalized_cache: RefCell<FnvHashMap<Ty<'tcx>, Ty<'tcx>>>,
+ pub lang_items: middle::lang_items::LanguageItems,
+ /// A mapping of fake provided method def_ids to the default implementation
+ pub provided_method_sources: RefCell<DefIdMap<DefId>>,
+
+ /// Maps from def-id of a type or region parameter to its
+ /// (inferred) variance.
+ pub item_variance_map: RefCell<DefIdMap<Rc<ty::ItemVariances>>>,
+
+ /// True if the variance has been computed yet; false otherwise.
+ pub variance_computed: Cell<bool>,
+
+ /// A method will be in this list if and only if it is a destructor.
+ pub destructors: RefCell<DefIdSet>,
+
+ /// Maps a DefId of a type to a list of its inherent impls.
+ /// Contains implementations of methods that are inherent to a type.
+ /// Methods in these implementations don't need to be exported.
+ pub inherent_impls: RefCell<DefIdMap<Rc<Vec<DefId>>>>,
+
+ /// Maps a DefId of an impl to a list of its items.
+ /// Note that this contains all of the impls that we know about,
+ /// including ones in other crates. It's not clear that this is the best
+ /// way to do it.
+ pub impl_items: RefCell<DefIdMap<Vec<ty::ImplOrTraitItemId>>>,
+
+ /// Set of used unsafe nodes (functions or blocks). Unsafe nodes not
+ /// present in this set can be warned about.
+ pub used_unsafe: RefCell<NodeSet>,
+
+ /// Set of nodes which mark locals as mutable which end up getting used at
+ /// some point. Local variable definitions not in this set can be warned
+ /// about.
+ pub used_mut_nodes: RefCell<NodeSet>,
+
+ /// The set of external nominal types whose implementations have been read.
+ /// This is used for lazy resolution of methods.
+ pub populated_external_types: RefCell<DefIdSet>,
+ /// The set of external primitive types whose implementations have been read.
+ /// FIXME(arielb1): why is this separate from populated_external_types?
+ pub populated_external_primitive_impls: RefCell<DefIdSet>,
+
+ /// These caches are used by const_eval when decoding external constants.
+ pub extern_const_statics: RefCell<DefIdMap<NodeId>>,
+ pub extern_const_variants: RefCell<DefIdMap<NodeId>>,
+ pub extern_const_fns: RefCell<DefIdMap<NodeId>>,
+
+ pub node_lint_levels: RefCell<FnvHashMap<(NodeId, lint::LintId),
+ lint::LevelSource>>,
+
+ /// The types that must be asserted to be the same size for `transmute`
+ /// to be valid. We gather up these restrictions in the intrinsicck pass
+ /// and check them in trans.
+ pub transmute_restrictions: RefCell<Vec<ty::TransmuteRestriction<'tcx>>>,
+
+ /// Maps any item's def-id to its stability index.
+ pub stability: RefCell<stability::Index<'tcx>>,
+
+ /// Caches the results of trait selection. This cache is used
+ /// for things that do not have to do with the parameters in scope.
+ pub selection_cache: traits::SelectionCache<'tcx>,
+
+ /// A set of predicates that have been fulfilled *somewhere*.
+ /// This is used to avoid duplicate work. Predicates are only
+ /// added to this set when they mention only "global" names
+ /// (i.e., no type or lifetime parameters).
+ pub fulfilled_predicates: RefCell<traits::FulfilledPredicates<'tcx>>,
+
+ /// Caches the representation hints for struct definitions.
+ pub repr_hint_cache: RefCell<DefIdMap<Rc<Vec<attr::ReprAttr>>>>,
+
+ /// Maps Expr NodeId's to their constant qualification.
+ pub const_qualif_map: RefCell<NodeMap<middle::check_const::ConstQualif>>,
+
+ /// Caches CoerceUnsized kinds for impls on custom types.
+ pub custom_coerce_unsized_kinds: RefCell<DefIdMap<ty::CustomCoerceUnsized>>,
+
+ /// Maps a cast expression to its kind. This is keyed on the
+ /// *from* expression of the cast, not the cast itself.
+ pub cast_kinds: RefCell<NodeMap<ty::cast::CastKind>>,
+
+ /// Maps Fn items to a collection of fragment infos.
+ ///
+ /// The main goal is to identify data (each of which may be moved
+ /// or assigned) whose subparts are not moved nor assigned
+ /// (i.e. their state is *unfragmented*) and corresponding ast
+ /// nodes where the path to that data is moved or assigned.
+ ///
+ /// In the long term, unfragmented values will have their
+ /// destructor entirely driven by a single stack-local drop-flag,
+ /// and their parents, the collections of the unfragmented values
+ /// (or more simply, "fragmented values"), are mapped to the
+ /// corresponding collections of stack-local drop-flags.
+ ///
+ /// (However, in the short term that is not the case; e.g. some
+ /// unfragmented paths still need to be zeroed, namely when they
+ /// reference parent data from an outer scope that was not
+ /// entirely moved, and therefore that needs to be zeroed so that
+ /// we do not get double-drop when we hit the end of the parent
+ /// scope.)
+ ///
+ /// Also: currently the table solely holds keys for node-ids of
+ /// unfragmented values (see `FragmentInfo` enum definition), but
+ /// longer-term we will need to also store mappings from
+ /// fragmented data to the set of unfragmented pieces that
+ /// constitute it.
+ pub fragment_infos: RefCell<DefIdMap<Vec<ty::FragmentInfo>>>,
+}
+impl<'tcx> ctxt<'tcx> {
+ pub fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind {
+ *self.tables.borrow().closure_kinds.get(&def_id).unwrap()
+ }
+
+ pub fn closure_type(&self,
+ def_id: DefId,
+ substs: &ClosureSubsts<'tcx>)
+ -> ty::ClosureTy<'tcx>
+ {
+ self.tables.borrow().closure_tys.get(&def_id).unwrap().subst(self, &substs.func_substs)
+ }
+
+ pub fn type_parameter_def(&self,
+ node_id: NodeId)
+ -> ty::TypeParameterDef<'tcx>
+ {
+ self.ty_param_defs.borrow().get(&node_id).unwrap().clone()
+ }
+
+ pub fn node_types(&self) -> Ref<NodeMap<Ty<'tcx>>> {
+ fn projection<'a, 'tcx>(tables: &'a Tables<'tcx>) -> &'a NodeMap<Ty<'tcx>> {
+ &tables.node_types
+ }
+
+ Ref::map(self.tables.borrow(), projection)
+ }
+
+ pub fn node_type_insert(&self, id: NodeId, ty: Ty<'tcx>) {
+ self.tables.borrow_mut().node_types.insert(id, ty);
+ }
+
+ pub fn intern_trait_def(&self, def: ty::TraitDef<'tcx>)
+ -> &'tcx ty::TraitDef<'tcx> {
+ let did = def.trait_ref.def_id;
+ let interned = self.arenas.trait_defs.alloc(def);
+ self.trait_defs.borrow_mut().insert(did, interned);
+ interned
+ }
+
+ pub fn alloc_trait_def(&self, def: ty::TraitDef<'tcx>)
+ -> &'tcx ty::TraitDef<'tcx> {
+ self.arenas.trait_defs.alloc(def)
+ }
+
+ pub fn intern_adt_def(&self,
+ did: DefId,
+ kind: ty::AdtKind,
+ variants: Vec<ty::VariantDefData<'tcx, 'tcx>>)
+ -> ty::AdtDefMaster<'tcx> {
+ let def = ty::AdtDefData::new(self, did, kind, variants);
+ let interned = self.arenas.adt_defs.alloc(def);
+ // this will need a transmute when reverse-variance is removed
+ self.adt_defs.borrow_mut().insert(did, interned);
+ interned
+ }
+
+ pub fn intern_stability(&self, stab: attr::Stability) -> &'tcx attr::Stability {
+ if let Some(st) = self.stability_interner.borrow().get(&stab) {
+ return st;
+ }
+
+ let interned = self.arenas.stability.alloc(stab);
+ self.stability_interner.borrow_mut().insert(interned, interned);
+ interned
+ }
+
+ pub fn store_free_region_map(&self, id: NodeId, map: FreeRegionMap) {
+ self.free_region_maps.borrow_mut()
+ .insert(id, map);
+ }
+
+ pub fn free_region_map(&self, id: NodeId) -> FreeRegionMap {
+ self.free_region_maps.borrow()[&id].clone()
+ }
+
+ pub fn lift<T: ?Sized + Lift<'tcx>>(&self, value: &T) -> Option<T::Lifted> {
+ value.lift_to_tcx(self)
+ }
+
+ /// Create a type context and call the closure with a `&ty::ctxt` reference
+ /// to the context. The closure enforces that the type context and any interned
+ /// value (types, substs, etc.) can only be used while `ty::tls` has a valid
+ /// reference to the context, to allow formatting values that need it.
+ pub fn create_and_enter<F, R>(s: Session,
+ arenas: &'tcx CtxtArenas<'tcx>,
+ def_map: DefMap,
+ named_region_map: resolve_lifetime::NamedRegionMap,
+ map: ast_map::Map<'tcx>,
+ freevars: RefCell<FreevarMap>,
+ region_maps: RegionMaps,
+ lang_items: middle::lang_items::LanguageItems,
+ stability: stability::Index<'tcx>,
+ f: F) -> (Session, R)
+ where F: FnOnce(&ctxt<'tcx>) -> R
+ {
+ let interner = RefCell::new(FnvHashMap());
+ let common_types = CommonTypes::new(&arenas.type_, &interner);
+
+ tls::enter(ctxt {
+ arenas: arenas,
+ interner: interner,
+ substs_interner: RefCell::new(FnvHashMap()),
+ bare_fn_interner: RefCell::new(FnvHashMap()),
+ region_interner: RefCell::new(FnvHashMap()),
+ stability_interner: RefCell::new(FnvHashMap()),
+ types: common_types,
+ named_region_map: named_region_map,
+ region_maps: region_maps,
+ free_region_maps: RefCell::new(FnvHashMap()),
+ item_variance_map: RefCell::new(DefIdMap()),
+ variance_computed: Cell::new(false),
+ sess: s,
+ def_map: def_map,
+ tables: RefCell::new(Tables::empty()),
+ impl_trait_refs: RefCell::new(DefIdMap()),
+ trait_defs: RefCell::new(DefIdMap()),
+ adt_defs: RefCell::new(DefIdMap()),
+ predicates: RefCell::new(DefIdMap()),
+ super_predicates: RefCell::new(DefIdMap()),
+ fulfilled_predicates: RefCell::new(traits::FulfilledPredicates::new()),
+ map: map,
+ freevars: freevars,
+ tcache: RefCell::new(DefIdMap()),
+ rcache: RefCell::new(FnvHashMap()),
+ tc_cache: RefCell::new(FnvHashMap()),
+ ast_ty_to_ty_cache: RefCell::new(NodeMap()),
+ impl_or_trait_items: RefCell::new(DefIdMap()),
+ trait_item_def_ids: RefCell::new(DefIdMap()),
+ trait_items_cache: RefCell::new(DefIdMap()),
+ ty_param_defs: RefCell::new(NodeMap()),
+ normalized_cache: RefCell::new(FnvHashMap()),
+ lang_items: lang_items,
+ provided_method_sources: RefCell::new(DefIdMap()),
+ destructors: RefCell::new(DefIdSet()),
+ inherent_impls: RefCell::new(DefIdMap()),
+ impl_items: RefCell::new(DefIdMap()),
+ used_unsafe: RefCell::new(NodeSet()),
+ used_mut_nodes: RefCell::new(NodeSet()),
+ populated_external_types: RefCell::new(DefIdSet()),
+ populated_external_primitive_impls: RefCell::new(DefIdSet()),
+ extern_const_statics: RefCell::new(DefIdMap()),
+ extern_const_variants: RefCell::new(DefIdMap()),
+ extern_const_fns: RefCell::new(DefIdMap()),
+ node_lint_levels: RefCell::new(FnvHashMap()),
+ transmute_restrictions: RefCell::new(Vec::new()),
+ stability: RefCell::new(stability),
+ selection_cache: traits::SelectionCache::new(),
+ repr_hint_cache: RefCell::new(DefIdMap()),
+ const_qualif_map: RefCell::new(NodeMap()),
+ custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
+ cast_kinds: RefCell::new(NodeMap()),
+ fragment_infos: RefCell::new(DefIdMap()),
+ }, f)
+ }
+}
+
+/// A trait implemented for all X<'a> types which can be safely and
+/// efficiently converted to X<'tcx> as long as they are part of the
+/// provided ty::ctxt<'tcx>.
+/// This can be done, for example, for Ty<'tcx> or &'tcx Substs<'tcx>
+/// by looking them up in their respective interners.
+/// None is returned if the value or one of the components is not part
+/// of the provided context.
+/// For Ty, None can be returned if either the type interner doesn't
+/// contain the TypeVariants key or if the address of the interned
+/// pointer differs. The latter case is possible if a primitive type,
+/// e.g. `()` or `u8`, was interned in a different context.
+pub trait Lift<'tcx> {
+ type Lifted;
+ fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Self::Lifted>;
+}
+
+impl<'a, 'tcx> Lift<'tcx> for Ty<'a> {
+ type Lifted = Ty<'tcx>;
+ fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Ty<'tcx>> {
+ if let Some(&ty) = tcx.interner.borrow().get(&self.sty) {
+ if *self as *const _ == ty as *const _ {
+ return Some(ty);
+ }
+ }
+ None
+ }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
+ type Lifted = &'tcx Substs<'tcx>;
+ fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<&'tcx Substs<'tcx>> {
+ if let Some(&substs) = tcx.substs_interner.borrow().get(*self) {
+ if *self as *const _ == substs as *const _ {
+ return Some(substs);
+ }
+ }
+ None
+ }
+}
+
+
+pub mod tls {
+ use middle::ty;
+ use session::Session;
+
+ use std::fmt;
+ use syntax::codemap;
+
+ /// Marker type used for the scoped TLS slot.
+ /// The type context cannot be used directly because the scoped TLS
+ /// in libstd doesn't allow types generic over lifetimes.
+ struct ThreadLocalTyCx;
+
+ scoped_thread_local!(static TLS_TCX: ThreadLocalTyCx);
+
+ fn span_debug(span: codemap::Span, f: &mut fmt::Formatter) -> fmt::Result {
+ with(|tcx| {
+ write!(f, "{}", tcx.sess.codemap().span_to_string(span))
+ })
+ }
+
+ pub fn enter<'tcx, F: FnOnce(&ty::ctxt<'tcx>) -> R, R>(tcx: ty::ctxt<'tcx>, f: F)
+ -> (Session, R) {
+ let result = codemap::SPAN_DEBUG.with(|span_dbg| {
+ let original_span_debug = span_dbg.get();
+ span_dbg.set(span_debug);
+ let tls_ptr = &tcx as *const _ as *const ThreadLocalTyCx;
+ let result = TLS_TCX.set(unsafe { &*tls_ptr }, || f(&tcx));
+ span_dbg.set(original_span_debug);
+ result
+ });
+ (tcx.sess, result)
+ }
+
+ pub fn with<F: FnOnce(&ty::ctxt) -> R, R>(f: F) -> R {
+ TLS_TCX.with(|tcx| f(unsafe { &*(tcx as *const _ as *const ty::ctxt) }))
+ }
+
+ pub fn with_opt<F: FnOnce(Option<&ty::ctxt>) -> R, R>(f: F) -> R {
+ if TLS_TCX.is_set() {
+ with(|v| f(Some(v)))
+ } else {
+ f(None)
+ }
+ }
+}
+
+macro_rules! sty_debug_print {
+ ($ctxt: expr, $($variant: ident),*) => {{
+ // curious inner module to allow variant names to be used as
+ // variable names.
+ #[allow(non_snake_case)]
+ mod inner {
+ use middle::ty;
+ #[derive(Copy, Clone)]
+ struct DebugStat {
+ total: usize,
+ region_infer: usize,
+ ty_infer: usize,
+ both_infer: usize,
+ }
+
+ pub fn go(tcx: &ty::ctxt) {
+ let mut total = DebugStat {
+ total: 0,
+ region_infer: 0, ty_infer: 0, both_infer: 0,
+ };
+ $(let mut $variant = total;)*
+
+
+ for (_, t) in tcx.interner.borrow().iter() {
+ let variant = match t.sty {
+ ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) |
+ ty::TyFloat(..) | ty::TyStr => continue,
+ ty::TyError => /* unimportant */ continue,
+ $(ty::$variant(..) => &mut $variant,)*
+ };
+ let region = t.flags.get().intersects(ty::TypeFlags::HAS_RE_INFER);
+ let ty = t.flags.get().intersects(ty::TypeFlags::HAS_TY_INFER);
+
+ variant.total += 1;
+ total.total += 1;
+ if region { total.region_infer += 1; variant.region_infer += 1 }
+ if ty { total.ty_infer += 1; variant.ty_infer += 1 }
+ if region && ty { total.both_infer += 1; variant.both_infer += 1 }
+ }
+ println!("Ty interner total ty region both");
+ $(println!(" {:18}: {uses:6} {usespc:4.1}%, \
+{ty:4.1}% {region:5.1}% {both:4.1}%",
+ stringify!($variant),
+ uses = $variant.total,
+ usespc = $variant.total as f64 * 100.0 / total.total as f64,
+ ty = $variant.ty_infer as f64 * 100.0 / total.total as f64,
+ region = $variant.region_infer as f64 * 100.0 / total.total as f64,
+ both = $variant.both_infer as f64 * 100.0 / total.total as f64);
+ )*
+ println!(" total {uses:6} \
+{ty:4.1}% {region:5.1}% {both:4.1}%",
+ uses = total.total,
+ ty = total.ty_infer as f64 * 100.0 / total.total as f64,
+ region = total.region_infer as f64 * 100.0 / total.total as f64,
+ both = total.both_infer as f64 * 100.0 / total.total as f64)
+ }
+ }
+
+ inner::go($ctxt)
+ }}
+}
+
+impl<'tcx> ctxt<'tcx> {
+ pub fn print_debug_stats(&self) {
+ sty_debug_print!(
+ self,
+ TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyBareFn, TyTrait,
+ TyStruct, TyClosure, TyTuple, TyParam, TyInfer, TyProjection);
+
+ println!("Substs interner: #{}", self.substs_interner.borrow().len());
+ println!("BareFnTy interner: #{}", self.bare_fn_interner.borrow().len());
+ println!("Region interner: #{}", self.region_interner.borrow().len());
+ println!("Stability interner: #{}", self.stability_interner.borrow().len());
+ }
+}
+
+
+/// An entry in the type interner.
+pub struct InternedTy<'tcx> {
+ ty: Ty<'tcx>
+}
+
+// NB: An InternedTy compares and hashes as a sty.
+impl<'tcx> PartialEq for InternedTy<'tcx> {
+ fn eq(&self, other: &InternedTy<'tcx>) -> bool {
+ self.ty.sty == other.ty.sty
+ }
+}
+
+impl<'tcx> Eq for InternedTy<'tcx> {}
+
+impl<'tcx> Hash for InternedTy<'tcx> {
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ self.ty.sty.hash(s)
+ }
+}
+
+impl<'tcx> Borrow<TypeVariants<'tcx>> for InternedTy<'tcx> {
+ fn borrow<'a>(&'a self) -> &'a TypeVariants<'tcx> {
+ &self.ty.sty
+ }
+}
+
+fn bound_list_is_sorted(bounds: &[ty::PolyProjectionPredicate]) -> bool {
+ bounds.is_empty() ||
+ bounds[1..].iter().enumerate().all(
+ |(index, bound)| bounds[index].sort_key() <= bound.sort_key())
+}
+
+impl<'tcx> ctxt<'tcx> {
+ // Type constructors
+ pub fn mk_substs(&self, substs: Substs<'tcx>) -> &'tcx Substs<'tcx> {
+ if let Some(substs) = self.substs_interner.borrow().get(&substs) {
+ return *substs;
+ }
+
+ let substs = self.arenas.substs.alloc(substs);
+ self.substs_interner.borrow_mut().insert(substs, substs);
+ substs
+ }
+
+ /// Create an unsafe fn ty based on a safe fn ty.
+ pub fn safe_to_unsafe_fn_ty(&self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> {
+ assert_eq!(bare_fn.unsafety, hir::Unsafety::Normal);
+ let unsafe_fn_ty_a = self.mk_bare_fn(ty::BareFnTy {
+ unsafety: hir::Unsafety::Unsafe,
+ abi: bare_fn.abi,
+ sig: bare_fn.sig.clone()
+ });
+ self.mk_fn(None, unsafe_fn_ty_a)
+ }
+
+ pub fn mk_bare_fn(&self, bare_fn: BareFnTy<'tcx>) -> &'tcx BareFnTy<'tcx> {
+ if let Some(bare_fn) = self.bare_fn_interner.borrow().get(&bare_fn) {
+ return *bare_fn;
+ }
+
+ let bare_fn = self.arenas.bare_fn.alloc(bare_fn);
+ self.bare_fn_interner.borrow_mut().insert(bare_fn, bare_fn);
+ bare_fn
+ }
+
+ pub fn mk_region(&self, region: Region) -> &'tcx Region {
+ if let Some(region) = self.region_interner.borrow().get(®ion) {
+ return *region;
+ }
+
+ let region = self.arenas.region.alloc(region);
+ self.region_interner.borrow_mut().insert(region, region);
+ region
+ }
+
+ fn intern_ty(type_arena: &'tcx TypedArena<TyS<'tcx>>,
+ interner: &RefCell<FnvHashMap<InternedTy<'tcx>, Ty<'tcx>>>,
+ st: TypeVariants<'tcx>)
+ -> Ty<'tcx> {
+ let ty: Ty /* don't be &mut TyS */ = {
+ let mut interner = interner.borrow_mut();
+ match interner.get(&st) {
+ Some(ty) => return *ty,
+ _ => ()
+ }
+
+ let flags = super::flags::FlagComputation::for_sty(&st);
+
+ let ty = match () {
+ () => type_arena.alloc(TyS { sty: st,
+ flags: Cell::new(flags.flags),
+ region_depth: flags.depth, }),
+ };
+
+ interner.insert(InternedTy { ty: ty }, ty);
+ ty
+ };
+
+ debug!("Interned type: {:?} Pointer: {:?}",
+ ty, ty as *const TyS);
+ ty
+ }
+
+ // 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 Ty above).
+ pub fn mk_ty(&self, st: TypeVariants<'tcx>) -> Ty<'tcx> {
+ ctxt::intern_ty(&self.arenas.type_, &self.interner, st)
+ }
+
+ pub fn mk_mach_int(&self, tm: hir::IntTy) -> Ty<'tcx> {
+ match tm {
+ hir::TyIs => self.types.isize,
+ hir::TyI8 => self.types.i8,
+ hir::TyI16 => self.types.i16,
+ hir::TyI32 => self.types.i32,
+ hir::TyI64 => self.types.i64,
+ }
+ }
+
+ pub fn mk_mach_uint(&self, tm: hir::UintTy) -> Ty<'tcx> {
+ match tm {
+ hir::TyUs => self.types.usize,
+ hir::TyU8 => self.types.u8,
+ hir::TyU16 => self.types.u16,
+ hir::TyU32 => self.types.u32,
+ hir::TyU64 => self.types.u64,
+ }
+ }
+
+ pub fn mk_mach_float(&self, tm: hir::FloatTy) -> Ty<'tcx> {
+ match tm {
+ hir::TyF32 => self.types.f32,
+ hir::TyF64 => self.types.f64,
+ }
+ }
+
+ pub fn mk_str(&self) -> Ty<'tcx> {
+ self.mk_ty(TyStr)
+ }
+
+ pub fn mk_static_str(&self) -> Ty<'tcx> {
+ self.mk_imm_ref(self.mk_region(ty::ReStatic), self.mk_str())
+ }
+
+ pub fn mk_enum(&self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
+ // take a copy of substs so that we own the vectors inside
+ self.mk_ty(TyEnum(def, substs))
+ }
+
+ pub fn mk_box(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ self.mk_ty(TyBox(ty))
+ }
+
+ pub fn mk_ptr(&self, tm: TypeAndMut<'tcx>) -> Ty<'tcx> {
+ self.mk_ty(TyRawPtr(tm))
+ }
+
+ pub fn mk_ref(&self, r: &'tcx Region, tm: TypeAndMut<'tcx>) -> Ty<'tcx> {
+ self.mk_ty(TyRef(r, tm))
+ }
+
+ pub fn mk_mut_ref(&self, r: &'tcx Region, ty: Ty<'tcx>) -> Ty<'tcx> {
+ self.mk_ref(r, TypeAndMut {ty: ty, mutbl: hir::MutMutable})
+ }
+
+ pub fn mk_imm_ref(&self, r: &'tcx Region, ty: Ty<'tcx>) -> Ty<'tcx> {
+ self.mk_ref(r, TypeAndMut {ty: ty, mutbl: hir::MutImmutable})
+ }
+
+ pub fn mk_mut_ptr(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ self.mk_ptr(TypeAndMut {ty: ty, mutbl: hir::MutMutable})
+ }
+
+ pub fn mk_imm_ptr(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ self.mk_ptr(TypeAndMut {ty: ty, mutbl: hir::MutImmutable})
+ }
+
+ pub fn mk_nil_ptr(&self) -> Ty<'tcx> {
+ self.mk_imm_ptr(self.mk_nil())
+ }
+
+ pub fn mk_array(&self, ty: Ty<'tcx>, n: usize) -> Ty<'tcx> {
+ self.mk_ty(TyArray(ty, n))
+ }
+
+ pub fn mk_slice(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ self.mk_ty(TySlice(ty))
+ }
+
+ pub fn mk_tup(&self, ts: Vec<Ty<'tcx>>) -> Ty<'tcx> {
+ self.mk_ty(TyTuple(ts))
+ }
+
+ pub fn mk_nil(&self) -> Ty<'tcx> {
+ self.mk_tup(Vec::new())
+ }
+
+ pub fn mk_bool(&self) -> Ty<'tcx> {
+ self.mk_ty(TyBool)
+ }
+
+ pub fn mk_fn(&self,
+ opt_def_id: Option<DefId>,
+ fty: &'tcx BareFnTy<'tcx>) -> Ty<'tcx> {
+ self.mk_ty(TyBareFn(opt_def_id, fty))
+ }
+
+ pub fn mk_ctor_fn(&self,
+ def_id: DefId,
+ input_tys: &[Ty<'tcx>],
+ output: Ty<'tcx>) -> Ty<'tcx> {
+ let input_args = input_tys.iter().cloned().collect();
+ self.mk_fn(Some(def_id), self.mk_bare_fn(BareFnTy {
+ unsafety: hir::Unsafety::Normal,
+ abi: abi::Rust,
+ sig: ty::Binder(ty::FnSig {
+ inputs: input_args,
+ output: ty::FnConverging(output),
+ variadic: false
+ })
+ }))
+ }
+
+ pub fn mk_trait(&self,
+ principal: ty::PolyTraitRef<'tcx>,
+ bounds: ExistentialBounds<'tcx>)
+ -> Ty<'tcx>
+ {
+ assert!(bound_list_is_sorted(&bounds.projection_bounds));
+
+ let inner = box TraitTy {
+ principal: principal,
+ bounds: bounds
+ };
+ self.mk_ty(TyTrait(inner))
+ }
+
+ pub fn mk_projection(&self,
+ trait_ref: TraitRef<'tcx>,
+ item_name: Name)
+ -> Ty<'tcx> {
+ // take a copy of substs so that we own the vectors inside
+ let inner = ProjectionTy { trait_ref: trait_ref, item_name: item_name };
+ self.mk_ty(TyProjection(inner))
+ }
+
+ pub fn mk_struct(&self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
+ // take a copy of substs so that we own the vectors inside
+ self.mk_ty(TyStruct(def, substs))
+ }
+
+ pub fn mk_closure(&self,
+ closure_id: DefId,
+ substs: &'tcx Substs<'tcx>,
+ tys: Vec<Ty<'tcx>>)
+ -> Ty<'tcx> {
+ self.mk_closure_from_closure_substs(closure_id, Box::new(ClosureSubsts {
+ func_substs: substs,
+ upvar_tys: tys
+ }))
+ }
+
+ pub fn mk_closure_from_closure_substs(&self,
+ closure_id: DefId,
+ closure_substs: Box<ClosureSubsts<'tcx>>)
+ -> Ty<'tcx> {
+ self.mk_ty(TyClosure(closure_id, closure_substs))
+ }
+
+ pub fn mk_var(&self, v: TyVid) -> Ty<'tcx> {
+ self.mk_infer(TyVar(v))
+ }
+
+ pub fn mk_int_var(&self, v: IntVid) -> Ty<'tcx> {
+ self.mk_infer(IntVar(v))
+ }
+
+ pub fn mk_float_var(&self, v: FloatVid) -> Ty<'tcx> {
+ self.mk_infer(FloatVar(v))
+ }
+
+ pub fn mk_infer(&self, it: InferTy) -> Ty<'tcx> {
+ self.mk_ty(TyInfer(it))
+ }
+
+ pub fn mk_param(&self,
+ space: subst::ParamSpace,
+ index: u32,
+ name: Name) -> Ty<'tcx> {
+ self.mk_ty(TyParam(ParamTy { space: space, idx: index, name: name }))
+ }
+
+ pub fn mk_self_type(&self) -> Ty<'tcx> {
+ self.mk_param(subst::SelfSpace, 0, special_idents::type_self.name)
+ }
+
+ pub fn mk_param_from_def(&self, def: &ty::TypeParameterDef) -> Ty<'tcx> {
+ self.mk_param(def.space, def.index, def.name)
+ }
+}
--- /dev/null
+// Copyright 2012-2015 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.
+
+use middle::def_id::DefId;
+use middle::subst;
+use middle::infer::type_variable;
+use middle::ty::{self, BoundRegion, Region, Ty};
+
+use std::fmt;
+use syntax::abi;
+use syntax::ast::Name;
+use syntax::codemap::Span;
+
+use rustc_front::hir;
+
+#[derive(Clone, Copy, Debug)]
+pub struct ExpectedFound<T> {
+ pub expected: T,
+ pub found: T
+}
+
+// Data structures used in type unification
+#[derive(Clone, Debug)]
+pub enum TypeError<'tcx> {
+ Mismatch,
+ UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
+ AbiMismatch(ExpectedFound<abi::Abi>),
+ Mutability,
+ BoxMutability,
+ PtrMutability,
+ RefMutability,
+ VecMutability,
+ TupleSize(ExpectedFound<usize>),
+ FixedArraySize(ExpectedFound<usize>),
+ TyParamSize(ExpectedFound<usize>),
+ ArgCount,
+ RegionsDoesNotOutlive(Region, Region),
+ RegionsNotSame(Region, Region),
+ RegionsNoOverlap(Region, Region),
+ RegionsInsufficientlyPolymorphic(BoundRegion, Region),
+ RegionsOverlyPolymorphic(BoundRegion, Region),
+ Sorts(ExpectedFound<Ty<'tcx>>),
+ IntegerAsChar,
+ IntMismatch(ExpectedFound<ty::IntVarValue>),
+ FloatMismatch(ExpectedFound<hir::FloatTy>),
+ Traits(ExpectedFound<DefId>),
+ BuiltinBoundsMismatch(ExpectedFound<ty::BuiltinBounds>),
+ VariadicMismatch(ExpectedFound<bool>),
+ CyclicTy,
+ ConvergenceMismatch(ExpectedFound<bool>),
+ ProjectionNameMismatched(ExpectedFound<Name>),
+ ProjectionBoundsLength(ExpectedFound<usize>),
+ TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>)
+}
+
+#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
+pub enum UnconstrainedNumeric {
+ UnconstrainedFloat,
+ UnconstrainedInt,
+ Neither,
+}
+
+/// 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.
+impl<'tcx> fmt::Display for TypeError<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ use self::TypeError::*;
+ fn report_maybe_different(f: &mut fmt::Formatter,
+ expected: String, found: String) -> fmt::Result {
+ // A naive approach to making sure that we're not reporting silly errors such as:
+ // (expected closure, found closure).
+ if expected == found {
+ write!(f, "expected {}, found a different {}", expected, found)
+ } else {
+ write!(f, "expected {}, found {}", expected, found)
+ }
+ }
+
+ match *self {
+ CyclicTy => write!(f, "cyclic type of infinite size"),
+ Mismatch => write!(f, "types differ"),
+ UnsafetyMismatch(values) => {
+ write!(f, "expected {} fn, found {} fn",
+ values.expected,
+ values.found)
+ }
+ AbiMismatch(values) => {
+ write!(f, "expected {} fn, found {} fn",
+ values.expected,
+ values.found)
+ }
+ Mutability => write!(f, "values differ in mutability"),
+ BoxMutability => {
+ write!(f, "boxed values differ in mutability")
+ }
+ VecMutability => write!(f, "vectors differ in mutability"),
+ PtrMutability => write!(f, "pointers differ in mutability"),
+ RefMutability => write!(f, "references differ in mutability"),
+ TyParamSize(values) => {
+ write!(f, "expected a type with {} type params, \
+ found one with {} type params",
+ values.expected,
+ values.found)
+ }
+ FixedArraySize(values) => {
+ write!(f, "expected an array with a fixed size of {} elements, \
+ found one with {} elements",
+ values.expected,
+ values.found)
+ }
+ TupleSize(values) => {
+ write!(f, "expected a tuple with {} elements, \
+ found one with {} elements",
+ values.expected,
+ values.found)
+ }
+ ArgCount => {
+ write!(f, "incorrect number of function parameters")
+ }
+ RegionsDoesNotOutlive(..) => {
+ write!(f, "lifetime mismatch")
+ }
+ RegionsNotSame(..) => {
+ write!(f, "lifetimes are not the same")
+ }
+ RegionsNoOverlap(..) => {
+ write!(f, "lifetimes do not intersect")
+ }
+ RegionsInsufficientlyPolymorphic(br, _) => {
+ write!(f, "expected bound lifetime parameter {}, \
+ found concrete lifetime", br)
+ }
+ RegionsOverlyPolymorphic(br, _) => {
+ write!(f, "expected concrete lifetime, \
+ found bound lifetime parameter {}", br)
+ }
+ Sorts(values) => ty::tls::with(|tcx| {
+ report_maybe_different(f, values.expected.sort_string(tcx),
+ values.found.sort_string(tcx))
+ }),
+ Traits(values) => ty::tls::with(|tcx| {
+ report_maybe_different(f,
+ format!("trait `{}`",
+ tcx.item_path_str(values.expected)),
+ format!("trait `{}`",
+ tcx.item_path_str(values.found)))
+ }),
+ BuiltinBoundsMismatch(values) => {
+ if values.expected.is_empty() {
+ write!(f, "expected no bounds, found `{}`",
+ values.found)
+ } else if values.found.is_empty() {
+ write!(f, "expected bounds `{}`, found no bounds",
+ values.expected)
+ } else {
+ write!(f, "expected bounds `{}`, found bounds `{}`",
+ values.expected,
+ values.found)
+ }
+ }
+ IntegerAsChar => {
+ write!(f, "expected an integral type, found `char`")
+ }
+ IntMismatch(ref values) => {
+ write!(f, "expected `{:?}`, found `{:?}`",
+ values.expected,
+ values.found)
+ }
+ FloatMismatch(ref values) => {
+ write!(f, "expected `{:?}`, found `{:?}`",
+ values.expected,
+ values.found)
+ }
+ VariadicMismatch(ref values) => {
+ write!(f, "expected {} fn, found {} function",
+ if values.expected { "variadic" } else { "non-variadic" },
+ if values.found { "variadic" } else { "non-variadic" })
+ }
+ ConvergenceMismatch(ref values) => {
+ write!(f, "expected {} fn, found {} function",
+ if values.expected { "converging" } else { "diverging" },
+ if values.found { "converging" } else { "diverging" })
+ }
+ ProjectionNameMismatched(ref values) => {
+ write!(f, "expected {}, found {}",
+ values.expected,
+ values.found)
+ }
+ ProjectionBoundsLength(ref values) => {
+ write!(f, "expected {} associated type bindings, found {}",
+ values.expected,
+ values.found)
+ },
+ TyParamDefaultMismatch(ref values) => {
+ write!(f, "conflicting type parameter defaults `{}` and `{}`",
+ values.expected.ty,
+ values.found.ty)
+ }
+ }
+ }
+}
+
+impl<'tcx> ty::TyS<'tcx> {
+ fn sort_string(&self, cx: &ty::ctxt) -> String {
+ match self.sty {
+ ty::TyBool | ty::TyChar | ty::TyInt(_) |
+ ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr => self.to_string(),
+ ty::TyTuple(ref tys) if tys.is_empty() => self.to_string(),
+
+ ty::TyEnum(def, _) => format!("enum `{}`", cx.item_path_str(def.did)),
+ ty::TyBox(_) => "box".to_string(),
+ ty::TyArray(_, n) => format!("array of {} elements", n),
+ ty::TySlice(_) => "slice".to_string(),
+ ty::TyRawPtr(_) => "*-ptr".to_string(),
+ ty::TyRef(_, _) => "&-ptr".to_string(),
+ ty::TyBareFn(Some(_), _) => format!("fn item"),
+ ty::TyBareFn(None, _) => "fn pointer".to_string(),
+ ty::TyTrait(ref inner) => {
+ format!("trait {}", cx.item_path_str(inner.principal_def_id()))
+ }
+ ty::TyStruct(def, _) => {
+ format!("struct `{}`", cx.item_path_str(def.did))
+ }
+ ty::TyClosure(..) => "closure".to_string(),
+ ty::TyTuple(_) => "tuple".to_string(),
+ ty::TyInfer(ty::TyVar(_)) => "inferred type".to_string(),
+ ty::TyInfer(ty::IntVar(_)) => "integral variable".to_string(),
+ ty::TyInfer(ty::FloatVar(_)) => "floating-point variable".to_string(),
+ ty::TyInfer(ty::FreshTy(_)) => "skolemized type".to_string(),
+ ty::TyInfer(ty::FreshIntTy(_)) => "skolemized integral type".to_string(),
+ ty::TyInfer(ty::FreshFloatTy(_)) => "skolemized floating-point type".to_string(),
+ ty::TyProjection(_) => "associated type".to_string(),
+ ty::TyParam(ref p) => {
+ if p.space == subst::SelfSpace {
+ "Self".to_string()
+ } else {
+ "type parameter".to_string()
+ }
+ }
+ ty::TyError => "type error".to_string(),
+ }
+ }
+}
+
+impl<'tcx> ty::ctxt<'tcx> {
+ pub fn note_and_explain_type_err(&self, err: &TypeError<'tcx>, sp: Span) {
+ use self::TypeError::*;
+
+ match err.clone() {
+ RegionsDoesNotOutlive(subregion, superregion) => {
+ self.note_and_explain_region("", subregion, "...");
+ self.note_and_explain_region("...does not necessarily outlive ",
+ superregion, "");
+ }
+ RegionsNotSame(region1, region2) => {
+ self.note_and_explain_region("", region1, "...");
+ self.note_and_explain_region("...is not the same lifetime as ",
+ region2, "");
+ }
+ RegionsNoOverlap(region1, region2) => {
+ self.note_and_explain_region("", region1, "...");
+ self.note_and_explain_region("...does not overlap ",
+ region2, "");
+ }
+ RegionsInsufficientlyPolymorphic(_, conc_region) => {
+ self.note_and_explain_region("concrete lifetime that was found is ",
+ conc_region, "");
+ }
+ RegionsOverlyPolymorphic(_, ty::ReVar(_)) => {
+ // don't bother to print out the message below for
+ // inference variables, it's not very illuminating.
+ }
+ RegionsOverlyPolymorphic(_, conc_region) => {
+ self.note_and_explain_region("expected concrete lifetime is ",
+ conc_region, "");
+ }
+ Sorts(values) => {
+ let expected_str = values.expected.sort_string(self);
+ let found_str = values.found.sort_string(self);
+ if expected_str == found_str && expected_str == "closure" {
+ self.sess.span_note(sp,
+ &format!("no two closures, even if identical, have the same type"));
+ self.sess.span_help(sp,
+ &format!("consider boxing your closure and/or \
+ using it as a trait object"));
+ }
+ },
+ TyParamDefaultMismatch(values) => {
+ let expected = values.expected;
+ let found = values.found;
+ self.sess.span_note(sp,
+ &format!("conflicting type parameter defaults `{}` and `{}`",
+ expected.ty,
+ found.ty));
+
+ match (expected.def_id.is_local(),
+ self.map.opt_span(expected.def_id.node)) {
+ (true, Some(span)) => {
+ self.sess.span_note(span,
+ &format!("a default was defined here..."));
+ }
+ (_, _) => {
+ self.sess.note(
+ &format!("a default is defined on `{}`",
+ self.item_path_str(expected.def_id)));
+ }
+ }
+
+ self.sess.span_note(
+ expected.origin_span,
+ &format!("...that was applied to an unconstrained type variable here"));
+
+ match (found.def_id.is_local(),
+ self.map.opt_span(found.def_id.node)) {
+ (true, Some(span)) => {
+ self.sess.span_note(span,
+ &format!("a second default was defined here..."));
+ }
+ (_, _) => {
+ self.sess.note(
+ &format!("a second default is defined on `{}`",
+ self.item_path_str(found.def_id)));
+ }
+ }
+
+ self.sess.span_note(
+ found.origin_span,
+ &format!("...that also applies to the same type variable here"));
+ }
+ _ => {}
+ }
+ }
+}
--- /dev/null
+// Copyright 2012-2015 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.
+
+use middle::subst;
+use middle::ty::{self, HasTypeFlags, Ty, TypeFlags};
+
+pub struct FlagComputation {
+ pub flags: TypeFlags,
+
+ // maximum depth of any bound region that we have seen thus far
+ pub depth: u32,
+}
+
+impl FlagComputation {
+ fn new() -> FlagComputation {
+ FlagComputation { flags: TypeFlags::empty(), depth: 0 }
+ }
+
+ pub fn for_sty(st: &ty::TypeVariants) -> FlagComputation {
+ let mut result = FlagComputation::new();
+ result.add_sty(st);
+ result
+ }
+
+ fn add_flags(&mut self, flags: TypeFlags) {
+ self.flags = self.flags | (flags & TypeFlags::NOMINAL_FLAGS);
+ }
+
+ fn add_depth(&mut self, depth: u32) {
+ if depth > self.depth {
+ self.depth = depth;
+ }
+ }
+
+ /// Adds the flags/depth from a set of types that appear within the current type, but within a
+ /// region binder.
+ fn add_bound_computation(&mut self, computation: &FlagComputation) {
+ self.add_flags(computation.flags);
+
+ // The types that contributed to `computation` occurred within
+ // a region binder, so subtract one from the region depth
+ // within when adding the depth to `self`.
+ let depth = computation.depth;
+ if depth > 0 {
+ self.add_depth(depth - 1);
+ }
+ }
+
+ fn add_sty(&mut self, st: &ty::TypeVariants) {
+ match st {
+ &ty::TyBool |
+ &ty::TyChar |
+ &ty::TyInt(_) |
+ &ty::TyFloat(_) |
+ &ty::TyUint(_) |
+ &ty::TyStr => {
+ }
+
+ // You might think that we could just return TyError for
+ // any type containing TyError as a component, and get
+ // rid of the TypeFlags::HAS_TY_ERR flag -- likewise for ty_bot (with
+ // the exception of function types that return bot).
+ // But doing so caused sporadic memory corruption, and
+ // neither I (tjc) nor nmatsakis could figure out why,
+ // so we're doing it this way.
+ &ty::TyError => {
+ self.add_flags(TypeFlags::HAS_TY_ERR)
+ }
+
+ &ty::TyParam(ref p) => {
+ self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
+ if p.space == subst::SelfSpace {
+ self.add_flags(TypeFlags::HAS_SELF);
+ } else {
+ self.add_flags(TypeFlags::HAS_PARAMS);
+ }
+ }
+
+ &ty::TyClosure(_, ref substs) => {
+ self.add_flags(TypeFlags::HAS_TY_CLOSURE);
+ self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
+ self.add_substs(&substs.func_substs);
+ self.add_tys(&substs.upvar_tys);
+ }
+
+ &ty::TyInfer(_) => {
+ self.add_flags(TypeFlags::HAS_LOCAL_NAMES); // it might, right?
+ self.add_flags(TypeFlags::HAS_TY_INFER)
+ }
+
+ &ty::TyEnum(_, substs) | &ty::TyStruct(_, substs) => {
+ self.add_substs(substs);
+ }
+
+ &ty::TyProjection(ref data) => {
+ self.add_flags(TypeFlags::HAS_PROJECTION);
+ self.add_projection_ty(data);
+ }
+
+ &ty::TyTrait(box ty::TraitTy { ref principal, ref bounds }) => {
+ let mut computation = FlagComputation::new();
+ computation.add_substs(principal.0.substs);
+ for projection_bound in &bounds.projection_bounds {
+ let mut proj_computation = FlagComputation::new();
+ proj_computation.add_projection_predicate(&projection_bound.0);
+ self.add_bound_computation(&proj_computation);
+ }
+ self.add_bound_computation(&computation);
+
+ self.add_bounds(bounds);
+ }
+
+ &ty::TyBox(tt) | &ty::TyArray(tt, _) | &ty::TySlice(tt) => {
+ self.add_ty(tt)
+ }
+
+ &ty::TyRawPtr(ref m) => {
+ self.add_ty(m.ty);
+ }
+
+ &ty::TyRef(r, ref m) => {
+ self.add_region(*r);
+ self.add_ty(m.ty);
+ }
+
+ &ty::TyTuple(ref ts) => {
+ self.add_tys(&ts[..]);
+ }
+
+ &ty::TyBareFn(_, ref f) => {
+ self.add_fn_sig(&f.sig);
+ }
+ }
+ }
+
+ fn add_ty(&mut self, ty: Ty) {
+ self.add_flags(ty.flags.get());
+ self.add_depth(ty.region_depth);
+ }
+
+ fn add_tys(&mut self, tys: &[Ty]) {
+ for &ty in tys {
+ self.add_ty(ty);
+ }
+ }
+
+ fn add_fn_sig(&mut self, fn_sig: &ty::PolyFnSig) {
+ let mut computation = FlagComputation::new();
+
+ computation.add_tys(&fn_sig.0.inputs);
+
+ if let ty::FnConverging(output) = fn_sig.0.output {
+ computation.add_ty(output);
+ }
+
+ self.add_bound_computation(&computation);
+ }
+
+ fn add_region(&mut self, r: ty::Region) {
+ match r {
+ ty::ReVar(..) |
+ ty::ReSkolemized(..) => { self.add_flags(TypeFlags::HAS_RE_INFER); }
+ ty::ReLateBound(debruijn, _) => { self.add_depth(debruijn.depth); }
+ ty::ReEarlyBound(..) => { self.add_flags(TypeFlags::HAS_RE_EARLY_BOUND); }
+ ty::ReStatic => {}
+ _ => { self.add_flags(TypeFlags::HAS_FREE_REGIONS); }
+ }
+
+ if !r.is_global() {
+ self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
+ }
+ }
+
+ fn add_projection_predicate(&mut self, projection_predicate: &ty::ProjectionPredicate) {
+ self.add_projection_ty(&projection_predicate.projection_ty);
+ self.add_ty(projection_predicate.ty);
+ }
+
+ fn add_projection_ty(&mut self, projection_ty: &ty::ProjectionTy) {
+ self.add_substs(projection_ty.trait_ref.substs);
+ }
+
+ fn add_substs(&mut self, substs: &subst::Substs) {
+ self.add_tys(substs.types.as_slice());
+ match substs.regions {
+ subst::ErasedRegions => {}
+ subst::NonerasedRegions(ref regions) => {
+ for &r in regions {
+ self.add_region(r);
+ }
+ }
+ }
+ }
+
+ fn add_bounds(&mut self, bounds: &ty::ExistentialBounds) {
+ self.add_region(bounds.region_bound);
+ }
+}
//! If you ever *do* need an override that doesn't exist, it's not hard
//! to convert the degenerate pattern into the proper thing.
+use middle::region;
use middle::subst;
-use middle::subst::VecPerParamSpace;
-use middle::ty::{self, Ty, HasTypeFlags, RegionEscape};
-use middle::traits;
+use middle::ty::{self, Binder, Ty, HasTypeFlags, RegionEscape};
use std::fmt;
-use std::rc::Rc;
-use syntax::abi;
-use rustc_front::hir;
-use syntax::owned_slice::OwnedSlice;
use util::nodemap::{FnvHashMap, FnvHashSet};
///////////////////////////////////////////////////////////////////////////
/// track the Debruijn index nesting level.
fn exit_region_binder(&mut self) { }
- fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
+ fn fold_binder<T>(&mut self, t: &Binder<T>) -> Binder<T>
where T : TypeFoldable<'tcx>
{
// FIXME(#20526) this should replace `enter_region_binder`/`exit_region_binder`.
}
}
-///////////////////////////////////////////////////////////////////////////
-// TypeFoldable implementations.
-//
-// Ideally, each type should invoke `folder.fold_foo(self)` and
-// nothing else. In some cases, though, we haven't gotten around to
-// adding methods on the `folder` yet, and thus the folding is
-// hard-coded here. This is less-flexible, because folders cannot
-// override the behavior, but there are a lot of random types and one
-// can easily refactor the folding into the TypeFolder trait as
-// needed.
-
-macro_rules! CopyImpls {
- ($($ty:ty),+) => {
- $(
- impl<'tcx> TypeFoldable<'tcx> for $ty {
- fn fold_with<F:TypeFolder<'tcx>>(&self, _: &mut F) -> $ty {
- *self
- }
- }
- )+
- }
-}
-
-CopyImpls! { (), hir::Unsafety, abi::Abi }
-
-impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
- fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> (T, U) {
- (self.0.fold_with(folder), self.1.fold_with(folder))
- }
-}
-
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Option<T> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Option<T> {
- self.as_ref().map(|t| t.fold_with(folder))
- }
-}
-
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Rc<T> {
- Rc::new((**self).fold_with(folder))
- }
-}
-
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Box<T> {
- let content: T = (**self).fold_with(folder);
- box content
- }
-}
-
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Vec<T> {
- self.iter().map(|t| t.fold_with(folder)).collect()
- }
-}
-
-impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Binder<T> {
- folder.fold_binder(self)
- }
-}
-
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for OwnedSlice<T> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> OwnedSlice<T> {
- self.iter().map(|t| t.fold_with(folder)).collect()
- }
-}
-
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for VecPerParamSpace<T> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> VecPerParamSpace<T> {
-
- // Things in the Fn space take place under an additional level
- // of region binding relative to the other spaces. This is
- // because those entries are attached to a method, and methods
- // always introduce a level of region binding.
-
- let result = self.map_enumerated(|(space, index, elem)| {
- if space == subst::FnSpace && index == 0 {
- // enter new level when/if we reach the first thing in fn space
- folder.enter_region_binder();
- }
- elem.fold_with(folder)
- });
- if result.len(subst::FnSpace) > 0 {
- // if there was anything in fn space, exit the region binding level
- folder.exit_region_binder();
- }
- result
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Ty<'tcx> {
- folder.fold_ty(*self)
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::BareFnTy<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::BareFnTy<'tcx> {
- folder.fold_bare_fn_ty(self)
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::ClosureTy<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ClosureTy<'tcx> {
- folder.fold_closure_ty(self)
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TypeAndMut<'tcx> {
- folder.fold_mt(self)
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::FnOutput<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::FnOutput<'tcx> {
- folder.fold_output(self)
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::FnSig<'tcx> {
- folder.fold_fn_sig(self)
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TraitRef<'tcx> {
- folder.fold_trait_ref(self)
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::Region {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Region {
- folder.fold_region(*self)
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for subst::Substs<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> subst::Substs<'tcx> {
- folder.fold_substs(self)
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ClosureSubsts<'tcx> {
- let func_substs = self.func_substs.fold_with(folder);
- ty::ClosureSubsts {
- func_substs: folder.tcx().mk_substs(func_substs),
- upvar_tys: self.upvar_tys.fold_with(folder),
- }
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::ItemSubsts<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ItemSubsts<'tcx> {
- ty::ItemSubsts {
- substs: self.substs.fold_with(folder),
- }
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::AutoRef<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::AutoRef<'tcx> {
- folder.fold_autoref(self)
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::BuiltinBounds {
- fn fold_with<F: TypeFolder<'tcx>>(&self, _folder: &mut F) -> ty::BuiltinBounds {
- *self
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialBounds<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ExistentialBounds<'tcx> {
- folder.fold_existential_bounds(self)
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TypeParameterDef<'tcx> {
- ty::TypeParameterDef {
- name: self.name,
- def_id: self.def_id,
- space: self.space,
- index: self.index,
- default: self.default.fold_with(folder),
- default_def_id: self.default_def_id,
- object_lifetime_default: self.object_lifetime_default.fold_with(folder),
- }
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ObjectLifetimeDefault {
- match *self {
- ty::ObjectLifetimeDefault::Ambiguous =>
- ty::ObjectLifetimeDefault::Ambiguous,
-
- ty::ObjectLifetimeDefault::BaseDefault =>
- ty::ObjectLifetimeDefault::BaseDefault,
-
- ty::ObjectLifetimeDefault::Specific(r) =>
- ty::ObjectLifetimeDefault::Specific(r.fold_with(folder)),
- }
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::RegionParameterDef {
- ty::RegionParameterDef {
- name: self.name,
- def_id: self.def_id,
- space: self.space,
- index: self.index,
- bounds: self.bounds.fold_with(folder)
- }
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::Generics<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Generics<'tcx> {
- ty::Generics {
- types: self.types.fold_with(folder),
- regions: self.regions.fold_with(folder),
- }
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::GenericPredicates<'tcx> {
- ty::GenericPredicates {
- predicates: self.predicates.fold_with(folder),
- }
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Predicate<'tcx> {
- match *self {
- ty::Predicate::Trait(ref a) =>
- ty::Predicate::Trait(a.fold_with(folder)),
- ty::Predicate::Equate(ref binder) =>
- ty::Predicate::Equate(binder.fold_with(folder)),
- ty::Predicate::RegionOutlives(ref binder) =>
- ty::Predicate::RegionOutlives(binder.fold_with(folder)),
- ty::Predicate::TypeOutlives(ref binder) =>
- ty::Predicate::TypeOutlives(binder.fold_with(folder)),
- ty::Predicate::Projection(ref binder) =>
- ty::Predicate::Projection(binder.fold_with(folder)),
- ty::Predicate::WellFormed(data) =>
- ty::Predicate::WellFormed(data.fold_with(folder)),
- ty::Predicate::ObjectSafe(trait_def_id) =>
- ty::Predicate::ObjectSafe(trait_def_id),
- }
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionPredicate<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ProjectionPredicate<'tcx> {
- ty::ProjectionPredicate {
- projection_ty: self.projection_ty.fold_with(folder),
- ty: self.ty.fold_with(folder),
- }
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionTy<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ProjectionTy<'tcx> {
- ty::ProjectionTy {
- trait_ref: self.trait_ref.fold_with(folder),
- item_name: self.item_name,
- }
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::InstantiatedPredicates<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::InstantiatedPredicates<'tcx> {
- ty::InstantiatedPredicates {
- predicates: self.predicates.fold_with(folder),
- }
- }
-}
-
-impl<'tcx,O> TypeFoldable<'tcx> for traits::Obligation<'tcx,O>
- where O : TypeFoldable<'tcx>
-{
- fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Obligation<'tcx, O> {
- traits::Obligation {
- cause: self.cause.clone(),
- recursion_depth: self.recursion_depth,
- predicate: self.predicate.fold_with(folder),
- }
- }
-}
-
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableImplData<'tcx, N> {
- fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableImplData<'tcx, N> {
- traits::VtableImplData {
- impl_def_id: self.impl_def_id,
- substs: self.substs.fold_with(folder),
- nested: self.nested.fold_with(folder),
- }
- }
-}
-
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableClosureData<'tcx, N> {
- fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableClosureData<'tcx, N> {
- traits::VtableClosureData {
- closure_def_id: self.closure_def_id,
- substs: self.substs.fold_with(folder),
- nested: self.nested.fold_with(folder),
- }
- }
-}
-
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableDefaultImplData<N> {
- fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableDefaultImplData<N> {
- traits::VtableDefaultImplData {
- trait_def_id: self.trait_def_id,
- nested: self.nested.fold_with(folder),
- }
- }
-}
-
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableBuiltinData<N> {
- fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableBuiltinData<N> {
- traits::VtableBuiltinData {
- nested: self.nested.fold_with(folder),
- }
- }
-}
-
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> {
- fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Vtable<'tcx, N> {
- match *self {
- traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)),
- traits::VtableDefaultImpl(ref t) => traits::VtableDefaultImpl(t.fold_with(folder)),
- traits::VtableClosure(ref d) => {
- traits::VtableClosure(d.fold_with(folder))
- }
- traits::VtableFnPointer(ref d) => {
- traits::VtableFnPointer(d.fold_with(folder))
- }
- traits::VtableParam(ref n) => traits::VtableParam(n.fold_with(folder)),
- traits::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)),
- traits::VtableObject(ref d) => traits::VtableObject(d.fold_with(folder)),
- }
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx> {
- fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableObjectData<'tcx> {
- traits::VtableObjectData {
- upcast_trait_ref: self.upcast_trait_ref.fold_with(folder),
- vtable_base: self.vtable_base
- }
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> {
- fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::EquatePredicate<'tcx> {
- ty::EquatePredicate(self.0.fold_with(folder),
- self.1.fold_with(folder))
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> {
- fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TraitPredicate<'tcx> {
- ty::TraitPredicate {
- trait_ref: self.trait_ref.fold_with(folder)
- }
- }
-}
-
-impl<'tcx,T,U> TypeFoldable<'tcx> for ty::OutlivesPredicate<T,U>
- where T : TypeFoldable<'tcx>,
- U : TypeFoldable<'tcx>,
-{
- fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::OutlivesPredicate<T,U> {
- ty::OutlivesPredicate(self.0.fold_with(folder),
- self.1.fold_with(folder))
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::ClosureUpvar<'tcx> {
- fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ClosureUpvar<'tcx> {
- ty::ClosureUpvar {
- def: self.def,
- span: self.span,
- ty: self.ty.fold_with(folder),
- }
- }
-}
-
-impl<'a, 'tcx> TypeFoldable<'tcx> for ty::ParameterEnvironment<'a, 'tcx> where 'tcx: 'a {
- fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ParameterEnvironment<'a, 'tcx> {
- ty::ParameterEnvironment {
- tcx: self.tcx,
- free_substs: self.free_substs.fold_with(folder),
- implicit_region_bound: self.implicit_region_bound.fold_with(folder),
- caller_bounds: self.caller_bounds.fold_with(folder),
- selection_cache: traits::SelectionCache::new(),
- free_id: self.free_id,
- }
- }
-}
-
///////////////////////////////////////////////////////////////////////////
// "super" routines: these are the default implementations for TypeFolder.
//
// They should invoke `foo.fold_with()` to do recursive folding.
pub fn super_fold_binder<'tcx, T, U>(this: &mut T,
- binder: &ty::Binder<U>)
- -> ty::Binder<U>
+ binder: &Binder<U>)
+ -> Binder<U>
where T : TypeFolder<'tcx>, U : TypeFoldable<'tcx>
{
this.enter_region_binder();
- let result = ty::Binder(binder.0.fold_with(this));
+ let result = Binder(binder.0.fold_with(this));
this.exit_region_binder();
result
}
///////////////////////////////////////////////////////////////////////////
// Region folder
+impl<'tcx> ty::ctxt<'tcx> {
+ /// Collects the free and escaping regions in `value` into `region_set`. Returns
+ /// whether any late-bound regions were skipped
+ pub fn collect_regions<T>(&self,
+ value: &T,
+ region_set: &mut FnvHashSet<ty::Region>)
+ -> bool
+ where T : TypeFoldable<'tcx>
+ {
+ let mut have_bound_regions = false;
+ self.fold_regions(value, &mut have_bound_regions,
+ |r, d| { region_set.insert(r.from_depth(d)); r });
+ have_bound_regions
+ }
+
+ /// Folds the escaping and free regions in `value` using `f`, and
+ /// sets `skipped_regions` to true if any late-bound region was found
+ /// and skipped.
+ pub fn fold_regions<T,F>(&self,
+ value: &T,
+ skipped_regions: &mut bool,
+ mut f: F)
+ -> T
+ where F : FnMut(ty::Region, u32) -> ty::Region,
+ T : TypeFoldable<'tcx>,
+ {
+ value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f))
+ }
+}
+
/// Folds over the substructure of a type, visiting its component
/// types and all regions that occur *free* within it.
///
}
}
-/// Collects the free and escaping regions in `value` into `region_set`. Returns
-/// whether any late-bound regions were skipped
-pub fn collect_regions<'tcx,T>(tcx: &ty::ctxt<'tcx>,
- value: &T,
- region_set: &mut FnvHashSet<ty::Region>) -> bool
- where T : TypeFoldable<'tcx>
-{
- let mut have_bound_regions = false;
- fold_regions(tcx, value, &mut have_bound_regions,
- |r, d| { region_set.insert(r.from_depth(d)); r });
- have_bound_regions
-}
-
-/// Folds the escaping and free regions in `value` using `f`, and
-/// sets `skipped_regions` to true if any late-bound region was found
-/// and skipped.
-pub fn fold_regions<'tcx,T,F>(tcx: &ty::ctxt<'tcx>,
- value: &T,
- skipped_regions: &mut bool,
- mut f: F)
- -> T
- where F : FnMut(ty::Region, u32) -> ty::Region,
- T : TypeFoldable<'tcx>,
-{
- value.fold_with(&mut RegionFolder::new(tcx, skipped_regions, &mut f))
-}
-
impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx>
{
fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx }
map: FnvHashMap<ty::BoundRegion, ty::Region>
}
+impl<'tcx> ty::ctxt<'tcx> {
+ pub fn replace_late_bound_regions<T,F>(&self,
+ value: &Binder<T>,
+ mut f: F)
+ -> (T, FnvHashMap<ty::BoundRegion, ty::Region>)
+ where F : FnMut(ty::BoundRegion) -> ty::Region,
+ T : TypeFoldable<'tcx>,
+ {
+ debug!("replace_late_bound_regions({:?})", value);
+ let mut replacer = RegionReplacer::new(self, &mut f);
+ let result = value.skip_binder().fold_with(&mut replacer);
+ (result, replacer.map)
+ }
+
+
+ /// Replace any late-bound regions bound in `value` with free variants attached to scope-id
+ /// `scope_id`.
+ pub fn liberate_late_bound_regions<T>(&self,
+ all_outlive_scope: region::CodeExtent,
+ value: &Binder<T>)
+ -> T
+ where T : TypeFoldable<'tcx>
+ {
+ self.replace_late_bound_regions(value, |br| {
+ ty::ReFree(ty::FreeRegion{scope: all_outlive_scope, bound_region: br})
+ }).0
+ }
+
+ /// Flattens two binding levels into one. So `for<'a> for<'b> Foo`
+ /// becomes `for<'a,'b> Foo`.
+ pub fn flatten_late_bound_regions<T>(&self, bound2_value: &Binder<Binder<T>>)
+ -> Binder<T>
+ where T: TypeFoldable<'tcx>
+ {
+ let bound0_value = bound2_value.skip_binder().skip_binder();
+ let value = self.fold_regions(bound0_value, &mut false,
+ |region, current_depth| {
+ match region {
+ ty::ReLateBound(debruijn, br) if debruijn.depth >= current_depth => {
+ // should be true if no escaping regions from bound2_value
+ assert!(debruijn.depth - current_depth <= 1);
+ ty::ReLateBound(ty::DebruijnIndex::new(current_depth), br)
+ }
+ _ => {
+ region
+ }
+ }
+ });
+ Binder(value)
+ }
+
+ pub fn no_late_bound_regions<T>(&self, value: &Binder<T>) -> Option<T>
+ where T : TypeFoldable<'tcx> + RegionEscape
+ {
+ if value.0.has_escaping_regions() {
+ None
+ } else {
+ Some(value.0.clone())
+ }
+ }
+
+ /// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also
+ /// method lookup and a few other places where precise region relationships are not required.
+ pub fn erase_late_bound_regions<T>(&self, value: &Binder<T>) -> T
+ where T : TypeFoldable<'tcx>
+ {
+ self.replace_late_bound_regions(value, |_| ty::ReStatic).0
+ }
+
+ /// Rewrite any late-bound regions so that they are anonymous. Region numbers are
+ /// assigned starting at 1 and increasing monotonically in the order traversed
+ /// by the fold operation.
+ ///
+ /// The chief purpose of this function is to canonicalize regions so that two
+ /// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become
+ /// structurally identical. For example, `for<'a, 'b> fn(&'a isize, &'b isize)` and
+ /// `for<'a, 'b> fn(&'b isize, &'a isize)` will become identical after anonymization.
+ pub fn anonymize_late_bound_regions<T>(&self, sig: &Binder<T>) -> Binder<T>
+ where T : TypeFoldable<'tcx>,
+ {
+ let mut counter = 0;
+ Binder(self.replace_late_bound_regions(sig, |_| {
+ counter += 1;
+ ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(counter))
+ }).0)
+ }
+}
+
impl<'a, 'tcx> RegionReplacer<'a, 'tcx> {
fn new<F>(tcx: &'a ty::ctxt<'tcx>, fld_r: &'a mut F) -> RegionReplacer<'a, 'tcx>
where F : FnMut(ty::BoundRegion) -> ty::Region
}
}
-pub fn replace_late_bound_regions<'tcx,T,F>(tcx: &ty::ctxt<'tcx>,
- value: &ty::Binder<T>,
- mut f: F)
- -> (T, FnvHashMap<ty::BoundRegion, ty::Region>)
- where F : FnMut(ty::BoundRegion) -> ty::Region,
- T : TypeFoldable<'tcx>,
-{
- debug!("replace_late_bound_regions({:?})", value);
- let mut replacer = RegionReplacer::new(tcx, &mut f);
- let result = value.skip_binder().fold_with(&mut replacer);
- (result, replacer.map)
-}
-
impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx>
{
fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx }
--- /dev/null
+// Copyright 2015 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.
+
+use middle::ty::{Ty, TyS};
+
+use rustc_data_structures::ivar;
+
+use std::fmt;
+use std::marker::PhantomData;
+use core::nonzero::NonZero;
+
+/// An IVar that contains a Ty. 'lt is a (reverse-variant) upper bound
+/// on the lifetime of the IVar. This is required because of variance
+/// problems: the IVar needs to be variant with respect to 'tcx (so
+/// it can be referred to from Ty) but can only be modified if its
+/// lifetime is exactly 'tcx.
+///
+/// Safety invariants:
+/// (A) self.0, if fulfilled, is a valid Ty<'tcx>
+/// (B) no aliases to this value with a 'tcx longer than this
+/// value's 'lt exist
+///
+/// NonZero is used rather than Unique because Unique isn't Copy.
+pub struct TyIVar<'tcx, 'lt: 'tcx>(ivar::Ivar<NonZero<*const TyS<'static>>>,
+ PhantomData<fn(TyS<'lt>)->TyS<'tcx>>);
+
+impl<'tcx, 'lt> TyIVar<'tcx, 'lt> {
+ #[inline]
+ pub fn new() -> Self {
+ // Invariant (A) satisfied because the IVar is unfulfilled
+ // Invariant (B) because 'lt : 'tcx
+ TyIVar(ivar::Ivar::new(), PhantomData)
+ }
+
+ #[inline]
+ pub fn get(&self) -> Option<Ty<'tcx>> {
+ match self.0.get() {
+ None => None,
+ // valid because of invariant (A)
+ Some(v) => Some(unsafe { &*(*v as *const TyS<'tcx>) })
+ }
+ }
+ #[inline]
+ pub fn unwrap(&self) -> Ty<'tcx> {
+ self.get().unwrap()
+ }
+
+ pub fn fulfill(&self, value: Ty<'lt>) {
+ // Invariant (A) is fulfilled, because by (B), every alias
+ // of this has a 'tcx longer than 'lt.
+ let value: *const TyS<'lt> = value;
+ // FIXME(27214): unneeded [as *const ()]
+ let value = value as *const () as *const TyS<'static>;
+ self.0.fulfill(unsafe { NonZero::new(value) })
+ }
+}
+
+impl<'tcx, 'lt> fmt::Debug for TyIVar<'tcx, 'lt> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self.get() {
+ Some(val) => write!(f, "TyIVar({:?})", val),
+ None => f.write_str("TyIVar(<unfulfilled>)")
+ }
+ }
+}
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// FIXME: (@jroesch) @eddyb should remove this when he renames ctxt
-#![allow(non_camel_case_types)]
-
-pub use self::InferTy::*;
pub use self::ImplOrTraitItemId::*;
pub use self::ClosureKind::*;
pub use self::Variance::*;
pub use self::AutoRef::*;
pub use self::DtorKind::*;
pub use self::ExplicitSelfCategory::*;
-pub use self::FnOutput::*;
-pub use self::Region::*;
pub use self::ImplOrTraitItemContainer::*;
pub use self::BorrowKind::*;
pub use self::ImplOrTraitItem::*;
-pub use self::BoundRegion::*;
-pub use self::TypeVariants::*;
pub use self::IntVarValue::*;
pub use self::CopyImplementationError::*;
pub use self::LvaluePreference::*;
-pub use self::BuiltinBound::Send as BoundSend;
-pub use self::BuiltinBound::Sized as BoundSized;
-pub use self::BuiltinBound::Copy as BoundCopy;
-pub use self::BuiltinBound::Sync as BoundSync;
-
use back::svh::Svh;
-use session::Session;
-use lint;
use front::map as ast_map;
use front::map::LinkedPath;
use metadata::csearch;
use middle;
-use middle::check_const;
use middle::const_eval::{self, ConstVal, ErrKind};
use middle::const_eval::EvalHint::UncheckedExprHint;
-use middle::def::{self, DefMap, ExportMap};
+use middle::def::{self, ExportMap};
use middle::def_id::{DefId, LOCAL_CRATE};
-use middle::free_region::FreeRegionMap;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
-use middle::region;
-use middle::resolve_lifetime;
use middle::infer;
-use middle::infer::type_variable;
use middle::pat_util;
-use middle::region::RegionMaps;
-use middle::stability;
use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace};
use middle::traits;
use middle::ty;
-use middle::ty::fold::{TypeFoldable, TypeFolder};
-use middle::ty::walk::{TypeWalker};
-use util::common::{memoized, ErrorReported};
-use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
+use middle::ty::fold::TypeFolder;
+use middle::ty::walk::TypeWalker;
+use util::common::memoized;
+use util::nodemap::{NodeMap, NodeSet, DefIdMap};
use util::nodemap::FnvHashMap;
use util::num::ToPrimitive;
-use arena::TypedArena;
use std::borrow::{Borrow, Cow};
-use std::cell::{Cell, RefCell, Ref};
+use std::cell::{Cell, RefCell};
use std::cmp;
-use std::fmt;
use std::hash::{Hash, SipHasher, Hasher};
use std::iter;
-use std::marker::PhantomData;
-use std::mem;
-use std::ops;
use std::rc::Rc;
use std::slice;
use std::vec::IntoIter;
-use collections::enum_set::{self, EnumSet, CLike};
-use core::nonzero::NonZero;
use std::collections::{HashMap, HashSet};
-use rustc_data_structures::ivar;
-use syntax::abi;
use syntax::ast::{self, CrateNum, Name, NodeId};
use syntax::codemap::Span;
use syntax::parse::token::{InternedString, special_idents};
use rustc_front::hir::{MutImmutable, MutMutable, Visibility};
use rustc_front::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt};
+pub use self::sty::{Binder, DebruijnIndex};
+pub use self::sty::{BuiltinBound, BuiltinBounds, ExistentialBounds};
+pub use self::sty::{BareFnTy, FnSig, PolyFnSig, FnOutput, PolyFnOutput};
+pub use self::sty::{ClosureTy, InferTy, ParamTy, ProjectionTy, TraitTy};
+pub use self::sty::{ClosureSubsts, TypeAndMut};
+pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef};
+pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region};
+pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid, SkolemizedRegionVid};
+pub use self::sty::BoundRegion::*;
+pub use self::sty::FnOutput::*;
+pub use self::sty::InferTy::*;
+pub use self::sty::Region::*;
+pub use self::sty::TypeVariants::*;
+
+pub use self::sty::BuiltinBound::Send as BoundSend;
+pub use self::sty::BuiltinBound::Sized as BoundSized;
+pub use self::sty::BuiltinBound::Copy as BoundCopy;
+pub use self::sty::BuiltinBound::Sync as BoundSync;
+
+pub use self::contents::TypeContents;
+pub use self::context::{ctxt, tls};
+pub use self::context::{CtxtArenas, Lift, Tables};
+
pub mod cast;
+pub mod error;
pub mod fast_reject;
pub mod fold;
pub mod _match;
pub mod walk;
pub mod wf;
+mod contents;
+mod context;
+mod flags;
+mod ivar;
+mod structural_impls;
+mod sty;
+
pub type Disr = u64;
pub const INITIAL_DISCRIMINANT_VALUE: Disr = 0;
pub container: ImplOrTraitItemContainer,
}
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
-pub struct TypeAndMut<'tcx> {
- pub ty: Ty<'tcx>,
- pub mutbl: hir::Mutability,
-}
-
-
#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub struct ItemVariances {
pub types: VecPerParamSpace<Variance>,
Bivariant, // T<A> <: T<B> -- e.g., unused type parameter
}
-impl fmt::Debug for Variance {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.write_str(match *self {
- Covariant => "+",
- Contravariant => "-",
- Invariant => "o",
- Bivariant => "*",
- })
- }
-}
-
#[derive(Copy, Clone)]
pub enum AutoAdjustment<'tcx> {
AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type
pub id: NodeId,
}
-/// Internal storage
-pub struct CtxtArenas<'tcx> {
- // internings
- type_: TypedArena<TyS<'tcx>>,
- substs: TypedArena<Substs<'tcx>>,
- bare_fn: TypedArena<BareFnTy<'tcx>>,
- region: TypedArena<Region>,
- stability: TypedArena<attr::Stability>,
-
- // references
- trait_defs: TypedArena<TraitDef<'tcx>>,
- adt_defs: TypedArena<AdtDefData<'tcx, 'tcx>>,
-}
-
-impl<'tcx> CtxtArenas<'tcx> {
- pub fn new() -> CtxtArenas<'tcx> {
- CtxtArenas {
- type_: TypedArena::new(),
- substs: TypedArena::new(),
- bare_fn: TypedArena::new(),
- region: TypedArena::new(),
- stability: TypedArena::new(),
-
- trait_defs: TypedArena::new(),
- adt_defs: TypedArena::new()
- }
- }
-}
-
-pub struct CommonTypes<'tcx> {
- pub bool: Ty<'tcx>,
- pub char: Ty<'tcx>,
- pub isize: Ty<'tcx>,
- pub i8: Ty<'tcx>,
- pub i16: Ty<'tcx>,
- pub i32: Ty<'tcx>,
- pub i64: Ty<'tcx>,
- pub usize: Ty<'tcx>,
- pub u8: Ty<'tcx>,
- pub u16: Ty<'tcx>,
- pub u32: Ty<'tcx>,
- pub u64: Ty<'tcx>,
- pub f32: Ty<'tcx>,
- pub f64: Ty<'tcx>,
- pub err: Ty<'tcx>,
-}
-
-pub struct Tables<'tcx> {
- /// 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.
- pub node_types: NodeMap<Ty<'tcx>>,
-
- /// 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.
- pub item_substs: NodeMap<ItemSubsts<'tcx>>,
-
- pub adjustments: NodeMap<ty::AutoAdjustment<'tcx>>,
-
- pub method_map: MethodMap<'tcx>,
-
- /// Borrows
- pub upvar_capture_map: UpvarCaptureMap,
-
- /// Records the type of each closure. The def ID is the ID of the
- /// expression defining the closure.
- pub closure_tys: DefIdMap<ClosureTy<'tcx>>,
-
- /// Records the type of each closure. The def ID is the ID of the
- /// expression defining the closure.
- pub closure_kinds: DefIdMap<ClosureKind>,
-}
-
-impl<'tcx> Tables<'tcx> {
- pub fn empty() -> Tables<'tcx> {
- Tables {
- node_types: FnvHashMap(),
- item_substs: NodeMap(),
- adjustments: NodeMap(),
- method_map: FnvHashMap(),
- upvar_capture_map: FnvHashMap(),
- closure_tys: DefIdMap(),
- closure_kinds: DefIdMap(),
- }
- }
-}
-
-/// The data structure to keep track of all the information that typechecker
-/// generates so that so that it can be reused and doesn't have to be redone
-/// later on.
-pub struct ctxt<'tcx> {
- /// The arenas that types etc are allocated from.
- arenas: &'tcx CtxtArenas<'tcx>,
-
- /// Specifically use a speedy hash algorithm for this hash map, it's used
- /// quite often.
- // FIXME(eddyb) use a FnvHashSet<InternedTy<'tcx>> when equivalent keys can
- // queried from a HashSet.
- interner: RefCell<FnvHashMap<InternedTy<'tcx>, Ty<'tcx>>>,
-
- // FIXME as above, use a hashset if equivalent elements can be queried.
- substs_interner: RefCell<FnvHashMap<&'tcx Substs<'tcx>, &'tcx Substs<'tcx>>>,
- bare_fn_interner: RefCell<FnvHashMap<&'tcx BareFnTy<'tcx>, &'tcx BareFnTy<'tcx>>>,
- region_interner: RefCell<FnvHashMap<&'tcx Region, &'tcx Region>>,
- stability_interner: RefCell<FnvHashMap<&'tcx attr::Stability, &'tcx attr::Stability>>,
-
- /// Common types, pre-interned for your convenience.
- pub types: CommonTypes<'tcx>,
-
- pub sess: Session,
- pub def_map: DefMap,
-
- pub named_region_map: resolve_lifetime::NamedRegionMap,
-
- pub region_maps: RegionMaps,
-
- // For each fn declared in the local crate, type check stores the
- // free-region relationships that were deduced from its where
- // clauses and parameter types. These are then read-again by
- // borrowck. (They are not used during trans, and hence are not
- // serialized or needed for cross-crate fns.)
- free_region_maps: RefCell<NodeMap<FreeRegionMap>>,
- // FIXME: jroesch make this a refcell
-
- pub tables: RefCell<Tables<'tcx>>,
-
- /// Maps from a trait item to the trait item "descriptor"
- pub impl_or_trait_items: RefCell<DefIdMap<ImplOrTraitItem<'tcx>>>,
-
- /// Maps from a trait def-id to a list of the def-ids of its trait items
- pub trait_item_def_ids: RefCell<DefIdMap<Rc<Vec<ImplOrTraitItemId>>>>,
-
- /// A cache for the trait_items() routine
- pub trait_items_cache: RefCell<DefIdMap<Rc<Vec<ImplOrTraitItem<'tcx>>>>>,
-
- pub impl_trait_refs: RefCell<DefIdMap<Option<TraitRef<'tcx>>>>,
- pub trait_defs: RefCell<DefIdMap<&'tcx TraitDef<'tcx>>>,
- pub adt_defs: RefCell<DefIdMap<AdtDefMaster<'tcx>>>,
-
- /// Maps from the def-id of an item (trait/struct/enum/fn) to its
- /// associated predicates.
- pub predicates: RefCell<DefIdMap<GenericPredicates<'tcx>>>,
-
- /// Maps from the def-id of a trait to the list of
- /// super-predicates. This is a subset of the full list of
- /// predicates. We store these in a separate map because we must
- /// evaluate them even during type conversion, often before the
- /// full predicates are available (note that supertraits have
- /// additional acyclicity requirements).
- pub super_predicates: RefCell<DefIdMap<GenericPredicates<'tcx>>>,
-
- pub map: ast_map::Map<'tcx>,
- pub freevars: RefCell<FreevarMap>,
- pub tcache: RefCell<DefIdMap<TypeScheme<'tcx>>>,
- pub rcache: RefCell<FnvHashMap<CReaderCacheKey, Ty<'tcx>>>,
- pub tc_cache: RefCell<FnvHashMap<Ty<'tcx>, TypeContents>>,
- pub ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
- pub ty_param_defs: RefCell<NodeMap<TypeParameterDef<'tcx>>>,
- pub normalized_cache: RefCell<FnvHashMap<Ty<'tcx>, Ty<'tcx>>>,
- pub lang_items: middle::lang_items::LanguageItems,
- /// A mapping of fake provided method def_ids to the default implementation
- pub provided_method_sources: RefCell<DefIdMap<DefId>>,
-
- /// Maps from def-id of a type or region parameter to its
- /// (inferred) variance.
- pub item_variance_map: RefCell<DefIdMap<Rc<ItemVariances>>>,
-
- /// True if the variance has been computed yet; false otherwise.
- pub variance_computed: Cell<bool>,
-
- /// A method will be in this list if and only if it is a destructor.
- pub destructors: RefCell<DefIdSet>,
-
- /// Maps a DefId of a type to a list of its inherent impls.
- /// Contains implementations of methods that are inherent to a type.
- /// Methods in these implementations don't need to be exported.
- pub inherent_impls: RefCell<DefIdMap<Rc<Vec<DefId>>>>,
-
- /// Maps a DefId of an impl to a list of its items.
- /// Note that this contains all of the impls that we know about,
- /// including ones in other crates. It's not clear that this is the best
- /// way to do it.
- pub impl_items: RefCell<DefIdMap<Vec<ImplOrTraitItemId>>>,
-
- /// Set of used unsafe nodes (functions or blocks). Unsafe nodes not
- /// present in this set can be warned about.
- pub used_unsafe: RefCell<NodeSet>,
-
- /// Set of nodes which mark locals as mutable which end up getting used at
- /// some point. Local variable definitions not in this set can be warned
- /// about.
- pub used_mut_nodes: RefCell<NodeSet>,
-
- /// The set of external nominal types whose implementations have been read.
- /// This is used for lazy resolution of methods.
- pub populated_external_types: RefCell<DefIdSet>,
- /// The set of external primitive types whose implementations have been read.
- /// FIXME(arielb1): why is this separate from populated_external_types?
- pub populated_external_primitive_impls: RefCell<DefIdSet>,
-
- /// These caches are used by const_eval when decoding external constants.
- pub extern_const_statics: RefCell<DefIdMap<NodeId>>,
- pub extern_const_variants: RefCell<DefIdMap<NodeId>>,
- pub extern_const_fns: RefCell<DefIdMap<NodeId>>,
-
- pub node_lint_levels: RefCell<FnvHashMap<(NodeId, lint::LintId),
- lint::LevelSource>>,
-
- /// The types that must be asserted to be the same size for `transmute`
- /// to be valid. We gather up these restrictions in the intrinsicck pass
- /// and check them in trans.
- pub transmute_restrictions: RefCell<Vec<TransmuteRestriction<'tcx>>>,
-
- /// Maps any item's def-id to its stability index.
- pub stability: RefCell<stability::Index<'tcx>>,
-
- /// Caches the results of trait selection. This cache is used
- /// for things that do not have to do with the parameters in scope.
- pub selection_cache: traits::SelectionCache<'tcx>,
-
- /// A set of predicates that have been fulfilled *somewhere*.
- /// This is used to avoid duplicate work. Predicates are only
- /// added to this set when they mention only "global" names
- /// (i.e., no type or lifetime parameters).
- pub fulfilled_predicates: RefCell<traits::FulfilledPredicates<'tcx>>,
-
- /// Caches the representation hints for struct definitions.
- pub repr_hint_cache: RefCell<DefIdMap<Rc<Vec<attr::ReprAttr>>>>,
-
- /// Maps Expr NodeId's to their constant qualification.
- pub const_qualif_map: RefCell<NodeMap<check_const::ConstQualif>>,
-
- /// Caches CoerceUnsized kinds for impls on custom types.
- pub custom_coerce_unsized_kinds: RefCell<DefIdMap<CustomCoerceUnsized>>,
-
- /// Maps a cast expression to its kind. This is keyed on the
- /// *from* expression of the cast, not the cast itself.
- pub cast_kinds: RefCell<NodeMap<cast::CastKind>>,
-
- /// Maps Fn items to a collection of fragment infos.
- ///
- /// The main goal is to identify data (each of which may be moved
- /// or assigned) whose subparts are not moved nor assigned
- /// (i.e. their state is *unfragmented*) and corresponding ast
- /// nodes where the path to that data is moved or assigned.
- ///
- /// In the long term, unfragmented values will have their
- /// destructor entirely driven by a single stack-local drop-flag,
- /// and their parents, the collections of the unfragmented values
- /// (or more simply, "fragmented values"), are mapped to the
- /// corresponding collections of stack-local drop-flags.
- ///
- /// (However, in the short term that is not the case; e.g. some
- /// unfragmented paths still need to be zeroed, namely when they
- /// reference parent data from an outer scope that was not
- /// entirely moved, and therefore that needs to be zeroed so that
- /// we do not get double-drop when we hit the end of the parent
- /// scope.)
- ///
- /// Also: currently the table solely holds keys for node-ids of
- /// unfragmented values (see `FragmentInfo` enum definition), but
- /// longer-term we will need to also store mappings from
- /// fragmented data to the set of unfragmented pieces that
- /// constitute it.
- pub fragment_infos: RefCell<DefIdMap<Vec<FragmentInfo>>>,
-}
-
/// Describes the fragment-state associated with a NodeId.
///
/// Currently only unfragmented paths have entries in the table,
Assigned { var: NodeId, assign_expr: NodeId, assignee_id: NodeId },
}
-impl<'tcx> ctxt<'tcx> {
- pub fn node_types(&self) -> Ref<NodeMap<Ty<'tcx>>> {
- fn projection<'a, 'tcx>(tables: &'a Tables<'tcx>) -> &'a NodeMap<Ty<'tcx>> {
- &tables.node_types
- }
-
- Ref::map(self.tables.borrow(), projection)
- }
-
- pub fn node_type_insert(&self, id: NodeId, ty: Ty<'tcx>) {
- self.tables.borrow_mut().node_types.insert(id, ty);
- }
-
- pub fn intern_trait_def(&self, def: TraitDef<'tcx>) -> &'tcx TraitDef<'tcx> {
- let did = def.trait_ref.def_id;
- let interned = self.arenas.trait_defs.alloc(def);
- self.trait_defs.borrow_mut().insert(did, interned);
- interned
- }
-
- pub fn intern_adt_def(&self,
- did: DefId,
- kind: AdtKind,
- variants: Vec<VariantDefData<'tcx, 'tcx>>)
- -> AdtDefMaster<'tcx> {
- let def = AdtDefData::new(self, did, kind, variants);
- let interned = self.arenas.adt_defs.alloc(def);
- // this will need a transmute when reverse-variance is removed
- self.adt_defs.borrow_mut().insert(did, interned);
- interned
- }
-
- pub fn intern_stability(&self, stab: attr::Stability) -> &'tcx attr::Stability {
- if let Some(st) = self.stability_interner.borrow().get(&stab) {
- return st;
- }
-
- let interned = self.arenas.stability.alloc(stab);
- self.stability_interner.borrow_mut().insert(interned, interned);
- interned
- }
-
- pub fn store_free_region_map(&self, id: NodeId, map: FreeRegionMap) {
- self.free_region_maps.borrow_mut()
- .insert(id, map);
- }
-
- pub fn free_region_map(&self, id: NodeId) -> FreeRegionMap {
- self.free_region_maps.borrow()[&id].clone()
- }
-
- pub fn lift<T: ?Sized + Lift<'tcx>>(&self, value: &T) -> Option<T::Lifted> {
- value.lift_to_tcx(self)
- }
-}
-
-/// A trait implemented for all X<'a> types which can be safely and
-/// efficiently converted to X<'tcx> as long as they are part of the
-/// provided ty::ctxt<'tcx>.
-/// This can be done, for example, for Ty<'tcx> or &'tcx Substs<'tcx>
-/// by looking them up in their respective interners.
-/// None is returned if the value or one of the components is not part
-/// of the provided context.
-/// For Ty, None can be returned if either the type interner doesn't
-/// contain the TypeVariants key or if the address of the interned
-/// pointer differs. The latter case is possible if a primitive type,
-/// e.g. `()` or `u8`, was interned in a different context.
-pub trait Lift<'tcx> {
- type Lifted;
- fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Self::Lifted>;
-}
-
-impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>> Lift<'tcx> for (A, B) {
- type Lifted = (A::Lifted, B::Lifted);
- fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Self::Lifted> {
- tcx.lift(&self.0).and_then(|a| tcx.lift(&self.1).map(|b| (a, b)))
- }
-}
-
-impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for [T] {
- type Lifted = Vec<T::Lifted>;
- fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Self::Lifted> {
- let mut result = Vec::with_capacity(self.len());
- for x in self {
- if let Some(value) = tcx.lift(x) {
- result.push(value);
- } else {
- return None;
- }
- }
- Some(result)
- }
-}
-
-impl<'tcx> Lift<'tcx> for Region {
- type Lifted = Self;
- fn lift_to_tcx(&self, _: &ctxt<'tcx>) -> Option<Region> {
- Some(*self)
- }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for Ty<'a> {
- type Lifted = Ty<'tcx>;
- fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Ty<'tcx>> {
- if let Some(&ty) = tcx.interner.borrow().get(&self.sty) {
- if *self as *const _ == ty as *const _ {
- return Some(ty);
- }
- }
- None
- }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
- type Lifted = &'tcx Substs<'tcx>;
- fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<&'tcx Substs<'tcx>> {
- if let Some(&substs) = tcx.substs_interner.borrow().get(*self) {
- if *self as *const _ == substs as *const _ {
- return Some(substs);
- }
- }
- None
- }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for TraitRef<'a> {
- type Lifted = TraitRef<'tcx>;
- fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<TraitRef<'tcx>> {
- tcx.lift(&self.substs).map(|substs| TraitRef {
- def_id: self.def_id,
- substs: substs
- })
- }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for TraitPredicate<'a> {
- type Lifted = TraitPredicate<'tcx>;
- fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<TraitPredicate<'tcx>> {
- tcx.lift(&self.trait_ref).map(|trait_ref| TraitPredicate {
- trait_ref: trait_ref
- })
- }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for EquatePredicate<'a> {
- type Lifted = EquatePredicate<'tcx>;
- fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<EquatePredicate<'tcx>> {
- tcx.lift(&(self.0, self.1)).map(|(a, b)| EquatePredicate(a, b))
- }
-}
-
-impl<'tcx, A: Copy+Lift<'tcx>, B: Copy+Lift<'tcx>> Lift<'tcx> for OutlivesPredicate<A, B> {
- type Lifted = OutlivesPredicate<A::Lifted, B::Lifted>;
- fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Self::Lifted> {
- tcx.lift(&(self.0, self.1)).map(|(a, b)| OutlivesPredicate(a, b))
- }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ProjectionPredicate<'a> {
- type Lifted = ProjectionPredicate<'tcx>;
- fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<ProjectionPredicate<'tcx>> {
- tcx.lift(&(self.projection_ty.trait_ref, self.ty)).map(|(trait_ref, ty)| {
- ProjectionPredicate {
- projection_ty: ProjectionTy {
- trait_ref: trait_ref,
- item_name: self.projection_ty.item_name
- },
- ty: ty
- }
- })
- }
-}
-
-impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Binder<T> {
- type Lifted = Binder<T::Lifted>;
- fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Self::Lifted> {
- tcx.lift(&self.0).map(|x| Binder(x))
- }
-}
-
-pub mod tls {
- use middle::ty;
- use session::Session;
-
- use std::fmt;
- use syntax::codemap;
-
- /// Marker type used for the scoped TLS slot.
- /// The type context cannot be used directly because the scoped TLS
- /// in libstd doesn't allow types generic over lifetimes.
- struct ThreadLocalTyCx;
-
- scoped_thread_local!(static TLS_TCX: ThreadLocalTyCx);
-
- fn span_debug(span: codemap::Span, f: &mut fmt::Formatter) -> fmt::Result {
- with(|tcx| {
- write!(f, "{}", tcx.sess.codemap().span_to_string(span))
- })
- }
-
- pub fn enter<'tcx, F: FnOnce(&ty::ctxt<'tcx>) -> R, R>(tcx: ty::ctxt<'tcx>, f: F)
- -> (Session, R) {
- let result = codemap::SPAN_DEBUG.with(|span_dbg| {
- let original_span_debug = span_dbg.get();
- span_dbg.set(span_debug);
- let tls_ptr = &tcx as *const _ as *const ThreadLocalTyCx;
- let result = TLS_TCX.set(unsafe { &*tls_ptr }, || f(&tcx));
- span_dbg.set(original_span_debug);
- result
- });
- (tcx.sess, result)
- }
-
- pub fn with<F: FnOnce(&ty::ctxt) -> R, R>(f: F) -> R {
- TLS_TCX.with(|tcx| f(unsafe { &*(tcx as *const _ as *const ty::ctxt) }))
- }
-
- pub fn with_opt<F: FnOnce(Option<&ty::ctxt>) -> R, R>(f: F) -> R {
- if TLS_TCX.is_set() {
- with(|v| f(Some(v)))
- } else {
- f(None)
- }
- }
-}
-
// Flags that we track on types. These flags are propagated upwards
// through the type during type construction, so that we can quickly
// check whether the type has various kinds of types in it without
}
}
-macro_rules! sty_debug_print {
- ($ctxt: expr, $($variant: ident),*) => {{
- // curious inner module to allow variant names to be used as
- // variable names.
- #[allow(non_snake_case)]
- mod inner {
- use middle::ty;
- #[derive(Copy, Clone)]
- struct DebugStat {
- total: usize,
- region_infer: usize,
- ty_infer: usize,
- both_infer: usize,
- }
-
- pub fn go(tcx: &ty::ctxt) {
- let mut total = DebugStat {
- total: 0,
- region_infer: 0, ty_infer: 0, both_infer: 0,
- };
- $(let mut $variant = total;)*
-
-
- for (_, t) in tcx.interner.borrow().iter() {
- let variant = match t.sty {
- ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) |
- ty::TyFloat(..) | ty::TyStr => continue,
- ty::TyError => /* unimportant */ continue,
- $(ty::$variant(..) => &mut $variant,)*
- };
- let region = t.flags.get().intersects(ty::TypeFlags::HAS_RE_INFER);
- let ty = t.flags.get().intersects(ty::TypeFlags::HAS_TY_INFER);
-
- variant.total += 1;
- total.total += 1;
- if region { total.region_infer += 1; variant.region_infer += 1 }
- if ty { total.ty_infer += 1; variant.ty_infer += 1 }
- if region && ty { total.both_infer += 1; variant.both_infer += 1 }
- }
- println!("Ty interner total ty region both");
- $(println!(" {:18}: {uses:6} {usespc:4.1}%, \
-{ty:4.1}% {region:5.1}% {both:4.1}%",
- stringify!($variant),
- uses = $variant.total,
- usespc = $variant.total as f64 * 100.0 / total.total as f64,
- ty = $variant.ty_infer as f64 * 100.0 / total.total as f64,
- region = $variant.region_infer as f64 * 100.0 / total.total as f64,
- both = $variant.both_infer as f64 * 100.0 / total.total as f64);
- )*
- println!(" total {uses:6} \
-{ty:4.1}% {region:5.1}% {both:4.1}%",
- uses = total.total,
- ty = total.ty_infer as f64 * 100.0 / total.total as f64,
- region = total.region_infer as f64 * 100.0 / total.total as f64,
- both = total.both_infer as f64 * 100.0 / total.total as f64)
- }
- }
-
- inner::go($ctxt)
- }}
-}
-
-impl<'tcx> ctxt<'tcx> {
- pub fn print_debug_stats(&self) {
- sty_debug_print!(
- self,
- TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyBareFn, TyTrait,
- TyStruct, TyClosure, TyTuple, TyParam, TyInfer, TyProjection);
-
- println!("Substs interner: #{}", self.substs_interner.borrow().len());
- println!("BareFnTy interner: #{}", self.bare_fn_interner.borrow().len());
- println!("Region interner: #{}", self.region_interner.borrow().len());
- println!("Stability interner: #{}", self.stability_interner.borrow().len());
- }
-}
-
pub struct TyS<'tcx> {
pub sty: TypeVariants<'tcx>,
pub flags: Cell<TypeFlags>,
region_depth: u32,
}
-impl fmt::Debug for TypeFlags {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", self.bits)
- }
-}
-
impl<'tcx> PartialEq for TyS<'tcx> {
#[inline]
fn eq(&self, other: &TyS<'tcx>) -> bool {
pub type Ty<'tcx> = &'tcx TyS<'tcx>;
-/// An IVar that contains a Ty. 'lt is a (reverse-variant) upper bound
-/// on the lifetime of the IVar. This is required because of variance
-/// problems: the IVar needs to be variant with respect to 'tcx (so
-/// it can be referred to from Ty) but can only be modified if its
-/// lifetime is exactly 'tcx.
-///
-/// Safety invariants:
-/// (A) self.0, if fulfilled, is a valid Ty<'tcx>
-/// (B) no aliases to this value with a 'tcx longer than this
-/// value's 'lt exist
-///
-/// NonZero is used rather than Unique because Unique isn't Copy.
-pub struct TyIVar<'tcx, 'lt: 'tcx>(ivar::Ivar<NonZero<*const TyS<'static>>>,
- PhantomData<fn(TyS<'lt>)->TyS<'tcx>>);
-
-impl<'tcx, 'lt> TyIVar<'tcx, 'lt> {
- #[inline]
- pub fn new() -> Self {
- // Invariant (A) satisfied because the IVar is unfulfilled
- // Invariant (B) because 'lt : 'tcx
- TyIVar(ivar::Ivar::new(), PhantomData)
- }
-
- #[inline]
- pub fn get(&self) -> Option<Ty<'tcx>> {
- match self.0.get() {
- None => None,
- // valid because of invariant (A)
- Some(v) => Some(unsafe { &*(*v as *const TyS<'tcx>) })
- }
- }
- #[inline]
- pub fn unwrap(&self) -> Ty<'tcx> {
- self.get().unwrap()
- }
-
- pub fn fulfill(&self, value: Ty<'lt>) {
- // Invariant (A) is fulfilled, because by (B), every alias
- // of this has a 'tcx longer than 'lt.
- let value: *const TyS<'lt> = value;
- // FIXME(27214): unneeded [as *const ()]
- let value = value as *const () as *const TyS<'static>;
- self.0.fulfill(unsafe { NonZero::new(value) })
- }
-}
-
-impl<'tcx, 'lt> fmt::Debug for TyIVar<'tcx, 'lt> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self.get() {
- Some(val) => write!(f, "TyIVar({:?})", val),
- None => f.write_str("TyIVar(<unfulfilled>)")
- }
- }
-}
-
-/// An entry in the type interner.
-pub struct InternedTy<'tcx> {
- ty: Ty<'tcx>
-}
-
-// NB: An InternedTy compares and hashes as a sty.
-impl<'tcx> PartialEq for InternedTy<'tcx> {
- fn eq(&self, other: &InternedTy<'tcx>) -> bool {
- self.ty.sty == other.ty.sty
- }
-}
-
-impl<'tcx> Eq for InternedTy<'tcx> {}
-
-impl<'tcx> Hash for InternedTy<'tcx> {
- fn hash<H: Hasher>(&self, s: &mut H) {
- self.ty.sty.hash(s)
- }
-}
-
-impl<'tcx> Borrow<TypeVariants<'tcx>> for InternedTy<'tcx> {
- fn borrow<'a>(&'a self) -> &'a TypeVariants<'tcx> {
- &self.ty.sty
- }
-}
-
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
-pub struct BareFnTy<'tcx> {
- pub unsafety: hir::Unsafety,
- pub abi: abi::Abi,
- pub sig: PolyFnSig<'tcx>,
-}
-
-#[derive(Clone, PartialEq, Eq, Hash)]
-pub struct ClosureTy<'tcx> {
- pub unsafety: hir::Unsafety,
- pub abi: abi::Abi,
- pub sig: PolyFnSig<'tcx>,
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
-pub enum FnOutput<'tcx> {
- FnConverging(Ty<'tcx>),
- FnDiverging
-}
-
-impl<'tcx> FnOutput<'tcx> {
- pub fn diverges(&self) -> bool {
- *self == FnDiverging
- }
-
- pub fn unwrap(self) -> Ty<'tcx> {
- match self {
- ty::FnConverging(t) => t,
- ty::FnDiverging => unreachable!()
- }
- }
-
- pub fn unwrap_or(self, def: Ty<'tcx>) -> Ty<'tcx> {
- match self {
- ty::FnConverging(t) => t,
- ty::FnDiverging => def
- }
- }
-}
-
-pub type PolyFnOutput<'tcx> = Binder<FnOutput<'tcx>>;
-
-impl<'tcx> PolyFnOutput<'tcx> {
- pub fn diverges(&self) -> bool {
- self.0.diverges()
- }
-}
-
-/// 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.
-/// - `variadic` indicates whether this is a variadic function. (only true for foreign fns)
-#[derive(Clone, PartialEq, Eq, Hash)]
-pub struct FnSig<'tcx> {
- pub inputs: Vec<Ty<'tcx>>,
- pub output: FnOutput<'tcx>,
- pub variadic: bool
-}
-
-pub type PolyFnSig<'tcx> = Binder<FnSig<'tcx>>;
-
-impl<'tcx> PolyFnSig<'tcx> {
- pub fn inputs(&self) -> ty::Binder<Vec<Ty<'tcx>>> {
- self.map_bound_ref(|fn_sig| fn_sig.inputs.clone())
- }
- pub fn input(&self, index: usize) -> ty::Binder<Ty<'tcx>> {
- self.map_bound_ref(|fn_sig| fn_sig.inputs[index])
- }
- pub fn output(&self) -> ty::Binder<FnOutput<'tcx>> {
- self.map_bound_ref(|fn_sig| fn_sig.output.clone())
- }
- pub fn variadic(&self) -> bool {
- self.skip_binder().variadic
- }
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub struct ParamTy {
- pub space: subst::ParamSpace,
- pub idx: u32,
- pub name: Name,
-}
-
-/// A [De Bruijn index][dbi] is a standard means of representing
-/// regions (and perhaps later types) in a higher-ranked setting. In
-/// particular, imagine a type like this:
-///
-/// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char)
-/// ^ ^ | | |
-/// | | | | |
-/// | +------------+ 1 | |
-/// | | |
-/// +--------------------------------+ 2 |
-/// | |
-/// +------------------------------------------+ 1
-///
-/// In this type, there are two binders (the outer fn and the inner
-/// fn). We need to be able to determine, for any given region, which
-/// fn type it is bound by, the inner or the outer one. There are
-/// various ways you can do this, but a De Bruijn index is one of the
-/// more convenient and has some nice properties. The basic idea is to
-/// count the number of binders, inside out. Some examples should help
-/// clarify what I mean.
-///
-/// Let's start with the reference type `&'b isize` that is the first
-/// argument to the inner function. This region `'b` is assigned a De
-/// Bruijn index of 1, meaning "the innermost binder" (in this case, a
-/// fn). The region `'a` that appears in the second argument type (`&'a
-/// isize`) would then be assigned a De Bruijn index of 2, meaning "the
-/// second-innermost binder". (These indices are written on the arrays
-/// in the diagram).
-///
-/// What is interesting is that De Bruijn index attached to a particular
-/// variable will vary depending on where it appears. For example,
-/// the final type `&'a char` also refers to the region `'a` declared on
-/// the outermost fn. But this time, this reference is not nested within
-/// any other binders (i.e., it is not an argument to the inner fn, but
-/// rather the outer one). Therefore, in this case, it is assigned a
-/// De Bruijn index of 1, because the innermost binder in that location
-/// is the outer fn.
-///
-/// [dbi]: http://en.wikipedia.org/wiki/De_Bruijn_index
-#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, Copy)]
-pub struct DebruijnIndex {
- // We maintain the invariant that this is never 0. So 1 indicates
- // the innermost binder. To ensure this, create with `DebruijnIndex::new`.
- pub depth: u32,
-}
-
-/// Representation of regions.
-///
-/// Unlike types, most region variants are "fictitious", not concrete,
-/// regions. Among these, `ReStatic`, `ReEmpty` and `ReScope` are the only
-/// ones representing concrete regions.
-///
-/// ## Bound Regions
-///
-/// These are regions that are stored behind a binder and must be substituted
-/// with some concrete region before being used. There are 2 kind of
-/// bound regions: early-bound, which are bound in a TypeScheme/TraitDef,
-/// and are substituted by a Substs, and late-bound, which are part of
-/// higher-ranked types (e.g. `for<'a> fn(&'a ())`) and are substituted by
-/// the likes of `liberate_late_bound_regions`. The distinction exists
-/// because higher-ranked lifetimes aren't supported in all places. See [1][2].
-///
-/// Unlike TyParam-s, bound regions are not supposed to exist "in the wild"
-/// outside their binder, e.g. in types passed to type inference, and
-/// should first be substituted (by skolemized regions, free regions,
-/// or region variables).
-///
-/// ## Skolemized and Free Regions
-///
-/// One often wants to work with bound regions without knowing their precise
-/// identity. For example, when checking a function, the lifetime of a borrow
-/// can end up being assigned to some region parameter. In these cases,
-/// it must be ensured that bounds on the region can't be accidentally
-/// assumed without being checked.
-///
-/// The process of doing that is called "skolemization". The bound regions
-/// are replaced by skolemized markers, which don't satisfy any relation
-/// not explicity provided.
-///
-/// There are 2 kinds of skolemized regions in rustc: `ReFree` and
-/// `ReSkolemized`. When checking an item's body, `ReFree` is supposed
-/// to be used. These also support explicit bounds: both the internally-stored
-/// *scope*, which the region is assumed to outlive, as well as other
-/// relations stored in the `FreeRegionMap`. Note that these relations
-/// aren't checked when you `make_subregion` (or `mk_eqty`), only by
-/// `resolve_regions_and_report_errors`.
-///
-/// When working with higher-ranked types, some region relations aren't
-/// yet known, so you can't just call `resolve_regions_and_report_errors`.
-/// `ReSkolemized` is designed for this purpose. In these contexts,
-/// there's also the risk that some inference variable laying around will
-/// get unified with your skolemized region: if you want to check whether
-/// `for<'a> Foo<'_>: 'a`, and you substitute your bound region `'a`
-/// with a skolemized region `'%a`, the variable `'_` would just be
-/// instantiated to the skolemized region `'%a`, which is wrong because
-/// the inference variable is supposed to satisfy the relation
-/// *for every value of the skolemized region*. To ensure that doesn't
-/// happen, you can use `leak_check`. This is more clearly explained
-/// by infer/higher_ranked/README.md.
-///
-/// [1] http://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/
-/// [2] http://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
-#[derive(Clone, PartialEq, Eq, Hash, Copy)]
-pub enum Region {
- // Region bound in a type or fn declaration which will be
- // substituted 'early' -- that is, at the same time when type
- // parameters are substituted.
- ReEarlyBound(EarlyBoundRegion),
-
- // Region bound in a function scope, which will be substituted when the
- // function is called.
- ReLateBound(DebruijnIndex, BoundRegion),
-
- /// 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.
- ReFree(FreeRegion),
-
- /// A concrete region naming some statically determined extent
- /// (e.g. an expression or sequence of statements) within the
- /// current function.
- ReScope(region::CodeExtent),
-
- /// Static data that has an "infinite" lifetime. Top in the region lattice.
- ReStatic,
-
- /// A region variable. Should not exist after typeck.
- ReVar(RegionVid),
-
- /// A skolemized region - basically the higher-ranked version of ReFree.
- /// Should not exist after typeck.
- ReSkolemized(SkolemizedRegionVid, BoundRegion),
-
- /// Empty lifetime is for data that is never accessed.
- /// Bottom in the region lattice. We treat ReEmpty somewhat
- /// specially; at least right now, we do not generate instances of
- /// it during the GLB computations, but rather
- /// generate an error instead. This is to improve error messages.
- /// The only way to get an instance of ReEmpty is to have a region
- /// variable with no constraints.
- ReEmpty,
-}
-
-#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
-pub struct EarlyBoundRegion {
- pub param_id: NodeId,
- pub space: subst::ParamSpace,
- pub index: u32,
- pub name: Name,
-}
-
/// Upvars do not get their own node-id. Instead, we use the pair of
/// the original var id (that is, the root variable that is referenced
/// by the upvar) and the id of the closure expression.
pub ty: Ty<'tcx>,
}
-impl Region {
- pub fn is_bound(&self) -> bool {
- match *self {
- ty::ReEarlyBound(..) => true,
- ty::ReLateBound(..) => true,
- _ => false
- }
- }
-
- pub fn needs_infer(&self) -> bool {
- match *self {
- ty::ReVar(..) | ty::ReSkolemized(..) => true,
- _ => false
- }
- }
-
- pub fn escapes_depth(&self, depth: u32) -> bool {
- match *self {
- ty::ReLateBound(debruijn, _) => debruijn.depth > depth,
- _ => false,
- }
- }
-
- /// Returns the depth of `self` from the (1-based) binding level `depth`
- pub fn from_depth(&self, depth: u32) -> Region {
- match *self {
- ty::ReLateBound(debruijn, r) => ty::ReLateBound(DebruijnIndex {
- depth: debruijn.depth - (depth - 1)
- }, r),
- r => r
- }
- }
-}
-
-#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash,
- RustcEncodable, RustcDecodable, Copy)]
-/// A "free" region `fr` can be interpreted as "some region
-/// at least as big as the scope `fr.scope`".
-pub struct FreeRegion {
- pub scope: region::CodeExtent,
- pub bound_region: BoundRegion
-}
-
-#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash,
- RustcEncodable, RustcDecodable, Copy)]
-pub enum BoundRegion {
- /// An anonymous region parameter for a given fn (&T)
- BrAnon(u32),
-
- /// Named region parameters for functions (a in &'a T)
- ///
- /// The def-id is needed to distinguish free regions in
- /// the event of shadowing.
- BrNamed(DefId, Name),
-
- /// Fresh bound identifiers created during GLB computations.
- BrFresh(u32),
-
- // Anonymous region for the implicit env pointer parameter
- // to a closure
- BrEnv
-}
-
-// NB: If you change this, you'll probably want to change the corresponding
-// AST structure in libsyntax/ast.rs as well.
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
-pub enum TypeVariants<'tcx> {
- /// The primitive boolean type. Written as `bool`.
- TyBool,
-
- /// The primitive character type; holds a Unicode scalar value
- /// (a non-surrogate code point). Written as `char`.
- TyChar,
-
- /// A primitive signed integer type. For example, `i32`.
- TyInt(hir::IntTy),
-
- /// A primitive unsigned integer type. For example, `u32`.
- TyUint(hir::UintTy),
-
- /// A primitive floating-point type. For example, `f64`.
- TyFloat(hir::FloatTy),
-
- /// An enumerated type, defined with `enum`.
- ///
- /// Substs here, possibly against intuition, *may* contain `TyParam`s.
- /// That is, even after substitution it is possible that there are type
- /// variables. This happens when the `TyEnum` corresponds to an enum
- /// definition and not a concrete use of it. To get the correct `TyEnum`
- /// from the tcx, use the `NodeId` from the `hir::Ty` and look it up in
- /// the `ast_ty_to_ty_cache`. This is probably true for `TyStruct` as
- /// well.
- TyEnum(AdtDef<'tcx>, &'tcx Substs<'tcx>),
-
- /// A structure type, defined with `struct`.
- ///
- /// See warning about substitutions for enumerated types.
- TyStruct(AdtDef<'tcx>, &'tcx Substs<'tcx>),
-
- /// `Box<T>`; this is nominally a struct in the documentation, but is
- /// special-cased internally. For example, it is possible to implicitly
- /// move the contents of a box out of that box, and methods of any type
- /// can have type `Box<Self>`.
- TyBox(Ty<'tcx>),
-
- /// The pointee of a string slice. Written as `str`.
- TyStr,
-
- /// An array with the given length. Written as `[T; n]`.
- TyArray(Ty<'tcx>, usize),
-
- /// The pointee of an array slice. Written as `[T]`.
- TySlice(Ty<'tcx>),
-
- /// A raw pointer. Written as `*mut T` or `*const T`
- TyRawPtr(TypeAndMut<'tcx>),
-
- /// A reference; a pointer with an associated lifetime. Written as
- /// `&a mut T` or `&'a T`.
- TyRef(&'tcx Region, TypeAndMut<'tcx>),
-
- /// If the def-id is Some(_), then this is the type of a specific
- /// fn item. Otherwise, if None(_), it a fn pointer type.
- ///
- /// FIXME: Conflating function pointers and the type of a
- /// function is probably a terrible idea; a function pointer is a
- /// value with a specific type, but a function can be polymorphic
- /// or dynamically dispatched.
- TyBareFn(Option<DefId>, &'tcx BareFnTy<'tcx>),
-
- /// A trait, defined with `trait`.
- TyTrait(Box<TraitTy<'tcx>>),
-
- /// The anonymous type of a closure. Used to represent the type of
- /// `|a| a`.
- TyClosure(DefId, Box<ClosureSubsts<'tcx>>),
-
- /// A tuple type. For example, `(i32, bool)`.
- TyTuple(Vec<Ty<'tcx>>),
-
- /// The projection of an associated type. For example,
- /// `<T as Trait<..>>::N`.
- TyProjection(ProjectionTy<'tcx>),
-
- /// A type parameter; for example, `T` in `fn f<T>(x: T) {}
- TyParam(ParamTy),
-
- /// A type variable used during type-checking.
- TyInfer(InferTy),
-
- /// A placeholder for a type which could not be computed; this is
- /// propagated to avoid useless error messages.
- TyError,
-}
-
-/// A closure can be modeled as a struct that looks like:
-///
-/// struct Closure<'l0...'li, T0...Tj, U0...Uk> {
-/// upvar0: U0,
-/// ...
-/// upvark: Uk
-/// }
-///
-/// where 'l0...'li and T0...Tj are the lifetime and type parameters
-/// in scope on the function that defined the closure, and U0...Uk are
-/// type parameters representing the types of its upvars (borrowed, if
-/// appropriate).
-///
-/// So, for example, given this function:
-///
-/// fn foo<'a, T>(data: &'a mut T) {
-/// do(|| data.count += 1)
-/// }
-///
-/// the type of the closure would be something like:
-///
-/// struct Closure<'a, T, U0> {
-/// data: U0
-/// }
-///
-/// Note that the type of the upvar is not specified in the struct.
-/// You may wonder how the impl would then be able to use the upvar,
-/// if it doesn't know it's type? The answer is that the impl is
-/// (conceptually) not fully generic over Closure but rather tied to
-/// instances with the expected upvar types:
-///
-/// impl<'b, 'a, T> FnMut() for Closure<'a, T, &'b mut &'a mut T> {
-/// ...
-/// }
-///
-/// You can see that the *impl* fully specified the type of the upvar
-/// and thus knows full well that `data` has type `&'b mut &'a mut T`.
-/// (Here, I am assuming that `data` is mut-borrowed.)
-///
-/// Now, the last question you may ask is: Why include the upvar types
-/// as extra type parameters? The reason for this design is that the
-/// upvar types can reference lifetimes that are internal to the
-/// creating function. In my example above, for example, the lifetime
-/// `'b` represents the extent of the closure itself; this is some
-/// subset of `foo`, probably just the extent of the call to the to
-/// `do()`. If we just had the lifetime/type parameters from the
-/// enclosing function, we couldn't name this lifetime `'b`. Note that
-/// there can also be lifetimes in the types of the upvars themselves,
-/// if one of them happens to be a reference to something that the
-/// creating fn owns.
-///
-/// OK, you say, so why not create a more minimal set of parameters
-/// that just includes the extra lifetime parameters? The answer is
-/// primarily that it would be hard --- we don't know at the time when
-/// we create the closure type what the full types of the upvars are,
-/// nor do we know which are borrowed and which are not. In this
-/// design, we can just supply a fresh type parameter and figure that
-/// out later.
-///
-/// All right, you say, but why include the type parameters from the
-/// original function then? The answer is that trans may need them
-/// when monomorphizing, and they may not appear in the upvars. A
-/// closure could capture no variables but still make use of some
-/// in-scope type parameter with a bound (e.g., if our example above
-/// had an extra `U: Default`, and the closure called `U::default()`).
-///
-/// There is another reason. This design (implicitly) prohibits
-/// closures from capturing themselves (except via a trait
-/// object). This simplifies closure inference considerably, since it
-/// means that when we infer the kind of a closure or its upvars, we
-/// don't have to handle cycles where the decisions we make for
-/// closure C wind up influencing the decisions we ought to make for
-/// closure C (which would then require fixed point iteration to
-/// handle). Plus it fixes an ICE. :P
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
-pub struct ClosureSubsts<'tcx> {
- /// Lifetime and type parameters from the enclosing function.
- /// These are separated out because trans wants to pass them around
- /// when monomorphizing.
- pub func_substs: &'tcx Substs<'tcx>,
-
- /// The types of the upvars. The list parallels the freevars and
- /// `upvar_borrows` lists. These are kept distinct so that we can
- /// easily index into them.
- pub upvar_tys: Vec<Ty<'tcx>>
-}
-
-#[derive(Clone, PartialEq, Eq, Hash)]
-pub struct TraitTy<'tcx> {
- pub principal: ty::PolyTraitRef<'tcx>,
- pub bounds: ExistentialBounds<'tcx>,
-}
-
-impl<'tcx> TraitTy<'tcx> {
- pub fn principal_def_id(&self) -> DefId {
- self.principal.0.def_id
- }
-
- /// Object types don't have a self-type specified. Therefore, when
- /// we convert the principal trait-ref into a normal trait-ref,
- /// you must give *some* self-type. A common choice is `mk_err()`
- /// or some skolemized type.
- pub fn principal_trait_ref_with_self_ty(&self,
- tcx: &ctxt<'tcx>,
- self_ty: Ty<'tcx>)
- -> ty::PolyTraitRef<'tcx>
- {
- // otherwise the escaping regions would be captured by the binder
- assert!(!self_ty.has_escaping_regions());
-
- ty::Binder(TraitRef {
- def_id: self.principal.0.def_id,
- substs: tcx.mk_substs(self.principal.0.substs.with_self_ty(self_ty)),
- })
- }
-
- pub fn projection_bounds_with_self_ty(&self,
- tcx: &ctxt<'tcx>,
- self_ty: Ty<'tcx>)
- -> Vec<ty::PolyProjectionPredicate<'tcx>>
- {
- // otherwise the escaping regions would be captured by the binders
- assert!(!self_ty.has_escaping_regions());
-
- self.bounds.projection_bounds.iter()
- .map(|in_poly_projection_predicate| {
- let in_projection_ty = &in_poly_projection_predicate.0.projection_ty;
- let substs = tcx.mk_substs(in_projection_ty.trait_ref.substs.with_self_ty(self_ty));
- let trait_ref = ty::TraitRef::new(in_projection_ty.trait_ref.def_id,
- substs);
- let projection_ty = ty::ProjectionTy {
- trait_ref: trait_ref,
- item_name: in_projection_ty.item_name
- };
- ty::Binder(ty::ProjectionPredicate {
- projection_ty: projection_ty,
- ty: in_poly_projection_predicate.0.ty
- })
- })
- .collect()
- }
-}
-
-/// A complete reference to a trait. These take numerous guises in syntax,
-/// but perhaps the most recognizable form is in a where clause:
-///
-/// T : Foo<U>
-///
-/// This would be represented by a trait-reference where the def-id is the
-/// def-id for the trait `Foo` and the substs defines `T` as parameter 0 in the
-/// `SelfSpace` and `U` as parameter 0 in the `TypeSpace`.
-///
-/// Trait references also appear in object types like `Foo<U>`, but in
-/// that case the `Self` parameter is absent from the substitutions.
-///
-/// Note that a `TraitRef` introduces a level of region binding, to
-/// account for higher-ranked trait bounds like `T : for<'a> Foo<&'a
-/// U>` or higher-ranked object types.
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
-pub struct TraitRef<'tcx> {
- pub def_id: DefId,
- pub substs: &'tcx Substs<'tcx>,
-}
-
-pub type PolyTraitRef<'tcx> = Binder<TraitRef<'tcx>>;
-
-impl<'tcx> PolyTraitRef<'tcx> {
- pub fn self_ty(&self) -> Ty<'tcx> {
- self.0.self_ty()
- }
-
- pub fn def_id(&self) -> DefId {
- self.0.def_id
- }
-
- pub fn substs(&self) -> &'tcx Substs<'tcx> {
- // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<>
- self.0.substs
- }
-
- pub fn input_types(&self) -> &[Ty<'tcx>] {
- // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<>
- self.0.input_types()
- }
-
- pub fn to_poly_trait_predicate(&self) -> PolyTraitPredicate<'tcx> {
- // Note that we preserve binding levels
- Binder(TraitPredicate { trait_ref: self.0.clone() })
- }
-}
-
-/// Binder is a binder for higher-ranked lifetimes. It is part of the
-/// compiler's representation for things like `for<'a> Fn(&'a isize)`
-/// (which would be represented by the type `PolyTraitRef ==
-/// Binder<TraitRef>`). Note that when we skolemize, instantiate,
-/// erase, or otherwise "discharge" these bound regions, we change the
-/// type from `Binder<T>` to just `T` (see
-/// e.g. `liberate_late_bound_regions`).
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
-pub struct Binder<T>(pub T);
-
-impl<T> Binder<T> {
- /// Skips the binder and returns the "bound" value. This is a
- /// risky thing to do because it's easy to get confused about
- /// debruijn indices and the like. It is usually better to
- /// discharge the binder using `no_late_bound_regions` or
- /// `replace_late_bound_regions` or something like
- /// that. `skip_binder` is only valid when you are either
- /// extracting data that has nothing to do with bound regions, you
- /// are doing some sort of test that does not involve bound
- /// regions, or you are being very careful about your depth
- /// accounting.
- ///
- /// Some examples where `skip_binder` is reasonable:
- /// - extracting the def-id from a PolyTraitRef;
- /// - comparing the self type of a PolyTraitRef to see if it is equal to
- /// a type parameter `X`, since the type `X` does not reference any regions
- pub fn skip_binder(&self) -> &T {
- &self.0
- }
-
- pub fn as_ref(&self) -> Binder<&T> {
- ty::Binder(&self.0)
- }
-
- pub fn map_bound_ref<F,U>(&self, f: F) -> Binder<U>
- where F: FnOnce(&T) -> U
- {
- self.as_ref().map_bound(f)
- }
-
- pub fn map_bound<F,U>(self, f: F) -> Binder<U>
- where F: FnOnce(T) -> U
- {
- ty::Binder(f(self.0))
- }
-}
-
#[derive(Clone, Copy, PartialEq)]
pub enum IntVarValue {
IntType(hir::IntTy),
UintType(hir::UintTy),
}
-#[derive(Clone, Copy, Debug)]
-pub struct ExpectedFound<T> {
- pub expected: T,
- pub found: T
-}
-
-// Data structures used in type unification
-#[derive(Clone, Debug)]
-pub enum TypeError<'tcx> {
- Mismatch,
- UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
- AbiMismatch(ExpectedFound<abi::Abi>),
- Mutability,
- BoxMutability,
- PtrMutability,
- RefMutability,
- VecMutability,
- TupleSize(ExpectedFound<usize>),
- FixedArraySize(ExpectedFound<usize>),
- TyParamSize(ExpectedFound<usize>),
- ArgCount,
- RegionsDoesNotOutlive(Region, Region),
- RegionsNotSame(Region, Region),
- RegionsNoOverlap(Region, Region),
- RegionsInsufficientlyPolymorphic(BoundRegion, Region),
- RegionsOverlyPolymorphic(BoundRegion, Region),
- Sorts(ExpectedFound<Ty<'tcx>>),
- IntegerAsChar,
- IntMismatch(ExpectedFound<IntVarValue>),
- FloatMismatch(ExpectedFound<hir::FloatTy>),
- Traits(ExpectedFound<DefId>),
- BuiltinBoundsMismatch(ExpectedFound<BuiltinBounds>),
- VariadicMismatch(ExpectedFound<bool>),
- CyclicTy,
- ConvergenceMismatch(ExpectedFound<bool>),
- ProjectionNameMismatched(ExpectedFound<Name>),
- ProjectionBoundsLength(ExpectedFound<usize>),
- TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>)
-}
-
-/// Bounds suitable for an existentially quantified type parameter
-/// such as those that appear in object types or closure types.
-#[derive(PartialEq, Eq, Hash, Clone)]
-pub struct ExistentialBounds<'tcx> {
- pub region_bound: ty::Region,
- pub builtin_bounds: BuiltinBounds,
- pub projection_bounds: Vec<PolyProjectionPredicate<'tcx>>,
-}
-
-impl<'tcx> ExistentialBounds<'tcx> {
- pub fn new(region_bound: ty::Region,
- builtin_bounds: BuiltinBounds,
- projection_bounds: Vec<PolyProjectionPredicate<'tcx>>)
- -> Self {
- let mut projection_bounds = projection_bounds;
- ty::sort_bounds_list(&mut projection_bounds);
- ExistentialBounds {
- region_bound: region_bound,
- builtin_bounds: builtin_bounds,
- projection_bounds: projection_bounds
- }
- }
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
-pub struct BuiltinBounds(EnumSet<BuiltinBound>);
-
-impl BuiltinBounds {
- pub fn empty() -> BuiltinBounds {
- BuiltinBounds(EnumSet::new())
- }
-
- pub fn iter(&self) -> enum_set::Iter<BuiltinBound> {
- self.into_iter()
- }
-
- pub fn to_predicates<'tcx>(&self,
- tcx: &ty::ctxt<'tcx>,
- self_ty: Ty<'tcx>) -> Vec<Predicate<'tcx>> {
- self.iter().filter_map(|builtin_bound|
- match traits::trait_ref_for_builtin_bound(tcx, builtin_bound, self_ty) {
- Ok(trait_ref) => Some(trait_ref.to_predicate()),
- Err(ErrorReported) => { None }
- }
- ).collect()
- }
-}
-
-impl ops::Deref for BuiltinBounds {
- type Target = EnumSet<BuiltinBound>;
- fn deref(&self) -> &Self::Target { &self.0 }
-}
-
-impl ops::DerefMut for BuiltinBounds {
- fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
-}
-
-impl<'a> IntoIterator for &'a BuiltinBounds {
- type Item = BuiltinBound;
- type IntoIter = enum_set::Iter<BuiltinBound>;
- fn into_iter(self) -> Self::IntoIter {
- (**self).into_iter()
- }
-}
-
-#[derive(Clone, RustcEncodable, PartialEq, Eq, RustcDecodable, Hash,
- Debug, Copy)]
-#[repr(usize)]
-pub enum BuiltinBound {
- Send,
- Sized,
- Copy,
- Sync,
-}
-
-impl CLike for BuiltinBound {
- fn to_usize(&self) -> usize {
- *self as usize
- }
- fn from_usize(v: usize) -> BuiltinBound {
- unsafe { mem::transmute(v) }
- }
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub struct TyVid {
- pub index: u32
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub struct IntVid {
- pub index: u32
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub struct FloatVid {
- pub index: u32
-}
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
-pub struct RegionVid {
- pub index: u32
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub struct SkolemizedRegionVid {
- pub index: u32
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub enum InferTy {
- TyVar(TyVid),
- IntVar(IntVid),
- FloatVar(FloatVid),
-
- /// A `FreshTy` is one that is generated as a replacement for an
- /// unbound type variable. This is convenient for caching etc. See
- /// `middle::infer::freshen` for more details.
- FreshTy(u32),
- FreshIntTy(u32),
- FreshFloatTy(u32)
-}
-
-#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
-pub enum UnconstrainedNumeric {
- UnconstrainedFloat,
- UnconstrainedInt,
- Neither,
-}
-
-
-impl fmt::Debug for TyVid {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "_#{}t", self.index)
- }
-}
-
-impl fmt::Debug for IntVid {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "_#{}i", self.index)
- }
-}
-
-impl fmt::Debug for FloatVid {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "_#{}f", self.index)
- }
-}
-
-impl fmt::Debug for RegionVid {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "'_#{}r", self.index)
- }
-}
-
-impl<'tcx> fmt::Debug for FnSig<'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "({:?}; variadic: {})->{:?}", self.inputs, self.variadic, self.output)
- }
-}
-
-impl fmt::Debug for InferTy {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- TyVar(ref v) => v.fmt(f),
- IntVar(ref v) => v.fmt(f),
- FloatVar(ref v) => v.fmt(f),
- FreshTy(v) => write!(f, "FreshTy({:?})", v),
- FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v),
- FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v)
- }
- }
-}
-
-impl fmt::Debug for IntVarValue {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- IntType(ref v) => v.fmt(f),
- UintType(ref v) => v.fmt(f),
- }
- }
-}
-
/// Default region to use for the bound of objects that are
/// supplied as the value for this type parameter. This is derived
/// from `T:'a` annotations appearing in the type definition. If
}
}
-/// Represents the projection of an associated type. In explicit UFCS
-/// form this would be written `<T as Trait<..>>::N`.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
-pub struct ProjectionTy<'tcx> {
- /// The trait reference `T as Trait<..>`.
- pub trait_ref: ty::TraitRef<'tcx>,
-
- /// The name `N` of the associated type.
- pub item_name: Name,
-}
-
-impl<'tcx> ProjectionTy<'tcx> {
- pub fn sort_key(&self) -> (DefId, Name) {
- (self.trait_ref.def_id, self.item_name)
- }
-}
-
pub trait ToPolyTraitRef<'tcx> {
fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>;
}
pub vis: hir::Visibility,
/// TyIVar is used here to allow for variance (see the doc at
/// AdtDefData).
- ty: TyIVar<'tcx, 'container>
+ ty: ivar::TyIVar<'tcx, 'container>
}
/// The definition of an abstract data type - a struct or enum.
did: did,
name: name,
vis: vis,
- ty: TyIVar::new()
+ ty: ivar::TyIVar::new()
}
}
}
}
-impl<'tcx> CommonTypes<'tcx> {
- fn new(arena: &'tcx TypedArena<TyS<'tcx>>,
- interner: &RefCell<FnvHashMap<InternedTy<'tcx>, Ty<'tcx>>>)
- -> CommonTypes<'tcx>
- {
- let mk = |sty| ctxt::intern_ty(arena, interner, sty);
- CommonTypes {
- bool: mk(TyBool),
- char: mk(TyChar),
- err: mk(TyError),
- isize: mk(TyInt(hir::TyIs)),
- i8: mk(TyInt(hir::TyI8)),
- i16: mk(TyInt(hir::TyI16)),
- i32: mk(TyInt(hir::TyI32)),
- i64: mk(TyInt(hir::TyI64)),
- usize: mk(TyUint(hir::TyUs)),
- u8: mk(TyUint(hir::TyU8)),
- u16: mk(TyUint(hir::TyU16)),
- u32: mk(TyUint(hir::TyU32)),
- u64: mk(TyUint(hir::TyU64)),
- f32: mk(TyFloat(hir::TyF32)),
- f64: mk(TyFloat(hir::TyF64)),
- }
+impl<'tcx> ctxt<'tcx> {
+ pub fn pat_contains_ref_binding(&self, pat: &hir::Pat) -> Option<hir::Mutability> {
+ pat_util::pat_contains_ref_binding(&self.def_map, pat)
}
-}
-
-struct FlagComputation {
- flags: TypeFlags,
-
- // maximum depth of any bound region that we have seen thus far
- depth: u32,
-}
-impl FlagComputation {
- fn new() -> FlagComputation {
- FlagComputation { flags: TypeFlags::empty(), depth: 0 }
+ pub fn arm_contains_ref_binding(&self, arm: &hir::Arm) -> Option<hir::Mutability> {
+ pat_util::arm_contains_ref_binding(&self.def_map, arm)
}
+}
- fn for_sty(st: &TypeVariants) -> FlagComputation {
- let mut result = FlagComputation::new();
- result.add_sty(st);
- result
+impl<'tcx> TyS<'tcx> {
+ /// Iterator that walks `self` and any types reachable from
+ /// `self`, in depth-first order. Note that just walks the types
+ /// that appear in `self`, it does not descend into the fields of
+ /// structs or variants. For example:
+ ///
+ /// ```notrust
+ /// isize => { isize }
+ /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
+ /// [isize] => { [isize], isize }
+ /// ```
+ pub fn walk(&'tcx self) -> TypeWalker<'tcx> {
+ TypeWalker::new(self)
}
- fn add_flags(&mut self, flags: TypeFlags) {
- self.flags = self.flags | (flags & TypeFlags::NOMINAL_FLAGS);
+ /// Iterator that walks the immediate children of `self`. Hence
+ /// `Foo<Bar<i32>, u32>` yields the sequence `[Bar<i32>, u32]`
+ /// (but not `i32`, like `walk`).
+ pub fn walk_shallow(&'tcx self) -> IntoIter<Ty<'tcx>> {
+ walk::walk_shallow(self)
}
- fn add_depth(&mut self, depth: u32) {
- if depth > self.depth {
- self.depth = depth;
+ pub fn as_opt_param_ty(&self) -> Option<ty::ParamTy> {
+ match self.sty {
+ ty::TyParam(ref d) => Some(d.clone()),
+ _ => None,
}
}
- /// Adds the flags/depth from a set of types that appear within the current type, but within a
- /// region binder.
- fn add_bound_computation(&mut self, computation: &FlagComputation) {
- self.add_flags(computation.flags);
-
- // The types that contributed to `computation` occurred within
- // a region binder, so subtract one from the region depth
- // within when adding the depth to `self`.
- let depth = computation.depth;
- if depth > 0 {
- self.add_depth(depth - 1);
+ pub fn is_param(&self, space: ParamSpace, index: u32) -> bool {
+ match self.sty {
+ ty::TyParam(ref data) => data.space == space && data.idx == index,
+ _ => false,
}
}
- fn add_sty(&mut self, st: &TypeVariants) {
- match st {
- &TyBool |
- &TyChar |
- &TyInt(_) |
- &TyFloat(_) |
- &TyUint(_) |
- &TyStr => {
- }
-
- // You might think that we could just return TyError for
- // any type containing TyError as a component, and get
- // rid of the TypeFlags::HAS_TY_ERR flag -- likewise for ty_bot (with
- // the exception of function types that return bot).
- // But doing so caused sporadic memory corruption, and
- // neither I (tjc) nor nmatsakis could figure out why,
- // so we're doing it this way.
- &TyError => {
- self.add_flags(TypeFlags::HAS_TY_ERR)
+ /// Returns the regions directly referenced from this type (but
+ /// not types reachable from this type via `walk_tys`). This
+ /// ignores late-bound regions binders.
+ pub fn regions(&self) -> Vec<ty::Region> {
+ match self.sty {
+ TyRef(region, _) => {
+ vec![*region]
}
-
- &TyParam(ref p) => {
- self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
- if p.space == subst::SelfSpace {
- self.add_flags(TypeFlags::HAS_SELF);
- } else {
- self.add_flags(TypeFlags::HAS_PARAMS);
- }
- }
-
- &TyClosure(_, ref substs) => {
- self.add_flags(TypeFlags::HAS_TY_CLOSURE);
- self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
- self.add_substs(&substs.func_substs);
- self.add_tys(&substs.upvar_tys);
- }
-
- &TyInfer(_) => {
- self.add_flags(TypeFlags::HAS_LOCAL_NAMES); // it might, right?
- self.add_flags(TypeFlags::HAS_TY_INFER)
- }
-
- &TyEnum(_, substs) | &TyStruct(_, substs) => {
- self.add_substs(substs);
- }
-
- &TyProjection(ref data) => {
- self.add_flags(TypeFlags::HAS_PROJECTION);
- self.add_projection_ty(data);
- }
-
- &TyTrait(box TraitTy { ref principal, ref bounds }) => {
- let mut computation = FlagComputation::new();
- computation.add_substs(principal.0.substs);
- for projection_bound in &bounds.projection_bounds {
- let mut proj_computation = FlagComputation::new();
- proj_computation.add_projection_predicate(&projection_bound.0);
- self.add_bound_computation(&proj_computation);
- }
- self.add_bound_computation(&computation);
-
- self.add_bounds(bounds);
- }
-
- &TyBox(tt) | &TyArray(tt, _) | &TySlice(tt) => {
- self.add_ty(tt)
- }
-
- &TyRawPtr(ref m) => {
- self.add_ty(m.ty);
- }
-
- &TyRef(r, ref m) => {
- self.add_region(*r);
- self.add_ty(m.ty);
- }
-
- &TyTuple(ref ts) => {
- self.add_tys(&ts[..]);
- }
-
- &TyBareFn(_, ref f) => {
- self.add_fn_sig(&f.sig);
- }
- }
- }
-
- fn add_ty(&mut self, ty: Ty) {
- self.add_flags(ty.flags.get());
- self.add_depth(ty.region_depth);
- }
-
- fn add_tys(&mut self, tys: &[Ty]) {
- for &ty in tys {
- self.add_ty(ty);
- }
- }
-
- fn add_fn_sig(&mut self, fn_sig: &PolyFnSig) {
- let mut computation = FlagComputation::new();
-
- computation.add_tys(&fn_sig.0.inputs);
-
- if let ty::FnConverging(output) = fn_sig.0.output {
- computation.add_ty(output);
- }
-
- self.add_bound_computation(&computation);
- }
-
- fn add_region(&mut self, r: Region) {
- match r {
- ty::ReVar(..) |
- ty::ReSkolemized(..) => { self.add_flags(TypeFlags::HAS_RE_INFER); }
- ty::ReLateBound(debruijn, _) => { self.add_depth(debruijn.depth); }
- ty::ReEarlyBound(..) => { self.add_flags(TypeFlags::HAS_RE_EARLY_BOUND); }
- ty::ReStatic => {}
- _ => { self.add_flags(TypeFlags::HAS_FREE_REGIONS); }
- }
-
- if !r.is_global() {
- self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
- }
- }
-
- fn add_projection_predicate(&mut self, projection_predicate: &ProjectionPredicate) {
- self.add_projection_ty(&projection_predicate.projection_ty);
- self.add_ty(projection_predicate.ty);
- }
-
- fn add_projection_ty(&mut self, projection_ty: &ProjectionTy) {
- self.add_substs(projection_ty.trait_ref.substs);
- }
-
- fn add_substs(&mut self, substs: &Substs) {
- self.add_tys(substs.types.as_slice());
- match substs.regions {
- subst::ErasedRegions => {}
- subst::NonerasedRegions(ref regions) => {
- for &r in regions {
- self.add_region(r);
- }
- }
- }
- }
-
- fn add_bounds(&mut self, bounds: &ExistentialBounds) {
- self.add_region(bounds.region_bound);
- }
-}
-
-impl<'tcx> ctxt<'tcx> {
- /// Create a type context and call the closure with a `&ty::ctxt` reference
- /// to the context. The closure enforces that the type context and any interned
- /// value (types, substs, etc.) can only be used while `ty::tls` has a valid
- /// reference to the context, to allow formatting values that need it.
- pub fn create_and_enter<F, R>(s: Session,
- arenas: &'tcx CtxtArenas<'tcx>,
- def_map: DefMap,
- named_region_map: resolve_lifetime::NamedRegionMap,
- map: ast_map::Map<'tcx>,
- freevars: RefCell<FreevarMap>,
- region_maps: RegionMaps,
- lang_items: middle::lang_items::LanguageItems,
- stability: stability::Index<'tcx>,
- f: F) -> (Session, R)
- where F: FnOnce(&ctxt<'tcx>) -> R
- {
- let interner = RefCell::new(FnvHashMap());
- let common_types = CommonTypes::new(&arenas.type_, &interner);
-
- tls::enter(ctxt {
- arenas: arenas,
- interner: interner,
- substs_interner: RefCell::new(FnvHashMap()),
- bare_fn_interner: RefCell::new(FnvHashMap()),
- region_interner: RefCell::new(FnvHashMap()),
- stability_interner: RefCell::new(FnvHashMap()),
- types: common_types,
- named_region_map: named_region_map,
- region_maps: region_maps,
- free_region_maps: RefCell::new(FnvHashMap()),
- item_variance_map: RefCell::new(DefIdMap()),
- variance_computed: Cell::new(false),
- sess: s,
- def_map: def_map,
- tables: RefCell::new(Tables::empty()),
- impl_trait_refs: RefCell::new(DefIdMap()),
- trait_defs: RefCell::new(DefIdMap()),
- adt_defs: RefCell::new(DefIdMap()),
- predicates: RefCell::new(DefIdMap()),
- super_predicates: RefCell::new(DefIdMap()),
- fulfilled_predicates: RefCell::new(traits::FulfilledPredicates::new()),
- map: map,
- freevars: freevars,
- tcache: RefCell::new(DefIdMap()),
- rcache: RefCell::new(FnvHashMap()),
- tc_cache: RefCell::new(FnvHashMap()),
- ast_ty_to_ty_cache: RefCell::new(NodeMap()),
- impl_or_trait_items: RefCell::new(DefIdMap()),
- trait_item_def_ids: RefCell::new(DefIdMap()),
- trait_items_cache: RefCell::new(DefIdMap()),
- ty_param_defs: RefCell::new(NodeMap()),
- normalized_cache: RefCell::new(FnvHashMap()),
- lang_items: lang_items,
- provided_method_sources: RefCell::new(DefIdMap()),
- destructors: RefCell::new(DefIdSet()),
- inherent_impls: RefCell::new(DefIdMap()),
- impl_items: RefCell::new(DefIdMap()),
- used_unsafe: RefCell::new(NodeSet()),
- used_mut_nodes: RefCell::new(NodeSet()),
- populated_external_types: RefCell::new(DefIdSet()),
- populated_external_primitive_impls: RefCell::new(DefIdSet()),
- extern_const_statics: RefCell::new(DefIdMap()),
- extern_const_variants: RefCell::new(DefIdMap()),
- extern_const_fns: RefCell::new(DefIdMap()),
- node_lint_levels: RefCell::new(FnvHashMap()),
- transmute_restrictions: RefCell::new(Vec::new()),
- stability: RefCell::new(stability),
- selection_cache: traits::SelectionCache::new(),
- repr_hint_cache: RefCell::new(DefIdMap()),
- const_qualif_map: RefCell::new(NodeMap()),
- custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
- cast_kinds: RefCell::new(NodeMap()),
- fragment_infos: RefCell::new(DefIdMap()),
- }, f)
- }
-
- // Type constructors
-
- pub fn mk_substs(&self, substs: Substs<'tcx>) -> &'tcx Substs<'tcx> {
- if let Some(substs) = self.substs_interner.borrow().get(&substs) {
- return *substs;
- }
-
- let substs = self.arenas.substs.alloc(substs);
- self.substs_interner.borrow_mut().insert(substs, substs);
- substs
- }
-
- /// Create an unsafe fn ty based on a safe fn ty.
- pub fn safe_to_unsafe_fn_ty(&self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> {
- assert_eq!(bare_fn.unsafety, hir::Unsafety::Normal);
- let unsafe_fn_ty_a = self.mk_bare_fn(ty::BareFnTy {
- unsafety: hir::Unsafety::Unsafe,
- abi: bare_fn.abi,
- sig: bare_fn.sig.clone()
- });
- self.mk_fn(None, unsafe_fn_ty_a)
- }
-
- pub fn mk_bare_fn(&self, bare_fn: BareFnTy<'tcx>) -> &'tcx BareFnTy<'tcx> {
- if let Some(bare_fn) = self.bare_fn_interner.borrow().get(&bare_fn) {
- return *bare_fn;
- }
-
- let bare_fn = self.arenas.bare_fn.alloc(bare_fn);
- self.bare_fn_interner.borrow_mut().insert(bare_fn, bare_fn);
- bare_fn
- }
-
- pub fn mk_region(&self, region: Region) -> &'tcx Region {
- if let Some(region) = self.region_interner.borrow().get(®ion) {
- return *region;
- }
-
- let region = self.arenas.region.alloc(region);
- self.region_interner.borrow_mut().insert(region, region);
- region
- }
-
- pub fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind {
- *self.tables.borrow().closure_kinds.get(&def_id).unwrap()
- }
-
- pub fn closure_type(&self,
- def_id: DefId,
- substs: &ClosureSubsts<'tcx>)
- -> ty::ClosureTy<'tcx>
- {
- self.tables.borrow().closure_tys.get(&def_id).unwrap().subst(self, &substs.func_substs)
- }
-
- pub fn type_parameter_def(&self,
- node_id: NodeId)
- -> TypeParameterDef<'tcx>
- {
- self.ty_param_defs.borrow().get(&node_id).unwrap().clone()
- }
-
- pub fn pat_contains_ref_binding(&self, pat: &hir::Pat) -> Option<hir::Mutability> {
- pat_util::pat_contains_ref_binding(&self.def_map, pat)
- }
-
- pub fn arm_contains_ref_binding(&self, arm: &hir::Arm) -> Option<hir::Mutability> {
- pat_util::arm_contains_ref_binding(&self.def_map, arm)
- }
-
- fn intern_ty(type_arena: &'tcx TypedArena<TyS<'tcx>>,
- interner: &RefCell<FnvHashMap<InternedTy<'tcx>, Ty<'tcx>>>,
- st: TypeVariants<'tcx>)
- -> Ty<'tcx> {
- let ty: Ty /* don't be &mut TyS */ = {
- let mut interner = interner.borrow_mut();
- match interner.get(&st) {
- Some(ty) => return *ty,
- _ => ()
- }
-
- let flags = FlagComputation::for_sty(&st);
-
- let ty = match () {
- () => type_arena.alloc(TyS { sty: st,
- flags: Cell::new(flags.flags),
- region_depth: flags.depth, }),
- };
-
- interner.insert(InternedTy { ty: ty }, ty);
- ty
- };
-
- debug!("Interned type: {:?} Pointer: {:?}",
- ty, ty as *const TyS);
- ty
- }
-
- // 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 Ty above).
- pub fn mk_ty(&self, st: TypeVariants<'tcx>) -> Ty<'tcx> {
- ctxt::intern_ty(&self.arenas.type_, &self.interner, st)
- }
-
- pub fn mk_mach_int(&self, tm: hir::IntTy) -> Ty<'tcx> {
- match tm {
- hir::TyIs => self.types.isize,
- hir::TyI8 => self.types.i8,
- hir::TyI16 => self.types.i16,
- hir::TyI32 => self.types.i32,
- hir::TyI64 => self.types.i64,
- }
- }
-
- pub fn mk_mach_uint(&self, tm: hir::UintTy) -> Ty<'tcx> {
- match tm {
- hir::TyUs => self.types.usize,
- hir::TyU8 => self.types.u8,
- hir::TyU16 => self.types.u16,
- hir::TyU32 => self.types.u32,
- hir::TyU64 => self.types.u64,
- }
- }
-
- pub fn mk_mach_float(&self, tm: hir::FloatTy) -> Ty<'tcx> {
- match tm {
- hir::TyF32 => self.types.f32,
- hir::TyF64 => self.types.f64,
- }
- }
-
- pub fn mk_str(&self) -> Ty<'tcx> {
- self.mk_ty(TyStr)
- }
-
- pub fn mk_static_str(&self) -> Ty<'tcx> {
- self.mk_imm_ref(self.mk_region(ty::ReStatic), self.mk_str())
- }
-
- pub fn mk_enum(&self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
- // take a copy of substs so that we own the vectors inside
- self.mk_ty(TyEnum(def, substs))
- }
-
- pub fn mk_box(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
- self.mk_ty(TyBox(ty))
- }
-
- pub fn mk_ptr(&self, tm: TypeAndMut<'tcx>) -> Ty<'tcx> {
- self.mk_ty(TyRawPtr(tm))
- }
-
- pub fn mk_ref(&self, r: &'tcx Region, tm: TypeAndMut<'tcx>) -> Ty<'tcx> {
- self.mk_ty(TyRef(r, tm))
- }
-
- pub fn mk_mut_ref(&self, r: &'tcx Region, ty: Ty<'tcx>) -> Ty<'tcx> {
- self.mk_ref(r, TypeAndMut {ty: ty, mutbl: hir::MutMutable})
- }
-
- pub fn mk_imm_ref(&self, r: &'tcx Region, ty: Ty<'tcx>) -> Ty<'tcx> {
- self.mk_ref(r, TypeAndMut {ty: ty, mutbl: hir::MutImmutable})
- }
-
- pub fn mk_mut_ptr(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
- self.mk_ptr(TypeAndMut {ty: ty, mutbl: hir::MutMutable})
- }
-
- pub fn mk_imm_ptr(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
- self.mk_ptr(TypeAndMut {ty: ty, mutbl: hir::MutImmutable})
- }
-
- pub fn mk_nil_ptr(&self) -> Ty<'tcx> {
- self.mk_imm_ptr(self.mk_nil())
- }
-
- pub fn mk_array(&self, ty: Ty<'tcx>, n: usize) -> Ty<'tcx> {
- self.mk_ty(TyArray(ty, n))
- }
-
- pub fn mk_slice(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
- self.mk_ty(TySlice(ty))
- }
-
- pub fn mk_tup(&self, ts: Vec<Ty<'tcx>>) -> Ty<'tcx> {
- self.mk_ty(TyTuple(ts))
- }
-
- pub fn mk_nil(&self) -> Ty<'tcx> {
- self.mk_tup(Vec::new())
- }
-
- pub fn mk_bool(&self) -> Ty<'tcx> {
- self.mk_ty(TyBool)
- }
-
- pub fn mk_fn(&self,
- opt_def_id: Option<DefId>,
- fty: &'tcx BareFnTy<'tcx>) -> Ty<'tcx> {
- self.mk_ty(TyBareFn(opt_def_id, fty))
- }
-
- pub fn mk_ctor_fn(&self,
- def_id: DefId,
- input_tys: &[Ty<'tcx>],
- output: Ty<'tcx>) -> Ty<'tcx> {
- let input_args = input_tys.iter().cloned().collect();
- self.mk_fn(Some(def_id), self.mk_bare_fn(BareFnTy {
- unsafety: hir::Unsafety::Normal,
- abi: abi::Rust,
- sig: ty::Binder(FnSig {
- inputs: input_args,
- output: ty::FnConverging(output),
- variadic: false
- })
- }))
- }
-
- pub fn mk_trait(&self,
- principal: ty::PolyTraitRef<'tcx>,
- bounds: ExistentialBounds<'tcx>)
- -> Ty<'tcx>
- {
- assert!(bound_list_is_sorted(&bounds.projection_bounds));
-
- let inner = box TraitTy {
- principal: principal,
- bounds: bounds
- };
- self.mk_ty(TyTrait(inner))
- }
-
- pub fn mk_projection(&self,
- trait_ref: TraitRef<'tcx>,
- item_name: Name)
- -> Ty<'tcx> {
- // take a copy of substs so that we own the vectors inside
- let inner = ProjectionTy { trait_ref: trait_ref, item_name: item_name };
- self.mk_ty(TyProjection(inner))
- }
-
- pub fn mk_struct(&self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
- // take a copy of substs so that we own the vectors inside
- self.mk_ty(TyStruct(def, substs))
- }
-
- pub fn mk_closure(&self,
- closure_id: DefId,
- substs: &'tcx Substs<'tcx>,
- tys: Vec<Ty<'tcx>>)
- -> Ty<'tcx> {
- self.mk_closure_from_closure_substs(closure_id, Box::new(ClosureSubsts {
- func_substs: substs,
- upvar_tys: tys
- }))
- }
-
- pub fn mk_closure_from_closure_substs(&self,
- closure_id: DefId,
- closure_substs: Box<ClosureSubsts<'tcx>>)
- -> Ty<'tcx> {
- self.mk_ty(TyClosure(closure_id, closure_substs))
- }
-
- pub fn mk_var(&self, v: TyVid) -> Ty<'tcx> {
- self.mk_infer(TyVar(v))
- }
-
- pub fn mk_int_var(&self, v: IntVid) -> Ty<'tcx> {
- self.mk_infer(IntVar(v))
- }
-
- pub fn mk_float_var(&self, v: FloatVid) -> Ty<'tcx> {
- self.mk_infer(FloatVar(v))
- }
-
- pub fn mk_infer(&self, it: InferTy) -> Ty<'tcx> {
- self.mk_ty(TyInfer(it))
- }
-
- pub fn mk_param(&self,
- space: subst::ParamSpace,
- index: u32,
- name: Name) -> Ty<'tcx> {
- self.mk_ty(TyParam(ParamTy { space: space, idx: index, name: name }))
- }
-
- pub fn mk_self_type(&self) -> Ty<'tcx> {
- self.mk_param(subst::SelfSpace, 0, special_idents::type_self.name)
- }
-
- pub fn mk_param_from_def(&self, def: &TypeParameterDef) -> Ty<'tcx> {
- self.mk_param(def.space, def.index, def.name)
- }
-}
-
-fn bound_list_is_sorted(bounds: &[ty::PolyProjectionPredicate]) -> bool {
- bounds.is_empty() ||
- bounds[1..].iter().enumerate().all(
- |(index, bound)| bounds[index].sort_key() <= bound.sort_key())
-}
-
-pub fn sort_bounds_list(bounds: &mut [ty::PolyProjectionPredicate]) {
- bounds.sort_by(|a, b| a.sort_key().cmp(&b.sort_key()))
-}
-
-impl<'tcx> TyS<'tcx> {
- /// Iterator that walks `self` and any types reachable from
- /// `self`, in depth-first order. Note that just walks the types
- /// that appear in `self`, it does not descend into the fields of
- /// structs or variants. For example:
- ///
- /// ```notrust
- /// isize => { isize }
- /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
- /// [isize] => { [isize], isize }
- /// ```
- pub fn walk(&'tcx self) -> TypeWalker<'tcx> {
- TypeWalker::new(self)
- }
-
- /// Iterator that walks the immediate children of `self`. Hence
- /// `Foo<Bar<i32>, u32>` yields the sequence `[Bar<i32>, u32]`
- /// (but not `i32`, like `walk`).
- pub fn walk_shallow(&'tcx self) -> IntoIter<Ty<'tcx>> {
- walk::walk_shallow(self)
- }
-
- pub fn as_opt_param_ty(&self) -> Option<ty::ParamTy> {
- match self.sty {
- ty::TyParam(ref d) => Some(d.clone()),
- _ => None,
- }
- }
-
- pub fn is_param(&self, space: ParamSpace, index: u32) -> bool {
- match self.sty {
- ty::TyParam(ref data) => data.space == space && data.idx == index,
- _ => false,
- }
- }
-
- /// Returns the regions directly referenced from this type (but
- /// not types reachable from this type via `walk_tys`). This
- /// ignores late-bound regions binders.
- pub fn regions(&self) -> Vec<ty::Region> {
- match self.sty {
- TyRef(region, _) => {
- vec![*region]
- }
- TyTrait(ref obj) => {
- let mut v = vec![obj.bounds.region_bound];
- v.push_all(obj.principal.skip_binder().substs.regions().as_slice());
- v
+ TyTrait(ref obj) => {
+ let mut v = vec![obj.bounds.region_bound];
+ v.push_all(obj.principal.skip_binder().substs.regions().as_slice());
+ v
}
TyEnum(_, substs) |
TyStruct(_, substs) => {
TyInfer(_) |
TyError => {
vec![]
- }
- }
- }
-
- /// Walks `ty` and any types appearing within `ty`, invoking the
- /// callback `f` on each type. If the callback returns false, then the
- /// children of the current type are ignored.
- ///
- /// Note: prefer `ty.walk()` where possible.
- pub fn maybe_walk<F>(&'tcx self, mut f: F)
- where F : FnMut(Ty<'tcx>) -> bool
- {
- let mut walker = self.walk();
- while let Some(ty) = walker.next() {
- if !f(ty) {
- walker.skip_current_subtree();
- }
- }
- }
-}
-
-impl ParamTy {
- pub fn new(space: subst::ParamSpace,
- index: u32,
- name: Name)
- -> ParamTy {
- ParamTy { space: space, idx: index, name: name }
- }
-
- pub fn for_self() -> ParamTy {
- ParamTy::new(subst::SelfSpace, 0, special_idents::type_self.name)
- }
-
- pub fn for_def(def: &TypeParameterDef) -> ParamTy {
- ParamTy::new(def.space, def.index, def.name)
- }
-
- pub fn to_ty<'tcx>(self, tcx: &ctxt<'tcx>) -> Ty<'tcx> {
- tcx.mk_param(self.space, self.idx, self.name)
- }
-
- pub fn is_self(&self) -> bool {
- self.space == subst::SelfSpace && self.idx == 0
- }
-}
-
-impl<'tcx> ItemSubsts<'tcx> {
- pub fn empty() -> ItemSubsts<'tcx> {
- ItemSubsts { substs: Substs::empty() }
- }
-
- pub fn is_noop(&self) -> bool {
- self.substs.is_noop()
- }
-}
-
-// Type utilities
-impl<'tcx> TyS<'tcx> {
- pub fn is_nil(&self) -> bool {
- match self.sty {
- TyTuple(ref tys) => tys.is_empty(),
- _ => false
- }
- }
-
- pub fn is_empty(&self, _cx: &ctxt) -> bool {
- // FIXME(#24885): be smarter here
- match self.sty {
- TyEnum(def, _) | TyStruct(def, _) => def.is_empty(),
- _ => false
- }
- }
-
- pub fn is_ty_var(&self) -> bool {
- match self.sty {
- TyInfer(TyVar(_)) => true,
- _ => false
- }
- }
-
- pub fn is_bool(&self) -> bool { self.sty == TyBool }
-
- pub fn is_self(&self) -> bool {
- match self.sty {
- TyParam(ref p) => p.space == subst::SelfSpace,
- _ => false
- }
- }
-
- fn is_slice(&self) -> bool {
- match self.sty {
- TyRawPtr(mt) | TyRef(_, mt) => match mt.ty.sty {
- TySlice(_) | TyStr => true,
- _ => false,
- },
- _ => false
- }
- }
-
- pub fn is_structural(&self) -> bool {
- match self.sty {
- TyStruct(..) | TyTuple(_) | TyEnum(..) |
- TyArray(..) | TyClosure(..) => true,
- _ => self.is_slice() | self.is_trait()
- }
- }
-
- #[inline]
- pub fn is_simd(&self) -> bool {
- match self.sty {
- TyStruct(def, _) => def.is_simd(),
- _ => false
- }
- }
-
- pub fn sequence_element_type(&self, cx: &ctxt<'tcx>) -> Ty<'tcx> {
- match self.sty {
- TyArray(ty, _) | TySlice(ty) => ty,
- TyStr => cx.mk_mach_uint(hir::TyU8),
- _ => cx.sess.bug(&format!("sequence_element_type called on non-sequence value: {}",
- self)),
- }
- }
-
- pub fn simd_type(&self, cx: &ctxt<'tcx>) -> Ty<'tcx> {
- match self.sty {
- TyStruct(def, substs) => {
- def.struct_variant().fields[0].ty(cx, substs)
- }
- _ => panic!("simd_type called on invalid type")
- }
- }
-
- pub fn simd_size(&self, _cx: &ctxt) -> usize {
- match self.sty {
- TyStruct(def, _) => def.struct_variant().fields.len(),
- _ => panic!("simd_size called on invalid type")
- }
- }
-
- pub fn is_region_ptr(&self) -> bool {
- match self.sty {
- TyRef(..) => true,
- _ => false
- }
- }
-
- pub fn is_unsafe_ptr(&self) -> bool {
- match self.sty {
- TyRawPtr(_) => return true,
- _ => return false
- }
- }
-
- pub fn is_unique(&self) -> bool {
- match self.sty {
- TyBox(_) => true,
- _ => false
- }
- }
-
- /*
- A scalar type is one that denotes an atomic datum, with no sub-components.
- (A TyRawPtr is scalar because it represents a non-managed pointer, so its
- contents are abstract to rustc.)
- */
- pub fn is_scalar(&self) -> bool {
- match self.sty {
- TyBool | TyChar | TyInt(_) | TyFloat(_) | TyUint(_) |
- TyInfer(IntVar(_)) | TyInfer(FloatVar(_)) |
- TyBareFn(..) | TyRawPtr(_) => true,
- _ => false
- }
- }
-
- /// Returns true if this type is a floating point type and false otherwise.
- pub fn is_floating_point(&self) -> bool {
- match self.sty {
- TyFloat(_) |
- TyInfer(FloatVar(_)) => true,
- _ => false,
- }
- }
-
- pub fn ty_to_def_id(&self) -> Option<DefId> {
- match self.sty {
- TyTrait(ref tt) => Some(tt.principal_def_id()),
- TyStruct(def, _) |
- TyEnum(def, _) => Some(def.did),
- TyClosure(id, _) => Some(id),
- _ => None
- }
- }
-
- pub fn ty_adt_def(&self) -> Option<AdtDef<'tcx>> {
- match self.sty {
- TyStruct(adt, _) | TyEnum(adt, _) => Some(adt),
- _ => None
- }
- }
-}
-
-/// 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 reference 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.
-#[derive(Clone, Copy)]
-pub struct TypeContents {
- pub bits: u64
-}
-
-macro_rules! def_type_content_sets {
- (mod $mname:ident { $($name:ident = $bits:expr),+ }) => {
- #[allow(non_snake_case)]
- mod $mname {
- use middle::ty::TypeContents;
- $(
- #[allow(non_upper_case_globals)]
- pub const $name: TypeContents = TypeContents { bits: $bits };
- )+
+ }
}
}
-}
-
-def_type_content_sets! {
- mod TC {
- None = 0b0000_0000__0000_0000__0000,
-
- // Things that are interior to the value (first nibble):
- InteriorUnsafe = 0b0000_0000__0000_0000__0010,
- InteriorParam = 0b0000_0000__0000_0000__0100,
- // InteriorAll = 0b00000000__00000000__1111,
- // Things that are owned by the value (second and third nibbles):
- OwnsOwned = 0b0000_0000__0000_0001__0000,
- OwnsDtor = 0b0000_0000__0000_0010__0000,
- OwnsAll = 0b0000_0000__1111_1111__0000,
-
- // Things that mean drop glue is necessary
- NeedsDrop = 0b0000_0000__0000_0111__0000,
-
- // All bits
- All = 0b1111_1111__1111_1111__1111
+ /// Walks `ty` and any types appearing within `ty`, invoking the
+ /// callback `f` on each type. If the callback returns false, then the
+ /// children of the current type are ignored.
+ ///
+ /// Note: prefer `ty.walk()` where possible.
+ pub fn maybe_walk<F>(&'tcx self, mut f: F)
+ where F : FnMut(Ty<'tcx>) -> bool
+ {
+ let mut walker = self.walk();
+ while let Some(ty) = walker.next() {
+ if !f(ty) {
+ walker.skip_current_subtree();
+ }
+ }
}
}
-impl TypeContents {
- pub fn when(&self, cond: bool) -> TypeContents {
- if cond {*self} else {TC::None}
- }
-
- pub fn intersects(&self, tc: TypeContents) -> bool {
- (self.bits & tc.bits) != 0
- }
-
- pub fn owns_owned(&self) -> bool {
- self.intersects(TC::OwnsOwned)
- }
-
- pub fn interior_param(&self) -> bool {
- self.intersects(TC::InteriorParam)
- }
-
- pub fn interior_unsafe(&self) -> bool {
- self.intersects(TC::InteriorUnsafe)
- }
-
- pub fn needs_drop(&self, _: &ctxt) -> bool {
- self.intersects(TC::NeedsDrop)
- }
-
- /// Includes only those bits that still apply when indirected through a `Box` pointer
- pub fn owned_pointer(&self) -> TypeContents {
- TC::OwnsOwned | (*self & TC::OwnsAll)
+impl ParamTy {
+ pub fn new(space: subst::ParamSpace,
+ index: u32,
+ name: Name)
+ -> ParamTy {
+ ParamTy { space: space, idx: index, name: name }
}
- pub fn union<T, F>(v: &[T], mut f: F) -> TypeContents where
- F: FnMut(&T) -> TypeContents,
- {
- v.iter().fold(TC::None, |tc, ty| tc | f(ty))
+ pub fn for_self() -> ParamTy {
+ ParamTy::new(subst::SelfSpace, 0, special_idents::type_self.name)
}
- pub fn has_dtor(&self) -> bool {
- self.intersects(TC::OwnsDtor)
+ pub fn for_def(def: &TypeParameterDef) -> ParamTy {
+ ParamTy::new(def.space, def.index, def.name)
}
-}
-
-impl ops::BitOr for TypeContents {
- type Output = TypeContents;
- fn bitor(self, other: TypeContents) -> TypeContents {
- TypeContents {bits: self.bits | other.bits}
+ pub fn to_ty<'tcx>(self, tcx: &ctxt<'tcx>) -> Ty<'tcx> {
+ tcx.mk_param(self.space, self.idx, self.name)
}
-}
-
-impl ops::BitAnd for TypeContents {
- type Output = TypeContents;
- fn bitand(self, other: TypeContents) -> TypeContents {
- TypeContents {bits: self.bits & other.bits}
+ pub fn is_self(&self) -> bool {
+ self.space == subst::SelfSpace && self.idx == 0
}
}
-impl ops::Sub for TypeContents {
- type Output = TypeContents;
-
- fn sub(self, other: TypeContents) -> TypeContents {
- TypeContents {bits: self.bits & !other.bits}
+impl<'tcx> ItemSubsts<'tcx> {
+ pub fn empty() -> ItemSubsts<'tcx> {
+ ItemSubsts { substs: Substs::empty() }
}
-}
-impl fmt::Debug for TypeContents {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "TypeContents({:b})", self.bits)
+ pub fn is_noop(&self) -> bool {
+ self.substs.is_noop()
}
}
impl<'tcx> TyS<'tcx> {
- pub fn type_contents(&'tcx self, cx: &ctxt<'tcx>) -> TypeContents {
- return memoized(&cx.tc_cache, self, |ty| {
- tc_ty(cx, ty, &mut FnvHashMap())
- });
-
- fn tc_ty<'tcx>(cx: &ctxt<'tcx>,
- ty: Ty<'tcx>,
- cache: &mut FnvHashMap<Ty<'tcx>, 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: Box<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::OwnsOwned, 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::OwnsOwned. This manifested as issue #4821.
- match cache.get(&ty) {
- Some(tc) => { return *tc; }
- None => {}
- }
- match cx.tc_cache.borrow().get(&ty) { // Must check both caches!
- Some(tc) => { return *tc; }
- None => {}
- }
- cache.insert(ty, TC::None);
-
- let result = match ty.sty {
- // usize and isize are ffi-unsafe
- TyUint(hir::TyUs) | TyInt(hir::TyIs) => {
- TC::None
- }
-
- // Scalar and unique types are sendable, and durable
- TyInfer(ty::FreshIntTy(_)) | TyInfer(ty::FreshFloatTy(_)) |
- TyBool | TyInt(_) | TyUint(_) | TyFloat(_) |
- TyBareFn(..) | ty::TyChar => {
- TC::None
- }
-
- TyBox(typ) => {
- tc_ty(cx, typ, cache).owned_pointer()
- }
-
- TyTrait(_) => {
- TC::All - TC::InteriorParam
- }
-
- TyRawPtr(_) => {
- TC::None
- }
-
- TyRef(_, _) => {
- TC::None
- }
-
- TyArray(ty, _) => {
- tc_ty(cx, ty, cache)
- }
-
- TySlice(ty) => {
- tc_ty(cx, ty, cache)
- }
- TyStr => TC::None,
-
- TyClosure(_, ref substs) => {
- TypeContents::union(&substs.upvar_tys, |ty| tc_ty(cx, &ty, cache))
- }
-
- TyTuple(ref tys) => {
- TypeContents::union(&tys[..],
- |ty| tc_ty(cx, *ty, cache))
- }
-
- TyStruct(def, substs) | TyEnum(def, substs) => {
- let mut res =
- TypeContents::union(&def.variants, |v| {
- TypeContents::union(&v.fields, |f| {
- tc_ty(cx, f.ty(cx, substs), cache)
- })
- });
-
- if def.has_dtor() {
- res = res | TC::OwnsDtor;
- }
-
- apply_lang_items(cx, def.did, res)
- }
-
- TyProjection(..) |
- TyParam(_) => {
- TC::All
- }
-
- TyInfer(_) |
- TyError => {
- cx.sess.bug("asked to compute contents of error type");
- }
- };
-
- cache.insert(ty, result);
- result
- }
-
- fn apply_lang_items(cx: &ctxt, did: DefId, tc: TypeContents)
- -> TypeContents {
- if Some(did) == cx.lang_items.unsafe_cell_type() {
- tc | TC::InteriorUnsafe
- } else {
- tc
- }
- }
- }
-
fn impls_bound<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>,
bound: ty::BuiltinBound,
span: Span)
r
}
- pub fn is_trait(&self) -> bool {
- match self.sty {
- TyTrait(..) => true,
- _ => false
- }
- }
-
- pub fn is_integral(&self) -> bool {
- match self.sty {
- TyInfer(IntVar(_)) | TyInt(_) | TyUint(_) => true,
- _ => false
- }
- }
-
- pub fn is_fresh(&self) -> bool {
- match self.sty {
- TyInfer(FreshTy(_)) => true,
- TyInfer(FreshIntTy(_)) => true,
- TyInfer(FreshFloatTy(_)) => true,
- _ => false
- }
- }
-
- pub fn is_uint(&self) -> bool {
- match self.sty {
- TyInfer(IntVar(_)) | TyUint(hir::TyUs) => true,
- _ => false
- }
- }
-
- pub fn is_char(&self) -> bool {
- match self.sty {
- TyChar => true,
- _ => false
- }
- }
-
- pub fn is_bare_fn(&self) -> bool {
- match self.sty {
- TyBareFn(..) => true,
- _ => false
- }
- }
-
- pub fn is_bare_fn_item(&self) -> bool {
- match self.sty {
- TyBareFn(Some(_), _) => true,
- _ => false
- }
- }
-
- pub fn is_fp(&self) -> bool {
- match self.sty {
- TyInfer(FloatVar(_)) | TyFloat(_) => true,
- _ => false
- }
- }
-
- pub fn is_numeric(&self) -> bool {
- self.is_integral() || self.is_fp()
- }
-
- pub fn is_signed(&self) -> bool {
- match self.sty {
- TyInt(_) => true,
- _ => false
- }
- }
-
- pub fn is_machine(&self) -> bool {
- match self.sty {
- TyInt(hir::TyIs) | TyUint(hir::TyUs) => false,
- TyInt(..) | TyUint(..) | TyFloat(..) => true,
- _ => false
- }
- }
-
- // Returns the type and mutability of *ty.
- //
- // The parameter `explicit` indicates if this is an *explicit* dereference.
- // Some types---notably unsafe ptrs---can only be dereferenced explicitly.
- pub fn builtin_deref(&self, explicit: bool, pref: LvaluePreference)
- -> Option<TypeAndMut<'tcx>>
- {
- match self.sty {
- TyBox(ty) => {
- Some(TypeAndMut {
- ty: ty,
- mutbl:
- if pref == PreferMutLvalue { hir::MutMutable } else { hir::MutImmutable },
- })
- },
- TyRef(_, mt) => Some(mt),
- TyRawPtr(mt) if explicit => Some(mt),
- _ => None
- }
- }
-
- // Returns the type of ty[i]
- pub fn builtin_index(&self) -> Option<Ty<'tcx>> {
- match self.sty {
- TyArray(ty, _) | TySlice(ty) => Some(ty),
- _ => None
- }
- }
-
- pub fn fn_sig(&self) -> &'tcx PolyFnSig<'tcx> {
- match self.sty {
- TyBareFn(_, ref f) => &f.sig,
- _ => panic!("Ty::fn_sig() called on non-fn type: {:?}", self)
- }
- }
-
- /// Returns the ABI of the given function.
- pub fn fn_abi(&self) -> abi::Abi {
- match self.sty {
- TyBareFn(_, ref f) => f.abi,
- _ => panic!("Ty::fn_abi() called on non-fn type"),
- }
- }
-
- // Type accessors for substructures of types
- pub fn fn_args(&self) -> ty::Binder<Vec<Ty<'tcx>>> {
- self.fn_sig().inputs()
- }
-
- pub fn fn_ret(&self) -> Binder<FnOutput<'tcx>> {
- self.fn_sig().output()
- }
-
- pub fn is_fn(&self) -> bool {
- match self.sty {
- TyBareFn(..) => true,
- _ => false
- }
- }
-
/// See `expr_ty_adjusted`
pub fn adjust<F>(&'tcx self, cx: &ctxt<'tcx>,
span: Span,
}
}
- fn sort_string(&self, cx: &ctxt) -> String {
-
- match self.sty {
- TyBool | TyChar | TyInt(_) |
- TyUint(_) | TyFloat(_) | TyStr => self.to_string(),
- TyTuple(ref tys) if tys.is_empty() => self.to_string(),
-
- TyEnum(def, _) => format!("enum `{}`", cx.item_path_str(def.did)),
- TyBox(_) => "box".to_string(),
- TyArray(_, n) => format!("array of {} elements", n),
- TySlice(_) => "slice".to_string(),
- TyRawPtr(_) => "*-ptr".to_string(),
- TyRef(_, _) => "&-ptr".to_string(),
- TyBareFn(Some(_), _) => format!("fn item"),
- TyBareFn(None, _) => "fn pointer".to_string(),
- TyTrait(ref inner) => {
- format!("trait {}", cx.item_path_str(inner.principal_def_id()))
- }
- TyStruct(def, _) => {
- format!("struct `{}`", cx.item_path_str(def.did))
- }
- TyClosure(..) => "closure".to_string(),
- TyTuple(_) => "tuple".to_string(),
- TyInfer(TyVar(_)) => "inferred type".to_string(),
- TyInfer(IntVar(_)) => "integral variable".to_string(),
- TyInfer(FloatVar(_)) => "floating-point variable".to_string(),
- TyInfer(FreshTy(_)) => "skolemized type".to_string(),
- TyInfer(FreshIntTy(_)) => "skolemized integral type".to_string(),
- TyInfer(FreshFloatTy(_)) => "skolemized floating-point type".to_string(),
- TyProjection(_) => "associated type".to_string(),
- TyParam(ref p) => {
- if p.space == subst::SelfSpace {
- "Self".to_string()
- } else {
- "type parameter".to_string()
- }
- }
- TyError => "type error".to_string(),
- }
- }
-}
-/// 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.
-impl<'tcx> fmt::Display for TypeError<'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- use self::TypeError::*;
- fn report_maybe_different(f: &mut fmt::Formatter,
- expected: String, found: String) -> fmt::Result {
- // A naive approach to making sure that we're not reporting silly errors such as:
- // (expected closure, found closure).
- if expected == found {
- write!(f, "expected {}, found a different {}", expected, found)
- } else {
- write!(f, "expected {}, found {}", expected, found)
- }
- }
-
- match *self {
- CyclicTy => write!(f, "cyclic type of infinite size"),
- Mismatch => write!(f, "types differ"),
- UnsafetyMismatch(values) => {
- write!(f, "expected {} fn, found {} fn",
- values.expected,
- values.found)
- }
- AbiMismatch(values) => {
- write!(f, "expected {} fn, found {} fn",
- values.expected,
- values.found)
- }
- Mutability => write!(f, "values differ in mutability"),
- BoxMutability => {
- write!(f, "boxed values differ in mutability")
- }
- VecMutability => write!(f, "vectors differ in mutability"),
- PtrMutability => write!(f, "pointers differ in mutability"),
- RefMutability => write!(f, "references differ in mutability"),
- TyParamSize(values) => {
- write!(f, "expected a type with {} type params, \
- found one with {} type params",
- values.expected,
- values.found)
- }
- FixedArraySize(values) => {
- write!(f, "expected an array with a fixed size of {} elements, \
- found one with {} elements",
- values.expected,
- values.found)
- }
- TupleSize(values) => {
- write!(f, "expected a tuple with {} elements, \
- found one with {} elements",
- values.expected,
- values.found)
- }
- ArgCount => {
- write!(f, "incorrect number of function parameters")
- }
- RegionsDoesNotOutlive(..) => {
- write!(f, "lifetime mismatch")
- }
- RegionsNotSame(..) => {
- write!(f, "lifetimes are not the same")
- }
- RegionsNoOverlap(..) => {
- write!(f, "lifetimes do not intersect")
- }
- RegionsInsufficientlyPolymorphic(br, _) => {
- write!(f, "expected bound lifetime parameter {}, \
- found concrete lifetime", br)
- }
- RegionsOverlyPolymorphic(br, _) => {
- write!(f, "expected concrete lifetime, \
- found bound lifetime parameter {}", br)
- }
- Sorts(values) => tls::with(|tcx| {
- report_maybe_different(f, values.expected.sort_string(tcx),
- values.found.sort_string(tcx))
- }),
- Traits(values) => tls::with(|tcx| {
- report_maybe_different(f,
- format!("trait `{}`",
- tcx.item_path_str(values.expected)),
- format!("trait `{}`",
- tcx.item_path_str(values.found)))
- }),
- BuiltinBoundsMismatch(values) => {
- if values.expected.is_empty() {
- write!(f, "expected no bounds, found `{}`",
- values.found)
- } else if values.found.is_empty() {
- write!(f, "expected bounds `{}`, found no bounds",
- values.expected)
- } else {
- write!(f, "expected bounds `{}`, found bounds `{}`",
- values.expected,
- values.found)
- }
- }
- IntegerAsChar => {
- write!(f, "expected an integral type, found `char`")
- }
- IntMismatch(ref values) => {
- write!(f, "expected `{:?}`, found `{:?}`",
- values.expected,
- values.found)
- }
- FloatMismatch(ref values) => {
- write!(f, "expected `{:?}`, found `{:?}`",
- values.expected,
- values.found)
- }
- VariadicMismatch(ref values) => {
- write!(f, "expected {} fn, found {} function",
- if values.expected { "variadic" } else { "non-variadic" },
- if values.found { "variadic" } else { "non-variadic" })
- }
- ConvergenceMismatch(ref values) => {
- write!(f, "expected {} fn, found {} function",
- if values.expected { "converging" } else { "diverging" },
- if values.found { "converging" } else { "diverging" })
- }
- ProjectionNameMismatched(ref values) => {
- write!(f, "expected {}, found {}",
- values.expected,
- values.found)
- }
- ProjectionBoundsLength(ref values) => {
- write!(f, "expected {} associated type bindings, found {}",
- values.expected,
- values.found)
- },
- TyParamDefaultMismatch(ref values) => {
- write!(f, "conflicting type parameter defaults `{}` and `{}`",
- values.expected.ty,
- values.found.ty)
- }
- }
- }
}
/// Helper for looking things up in the various maps that are populated during
hir::ExprAssignOp(..) |
hir::ExprLit(_) |
hir::ExprUnary(..) |
- hir::ExprBox(..) |
- hir::ExprAddrOf(..) |
- hir::ExprBinary(..) |
- hir::ExprCast(..) => {
- false
- }
-
- hir::ExprParen(ref e) => self.expr_is_lval(e),
- }
- }
-
- pub fn note_and_explain_type_err(&self, err: &TypeError<'tcx>, sp: Span) {
- use self::TypeError::*;
-
- match err.clone() {
- RegionsDoesNotOutlive(subregion, superregion) => {
- self.note_and_explain_region("", subregion, "...");
- self.note_and_explain_region("...does not necessarily outlive ",
- superregion, "");
- }
- RegionsNotSame(region1, region2) => {
- self.note_and_explain_region("", region1, "...");
- self.note_and_explain_region("...is not the same lifetime as ",
- region2, "");
- }
- RegionsNoOverlap(region1, region2) => {
- self.note_and_explain_region("", region1, "...");
- self.note_and_explain_region("...does not overlap ",
- region2, "");
- }
- RegionsInsufficientlyPolymorphic(_, conc_region) => {
- self.note_and_explain_region("concrete lifetime that was found is ",
- conc_region, "");
- }
- RegionsOverlyPolymorphic(_, ty::ReVar(_)) => {
- // don't bother to print out the message below for
- // inference variables, it's not very illuminating.
- }
- RegionsOverlyPolymorphic(_, conc_region) => {
- self.note_and_explain_region("expected concrete lifetime is ",
- conc_region, "");
- }
- Sorts(values) => {
- let expected_str = values.expected.sort_string(self);
- let found_str = values.found.sort_string(self);
- if expected_str == found_str && expected_str == "closure" {
- self.sess.span_note(sp,
- &format!("no two closures, even if identical, have the same type"));
- self.sess.span_help(sp,
- &format!("consider boxing your closure and/or \
- using it as a trait object"));
- }
- },
- TyParamDefaultMismatch(values) => {
- let expected = values.expected;
- let found = values.found;
- self.sess.span_note(sp,
- &format!("conflicting type parameter defaults `{}` and `{}`",
- expected.ty,
- found.ty));
-
- match (expected.def_id.is_local(),
- self.map.opt_span(expected.def_id.node)) {
- (true, Some(span)) => {
- self.sess.span_note(span,
- &format!("a default was defined here..."));
- }
- (_, _) => {
- self.sess.note(
- &format!("a default is defined on `{}`",
- self.item_path_str(expected.def_id)));
- }
- }
-
- self.sess.span_note(
- expected.origin_span,
- &format!("...that was applied to an unconstrained type variable here"));
-
- match (found.def_id.is_local(),
- self.map.opt_span(found.def_id.node)) {
- (true, Some(span)) => {
- self.sess.span_note(span,
- &format!("a second default was defined here..."));
- }
- (_, _) => {
- self.sess.note(
- &format!("a second default is defined on `{}`",
- self.item_path_str(found.def_id)));
- }
- }
-
- self.sess.span_note(
- found.origin_span,
- &format!("...that also applies to the same type variable here"));
+ hir::ExprBox(..) |
+ hir::ExprAddrOf(..) |
+ hir::ExprBinary(..) |
+ hir::ExprCast(..) => {
+ false
}
- _ => {}
+
+ hir::ExprParen(ref e) => self.expr_is_lval(e),
}
}
self.def_map.borrow().get(&tr.ref_id).expect("no def-map entry for trait").def_id()
}
- pub fn try_add_builtin_trait(&self,
- trait_def_id: DefId,
- builtin_bounds: &mut EnumSet<BuiltinBound>)
- -> bool
- {
- //! Checks whether `trait_ref` refers to one of the builtin
- //! traits, like `Send`, and adds the corresponding
- //! bound to the set `builtin_bounds` if so. Returns true if `trait_ref`
- //! is a builtin trait.
-
- match self.lang_items.to_builtin_kind(trait_def_id) {
- Some(bound) => { builtin_bounds.insert(bound); true }
- None => false
- }
- }
-
pub fn item_path_str(&self, id: DefId) -> String {
self.with_path(id, |path| ast_map::path_to_string(path))
}
pub fn lookup_trait_def(&self, did: DefId) -> &'tcx TraitDef<'tcx> {
lookup_locally_or_in_crate_store(
"trait_defs", did, &self.trait_defs,
- || self.arenas.trait_defs.alloc(csearch::get_trait_def(self, did))
+ || self.alloc_trait_def(csearch::get_trait_def(self, did))
)
}
}
}
- /// Replace any late-bound regions bound in `value` with free variants attached to scope-id
- /// `scope_id`.
- pub fn liberate_late_bound_regions<T>(&self,
- all_outlive_scope: region::CodeExtent,
- value: &Binder<T>)
- -> T
- where T : TypeFoldable<'tcx>
- {
- fold::replace_late_bound_regions(
- self, value,
- |br| ty::ReFree(ty::FreeRegion{scope: all_outlive_scope, bound_region: br})).0
- }
-
- /// Flattens two binding levels into one. So `for<'a> for<'b> Foo`
- /// becomes `for<'a,'b> Foo`.
- pub fn flatten_late_bound_regions<T>(&self, bound2_value: &Binder<Binder<T>>)
- -> Binder<T>
- where T: TypeFoldable<'tcx>
- {
- let bound0_value = bound2_value.skip_binder().skip_binder();
- let value = fold::fold_regions(self, bound0_value, &mut false,
- |region, current_depth| {
- match region {
- ty::ReLateBound(debruijn, br) if debruijn.depth >= current_depth => {
- // should be true if no escaping regions from bound2_value
- assert!(debruijn.depth - current_depth <= 1);
- ty::ReLateBound(DebruijnIndex::new(current_depth), br)
- }
- _ => {
- region
- }
- }
- });
- Binder(value)
- }
-
- pub fn no_late_bound_regions<T>(&self, value: &Binder<T>) -> Option<T>
- where T : TypeFoldable<'tcx> + RegionEscape
- {
- if value.0.has_escaping_regions() {
- None
- } else {
- Some(value.0.clone())
- }
- }
-
- /// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also
- /// method lookup and a few other places where precise region relationships are not required.
- pub fn erase_late_bound_regions<T>(&self, value: &Binder<T>) -> T
- where T : TypeFoldable<'tcx>
- {
- fold::replace_late_bound_regions(self, value, |_| ty::ReStatic).0
- }
-
- /// Rewrite any late-bound regions so that they are anonymous. Region numbers are
- /// assigned starting at 1 and increasing monotonically in the order traversed
- /// by the fold operation.
- ///
- /// The chief purpose of this function is to canonicalize regions so that two
- /// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become
- /// structurally identical. For example, `for<'a, 'b> fn(&'a isize, &'b isize)` and
- /// `for<'a, 'b> fn(&'b isize, &'a isize)` will become identical after anonymization.
- pub fn anonymize_late_bound_regions<T>(&self, sig: &Binder<T>) -> Binder<T>
- where T : TypeFoldable<'tcx>,
- {
- let mut counter = 0;
- ty::Binder(fold::replace_late_bound_regions(self, sig, |_| {
- counter += 1;
- ReLateBound(ty::DebruijnIndex::new(1), BrAnon(counter))
- }).0)
- }
-
pub fn make_substs_for_receiver_types(&self,
trait_ref: &ty::TraitRef<'tcx>,
method: &ty::Method<'tcx>)
}
}
-impl DebruijnIndex {
- pub fn new(depth: u32) -> DebruijnIndex {
- assert!(depth > 0);
- DebruijnIndex { depth: depth }
- }
-
- pub fn shifted(&self, amount: u32) -> DebruijnIndex {
- DebruijnIndex { depth: self.depth + amount }
- }
-}
-
-impl<'tcx> fmt::Debug for AutoAdjustment<'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- AdjustReifyFnPointer => {
- write!(f, "AdjustReifyFnPointer")
- }
- AdjustUnsafeFnPointer => {
- write!(f, "AdjustUnsafeFnPointer")
- }
- AdjustDerefRef(ref data) => {
- write!(f, "{:?}", data)
- }
- }
- }
-}
-
-impl<'tcx> fmt::Debug for AutoDerefRef<'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "AutoDerefRef({}, unsize={:?}, {:?})",
- self.autoderefs, self.unsize, self.autoref)
- }
-}
-
-impl<'tcx> fmt::Debug for TraitTy<'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "TraitTy({:?},{:?})",
- self.principal,
- self.bounds)
- }
-}
-
-impl<'tcx> fmt::Debug for ty::Predicate<'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- Predicate::Trait(ref a) => write!(f, "{:?}", a),
- Predicate::Equate(ref pair) => write!(f, "{:?}", pair),
- Predicate::RegionOutlives(ref pair) => write!(f, "{:?}", pair),
- Predicate::TypeOutlives(ref pair) => write!(f, "{:?}", pair),
- Predicate::Projection(ref pair) => write!(f, "{:?}", pair),
- Predicate::WellFormed(ty) => write!(f, "WF({:?})", ty),
- Predicate::ObjectSafe(trait_def_id) => write!(f, "ObjectSafe({:?})", trait_def_id),
- }
- }
-}
-
-// FIXME(#20298) -- all of these traits basically walk various
-// structures to test whether types/regions are reachable with various
-// properties. It should be possible to express them in terms of one
-// common "walker" trait or something.
-
/// An "escaping region" is a bound region whose binder is not part of `t`.
///
/// So, for example, consider a type like the following, which has two binders:
fn has_regions_escaping_depth(&self, depth: u32) -> bool;
}
-impl<'tcx> RegionEscape for Ty<'tcx> {
- fn has_regions_escaping_depth(&self, depth: u32) -> bool {
- self.region_depth > depth
- }
-}
-
-impl<'tcx> RegionEscape for TraitTy<'tcx> {
- fn has_regions_escaping_depth(&self, depth: u32) -> bool {
- self.principal.has_regions_escaping_depth(depth) ||
- self.bounds.has_regions_escaping_depth(depth)
- }
-}
-
-impl<'tcx> RegionEscape for ExistentialBounds<'tcx> {
- fn has_regions_escaping_depth(&self, depth: u32) -> bool {
- self.region_bound.has_regions_escaping_depth(depth) ||
- self.projection_bounds.has_regions_escaping_depth(depth)
- }
-}
-
-impl<'tcx> RegionEscape for Substs<'tcx> {
- fn has_regions_escaping_depth(&self, depth: u32) -> bool {
- self.types.has_regions_escaping_depth(depth) ||
- self.regions.has_regions_escaping_depth(depth)
- }
-}
-
-impl<'tcx> RegionEscape for ClosureSubsts<'tcx> {
- fn has_regions_escaping_depth(&self, depth: u32) -> bool {
- self.func_substs.has_regions_escaping_depth(depth) ||
- self.upvar_tys.iter().any(|t| t.has_regions_escaping_depth(depth))
- }
-}
-
-impl<T:RegionEscape> RegionEscape for Vec<T> {
- fn has_regions_escaping_depth(&self, depth: u32) -> bool {
- self.iter().any(|t| t.has_regions_escaping_depth(depth))
- }
-}
-
-impl<'tcx> RegionEscape for FnSig<'tcx> {
- fn has_regions_escaping_depth(&self, depth: u32) -> bool {
- self.inputs.has_regions_escaping_depth(depth) ||
- self.output.has_regions_escaping_depth(depth)
- }
-}
-
-impl<'tcx,T:RegionEscape> RegionEscape for VecPerParamSpace<T> {
- fn has_regions_escaping_depth(&self, depth: u32) -> bool {
- self.iter_enumerated().any(|(space, _, t)| {
- if space == subst::FnSpace {
- t.has_regions_escaping_depth(depth+1)
- } else {
- t.has_regions_escaping_depth(depth)
- }
- })
- }
-}
-
-impl<'tcx> RegionEscape for TypeScheme<'tcx> {
- fn has_regions_escaping_depth(&self, depth: u32) -> bool {
- self.ty.has_regions_escaping_depth(depth)
- }
-}
-
-impl RegionEscape for Region {
- fn has_regions_escaping_depth(&self, depth: u32) -> bool {
- self.escapes_depth(depth)
- }
-}
-
-impl<'tcx> RegionEscape for GenericPredicates<'tcx> {
- fn has_regions_escaping_depth(&self, depth: u32) -> bool {
- self.predicates.has_regions_escaping_depth(depth)
- }
-}
-
-impl<'tcx> RegionEscape for Predicate<'tcx> {
- fn has_regions_escaping_depth(&self, depth: u32) -> bool {
- match *self {
- Predicate::Trait(ref data) => data.has_regions_escaping_depth(depth),
- Predicate::Equate(ref data) => data.has_regions_escaping_depth(depth),
- Predicate::RegionOutlives(ref data) => data.has_regions_escaping_depth(depth),
- Predicate::TypeOutlives(ref data) => data.has_regions_escaping_depth(depth),
- Predicate::Projection(ref data) => data.has_regions_escaping_depth(depth),
- Predicate::WellFormed(ty) => ty.has_regions_escaping_depth(depth),
- Predicate::ObjectSafe(_trait_def_id) => false,
- }
- }
-}
-
-impl<'tcx,P:RegionEscape> RegionEscape for traits::Obligation<'tcx,P> {
- fn has_regions_escaping_depth(&self, depth: u32) -> bool {
- self.predicate.has_regions_escaping_depth(depth)
- }
-}
-
-impl<'tcx> RegionEscape for TraitRef<'tcx> {
- fn has_regions_escaping_depth(&self, depth: u32) -> bool {
- self.substs.types.iter().any(|t| t.has_regions_escaping_depth(depth)) ||
- self.substs.regions.has_regions_escaping_depth(depth)
- }
-}
-
-impl<'tcx> RegionEscape for subst::RegionSubsts {
- fn has_regions_escaping_depth(&self, depth: u32) -> bool {
- match *self {
- subst::ErasedRegions => false,
- subst::NonerasedRegions(ref r) => {
- r.iter().any(|t| t.has_regions_escaping_depth(depth))
- }
- }
- }
-}
-
-impl<'tcx,T:RegionEscape> RegionEscape for Binder<T> {
- fn has_regions_escaping_depth(&self, depth: u32) -> bool {
- self.0.has_regions_escaping_depth(depth + 1)
- }
-}
-
-impl<'tcx> RegionEscape for FnOutput<'tcx> {
- fn has_regions_escaping_depth(&self, depth: u32) -> bool {
- match *self {
- FnConverging(t) => t.has_regions_escaping_depth(depth),
- FnDiverging => false
- }
- }
-}
-
-impl<'tcx> RegionEscape for EquatePredicate<'tcx> {
- fn has_regions_escaping_depth(&self, depth: u32) -> bool {
- self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth)
- }
-}
-
-impl<'tcx> RegionEscape for TraitPredicate<'tcx> {
- fn has_regions_escaping_depth(&self, depth: u32) -> bool {
- self.trait_ref.has_regions_escaping_depth(depth)
- }
-}
-
-impl<T:RegionEscape,U:RegionEscape> RegionEscape for OutlivesPredicate<T,U> {
- fn has_regions_escaping_depth(&self, depth: u32) -> bool {
- self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth)
- }
-}
-
-impl<'tcx> RegionEscape for ProjectionPredicate<'tcx> {
- fn has_regions_escaping_depth(&self, depth: u32) -> bool {
- self.projection_ty.has_regions_escaping_depth(depth) ||
- self.ty.has_regions_escaping_depth(depth)
- }
-}
-
-impl<'tcx> RegionEscape for ProjectionTy<'tcx> {
- fn has_regions_escaping_depth(&self, depth: u32) -> bool {
- self.trait_ref.has_regions_escaping_depth(depth)
- }
-}
-
pub trait HasTypeFlags {
fn has_type_flags(&self, flags: TypeFlags) -> bool;
fn has_projection_types(&self) -> bool {
!self.has_type_flags(TypeFlags::HAS_LOCAL_NAMES)
}
}
-
-impl<'tcx,T:HasTypeFlags> HasTypeFlags for Vec<T> {
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- self[..].has_type_flags(flags)
- }
-}
-
-impl<'tcx,T:HasTypeFlags> HasTypeFlags for [T] {
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- self.iter().any(|p| p.has_type_flags(flags))
- }
-}
-
-impl<'tcx,T:HasTypeFlags> HasTypeFlags for VecPerParamSpace<T> {
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- self.iter().any(|p| p.has_type_flags(flags))
- }
-}
-
-impl HasTypeFlags for abi::Abi {
- fn has_type_flags(&self, _flags: TypeFlags) -> bool {
- false
- }
-}
-
-impl HasTypeFlags for hir::Unsafety {
- fn has_type_flags(&self, _flags: TypeFlags) -> bool {
- false
- }
-}
-
-impl HasTypeFlags for BuiltinBounds {
- fn has_type_flags(&self, _flags: TypeFlags) -> bool {
- false
- }
-}
-
-impl<'tcx> HasTypeFlags for ClosureTy<'tcx> {
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- self.sig.has_type_flags(flags)
- }
-}
-
-impl<'tcx> HasTypeFlags for ClosureUpvar<'tcx> {
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- self.ty.has_type_flags(flags)
- }
-}
-
-impl<'tcx> HasTypeFlags for ExistentialBounds<'tcx> {
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- self.projection_bounds.has_type_flags(flags)
- }
-}
-
-impl<'tcx> HasTypeFlags for ty::InstantiatedPredicates<'tcx> {
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- self.predicates.has_type_flags(flags)
- }
-}
-
-impl<'tcx> HasTypeFlags for Predicate<'tcx> {
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- match *self {
- Predicate::Trait(ref data) => data.has_type_flags(flags),
- Predicate::Equate(ref data) => data.has_type_flags(flags),
- Predicate::RegionOutlives(ref data) => data.has_type_flags(flags),
- Predicate::TypeOutlives(ref data) => data.has_type_flags(flags),
- Predicate::Projection(ref data) => data.has_type_flags(flags),
- Predicate::WellFormed(data) => data.has_type_flags(flags),
- Predicate::ObjectSafe(_trait_def_id) => false,
- }
- }
-}
-
-impl<'tcx> HasTypeFlags for TraitPredicate<'tcx> {
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- self.trait_ref.has_type_flags(flags)
- }
-}
-
-impl<'tcx> HasTypeFlags for EquatePredicate<'tcx> {
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- self.0.has_type_flags(flags) || self.1.has_type_flags(flags)
- }
-}
-
-impl HasTypeFlags for Region {
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- if flags.intersects(TypeFlags::HAS_LOCAL_NAMES) {
- // does this represent a region that cannot be named in a global
- // way? used in fulfillment caching.
- match *self {
- ty::ReStatic | ty::ReEmpty => {}
- _ => return true
- }
- }
- if flags.intersects(TypeFlags::HAS_RE_INFER) {
- match *self {
- ty::ReVar(_) | ty::ReSkolemized(..) => { return true }
- _ => {}
- }
- }
- false
- }
-}
-
-impl<T:HasTypeFlags,U:HasTypeFlags> HasTypeFlags for OutlivesPredicate<T,U> {
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- self.0.has_type_flags(flags) || self.1.has_type_flags(flags)
- }
-}
-
-impl<'tcx> HasTypeFlags for ProjectionPredicate<'tcx> {
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- self.projection_ty.has_type_flags(flags) || self.ty.has_type_flags(flags)
- }
-}
-
-impl<'tcx> HasTypeFlags for ProjectionTy<'tcx> {
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- self.trait_ref.has_type_flags(flags)
- }
-}
-
-impl<'tcx> HasTypeFlags for Ty<'tcx> {
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- self.flags.get().intersects(flags)
- }
-}
-
-impl<'tcx> HasTypeFlags for TypeAndMut<'tcx> {
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- self.ty.has_type_flags(flags)
- }
-}
-
-impl<'tcx> HasTypeFlags for TraitRef<'tcx> {
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- self.substs.has_type_flags(flags)
- }
-}
-
-impl<'tcx> HasTypeFlags for subst::Substs<'tcx> {
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- self.types.has_type_flags(flags) || match self.regions {
- subst::ErasedRegions => false,
- subst::NonerasedRegions(ref r) => r.has_type_flags(flags)
- }
- }
-}
-
-impl<'tcx,T> HasTypeFlags for Option<T>
- where T : HasTypeFlags
-{
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- self.iter().any(|t| t.has_type_flags(flags))
- }
-}
-
-impl<'tcx,T> HasTypeFlags for Rc<T>
- where T : HasTypeFlags
-{
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- (**self).has_type_flags(flags)
- }
-}
-
-impl<'tcx,T> HasTypeFlags for Box<T>
- where T : HasTypeFlags
-{
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- (**self).has_type_flags(flags)
- }
-}
-
-impl<T> HasTypeFlags for Binder<T>
- where T : HasTypeFlags
-{
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- self.0.has_type_flags(flags)
- }
-}
-
-impl<'tcx> HasTypeFlags for FnOutput<'tcx> {
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- match *self {
- FnConverging(t) => t.has_type_flags(flags),
- FnDiverging => false,
- }
- }
-}
-
-impl<'tcx> HasTypeFlags for FnSig<'tcx> {
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- self.inputs.iter().any(|t| t.has_type_flags(flags)) ||
- self.output.has_type_flags(flags)
- }
-}
-
-impl<'tcx> HasTypeFlags for BareFnTy<'tcx> {
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- self.sig.has_type_flags(flags)
- }
-}
-
-impl<'tcx> HasTypeFlags for ClosureSubsts<'tcx> {
- fn has_type_flags(&self, flags: TypeFlags) -> bool {
- self.func_substs.has_type_flags(flags) ||
- self.upvar_tys.iter().any(|t| t.has_type_flags(flags))
- }
-}
-
-impl<'tcx> fmt::Debug for ClosureTy<'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "ClosureTy({},{:?},{})",
- self.unsafety,
- self.sig,
- self.abi)
- }
-}
-
-impl<'tcx> fmt::Debug for ClosureUpvar<'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "ClosureUpvar({:?},{:?})",
- self.def,
- self.ty)
- }
-}
-
-impl<'a, 'tcx> fmt::Debug for ParameterEnvironment<'a, 'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "ParameterEnvironment(\
- free_substs={:?}, \
- implicit_region_bound={:?}, \
- caller_bounds={:?})",
- self.free_substs,
- self.implicit_region_bound,
- self.caller_bounds)
- }
-}
-
-impl<'tcx> fmt::Debug for ObjectLifetimeDefault {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- ObjectLifetimeDefault::Ambiguous => write!(f, "Ambiguous"),
- ObjectLifetimeDefault::BaseDefault => write!(f, "BaseDefault"),
- ObjectLifetimeDefault::Specific(ref r) => write!(f, "{:?}", r),
- }
- }
-}
use middle::def_id::DefId;
use middle::subst::{ErasedRegions, NonerasedRegions, ParamSpace, Substs};
-use middle::ty::{self, HasTypeFlags, Ty, TypeError};
+use middle::ty::{self, HasTypeFlags, Ty};
+use middle::ty::error::{ExpectedFound, TypeError};
use middle::ty::fold::TypeFoldable;
use std::rc::Rc;
use syntax::abi;
use rustc_front::hir as ast;
-pub type RelateResult<'tcx, T> = Result<T, ty::TypeError<'tcx>>;
+pub type RelateResult<'tcx, T> = Result<T, TypeError<'tcx>>;
#[derive(Clone, Debug)]
pub enum Cause {
pub fn expected_found<'a,'tcx:'a,R,T>(relation: &mut R,
a: &T,
b: &T)
- -> ty::ExpectedFound<T>
+ -> ExpectedFound<T>
where R: TypeRelation<'a,'tcx>, T: Clone
{
expected_found_bool(relation.a_is_expected(), a, b)
pub fn expected_found_bool<T>(a_is_expected: bool,
a: &T,
b: &T)
- -> ty::ExpectedFound<T>
+ -> ExpectedFound<T>
where T: Clone
{
let a = a.clone();
let b = b.clone();
if a_is_expected {
- ty::ExpectedFound {expected: a, found: b}
+ ExpectedFound {expected: a, found: b}
} else {
- ty::ExpectedFound {expected: b, found: a}
+ ExpectedFound {expected: b, found: a}
}
}
--- /dev/null
+// Copyright 2012-2015 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.
+
+use middle::subst::{self, VecPerParamSpace};
+use middle::traits;
+use middle::ty::{self, TraitRef, Ty, TypeAndMut};
+use middle::ty::{HasTypeFlags, Lift, TypeFlags, RegionEscape};
+use middle::ty::fold::{TypeFoldable, TypeFolder};
+
+use std::rc::Rc;
+use syntax::abi;
+use syntax::owned_slice::OwnedSlice;
+
+use rustc_front::hir;
+
+// FIXME(#20298) -- all of these traits basically walk various
+// structures to test whether types/regions are reachable with various
+// properties. It should be possible to express them in terms of one
+// common "walker" trait or something.
+
+impl<'tcx> RegionEscape for Ty<'tcx> {
+ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+ self.region_depth > depth
+ }
+}
+
+impl<'tcx> RegionEscape for ty::TraitTy<'tcx> {
+ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+ self.principal.has_regions_escaping_depth(depth) ||
+ self.bounds.has_regions_escaping_depth(depth)
+ }
+}
+
+impl<'tcx> RegionEscape for ty::ExistentialBounds<'tcx> {
+ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+ self.region_bound.has_regions_escaping_depth(depth) ||
+ self.projection_bounds.has_regions_escaping_depth(depth)
+ }
+}
+
+impl<'tcx> RegionEscape for subst::Substs<'tcx> {
+ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+ self.types.has_regions_escaping_depth(depth) ||
+ self.regions.has_regions_escaping_depth(depth)
+ }
+}
+
+impl<'tcx> RegionEscape for ty::ClosureSubsts<'tcx> {
+ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+ self.func_substs.has_regions_escaping_depth(depth) ||
+ self.upvar_tys.iter().any(|t| t.has_regions_escaping_depth(depth))
+ }
+}
+
+impl<T:RegionEscape> RegionEscape for Vec<T> {
+ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+ self.iter().any(|t| t.has_regions_escaping_depth(depth))
+ }
+}
+
+impl<'tcx> RegionEscape for ty::FnSig<'tcx> {
+ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+ self.inputs.has_regions_escaping_depth(depth) ||
+ self.output.has_regions_escaping_depth(depth)
+ }
+}
+
+impl<'tcx,T:RegionEscape> RegionEscape for VecPerParamSpace<T> {
+ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+ self.iter_enumerated().any(|(space, _, t)| {
+ if space == subst::FnSpace {
+ t.has_regions_escaping_depth(depth+1)
+ } else {
+ t.has_regions_escaping_depth(depth)
+ }
+ })
+ }
+}
+
+impl<'tcx> RegionEscape for ty::TypeScheme<'tcx> {
+ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+ self.ty.has_regions_escaping_depth(depth)
+ }
+}
+
+impl RegionEscape for ty::Region {
+ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+ self.escapes_depth(depth)
+ }
+}
+
+impl<'tcx> RegionEscape for ty::GenericPredicates<'tcx> {
+ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+ self.predicates.has_regions_escaping_depth(depth)
+ }
+}
+
+impl<'tcx> RegionEscape for ty::Predicate<'tcx> {
+ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+ match *self {
+ ty::Predicate::Trait(ref data) => data.has_regions_escaping_depth(depth),
+ ty::Predicate::Equate(ref data) => data.has_regions_escaping_depth(depth),
+ ty::Predicate::RegionOutlives(ref data) => data.has_regions_escaping_depth(depth),
+ ty::Predicate::TypeOutlives(ref data) => data.has_regions_escaping_depth(depth),
+ ty::Predicate::Projection(ref data) => data.has_regions_escaping_depth(depth),
+ ty::Predicate::WellFormed(ty) => ty.has_regions_escaping_depth(depth),
+ ty::Predicate::ObjectSafe(_trait_def_id) => false,
+ }
+ }
+}
+
+impl<'tcx,P:RegionEscape> RegionEscape for traits::Obligation<'tcx,P> {
+ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+ self.predicate.has_regions_escaping_depth(depth)
+ }
+}
+
+impl<'tcx> RegionEscape for TraitRef<'tcx> {
+ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+ self.substs.types.iter().any(|t| t.has_regions_escaping_depth(depth)) ||
+ self.substs.regions.has_regions_escaping_depth(depth)
+ }
+}
+
+impl<'tcx> RegionEscape for subst::RegionSubsts {
+ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+ match *self {
+ subst::ErasedRegions => false,
+ subst::NonerasedRegions(ref r) => {
+ r.iter().any(|t| t.has_regions_escaping_depth(depth))
+ }
+ }
+ }
+}
+
+impl<'tcx,T:RegionEscape> RegionEscape for ty::Binder<T> {
+ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+ self.0.has_regions_escaping_depth(depth + 1)
+ }
+}
+
+impl<'tcx> RegionEscape for ty::FnOutput<'tcx> {
+ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+ match *self {
+ ty::FnConverging(t) => t.has_regions_escaping_depth(depth),
+ ty::FnDiverging => false
+ }
+ }
+}
+
+impl<'tcx> RegionEscape for ty::EquatePredicate<'tcx> {
+ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+ self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth)
+ }
+}
+
+impl<'tcx> RegionEscape for ty::TraitPredicate<'tcx> {
+ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+ self.trait_ref.has_regions_escaping_depth(depth)
+ }
+}
+
+impl<T:RegionEscape,U:RegionEscape> RegionEscape for ty::OutlivesPredicate<T,U> {
+ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+ self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth)
+ }
+}
+
+impl<'tcx> RegionEscape for ty::ProjectionPredicate<'tcx> {
+ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+ self.projection_ty.has_regions_escaping_depth(depth) ||
+ self.ty.has_regions_escaping_depth(depth)
+ }
+}
+
+impl<'tcx> RegionEscape for ty::ProjectionTy<'tcx> {
+ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+ self.trait_ref.has_regions_escaping_depth(depth)
+ }
+}
+impl<'tcx,T:HasTypeFlags> HasTypeFlags for Vec<T> {
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ self[..].has_type_flags(flags)
+ }
+}
+
+impl<'tcx,T:HasTypeFlags> HasTypeFlags for [T] {
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ self.iter().any(|p| p.has_type_flags(flags))
+ }
+}
+
+impl<'tcx,T:HasTypeFlags> HasTypeFlags for VecPerParamSpace<T> {
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ self.iter().any(|p| p.has_type_flags(flags))
+ }
+}
+
+impl HasTypeFlags for abi::Abi {
+ fn has_type_flags(&self, _flags: TypeFlags) -> bool {
+ false
+ }
+}
+
+impl HasTypeFlags for hir::Unsafety {
+ fn has_type_flags(&self, _flags: TypeFlags) -> bool {
+ false
+ }
+}
+
+impl HasTypeFlags for ty::BuiltinBounds {
+ fn has_type_flags(&self, _flags: TypeFlags) -> bool {
+ false
+ }
+}
+
+impl<'tcx> HasTypeFlags for ty::ClosureTy<'tcx> {
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ self.sig.has_type_flags(flags)
+ }
+}
+
+impl<'tcx> HasTypeFlags for ty::ClosureUpvar<'tcx> {
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ self.ty.has_type_flags(flags)
+ }
+}
+
+impl<'tcx> HasTypeFlags for ty::ExistentialBounds<'tcx> {
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ self.projection_bounds.has_type_flags(flags)
+ }
+}
+
+impl<'tcx> HasTypeFlags for ty::InstantiatedPredicates<'tcx> {
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ self.predicates.has_type_flags(flags)
+ }
+}
+
+impl<'tcx> HasTypeFlags for ty::Predicate<'tcx> {
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ match *self {
+ ty::Predicate::Trait(ref data) => data.has_type_flags(flags),
+ ty::Predicate::Equate(ref data) => data.has_type_flags(flags),
+ ty::Predicate::RegionOutlives(ref data) => data.has_type_flags(flags),
+ ty::Predicate::TypeOutlives(ref data) => data.has_type_flags(flags),
+ ty::Predicate::Projection(ref data) => data.has_type_flags(flags),
+ ty::Predicate::WellFormed(data) => data.has_type_flags(flags),
+ ty::Predicate::ObjectSafe(_trait_def_id) => false,
+ }
+ }
+}
+
+impl<'tcx> HasTypeFlags for ty::TraitPredicate<'tcx> {
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ self.trait_ref.has_type_flags(flags)
+ }
+}
+
+impl<'tcx> HasTypeFlags for ty::EquatePredicate<'tcx> {
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ self.0.has_type_flags(flags) || self.1.has_type_flags(flags)
+ }
+}
+
+impl HasTypeFlags for ty::Region {
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ if flags.intersects(TypeFlags::HAS_LOCAL_NAMES) {
+ // does this represent a region that cannot be named in a global
+ // way? used in fulfillment caching.
+ match *self {
+ ty::ReStatic | ty::ReEmpty => {}
+ _ => return true
+ }
+ }
+ if flags.intersects(TypeFlags::HAS_RE_INFER) {
+ match *self {
+ ty::ReVar(_) | ty::ReSkolemized(..) => { return true }
+ _ => {}
+ }
+ }
+ false
+ }
+}
+
+impl<T:HasTypeFlags,U:HasTypeFlags> HasTypeFlags for ty::OutlivesPredicate<T,U> {
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ self.0.has_type_flags(flags) || self.1.has_type_flags(flags)
+ }
+}
+
+impl<'tcx> HasTypeFlags for ty::ProjectionPredicate<'tcx> {
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ self.projection_ty.has_type_flags(flags) || self.ty.has_type_flags(flags)
+ }
+}
+
+impl<'tcx> HasTypeFlags for ty::ProjectionTy<'tcx> {
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ self.trait_ref.has_type_flags(flags)
+ }
+}
+
+impl<'tcx> HasTypeFlags for Ty<'tcx> {
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ self.flags.get().intersects(flags)
+ }
+}
+
+impl<'tcx> HasTypeFlags for TypeAndMut<'tcx> {
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ self.ty.has_type_flags(flags)
+ }
+}
+
+impl<'tcx> HasTypeFlags for TraitRef<'tcx> {
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ self.substs.has_type_flags(flags)
+ }
+}
+
+impl<'tcx> HasTypeFlags for subst::Substs<'tcx> {
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ self.types.has_type_flags(flags) || match self.regions {
+ subst::ErasedRegions => false,
+ subst::NonerasedRegions(ref r) => r.has_type_flags(flags)
+ }
+ }
+}
+
+impl<'tcx,T> HasTypeFlags for Option<T>
+ where T : HasTypeFlags
+{
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ self.iter().any(|t| t.has_type_flags(flags))
+ }
+}
+
+impl<'tcx,T> HasTypeFlags for Rc<T>
+ where T : HasTypeFlags
+{
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ (**self).has_type_flags(flags)
+ }
+}
+
+impl<'tcx,T> HasTypeFlags for Box<T>
+ where T : HasTypeFlags
+{
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ (**self).has_type_flags(flags)
+ }
+}
+
+impl<T> HasTypeFlags for ty::Binder<T>
+ where T : HasTypeFlags
+{
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ self.0.has_type_flags(flags)
+ }
+}
+
+impl<'tcx> HasTypeFlags for ty::FnOutput<'tcx> {
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ match *self {
+ ty::FnConverging(t) => t.has_type_flags(flags),
+ ty::FnDiverging => false,
+ }
+ }
+}
+
+impl<'tcx> HasTypeFlags for ty::FnSig<'tcx> {
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ self.inputs.iter().any(|t| t.has_type_flags(flags)) ||
+ self.output.has_type_flags(flags)
+ }
+}
+
+impl<'tcx> HasTypeFlags for ty::BareFnTy<'tcx> {
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ self.sig.has_type_flags(flags)
+ }
+}
+
+impl<'tcx> HasTypeFlags for ty::ClosureSubsts<'tcx> {
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ self.func_substs.has_type_flags(flags) ||
+ self.upvar_tys.iter().any(|t| t.has_type_flags(flags))
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Lift implementations
+
+impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>> Lift<'tcx> for (A, B) {
+ type Lifted = (A::Lifted, B::Lifted);
+ fn lift_to_tcx(&self, tcx: &ty::ctxt<'tcx>) -> Option<Self::Lifted> {
+ tcx.lift(&self.0).and_then(|a| tcx.lift(&self.1).map(|b| (a, b)))
+ }
+}
+
+impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for [T] {
+ type Lifted = Vec<T::Lifted>;
+ fn lift_to_tcx(&self, tcx: &ty::ctxt<'tcx>) -> Option<Self::Lifted> {
+ let mut result = Vec::with_capacity(self.len());
+ for x in self {
+ if let Some(value) = tcx.lift(x) {
+ result.push(value);
+ } else {
+ return None;
+ }
+ }
+ Some(result)
+ }
+}
+
+impl<'tcx> Lift<'tcx> for ty::Region {
+ type Lifted = Self;
+ fn lift_to_tcx(&self, _: &ty::ctxt<'tcx>) -> Option<ty::Region> {
+ Some(*self)
+ }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for TraitRef<'a> {
+ type Lifted = TraitRef<'tcx>;
+ fn lift_to_tcx(&self, tcx: &ty::ctxt<'tcx>) -> Option<TraitRef<'tcx>> {
+ tcx.lift(&self.substs).map(|substs| TraitRef {
+ def_id: self.def_id,
+ substs: substs
+ })
+ }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> {
+ type Lifted = ty::TraitPredicate<'tcx>;
+ fn lift_to_tcx(&self, tcx: &ty::ctxt<'tcx>) -> Option<ty::TraitPredicate<'tcx>> {
+ tcx.lift(&self.trait_ref).map(|trait_ref| ty::TraitPredicate {
+ trait_ref: trait_ref
+ })
+ }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for ty::EquatePredicate<'a> {
+ type Lifted = ty::EquatePredicate<'tcx>;
+ fn lift_to_tcx(&self, tcx: &ty::ctxt<'tcx>) -> Option<ty::EquatePredicate<'tcx>> {
+ tcx.lift(&(self.0, self.1)).map(|(a, b)| ty::EquatePredicate(a, b))
+ }
+}
+
+impl<'tcx, A: Copy+Lift<'tcx>, B: Copy+Lift<'tcx>> Lift<'tcx> for ty::OutlivesPredicate<A, B> {
+ type Lifted = ty::OutlivesPredicate<A::Lifted, B::Lifted>;
+ fn lift_to_tcx(&self, tcx: &ty::ctxt<'tcx>) -> Option<Self::Lifted> {
+ tcx.lift(&(self.0, self.1)).map(|(a, b)| ty::OutlivesPredicate(a, b))
+ }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionPredicate<'a> {
+ type Lifted = ty::ProjectionPredicate<'tcx>;
+ fn lift_to_tcx(&self, tcx: &ty::ctxt<'tcx>) -> Option<ty::ProjectionPredicate<'tcx>> {
+ tcx.lift(&(self.projection_ty.trait_ref, self.ty)).map(|(trait_ref, ty)| {
+ ty::ProjectionPredicate {
+ projection_ty: ty::ProjectionTy {
+ trait_ref: trait_ref,
+ item_name: self.projection_ty.item_name
+ },
+ ty: ty
+ }
+ })
+ }
+}
+
+impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<T> {
+ type Lifted = ty::Binder<T::Lifted>;
+ fn lift_to_tcx(&self, tcx: &ty::ctxt<'tcx>) -> Option<Self::Lifted> {
+ tcx.lift(&self.0).map(|x| ty::Binder(x))
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// TypeFoldable implementations.
+//
+// Ideally, each type should invoke `folder.fold_foo(self)` and
+// nothing else. In some cases, though, we haven't gotten around to
+// adding methods on the `folder` yet, and thus the folding is
+// hard-coded here. This is less-flexible, because folders cannot
+// override the behavior, but there are a lot of random types and one
+// can easily refactor the folding into the TypeFolder trait as
+// needed.
+
+macro_rules! CopyImpls {
+ ($($ty:ty),+) => {
+ $(
+ impl<'tcx> TypeFoldable<'tcx> for $ty {
+ fn fold_with<F:TypeFolder<'tcx>>(&self, _: &mut F) -> $ty {
+ *self
+ }
+ }
+ )+
+ }
+}
+
+CopyImpls! { (), hir::Unsafety, abi::Abi }
+
+impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
+ fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> (T, U) {
+ (self.0.fold_with(folder), self.1.fold_with(folder))
+ }
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Option<T> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Option<T> {
+ self.as_ref().map(|t| t.fold_with(folder))
+ }
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Rc<T> {
+ Rc::new((**self).fold_with(folder))
+ }
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Box<T> {
+ let content: T = (**self).fold_with(folder);
+ box content
+ }
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Vec<T> {
+ self.iter().map(|t| t.fold_with(folder)).collect()
+ }
+}
+
+impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Binder<T> {
+ folder.fold_binder(self)
+ }
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for OwnedSlice<T> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> OwnedSlice<T> {
+ self.iter().map(|t| t.fold_with(folder)).collect()
+ }
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for VecPerParamSpace<T> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> VecPerParamSpace<T> {
+
+ // Things in the Fn space take place under an additional level
+ // of region binding relative to the other spaces. This is
+ // because those entries are attached to a method, and methods
+ // always introduce a level of region binding.
+
+ let result = self.map_enumerated(|(space, index, elem)| {
+ if space == subst::FnSpace && index == 0 {
+ // enter new level when/if we reach the first thing in fn space
+ folder.enter_region_binder();
+ }
+ elem.fold_with(folder)
+ });
+ if result.len(subst::FnSpace) > 0 {
+ // if there was anything in fn space, exit the region binding level
+ folder.exit_region_binder();
+ }
+ result
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Ty<'tcx> {
+ folder.fold_ty(*self)
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::BareFnTy<'tcx> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::BareFnTy<'tcx> {
+ folder.fold_bare_fn_ty(self)
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::ClosureTy<'tcx> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ClosureTy<'tcx> {
+ folder.fold_closure_ty(self)
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TypeAndMut<'tcx> {
+ folder.fold_mt(self)
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::FnOutput<'tcx> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::FnOutput<'tcx> {
+ folder.fold_output(self)
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::FnSig<'tcx> {
+ folder.fold_fn_sig(self)
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TraitRef<'tcx> {
+ folder.fold_trait_ref(self)
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::Region {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Region {
+ folder.fold_region(*self)
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for subst::Substs<'tcx> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> subst::Substs<'tcx> {
+ folder.fold_substs(self)
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ClosureSubsts<'tcx> {
+ let func_substs = self.func_substs.fold_with(folder);
+ ty::ClosureSubsts {
+ func_substs: folder.tcx().mk_substs(func_substs),
+ upvar_tys: self.upvar_tys.fold_with(folder),
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::ItemSubsts<'tcx> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ItemSubsts<'tcx> {
+ ty::ItemSubsts {
+ substs: self.substs.fold_with(folder),
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::AutoRef<'tcx> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::AutoRef<'tcx> {
+ folder.fold_autoref(self)
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::BuiltinBounds {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, _folder: &mut F) -> ty::BuiltinBounds {
+ *self
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialBounds<'tcx> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ExistentialBounds<'tcx> {
+ folder.fold_existential_bounds(self)
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TypeParameterDef<'tcx> {
+ ty::TypeParameterDef {
+ name: self.name,
+ def_id: self.def_id,
+ space: self.space,
+ index: self.index,
+ default: self.default.fold_with(folder),
+ default_def_id: self.default_def_id,
+ object_lifetime_default: self.object_lifetime_default.fold_with(folder),
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ObjectLifetimeDefault {
+ match *self {
+ ty::ObjectLifetimeDefault::Ambiguous =>
+ ty::ObjectLifetimeDefault::Ambiguous,
+
+ ty::ObjectLifetimeDefault::BaseDefault =>
+ ty::ObjectLifetimeDefault::BaseDefault,
+
+ ty::ObjectLifetimeDefault::Specific(r) =>
+ ty::ObjectLifetimeDefault::Specific(r.fold_with(folder)),
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::RegionParameterDef {
+ ty::RegionParameterDef {
+ name: self.name,
+ def_id: self.def_id,
+ space: self.space,
+ index: self.index,
+ bounds: self.bounds.fold_with(folder)
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::Generics<'tcx> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Generics<'tcx> {
+ ty::Generics {
+ types: self.types.fold_with(folder),
+ regions: self.regions.fold_with(folder),
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::GenericPredicates<'tcx> {
+ ty::GenericPredicates {
+ predicates: self.predicates.fold_with(folder),
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Predicate<'tcx> {
+ match *self {
+ ty::Predicate::Trait(ref a) =>
+ ty::Predicate::Trait(a.fold_with(folder)),
+ ty::Predicate::Equate(ref binder) =>
+ ty::Predicate::Equate(binder.fold_with(folder)),
+ ty::Predicate::RegionOutlives(ref binder) =>
+ ty::Predicate::RegionOutlives(binder.fold_with(folder)),
+ ty::Predicate::TypeOutlives(ref binder) =>
+ ty::Predicate::TypeOutlives(binder.fold_with(folder)),
+ ty::Predicate::Projection(ref binder) =>
+ ty::Predicate::Projection(binder.fold_with(folder)),
+ ty::Predicate::WellFormed(data) =>
+ ty::Predicate::WellFormed(data.fold_with(folder)),
+ ty::Predicate::ObjectSafe(trait_def_id) =>
+ ty::Predicate::ObjectSafe(trait_def_id),
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionPredicate<'tcx> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ProjectionPredicate<'tcx> {
+ ty::ProjectionPredicate {
+ projection_ty: self.projection_ty.fold_with(folder),
+ ty: self.ty.fold_with(folder),
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionTy<'tcx> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ProjectionTy<'tcx> {
+ ty::ProjectionTy {
+ trait_ref: self.trait_ref.fold_with(folder),
+ item_name: self.item_name,
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::InstantiatedPredicates<'tcx> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::InstantiatedPredicates<'tcx> {
+ ty::InstantiatedPredicates {
+ predicates: self.predicates.fold_with(folder),
+ }
+ }
+}
+
+impl<'tcx,O> TypeFoldable<'tcx> for traits::Obligation<'tcx,O>
+ where O : TypeFoldable<'tcx>
+{
+ fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Obligation<'tcx, O> {
+ traits::Obligation {
+ cause: self.cause.clone(),
+ recursion_depth: self.recursion_depth,
+ predicate: self.predicate.fold_with(folder),
+ }
+ }
+}
+
+impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableImplData<'tcx, N> {
+ fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableImplData<'tcx, N> {
+ traits::VtableImplData {
+ impl_def_id: self.impl_def_id,
+ substs: self.substs.fold_with(folder),
+ nested: self.nested.fold_with(folder),
+ }
+ }
+}
+
+impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableClosureData<'tcx, N> {
+ fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableClosureData<'tcx, N> {
+ traits::VtableClosureData {
+ closure_def_id: self.closure_def_id,
+ substs: self.substs.fold_with(folder),
+ nested: self.nested.fold_with(folder),
+ }
+ }
+}
+
+impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableDefaultImplData<N> {
+ fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableDefaultImplData<N> {
+ traits::VtableDefaultImplData {
+ trait_def_id: self.trait_def_id,
+ nested: self.nested.fold_with(folder),
+ }
+ }
+}
+
+impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableBuiltinData<N> {
+ fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableBuiltinData<N> {
+ traits::VtableBuiltinData {
+ nested: self.nested.fold_with(folder),
+ }
+ }
+}
+
+impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> {
+ fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Vtable<'tcx, N> {
+ match *self {
+ traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)),
+ traits::VtableDefaultImpl(ref t) => traits::VtableDefaultImpl(t.fold_with(folder)),
+ traits::VtableClosure(ref d) => {
+ traits::VtableClosure(d.fold_with(folder))
+ }
+ traits::VtableFnPointer(ref d) => {
+ traits::VtableFnPointer(d.fold_with(folder))
+ }
+ traits::VtableParam(ref n) => traits::VtableParam(n.fold_with(folder)),
+ traits::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)),
+ traits::VtableObject(ref d) => traits::VtableObject(d.fold_with(folder)),
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx> {
+ fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableObjectData<'tcx> {
+ traits::VtableObjectData {
+ upcast_trait_ref: self.upcast_trait_ref.fold_with(folder),
+ vtable_base: self.vtable_base
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> {
+ fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::EquatePredicate<'tcx> {
+ ty::EquatePredicate(self.0.fold_with(folder),
+ self.1.fold_with(folder))
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> {
+ fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TraitPredicate<'tcx> {
+ ty::TraitPredicate {
+ trait_ref: self.trait_ref.fold_with(folder)
+ }
+ }
+}
+
+impl<'tcx,T,U> TypeFoldable<'tcx> for ty::OutlivesPredicate<T,U>
+ where T : TypeFoldable<'tcx>,
+ U : TypeFoldable<'tcx>,
+{
+ fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::OutlivesPredicate<T,U> {
+ ty::OutlivesPredicate(self.0.fold_with(folder),
+ self.1.fold_with(folder))
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::ClosureUpvar<'tcx> {
+ fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ClosureUpvar<'tcx> {
+ ty::ClosureUpvar {
+ def: self.def,
+ span: self.span,
+ ty: self.ty.fold_with(folder),
+ }
+ }
+}
+
+impl<'a, 'tcx> TypeFoldable<'tcx> for ty::ParameterEnvironment<'a, 'tcx> where 'tcx: 'a {
+ fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ParameterEnvironment<'a, 'tcx> {
+ ty::ParameterEnvironment {
+ tcx: self.tcx,
+ free_substs: self.free_substs.fold_with(folder),
+ implicit_region_bound: self.implicit_region_bound.fold_with(folder),
+ caller_bounds: self.caller_bounds.fold_with(folder),
+ selection_cache: traits::SelectionCache::new(),
+ free_id: self.free_id,
+ }
+ }
+}
--- /dev/null
+// Copyright 2012-2015 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.
+
+//! This module contains TypeVariants and its major components
+
+use middle::def_id::DefId;
+use middle::region;
+use middle::subst::{self, Substs};
+use middle::traits;
+use middle::ty::{self, AdtDef, TypeFlags, Ty, TyS};
+use middle::ty::{RegionEscape, ToPredicate};
+use util::common::ErrorReported;
+
+use collections::enum_set::{self, EnumSet, CLike};
+use std::fmt;
+use std::ops;
+use std::mem;
+use syntax::abi;
+use syntax::ast::{Name, NodeId};
+
+use rustc_front::hir;
+
+use self::FnOutput::*;
+use self::InferTy::*;
+use self::TypeVariants::*;
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+pub struct TypeAndMut<'tcx> {
+ pub ty: Ty<'tcx>,
+ pub mutbl: hir::Mutability,
+}
+
+#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash,
+ RustcEncodable, RustcDecodable, Copy)]
+/// A "free" region `fr` can be interpreted as "some region
+/// at least as big as the scope `fr.scope`".
+pub struct FreeRegion {
+ pub scope: region::CodeExtent,
+ pub bound_region: BoundRegion
+}
+
+#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash,
+ RustcEncodable, RustcDecodable, Copy)]
+pub enum BoundRegion {
+ /// An anonymous region parameter for a given fn (&T)
+ BrAnon(u32),
+
+ /// Named region parameters for functions (a in &'a T)
+ ///
+ /// The def-id is needed to distinguish free regions in
+ /// the event of shadowing.
+ BrNamed(DefId, Name),
+
+ /// Fresh bound identifiers created during GLB computations.
+ BrFresh(u32),
+
+ // Anonymous region for the implicit env pointer parameter
+ // to a closure
+ BrEnv
+}
+
+// NB: If you change this, you'll probably want to change the corresponding
+// AST structure in libsyntax/ast.rs as well.
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub enum TypeVariants<'tcx> {
+ /// The primitive boolean type. Written as `bool`.
+ TyBool,
+
+ /// The primitive character type; holds a Unicode scalar value
+ /// (a non-surrogate code point). Written as `char`.
+ TyChar,
+
+ /// A primitive signed integer type. For example, `i32`.
+ TyInt(hir::IntTy),
+
+ /// A primitive unsigned integer type. For example, `u32`.
+ TyUint(hir::UintTy),
+
+ /// A primitive floating-point type. For example, `f64`.
+ TyFloat(hir::FloatTy),
+
+ /// An enumerated type, defined with `enum`.
+ ///
+ /// Substs here, possibly against intuition, *may* contain `TyParam`s.
+ /// That is, even after substitution it is possible that there are type
+ /// variables. This happens when the `TyEnum` corresponds to an enum
+ /// definition and not a concrete use of it. To get the correct `TyEnum`
+ /// from the tcx, use the `NodeId` from the `hir::Ty` and look it up in
+ /// the `ast_ty_to_ty_cache`. This is probably true for `TyStruct` as
+ /// well.
+ TyEnum(AdtDef<'tcx>, &'tcx Substs<'tcx>),
+
+ /// A structure type, defined with `struct`.
+ ///
+ /// See warning about substitutions for enumerated types.
+ TyStruct(AdtDef<'tcx>, &'tcx Substs<'tcx>),
+
+ /// `Box<T>`; this is nominally a struct in the documentation, but is
+ /// special-cased internally. For example, it is possible to implicitly
+ /// move the contents of a box out of that box, and methods of any type
+ /// can have type `Box<Self>`.
+ TyBox(Ty<'tcx>),
+
+ /// The pointee of a string slice. Written as `str`.
+ TyStr,
+
+ /// An array with the given length. Written as `[T; n]`.
+ TyArray(Ty<'tcx>, usize),
+
+ /// The pointee of an array slice. Written as `[T]`.
+ TySlice(Ty<'tcx>),
+
+ /// A raw pointer. Written as `*mut T` or `*const T`
+ TyRawPtr(TypeAndMut<'tcx>),
+
+ /// A reference; a pointer with an associated lifetime. Written as
+ /// `&a mut T` or `&'a T`.
+ TyRef(&'tcx Region, TypeAndMut<'tcx>),
+
+ /// If the def-id is Some(_), then this is the type of a specific
+ /// fn item. Otherwise, if None(_), it a fn pointer type.
+ ///
+ /// FIXME: Conflating function pointers and the type of a
+ /// function is probably a terrible idea; a function pointer is a
+ /// value with a specific type, but a function can be polymorphic
+ /// or dynamically dispatched.
+ TyBareFn(Option<DefId>, &'tcx BareFnTy<'tcx>),
+
+ /// A trait, defined with `trait`.
+ TyTrait(Box<TraitTy<'tcx>>),
+
+ /// The anonymous type of a closure. Used to represent the type of
+ /// `|a| a`.
+ TyClosure(DefId, Box<ClosureSubsts<'tcx>>),
+
+ /// A tuple type. For example, `(i32, bool)`.
+ TyTuple(Vec<Ty<'tcx>>),
+
+ /// The projection of an associated type. For example,
+ /// `<T as Trait<..>>::N`.
+ TyProjection(ProjectionTy<'tcx>),
+
+ /// A type parameter; for example, `T` in `fn f<T>(x: T) {}
+ TyParam(ParamTy),
+
+ /// A type variable used during type-checking.
+ TyInfer(InferTy),
+
+ /// A placeholder for a type which could not be computed; this is
+ /// propagated to avoid useless error messages.
+ TyError,
+}
+
+/// A closure can be modeled as a struct that looks like:
+///
+/// struct Closure<'l0...'li, T0...Tj, U0...Uk> {
+/// upvar0: U0,
+/// ...
+/// upvark: Uk
+/// }
+///
+/// where 'l0...'li and T0...Tj are the lifetime and type parameters
+/// in scope on the function that defined the closure, and U0...Uk are
+/// type parameters representing the types of its upvars (borrowed, if
+/// appropriate).
+///
+/// So, for example, given this function:
+///
+/// fn foo<'a, T>(data: &'a mut T) {
+/// do(|| data.count += 1)
+/// }
+///
+/// the type of the closure would be something like:
+///
+/// struct Closure<'a, T, U0> {
+/// data: U0
+/// }
+///
+/// Note that the type of the upvar is not specified in the struct.
+/// You may wonder how the impl would then be able to use the upvar,
+/// if it doesn't know it's type? The answer is that the impl is
+/// (conceptually) not fully generic over Closure but rather tied to
+/// instances with the expected upvar types:
+///
+/// impl<'b, 'a, T> FnMut() for Closure<'a, T, &'b mut &'a mut T> {
+/// ...
+/// }
+///
+/// You can see that the *impl* fully specified the type of the upvar
+/// and thus knows full well that `data` has type `&'b mut &'a mut T`.
+/// (Here, I am assuming that `data` is mut-borrowed.)
+///
+/// Now, the last question you may ask is: Why include the upvar types
+/// as extra type parameters? The reason for this design is that the
+/// upvar types can reference lifetimes that are internal to the
+/// creating function. In my example above, for example, the lifetime
+/// `'b` represents the extent of the closure itself; this is some
+/// subset of `foo`, probably just the extent of the call to the to
+/// `do()`. If we just had the lifetime/type parameters from the
+/// enclosing function, we couldn't name this lifetime `'b`. Note that
+/// there can also be lifetimes in the types of the upvars themselves,
+/// if one of them happens to be a reference to something that the
+/// creating fn owns.
+///
+/// OK, you say, so why not create a more minimal set of parameters
+/// that just includes the extra lifetime parameters? The answer is
+/// primarily that it would be hard --- we don't know at the time when
+/// we create the closure type what the full types of the upvars are,
+/// nor do we know which are borrowed and which are not. In this
+/// design, we can just supply a fresh type parameter and figure that
+/// out later.
+///
+/// All right, you say, but why include the type parameters from the
+/// original function then? The answer is that trans may need them
+/// when monomorphizing, and they may not appear in the upvars. A
+/// closure could capture no variables but still make use of some
+/// in-scope type parameter with a bound (e.g., if our example above
+/// had an extra `U: Default`, and the closure called `U::default()`).
+///
+/// There is another reason. This design (implicitly) prohibits
+/// closures from capturing themselves (except via a trait
+/// object). This simplifies closure inference considerably, since it
+/// means that when we infer the kind of a closure or its upvars, we
+/// don't have to handle cycles where the decisions we make for
+/// closure C wind up influencing the decisions we ought to make for
+/// closure C (which would then require fixed point iteration to
+/// handle). Plus it fixes an ICE. :P
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub struct ClosureSubsts<'tcx> {
+ /// Lifetime and type parameters from the enclosing function.
+ /// These are separated out because trans wants to pass them around
+ /// when monomorphizing.
+ pub func_substs: &'tcx Substs<'tcx>,
+
+ /// The types of the upvars. The list parallels the freevars and
+ /// `upvar_borrows` lists. These are kept distinct so that we can
+ /// easily index into them.
+ pub upvar_tys: Vec<Ty<'tcx>>
+}
+
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct TraitTy<'tcx> {
+ pub principal: ty::PolyTraitRef<'tcx>,
+ pub bounds: ExistentialBounds<'tcx>,
+}
+
+impl<'tcx> TraitTy<'tcx> {
+ pub fn principal_def_id(&self) -> DefId {
+ self.principal.0.def_id
+ }
+
+ /// Object types don't have a self-type specified. Therefore, when
+ /// we convert the principal trait-ref into a normal trait-ref,
+ /// you must give *some* self-type. A common choice is `mk_err()`
+ /// or some skolemized type.
+ pub fn principal_trait_ref_with_self_ty(&self,
+ tcx: &ty::ctxt<'tcx>,
+ self_ty: Ty<'tcx>)
+ -> ty::PolyTraitRef<'tcx>
+ {
+ // otherwise the escaping regions would be captured by the binder
+ assert!(!self_ty.has_escaping_regions());
+
+ ty::Binder(TraitRef {
+ def_id: self.principal.0.def_id,
+ substs: tcx.mk_substs(self.principal.0.substs.with_self_ty(self_ty)),
+ })
+ }
+
+ pub fn projection_bounds_with_self_ty(&self,
+ tcx: &ty::ctxt<'tcx>,
+ self_ty: Ty<'tcx>)
+ -> Vec<ty::PolyProjectionPredicate<'tcx>>
+ {
+ // otherwise the escaping regions would be captured by the binders
+ assert!(!self_ty.has_escaping_regions());
+
+ self.bounds.projection_bounds.iter()
+ .map(|in_poly_projection_predicate| {
+ let in_projection_ty = &in_poly_projection_predicate.0.projection_ty;
+ let substs = tcx.mk_substs(in_projection_ty.trait_ref.substs.with_self_ty(self_ty));
+ let trait_ref = ty::TraitRef::new(in_projection_ty.trait_ref.def_id,
+ substs);
+ let projection_ty = ty::ProjectionTy {
+ trait_ref: trait_ref,
+ item_name: in_projection_ty.item_name
+ };
+ ty::Binder(ty::ProjectionPredicate {
+ projection_ty: projection_ty,
+ ty: in_poly_projection_predicate.0.ty
+ })
+ })
+ .collect()
+ }
+}
+
+/// A complete reference to a trait. These take numerous guises in syntax,
+/// but perhaps the most recognizable form is in a where clause:
+///
+/// T : Foo<U>
+///
+/// This would be represented by a trait-reference where the def-id is the
+/// def-id for the trait `Foo` and the substs defines `T` as parameter 0 in the
+/// `SelfSpace` and `U` as parameter 0 in the `TypeSpace`.
+///
+/// Trait references also appear in object types like `Foo<U>`, but in
+/// that case the `Self` parameter is absent from the substitutions.
+///
+/// Note that a `TraitRef` introduces a level of region binding, to
+/// account for higher-ranked trait bounds like `T : for<'a> Foo<&'a
+/// U>` or higher-ranked object types.
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+pub struct TraitRef<'tcx> {
+ pub def_id: DefId,
+ pub substs: &'tcx Substs<'tcx>,
+}
+
+pub type PolyTraitRef<'tcx> = Binder<TraitRef<'tcx>>;
+
+impl<'tcx> PolyTraitRef<'tcx> {
+ pub fn self_ty(&self) -> Ty<'tcx> {
+ self.0.self_ty()
+ }
+
+ pub fn def_id(&self) -> DefId {
+ self.0.def_id
+ }
+
+ pub fn substs(&self) -> &'tcx Substs<'tcx> {
+ // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<>
+ self.0.substs
+ }
+
+ pub fn input_types(&self) -> &[Ty<'tcx>] {
+ // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<>
+ self.0.input_types()
+ }
+
+ pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> {
+ // Note that we preserve binding levels
+ Binder(ty::TraitPredicate { trait_ref: self.0.clone() })
+ }
+}
+
+/// Binder is a binder for higher-ranked lifetimes. It is part of the
+/// compiler's representation for things like `for<'a> Fn(&'a isize)`
+/// (which would be represented by the type `PolyTraitRef ==
+/// Binder<TraitRef>`). Note that when we skolemize, instantiate,
+/// erase, or otherwise "discharge" these bound regions, we change the
+/// type from `Binder<T>` to just `T` (see
+/// e.g. `liberate_late_bound_regions`).
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub struct Binder<T>(pub T);
+
+impl<T> Binder<T> {
+ /// Skips the binder and returns the "bound" value. This is a
+ /// risky thing to do because it's easy to get confused about
+ /// debruijn indices and the like. It is usually better to
+ /// discharge the binder using `no_late_bound_regions` or
+ /// `replace_late_bound_regions` or something like
+ /// that. `skip_binder` is only valid when you are either
+ /// extracting data that has nothing to do with bound regions, you
+ /// are doing some sort of test that does not involve bound
+ /// regions, or you are being very careful about your depth
+ /// accounting.
+ ///
+ /// Some examples where `skip_binder` is reasonable:
+ /// - extracting the def-id from a PolyTraitRef;
+ /// - comparing the self type of a PolyTraitRef to see if it is equal to
+ /// a type parameter `X`, since the type `X` does not reference any regions
+ pub fn skip_binder(&self) -> &T {
+ &self.0
+ }
+
+ pub fn as_ref(&self) -> Binder<&T> {
+ ty::Binder(&self.0)
+ }
+
+ pub fn map_bound_ref<F,U>(&self, f: F) -> Binder<U>
+ where F: FnOnce(&T) -> U
+ {
+ self.as_ref().map_bound(f)
+ }
+
+ pub fn map_bound<F,U>(self, f: F) -> Binder<U>
+ where F: FnOnce(T) -> U
+ {
+ ty::Binder(f(self.0))
+ }
+}
+
+impl fmt::Debug for TypeFlags {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", self.bits)
+ }
+}
+
+/// Represents the projection of an associated type. In explicit UFCS
+/// form this would be written `<T as Trait<..>>::N`.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub struct ProjectionTy<'tcx> {
+ /// The trait reference `T as Trait<..>`.
+ pub trait_ref: ty::TraitRef<'tcx>,
+
+ /// The name `N` of the associated type.
+ pub item_name: Name,
+}
+
+impl<'tcx> ProjectionTy<'tcx> {
+ pub fn sort_key(&self) -> (DefId, Name) {
+ (self.trait_ref.def_id, self.item_name)
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub struct BareFnTy<'tcx> {
+ pub unsafety: hir::Unsafety,
+ pub abi: abi::Abi,
+ pub sig: PolyFnSig<'tcx>,
+}
+
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct ClosureTy<'tcx> {
+ pub unsafety: hir::Unsafety,
+ pub abi: abi::Abi,
+ pub sig: PolyFnSig<'tcx>,
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+pub enum FnOutput<'tcx> {
+ FnConverging(Ty<'tcx>),
+ FnDiverging
+}
+
+impl<'tcx> FnOutput<'tcx> {
+ pub fn diverges(&self) -> bool {
+ *self == FnDiverging
+ }
+
+ pub fn unwrap(self) -> Ty<'tcx> {
+ match self {
+ ty::FnConverging(t) => t,
+ ty::FnDiverging => unreachable!()
+ }
+ }
+
+ pub fn unwrap_or(self, def: Ty<'tcx>) -> Ty<'tcx> {
+ match self {
+ ty::FnConverging(t) => t,
+ ty::FnDiverging => def
+ }
+ }
+}
+
+pub type PolyFnOutput<'tcx> = Binder<FnOutput<'tcx>>;
+
+impl<'tcx> PolyFnOutput<'tcx> {
+ pub fn diverges(&self) -> bool {
+ self.0.diverges()
+ }
+}
+
+/// 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.
+/// - `variadic` indicates whether this is a variadic function. (only true for foreign fns)
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct FnSig<'tcx> {
+ pub inputs: Vec<Ty<'tcx>>,
+ pub output: FnOutput<'tcx>,
+ pub variadic: bool
+}
+
+pub type PolyFnSig<'tcx> = Binder<FnSig<'tcx>>;
+
+impl<'tcx> PolyFnSig<'tcx> {
+ pub fn inputs(&self) -> ty::Binder<Vec<Ty<'tcx>>> {
+ self.map_bound_ref(|fn_sig| fn_sig.inputs.clone())
+ }
+ pub fn input(&self, index: usize) -> ty::Binder<Ty<'tcx>> {
+ self.map_bound_ref(|fn_sig| fn_sig.inputs[index])
+ }
+ pub fn output(&self) -> ty::Binder<FnOutput<'tcx>> {
+ self.map_bound_ref(|fn_sig| fn_sig.output.clone())
+ }
+ pub fn variadic(&self) -> bool {
+ self.skip_binder().variadic
+ }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub struct ParamTy {
+ pub space: subst::ParamSpace,
+ pub idx: u32,
+ pub name: Name,
+}
+
+/// A [De Bruijn index][dbi] is a standard means of representing
+/// regions (and perhaps later types) in a higher-ranked setting. In
+/// particular, imagine a type like this:
+///
+/// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char)
+/// ^ ^ | | |
+/// | | | | |
+/// | +------------+ 1 | |
+/// | | |
+/// +--------------------------------+ 2 |
+/// | |
+/// +------------------------------------------+ 1
+///
+/// In this type, there are two binders (the outer fn and the inner
+/// fn). We need to be able to determine, for any given region, which
+/// fn type it is bound by, the inner or the outer one. There are
+/// various ways you can do this, but a De Bruijn index is one of the
+/// more convenient and has some nice properties. The basic idea is to
+/// count the number of binders, inside out. Some examples should help
+/// clarify what I mean.
+///
+/// Let's start with the reference type `&'b isize` that is the first
+/// argument to the inner function. This region `'b` is assigned a De
+/// Bruijn index of 1, meaning "the innermost binder" (in this case, a
+/// fn). The region `'a` that appears in the second argument type (`&'a
+/// isize`) would then be assigned a De Bruijn index of 2, meaning "the
+/// second-innermost binder". (These indices are written on the arrays
+/// in the diagram).
+///
+/// What is interesting is that De Bruijn index attached to a particular
+/// variable will vary depending on where it appears. For example,
+/// the final type `&'a char` also refers to the region `'a` declared on
+/// the outermost fn. But this time, this reference is not nested within
+/// any other binders (i.e., it is not an argument to the inner fn, but
+/// rather the outer one). Therefore, in this case, it is assigned a
+/// De Bruijn index of 1, because the innermost binder in that location
+/// is the outer fn.
+///
+/// [dbi]: http://en.wikipedia.org/wiki/De_Bruijn_index
+#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, Copy)]
+pub struct DebruijnIndex {
+ // We maintain the invariant that this is never 0. So 1 indicates
+ // the innermost binder. To ensure this, create with `DebruijnIndex::new`.
+ pub depth: u32,
+}
+
+/// Representation of regions.
+///
+/// Unlike types, most region variants are "fictitious", not concrete,
+/// regions. Among these, `ReStatic`, `ReEmpty` and `ReScope` are the only
+/// ones representing concrete regions.
+///
+/// ## Bound Regions
+///
+/// These are regions that are stored behind a binder and must be substituted
+/// with some concrete region before being used. There are 2 kind of
+/// bound regions: early-bound, which are bound in a TypeScheme/TraitDef,
+/// and are substituted by a Substs, and late-bound, which are part of
+/// higher-ranked types (e.g. `for<'a> fn(&'a ())`) and are substituted by
+/// the likes of `liberate_late_bound_regions`. The distinction exists
+/// because higher-ranked lifetimes aren't supported in all places. See [1][2].
+///
+/// Unlike TyParam-s, bound regions are not supposed to exist "in the wild"
+/// outside their binder, e.g. in types passed to type inference, and
+/// should first be substituted (by skolemized regions, free regions,
+/// or region variables).
+///
+/// ## Skolemized and Free Regions
+///
+/// One often wants to work with bound regions without knowing their precise
+/// identity. For example, when checking a function, the lifetime of a borrow
+/// can end up being assigned to some region parameter. In these cases,
+/// it must be ensured that bounds on the region can't be accidentally
+/// assumed without being checked.
+///
+/// The process of doing that is called "skolemization". The bound regions
+/// are replaced by skolemized markers, which don't satisfy any relation
+/// not explicity provided.
+///
+/// There are 2 kinds of skolemized regions in rustc: `ReFree` and
+/// `ReSkolemized`. When checking an item's body, `ReFree` is supposed
+/// to be used. These also support explicit bounds: both the internally-stored
+/// *scope*, which the region is assumed to outlive, as well as other
+/// relations stored in the `FreeRegionMap`. Note that these relations
+/// aren't checked when you `make_subregion` (or `mk_eqty`), only by
+/// `resolve_regions_and_report_errors`.
+///
+/// When working with higher-ranked types, some region relations aren't
+/// yet known, so you can't just call `resolve_regions_and_report_errors`.
+/// `ReSkolemized` is designed for this purpose. In these contexts,
+/// there's also the risk that some inference variable laying around will
+/// get unified with your skolemized region: if you want to check whether
+/// `for<'a> Foo<'_>: 'a`, and you substitute your bound region `'a`
+/// with a skolemized region `'%a`, the variable `'_` would just be
+/// instantiated to the skolemized region `'%a`, which is wrong because
+/// the inference variable is supposed to satisfy the relation
+/// *for every value of the skolemized region*. To ensure that doesn't
+/// happen, you can use `leak_check`. This is more clearly explained
+/// by infer/higher_ranked/README.md.
+///
+/// [1] http://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/
+/// [2] http://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
+#[derive(Clone, PartialEq, Eq, Hash, Copy)]
+pub enum Region {
+ // Region bound in a type or fn declaration which will be
+ // substituted 'early' -- that is, at the same time when type
+ // parameters are substituted.
+ ReEarlyBound(EarlyBoundRegion),
+
+ // Region bound in a function scope, which will be substituted when the
+ // function is called.
+ ReLateBound(DebruijnIndex, BoundRegion),
+
+ /// 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.
+ ReFree(FreeRegion),
+
+ /// A concrete region naming some statically determined extent
+ /// (e.g. an expression or sequence of statements) within the
+ /// current function.
+ ReScope(region::CodeExtent),
+
+ /// Static data that has an "infinite" lifetime. Top in the region lattice.
+ ReStatic,
+
+ /// A region variable. Should not exist after typeck.
+ ReVar(RegionVid),
+
+ /// A skolemized region - basically the higher-ranked version of ReFree.
+ /// Should not exist after typeck.
+ ReSkolemized(SkolemizedRegionVid, BoundRegion),
+
+ /// Empty lifetime is for data that is never accessed.
+ /// Bottom in the region lattice. We treat ReEmpty somewhat
+ /// specially; at least right now, we do not generate instances of
+ /// it during the GLB computations, but rather
+ /// generate an error instead. This is to improve error messages.
+ /// The only way to get an instance of ReEmpty is to have a region
+ /// variable with no constraints.
+ ReEmpty,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
+pub struct EarlyBoundRegion {
+ pub param_id: NodeId,
+ pub space: subst::ParamSpace,
+ pub index: u32,
+ pub name: Name,
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub struct TyVid {
+ pub index: u32
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub struct IntVid {
+ pub index: u32
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub struct FloatVid {
+ pub index: u32
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
+pub struct RegionVid {
+ pub index: u32
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub struct SkolemizedRegionVid {
+ pub index: u32
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub enum InferTy {
+ TyVar(TyVid),
+ IntVar(IntVid),
+ FloatVar(FloatVid),
+
+ /// A `FreshTy` is one that is generated as a replacement for an
+ /// unbound type variable. This is convenient for caching etc. See
+ /// `middle::infer::freshen` for more details.
+ FreshTy(u32),
+ FreshIntTy(u32),
+ FreshFloatTy(u32)
+}
+
+/// Bounds suitable for an existentially quantified type parameter
+/// such as those that appear in object types or closure types.
+#[derive(PartialEq, Eq, Hash, Clone)]
+pub struct ExistentialBounds<'tcx> {
+ pub region_bound: ty::Region,
+ pub builtin_bounds: BuiltinBounds,
+ pub projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
+}
+
+impl<'tcx> ExistentialBounds<'tcx> {
+ pub fn new(region_bound: ty::Region,
+ builtin_bounds: BuiltinBounds,
+ projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>)
+ -> Self {
+ let mut projection_bounds = projection_bounds;
+ projection_bounds.sort_by(|a, b| a.sort_key().cmp(&b.sort_key()));
+ ExistentialBounds {
+ region_bound: region_bound,
+ builtin_bounds: builtin_bounds,
+ projection_bounds: projection_bounds
+ }
+ }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+pub struct BuiltinBounds(EnumSet<BuiltinBound>);
+
+impl BuiltinBounds {
+ pub fn empty() -> BuiltinBounds {
+ BuiltinBounds(EnumSet::new())
+ }
+
+ pub fn iter(&self) -> enum_set::Iter<BuiltinBound> {
+ self.into_iter()
+ }
+
+ pub fn to_predicates<'tcx>(&self,
+ tcx: &ty::ctxt<'tcx>,
+ self_ty: Ty<'tcx>) -> Vec<ty::Predicate<'tcx>> {
+ self.iter().filter_map(|builtin_bound|
+ match traits::trait_ref_for_builtin_bound(tcx, builtin_bound, self_ty) {
+ Ok(trait_ref) => Some(trait_ref.to_predicate()),
+ Err(ErrorReported) => { None }
+ }
+ ).collect()
+ }
+}
+
+impl ops::Deref for BuiltinBounds {
+ type Target = EnumSet<BuiltinBound>;
+ fn deref(&self) -> &Self::Target { &self.0 }
+}
+
+impl ops::DerefMut for BuiltinBounds {
+ fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
+}
+
+impl<'a> IntoIterator for &'a BuiltinBounds {
+ type Item = BuiltinBound;
+ type IntoIter = enum_set::Iter<BuiltinBound>;
+ fn into_iter(self) -> Self::IntoIter {
+ (**self).into_iter()
+ }
+}
+
+#[derive(Clone, RustcEncodable, PartialEq, Eq, RustcDecodable, Hash,
+ Debug, Copy)]
+#[repr(usize)]
+pub enum BuiltinBound {
+ Send,
+ Sized,
+ Copy,
+ Sync,
+}
+
+impl CLike for BuiltinBound {
+ fn to_usize(&self) -> usize {
+ *self as usize
+ }
+ fn from_usize(v: usize) -> BuiltinBound {
+ unsafe { mem::transmute(v) }
+ }
+}
+
+impl<'tcx> ty::ctxt<'tcx> {
+ pub fn try_add_builtin_trait(&self,
+ trait_def_id: DefId,
+ builtin_bounds: &mut EnumSet<BuiltinBound>)
+ -> bool
+ {
+ //! Checks whether `trait_ref` refers to one of the builtin
+ //! traits, like `Send`, and adds the corresponding
+ //! bound to the set `builtin_bounds` if so. Returns true if `trait_ref`
+ //! is a builtin trait.
+
+ match self.lang_items.to_builtin_kind(trait_def_id) {
+ Some(bound) => { builtin_bounds.insert(bound); true }
+ None => false
+ }
+ }
+}
+
+impl DebruijnIndex {
+ pub fn new(depth: u32) -> DebruijnIndex {
+ assert!(depth > 0);
+ DebruijnIndex { depth: depth }
+ }
+
+ pub fn shifted(&self, amount: u32) -> DebruijnIndex {
+ DebruijnIndex { depth: self.depth + amount }
+ }
+}
+
+// Region utilities
+impl Region {
+ pub fn is_bound(&self) -> bool {
+ match *self {
+ ty::ReEarlyBound(..) => true,
+ ty::ReLateBound(..) => true,
+ _ => false
+ }
+ }
+
+ pub fn needs_infer(&self) -> bool {
+ match *self {
+ ty::ReVar(..) | ty::ReSkolemized(..) => true,
+ _ => false
+ }
+ }
+
+ pub fn escapes_depth(&self, depth: u32) -> bool {
+ match *self {
+ ty::ReLateBound(debruijn, _) => debruijn.depth > depth,
+ _ => false,
+ }
+ }
+
+ /// Returns the depth of `self` from the (1-based) binding level `depth`
+ pub fn from_depth(&self, depth: u32) -> Region {
+ match *self {
+ ty::ReLateBound(debruijn, r) => ty::ReLateBound(DebruijnIndex {
+ depth: debruijn.depth - (depth - 1)
+ }, r),
+ r => r
+ }
+ }
+}
+
+// Type utilities
+impl<'tcx> TyS<'tcx> {
+ pub fn is_nil(&self) -> bool {
+ match self.sty {
+ TyTuple(ref tys) => tys.is_empty(),
+ _ => false
+ }
+ }
+
+ pub fn is_empty(&self, _cx: &ty::ctxt) -> bool {
+ // FIXME(#24885): be smarter here
+ match self.sty {
+ TyEnum(def, _) | TyStruct(def, _) => def.is_empty(),
+ _ => false
+ }
+ }
+
+ pub fn is_ty_var(&self) -> bool {
+ match self.sty {
+ TyInfer(TyVar(_)) => true,
+ _ => false
+ }
+ }
+
+ pub fn is_bool(&self) -> bool { self.sty == TyBool }
+
+ pub fn is_self(&self) -> bool {
+ match self.sty {
+ TyParam(ref p) => p.space == subst::SelfSpace,
+ _ => false
+ }
+ }
+
+ fn is_slice(&self) -> bool {
+ match self.sty {
+ TyRawPtr(mt) | TyRef(_, mt) => match mt.ty.sty {
+ TySlice(_) | TyStr => true,
+ _ => false,
+ },
+ _ => false
+ }
+ }
+
+ pub fn is_structural(&self) -> bool {
+ match self.sty {
+ TyStruct(..) | TyTuple(_) | TyEnum(..) |
+ TyArray(..) | TyClosure(..) => true,
+ _ => self.is_slice() | self.is_trait()
+ }
+ }
+
+ #[inline]
+ pub fn is_simd(&self) -> bool {
+ match self.sty {
+ TyStruct(def, _) => def.is_simd(),
+ _ => false
+ }
+ }
+
+ pub fn sequence_element_type(&self, cx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
+ match self.sty {
+ TyArray(ty, _) | TySlice(ty) => ty,
+ TyStr => cx.mk_mach_uint(hir::TyU8),
+ _ => cx.sess.bug(&format!("sequence_element_type called on non-sequence value: {}",
+ self)),
+ }
+ }
+
+ pub fn simd_type(&self, cx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
+ match self.sty {
+ TyStruct(def, substs) => {
+ def.struct_variant().fields[0].ty(cx, substs)
+ }
+ _ => panic!("simd_type called on invalid type")
+ }
+ }
+
+ pub fn simd_size(&self, _cx: &ty::ctxt) -> usize {
+ match self.sty {
+ TyStruct(def, _) => def.struct_variant().fields.len(),
+ _ => panic!("simd_size called on invalid type")
+ }
+ }
+
+ pub fn is_region_ptr(&self) -> bool {
+ match self.sty {
+ TyRef(..) => true,
+ _ => false
+ }
+ }
+
+ pub fn is_unsafe_ptr(&self) -> bool {
+ match self.sty {
+ TyRawPtr(_) => return true,
+ _ => return false
+ }
+ }
+
+ pub fn is_unique(&self) -> bool {
+ match self.sty {
+ TyBox(_) => true,
+ _ => false
+ }
+ }
+
+ /*
+ A scalar type is one that denotes an atomic datum, with no sub-components.
+ (A TyRawPtr is scalar because it represents a non-managed pointer, so its
+ contents are abstract to rustc.)
+ */
+ pub fn is_scalar(&self) -> bool {
+ match self.sty {
+ TyBool | TyChar | TyInt(_) | TyFloat(_) | TyUint(_) |
+ TyInfer(IntVar(_)) | TyInfer(FloatVar(_)) |
+ TyBareFn(..) | TyRawPtr(_) => true,
+ _ => false
+ }
+ }
+
+ /// Returns true if this type is a floating point type and false otherwise.
+ pub fn is_floating_point(&self) -> bool {
+ match self.sty {
+ TyFloat(_) |
+ TyInfer(FloatVar(_)) => true,
+ _ => false,
+ }
+ }
+
+ pub fn is_trait(&self) -> bool {
+ match self.sty {
+ TyTrait(..) => true,
+ _ => false
+ }
+ }
+
+ pub fn is_integral(&self) -> bool {
+ match self.sty {
+ TyInfer(IntVar(_)) | TyInt(_) | TyUint(_) => true,
+ _ => false
+ }
+ }
+
+ pub fn is_fresh(&self) -> bool {
+ match self.sty {
+ TyInfer(FreshTy(_)) => true,
+ TyInfer(FreshIntTy(_)) => true,
+ TyInfer(FreshFloatTy(_)) => true,
+ _ => false
+ }
+ }
+
+ pub fn is_uint(&self) -> bool {
+ match self.sty {
+ TyInfer(IntVar(_)) | TyUint(hir::TyUs) => true,
+ _ => false
+ }
+ }
+
+ pub fn is_char(&self) -> bool {
+ match self.sty {
+ TyChar => true,
+ _ => false
+ }
+ }
+
+ pub fn is_bare_fn(&self) -> bool {
+ match self.sty {
+ TyBareFn(..) => true,
+ _ => false
+ }
+ }
+
+ pub fn is_bare_fn_item(&self) -> bool {
+ match self.sty {
+ TyBareFn(Some(_), _) => true,
+ _ => false
+ }
+ }
+
+ pub fn is_fp(&self) -> bool {
+ match self.sty {
+ TyInfer(FloatVar(_)) | TyFloat(_) => true,
+ _ => false
+ }
+ }
+
+ pub fn is_numeric(&self) -> bool {
+ self.is_integral() || self.is_fp()
+ }
+
+ pub fn is_signed(&self) -> bool {
+ match self.sty {
+ TyInt(_) => true,
+ _ => false
+ }
+ }
+
+ pub fn is_machine(&self) -> bool {
+ match self.sty {
+ TyInt(hir::TyIs) | TyUint(hir::TyUs) => false,
+ TyInt(..) | TyUint(..) | TyFloat(..) => true,
+ _ => false
+ }
+ }
+
+ // Returns the type and mutability of *ty.
+ //
+ // The parameter `explicit` indicates if this is an *explicit* dereference.
+ // Some types---notably unsafe ptrs---can only be dereferenced explicitly.
+ pub fn builtin_deref(&self, explicit: bool, pref: ty::LvaluePreference)
+ -> Option<TypeAndMut<'tcx>>
+ {
+ match self.sty {
+ TyBox(ty) => {
+ Some(TypeAndMut {
+ ty: ty,
+ mutbl: if pref == ty::PreferMutLvalue {
+ hir::MutMutable
+ } else {
+ hir::MutImmutable
+ },
+ })
+ },
+ TyRef(_, mt) => Some(mt),
+ TyRawPtr(mt) if explicit => Some(mt),
+ _ => None
+ }
+ }
+
+ // Returns the type of ty[i]
+ pub fn builtin_index(&self) -> Option<Ty<'tcx>> {
+ match self.sty {
+ TyArray(ty, _) | TySlice(ty) => Some(ty),
+ _ => None
+ }
+ }
+
+ pub fn fn_sig(&self) -> &'tcx PolyFnSig<'tcx> {
+ match self.sty {
+ TyBareFn(_, ref f) => &f.sig,
+ _ => panic!("Ty::fn_sig() called on non-fn type: {:?}", self)
+ }
+ }
+
+ /// Returns the ABI of the given function.
+ pub fn fn_abi(&self) -> abi::Abi {
+ match self.sty {
+ TyBareFn(_, ref f) => f.abi,
+ _ => panic!("Ty::fn_abi() called on non-fn type"),
+ }
+ }
+
+ // Type accessors for substructures of types
+ pub fn fn_args(&self) -> ty::Binder<Vec<Ty<'tcx>>> {
+ self.fn_sig().inputs()
+ }
+
+ pub fn fn_ret(&self) -> Binder<FnOutput<'tcx>> {
+ self.fn_sig().output()
+ }
+
+ pub fn is_fn(&self) -> bool {
+ match self.sty {
+ TyBareFn(..) => true,
+ _ => false
+ }
+ }
+
+ pub fn ty_to_def_id(&self) -> Option<DefId> {
+ match self.sty {
+ TyTrait(ref tt) => Some(tt.principal_def_id()),
+ TyStruct(def, _) |
+ TyEnum(def, _) => Some(def.did),
+ TyClosure(id, _) => Some(id),
+ _ => None
+ }
+ }
+
+ pub fn ty_adt_def(&self) -> Option<AdtDef<'tcx>> {
+ match self.sty {
+ TyStruct(adt, _) | TyEnum(adt, _) => Some(adt),
+ _ => None
+ }
+ }
+}
use middle::ty::TyClosure;
use middle::ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer};
use middle::ty::{self, TypeAndMut, Ty, HasTypeFlags};
-use middle::ty::fold::{self, TypeFoldable};
+use middle::ty::fold::TypeFoldable;
use std::fmt;
use syntax::abi;
}
};
- let new_value = fold::replace_late_bound_regions(tcx, &value, |br| {
+ let new_value = tcx.replace_late_bound_regions(&value, |br| {
let _ = start_or_continue(f, "for<", ", ");
ty::ReLateBound(ty::DebruijnIndex::new(1), match br {
ty::BrNamed(_, name) => {
struct TraitAndProjections<'tcx>(ty::TraitRef<'tcx>, Vec<ty::ProjectionPredicate<'tcx>>);
impl<'tcx> TypeFoldable<'tcx> for TraitAndProjections<'tcx> {
- fn fold_with<F: fold::TypeFolder<'tcx>>(&self, folder: &mut F)
+ fn fold_with<F:ty::fold::TypeFolder<'tcx>>(&self, folder: &mut F)
-> TraitAndProjections<'tcx> {
TraitAndProjections(self.0.fold_with(folder), self.1.fold_with(folder))
}
}
}
+impl<'tcx> fmt::Debug for ty::AutoAdjustment<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ ty::AdjustReifyFnPointer => {
+ write!(f, "AdjustReifyFnPointer")
+ }
+ ty::AdjustUnsafeFnPointer => {
+ write!(f, "AdjustUnsafeFnPointer")
+ }
+ ty::AdjustDerefRef(ref data) => {
+ write!(f, "{:?}", data)
+ }
+ }
+ }
+}
+
+impl<'tcx> fmt::Debug for ty::AutoDerefRef<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "AutoDerefRef({}, unsize={:?}, {:?})",
+ self.autoderefs, self.unsize, self.autoref)
+ }
+}
+
+impl<'tcx> fmt::Debug for ty::TraitTy<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "TraitTy({:?},{:?})",
+ self.principal,
+ self.bounds)
+ }
+}
+
+impl<'tcx> fmt::Debug for ty::Predicate<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ ty::Predicate::Trait(ref a) => write!(f, "{:?}", a),
+ ty::Predicate::Equate(ref pair) => write!(f, "{:?}", pair),
+ ty::Predicate::RegionOutlives(ref pair) => write!(f, "{:?}", pair),
+ ty::Predicate::TypeOutlives(ref pair) => write!(f, "{:?}", pair),
+ ty::Predicate::Projection(ref pair) => write!(f, "{:?}", pair),
+ ty::Predicate::WellFormed(ty) => write!(f, "WF({:?})", ty),
+ ty::Predicate::ObjectSafe(trait_def_id) => {
+ write!(f, "ObjectSafe({:?})", trait_def_id)
+ }
+ }
+ }
+}
+
impl fmt::Display for ty::BoundRegion {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if verbose() {
}
}
+impl<'tcx> fmt::Debug for ty::ClosureTy<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "ClosureTy({},{:?},{})",
+ self.unsafety,
+ self.sig,
+ self.abi)
+ }
+}
+
+impl<'tcx> fmt::Debug for ty::ClosureUpvar<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "ClosureUpvar({:?},{:?})",
+ self.def,
+ self.ty)
+ }
+}
+
+impl<'a, 'tcx> fmt::Debug for ty::ParameterEnvironment<'a, 'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "ParameterEnvironment(\
+ free_substs={:?}, \
+ implicit_region_bound={:?}, \
+ caller_bounds={:?})",
+ self.free_substs,
+ self.implicit_region_bound,
+ self.caller_bounds)
+ }
+}
+
+impl<'tcx> fmt::Debug for ty::ObjectLifetimeDefault {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ ty::ObjectLifetimeDefault::Ambiguous => write!(f, "Ambiguous"),
+ ty::ObjectLifetimeDefault::BaseDefault => write!(f, "BaseDefault"),
+ ty::ObjectLifetimeDefault::Specific(ref r) => write!(f, "{:?}", r),
+ }
+ }
+}
+
impl fmt::Display for ty::Region {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if verbose() {
}
}
+impl fmt::Debug for ty::Variance {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str(match *self {
+ ty::Covariant => "+",
+ ty::Contravariant => "-",
+ ty::Invariant => "o",
+ ty::Bivariant => "*",
+ })
+ }
+}
+
impl fmt::Debug for ty::ItemVariances {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ItemVariances(types={:?}, regions={:?})",
}
}
+impl fmt::Debug for ty::TyVid {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "_#{}t", self.index)
+ }
+}
+
+impl fmt::Debug for ty::IntVid {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "_#{}i", self.index)
+ }
+}
+
+impl fmt::Debug for ty::FloatVid {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "_#{}f", self.index)
+ }
+}
+
+impl fmt::Debug for ty::RegionVid {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "'_#{}r", self.index)
+ }
+}
+
+impl<'tcx> fmt::Debug for ty::FnSig<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "({:?}; variadic: {})->{:?}", self.inputs, self.variadic, self.output)
+ }
+}
+
+impl fmt::Debug for ty::InferTy {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ ty::TyVar(ref v) => v.fmt(f),
+ ty::IntVar(ref v) => v.fmt(f),
+ ty::FloatVar(ref v) => v.fmt(f),
+ ty::FreshTy(v) => write!(f, "FreshTy({:?})", v),
+ ty::FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v),
+ ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v)
+ }
+ }
+}
+
+impl fmt::Debug for ty::IntVarValue {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ ty::IntType(ref v) => v.fmt(f),
+ ty::UintType(ref v) => v.fmt(f),
+ }
+ }
+}
+
// The generic impl doesn't work yet because projections are not
// normalized under HRTB.
/*impl<T> fmt::Display for ty::Binder<T>
for (input_type, input_pat) in input_tys.iter().zip(input_pats) {
let mut regions = FnvHashSet();
- let have_bound_regions = ty::fold::collect_regions(tcx,
- input_type,
- &mut regions);
+ let have_bound_regions = tcx.collect_regions(input_type, &mut regions);
debug!("find_implied_output_regions: collected {:?} from {:?} \
have_bound_regions={:?}", ®ions, input_type, have_bound_regions);
use middle::traits::{self, ObligationCause};
use middle::traits::{predicate_for_trait_def, report_selection_error};
use middle::ty::{AutoDerefRef, AdjustDerefRef};
-use middle::ty::{self, LvaluePreference, TypeAndMut, Ty, TypeError};
+use middle::ty::{self, LvaluePreference, TypeAndMut, Ty};
+use middle::ty::error::TypeError;
use middle::ty::relate::RelateResult;
use util::common::indent;
ty_a: Ty<'tcx>,
ty_b: Ty<'tcx>,
handle_err: F) where
- F: FnOnce(Span, Ty<'tcx>, Ty<'tcx>, &ty::TypeError<'tcx>),
+ F: FnOnce(Span, Ty<'tcx>, Ty<'tcx>, &ty::error::TypeError<'tcx>),
{
// n.b.: order of actual, expected is reversed
match infer::mk_subty(fcx.infcx(), b_is_expected, infer::Misc(sp),
use middle::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
use middle::ty::{self, HasTypeFlags, RegionEscape, ToPolyTraitRef, Ty};
use middle::ty::{MethodCall, MethodCallee};
+use middle::ty::error::TypeError;
use middle::ty::fold::{TypeFolder, TypeFoldable};
use require_c_abi_if_variadic;
use rscope::{ElisionFailureInfo, RegionScope};
origin: infer::TypeOrigin,
sub: Ty<'tcx>,
sup: Ty<'tcx>)
- -> Result<(), ty::TypeError<'tcx>> {
+ -> Result<(), TypeError<'tcx>> {
infer::mk_subty(self.infcx(), a_is_expected, origin, sub, sup)
}
origin: infer::TypeOrigin,
sub: Ty<'tcx>,
sup: Ty<'tcx>)
- -> Result<(), ty::TypeError<'tcx>> {
+ -> Result<(), TypeError<'tcx>> {
infer::mk_eqty(self.infcx(), a_is_expected, origin, sub, sup)
}
sp: Span,
mk_msg: M,
actual_ty: Ty<'tcx>,
- err: Option<&ty::TypeError<'tcx>>) where
+ err: Option<&TypeError<'tcx>>) where
M: FnOnce(String) -> String,
{
self.infcx().type_error_message(sp, mk_msg, actual_ty, err);
sp: Span,
e: Ty<'tcx>,
a: Ty<'tcx>,
- err: &ty::TypeError<'tcx>) {
+ err: &TypeError<'tcx>) {
self.infcx().report_mismatched_types(sp, e, a, err)
}
/// Apply "fallbacks" to some types
/// ! gets replaced with (), unconstrained ints with i32, and unconstrained floats with f64.
fn default_type_parameters(&self) {
- use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither};
+ use middle::ty::error::UnconstrainedNumeric::Neither;
+ use middle::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
for ty in &self.infcx().unsolved_variables() {
let resolved = self.infcx().resolve_type_vars_if_possible(ty);
if self.infcx().type_var_diverges(resolved) {
}
fn new_select_all_obligations_and_apply_defaults(&self) {
- use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither};
+ use middle::ty::error::UnconstrainedNumeric::Neither;
+ use middle::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
- // For the time being this errs on the side of being memory wasteful but provides better
+ // For the time being this errs on the side of being memory wasteful but provides better
// error reporting.
// let type_variables = self.infcx().type_variables.clone();
default_map: &FnvHashMap<&Ty<'tcx>, type_variable::Default<'tcx>>,
conflict: Ty<'tcx>)
-> Option<type_variable::Default<'tcx>> {
- use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither};
+ use middle::ty::error::UnconstrainedNumeric::Neither;
+ use middle::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
// Ensure that we apply the conflicting default first
let mut unbound_tyvars = Vec::with_capacity(unbound_vars.len() + 1);
mk_ptr: &Fn(Ty<'tcx>) -> Ty<'tcx>| {
if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) {
infcx.report_mismatched_types(span, mk_ptr(mt_b.ty),
- target, &ty::TypeError::Mutability);
+ target, &ty::error::TypeError::Mutability);
}
(mt_a.ty, mt_b.ty, unsize_trait, None)
};
* before we really have a `ParameterEnvironment` to check.
*/
- ty::fold::fold_regions(tcx, value, &mut false, |region, _| {
+ tcx.fold_regions(value, &mut false, |region, _| {
match region {
ty::ReEarlyBound(data) => {
let def_id = DefId::local(data.param_id);