From caa10c3bde60ce0d9b5401771c443bff51d2a8e2 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 6 Sep 2015 18:32:34 +0300 Subject: [PATCH 1/4] move middle::ty and related modules to middle/ty/ --- src/librustc/lib.rs | 8 ------ src/librustc/middle/astencode.rs | 2 +- src/librustc/middle/check_const.rs | 2 +- src/librustc/middle/free_region.rs | 2 +- src/librustc/middle/implicator.rs | 2 +- src/librustc/middle/infer/bivariate.rs | 2 +- src/librustc/middle/infer/combine.rs | 19 +++++++------ src/librustc/middle/infer/equate.rs | 2 +- src/librustc/middle/infer/freshen.rs | 7 +++-- src/librustc/middle/infer/glb.rs | 2 +- .../middle/infer/higher_ranked/mod.rs | 12 ++++----- src/librustc/middle/infer/lattice.rs | 2 +- src/librustc/middle/infer/lub.rs | 3 +-- src/librustc/middle/infer/mod.rs | 12 ++++----- .../middle/infer/region_inference/mod.rs | 2 +- src/librustc/middle/infer/resolve.rs | 10 +++---- src/librustc/middle/infer/sub.rs | 2 +- src/librustc/middle/subst.rs | 8 +++--- src/librustc/middle/traits/error_reporting.rs | 2 +- src/librustc/middle/traits/fulfill.rs | 5 ++-- src/librustc/middle/traits/mod.rs | 2 +- src/librustc/middle/traits/project.rs | 4 +-- src/librustc/middle/traits/select.rs | 20 +++++++------- .../middle/{ty_match.rs => ty/_match.rs} | 6 ++--- src/librustc/middle/{ => ty}/cast.rs | 0 src/librustc/middle/{ => ty}/fast_reject.rs | 0 .../middle/{ty_fold.rs => ty/fold.rs} | 0 src/librustc/middle/{ty.rs => ty/mod.rs} | 27 ++++++++++++------- src/librustc/middle/{ => ty}/outlives.rs | 0 .../middle/{ty_relate/mod.rs => ty/relate.rs} | 2 +- .../middle/{ty_walk.rs => ty/walk.rs} | 0 src/librustc/middle/{ => ty}/wf.rs | 3 +-- src/librustc/util/ppaux.rs | 6 ++--- src/librustc_driver/test.rs | 2 +- src/librustc_trans/trans/common.rs | 9 +++---- src/librustc_trans/trans/consts.rs | 2 +- src/librustc_trans/trans/expr.rs | 6 ++--- src/librustc_trans/trans/monomorphize.rs | 2 +- src/librustc_typeck/astconv.rs | 11 ++++---- src/librustc_typeck/check/assoc.rs | 2 +- src/librustc_typeck/check/cast.rs | 6 ++--- src/librustc_typeck/check/coercion.rs | 2 +- src/librustc_typeck/check/intrinsic.rs | 2 +- src/librustc_typeck/check/method/confirm.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 11 ++++---- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/check/regionck.rs | 21 +++++++-------- src/librustc_typeck/check/wf.rs | 2 +- src/librustc_typeck/check/wfcheck.rs | 23 ++++++++-------- src/librustc_typeck/check/writeback.rs | 2 +- src/librustc_typeck/collect.rs | 4 +-- src/librustc_typeck/rscope.rs | 7 +++-- 52 files changed, 140 insertions(+), 154 deletions(-) rename src/librustc/middle/{ty_match.rs => ty/_match.rs} (94%) rename src/librustc/middle/{ => ty}/cast.rs (100%) rename src/librustc/middle/{ => ty}/fast_reject.rs (100%) rename src/librustc/middle/{ty_fold.rs => ty/fold.rs} (100%) rename src/librustc/middle/{ty.rs => ty/mod.rs} (99%) rename src/librustc/middle/{ => ty}/outlives.rs (100%) rename src/librustc/middle/{ty_relate/mod.rs => ty/relate.rs} (99%) rename src/librustc/middle/{ty_walk.rs => ty/walk.rs} (100%) rename src/librustc/middle/{ => ty}/wf.rs (99%) diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index b11bf6f80fb7b..cfeab976e24cb 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -107,7 +107,6 @@ pub mod front { pub mod middle { pub mod astconv_util; pub mod astencode; - pub mod cast; pub mod cfg; pub mod check_const; pub mod check_static_recursion; @@ -124,7 +123,6 @@ pub mod middle { pub mod effect; pub mod entry; pub mod expr_use_visitor; - pub mod fast_reject; pub mod free_region; pub mod intrinsicck; pub mod infer; @@ -132,7 +130,6 @@ pub mod middle { pub mod lang_items; pub mod liveness; pub mod mem_categorization; - pub mod outlives; pub mod pat_util; pub mod privacy; pub mod reachable; @@ -143,11 +140,6 @@ pub mod middle { pub mod subst; pub mod traits; pub mod ty; - pub mod ty_fold; - pub mod ty_match; - pub mod ty_relate; - pub mod ty_walk; - pub mod wf; pub mod weak_lang_items; } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index abf2d5f3625dc..ac2dd54598253 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -27,7 +27,7 @@ use metadata::tydecode; use metadata::tydecode::{DefIdSource, NominalType, TypeWithId}; use metadata::tydecode::{RegionParameter, ClosureSource}; use metadata::tyencode; -use middle::cast; +use middle::ty::cast; use middle::check_const::ConstQualif; use middle::def; use middle::def_id::{DefId, LOCAL_CRATE}; diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 37e144281760f..48c8cca76b056 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -24,7 +24,7 @@ // - It's not possible to take the address of a static item with unsafe interior. This is enforced // by borrowck::gather_loans -use middle::cast::{CastKind}; +use middle::ty::cast::{CastKind}; use middle::const_eval; use middle::const_eval::EvalHint::ExprTypeChecked; use middle::def; diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index c39c3fd302712..2e9e5fafb1d9b 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -16,7 +16,7 @@ //! region outlives another and so forth. use middle::ty::{self, FreeRegion, Region}; -use middle::wf::ImpliedBound; +use middle::ty::wf::ImpliedBound; use rustc_data_structures::transitive_relation::TransitiveRelation; #[derive(Clone)] diff --git a/src/librustc/middle/implicator.rs b/src/librustc/middle/implicator.rs index b1a4e0270c2f9..9f33c4df03d41 100644 --- a/src/librustc/middle/implicator.rs +++ b/src/librustc/middle/implicator.rs @@ -15,7 +15,7 @@ use middle::infer::{InferCtxt, GenericKind}; use middle::subst::Substs; use middle::traits; use middle::ty::{self, RegionEscape, ToPredicate, Ty}; -use middle::ty_fold::{TypeFoldable, TypeFolder}; +use middle::ty::fold::{TypeFoldable, TypeFolder}; use syntax::ast; use syntax::codemap::Span; diff --git a/src/librustc/middle/infer/bivariate.rs b/src/librustc/middle/infer/bivariate.rs index d2268894b20a1..2d9432b75e719 100644 --- a/src/librustc/middle/infer/bivariate.rs +++ b/src/librustc/middle/infer/bivariate.rs @@ -30,7 +30,7 @@ use super::type_variable::{BiTo}; use middle::ty::{self, Ty}; use middle::ty::TyVar; -use middle::ty_relate::{Relate, RelateResult, TypeRelation}; +use middle::ty::relate::{Relate, RelateResult, TypeRelation}; pub struct Bivariate<'a, 'tcx: 'a> { fields: CombineFields<'a, 'tcx> diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index 00edd054aa5b6..3a29fdfae2307 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -44,9 +44,8 @@ use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf}; use middle::ty::{TyVar}; use middle::ty::{IntType, UintType}; use middle::ty::{self, Ty, TypeError}; -use middle::ty_fold; -use middle::ty_fold::{TypeFolder, TypeFoldable}; -use middle::ty_relate::{self, Relate, RelateResult, TypeRelation}; +use middle::ty::fold::{TypeFolder, TypeFoldable}; +use middle::ty::relate::{Relate, RelateResult, TypeRelation}; use syntax::codemap::Span; use rustc_front::hir; @@ -56,7 +55,7 @@ pub struct CombineFields<'a, 'tcx: 'a> { pub infcx: &'a InferCtxt<'a, 'tcx>, pub a_is_expected: bool, pub trace: TypeTrace<'tcx>, - pub cause: Option, + pub cause: Option, } pub fn super_combine_tys<'a,'tcx:'a,R>(infcx: &InferCtxt<'a, 'tcx>, @@ -108,12 +107,12 @@ pub fn super_combine_tys<'a,'tcx:'a,R>(infcx: &InferCtxt<'a, 'tcx>, // All other cases of inference are errors (&ty::TyInfer(_), _) | (_, &ty::TyInfer(_)) => { - Err(TypeError::Sorts(ty_relate::expected_found(relation, &a, &b))) + Err(TypeError::Sorts(ty::relate::expected_found(relation, &a, &b))) } _ => { - ty_relate::super_relate_tys(relation, a, b) + ty::relate::super_relate_tys(relation, a, b) } } } @@ -293,7 +292,7 @@ struct Generalizer<'cx, 'tcx:'cx> { cycle_detected: bool, } -impl<'cx, 'tcx> ty_fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> { +impl<'cx, 'tcx> ty::fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { self.infcx.tcx } @@ -319,7 +318,7 @@ impl<'cx, 'tcx> ty_fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> { } } _ => { - ty_fold::super_fold_ty(self, t) + ty::fold::super_fold_ty(self, t) } } } @@ -384,7 +383,7 @@ fn int_unification_error<'tcx>(a_is_expected: bool, v: (ty::IntVarValue, ty::Int -> ty::TypeError<'tcx> { let (a, b) = v; - TypeError::IntMismatch(ty_relate::expected_found_bool(a_is_expected, &a, &b)) + TypeError::IntMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b)) } fn float_unification_error<'tcx>(a_is_expected: bool, @@ -392,5 +391,5 @@ fn float_unification_error<'tcx>(a_is_expected: bool, -> ty::TypeError<'tcx> { let (a, b) = v; - TypeError::FloatMismatch(ty_relate::expected_found_bool(a_is_expected, &a, &b)) + TypeError::FloatMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b)) } diff --git a/src/librustc/middle/infer/equate.rs b/src/librustc/middle/infer/equate.rs index cbbf73d942073..07ce4688c069f 100644 --- a/src/librustc/middle/infer/equate.rs +++ b/src/librustc/middle/infer/equate.rs @@ -15,7 +15,7 @@ use super::type_variable::{EqTo}; use middle::ty::{self, Ty}; use middle::ty::TyVar; -use middle::ty_relate::{Relate, RelateResult, TypeRelation}; +use middle::ty::relate::{Relate, RelateResult, TypeRelation}; pub struct Equate<'a, 'tcx: 'a> { fields: CombineFields<'a, 'tcx> diff --git a/src/librustc/middle/infer/freshen.rs b/src/librustc/middle/infer/freshen.rs index c72a4fc0db309..0bae3cd2d8690 100644 --- a/src/librustc/middle/infer/freshen.rs +++ b/src/librustc/middle/infer/freshen.rs @@ -31,9 +31,8 @@ //! inferencer knows "so far". use middle::ty::{self, Ty, HasTypeFlags}; -use middle::ty_fold; -use middle::ty_fold::TypeFoldable; -use middle::ty_fold::TypeFolder; +use middle::ty::fold::TypeFoldable; +use middle::ty::fold::TypeFolder; use std::collections::hash_map::{self, Entry}; use super::InferCtxt; @@ -170,7 +169,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { ty::TyTuple(..) | ty::TyProjection(..) | ty::TyParam(..) => { - ty_fold::super_fold_ty(self, t) + ty::fold::super_fold_ty(self, t) } } } diff --git a/src/librustc/middle/infer/glb.rs b/src/librustc/middle/infer/glb.rs index d6b03266b1fe7..0035f31e8db94 100644 --- a/src/librustc/middle/infer/glb.rs +++ b/src/librustc/middle/infer/glb.rs @@ -15,7 +15,7 @@ use super::lattice::{self, LatticeDir}; use super::Subtype; use middle::ty::{self, Ty}; -use middle::ty_relate::{Relate, RelateResult, TypeRelation}; +use middle::ty::relate::{Relate, RelateResult, TypeRelation}; /// "Greatest lower bound" (common subtype) pub struct Glb<'a, 'tcx: 'a> { diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index 0c539a5d0e0c2..10a31f0e657e5 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -15,8 +15,8 @@ use super::{CombinedSnapshot, InferCtxt, HigherRankedType, SkolemizationMap}; use super::combine::CombineFields; use middle::ty::{self, TypeError, Binder}; -use middle::ty_fold::{self, TypeFoldable}; -use middle::ty_relate::{Relate, RelateResult, TypeRelation}; +use middle::ty::fold::TypeFoldable; +use middle::ty::relate::{Relate, RelateResult, TypeRelation}; use syntax::codemap::Span; use util::nodemap::{FnvHashMap, FnvHashSet}; @@ -358,7 +358,7 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>, where T: TypeFoldable<'tcx>, F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region, { - ty_fold::fold_regions(tcx, unbound_value, &mut false, |region, current_depth| { + ty::fold::fold_regions(tcx, 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 @@ -438,7 +438,7 @@ impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> { let mut escaping_region_vars = FnvHashSet(); for ty in &escaping_types { - ty_fold::collect_regions(self.tcx, ty, &mut escaping_region_vars); + ty::fold::collect_regions(self.tcx, ty, &mut escaping_region_vars); } region_vars.retain(|®ion_vid| { @@ -468,7 +468,7 @@ pub fn skolemize_late_bound_regions<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, * details. */ - let (result, map) = ty_fold::replace_late_bound_regions(infcx.tcx, binder, |br| { + let (result, map) = ty::fold::replace_late_bound_regions(infcx.tcx, binder, |br| { infcx.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot) }); @@ -590,7 +590,7 @@ pub fn plug_leaks<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, // 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 = ty::fold::fold_regions(infcx.tcx, &value, &mut false, |r, current_depth| { match inv_skol_map.get(&r) { None => r, Some(br) => { diff --git a/src/librustc/middle/infer/lattice.rs b/src/librustc/middle/infer/lattice.rs index 7b34fda24064e..2a560ec8a1d23 100644 --- a/src/librustc/middle/infer/lattice.rs +++ b/src/librustc/middle/infer/lattice.rs @@ -34,7 +34,7 @@ use super::InferCtxt; use middle::ty::TyVar; use middle::ty::{self, Ty}; -use middle::ty_relate::{RelateResult, TypeRelation}; +use middle::ty::relate::{RelateResult, TypeRelation}; pub trait LatticeDir<'f,'tcx> : TypeRelation<'f,'tcx> { fn infcx(&self) -> &'f InferCtxt<'f, 'tcx>; diff --git a/src/librustc/middle/infer/lub.rs b/src/librustc/middle/infer/lub.rs index 9d993ead5ca20..238dad65ef0d9 100644 --- a/src/librustc/middle/infer/lub.rs +++ b/src/librustc/middle/infer/lub.rs @@ -15,7 +15,7 @@ use super::lattice::{self, LatticeDir}; use super::Subtype; use middle::ty::{self, Ty}; -use middle::ty_relate::{Relate, RelateResult, TypeRelation}; +use middle::ty::relate::{Relate, RelateResult, TypeRelation}; /// "Least upper bound" (common supertype) pub struct Lub<'a, 'tcx: 'a> { @@ -83,4 +83,3 @@ impl<'a, 'tcx> LatticeDir<'a,'tcx> for Lub<'a, 'tcx> { Ok(()) } } - diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 4ef96c0f3b450..5b94f5311fd0f 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -32,8 +32,8 @@ 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_fold::{self, TypeFolder, TypeFoldable}; -use middle::ty_relate::{Relate, RelateResult, TypeRelation}; +use middle::ty::fold::{TypeFolder, TypeFoldable}; +use middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_data_structures::unify::{self, UnificationTable}; use std::cell::{RefCell, Ref}; use std::fmt; @@ -583,7 +583,7 @@ pub fn drain_fulfillment_cx<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, /// Returns an equivalent value with all free regions removed (note /// that late-bound regions remain, because they are important for /// subtyping, but they are anonymized and normalized as well). This -/// is a stronger, caching version of `ty_fold::erase_regions`. +/// is a stronger, caching version of `ty::fold::erase_regions`. pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T where T : TypeFoldable<'tcx> { @@ -603,7 +603,7 @@ pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T Some(u) => return u } - let t_norm = ty_fold::super_fold_ty(self, ty); + let t_norm = ty::fold::super_fold_ty(self, ty); self.tcx().normalized_cache.borrow_mut().insert(ty, t_norm); return t_norm; } @@ -612,7 +612,7 @@ pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T where T : TypeFoldable<'tcx> { let u = self.tcx().anonymize_late_bound_regions(t); - ty_fold::super_fold_binder(self, &u) + ty::fold::super_fold_binder(self, &u) } fn fold_region(&mut self, r: ty::Region) -> ty::Region { @@ -1406,7 +1406,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { -> (T, FnvHashMap) where T : TypeFoldable<'tcx> { - ty_fold::replace_late_bound_regions( + ty::fold::replace_late_bound_regions( self.tcx, value, |br| self.next_region_var(LateBoundRegion(span, br, lbrct))) diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index d81f8e0ae9093..a62fd8890baf6 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -27,7 +27,7 @@ use middle::ty::{self, Ty, TypeError}; 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_relate::RelateResult; +use middle::ty::relate::RelateResult; use util::common::indenter; use util::nodemap::{FnvHashMap, FnvHashSet}; diff --git a/src/librustc/middle/infer/resolve.rs b/src/librustc/middle/infer/resolve.rs index 9cc9f148ce183..4bcceade77599 100644 --- a/src/librustc/middle/infer/resolve.rs +++ b/src/librustc/middle/infer/resolve.rs @@ -10,7 +10,7 @@ use super::{InferCtxt, FixupError, FixupResult}; use middle::ty::{self, Ty, HasTypeFlags}; -use middle::ty_fold::{self, TypeFoldable}; +use middle::ty::fold::{TypeFoldable}; /////////////////////////////////////////////////////////////////////////// // OPPORTUNISTIC TYPE RESOLVER @@ -30,7 +30,7 @@ impl<'a, 'tcx> OpportunisticTypeResolver<'a, 'tcx> { } } -impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for OpportunisticTypeResolver<'a, 'tcx> { +impl<'a, 'tcx> ty::fold::TypeFolder<'tcx> for OpportunisticTypeResolver<'a, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { self.infcx.tcx } @@ -40,7 +40,7 @@ impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for OpportunisticTypeResolver<'a, 'tcx> t // micro-optimize -- if there is nothing in this type that this fold affects... } else { let t0 = self.infcx.shallow_resolve(t); - ty_fold::super_fold_ty(self, t0) + ty::fold::super_fold_ty(self, t0) } } } @@ -69,7 +69,7 @@ struct FullTypeResolver<'a, 'tcx:'a> { err: Option, } -impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { +impl<'a, 'tcx> ty::fold::TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { self.infcx.tcx } @@ -98,7 +98,7 @@ impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { t)); } _ => { - ty_fold::super_fold_ty(self, t) + ty::fold::super_fold_ty(self, t) } } } diff --git a/src/librustc/middle/infer/sub.rs b/src/librustc/middle/infer/sub.rs index 4d76d613392ee..155f5f44002f4 100644 --- a/src/librustc/middle/infer/sub.rs +++ b/src/librustc/middle/infer/sub.rs @@ -15,7 +15,7 @@ use super::type_variable::{SubtypeOf, SupertypeOf}; use middle::ty::{self, Ty}; use middle::ty::TyVar; -use middle::ty_relate::{Cause, Relate, RelateResult, TypeRelation}; +use middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; use std::mem; /// "Greatest lower bound" (common subtype) diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index 7d8a20c42e36e..c44891de0a055 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -14,7 +14,7 @@ pub use self::ParamSpace::*; pub use self::RegionSubsts::*; use middle::ty::{self, Ty, HasTypeFlags, RegionEscape}; -use middle::ty_fold::{self, TypeFoldable, TypeFolder}; +use middle::ty::fold::{TypeFoldable, TypeFolder}; use std::fmt; use std::iter::IntoIterator; @@ -643,7 +643,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { self.ty_for_param(p, t) } _ => { - ty_fold::super_fold_ty(self, t) + ty::fold::super_fold_ty(self, t) } }; @@ -731,13 +731,13 @@ impl<'a,'tcx> SubstFolder<'a,'tcx> { return ty; } - let result = ty_fold::shift_regions(self.tcx(), self.region_binders_passed, &ty); + let result = ty::fold::shift_regions(self.tcx(), self.region_binders_passed, &ty); debug!("shift_regions: shifted result = {:?}", result); result } fn shift_region_through_binders(&self, region: ty::Region) -> ty::Region { - ty_fold::shift_region(region, self.region_binders_passed) + ty::fold::shift_region(region, self.region_binders_passed) } } diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs index a3a903c33933e..5322a571ed91e 100644 --- a/src/librustc/middle/traits/error_reporting.rs +++ b/src/librustc/middle/traits/error_reporting.rs @@ -27,7 +27,7 @@ use fmt_macros::{Parser, Piece, Position}; use middle::def_id::DefId; use middle::infer::InferCtxt; use middle::ty::{self, ToPredicate, HasTypeFlags, ToPolyTraitRef, TraitRef, Ty}; -use middle::ty_fold::TypeFoldable; +use middle::ty::fold::TypeFoldable; use std::collections::HashMap; use std::fmt; use syntax::codemap::Span; diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 99e12b7428d2a..6271dd211662e 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -10,7 +10,6 @@ use middle::infer::InferCtxt; use middle::ty::{self, RegionEscape, Ty, HasTypeFlags}; -use middle::wf; use std::fmt; use syntax::ast; @@ -496,8 +495,8 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, ObligationCauseCode::RFC1214(_) => true, _ => false, }; - match wf::obligations(selcx.infcx(), obligation.cause.body_id, - ty, obligation.cause.span, rfc1214) { + match ty::wf::obligations(selcx.infcx(), obligation.cause.body_id, + ty, obligation.cause.span, rfc1214) { Some(obligations) => { new_obligations.extend(obligations); true diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 667cad8fc88ae..6c581a701a27e 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -19,7 +19,7 @@ use middle::def_id::DefId; use middle::free_region::FreeRegionMap; use middle::subst; use middle::ty::{self, HasTypeFlags, Ty}; -use middle::ty_fold::TypeFoldable; +use middle::ty::fold::TypeFoldable; use middle::infer::{self, fixup_err_to_string, InferCtxt}; use std::rc::Rc; use syntax::ast; diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index cacefbb1a8551..0d320989cbc7f 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -24,7 +24,7 @@ use super::util; use middle::infer; use middle::subst::Subst; use middle::ty::{self, ToPredicate, RegionEscape, HasTypeFlags, ToPolyTraitRef, Ty}; -use middle::ty_fold::{self, TypeFoldable, TypeFolder}; +use middle::ty::fold::{TypeFoldable, TypeFolder}; use syntax::parse::token; use util::common::FN_OUTPUT_NAME; @@ -265,7 +265,7 @@ impl<'a,'b,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'b,'tcx> { // normalize it when we instantiate those bound regions (which // should occur eventually). - let ty = ty_fold::super_fold_ty(self, ty); + let ty = ty::fold::super_fold_ty(self, ty); match ty.sty { ty::TyProjection(ref data) if !data.has_escaping_regions() => { // (*) diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index ccdb271d43f85..6f422018c13d5 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -38,15 +38,13 @@ use super::object_safety; use super::util; use middle::def_id::{DefId, LOCAL_CRATE}; -use middle::fast_reject; -use middle::subst::{Subst, Substs, TypeSpace}; -use middle::ty::{self, ToPredicate, RegionEscape, ToPolyTraitRef, Ty, HasTypeFlags}; use middle::infer; use middle::infer::{InferCtxt, TypeFreshener}; -use middle::ty_fold::TypeFoldable; -use middle::ty_match; -use middle::ty_relate::TypeRelation; -use middle::wf; +use middle::subst::{Subst, Substs, TypeSpace}; +use middle::ty::{self, ToPredicate, RegionEscape, ToPolyTraitRef, Ty, HasTypeFlags}; +use middle::ty::fast_reject; +use middle::ty::fold::TypeFoldable; +use middle::ty::relate::TypeRelation; use std::cell::RefCell; use std::fmt; @@ -471,9 +469,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::Predicate::WellFormed(ty) => { - match wf::obligations(self.infcx, obligation.cause.body_id, - ty, obligation.cause.span, - obligation.cause.code.is_rfc1214()) { + match ty::wf::obligations(self.infcx, obligation.cause.body_id, + ty, obligation.cause.span, + obligation.cause.code.is_rfc1214()) { Some(obligations) => self.evaluate_predicates_recursively(previous_stack, obligations.iter()), None => @@ -2824,7 +2822,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { current: &ty::PolyTraitRef<'tcx>) -> bool { - let mut matcher = ty_match::Match::new(self.tcx()); + let mut matcher = ty::_match::Match::new(self.tcx()); matcher.relate(previous, current).is_ok() } diff --git a/src/librustc/middle/ty_match.rs b/src/librustc/middle/ty/_match.rs similarity index 94% rename from src/librustc/middle/ty_match.rs rename to src/librustc/middle/ty/_match.rs index 4aa0e553a7aa6..2ebb23369bd01 100644 --- a/src/librustc/middle/ty_match.rs +++ b/src/librustc/middle/ty/_match.rs @@ -9,7 +9,7 @@ // except according to those terms. use middle::ty::{self, Ty}; -use middle::ty_relate::{self, Relate, TypeRelation, RelateResult}; +use middle::ty::relate::{self, Relate, TypeRelation, RelateResult}; /// A type "A" *matches* "B" if the fresh types in B could be /// substituted with values so as to make it equal to A. Matching is @@ -73,7 +73,7 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Match<'a, 'tcx> { (&ty::TyInfer(_), _) | (_, &ty::TyInfer(_)) => { - Err(ty::TypeError::Sorts(ty_relate::expected_found(self, &a, &b))) + Err(ty::TypeError::Sorts(relate::expected_found(self, &a, &b))) } (&ty::TyError, _) | (_, &ty::TyError) => { @@ -81,7 +81,7 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Match<'a, 'tcx> { } _ => { - ty_relate::super_relate_tys(self, a, b) + relate::super_relate_tys(self, a, b) } } } diff --git a/src/librustc/middle/cast.rs b/src/librustc/middle/ty/cast.rs similarity index 100% rename from src/librustc/middle/cast.rs rename to src/librustc/middle/ty/cast.rs diff --git a/src/librustc/middle/fast_reject.rs b/src/librustc/middle/ty/fast_reject.rs similarity index 100% rename from src/librustc/middle/fast_reject.rs rename to src/librustc/middle/ty/fast_reject.rs diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty/fold.rs similarity index 100% rename from src/librustc/middle/ty_fold.rs rename to src/librustc/middle/ty/fold.rs diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty/mod.rs similarity index 99% rename from src/librustc/middle/ty.rs rename to src/librustc/middle/ty/mod.rs index 7f61526a8f903..21f068ca887a0 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty/mod.rs @@ -43,13 +43,11 @@ use front::map as ast_map; use front::map::LinkedPath; use metadata::csearch; use middle; -use middle::cast; 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_id::{DefId, LOCAL_CRATE}; -use middle::fast_reject; use middle::free_region::FreeRegionMap; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; use middle::region; @@ -62,8 +60,8 @@ use middle::stability; use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace}; use middle::traits; use middle::ty; -use middle::ty_fold::{self, TypeFoldable, TypeFolder}; -use middle::ty_walk::{self, TypeWalker}; +use middle::ty::fold::{TypeFoldable, TypeFolder}; +use middle::ty::walk::{TypeWalker}; use util::common::{memoized, ErrorReported}; use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet}; use util::nodemap::FnvHashMap; @@ -96,6 +94,15 @@ use rustc_front::hir::{ItemImpl, ItemTrait}; use rustc_front::hir::{MutImmutable, MutMutable, Visibility}; use rustc_front::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt}; +pub mod cast; +pub mod fast_reject; +pub mod fold; +pub mod _match; +pub mod outlives; +pub mod relate; +pub mod walk; +pub mod wf; + pub type Disr = u64; pub const INITIAL_DISCRIMINANT_VALUE: Disr = 0; @@ -4252,7 +4259,7 @@ impl<'tcx> TyS<'tcx> { /// `Foo, u32>` yields the sequence `[Bar, u32]` /// (but not `i32`, like `walk`). pub fn walk_shallow(&'tcx self) -> IntoIter> { - ty_walk::walk_shallow(self) + walk::walk_shallow(self) } pub fn as_opt_param_ty(&self) -> Option { @@ -6879,7 +6886,7 @@ impl<'tcx> ctxt<'tcx> { -> T where T : TypeFoldable<'tcx> { - ty_fold::replace_late_bound_regions( + fold::replace_late_bound_regions( self, value, |br| ty::ReFree(ty::FreeRegion{scope: all_outlive_scope, bound_region: br})).0 } @@ -6891,8 +6898,8 @@ impl<'tcx> ctxt<'tcx> { where T: TypeFoldable<'tcx> { let bound0_value = bound2_value.skip_binder().skip_binder(); - let value = ty_fold::fold_regions(self, bound0_value, &mut false, - |region, current_depth| { + 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 @@ -6922,7 +6929,7 @@ impl<'tcx> ctxt<'tcx> { pub fn erase_late_bound_regions(&self, value: &Binder) -> T where T : TypeFoldable<'tcx> { - ty_fold::replace_late_bound_regions(self, value, |_| ty::ReStatic).0 + fold::replace_late_bound_regions(self, value, |_| ty::ReStatic).0 } /// Rewrite any late-bound regions so that they are anonymous. Region numbers are @@ -6937,7 +6944,7 @@ impl<'tcx> ctxt<'tcx> { where T : TypeFoldable<'tcx>, { let mut counter = 0; - ty::Binder(ty_fold::replace_late_bound_regions(self, sig, |_| { + ty::Binder(fold::replace_late_bound_regions(self, sig, |_| { counter += 1; ReLateBound(ty::DebruijnIndex::new(1), BrAnon(counter)) }).0) diff --git a/src/librustc/middle/outlives.rs b/src/librustc/middle/ty/outlives.rs similarity index 100% rename from src/librustc/middle/outlives.rs rename to src/librustc/middle/ty/outlives.rs diff --git a/src/librustc/middle/ty_relate/mod.rs b/src/librustc/middle/ty/relate.rs similarity index 99% rename from src/librustc/middle/ty_relate/mod.rs rename to src/librustc/middle/ty/relate.rs index d2d612ece6f80..7baf075cc69ba 100644 --- a/src/librustc/middle/ty_relate/mod.rs +++ b/src/librustc/middle/ty/relate.rs @@ -16,7 +16,7 @@ use middle::def_id::DefId; use middle::subst::{ErasedRegions, NonerasedRegions, ParamSpace, Substs}; use middle::ty::{self, HasTypeFlags, Ty, TypeError}; -use middle::ty_fold::TypeFoldable; +use middle::ty::fold::TypeFoldable; use std::rc::Rc; use syntax::abi; use rustc_front::hir as ast; diff --git a/src/librustc/middle/ty_walk.rs b/src/librustc/middle/ty/walk.rs similarity index 100% rename from src/librustc/middle/ty_walk.rs rename to src/librustc/middle/ty/walk.rs diff --git a/src/librustc/middle/wf.rs b/src/librustc/middle/ty/wf.rs similarity index 99% rename from src/librustc/middle/wf.rs rename to src/librustc/middle/ty/wf.rs index 96942756b9882..20534f72666db 100644 --- a/src/librustc/middle/wf.rs +++ b/src/librustc/middle/ty/wf.rs @@ -10,7 +10,7 @@ use middle::def_id::DefId; use middle::infer::InferCtxt; -use middle::outlives::{self, Component}; +use middle::ty::outlives::{self, Component}; use middle::subst::Substs; use middle::traits; use middle::ty::{self, RegionEscape, ToPredicate, Ty}; @@ -544,4 +544,3 @@ pub fn object_region_bounds<'tcx>( tcx.required_region_bounds(open_ty, predicates) } - diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index a0701d852bc04..222de42643297 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -21,7 +21,7 @@ use middle::ty::{TyParam, TyRawPtr, TyRef, TyTuple}; 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::{self, TypeFoldable}; use std::fmt; use syntax::abi; @@ -219,7 +219,7 @@ fn in_binder<'tcx, T, U>(f: &mut fmt::Formatter, } }; - let new_value = ty_fold::replace_late_bound_regions(tcx, &value, |br| { + let new_value = fold::replace_late_bound_regions(tcx, &value, |br| { let _ = start_or_continue(f, "for<", ", "); ty::ReLateBound(ty::DebruijnIndex::new(1), match br { ty::BrNamed(_, name) => { @@ -255,7 +255,7 @@ fn in_binder<'tcx, T, U>(f: &mut fmt::Formatter, struct TraitAndProjections<'tcx>(ty::TraitRef<'tcx>, Vec>); impl<'tcx> TypeFoldable<'tcx> for TraitAndProjections<'tcx> { - fn fold_with>(&self, folder: &mut F) + fn fold_with>(&self, folder: &mut F) -> TraitAndProjections<'tcx> { TraitAndProjections(self.0.fold_with(folder), self.1.fold_with(folder)) } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index c96495fcfc986..96d9572b48591 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -24,7 +24,7 @@ use rustc_typeck::middle::stability; use rustc_typeck::middle::subst; use rustc_typeck::middle::subst::Subst; use rustc_typeck::middle::ty::{self, Ty, RegionEscape}; -use rustc_typeck::middle::ty_relate::TypeRelation; +use rustc_typeck::middle::ty::relate::TypeRelation; use rustc_typeck::middle::infer; use rustc_typeck::middle::infer::lub::Lub; use rustc_typeck::middle::infer::glb::Glb; diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 6843e4cab83e9..044e96db04de5 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -38,8 +38,7 @@ use trans::type_::Type; use trans::type_of; use middle::traits; use middle::ty::{self, HasTypeFlags, Ty}; -use middle::ty_fold; -use middle::ty_fold::{TypeFolder, TypeFoldable}; +use middle::ty::fold::{TypeFolder, TypeFoldable}; use rustc::front::map::{PathElem, PathName}; use rustc_front::hir; use util::nodemap::{FnvHashMap, NodeMap}; @@ -60,7 +59,7 @@ pub use trans::context::CrateContext; /// Returns an equivalent value with all free regions removed (note /// that late-bound regions remain, because they are important for /// subtyping, but they are anonymized and normalized as well). This -/// is a stronger, caching version of `ty_fold::erase_regions`. +/// is a stronger, caching version of `ty::fold::erase_regions`. pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T where T : TypeFoldable<'tcx> { @@ -80,7 +79,7 @@ pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T Some(u) => return u } - let t_norm = ty_fold::super_fold_ty(self, ty); + let t_norm = ty::fold::super_fold_ty(self, ty); self.tcx().normalized_cache.borrow_mut().insert(ty, t_norm); return t_norm; } @@ -89,7 +88,7 @@ pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T where T : TypeFoldable<'tcx> { let u = self.tcx().anonymize_late_bound_regions(t); - ty_fold::super_fold_binder(self, &u) + ty::fold::super_fold_binder(self, &u) } fn fold_region(&mut self, r: ty::Region) -> ty::Region { diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index a3ba174a6e5a4..c98760ce02a26 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -33,9 +33,9 @@ use trans::declare; use trans::monomorphize; use trans::type_::Type; use trans::type_of; -use middle::cast::{CastTy,IntTy}; use middle::subst::Substs; use middle::ty::{self, Ty}; +use middle::ty::cast::{CastTy,IntTy}; use util::nodemap::NodeMap; use rustc_front::hir; diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 3a7fa040e4f8c..59040b9cafef5 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -71,10 +71,10 @@ use trans::machine; use trans::meth; use trans::tvec; use trans::type_of; -use middle::cast::{CastKind, CastTy}; use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustUnsafeFnPointer}; use middle::ty::{self, Ty}; use middle::ty::MethodCall; +use middle::ty::cast::{CastKind, CastTy}; use util::common::indenter; use trans::machine::{llsize_of, llsize_of_alloc}; use trans::type_::Type; @@ -2045,8 +2045,8 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, id: ast::NodeId) -> DatumBlock<'blk, 'tcx, Expr> { - use middle::cast::CastTy::*; - use middle::cast::IntTy::*; + use middle::ty::cast::CastTy::*; + use middle::ty::cast::IntTy::*; fn int_cast(bcx: Block, lldsttype: Type, diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index ae425f29132fa..1ef9981a0a46a 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -17,7 +17,7 @@ use middle::infer; use middle::subst; use middle::subst::{Subst, Substs}; use middle::traits; -use middle::ty_fold::{TypeFolder, TypeFoldable}; +use middle::ty::fold::{TypeFolder, TypeFoldable}; use trans::attributes; use trans::base::{trans_enum_variant, push_ctxt, get_item_val}; use trans::base::trans_fn; diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index fb61f1ef42d7b..e6f9b1f9d6dec 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -53,13 +53,12 @@ use middle::const_eval::{self, ConstVal}; use middle::const_eval::EvalHint::UncheckedExprHint; use middle::def; use middle::def_id::{DefId, LOCAL_CRATE}; -use middle::wf::object_region_bounds; use middle::resolve_lifetime as rl; use middle::privacy::{AllPublic, LastMod}; use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs, ParamSpace}; use middle::traits; use middle::ty::{self, RegionEscape, Ty, ToPredicate, HasTypeFlags}; -use middle::ty_fold; +use middle::ty::wf::object_region_bounds; use require_c_abi_if_variadic; use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope, @@ -535,9 +534,9 @@ fn find_implied_output_region<'tcx>(tcx: &ty::ctxt<'tcx>, 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 = ty::fold::collect_regions(tcx, + input_type, + &mut regions); debug!("find_implied_output_regions: collected {:?} from {:?} \ have_bound_regions={:?}", ®ions, input_type, have_bound_regions); @@ -2249,7 +2248,7 @@ impl<'tcx> Bounds<'tcx> { for ®ion_bound in &self.region_bounds { // account for the binder being introduced below; no need to shift `param_ty` // because, at present at least, it can only refer to early-bound regions - let region_bound = ty_fold::shift_region(region_bound, 1); + let region_bound = ty::fold::shift_region(region_bound, 1); vec.push(ty::Binder(ty::OutlivesPredicate(param_ty, region_bound)).to_predicate()); } diff --git a/src/librustc_typeck/check/assoc.rs b/src/librustc_typeck/check/assoc.rs index c80c48a96922d..8dc95562e44af 100644 --- a/src/librustc_typeck/check/assoc.rs +++ b/src/librustc_typeck/check/assoc.rs @@ -12,7 +12,7 @@ use middle::infer::InferCtxt; use middle::traits::{self, FulfillmentContext, Normalized, MiscObligation, SelectionContext, ObligationCause}; use middle::ty::HasTypeFlags; -use middle::ty_fold::TypeFoldable; +use middle::ty::fold::TypeFoldable; use syntax::ast; use syntax::codemap::Span; diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 799a3e86a7519..98c8c0a319946 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -44,9 +44,9 @@ use super::FnCtxt; use super::structurally_resolved_type; use lint; -use middle::cast::{CastKind, CastTy}; use middle::def_id::DefId; use middle::ty::{self, Ty, HasTypeFlags}; +use middle::ty::cast::{CastKind, CastTy}; use syntax::codemap::Span; use rustc_front::hir; use rustc_front::hir::UintTy::TyU8; @@ -226,8 +226,8 @@ impl<'tcx> CastCheck<'tcx> { /// can return Ok and create type errors in the fcx rather than returning /// directly. coercion-cast is handled in check instead of here. fn do_check<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result { - use middle::cast::IntTy::*; - use middle::cast::CastTy::*; + use middle::ty::cast::IntTy::*; + use middle::ty::cast::CastTy::*; let (t_from, t_cast) = match (CastTy::from_ty(self.expr_ty), CastTy::from_ty(self.cast_ty)) { diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 65409afa52d10..d3a292676c5ef 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -67,7 +67,7 @@ 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_relate::RelateResult; +use middle::ty::relate::RelateResult; use util::common::indent; use std::cell::RefCell; diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index d1f898d82fdd3..e7c7b5831d0fc 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -17,7 +17,7 @@ use middle::def_id::DefId; use middle::subst; use middle::ty::FnSig; use middle::ty::{self, Ty}; -use middle::ty_fold::TypeFolder; +use middle::ty::fold::TypeFolder; use {CrateCtxt, require_same_types}; use std::collections::{HashMap}; diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 040e644a94d1f..048a2b62bcaa3 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -16,7 +16,7 @@ use middle::def_id::DefId; use middle::subst::{self}; use middle::traits; use middle::ty::{self, NoPreference, PreferMutLvalue, Ty}; -use middle::ty_fold::TypeFoldable; +use middle::ty::fold::TypeFoldable; use middle::infer; use middle::infer::InferCtxt; use syntax::codemap::Span; diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index b04899f5ecdc7..f65602d9aaccb 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -16,13 +16,12 @@ use super::suggest; use check; use check::{FnCtxt, UnresolvedTypeAction}; use middle::def_id::DefId; -use middle::fast_reject; use middle::subst; use middle::subst::Subst; use middle::traits; use middle::ty::{self, NoPreference, RegionEscape, Ty, ToPolyTraitRef, TraitRef}; use middle::ty::HasTypeFlags; -use middle::ty_fold::TypeFoldable; +use middle::ty::fold::TypeFoldable; use middle::infer; use middle::infer::InferCtxt; use syntax::ast; @@ -41,7 +40,7 @@ struct ProbeContext<'a, 'tcx:'a> { mode: Mode, item_name: ast::Name, steps: Rc>>, - opt_simplified_steps: Option>, + opt_simplified_steps: Option>, inherent_candidates: Vec>, extension_candidates: Vec>, impl_dups: HashSet, @@ -163,7 +162,7 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Create a list of simplified self types, if we can. let mut simplified_steps = Vec::new(); for step in &steps { - match fast_reject::simplify_type(fcx.tcx(), step.self_ty, true) { + match ty::fast_reject::simplify_type(fcx.tcx(), step.self_ty, true) { None => { break; } Some(simplified_type) => { simplified_steps.push(simplified_type); } } @@ -236,7 +235,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { mode: Mode, item_name: ast::Name, steps: Vec>, - opt_simplified_steps: Option>) + opt_simplified_steps: Option>) -> ProbeContext<'a,'tcx> { ProbeContext { @@ -684,7 +683,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { let impl_type = self.tcx().lookup_item_type(impl_def_id); let impl_simplified_type = - match fast_reject::simplify_type(self.tcx(), impl_type.ty, false) { + match ty::fast_reject::simplify_type(self.tcx(), impl_type.ty, false) { Some(simplified_type) => simplified_type, None => { return true; } }; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b1fbf97d1a74b..dc433786ae4d6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -97,7 +97,7 @@ use middle::ty::{Disr, ParamTy, ParameterEnvironment}; use middle::ty::{LvaluePreference, NoPreference, PreferMutLvalue}; use middle::ty::{self, HasTypeFlags, RegionEscape, ToPolyTraitRef, Ty}; use middle::ty::{MethodCall, MethodCallee}; -use middle::ty_fold::{TypeFolder, TypeFoldable}; +use middle::ty::fold::{TypeFolder, TypeFoldable}; use require_c_abi_if_variadic; use rscope::{ElisionFailureInfo, RegionScope}; use session::Session; diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 844e143b9fa5b..b6ff7b529c556 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -88,14 +88,13 @@ use check::FnCtxt; use middle::free_region::FreeRegionMap; use middle::implicator::{self, Implication}; use middle::mem_categorization as mc; -use middle::outlives; use middle::region::CodeExtent; use middle::subst::Substs; use middle::traits; use middle::ty::{self, RegionEscape, ReScope, Ty, MethodCall, HasTypeFlags}; use middle::infer::{self, GenericKind, InferCtxt, SubregionOrigin, VerifyBound}; use middle::pat_util; -use middle::wf::{self, ImpliedBound}; +use middle::ty::wf::ImpliedBound; use std::mem; use std::rc::Rc; @@ -420,7 +419,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { for &ty in fn_sig_tys { let ty = self.resolve_type(ty); debug!("relate_free_regions(t={:?})", ty); - let implied_bounds = wf::implied_bounds(self.fcx.infcx(), body_id, ty, span); + let implied_bounds = ty::wf::implied_bounds(self.fcx.infcx(), body_id, ty, span); // Record any relations between free regions that we observe into the free-region-map. self.free_region_map.relate_free_regions_from_implied_bounds(&implied_bounds); @@ -1527,31 +1526,31 @@ pub fn type_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, assert!(!ty.has_escaping_regions()); - let components = outlives::components(rcx.infcx(), ty); + let components = ty::outlives::components(rcx.infcx(), ty); components_must_outlive(rcx, origin, components, region); } fn components_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, origin: infer::SubregionOrigin<'tcx>, - components: Vec>, + components: Vec>, region: ty::Region) { for component in components { let origin = origin.clone(); match component { - outlives::Component::Region(region1) => { + ty::outlives::Component::Region(region1) => { rcx.fcx.mk_subr(origin, region, region1); } - outlives::Component::Param(param_ty) => { + ty::outlives::Component::Param(param_ty) => { param_ty_must_outlive(rcx, origin, region, param_ty); } - outlives::Component::Projection(projection_ty) => { + ty::outlives::Component::Projection(projection_ty) => { projection_must_outlive(rcx, origin, region, projection_ty); } - outlives::Component::EscapingProjection(subcomponents) => { + ty::outlives::Component::EscapingProjection(subcomponents) => { components_must_outlive(rcx, origin, subcomponents, region); } - outlives::Component::UnresolvedInferenceVariable(v) => { + ty::outlives::Component::UnresolvedInferenceVariable(v) => { // ignore this, we presume it will yield an error // later, since if a type variable is not resolved by // this point it never will be @@ -1559,7 +1558,7 @@ fn components_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, origin.span(), &format!("unresolved inference variable in outlives: {:?}", v)); } - outlives::Component::RFC1214(subcomponents) => { + ty::outlives::Component::RFC1214(subcomponents) => { let suborigin = infer::RFC1214Subregion(Rc::new(origin)); components_must_outlive(rcx, suborigin, subcomponents, region); } diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index 99cb12813077c..2c931e7830d59 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -17,7 +17,7 @@ use middle::region; use middle::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace}; use middle::traits; use middle::ty::{self, Ty}; -use middle::ty_fold::{TypeFolder, TypeFoldable, super_fold_ty}; +use middle::ty::fold::{TypeFolder, TypeFoldable, super_fold_ty}; use std::cell::RefCell; use std::collections::HashSet; diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index a53f15ce2aa84..06dd80c57ada8 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -16,8 +16,7 @@ use middle::def_id::DefId; use middle::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace}; use middle::traits; use middle::ty::{self, Ty}; -use middle::ty_fold::{TypeFolder}; -use middle::wf; +use middle::ty::fold::{TypeFolder}; use std::cell::RefCell; use std::collections::HashSet; @@ -309,11 +308,11 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { fcx.instantiate_type_scheme( ast_trait_ref.path.span, free_substs, &trait_ref); let obligations = - wf::trait_obligations(fcx.infcx(), - fcx.body_id, - &trait_ref, - ast_trait_ref.path.span, - true); + ty::wf::trait_obligations(fcx.infcx(), + fcx.body_id, + &trait_ref, + ast_trait_ref.path.span, + true); for obligation in obligations { fcx.register_predicate(obligation); } @@ -341,11 +340,11 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { let obligations = predicates.predicates .iter() - .flat_map(|p| wf::predicate_obligations(fcx.infcx(), - fcx.body_id, - p, - span, - true)); + .flat_map(|p| ty::wf::predicate_obligations(fcx.infcx(), + fcx.body_id, + p, + span, + true)); for obligation in obligations { fcx.register_predicate(obligation); diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 94c01eb70e88a..de841a0cc0022 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -18,7 +18,7 @@ use check::FnCtxt; use middle::def_id::DefId; use middle::pat_util; use middle::ty::{self, Ty, MethodCall, MethodCallee}; -use middle::ty_fold::{TypeFolder,TypeFoldable}; +use middle::ty::fold::{TypeFolder,TypeFoldable}; use middle::infer; use write_substs_to_tcx; use write_ty_to_tcx; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index f0b68e5e9025f..930eb431f4957 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -78,7 +78,7 @@ use middle::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerPar use middle::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty, TypeScheme, IntTypeExt}; use middle::ty::{VariantKind}; -use middle::ty_fold::{self, TypeFolder, TypeFoldable}; +use middle::ty::fold::{TypeFolder, TypeFoldable}; use middle::infer; use rscope::*; use rustc::front::map as hir_map; @@ -2374,7 +2374,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( * before we really have a `ParameterEnvironment` to check. */ - ty_fold::fold_regions(tcx, value, &mut false, |region, _| { + ty::fold::fold_regions(tcx, value, &mut false, |region, _| { match region { ty::ReEarlyBound(data) => { let def_id = DefId::local(data.param_id); diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index 28403ab22826c..1b02c736dce3b 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -10,7 +10,6 @@ use middle::ty; -use middle::ty_fold; use std::cell::Cell; use syntax::codemap::Span; @@ -239,11 +238,11 @@ impl<'r> ShiftedRscope<'r> { impl<'r> RegionScope for ShiftedRscope<'r> { fn object_lifetime_default(&self, span: Span) -> Option { self.base_scope.object_lifetime_default(span) - .map(|r| ty_fold::shift_region(r, 1)) + .map(|r| ty::fold::shift_region(r, 1)) } fn base_object_lifetime_default(&self, span: Span) -> ty::Region { - ty_fold::shift_region(self.base_scope.base_object_lifetime_default(span), 1) + ty::fold::shift_region(self.base_scope.base_object_lifetime_default(span), 1) } fn anon_regions(&self, @@ -254,7 +253,7 @@ impl<'r> RegionScope for ShiftedRscope<'r> { match self.base_scope.anon_regions(span, count) { Ok(mut v) => { for r in &mut v { - *r = ty_fold::shift_region(*r, 1); + *r = ty::fold::shift_region(*r, 1); } Ok(v) } From 5f564fbbe46ee609e841062dad1817f17f90943c Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 6 Sep 2015 21:51:58 +0300 Subject: [PATCH 2/4] split ty.rs into smaller parts --- src/librustc/middle/infer/combine.rs | 11 +- src/librustc/middle/infer/error_reporting.rs | 27 +- .../middle/infer/higher_ranked/mod.rs | 11 +- src/librustc/middle/infer/mod.rs | 39 +- .../middle/infer/region_inference/mod.rs | 5 +- src/librustc/middle/traits/mod.rs | 2 +- src/librustc/middle/traits/project.rs | 2 +- src/librustc/middle/ty/_match.rs | 3 +- src/librustc/middle/ty/contents.rs | 269 ++ src/librustc/middle/ty/context.rs | 964 +++++ src/librustc/middle/ty/error.rs | 342 ++ src/librustc/middle/ty/flags.rs | 205 + src/librustc/middle/ty/fold.rs | 585 +-- src/librustc/middle/ty/ivar.rs | 72 + src/librustc/middle/ty/mod.rs | 3748 +---------------- src/librustc/middle/ty/relate.rs | 13 +- src/librustc/middle/ty/structural_impls.rs | 895 ++++ src/librustc/middle/ty/sty.rs | 1129 +++++ src/librustc/util/ppaux.rs | 155 +- src/librustc_typeck/astconv.rs | 4 +- src/librustc_typeck/check/coercion.rs | 3 +- src/librustc_typeck/check/demand.rs | 2 +- src/librustc_typeck/check/mod.rs | 20 +- src/librustc_typeck/coherence/mod.rs | 2 +- src/librustc_typeck/collect.rs | 2 +- 25 files changed, 4355 insertions(+), 4155 deletions(-) create mode 100644 src/librustc/middle/ty/contents.rs create mode 100644 src/librustc/middle/ty/context.rs create mode 100644 src/librustc/middle/ty/error.rs create mode 100644 src/librustc/middle/ty/flags.rs create mode 100644 src/librustc/middle/ty/ivar.rs create mode 100644 src/librustc/middle/ty/structural_impls.rs create mode 100644 src/librustc/middle/ty/sty.rs diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index 3a29fdfae2307..2447a8cee7bbb 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -43,7 +43,8 @@ use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf}; 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}; @@ -362,12 +363,12 @@ impl<'cx, 'tcx> ty::fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> { pub trait RelateResultCompare<'tcx, T> { fn compare(&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(&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 { @@ -380,7 +381,7 @@ impl<'tcx, T:Clone + PartialEq> RelateResultCompare<'tcx, T> for RelateResult<'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)) @@ -388,7 +389,7 @@ fn int_unification_error<'tcx>(a_is_expected: bool, v: (ty::IntVarValue, ty::Int 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)) diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 7ec39ac851574..f0fa7d7cdf851 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -82,8 +82,9 @@ use middle::def_id::DefId; 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; @@ -225,19 +226,19 @@ pub trait ErrorReporting<'tcx> { fn process_errors(&self, errors: &Vec>) -> Vec>; - 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; fn expected_found_str + HasTypeFlags>( &self, - exp_found: &ty::ExpectedFound) + exp_found: &ty::error::ExpectedFound) -> Option; fn report_concrete_failure(&self, @@ -266,7 +267,7 @@ pub trait ErrorReporting<'tcx> { 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]); @@ -473,7 +474,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { } } - 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 => { @@ -497,7 +498,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { } /// 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 @@ -520,7 +521,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { } }; 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) { @@ -533,7 +534,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { _ => () } }, - 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); }, @@ -543,7 +544,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { 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); @@ -561,7 +562,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { fn expected_found_str + HasTypeFlags>( &self, - exp_found: &ty::ExpectedFound) + exp_found: &ty::error::ExpectedFound) -> Option { let expected = exp_found.expected.resolve(self); @@ -975,7 +976,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { 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()); diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index 10a31f0e657e5..b0fce71d3f061 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -14,7 +14,8 @@ 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; @@ -358,7 +359,7 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>, 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 @@ -438,7 +439,7 @@ impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> { 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| { @@ -468,7 +469,7 @@ pub fn skolemize_late_bound_regions<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, * 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) }); @@ -590,7 +591,7 @@ pub fn plug_leaks<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, // 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) => { diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 5b94f5311fd0f..b9e9ee5e24497 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -30,8 +30,9 @@ use middle::subst::Substs; 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}; @@ -171,9 +172,9 @@ impl fmt::Display for TypeOrigin { /// See `error_reporting.rs` for more details #[derive(Clone, Debug)] pub enum ValuePairs<'tcx> { - Types(ty::ExpectedFound>), - TraitRefs(ty::ExpectedFound>), - PolyTraitRefs(ty::ExpectedFound>), + Types(ExpectedFound>), + TraitRefs(ExpectedFound>), + PolyTraitRefs(ExpectedFound>), } /// The trace designates the path through inference that we took to @@ -479,12 +480,12 @@ pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, fn expected_found(a_is_expected: bool, a: T, b: T) - -> ty::ExpectedFound + -> ExpectedFound { 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} } } @@ -656,7 +657,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } 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) { @@ -1312,7 +1314,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { sp: Span, mk_msg: M, actual_ty: String, - err: Option<&ty::TypeError<'tcx>>) where + err: Option<&TypeError<'tcx>>) where M: FnOnce(Option, String) -> String, { self.type_error_message_str_with_expected(sp, mk_msg, None, actual_ty, err) @@ -1323,7 +1325,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { mk_msg: M, expected_ty: Option>, actual_ty: String, - err: Option<&ty::TypeError<'tcx>>) where + err: Option<&TypeError<'tcx>>) where M: FnOnce(Option, String) -> String, { debug!("hi! expected_ty = {:?}, actual_ty = {}", expected_ty, actual_ty); @@ -1349,7 +1351,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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); @@ -1368,10 +1370,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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 }) @@ -1385,14 +1387,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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 })); @@ -1406,8 +1408,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { -> (T, FnvHashMap) 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))) } @@ -1555,7 +1556,7 @@ impl<'tcx> TypeTrace<'tcx> { 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, }) diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index a62fd8890baf6..1fc5294877065 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -23,10 +23,11 @@ use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable}; 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}; @@ -157,7 +158,7 @@ pub enum RegionResolutionError<'tcx> { /// should put a lifetime. In those cases we process and put those errors /// into `ProcessedErrors` before we do any reporting. ProcessedErrors(Vec, - Vec<(TypeTrace<'tcx>, ty::TypeError<'tcx>)>, + Vec<(TypeTrace<'tcx>, TypeError<'tcx>)>, Vec), } diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 6c581a701a27e..a79837e7fb14f 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -168,7 +168,7 @@ pub enum SelectionError<'tcx> { Unimplemented, OutputTypeParameterMismatch(ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>, - ty::TypeError<'tcx>), + ty::error::TypeError<'tcx>), TraitNotObjectSafe(DefId), } diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index 0d320989cbc7f..f13b81ccdb22f 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -51,7 +51,7 @@ pub enum ProjectionTyError<'tcx> { #[derive(Clone)] pub struct MismatchedProjectionTypes<'tcx> { - pub err: ty::TypeError<'tcx> + pub err: ty::error::TypeError<'tcx> } #[derive(PartialEq, Eq, Debug)] diff --git a/src/librustc/middle/ty/_match.rs b/src/librustc/middle/ty/_match.rs index 2ebb23369bd01..5a3ad9095ad2c 100644 --- a/src/librustc/middle/ty/_match.rs +++ b/src/librustc/middle/ty/_match.rs @@ -9,6 +9,7 @@ // 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 @@ -73,7 +74,7 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Match<'a, 'tcx> { (&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) => { diff --git a/src/librustc/middle/ty/contents.rs b/src/librustc/middle/ty/contents.rs new file mode 100644 index 0000000000000..bcce9e8ea5476 --- /dev/null +++ b/src/librustc/middle/ty/contents.rs @@ -0,0 +1,269 @@ +// 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 or the MIT license +// , 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(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, 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>, ... } + // + // 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 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 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 + } + } + } +} diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs new file mode 100644 index 0000000000000..4d57e0980ef54 --- /dev/null +++ b/src/librustc/middle/ty/context.rs @@ -0,0 +1,964 @@ +// 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 or the MIT license +// , 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>, + substs: TypedArena>, + bare_fn: TypedArena>, + region: TypedArena, + stability: TypedArena, + + // references + trait_defs: TypedArena>, + adt_defs: TypedArena>, +} + +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>, + + /// 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>, + + pub adjustments: NodeMap>, + + 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>, + + /// Records the type of each closure. The def ID is the ID of the + /// expression defining the closure. + pub closure_kinds: DefIdMap, +} + +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>, + interner: &RefCell, 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> when equivalent keys can + // queried from a HashSet. + interner: RefCell, Ty<'tcx>>>, + + // FIXME as above, use a hashset if equivalent elements can be queried. + substs_interner: RefCell, &'tcx Substs<'tcx>>>, + bare_fn_interner: RefCell, &'tcx BareFnTy<'tcx>>>, + region_interner: RefCell>, + stability_interner: RefCell>, + + /// 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>, + // FIXME: jroesch make this a refcell + + pub tables: RefCell>, + + /// Maps from a trait item to the trait item "descriptor" + pub impl_or_trait_items: RefCell>>, + + /// Maps from a trait def-id to a list of the def-ids of its trait items + pub trait_item_def_ids: RefCell>>>, + + /// A cache for the trait_items() routine + pub trait_items_cache: RefCell>>>>, + + pub impl_trait_refs: RefCell>>>, + pub trait_defs: RefCell>>, + pub adt_defs: RefCell>>, + + /// Maps from the def-id of an item (trait/struct/enum/fn) to its + /// associated predicates. + pub predicates: RefCell>>, + + /// 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>>, + + pub map: ast_map::Map<'tcx>, + pub freevars: RefCell, + pub tcache: RefCell>>, + pub rcache: RefCell>>, + pub tc_cache: RefCell, ty::contents::TypeContents>>, + pub ast_ty_to_ty_cache: RefCell>>, + pub ty_param_defs: RefCell>>, + pub normalized_cache: RefCell, 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>, + + /// Maps from def-id of a type or region parameter to its + /// (inferred) variance. + pub item_variance_map: RefCell>>, + + /// True if the variance has been computed yet; false otherwise. + pub variance_computed: Cell, + + /// A method will be in this list if and only if it is a destructor. + pub destructors: RefCell, + + /// 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>>>, + + /// 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>>, + + /// Set of used unsafe nodes (functions or blocks). Unsafe nodes not + /// present in this set can be warned about. + pub used_unsafe: RefCell, + + /// 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, + + /// The set of external nominal types whose implementations have been read. + /// This is used for lazy resolution of methods. + pub populated_external_types: RefCell, + /// 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, + + /// These caches are used by const_eval when decoding external constants. + pub extern_const_statics: RefCell>, + pub extern_const_variants: RefCell>, + pub extern_const_fns: RefCell>, + + pub node_lint_levels: RefCell>, + + /// 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>>, + + /// Maps any item's def-id to its stability index. + pub stability: RefCell>, + + /// 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>, + + /// Caches the representation hints for struct definitions. + pub repr_hint_cache: RefCell>>>, + + /// Maps Expr NodeId's to their constant qualification. + pub const_qualif_map: RefCell>, + + /// Caches CoerceUnsized kinds for impls on custom types. + pub custom_coerce_unsized_kinds: RefCell>, + + /// 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>, + + /// 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>>, +} +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>> { + fn projection<'a, 'tcx>(tables: &'a Tables<'tcx>) -> &'a NodeMap> { + &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::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>(&self, value: &T) -> Option { + 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(s: Session, + arenas: &'tcx CtxtArenas<'tcx>, + def_map: DefMap, + named_region_map: resolve_lifetime::NamedRegionMap, + map: ast_map::Map<'tcx>, + freevars: RefCell, + 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; +} + +impl<'a, 'tcx> Lift<'tcx> for Ty<'a> { + type Lifted = Ty<'tcx>; + fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option> { + 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 R, R>(f: F) -> R { + TLS_TCX.with(|tcx| f(unsafe { &*(tcx as *const _ as *const ty::ctxt) })) + } + + pub fn with_opt) -> 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(&self, s: &mut H) { + self.ty.sty.hash(s) + } +} + +impl<'tcx> Borrow> 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>, + interner: &RefCell, 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> { + 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, + 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> { + 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>) + -> 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) + } +} diff --git a/src/librustc/middle/ty/error.rs b/src/librustc/middle/ty/error.rs new file mode 100644 index 0000000000000..72c4366c5bcd5 --- /dev/null +++ b/src/librustc/middle/ty/error.rs @@ -0,0 +1,342 @@ +// 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 or the MIT license +// , 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 { + pub expected: T, + pub found: T +} + +// Data structures used in type unification +#[derive(Clone, Debug)] +pub enum TypeError<'tcx> { + Mismatch, + UnsafetyMismatch(ExpectedFound), + AbiMismatch(ExpectedFound), + Mutability, + BoxMutability, + PtrMutability, + RefMutability, + VecMutability, + TupleSize(ExpectedFound), + FixedArraySize(ExpectedFound), + TyParamSize(ExpectedFound), + ArgCount, + RegionsDoesNotOutlive(Region, Region), + RegionsNotSame(Region, Region), + RegionsNoOverlap(Region, Region), + RegionsInsufficientlyPolymorphic(BoundRegion, Region), + RegionsOverlyPolymorphic(BoundRegion, Region), + Sorts(ExpectedFound>), + IntegerAsChar, + IntMismatch(ExpectedFound), + FloatMismatch(ExpectedFound), + Traits(ExpectedFound), + BuiltinBoundsMismatch(ExpectedFound), + VariadicMismatch(ExpectedFound), + CyclicTy, + ConvergenceMismatch(ExpectedFound), + ProjectionNameMismatched(ExpectedFound), + ProjectionBoundsLength(ExpectedFound), + TyParamDefaultMismatch(ExpectedFound>) +} + +#[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")); + } + _ => {} + } + } +} diff --git a/src/librustc/middle/ty/flags.rs b/src/librustc/middle/ty/flags.rs new file mode 100644 index 0000000000000..94a50e3cac7f7 --- /dev/null +++ b/src/librustc/middle/ty/flags.rs @@ -0,0 +1,205 @@ +// 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 or the MIT license +// , 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); + } +} diff --git a/src/librustc/middle/ty/fold.rs b/src/librustc/middle/ty/fold.rs index c6d213583af20..9de58369a63f8 100644 --- a/src/librustc/middle/ty/fold.rs +++ b/src/librustc/middle/ty/fold.rs @@ -34,16 +34,11 @@ //! 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}; /////////////////////////////////////////////////////////////////////////// @@ -74,7 +69,7 @@ pub trait TypeFolder<'tcx> : Sized { /// track the Debruijn index nesting level. fn exit_region_binder(&mut self) { } - fn fold_binder(&mut self, t: &ty::Binder) -> ty::Binder + fn fold_binder(&mut self, t: &Binder) -> Binder where T : TypeFoldable<'tcx> { // FIXME(#20526) this should replace `enter_region_binder`/`exit_region_binder`. @@ -142,428 +137,18 @@ pub trait TypeFolder<'tcx> : Sized { } } -/////////////////////////////////////////////////////////////////////////// -// 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>(&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>(&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 { - fn fold_with>(&self, folder: &mut F) -> Option { - self.as_ref().map(|t| t.fold_with(folder)) - } -} - -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc { - fn fold_with>(&self, folder: &mut F) -> Rc { - Rc::new((**self).fold_with(folder)) - } -} - -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box { - fn fold_with>(&self, folder: &mut F) -> Box { - let content: T = (**self).fold_with(folder); - box content - } -} - -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec { - fn fold_with>(&self, folder: &mut F) -> Vec { - self.iter().map(|t| t.fold_with(folder)).collect() - } -} - -impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder { - fn fold_with>(&self, folder: &mut F) -> ty::Binder { - folder.fold_binder(self) - } -} - -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for OwnedSlice { - fn fold_with>(&self, folder: &mut F) -> OwnedSlice { - self.iter().map(|t| t.fold_with(folder)).collect() - } -} - -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for VecPerParamSpace { - fn fold_with>(&self, folder: &mut F) -> VecPerParamSpace { - - // 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>(&self, folder: &mut F) -> Ty<'tcx> { - folder.fold_ty(*self) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::BareFnTy<'tcx> { - fn fold_with>(&self, folder: &mut F) -> ty::BareFnTy<'tcx> { - folder.fold_bare_fn_ty(self) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::ClosureTy<'tcx> { - fn fold_with>(&self, folder: &mut F) -> ty::ClosureTy<'tcx> { - folder.fold_closure_ty(self) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> { - fn fold_with>(&self, folder: &mut F) -> ty::TypeAndMut<'tcx> { - folder.fold_mt(self) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::FnOutput<'tcx> { - fn fold_with>(&self, folder: &mut F) -> ty::FnOutput<'tcx> { - folder.fold_output(self) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> { - fn fold_with>(&self, folder: &mut F) -> ty::FnSig<'tcx> { - folder.fold_fn_sig(self) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> { - fn fold_with>(&self, folder: &mut F) -> ty::TraitRef<'tcx> { - folder.fold_trait_ref(self) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::Region { - fn fold_with>(&self, folder: &mut F) -> ty::Region { - folder.fold_region(*self) - } -} - -impl<'tcx> TypeFoldable<'tcx> for subst::Substs<'tcx> { - fn fold_with>(&self, folder: &mut F) -> subst::Substs<'tcx> { - folder.fold_substs(self) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> { - fn fold_with>(&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>(&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>(&self, folder: &mut F) -> ty::AutoRef<'tcx> { - folder.fold_autoref(self) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::BuiltinBounds { - fn fold_with>(&self, _folder: &mut F) -> ty::BuiltinBounds { - *self - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialBounds<'tcx> { - fn fold_with>(&self, folder: &mut F) -> ty::ExistentialBounds<'tcx> { - folder.fold_existential_bounds(self) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> { - fn fold_with>(&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>(&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>(&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>(&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>(&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>(&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>(&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>(&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>(&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>(&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>(&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>(&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 { - fn fold_with>(&self, folder: &mut F) -> traits::VtableDefaultImplData { - 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 { - fn fold_with>(&self, folder: &mut F) -> traits::VtableBuiltinData { - traits::VtableBuiltinData { - nested: self.nested.fold_with(folder), - } - } -} - -impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> { - fn fold_with>(&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>(&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>(&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>(&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 - where T : TypeFoldable<'tcx>, - U : TypeFoldable<'tcx>, -{ - fn fold_with>(&self, folder: &mut F) -> ty::OutlivesPredicate { - ty::OutlivesPredicate(self.0.fold_with(folder), - self.1.fold_with(folder)) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::ClosureUpvar<'tcx> { - fn fold_with>(&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>(&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) - -> ty::Binder + binder: &Binder) + -> Binder 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 } @@ -754,6 +339,36 @@ impl<'a, 'tcx, F> TypeFolder<'tcx> for BottomUpFolder<'a, 'tcx, F> where /////////////////////////////////////////////////////////////////////////// // 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(&self, + value: &T, + region_set: &mut FnvHashSet) + -> 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(&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. /// @@ -785,33 +400,6 @@ impl<'a, 'tcx> RegionFolder<'a, 'tcx> { } } -/// 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) -> 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 } @@ -853,6 +441,94 @@ struct RegionReplacer<'a, 'tcx: 'a> { map: FnvHashMap } +impl<'tcx> ty::ctxt<'tcx> { + pub fn replace_late_bound_regions(&self, + value: &Binder, + mut f: F) + -> (T, FnvHashMap) + 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(&self, + all_outlive_scope: region::CodeExtent, + value: &Binder) + -> 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(&self, bound2_value: &Binder>) + -> Binder + 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(&self, value: &Binder) -> Option + 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(&self, value: &Binder) -> 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(&self, sig: &Binder) -> Binder + 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(tcx: &'a ty::ctxt<'tcx>, fld_r: &'a mut F) -> RegionReplacer<'a, 'tcx> where F : FnMut(ty::BoundRegion) -> ty::Region @@ -866,19 +542,6 @@ impl<'a, 'tcx> RegionReplacer<'a, 'tcx> { } } -pub fn replace_late_bound_regions<'tcx,T,F>(tcx: &ty::ctxt<'tcx>, - value: &ty::Binder, - mut f: F) - -> (T, FnvHashMap) - 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 } diff --git a/src/librustc/middle/ty/ivar.rs b/src/librustc/middle/ty/ivar.rs new file mode 100644 index 0000000000000..73d567d0acf40 --- /dev/null +++ b/src/librustc/middle/ty/ivar.rs @@ -0,0 +1,72 @@ +// 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 or the MIT license +// , 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>>, + PhantomData)->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> { + 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()") + } + } +} diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs index 21f068ca887a0..ab1160d7deb02 100644 --- a/src/librustc/middle/ty/mod.rs +++ b/src/librustc/middle/ty/mod.rs @@ -1,4 +1,4 @@ -// 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. // @@ -8,10 +8,6 @@ // 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::*; @@ -20,71 +16,44 @@ pub use self::Representability::*; 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}; @@ -94,7 +63,31 @@ use rustc_front::hir::{ItemImpl, ItemTrait}; 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; @@ -103,6 +96,13 @@ pub mod relate; 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; @@ -421,13 +421,6 @@ pub struct AssociatedType<'tcx> { 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, @@ -442,17 +435,6 @@ pub enum Variance { Bivariant, // T <: T -- 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 @@ -638,275 +620,6 @@ pub struct TransmuteRestriction<'tcx> { pub id: NodeId, } -/// Internal storage -pub struct CtxtArenas<'tcx> { - // internings - type_: TypedArena>, - substs: TypedArena>, - bare_fn: TypedArena>, - region: TypedArena, - stability: TypedArena, - - // references - trait_defs: TypedArena>, - adt_defs: TypedArena>, -} - -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>, - - /// 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>, - - pub adjustments: NodeMap>, - - 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>, - - /// Records the type of each closure. The def ID is the ID of the - /// expression defining the closure. - pub closure_kinds: DefIdMap, -} - -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> when equivalent keys can - // queried from a HashSet. - interner: RefCell, Ty<'tcx>>>, - - // FIXME as above, use a hashset if equivalent elements can be queried. - substs_interner: RefCell, &'tcx Substs<'tcx>>>, - bare_fn_interner: RefCell, &'tcx BareFnTy<'tcx>>>, - region_interner: RefCell>, - stability_interner: RefCell>, - - /// 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>, - // FIXME: jroesch make this a refcell - - pub tables: RefCell>, - - /// Maps from a trait item to the trait item "descriptor" - pub impl_or_trait_items: RefCell>>, - - /// Maps from a trait def-id to a list of the def-ids of its trait items - pub trait_item_def_ids: RefCell>>>, - - /// A cache for the trait_items() routine - pub trait_items_cache: RefCell>>>>, - - pub impl_trait_refs: RefCell>>>, - pub trait_defs: RefCell>>, - pub adt_defs: RefCell>>, - - /// Maps from the def-id of an item (trait/struct/enum/fn) to its - /// associated predicates. - pub predicates: RefCell>>, - - /// 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>>, - - pub map: ast_map::Map<'tcx>, - pub freevars: RefCell, - pub tcache: RefCell>>, - pub rcache: RefCell>>, - pub tc_cache: RefCell, TypeContents>>, - pub ast_ty_to_ty_cache: RefCell>>, - pub ty_param_defs: RefCell>>, - pub normalized_cache: RefCell, 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>, - - /// Maps from def-id of a type or region parameter to its - /// (inferred) variance. - pub item_variance_map: RefCell>>, - - /// True if the variance has been computed yet; false otherwise. - pub variance_computed: Cell, - - /// A method will be in this list if and only if it is a destructor. - pub destructors: RefCell, - - /// 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>>>, - - /// 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>>, - - /// Set of used unsafe nodes (functions or blocks). Unsafe nodes not - /// present in this set can be warned about. - pub used_unsafe: RefCell, - - /// 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, - - /// The set of external nominal types whose implementations have been read. - /// This is used for lazy resolution of methods. - pub populated_external_types: RefCell, - /// 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, - - /// These caches are used by const_eval when decoding external constants. - pub extern_const_statics: RefCell>, - pub extern_const_variants: RefCell>, - pub extern_const_fns: RefCell>, - - pub node_lint_levels: RefCell>, - - /// 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>>, - - /// Maps any item's def-id to its stability index. - pub stability: RefCell>, - - /// 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>, - - /// Caches the representation hints for struct definitions. - pub repr_hint_cache: RefCell>>>, - - /// Maps Expr NodeId's to their constant qualification. - pub const_qualif_map: RefCell>, - - /// Caches CoerceUnsized kinds for impls on custom types. - pub custom_coerce_unsized_kinds: RefCell>, - - /// 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>, - - /// 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>>, -} - /// Describes the fragment-state associated with a NodeId. /// /// Currently only unfragmented paths have entries in the table, @@ -918,232 +631,6 @@ pub enum FragmentInfo { Assigned { var: NodeId, assign_expr: NodeId, assignee_id: NodeId }, } -impl<'tcx> ctxt<'tcx> { - pub fn node_types(&self) -> Ref>> { - fn projection<'a, 'tcx>(tables: &'a Tables<'tcx>) -> &'a NodeMap> { - &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>) - -> 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>(&self, value: &T) -> Option { - 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; -} - -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 { - 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; - fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option { - 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 { - Some(*self) - } -} - -impl<'a, 'tcx> Lift<'tcx> for Ty<'a> { - type Lifted = Ty<'tcx>; - fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option> { - 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> { - 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> { - 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> { - 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 { - type Lifted = OutlivesPredicate; - fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option { - 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> { - 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 { - type Lifted = Binder; - fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option { - 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 R, R>(f: F) -> R { - TLS_TCX.with(|tcx| f(unsafe { &*(tcx as *const _ as *const ty::ctxt) })) - } - - pub fn with_opt) -> 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 @@ -1190,82 +677,6 @@ bitflags! { } } -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, @@ -1274,12 +685,6 @@ pub struct TyS<'tcx> { 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 { @@ -1297,323 +702,6 @@ impl<'tcx> Hash for TyS<'tcx> { 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>>, - PhantomData)->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> { - 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()") - } - } -} - -/// 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(&self, s: &mut H) { - self.ty.sty.hash(s) - } -} - -impl<'tcx> Borrow> 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>; - -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>, - pub output: FnOutput<'tcx>, - pub variadic: bool -} - -pub type PolyFnSig<'tcx> = Binder>; - -impl<'tcx> PolyFnSig<'tcx> { - pub fn inputs(&self) -> ty::Binder>> { - self.map_bound_ref(|fn_sig| fn_sig.inputs.clone()) - } - pub fn input(&self, index: usize) -> ty::Binder> { - self.map_bound_ref(|fn_sig| fn_sig.inputs[index]) - } - pub fn output(&self) -> ty::Binder> { - 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. @@ -1702,628 +790,12 @@ pub struct ClosureUpvar<'tcx> { 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`; 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`. - 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, &'tcx BareFnTy<'tcx>), - - /// A trait, defined with `trait`. - TyTrait(Box>), - - /// The anonymous type of a closure. Used to represent the type of - /// `|a| a`. - TyClosure(DefId, Box>), - - /// A tuple type. For example, `(i32, bool)`. - TyTuple(Vec>), - - /// The projection of an associated type. For example, - /// `>::N`. - TyProjection(ProjectionTy<'tcx>), - - /// A type parameter; for example, `T` in `fn f(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> -} - -#[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> - { - // 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 -/// -/// 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`, 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>; - -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`). Note that when we skolemize, instantiate, -/// erase, or otherwise "discharge" these bound regions, we change the -/// type from `Binder` to just `T` (see -/// e.g. `liberate_late_bound_regions`). -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct Binder(pub T); - -impl Binder { - /// 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(&self, f: F) -> Binder - where F: FnOnce(&T) -> U - { - self.as_ref().map_bound(f) - } - - pub fn map_bound(self, f: F) -> Binder - 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 { - pub expected: T, - pub found: T -} - -// Data structures used in type unification -#[derive(Clone, Debug)] -pub enum TypeError<'tcx> { - Mismatch, - UnsafetyMismatch(ExpectedFound), - AbiMismatch(ExpectedFound), - Mutability, - BoxMutability, - PtrMutability, - RefMutability, - VecMutability, - TupleSize(ExpectedFound), - FixedArraySize(ExpectedFound), - TyParamSize(ExpectedFound), - ArgCount, - RegionsDoesNotOutlive(Region, Region), - RegionsNotSame(Region, Region), - RegionsNoOverlap(Region, Region), - RegionsInsufficientlyPolymorphic(BoundRegion, Region), - RegionsOverlyPolymorphic(BoundRegion, Region), - Sorts(ExpectedFound>), - IntegerAsChar, - IntMismatch(ExpectedFound), - FloatMismatch(ExpectedFound), - Traits(ExpectedFound), - BuiltinBoundsMismatch(ExpectedFound), - VariadicMismatch(ExpectedFound), - CyclicTy, - ConvergenceMismatch(ExpectedFound), - ProjectionNameMismatched(ExpectedFound), - ProjectionBoundsLength(ExpectedFound), - TyParamDefaultMismatch(ExpectedFound>) -} - -/// 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>, -} - -impl<'tcx> ExistentialBounds<'tcx> { - pub fn new(region_bound: ty::Region, - builtin_bounds: BuiltinBounds, - projection_bounds: Vec>) - -> 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); - -impl BuiltinBounds { - pub fn empty() -> BuiltinBounds { - BuiltinBounds(EnumSet::new()) - } - - pub fn iter(&self) -> enum_set::Iter { - self.into_iter() - } - - pub fn to_predicates<'tcx>(&self, - tcx: &ty::ctxt<'tcx>, - self_ty: Ty<'tcx>) -> Vec> { - 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; - 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; - 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 @@ -2620,23 +1092,6 @@ impl<'tcx> PolyProjectionPredicate<'tcx> { } } -/// Represents the projection of an associated type. In explicit UFCS -/// form this would be written `>::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>; } @@ -3314,7 +1769,7 @@ pub struct FieldDefData<'tcx, 'container: '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. @@ -3572,7 +2027,7 @@ impl<'tcx, 'container> FieldDefData<'tcx, 'container> { did: did, name: name, vis: vis, - ty: TyIVar::new() + ty: ivar::TyIVar::new() } } @@ -3638,656 +2093,64 @@ impl ClosureKind { } } -impl<'tcx> CommonTypes<'tcx> { - fn new(arena: &'tcx TypedArena>, - interner: &RefCell, 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 { + 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 { + 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> => { Foo>, Bar, 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, u32>` yields the sequence `[Bar, u32]` + /// (but not `i32`, like `walk`). + pub fn walk_shallow(&'tcx self) -> IntoIter> { + 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 { + 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 { + 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(s: Session, - arenas: &'tcx CtxtArenas<'tcx>, - def_map: DefMap, - named_region_map: resolve_lifetime::NamedRegionMap, - map: ast_map::Map<'tcx>, - freevars: RefCell, - 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 { - pat_util::pat_contains_ref_binding(&self.def_map, pat) - } - - pub fn arm_contains_ref_binding(&self, arm: &hir::Arm) -> Option { - pat_util::arm_contains_ref_binding(&self.def_map, arm) - } - - fn intern_ty(type_arena: &'tcx TypedArena>, - interner: &RefCell, 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> { - 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, - 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> { - 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>) - -> 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> => { Foo>, Bar, isize } - /// [isize] => { [isize], isize } - /// ``` - pub fn walk(&'tcx self) -> TypeWalker<'tcx> { - TypeWalker::new(self) - } - - /// Iterator that walks the immediate children of `self`. Hence - /// `Foo, u32>` yields the sequence `[Bar, u32]` - /// (but not `i32`, like `walk`). - pub fn walk_shallow(&'tcx self) -> IntoIter> { - walk::walk_shallow(self) - } - - pub fn as_opt_param_ty(&self) -> Option { - 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 { - 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) => { @@ -4315,457 +2178,63 @@ impl<'tcx> TyS<'tcx> { 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(&'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 { - 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> { - 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(&'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(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, 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>, ... } - // - // 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 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 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) @@ -5037,143 +2506,6 @@ impl<'tcx> TyS<'tcx> { 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> - { - 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> { - 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>> { - self.fn_sig().inputs() - } - - pub fn fn_ret(&self) -> Binder> { - self.fn_sig().output() - } - - pub fn is_fn(&self) -> bool { - match self.sty { - TyBareFn(..) => true, - _ => false - } - } - /// See `expr_ty_adjusted` pub fn adjust(&'tcx self, cx: &ctxt<'tcx>, span: Span, @@ -5285,187 +2617,6 @@ impl<'tcx> TyS<'tcx> { } } - 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 @@ -5724,102 +2875,14 @@ impl<'tcx> ctxt<'tcx> { 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), } } @@ -5986,22 +3049,6 @@ impl<'tcx> ctxt<'tcx> { 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) - -> 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)) } @@ -6070,7 +3117,7 @@ impl<'tcx> ctxt<'tcx> { 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)) ) } @@ -6878,78 +3925,6 @@ impl<'tcx> ctxt<'tcx> { } } - /// Replace any late-bound regions bound in `value` with free variants attached to scope-id - /// `scope_id`. - pub fn liberate_late_bound_regions(&self, - all_outlive_scope: region::CodeExtent, - value: &Binder) - -> 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(&self, bound2_value: &Binder>) - -> Binder - 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(&self, value: &Binder) -> Option - 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(&self, value: &Binder) -> 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(&self, sig: &Binder) -> Binder - 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>) @@ -6975,67 +3950,6 @@ impl<'tcx> ctxt<'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: @@ -7066,167 +3980,6 @@ pub trait RegionEscape { 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 RegionEscape for Vec { - 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 { - 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 { - 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 RegionEscape for OutlivesPredicate { - 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 { @@ -7266,254 +4019,3 @@ pub trait HasTypeFlags { !self.has_type_flags(TypeFlags::HAS_LOCAL_NAMES) } } - -impl<'tcx,T:HasTypeFlags> HasTypeFlags for Vec { - 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 { - 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 HasTypeFlags for OutlivesPredicate { - 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 - 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 - where T : HasTypeFlags -{ - fn has_type_flags(&self, flags: TypeFlags) -> bool { - (**self).has_type_flags(flags) - } -} - -impl<'tcx,T> HasTypeFlags for Box - where T : HasTypeFlags -{ - fn has_type_flags(&self, flags: TypeFlags) -> bool { - (**self).has_type_flags(flags) - } -} - -impl HasTypeFlags for Binder - 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), - } - } -} diff --git a/src/librustc/middle/ty/relate.rs b/src/librustc/middle/ty/relate.rs index 7baf075cc69ba..ff0a9789cf1f8 100644 --- a/src/librustc/middle/ty/relate.rs +++ b/src/librustc/middle/ty/relate.rs @@ -15,13 +15,14 @@ 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>; +pub type RelateResult<'tcx, T> = Result>; #[derive(Clone, Debug)] pub enum Cause { @@ -662,7 +663,7 @@ impl<'a,'tcx:'a,T> Relate<'a,'tcx> for Box pub fn expected_found<'a,'tcx:'a,R,T>(relation: &mut R, a: &T, b: &T) - -> ty::ExpectedFound + -> ExpectedFound where R: TypeRelation<'a,'tcx>, T: Clone { expected_found_bool(relation.a_is_expected(), a, b) @@ -671,14 +672,14 @@ pub fn expected_found<'a,'tcx:'a,R,T>(relation: &mut R, pub fn expected_found_bool(a_is_expected: bool, a: &T, b: &T) - -> ty::ExpectedFound + -> ExpectedFound 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} } } diff --git a/src/librustc/middle/ty/structural_impls.rs b/src/librustc/middle/ty/structural_impls.rs new file mode 100644 index 0000000000000..55d064844b13d --- /dev/null +++ b/src/librustc/middle/ty/structural_impls.rs @@ -0,0 +1,895 @@ +// 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 or the MIT license +// , 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 RegionEscape for Vec { + 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 { + 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 { + 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 RegionEscape for ty::OutlivesPredicate { + 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 { + 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 { + 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 HasTypeFlags for ty::OutlivesPredicate { + 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 + 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 + where T : HasTypeFlags +{ + fn has_type_flags(&self, flags: TypeFlags) -> bool { + (**self).has_type_flags(flags) + } +} + +impl<'tcx,T> HasTypeFlags for Box + where T : HasTypeFlags +{ + fn has_type_flags(&self, flags: TypeFlags) -> bool { + (**self).has_type_flags(flags) + } +} + +impl HasTypeFlags for ty::Binder + 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 { + 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; + fn lift_to_tcx(&self, tcx: &ty::ctxt<'tcx>) -> Option { + 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 { + Some(*self) + } +} + +impl<'a, 'tcx> Lift<'tcx> for TraitRef<'a> { + type Lifted = TraitRef<'tcx>; + fn lift_to_tcx(&self, tcx: &ty::ctxt<'tcx>) -> Option> { + 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> { + 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> { + 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 { + type Lifted = ty::OutlivesPredicate; + fn lift_to_tcx(&self, tcx: &ty::ctxt<'tcx>) -> Option { + 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> { + 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 { + type Lifted = ty::Binder; + fn lift_to_tcx(&self, tcx: &ty::ctxt<'tcx>) -> Option { + 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>(&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>(&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 { + fn fold_with>(&self, folder: &mut F) -> Option { + self.as_ref().map(|t| t.fold_with(folder)) + } +} + +impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc { + fn fold_with>(&self, folder: &mut F) -> Rc { + Rc::new((**self).fold_with(folder)) + } +} + +impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box { + fn fold_with>(&self, folder: &mut F) -> Box { + let content: T = (**self).fold_with(folder); + box content + } +} + +impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec { + fn fold_with>(&self, folder: &mut F) -> Vec { + self.iter().map(|t| t.fold_with(folder)).collect() + } +} + +impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder { + fn fold_with>(&self, folder: &mut F) -> ty::Binder { + folder.fold_binder(self) + } +} + +impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for OwnedSlice { + fn fold_with>(&self, folder: &mut F) -> OwnedSlice { + self.iter().map(|t| t.fold_with(folder)).collect() + } +} + +impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for VecPerParamSpace { + fn fold_with>(&self, folder: &mut F) -> VecPerParamSpace { + + // 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>(&self, folder: &mut F) -> Ty<'tcx> { + folder.fold_ty(*self) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::BareFnTy<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::BareFnTy<'tcx> { + folder.fold_bare_fn_ty(self) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::ClosureTy<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::ClosureTy<'tcx> { + folder.fold_closure_ty(self) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::TypeAndMut<'tcx> { + folder.fold_mt(self) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::FnOutput<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::FnOutput<'tcx> { + folder.fold_output(self) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::FnSig<'tcx> { + folder.fold_fn_sig(self) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::TraitRef<'tcx> { + folder.fold_trait_ref(self) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::Region { + fn fold_with>(&self, folder: &mut F) -> ty::Region { + folder.fold_region(*self) + } +} + +impl<'tcx> TypeFoldable<'tcx> for subst::Substs<'tcx> { + fn fold_with>(&self, folder: &mut F) -> subst::Substs<'tcx> { + folder.fold_substs(self) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> { + fn fold_with>(&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>(&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>(&self, folder: &mut F) -> ty::AutoRef<'tcx> { + folder.fold_autoref(self) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::BuiltinBounds { + fn fold_with>(&self, _folder: &mut F) -> ty::BuiltinBounds { + *self + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialBounds<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::ExistentialBounds<'tcx> { + folder.fold_existential_bounds(self) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> { + fn fold_with>(&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>(&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>(&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>(&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>(&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>(&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>(&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>(&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>(&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>(&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>(&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>(&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 { + fn fold_with>(&self, folder: &mut F) -> traits::VtableDefaultImplData { + 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 { + fn fold_with>(&self, folder: &mut F) -> traits::VtableBuiltinData { + traits::VtableBuiltinData { + nested: self.nested.fold_with(folder), + } + } +} + +impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> { + fn fold_with>(&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>(&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>(&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>(&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 + where T : TypeFoldable<'tcx>, + U : TypeFoldable<'tcx>, +{ + fn fold_with>(&self, folder: &mut F) -> ty::OutlivesPredicate { + ty::OutlivesPredicate(self.0.fold_with(folder), + self.1.fold_with(folder)) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::ClosureUpvar<'tcx> { + fn fold_with>(&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>(&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, + } + } +} diff --git a/src/librustc/middle/ty/sty.rs b/src/librustc/middle/ty/sty.rs new file mode 100644 index 0000000000000..a04cc89ee18a0 --- /dev/null +++ b/src/librustc/middle/ty/sty.rs @@ -0,0 +1,1129 @@ +// 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 or the MIT license +// , 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`; 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`. + 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, &'tcx BareFnTy<'tcx>), + + /// A trait, defined with `trait`. + TyTrait(Box>), + + /// The anonymous type of a closure. Used to represent the type of + /// `|a| a`. + TyClosure(DefId, Box>), + + /// A tuple type. For example, `(i32, bool)`. + TyTuple(Vec>), + + /// The projection of an associated type. For example, + /// `>::N`. + TyProjection(ProjectionTy<'tcx>), + + /// A type parameter; for example, `T` in `fn f(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> +} + +#[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> + { + // 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 +/// +/// 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`, 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>; + +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`). Note that when we skolemize, instantiate, +/// erase, or otherwise "discharge" these bound regions, we change the +/// type from `Binder` to just `T` (see +/// e.g. `liberate_late_bound_regions`). +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct Binder(pub T); + +impl Binder { + /// 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(&self, f: F) -> Binder + where F: FnOnce(&T) -> U + { + self.as_ref().map_bound(f) + } + + pub fn map_bound(self, f: F) -> Binder + 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 `>::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>; + +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>, + pub output: FnOutput<'tcx>, + pub variadic: bool +} + +pub type PolyFnSig<'tcx> = Binder>; + +impl<'tcx> PolyFnSig<'tcx> { + pub fn inputs(&self) -> ty::Binder>> { + self.map_bound_ref(|fn_sig| fn_sig.inputs.clone()) + } + pub fn input(&self, index: usize) -> ty::Binder> { + self.map_bound_ref(|fn_sig| fn_sig.inputs[index]) + } + pub fn output(&self) -> ty::Binder> { + 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>, +} + +impl<'tcx> ExistentialBounds<'tcx> { + pub fn new(region_bound: ty::Region, + builtin_bounds: BuiltinBounds, + projection_bounds: Vec>) + -> 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); + +impl BuiltinBounds { + pub fn empty() -> BuiltinBounds { + BuiltinBounds(EnumSet::new()) + } + + pub fn iter(&self) -> enum_set::Iter { + self.into_iter() + } + + pub fn to_predicates<'tcx>(&self, + tcx: &ty::ctxt<'tcx>, + self_ty: Ty<'tcx>) -> Vec> { + 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; + 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; + 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) + -> 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> + { + 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> { + 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>> { + self.fn_sig().inputs() + } + + pub fn fn_ret(&self) -> Binder> { + self.fn_sig().output() + } + + pub fn is_fn(&self) -> bool { + match self.sty { + TyBareFn(..) => true, + _ => false + } + } + + pub fn ty_to_def_id(&self) -> Option { + 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> { + match self.sty { + TyStruct(adt, _) | TyEnum(adt, _) => Some(adt), + _ => None + } + } +} diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 222de42643297..99e41bd22b8bb 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -21,7 +21,7 @@ use middle::ty::{TyParam, TyRawPtr, TyRef, TyTuple}; 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; @@ -219,7 +219,7 @@ fn in_binder<'tcx, T, U>(f: &mut fmt::Formatter, } }; - 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) => { @@ -255,7 +255,7 @@ fn in_binder<'tcx, T, U>(f: &mut fmt::Formatter, struct TraitAndProjections<'tcx>(ty::TraitRef<'tcx>, Vec>); impl<'tcx> TypeFoldable<'tcx> for TraitAndProjections<'tcx> { - fn fold_with>(&self, folder: &mut F) + fn fold_with>(&self, folder: &mut F) -> TraitAndProjections<'tcx> { TraitAndProjections(self.0.fold_with(folder), self.1.fold_with(folder)) } @@ -388,6 +388,53 @@ impl<'tcx, 'container> fmt::Debug for ty::AdtDefData<'tcx, 'container> { } } +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() { @@ -452,6 +499,45 @@ impl fmt::Debug for ty::Region { } } +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() { @@ -486,6 +572,17 @@ impl fmt::Debug for ty::FreeRegion { } } +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={:?})", @@ -570,6 +667,58 @@ impl fmt::Display for ty::BuiltinBounds { } } +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 fmt::Display for ty::Binder diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index e6f9b1f9d6dec..a9322bf2197b0 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -534,9 +534,7 @@ fn find_implied_output_region<'tcx>(tcx: &ty::ctxt<'tcx>, 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); diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index d3a292676c5ef..cde188fa41e48 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -66,7 +66,8 @@ use middle::infer::{self, Coercion}; 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; diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index c16892d074163..fe822138c9b5b 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -32,7 +32,7 @@ pub fn suptype_with_fn<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, 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), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index dc433786ae4d6..3160ed3502578 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -97,6 +97,7 @@ use middle::ty::{Disr, ParamTy, ParameterEnvironment}; 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}; @@ -1627,7 +1628,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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) } @@ -1636,7 +1637,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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) } @@ -1651,7 +1652,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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); @@ -1661,7 +1662,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sp: Span, e: Ty<'tcx>, a: Ty<'tcx>, - err: &ty::TypeError<'tcx>) { + err: &TypeError<'tcx>) { self.infcx().report_mismatched_types(sp, e, a, err) } @@ -1766,7 +1767,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// 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) { @@ -1801,9 +1803,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } 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(); @@ -1973,7 +1976,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { default_map: &FnvHashMap<&Ty<'tcx>, type_variable::Default<'tcx>>, conflict: Ty<'tcx>) -> Option> { - 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); diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 8683afe44735a..8048c302f2c78 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -446,7 +446,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { 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) }; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 930eb431f4957..0f71c4d8ceb56 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2374,7 +2374,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( * 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); From 2ad5a61fe234e54c9385efac7fb4d04f34a137b1 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 14 Sep 2015 12:53:53 +0300 Subject: [PATCH 3/4] move traits structural impls to traits::structural_impls --- src/librustc/middle/traits/fulfill.rs | 9 - src/librustc/middle/traits/mod.rs | 1 + src/librustc/middle/traits/project.rs | 26 -- .../middle/traits/structural_impls.rs | 235 ++++++++++++++++++ src/librustc/middle/traits/util.rs | 111 +-------- src/librustc/middle/ty/structural_impls.rs | 82 ------ 6 files changed, 238 insertions(+), 226 deletions(-) create mode 100644 src/librustc/middle/traits/structural_impls.rs diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 6271dd211662e..29032f0c4719a 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -11,7 +11,6 @@ use middle::infer::InferCtxt; use middle::ty::{self, RegionEscape, Ty, HasTypeFlags}; -use std::fmt; use syntax::ast; use util::common::ErrorReported; use util::nodemap::{FnvHashSet, NodeMap}; @@ -509,14 +508,6 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, } } -impl<'tcx> fmt::Debug for RegionObligation<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "RegionObligation(sub_region={:?}, sup_type={:?})", - self.sub_region, - self.sup_type) - } -} - fn register_region_obligation<'tcx>(t_a: Ty<'tcx>, r_b: ty::Region, cause: ObligationCause<'tcx>, diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index a79837e7fb14f..14765e861c32d 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -63,6 +63,7 @@ mod fulfill; mod project; mod object_safety; mod select; +mod structural_impls; mod util; /// An `Obligation` represents some trait reference (e.g. `int:Eq`) for diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index f13b81ccdb22f..a2c09f88ab331 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -28,8 +28,6 @@ use middle::ty::fold::{TypeFoldable, TypeFolder}; use syntax::parse::token; use util::common::FN_OUTPUT_NAME; -use std::fmt; - pub type PolyProjectionObligation<'tcx> = Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>; @@ -917,27 +915,3 @@ fn confirm_impl_candidate<'cx,'tcx>( &format!("No associated type for {:?}", trait_ref)); } - -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Normalized<'tcx, T> { - fn fold_with>(&self, folder: &mut F) -> Normalized<'tcx, T> { - Normalized { - value: self.value.fold_with(folder), - obligations: self.obligations.fold_with(folder), - } - } -} - -impl<'tcx, T: HasTypeFlags> HasTypeFlags for Normalized<'tcx, T> { - fn has_type_flags(&self, flags: ty::TypeFlags) -> bool { - self.value.has_type_flags(flags) || - self.obligations.has_type_flags(flags) - } -} - -impl<'tcx, T:fmt::Debug> fmt::Debug for Normalized<'tcx, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Normalized({:?},{:?})", - self.value, - self.obligations) - } -} diff --git a/src/librustc/middle/traits/structural_impls.rs b/src/librustc/middle/traits/structural_impls.rs new file mode 100644 index 0000000000000..88c219a7c7ace --- /dev/null +++ b/src/librustc/middle/traits/structural_impls.rs @@ -0,0 +1,235 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use middle::traits; +use middle::traits::project::Normalized; +use middle::ty::{HasTypeFlags, TypeFlags, RegionEscape}; +use middle::ty::fold::{TypeFoldable, TypeFolder}; + +use std::fmt; + +// structural impls for the structs in middle::traits + +impl<'tcx, T: fmt::Debug> fmt::Debug for Normalized<'tcx, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Normalized({:?},{:?})", + self.value, + self.obligations) + } +} + +impl<'tcx> fmt::Debug for traits::RegionObligation<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "RegionObligation(sub_region={:?}, sup_type={:?})", + self.sub_region, + self.sup_type) + } +} +impl<'tcx, O: fmt::Debug> fmt::Debug for traits::Obligation<'tcx, O> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Obligation(predicate={:?},depth={})", + self.predicate, + self.recursion_depth) + } +} + +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::Vtable<'tcx, N> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + super::VtableImpl(ref v) => + write!(f, "{:?}", v), + + super::VtableDefaultImpl(ref t) => + write!(f, "{:?}", t), + + super::VtableClosure(ref d) => + write!(f, "{:?}", d), + + super::VtableFnPointer(ref d) => + write!(f, "VtableFnPointer({:?})", d), + + super::VtableObject(ref d) => + write!(f, "{:?}", d), + + super::VtableParam(ref n) => + write!(f, "VtableParam({:?})", n), + + super::VtableBuiltin(ref d) => + write!(f, "{:?}", d) + } + } +} + +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableImplData<'tcx, N> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "VtableImpl(impl_def_id={:?}, substs={:?}, nested={:?})", + self.impl_def_id, + self.substs, + self.nested) + } +} + +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableClosureData<'tcx, N> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "VtableClosure(closure_def_id={:?}, substs={:?}, nested={:?})", + self.closure_def_id, + self.substs, + self.nested) + } +} + +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableBuiltinData { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "VtableBuiltin(nested={:?})", self.nested) + } +} + +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableDefaultImplData { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "VtableDefaultImplData(trait_def_id={:?}, nested={:?})", + self.trait_def_id, + self.nested) + } +} + +impl<'tcx> fmt::Debug for traits::VtableObjectData<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "VtableObject(upcast={:?}, vtable_base={})", + self.upcast_trait_ref, + self.vtable_base) + } +} + +impl<'tcx> fmt::Debug for traits::FulfillmentError<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "FulfillmentError({:?},{:?})", + self.obligation, + self.code) + } +} + +impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + super::CodeSelectionError(ref e) => write!(f, "{:?}", e), + super::CodeProjectionError(ref e) => write!(f, "{:?}", e), + super::CodeAmbiguity => write!(f, "Ambiguity") + } + } +} + +impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "MismatchedProjectionTypes({:?})", self.err) + } +} + +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, T: HasTypeFlags> HasTypeFlags for traits::Obligation<'tcx, T> { + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self.predicate.has_type_flags(flags) + } +} + +impl<'tcx, T: HasTypeFlags> HasTypeFlags for Normalized<'tcx, T> { + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self.value.has_type_flags(flags) || + self.obligations.has_type_flags(flags) + } +} + +impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> +{ + fn fold_with>(&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>(&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>(&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 { + fn fold_with>(&self, folder: &mut F) -> traits::VtableDefaultImplData { + 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 { + fn fold_with>(&self, folder: &mut F) -> traits::VtableBuiltinData { + traits::VtableBuiltinData { + nested: self.nested.fold_with(folder), + } + } +} + +impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> { + fn fold_with>(&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>(&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, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Normalized<'tcx, T> { + fn fold_with>(&self, folder: &mut F) -> Normalized<'tcx, T> { + Normalized { + value: self.value.fold_with(folder), + obligations: self.obligations.fold_with(folder), + } + } +} diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 40d767d8c5f17..1c5156aab02be 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -11,14 +11,12 @@ use middle::def_id::DefId; use middle::infer::InferCtxt; use middle::subst::Substs; -use middle::ty::{self, HasTypeFlags, Ty, ToPredicate, ToPolyTraitRef}; -use std::fmt; +use middle::ty::{self, Ty, ToPredicate, ToPolyTraitRef}; use syntax::codemap::Span; use util::common::ErrorReported; use util::nodemap::FnvHashSet; -use super::{Obligation, ObligationCause, PredicateObligation, - VtableImpl, VtableParam, VtableImplData, VtableDefaultImplData}; +use super::{Obligation, ObligationCause, PredicateObligation}; struct PredicateSet<'a,'tcx:'a> { tcx: &'a ty::ctxt<'tcx>, @@ -477,108 +475,3 @@ pub fn closure_trait_ref_and_return_type<'tcx>( }; ty::Binder((trait_ref, sig.0.output.unwrap_or(tcx.mk_nil()))) } - -impl<'tcx,O:fmt::Debug> fmt::Debug for super::Obligation<'tcx, O> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Obligation(predicate={:?},depth={})", - self.predicate, - self.recursion_depth) - } -} - -impl<'tcx, N:fmt::Debug> fmt::Debug for super::Vtable<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - super::VtableImpl(ref v) => - write!(f, "{:?}", v), - - super::VtableDefaultImpl(ref t) => - write!(f, "{:?}", t), - - super::VtableClosure(ref d) => - write!(f, "{:?}", d), - - super::VtableFnPointer(ref d) => - write!(f, "VtableFnPointer({:?})", d), - - super::VtableObject(ref d) => - write!(f, "{:?}", d), - - super::VtableParam(ref n) => - write!(f, "VtableParam({:?})", n), - - super::VtableBuiltin(ref d) => - write!(f, "{:?}", d) - } - } -} - -impl<'tcx, N:fmt::Debug> fmt::Debug for super::VtableImplData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "VtableImpl(impl_def_id={:?}, substs={:?}, nested={:?})", - self.impl_def_id, - self.substs, - self.nested) - } -} - -impl<'tcx, N:fmt::Debug> fmt::Debug for super::VtableClosureData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "VtableClosure(closure_def_id={:?}, substs={:?}, nested={:?})", - self.closure_def_id, - self.substs, - self.nested) - } -} - -impl<'tcx, N:fmt::Debug> fmt::Debug for super::VtableBuiltinData { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "VtableBuiltin(nested={:?})", self.nested) - } -} - -impl<'tcx, N:fmt::Debug> fmt::Debug for super::VtableDefaultImplData { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "VtableDefaultImplData(trait_def_id={:?}, nested={:?})", - self.trait_def_id, - self.nested) - } -} - -impl<'tcx> fmt::Debug for super::VtableObjectData<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "VtableObject(upcast={:?}, vtable_base={})", - self.upcast_trait_ref, - self.vtable_base) - } -} - -impl<'tcx> fmt::Debug for super::FulfillmentError<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "FulfillmentError({:?},{:?})", - self.obligation, - self.code) - } -} - -impl<'tcx> fmt::Debug for super::FulfillmentErrorCode<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - super::CodeSelectionError(ref e) => write!(f, "{:?}", e), - super::CodeProjectionError(ref e) => write!(f, "{:?}", e), - super::CodeAmbiguity => write!(f, "Ambiguity") - } - } -} - -impl<'tcx> fmt::Debug for super::MismatchedProjectionTypes<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "MismatchedProjectionTypes({:?})", self.err) - } -} - -impl<'tcx, T: HasTypeFlags> HasTypeFlags for Obligation<'tcx, T> { - fn has_type_flags(&self, flags: ty::TypeFlags) -> bool { - self.predicate.has_type_flags(flags) - } -} diff --git a/src/librustc/middle/ty/structural_impls.rs b/src/librustc/middle/ty/structural_impls.rs index 55d064844b13d..94e4672ea9710 100644 --- a/src/librustc/middle/ty/structural_impls.rs +++ b/src/librustc/middle/ty/structural_impls.rs @@ -116,12 +116,6 @@ impl<'tcx> RegionEscape for ty::Predicate<'tcx> { } } -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)) || @@ -770,82 +764,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::InstantiatedPredicates<'tcx> { } } -impl<'tcx,O> TypeFoldable<'tcx> for traits::Obligation<'tcx,O> - where O : TypeFoldable<'tcx> -{ - fn fold_with>(&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>(&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>(&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 { - fn fold_with>(&self, folder: &mut F) -> traits::VtableDefaultImplData { - 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 { - fn fold_with>(&self, folder: &mut F) -> traits::VtableBuiltinData { - traits::VtableBuiltinData { - nested: self.nested.fold_with(folder), - } - } -} - -impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> { - fn fold_with>(&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>(&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>(&self, folder: &mut F) -> ty::EquatePredicate<'tcx> { ty::EquatePredicate(self.0.fold_with(folder), From 5a95acb8aba07ea8e5255893aa4e01e5ba5c2349 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 14 Sep 2015 14:55:56 +0300 Subject: [PATCH 4/4] split ty::util and ty::adjustment --- src/librustc/metadata/csearch.rs | 8 +- src/librustc/metadata/decoder.rs | 8 +- src/librustc/middle/astencode.rs | 58 +- src/librustc/middle/check_const.rs | 9 +- src/librustc/middle/expr_use_visitor.rs | 15 +- src/librustc/middle/infer/mod.rs | 7 +- src/librustc/middle/mem_categorization.rs | 11 +- src/librustc/middle/ty/adjustment.rs | 249 ++++ src/librustc/middle/ty/context.rs | 4 +- src/librustc/middle/ty/fold.rs | 14 +- src/librustc/middle/ty/mod.rs | 1203 +------------------ src/librustc/middle/ty/structural_impls.rs | 4 +- src/librustc/middle/ty/sty.rs | 83 ++ src/librustc/middle/ty/util.rs | 891 ++++++++++++++ src/librustc/util/ppaux.rs | 10 +- src/librustc_lint/builtin.rs | 11 +- src/librustc_mir/tcx/expr.rs | 10 +- src/librustc_trans/trans/consts.rs | 8 +- src/librustc_trans/trans/expr.rs | 5 +- src/librustc_typeck/check/coercion.rs | 18 +- src/librustc_typeck/check/method/confirm.rs | 13 +- src/librustc_typeck/check/method/mod.rs | 5 +- src/librustc_typeck/check/mod.rs | 21 +- src/librustc_typeck/check/regionck.rs | 13 +- src/librustc_typeck/check/writeback.rs | 13 +- src/librustc_typeck/coherence/mod.rs | 13 +- src/librustc_typeck/collect.rs | 3 +- 27 files changed, 1387 insertions(+), 1320 deletions(-) create mode 100644 src/librustc/middle/ty/adjustment.rs create mode 100644 src/librustc/middle/ty/util.rs diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index c539bfc596413..e1cb9bd0e77cf 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -247,9 +247,11 @@ pub fn get_impl_polarity<'tcx>(tcx: &ty::ctxt<'tcx>, decoder::get_impl_polarity(&*cdata, def.node) } -pub fn get_custom_coerce_unsized_kind<'tcx>(tcx: &ty::ctxt<'tcx>, - def: DefId) - -> Option { +pub fn get_custom_coerce_unsized_kind<'tcx>( + tcx: &ty::ctxt<'tcx>, + def: DefId) + -> Option +{ let cstore = &tcx.sess.cstore; let cdata = cstore.get_crate_data(def.krate); decoder::get_custom_coerce_unsized_kind(&*cdata, def.node) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 309a18feb9aad..e2cf50cf30ad0 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -540,9 +540,11 @@ pub fn get_impl_polarity<'tcx>(cdata: Cmd, } } -pub fn get_custom_coerce_unsized_kind<'tcx>(cdata: Cmd, - id: ast::NodeId) - -> Option { +pub fn get_custom_coerce_unsized_kind<'tcx>( + cdata: Cmd, + id: ast::NodeId) + -> Option +{ let item_doc = cdata.lookup_item(id); reader::maybe_get_doc(item_doc, tag_impl_coerce_unsized_kind).map(|kind_doc| { let mut decoder = reader::Decoder::new(kind_doc); diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index ac2dd54598253..0bd4434857abd 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -27,6 +27,7 @@ use metadata::tydecode; use metadata::tydecode::{DefIdSource, NominalType, TypeWithId}; use metadata::tydecode::{RegionParameter, ClosureSource}; use metadata::tyencode; +use middle::ty::adjustment; use middle::ty::cast; use middle::check_const::ConstQualif; use middle::def; @@ -646,11 +647,11 @@ trait rbml_writer_helpers<'tcx> { fn emit_builtin_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::BuiltinBounds); fn emit_upvar_capture(&mut self, ecx: &e::EncodeContext, capture: &ty::UpvarCapture); fn emit_auto_adjustment<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - adj: &ty::AutoAdjustment<'tcx>); + adj: &adjustment::AutoAdjustment<'tcx>); fn emit_autoref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - autoref: &ty::AutoRef<'tcx>); + autoref: &adjustment::AutoRef<'tcx>); fn emit_auto_deref_ref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - auto_deref_ref: &ty::AutoDerefRef<'tcx>); + auto_deref_ref: &adjustment::AutoDerefRef<'tcx>); } impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { @@ -771,22 +772,22 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { } fn emit_auto_adjustment<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - adj: &ty::AutoAdjustment<'tcx>) { + adj: &adjustment::AutoAdjustment<'tcx>) { use serialize::Encoder; self.emit_enum("AutoAdjustment", |this| { match *adj { - ty::AdjustReifyFnPointer=> { + adjustment::AdjustReifyFnPointer=> { this.emit_enum_variant("AdjustReifyFnPointer", 1, 0, |_| Ok(())) } - ty::AdjustUnsafeFnPointer => { + adjustment::AdjustUnsafeFnPointer => { this.emit_enum_variant("AdjustUnsafeFnPointer", 2, 0, |_| { Ok(()) }) } - ty::AdjustDerefRef(ref auto_deref_ref) => { + adjustment::AdjustDerefRef(ref auto_deref_ref) => { this.emit_enum_variant("AdjustDerefRef", 3, 2, |this| { this.emit_enum_variant_arg(0, |this| Ok(this.emit_auto_deref_ref(ecx, auto_deref_ref))) @@ -797,19 +798,19 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { } fn emit_autoref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - autoref: &ty::AutoRef<'tcx>) { + autoref: &adjustment::AutoRef<'tcx>) { use serialize::Encoder; self.emit_enum("AutoRef", |this| { match autoref { - &ty::AutoPtr(r, m) => { + &adjustment::AutoPtr(r, m) => { this.emit_enum_variant("AutoPtr", 0, 2, |this| { this.emit_enum_variant_arg(0, |this| Ok(this.emit_region(ecx, *r))); this.emit_enum_variant_arg(1, |this| m.encode(this)) }) } - &ty::AutoUnsafe(m) => { + &adjustment::AutoUnsafe(m) => { this.emit_enum_variant("AutoUnsafe", 1, 1, |this| { this.emit_enum_variant_arg(0, |this| m.encode(this)) }) @@ -819,7 +820,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { } fn emit_auto_deref_ref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - auto_deref_ref: &ty::AutoDerefRef<'tcx>) { + auto_deref_ref: &adjustment::AutoDerefRef<'tcx>) { use serialize::Encoder; self.emit_struct("AutoDerefRef", 2, |this| { @@ -974,7 +975,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, if let Some(adjustment) = tcx.tables.borrow().adjustments.get(&id) { match *adjustment { - ty::AdjustDerefRef(ref adj) => { + adjustment::AdjustDerefRef(ref adj) => { for autoderef in 0..adj.autoderefs { let method_call = ty::MethodCall::autoderef(id, autoderef as u32); if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) { @@ -1063,7 +1064,7 @@ trait rbml_decoder_decoder_helpers<'tcx> { fn read_upvar_capture(&mut self, dcx: &DecodeContext) -> ty::UpvarCapture; fn read_auto_adjustment<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::AutoAdjustment<'tcx>; + -> adjustment::AutoAdjustment<'tcx>; fn read_cast_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> cast::CastKind; fn read_closure_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) @@ -1071,9 +1072,9 @@ trait rbml_decoder_decoder_helpers<'tcx> { fn read_closure_ty<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::ClosureTy<'tcx>; fn read_auto_deref_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::AutoDerefRef<'tcx>; + -> adjustment::AutoDerefRef<'tcx>; fn read_autoref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::AutoRef<'tcx>; + -> adjustment::AutoRef<'tcx>; fn convert_def_id(&mut self, dcx: &DecodeContext, source: DefIdSource, @@ -1246,30 +1247,30 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { }).unwrap() } fn read_auto_adjustment<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> ty::AutoAdjustment<'tcx> { + -> adjustment::AutoAdjustment<'tcx> { self.read_enum("AutoAdjustment", |this| { let variants = ["AdjustReifyFnPointer", "AdjustUnsafeFnPointer", "AdjustDerefRef"]; this.read_enum_variant(&variants, |this, i| { Ok(match i { - 1 => ty::AdjustReifyFnPointer, - 2 => ty::AdjustUnsafeFnPointer, + 1 => adjustment::AdjustReifyFnPointer, + 2 => adjustment::AdjustUnsafeFnPointer, 3 => { - let auto_deref_ref: ty::AutoDerefRef = + let auto_deref_ref: adjustment::AutoDerefRef = this.read_enum_variant_arg(0, |this| Ok(this.read_auto_deref_ref(dcx))).unwrap(); - ty::AdjustDerefRef(auto_deref_ref) + adjustment::AdjustDerefRef(auto_deref_ref) } - _ => panic!("bad enum variant for ty::AutoAdjustment") + _ => panic!("bad enum variant for adjustment::AutoAdjustment") }) }) }).unwrap() } fn read_auto_deref_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> ty::AutoDerefRef<'tcx> { + -> adjustment::AutoDerefRef<'tcx> { self.read_struct("AutoDerefRef", 2, |this| { - Ok(ty::AutoDerefRef { + Ok(adjustment::AutoDerefRef { autoderefs: this.read_struct_field("autoderefs", 0, |this| { Decodable::decode(this) }).unwrap(), @@ -1296,7 +1297,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { } fn read_autoref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> ty::AutoRef<'tcx> { + -> adjustment::AutoRef<'tcx> { self.read_enum("AutoRef", |this| { let variants = ["AutoPtr", "AutoUnsafe"]; this.read_enum_variant(&variants, |this, i| { @@ -1311,15 +1312,15 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { Decodable::decode(this) }).unwrap(); - ty::AutoPtr(dcx.tcx.mk_region(r), m) + adjustment::AutoPtr(dcx.tcx.mk_region(r), m) } 1 => { let m: hir::Mutability = this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); - ty::AutoUnsafe(m) + adjustment::AutoUnsafe(m) } - _ => panic!("bad enum variant for ty::AutoRef") + _ => panic!("bad enum variant for adjustment::AutoRef") }) }) }).unwrap() @@ -1467,7 +1468,8 @@ fn decode_side_tables(dcx: &DecodeContext, dcx.tcx.tables.borrow_mut().method_map.insert(method_call, method); } c::tag_table_adjustments => { - let adj: ty::AutoAdjustment = val_dsr.read_auto_adjustment(dcx); + let adj = + val_dsr.read_auto_adjustment(dcx); dcx.tcx.tables.borrow_mut().adjustments.insert(id, adj); } c::tag_table_closure_tys => { diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 48c8cca76b056..661299cd7f3fc 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -798,8 +798,13 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, /// Check the adjustments of an expression fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) { match v.tcx.tables.borrow().adjustments.get(&e.id) { - None | Some(&ty::AdjustReifyFnPointer) | Some(&ty::AdjustUnsafeFnPointer) => {} - Some(&ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs, .. })) => { + None | + Some(&ty::adjustment::AdjustReifyFnPointer) | + Some(&ty::adjustment::AdjustUnsafeFnPointer) => {} + + Some(&ty::adjustment::AdjustDerefRef( + ty::adjustment::AutoDerefRef { autoderefs, .. } + )) => { if (0..autoderefs as u32).any(|autoderef| { v.tcx.is_overloaded_autoderef(e.id, autoderef) }) { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index d2bb31f10bd14..a8fed5eab16be 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -25,6 +25,7 @@ use middle::def_id::{DefId}; use middle::infer; use middle::mem_categorization as mc; use middle::ty; +use middle::ty::adjustment; use rustc_front::hir; @@ -726,8 +727,8 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { let adj = typer.adjustments().get(&expr.id).map(|x| x.clone()); if let Some(adjustment) = adj { match adjustment { - ty::AdjustReifyFnPointer | - ty::AdjustUnsafeFnPointer => { + adjustment::AdjustReifyFnPointer | + adjustment::AdjustUnsafeFnPointer => { // Creating a closure/fn-pointer or unsizing consumes // the input and stores it into the resulting rvalue. debug!("walk_adjustment(AdjustReifyFnPointer|AdjustUnsafeFnPointer)"); @@ -735,7 +736,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { return_if_err!(self.mc.cat_expr_unadjusted(expr)); self.delegate_consume(expr.id, expr.span, cmt_unadjusted); } - ty::AdjustDerefRef(ref adj) => { + adjustment::AdjustDerefRef(ref adj) => { self.walk_autoderefref(expr, adj); } } @@ -778,7 +779,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { fn walk_autoderefref(&mut self, expr: &hir::Expr, - adj: &ty::AutoDerefRef<'tcx>) { + adj: &adjustment::AutoDerefRef<'tcx>) { debug!("walk_autoderefref expr={:?} adj={:?}", expr, adj); @@ -809,7 +810,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { fn walk_autoref(&mut self, expr: &hir::Expr, cmt_base: mc::cmt<'tcx>, - opt_autoref: Option>) + opt_autoref: Option>) -> mc::cmt<'tcx> { debug!("walk_autoref(expr.id={} cmt_derefd={:?} opt_autoref={:?})", @@ -828,7 +829,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { }; match *autoref { - ty::AutoPtr(r, m) => { + adjustment::AutoPtr(r, m) => { self.delegate.borrow(expr.id, expr.span, cmt_base, @@ -837,7 +838,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { AutoRef); } - ty::AutoUnsafe(m) => { + adjustment::AutoUnsafe(m) => { debug!("walk_autoref: expr.id={} cmt_base={:?}", expr.id, cmt_base); diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index b9e9ee5e24497..ffb631e105b3a 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -30,6 +30,7 @@ use middle::subst::Substs; use middle::subst::Subst; use middle::traits::{self, FulfillmentContext, Normalized, SelectionContext, ObligationCause}; +use middle::ty::adjustment; use middle::ty::{TyVid, IntVid, FloatVid, RegionVid}; use middle::ty::{self, Ty, HasTypeFlags}; use middle::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; @@ -1151,7 +1152,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// Apply `adjustment` to the type of `expr` pub fn adjust_expr_ty(&self, expr: &hir::Expr, - adjustment: Option<&ty::AutoAdjustment<'tcx>>) + adjustment: Option<&adjustment::AutoAdjustment<'tcx>>) -> Ty<'tcx> { let raw_ty = self.expr_ty(expr); @@ -1485,9 +1486,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .map(|method| method.def_id) } - pub fn adjustments(&self) -> Ref>> { + pub fn adjustments(&self) -> Ref>> { fn project_adjustments<'a, 'tcx>(tables: &'a ty::Tables<'tcx>) - -> &'a NodeMap> { + -> &'a NodeMap> { &tables.adjustments } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 51005ef8b9770..dd2f48d25b4b0 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -77,6 +77,7 @@ use front::map as ast_map; use middle::infer; use middle::check_const; use middle::def; +use middle::ty::adjustment; use middle::ty::{self, Ty}; use rustc_front::hir::{MutImmutable, MutMutable}; @@ -421,16 +422,16 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> { Some(adjustment) => { match *adjustment { - ty::AdjustDerefRef( - ty::AutoDerefRef { + adjustment::AdjustDerefRef( + adjustment::AutoDerefRef { autoref: None, unsize: None, autoderefs, ..}) => { // Equivalent to *expr or something similar. self.cat_expr_autoderefd(expr, autoderefs) } - ty::AdjustReifyFnPointer | - ty::AdjustUnsafeFnPointer | - ty::AdjustDerefRef(_) => { + adjustment::AdjustReifyFnPointer | + adjustment::AdjustUnsafeFnPointer | + adjustment::AdjustDerefRef(_) => { debug!("cat_expr({:?}): {:?}", adjustment, expr); diff --git a/src/librustc/middle/ty/adjustment.rs b/src/librustc/middle/ty/adjustment.rs new file mode 100644 index 0000000000000..cadab499c0765 --- /dev/null +++ b/src/librustc/middle/ty/adjustment.rs @@ -0,0 +1,249 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use self::AutoAdjustment::*; +pub use self::AutoRef::*; + +use middle::ty::{self, Ty, TypeAndMut}; +use middle::ty::HasTypeFlags; +use middle::ty::LvaluePreference::{NoPreference}; + +use syntax::ast; +use syntax::codemap::Span; + +use rustc_front::hir; + +#[derive(Copy, Clone)] +pub enum AutoAdjustment<'tcx> { + AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type + AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer + AdjustDerefRef(AutoDerefRef<'tcx>), +} + +/// Represents coercing a pointer to a different kind of pointer - where 'kind' +/// here means either or both of raw vs borrowed vs unique and fat vs thin. +/// +/// We transform pointers by following the following steps in order: +/// 1. Deref the pointer `self.autoderefs` times (may be 0). +/// 2. If `autoref` is `Some(_)`, then take the address and produce either a +/// `&` or `*` pointer. +/// 3. If `unsize` is `Some(_)`, then apply the unsize transformation, +/// which will do things like convert thin pointers to fat +/// pointers, or convert structs containing thin pointers to +/// structs containing fat pointers, or convert between fat +/// pointers. We don't store the details of how the transform is +/// done (in fact, we don't know that, because it might depend on +/// the precise type parameters). We just store the target +/// type. Trans figures out what has to be done at monomorphization +/// time based on the precise source/target type at hand. +/// +/// To make that more concrete, here are some common scenarios: +/// +/// 1. The simplest cases are where the pointer is not adjusted fat vs thin. +/// Here the pointer will be dereferenced N times (where a dereference can +/// happen to to raw or borrowed pointers or any smart pointer which implements +/// Deref, including Box<_>). The number of dereferences is given by +/// `autoderefs`. It can then be auto-referenced zero or one times, indicated +/// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is +/// None. +/// +/// 2. A thin-to-fat coercon involves unsizing the underlying data. We start +/// with a thin pointer, deref a number of times, unsize the underlying data, +/// then autoref. The 'unsize' phase may change a fixed length array to a +/// dynamically sized one, a concrete object to a trait object, or statically +/// sized struct to a dyncamically sized one. E.g., &[i32; 4] -> &[i32] is +/// represented by: +/// +/// ``` +/// AutoDerefRef { +/// autoderefs: 1, // &[i32; 4] -> [i32; 4] +/// autoref: Some(AutoPtr), // [i32] -> &[i32] +/// unsize: Some([i32]), // [i32; 4] -> [i32] +/// } +/// ``` +/// +/// Note that for a struct, the 'deep' unsizing of the struct is not recorded. +/// E.g., `struct Foo { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]> +/// The autoderef and -ref are the same as in the above example, but the type +/// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about +/// the underlying conversions from `[i32; 4]` to `[i32]`. +/// +/// 3. Coercing a `Box` to `Box` is an interesting special case. In +/// that case, we have the pointer we need coming in, so there are no +/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation. +/// At some point, of course, `Box` should move out of the compiler, in which +/// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> -> +/// Box<[i32]> is represented by: +/// +/// ``` +/// AutoDerefRef { +/// autoderefs: 0, +/// autoref: None, +/// unsize: Some(Box<[i32]>), +/// } +/// ``` +#[derive(Copy, Clone)] +pub struct AutoDerefRef<'tcx> { + /// Step 1. Apply a number of dereferences, producing an lvalue. + pub autoderefs: usize, + + /// Step 2. Optionally produce a pointer/reference from the value. + pub autoref: Option>, + + /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to + /// `&[T]`. The stored type is the target pointer type. Note that + /// the source could be a thin or fat pointer. + pub unsize: Option>, +} + +impl<'tcx> AutoAdjustment<'tcx> { + pub fn is_identity(&self) -> bool { + match *self { + AdjustReifyFnPointer | + AdjustUnsafeFnPointer => false, + AdjustDerefRef(ref r) => r.is_identity(), + } + } +} +impl<'tcx> AutoDerefRef<'tcx> { + pub fn is_identity(&self) -> bool { + self.autoderefs == 0 && self.unsize.is_none() && self.autoref.is_none() + } +} + + +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum AutoRef<'tcx> { + /// Convert from T to &T. + AutoPtr(&'tcx ty::Region, hir::Mutability), + + /// Convert from T to *T. + /// Value to thin pointer. + AutoUnsafe(hir::Mutability), +} + +#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] +pub enum CustomCoerceUnsized { + /// Records the index of the field being coerced. + Struct(usize) +} + +impl<'tcx> ty::TyS<'tcx> { + /// See `expr_ty_adjusted` + pub fn adjust(&'tcx self, cx: &ty::ctxt<'tcx>, + span: Span, + expr_id: ast::NodeId, + adjustment: Option<&AutoAdjustment<'tcx>>, + mut method_type: F) + -> Ty<'tcx> where + F: FnMut(ty::MethodCall) -> Option>, + { + if let ty::TyError = self.sty { + return self; + } + + return match adjustment { + Some(adjustment) => { + match *adjustment { + AdjustReifyFnPointer => { + match self.sty { + ty::TyBareFn(Some(_), b) => { + cx.mk_fn(None, b) + } + _ => { + cx.sess.bug( + &format!("AdjustReifyFnPointer adjustment on non-fn-item: \ + {:?}", self)); + } + } + } + + AdjustUnsafeFnPointer => { + match self.sty { + ty::TyBareFn(None, b) => cx.safe_to_unsafe_fn_ty(b), + ref b => { + cx.sess.bug( + &format!("AdjustReifyFnPointer adjustment on non-fn-item: \ + {:?}", + b)); + } + } + } + + AdjustDerefRef(ref adj) => { + let mut adjusted_ty = self; + + if !adjusted_ty.references_error() { + for i in 0..adj.autoderefs { + adjusted_ty = + adjusted_ty.adjust_for_autoderef(cx, + expr_id, + span, + i as u32, + &mut method_type); + } + } + + if let Some(target) = adj.unsize { + target + } else { + adjusted_ty.adjust_for_autoref(cx, adj.autoref) + } + } + } + } + None => self + }; + } + + pub fn adjust_for_autoderef(&'tcx self, + cx: &ty::ctxt<'tcx>, + expr_id: ast::NodeId, + expr_span: Span, + autoderef: u32, // how many autoderefs so far? + mut method_type: F) + -> Ty<'tcx> where + F: FnMut(ty::MethodCall) -> Option>, + { + let method_call = ty::MethodCall::autoderef(expr_id, autoderef); + let mut adjusted_ty = self; + if let Some(method_ty) = method_type(method_call) { + // Method calls always have all late-bound regions + // fully instantiated. + let fn_ret = cx.no_late_bound_regions(&method_ty.fn_ret()).unwrap(); + adjusted_ty = fn_ret.unwrap(); + } + match adjusted_ty.builtin_deref(true, NoPreference) { + Some(mt) => mt.ty, + None => { + cx.sess.span_bug( + expr_span, + &format!("the {}th autoderef failed: {}", + autoderef, + adjusted_ty) + ); + } + } + } + + pub fn adjust_for_autoref(&'tcx self, cx: &ty::ctxt<'tcx>, + autoref: Option>) + -> Ty<'tcx> { + match autoref { + None => self, + Some(AutoPtr(r, m)) => { + cx.mk_ref(r, TypeAndMut { ty: self, mutbl: m }) + } + Some(AutoUnsafe(m)) => { + cx.mk_ptr(TypeAndMut { ty: self, mutbl: m }) + } + } + } +} diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs index 4d57e0980ef54..e3b6da56680da 100644 --- a/src/librustc/middle/ty/context.rs +++ b/src/librustc/middle/ty/context.rs @@ -106,7 +106,7 @@ pub struct Tables<'tcx> { /// other items. pub item_substs: NodeMap>, - pub adjustments: NodeMap>, + pub adjustments: NodeMap>, pub method_map: ty::MethodMap<'tcx>, @@ -308,7 +308,7 @@ pub struct ctxt<'tcx> { pub const_qualif_map: RefCell>, /// Caches CoerceUnsized kinds for impls on custom types. - pub custom_coerce_unsized_kinds: RefCell>, + pub custom_coerce_unsized_kinds: RefCell>, /// Maps a cast expression to its kind. This is keyed on the /// *from* expression of the cast, not the cast itself. diff --git a/src/librustc/middle/ty/fold.rs b/src/librustc/middle/ty/fold.rs index 9de58369a63f8..751bac28ce4c2 100644 --- a/src/librustc/middle/ty/fold.rs +++ b/src/librustc/middle/ty/fold.rs @@ -36,6 +36,7 @@ use middle::region; use middle::subst; +use middle::ty::adjustment; use middle::ty::{self, Binder, Ty, HasTypeFlags, RegionEscape}; use std::fmt; @@ -128,7 +129,8 @@ pub trait TypeFolder<'tcx> : Sized { super_fold_existential_bounds(self, s) } - fn fold_autoref(&mut self, ar: &ty::AutoRef<'tcx>) -> ty::AutoRef<'tcx> { + fn fold_autoref(&mut self, ar: &adjustment::AutoRef<'tcx>) + -> adjustment::AutoRef<'tcx> { super_fold_autoref(self, ar) } @@ -296,15 +298,15 @@ pub fn super_fold_existential_bounds<'tcx, T: TypeFolder<'tcx>>( } pub fn super_fold_autoref<'tcx, T: TypeFolder<'tcx>>(this: &mut T, - autoref: &ty::AutoRef<'tcx>) - -> ty::AutoRef<'tcx> + autoref: &adjustment::AutoRef<'tcx>) + -> adjustment::AutoRef<'tcx> { match *autoref { - ty::AutoPtr(r, m) => { + adjustment::AutoPtr(r, m) => { let r = r.fold_with(this); - ty::AutoPtr(this.tcx().mk_region(r), m) + adjustment::AutoPtr(this.tcx().mk_region(r), m) } - ty::AutoUnsafe(m) => ty::AutoUnsafe(m) + adjustment::AutoUnsafe(m) => adjustment::AutoUnsafe(m) } } diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs index ab1160d7deb02..dff423b35dd0a 100644 --- a/src/librustc/middle/ty/mod.rs +++ b/src/librustc/middle/ty/mod.rs @@ -11,30 +11,21 @@ pub use self::ImplOrTraitItemId::*; pub use self::ClosureKind::*; pub use self::Variance::*; -pub use self::AutoAdjustment::*; -pub use self::Representability::*; -pub use self::AutoRef::*; pub use self::DtorKind::*; pub use self::ExplicitSelfCategory::*; pub use self::ImplOrTraitItemContainer::*; pub use self::BorrowKind::*; pub use self::ImplOrTraitItem::*; pub use self::IntVarValue::*; -pub use self::CopyImplementationError::*; pub use self::LvaluePreference::*; -use back::svh::Svh; use front::map as ast_map; use front::map::LinkedPath; use metadata::csearch; use middle; -use middle::const_eval::{self, ConstVal, ErrKind}; -use middle::const_eval::EvalHint::UncheckedExprHint; use middle::def::{self, ExportMap}; use middle::def_id::{DefId, LOCAL_CRATE}; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; -use middle::infer; -use middle::pat_util; use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace}; use middle::traits; use middle::ty; @@ -43,12 +34,10 @@ use middle::ty::walk::TypeWalker; use util::common::memoized; use util::nodemap::{NodeMap, NodeSet, DefIdMap}; use util::nodemap::FnvHashMap; -use util::num::ToPrimitive; use std::borrow::{Borrow, Cow}; use std::cell::{Cell, RefCell}; -use std::cmp; -use std::hash::{Hash, SipHasher, Hasher}; +use std::hash::{Hash, Hasher}; use std::iter; use std::rc::Rc; use std::slice; @@ -61,7 +50,7 @@ use syntax::parse::token::{InternedString, special_idents}; use rustc_front::hir; use rustc_front::hir::{ItemImpl, ItemTrait}; use rustc_front::hir::{MutImmutable, MutMutable, Visibility}; -use rustc_front::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt}; +use rustc_front::attr::{self, AttrMetaMethods}; pub use self::sty::{Binder, DebruijnIndex}; pub use self::sty::{BuiltinBound, BuiltinBounds, ExistentialBounds}; @@ -86,6 +75,7 @@ pub use self::contents::TypeContents; pub use self::context::{ctxt, tls}; pub use self::context::{CtxtArenas, Lift, Tables}; +pub mod adjustment; pub mod cast; pub mod error; pub mod fast_reject; @@ -95,6 +85,7 @@ pub mod outlives; pub mod relate; pub mod walk; pub mod wf; +pub mod util; mod contents; mod context; @@ -104,7 +95,6 @@ mod structural_impls; mod sty; pub type Disr = u64; - pub const INITIAL_DISCRIMINANT_VALUE: Disr = 0; // Data types @@ -143,126 +133,6 @@ impl DtorKind { } } -pub trait IntTypeExt { - fn to_ty<'tcx>(&self, cx: &ctxt<'tcx>) -> Ty<'tcx>; - fn i64_to_disr(&self, val: i64) -> Option; - fn u64_to_disr(&self, val: u64) -> Option; - fn disr_incr(&self, val: Disr) -> Option; - fn disr_string(&self, val: Disr) -> String; - fn disr_wrap_incr(&self, val: Option) -> Disr; -} - -impl IntTypeExt for attr::IntType { - fn to_ty<'tcx>(&self, cx: &ctxt<'tcx>) -> Ty<'tcx> { - match *self { - SignedInt(hir::TyI8) => cx.types.i8, - SignedInt(hir::TyI16) => cx.types.i16, - SignedInt(hir::TyI32) => cx.types.i32, - SignedInt(hir::TyI64) => cx.types.i64, - SignedInt(hir::TyIs) => cx.types.isize, - UnsignedInt(hir::TyU8) => cx.types.u8, - UnsignedInt(hir::TyU16) => cx.types.u16, - UnsignedInt(hir::TyU32) => cx.types.u32, - UnsignedInt(hir::TyU64) => cx.types.u64, - UnsignedInt(hir::TyUs) => cx.types.usize, - } - } - - fn i64_to_disr(&self, val: i64) -> Option { - match *self { - SignedInt(hir::TyI8) => val.to_i8() .map(|v| v as Disr), - SignedInt(hir::TyI16) => val.to_i16() .map(|v| v as Disr), - SignedInt(hir::TyI32) => val.to_i32() .map(|v| v as Disr), - SignedInt(hir::TyI64) => val.to_i64() .map(|v| v as Disr), - UnsignedInt(hir::TyU8) => val.to_u8() .map(|v| v as Disr), - UnsignedInt(hir::TyU16) => val.to_u16() .map(|v| v as Disr), - UnsignedInt(hir::TyU32) => val.to_u32() .map(|v| v as Disr), - UnsignedInt(hir::TyU64) => val.to_u64() .map(|v| v as Disr), - - UnsignedInt(hir::TyUs) | - SignedInt(hir::TyIs) => unreachable!(), - } - } - - fn u64_to_disr(&self, val: u64) -> Option { - match *self { - SignedInt(hir::TyI8) => val.to_i8() .map(|v| v as Disr), - SignedInt(hir::TyI16) => val.to_i16() .map(|v| v as Disr), - SignedInt(hir::TyI32) => val.to_i32() .map(|v| v as Disr), - SignedInt(hir::TyI64) => val.to_i64() .map(|v| v as Disr), - UnsignedInt(hir::TyU8) => val.to_u8() .map(|v| v as Disr), - UnsignedInt(hir::TyU16) => val.to_u16() .map(|v| v as Disr), - UnsignedInt(hir::TyU32) => val.to_u32() .map(|v| v as Disr), - UnsignedInt(hir::TyU64) => val.to_u64() .map(|v| v as Disr), - - UnsignedInt(hir::TyUs) | - SignedInt(hir::TyIs) => unreachable!(), - } - } - - fn disr_incr(&self, val: Disr) -> Option { - macro_rules! add1 { - ($e:expr) => { $e.and_then(|v|v.checked_add(1)).map(|v| v as Disr) } - } - match *self { - // SignedInt repr means we *want* to reinterpret the bits - // treating the highest bit of Disr as a sign-bit, so - // cast to i64 before range-checking. - SignedInt(hir::TyI8) => add1!((val as i64).to_i8()), - SignedInt(hir::TyI16) => add1!((val as i64).to_i16()), - SignedInt(hir::TyI32) => add1!((val as i64).to_i32()), - SignedInt(hir::TyI64) => add1!(Some(val as i64)), - - UnsignedInt(hir::TyU8) => add1!(val.to_u8()), - UnsignedInt(hir::TyU16) => add1!(val.to_u16()), - UnsignedInt(hir::TyU32) => add1!(val.to_u32()), - UnsignedInt(hir::TyU64) => add1!(Some(val)), - - UnsignedInt(hir::TyUs) | - SignedInt(hir::TyIs) => unreachable!(), - } - } - - // This returns a String because (1.) it is only used for - // rendering an error message and (2.) a string can represent the - // full range from `i64::MIN` through `u64::MAX`. - fn disr_string(&self, val: Disr) -> String { - match *self { - SignedInt(hir::TyI8) => format!("{}", val as i8 ), - SignedInt(hir::TyI16) => format!("{}", val as i16), - SignedInt(hir::TyI32) => format!("{}", val as i32), - SignedInt(hir::TyI64) => format!("{}", val as i64), - UnsignedInt(hir::TyU8) => format!("{}", val as u8 ), - UnsignedInt(hir::TyU16) => format!("{}", val as u16), - UnsignedInt(hir::TyU32) => format!("{}", val as u32), - UnsignedInt(hir::TyU64) => format!("{}", val as u64), - - UnsignedInt(hir::TyUs) | - SignedInt(hir::TyIs) => unreachable!(), - } - } - - fn disr_wrap_incr(&self, val: Option) -> Disr { - macro_rules! add1 { - ($e:expr) => { ($e).wrapping_add(1) as Disr } - } - let val = val.unwrap_or(ty::INITIAL_DISCRIMINANT_VALUE); - match *self { - SignedInt(hir::TyI8) => add1!(val as i8 ), - SignedInt(hir::TyI16) => add1!(val as i16), - SignedInt(hir::TyI32) => add1!(val as i32), - SignedInt(hir::TyI64) => add1!(val as i64), - UnsignedInt(hir::TyU8) => add1!(val as u8 ), - UnsignedInt(hir::TyU16) => add1!(val as u16), - UnsignedInt(hir::TyU32) => add1!(val as u32), - UnsignedInt(hir::TyU64) => add1!(val as u64), - - UnsignedInt(hir::TyUs) | - SignedInt(hir::TyIs) => unreachable!(), - } - } -} - #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum ImplOrTraitItemContainer { TraitContainer(DefId), @@ -435,105 +305,6 @@ pub enum Variance { Bivariant, // T <: T -- e.g., unused type parameter } -#[derive(Copy, Clone)] -pub enum AutoAdjustment<'tcx> { - AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type - AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer - AdjustDerefRef(AutoDerefRef<'tcx>), -} - -/// Represents coercing a pointer to a different kind of pointer - where 'kind' -/// here means either or both of raw vs borrowed vs unique and fat vs thin. -/// -/// We transform pointers by following the following steps in order: -/// 1. Deref the pointer `self.autoderefs` times (may be 0). -/// 2. If `autoref` is `Some(_)`, then take the address and produce either a -/// `&` or `*` pointer. -/// 3. If `unsize` is `Some(_)`, then apply the unsize transformation, -/// which will do things like convert thin pointers to fat -/// pointers, or convert structs containing thin pointers to -/// structs containing fat pointers, or convert between fat -/// pointers. We don't store the details of how the transform is -/// done (in fact, we don't know that, because it might depend on -/// the precise type parameters). We just store the target -/// type. Trans figures out what has to be done at monomorphization -/// time based on the precise source/target type at hand. -/// -/// To make that more concrete, here are some common scenarios: -/// -/// 1. The simplest cases are where the pointer is not adjusted fat vs thin. -/// Here the pointer will be dereferenced N times (where a dereference can -/// happen to to raw or borrowed pointers or any smart pointer which implements -/// Deref, including Box<_>). The number of dereferences is given by -/// `autoderefs`. It can then be auto-referenced zero or one times, indicated -/// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is -/// None. -/// -/// 2. A thin-to-fat coercon involves unsizing the underlying data. We start -/// with a thin pointer, deref a number of times, unsize the underlying data, -/// then autoref. The 'unsize' phase may change a fixed length array to a -/// dynamically sized one, a concrete object to a trait object, or statically -/// sized struct to a dyncamically sized one. E.g., &[i32; 4] -> &[i32] is -/// represented by: -/// -/// ``` -/// AutoDerefRef { -/// autoderefs: 1, // &[i32; 4] -> [i32; 4] -/// autoref: Some(AutoPtr), // [i32] -> &[i32] -/// unsize: Some([i32]), // [i32; 4] -> [i32] -/// } -/// ``` -/// -/// Note that for a struct, the 'deep' unsizing of the struct is not recorded. -/// E.g., `struct Foo { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]> -/// The autoderef and -ref are the same as in the above example, but the type -/// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about -/// the underlying conversions from `[i32; 4]` to `[i32]`. -/// -/// 3. Coercing a `Box` to `Box` is an interesting special case. In -/// that case, we have the pointer we need coming in, so there are no -/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation. -/// At some point, of course, `Box` should move out of the compiler, in which -/// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> -> -/// Box<[i32]> is represented by: -/// -/// ``` -/// AutoDerefRef { -/// autoderefs: 0, -/// autoref: None, -/// unsize: Some(Box<[i32]>), -/// } -/// ``` -#[derive(Copy, Clone)] -pub struct AutoDerefRef<'tcx> { - /// Step 1. Apply a number of dereferences, producing an lvalue. - pub autoderefs: usize, - - /// Step 2. Optionally produce a pointer/reference from the value. - pub autoref: Option>, - - /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to - /// `&[T]`. The stored type is the target pointer type. Note that - /// the source could be a thin or fat pointer. - pub unsize: Option>, -} - -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum AutoRef<'tcx> { - /// Convert from T to &T. - AutoPtr(&'tcx Region, hir::Mutability), - - /// Convert from T to *T. - /// Value to thin pointer. - AutoUnsafe(hir::Mutability), -} - -#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] -pub enum CustomCoerceUnsized { - /// Records the index of the field being coerced. - Struct(usize) -} - #[derive(Clone, Copy, Debug)] pub struct MethodCallee<'tcx> { /// Impl method ID, for inherent methods, or trait method ID, otherwise. @@ -1502,52 +1273,6 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { } } } - - pub fn can_type_implement_copy(&self, self_type: Ty<'tcx>, span: Span) - -> Result<(),CopyImplementationError> { - let tcx = self.tcx; - - // FIXME: (@jroesch) float this code up - let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(self.clone()), false); - - let adt = match self_type.sty { - ty::TyStruct(struct_def, substs) => { - for field in struct_def.all_fields() { - let field_ty = field.ty(tcx, substs); - if infcx.type_moves_by_default(field_ty, span) { - return Err(FieldDoesNotImplementCopy(field.name)) - } - } - struct_def - } - ty::TyEnum(enum_def, substs) => { - for variant in &enum_def.variants { - for field in &variant.fields { - let field_ty = field.ty(tcx, substs); - if infcx.type_moves_by_default(field_ty, span) { - return Err(VariantDoesNotImplementCopy(variant.name)) - } - } - } - enum_def - } - _ => return Err(TypeIsStructural), - }; - - if adt.has_dtor() { - return Err(TypeHasDestructor) - } - - Ok(()) - } -} - -#[derive(Copy, Clone)] -pub enum CopyImplementationError { - FieldDoesNotImplementCopy(Name), - VariantDoesNotImplementCopy(Name), - TypeIsStructural, - TypeHasDestructor, } /// A "type scheme", in ML terminology, is a type combined with some @@ -2093,16 +1818,6 @@ impl ClosureKind { } } -impl<'tcx> ctxt<'tcx> { - pub fn pat_contains_ref_binding(&self, pat: &hir::Pat) -> Option { - pat_util::pat_contains_ref_binding(&self.def_map, pat) - } - - pub fn arm_contains_ref_binding(&self, arm: &hir::Arm) -> Option { - pat_util::arm_contains_ref_binding(&self.def_map, arm) - } -} - impl<'tcx> TyS<'tcx> { /// Iterator that walks `self` and any types reachable from /// `self`, in depth-first order. Note that just walks the types @@ -2125,63 +1840,6 @@ impl<'tcx> TyS<'tcx> { walk::walk_shallow(self) } - pub fn as_opt_param_ty(&self) -> Option { - 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 { - 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 - } - TyEnum(_, substs) | - TyStruct(_, substs) => { - substs.regions().as_slice().to_vec() - } - TyClosure(_, ref substs) => { - substs.func_substs.regions().as_slice().to_vec() - } - TyProjection(ref data) => { - data.trait_ref.substs.regions().as_slice().to_vec() - } - TyBareFn(..) | - TyBool | - TyChar | - TyInt(_) | - TyUint(_) | - TyFloat(_) | - TyBox(_) | - TyStr | - TyArray(_, _) | - TySlice(_) | - TyRawPtr(_) | - TyTuple(_) | - TyParam(_) | - 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. @@ -2199,31 +1857,6 @@ impl<'tcx> TyS<'tcx> { } } -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() } @@ -2234,99 +1867,6 @@ impl<'tcx> ItemSubsts<'tcx> { } } -impl<'tcx> TyS<'tcx> { - fn impls_bound<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, - bound: ty::BuiltinBound, - span: Span) - -> bool - { - let tcx = param_env.tcx; - let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env.clone()), false); - - let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, - self, bound, span); - - debug!("Ty::impls_bound({:?}, {:?}) = {:?}", - self, bound, is_impld); - - is_impld - } - - // FIXME (@jroesch): I made this public to use it, not sure if should be private - pub fn moves_by_default<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, - span: Span) -> bool { - if self.flags.get().intersects(TypeFlags::MOVENESS_CACHED) { - return self.flags.get().intersects(TypeFlags::MOVES_BY_DEFAULT); - } - - assert!(!self.needs_infer()); - - // Fast-path for primitive types - let result = match self.sty { - TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | - TyRawPtr(..) | TyBareFn(..) | TyRef(_, TypeAndMut { - mutbl: hir::MutImmutable, .. - }) => Some(false), - - TyStr | TyBox(..) | TyRef(_, TypeAndMut { - mutbl: hir::MutMutable, .. - }) => Some(true), - - TyArray(..) | TySlice(_) | TyTrait(..) | TyTuple(..) | - TyClosure(..) | TyEnum(..) | TyStruct(..) | - TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None - }.unwrap_or_else(|| !self.impls_bound(param_env, ty::BoundCopy, span)); - - if !self.has_param_types() && !self.has_self_ty() { - self.flags.set(self.flags.get() | if result { - TypeFlags::MOVENESS_CACHED | TypeFlags::MOVES_BY_DEFAULT - } else { - TypeFlags::MOVENESS_CACHED - }); - } - - result - } - - #[inline] - pub fn is_sized<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, - span: Span) -> bool - { - if self.flags.get().intersects(TypeFlags::SIZEDNESS_CACHED) { - return self.flags.get().intersects(TypeFlags::IS_SIZED); - } - - self.is_sized_uncached(param_env, span) - } - - fn is_sized_uncached<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, - span: Span) -> bool { - assert!(!self.needs_infer()); - - // Fast-path for primitive types - let result = match self.sty { - TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | - TyBox(..) | TyRawPtr(..) | TyRef(..) | TyBareFn(..) | - TyArray(..) | TyTuple(..) | TyClosure(..) => Some(true), - - TyStr | TyTrait(..) | TySlice(_) => Some(false), - - TyEnum(..) | TyStruct(..) | TyProjection(..) | TyParam(..) | - TyInfer(..) | TyError => None - }.unwrap_or_else(|| self.impls_bound(param_env, ty::BoundSized, span)); - - if !self.has_param_types() && !self.has_self_ty() { - self.flags.set(self.flags.get() | if result { - TypeFlags::SIZEDNESS_CACHED | TypeFlags::IS_SIZED - } else { - TypeFlags::SIZEDNESS_CACHED - }); - } - - result - } -} - #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum LvaluePreference { PreferMutLvalue, @@ -2342,283 +1882,6 @@ impl LvaluePreference { } } -/// Describes whether a type is representable. For types that are not -/// representable, 'SelfRecursive' and 'ContainsRecursive' are used to -/// distinguish between types that are recursive with themselves and types that -/// contain a different recursive type. These cases can therefore be treated -/// differently when reporting errors. -/// -/// The ordering of the cases is significant. They are sorted so that cmp::max -/// will keep the "more erroneous" of two values. -#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Debug)] -pub enum Representability { - Representable, - ContainsRecursive, - SelfRecursive, -} - -impl<'tcx> TyS<'tcx> { - /// Check whether a type is representable. This means it cannot contain unboxed - /// structural recursion. This check is needed for structs and enums. - pub fn is_representable(&'tcx self, cx: &ctxt<'tcx>, sp: Span) -> Representability { - - // Iterate until something non-representable is found - fn find_nonrepresentable<'tcx, It: Iterator>>(cx: &ctxt<'tcx>, sp: Span, - seen: &mut Vec>, - iter: It) - -> Representability { - iter.fold(Representable, - |r, ty| cmp::max(r, is_type_structurally_recursive(cx, sp, seen, ty))) - } - - fn are_inner_types_recursive<'tcx>(cx: &ctxt<'tcx>, sp: Span, - seen: &mut Vec>, ty: Ty<'tcx>) - -> Representability { - match ty.sty { - TyTuple(ref ts) => { - find_nonrepresentable(cx, sp, seen, ts.iter().cloned()) - } - // Fixed-length vectors. - // FIXME(#11924) Behavior undecided for zero-length vectors. - TyArray(ty, _) => { - is_type_structurally_recursive(cx, sp, seen, ty) - } - TyStruct(def, substs) | TyEnum(def, substs) => { - find_nonrepresentable(cx, - sp, - seen, - def.all_fields().map(|f| f.ty(cx, substs))) - } - TyClosure(..) => { - // this check is run on type definitions, so we don't expect - // to see closure types - cx.sess.bug(&format!("requires check invoked on inapplicable type: {:?}", ty)) - } - _ => Representable, - } - } - - fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: AdtDef<'tcx>) -> bool { - match ty.sty { - TyStruct(ty_def, _) | TyEnum(ty_def, _) => { - ty_def == def - } - _ => false - } - } - - fn same_type<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - match (&a.sty, &b.sty) { - (&TyStruct(did_a, ref substs_a), &TyStruct(did_b, ref substs_b)) | - (&TyEnum(did_a, ref substs_a), &TyEnum(did_b, ref substs_b)) => { - if did_a != did_b { - return false; - } - - let types_a = substs_a.types.get_slice(subst::TypeSpace); - let types_b = substs_b.types.get_slice(subst::TypeSpace); - - let mut pairs = types_a.iter().zip(types_b); - - pairs.all(|(&a, &b)| same_type(a, b)) - } - _ => { - a == b - } - } - } - - // Does the type `ty` directly (without indirection through a pointer) - // contain any types on stack `seen`? - fn is_type_structurally_recursive<'tcx>(cx: &ctxt<'tcx>, sp: Span, - seen: &mut Vec>, - ty: Ty<'tcx>) -> Representability { - debug!("is_type_structurally_recursive: {:?}", ty); - - match ty.sty { - TyStruct(def, _) | TyEnum(def, _) => { - { - // Iterate through stack of previously seen types. - let mut iter = seen.iter(); - - // The first item in `seen` is the type we are actually curious about. - // We want to return SelfRecursive if this type contains itself. - // It is important that we DON'T take generic parameters into account - // for this check, so that Bar in this example counts as SelfRecursive: - // - // struct Foo; - // struct Bar { x: Bar } - - match iter.next() { - Some(&seen_type) => { - if same_struct_or_enum(seen_type, def) { - debug!("SelfRecursive: {:?} contains {:?}", - seen_type, - ty); - return SelfRecursive; - } - } - None => {} - } - - // We also need to know whether the first item contains other types - // that are structurally recursive. If we don't catch this case, we - // will recurse infinitely for some inputs. - // - // It is important that we DO take generic parameters into account - // here, so that code like this is considered SelfRecursive, not - // ContainsRecursive: - // - // struct Foo { Option> } - - for &seen_type in iter { - if same_type(ty, seen_type) { - debug!("ContainsRecursive: {:?} contains {:?}", - seen_type, - ty); - return ContainsRecursive; - } - } - } - - // For structs and enums, track all previously seen types by pushing them - // onto the 'seen' stack. - seen.push(ty); - let out = are_inner_types_recursive(cx, sp, seen, ty); - seen.pop(); - out - } - _ => { - // No need to push in other cases. - are_inner_types_recursive(cx, sp, seen, ty) - } - } - } - - debug!("is_type_representable: {:?}", self); - - // To avoid a stack overflow when checking an enum variant or struct that - // contains a different, structurally recursive type, maintain a stack - // of seen types and check recursion for each of them (issues #3008, #3779). - let mut seen: Vec = Vec::new(); - let r = is_type_structurally_recursive(cx, sp, &mut seen, self); - debug!("is_type_representable: {:?} is {:?}", self, r); - r - } - - /// See `expr_ty_adjusted` - pub fn adjust(&'tcx self, cx: &ctxt<'tcx>, - span: Span, - expr_id: NodeId, - adjustment: Option<&AutoAdjustment<'tcx>>, - mut method_type: F) - -> Ty<'tcx> where - F: FnMut(MethodCall) -> Option>, - { - if let TyError = self.sty { - return self; - } - - return match adjustment { - Some(adjustment) => { - match *adjustment { - AdjustReifyFnPointer => { - match self.sty { - ty::TyBareFn(Some(_), b) => { - cx.mk_fn(None, b) - } - _ => { - cx.sess.bug( - &format!("AdjustReifyFnPointer adjustment on non-fn-item: \ - {:?}", self)); - } - } - } - - AdjustUnsafeFnPointer => { - match self.sty { - ty::TyBareFn(None, b) => cx.safe_to_unsafe_fn_ty(b), - ref b => { - cx.sess.bug( - &format!("AdjustReifyFnPointer adjustment on non-fn-item: \ - {:?}", - b)); - } - } - } - - AdjustDerefRef(ref adj) => { - let mut adjusted_ty = self; - - if !adjusted_ty.references_error() { - for i in 0..adj.autoderefs { - adjusted_ty = - adjusted_ty.adjust_for_autoderef(cx, - expr_id, - span, - i as u32, - &mut method_type); - } - } - - if let Some(target) = adj.unsize { - target - } else { - adjusted_ty.adjust_for_autoref(cx, adj.autoref) - } - } - } - } - None => self - }; - } - - pub fn adjust_for_autoderef(&'tcx self, - cx: &ctxt<'tcx>, - expr_id: ast::NodeId, - expr_span: Span, - autoderef: u32, // how many autoderefs so far? - mut method_type: F) - -> Ty<'tcx> where - F: FnMut(MethodCall) -> Option>, - { - let method_call = MethodCall::autoderef(expr_id, autoderef); - let mut adjusted_ty = self; - if let Some(method_ty) = method_type(method_call) { - // Method calls always have all late-bound regions - // fully instantiated. - let fn_ret = cx.no_late_bound_regions(&method_ty.fn_ret()).unwrap(); - adjusted_ty = fn_ret.unwrap(); - } - match adjusted_ty.builtin_deref(true, NoPreference) { - Some(mt) => mt.ty, - None => { - cx.sess.span_bug( - expr_span, - &format!("the {}th autoderef failed: {}", - autoderef, - adjusted_ty) - ); - } - } - } - - pub fn adjust_for_autoref(&'tcx self, cx: &ctxt<'tcx>, - autoref: Option>) - -> Ty<'tcx> { - match autoref { - None => self, - Some(AutoPtr(r, m)) => { - cx.mk_ref(r, TypeAndMut { ty: self, mutbl: m }) - } - Some(AutoUnsafe(m)) => { - cx.mk_ptr(TypeAndMut { ty: self, mutbl: m }) - } - } - } - -} - /// Helper for looking things up in the various maps that are populated during /// typeck::collect (e.g., `cx.impl_or_trait_items`, `cx.tcache`, etc). All of /// these share the pattern that if the id is local, it should have been loaded @@ -2679,45 +1942,6 @@ impl BorrowKind { } impl<'tcx> ctxt<'tcx> { - /// Returns the type of element at index `i` in tuple or tuple-like type `t`. - /// For an enum `t`, `variant` is None only if `t` is a univariant enum. - pub fn positional_element_ty(&self, - ty: Ty<'tcx>, - i: usize, - variant: Option) -> Option> { - match (&ty.sty, variant) { - (&TyStruct(def, substs), None) => { - def.struct_variant().fields.get(i).map(|f| f.ty(self, substs)) - } - (&TyEnum(def, substs), Some(vid)) => { - def.variant_with_id(vid).fields.get(i).map(|f| f.ty(self, substs)) - } - (&TyEnum(def, substs), None) => { - assert!(def.is_univariant()); - def.variants[0].fields.get(i).map(|f| f.ty(self, substs)) - } - (&TyTuple(ref v), None) => v.get(i).cloned(), - _ => None - } - } - - /// Returns the type of element at field `n` in struct or struct-like type `t`. - /// For an enum `t`, `variant` must be some def id. - pub fn named_element_ty(&self, - ty: Ty<'tcx>, - n: Name, - variant: Option) -> Option> { - match (&ty.sty, variant) { - (&TyStruct(def, substs), None) => { - def.struct_variant().find_field_named(n).map(|f| f.ty(self, substs)) - } - (&TyEnum(def, substs), Some(vid)) => { - def.variant_with_id(vid).find_field_named(n).map(|f| f.ty(self, substs)) - } - _ => return None - } - } - pub fn node_id_to_type(&self, id: NodeId) -> Ty<'tcx> { match self.node_id_to_type_opt(id) { Some(ty) => ty, @@ -2992,7 +2216,7 @@ impl<'tcx> ctxt<'tcx> { } } - pub fn custom_coerce_unsized_kind(&self, did: DefId) -> CustomCoerceUnsized { + pub fn custom_coerce_unsized_kind(&self, did: DefId) -> adjustment::CustomCoerceUnsized { memoized(&self.custom_coerce_unsized_kinds, did, |did: DefId| { let (kind, src) = if did.krate != LOCAL_CRATE { (csearch::get_custom_coerce_unsized_kind(self, did), "external") @@ -3071,35 +2295,6 @@ impl<'tcx> ctxt<'tcx> { } } - /// Returns `(normalized_type, ty)`, where `normalized_type` is the - /// IntType representation of one of {i64,i32,i16,i8,u64,u32,u16,u8}, - /// and `ty` is the original type (i.e. may include `isize` or - /// `usize`). - pub fn enum_repr_type(&self, opt_hint: Option<&attr::ReprAttr>) - -> (attr::IntType, Ty<'tcx>) { - let repr_type = match opt_hint { - // Feed in the given type - Some(&attr::ReprInt(_, int_t)) => int_t, - // ... but provide sensible default if none provided - // - // NB. Historically `fn enum_variants` generate i64 here, while - // rustc_typeck::check would generate isize. - _ => SignedInt(hir::TyIs), - }; - - let repr_type_ty = repr_type.to_ty(self); - let repr_type = match repr_type { - SignedInt(hir::TyIs) => - SignedInt(self.sess.target.int_type), - UnsignedInt(hir::TyUs) => - UnsignedInt(self.sess.target.uint_type), - other => other - }; - - (repr_type, repr_type_ty) - } - - // Register a given item type pub fn register_item_type(&self, did: DefId, ty: TypeScheme<'tcx>) { self.tcache.borrow_mut().insert(did, ty); @@ -3195,155 +2390,6 @@ impl<'tcx> ctxt<'tcx> { }) } - - /// Returns the deeply last field of nested structures, or the same type, - /// if not a structure at all. Corresponds to the only possible unsized - /// field, and its type can be used to determine unsizing strategy. - pub fn struct_tail(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { - while let TyStruct(def, substs) = ty.sty { - match def.struct_variant().fields.last() { - Some(f) => ty = f.ty(self, substs), - None => break - } - } - ty - } - - /// Same as applying struct_tail on `source` and `target`, but only - /// keeps going as long as the two types are instances of the same - /// structure definitions. - /// For `(Foo>, Foo)`, the result will be `(Foo, Trait)`, - /// whereas struct_tail produces `T`, and `Trait`, respectively. - pub fn struct_lockstep_tails(&self, - source: Ty<'tcx>, - target: Ty<'tcx>) - -> (Ty<'tcx>, Ty<'tcx>) { - let (mut a, mut b) = (source, target); - while let (&TyStruct(a_def, a_substs), &TyStruct(b_def, b_substs)) = (&a.sty, &b.sty) { - if a_def != b_def { - break; - } - if let Some(f) = a_def.struct_variant().fields.last() { - a = f.ty(self, a_substs); - b = f.ty(self, b_substs); - } else { - break; - } - } - (a, b) - } - - // Returns the repeat count for a repeating vector expression. - pub fn eval_repeat_count(&self, count_expr: &hir::Expr) -> usize { - let hint = UncheckedExprHint(self.types.usize); - match const_eval::eval_const_expr_partial(self, count_expr, hint) { - Ok(val) => { - let found = match val { - ConstVal::Uint(count) => return count as usize, - ConstVal::Int(count) if count >= 0 => return count as usize, - const_val => const_val.description(), - }; - span_err!(self.sess, count_expr.span, E0306, - "expected positive integer for repeat count, found {}", - found); - } - Err(err) => { - let err_msg = match count_expr.node { - hir::ExprPath(None, hir::Path { - global: false, - ref segments, - .. - }) if segments.len() == 1 => - format!("found variable"), - _ => match err.kind { - ErrKind::MiscCatchAll => format!("but found {}", err.description()), - _ => format!("but {}", err.description()) - } - }; - span_err!(self.sess, count_expr.span, E0307, - "expected constant integer for repeat count, {}", err_msg); - } - } - 0 - } - - // Iterate over a type parameter's bounded traits and any supertraits - // of those traits, ignoring kinds. - // Here, the supertraits are the transitive closure of the supertrait - // relation on the supertraits from each bounded trait's constraint - // list. - pub fn each_bound_trait_and_supertraits(&self, - bounds: &[PolyTraitRef<'tcx>], - mut f: F) - -> bool where - F: FnMut(PolyTraitRef<'tcx>) -> bool, - { - for bound_trait_ref in traits::transitive_bounds(self, bounds) { - if !f(bound_trait_ref) { - return false; - } - } - return true; - } - - /// Given a set of predicates that apply to an object type, returns - /// the region bounds that the (erased) `Self` type must - /// outlive. Precisely *because* the `Self` type is erased, the - /// parameter `erased_self_ty` must be supplied to indicate what type - /// has been used to represent `Self` in the predicates - /// themselves. This should really be a unique type; `FreshTy(0)` is a - /// popular choice. - /// - /// NB: in some cases, particularly around higher-ranked bounds, - /// this function returns a kind of conservative approximation. - /// That is, all regions returned by this function are definitely - /// required, but there may be other region bounds that are not - /// returned, as well as requirements like `for<'a> T: 'a`. - /// - /// Requires that trait definitions have been processed so that we can - /// elaborate predicates and walk supertraits. - pub fn required_region_bounds(&self, - erased_self_ty: Ty<'tcx>, - predicates: Vec>) - -> Vec { - debug!("required_region_bounds(erased_self_ty={:?}, predicates={:?})", - erased_self_ty, - predicates); - - assert!(!erased_self_ty.has_escaping_regions()); - - traits::elaborate_predicates(self, predicates) - .filter_map(|predicate| { - match predicate { - ty::Predicate::Projection(..) | - ty::Predicate::Trait(..) | - ty::Predicate::Equate(..) | - ty::Predicate::WellFormed(..) | - ty::Predicate::ObjectSafe(..) | - ty::Predicate::RegionOutlives(..) => { - None - } - ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t, r))) => { - // Search for a bound of the form `erased_self_ty - // : 'a`, but be wary of something like `for<'a> - // erased_self_ty : 'a` (we interpret a - // higher-ranked bound like that as 'static, - // though at present the code in `fulfill.rs` - // considers such bounds to be unsatisfiable, so - // it's kind of a moot point since you could never - // construct such an object, but this seems - // correct even if that code changes). - if t == erased_self_ty && !r.has_escaping_regions() { - Some(r) - } else { - None - } - } - } - }) - .collect() - } - pub fn item_variances(&self, item_id: DefId) -> Rc { lookup_locally_or_in_crate_store( "item_variance_map", item_id, &self.item_variance_map, @@ -3527,148 +2573,6 @@ impl<'tcx> ctxt<'tcx> { } } - /// Creates a hash of the type `Ty` which will be the same no matter what crate - /// context it's calculated within. This is used by the `type_id` intrinsic. - pub fn hash_crate_independent(&self, ty: Ty<'tcx>, svh: &Svh) -> u64 { - let mut state = SipHasher::new(); - helper(self, ty, svh, &mut state); - return state.finish(); - - fn helper<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh, - state: &mut SipHasher) { - macro_rules! byte { ($b:expr) => { ($b as u8).hash(state) } } - macro_rules! hash { ($e:expr) => { $e.hash(state) } } - - let region = |state: &mut SipHasher, r: Region| { - match r { - ReStatic => {} - ReLateBound(db, BrAnon(i)) => { - db.hash(state); - i.hash(state); - } - ReEmpty | - ReEarlyBound(..) | - ReLateBound(..) | - ReFree(..) | - ReScope(..) | - ReVar(..) | - ReSkolemized(..) => { - tcx.sess.bug("unexpected region found when hashing a type") - } - } - }; - let did = |state: &mut SipHasher, did: DefId| { - let h = if did.is_local() { - svh.clone() - } else { - tcx.sess.cstore.get_crate_hash(did.krate) - }; - h.as_str().hash(state); - did.node.hash(state); - }; - let mt = |state: &mut SipHasher, mt: TypeAndMut| { - mt.mutbl.hash(state); - }; - let fn_sig = |state: &mut SipHasher, sig: &Binder>| { - let sig = tcx.anonymize_late_bound_regions(sig).0; - for a in &sig.inputs { helper(tcx, *a, svh, state); } - if let ty::FnConverging(output) = sig.output { - helper(tcx, output, svh, state); - } - }; - ty.maybe_walk(|ty| { - match ty.sty { - TyBool => byte!(2), - TyChar => byte!(3), - TyInt(i) => { - byte!(4); - hash!(i); - } - TyUint(u) => { - byte!(5); - hash!(u); - } - TyFloat(f) => { - byte!(6); - hash!(f); - } - TyStr => { - byte!(7); - } - TyEnum(d, _) => { - byte!(8); - did(state, d.did); - } - TyBox(_) => { - byte!(9); - } - TyArray(_, n) => { - byte!(10); - n.hash(state); - } - TySlice(_) => { - byte!(11); - } - TyRawPtr(m) => { - byte!(12); - mt(state, m); - } - TyRef(r, m) => { - byte!(13); - region(state, *r); - mt(state, m); - } - TyBareFn(opt_def_id, ref b) => { - byte!(14); - hash!(opt_def_id); - hash!(b.unsafety); - hash!(b.abi); - fn_sig(state, &b.sig); - return false; - } - TyTrait(ref data) => { - byte!(17); - did(state, data.principal_def_id()); - hash!(data.bounds); - - let principal = tcx.anonymize_late_bound_regions(&data.principal).0; - for subty in &principal.substs.types { - helper(tcx, subty, svh, state); - } - - return false; - } - TyStruct(d, _) => { - byte!(18); - did(state, d.did); - } - TyTuple(ref inner) => { - byte!(19); - hash!(inner.len()); - } - TyParam(p) => { - byte!(20); - hash!(p.space); - hash!(p.idx); - hash!(p.name.as_str()); - } - TyInfer(_) => unreachable!(), - TyError => byte!(21), - TyClosure(d, _) => { - byte!(22); - did(state, d); - } - TyProjection(ref data) => { - byte!(23); - did(state, data.trait_ref.def_id); - hash!(data.item_name.as_str()); - } - } - true - }); - } - } - /// Construct a parameter environment suitable for static contexts or other contexts where there /// are no free type/lifetime parameters in scope. pub fn empty_parameter_environment<'a>(&'a self) @@ -3786,87 +2690,6 @@ impl<'tcx> ctxt<'tcx> { pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option { Some(self.tables.borrow().upvar_capture_map.get(&upvar_id).unwrap().clone()) } - - - /// Returns true if this ADT is a dtorck type, i.e. whether it being - /// safe for destruction requires it to be alive - fn is_adt_dtorck(&self, adt: AdtDef<'tcx>) -> bool { - let dtor_method = match adt.destructor() { - Some(dtor) => dtor, - None => return false - }; - let impl_did = self.impl_of_method(dtor_method).unwrap_or_else(|| { - self.sess.bug(&format!("no Drop impl for the dtor of `{:?}`", adt)) - }); - let generics = adt.type_scheme(self).generics; - - // In `impl<'a> Drop ...`, we automatically assume - // `'a` is meaningful and thus represents a bound - // through which we could reach borrowed data. - // - // FIXME (pnkfelix): In the future it would be good to - // extend the language to allow the user to express, - // in the impl signature, that a lifetime is not - // actually used (something like `where 'a: ?Live`). - if generics.has_region_params(subst::TypeSpace) { - debug!("typ: {:?} has interesting dtor due to region params", - adt); - return true; - } - - let mut seen_items = Vec::new(); - let mut items_to_inspect = vec![impl_did]; - while let Some(item_def_id) = items_to_inspect.pop() { - if seen_items.contains(&item_def_id) { - continue; - } - - for pred in self.lookup_predicates(item_def_id).predicates { - let result = match pred { - ty::Predicate::Equate(..) | - ty::Predicate::RegionOutlives(..) | - ty::Predicate::TypeOutlives(..) | - ty::Predicate::WellFormed(..) | - ty::Predicate::ObjectSafe(..) | - ty::Predicate::Projection(..) => { - // For now, assume all these where-clauses - // may give drop implementation capabilty - // to access borrowed data. - true - } - - ty::Predicate::Trait(ty::Binder(ref t_pred)) => { - let def_id = t_pred.trait_ref.def_id; - if self.trait_items(def_id).len() != 0 { - // If trait has items, assume it adds - // capability to access borrowed data. - true - } else { - // Trait without items is itself - // uninteresting from POV of dropck. - // - // However, may have parent w/ items; - // so schedule checking of predicates, - items_to_inspect.push(def_id); - // and say "no capability found" for now. - false - } - } - }; - - if result { - debug!("typ: {:?} has interesting dtor due to generic preds, e.g. {:?}", - adt, pred); - return true; - } - } - - seen_items.push(item_def_id); - } - - debug!("typ: {:?} is dtorck-safe", adt); - false - } } /// The category of explicit self. @@ -3899,22 +2722,6 @@ pub type TraitMap = NodeMap>; // imported. pub type GlobMap = HashMap>; -impl<'tcx> AutoAdjustment<'tcx> { - pub fn is_identity(&self) -> bool { - match *self { - AdjustReifyFnPointer | - AdjustUnsafeFnPointer => false, - AdjustDerefRef(ref r) => r.is_identity(), - } - } -} - -impl<'tcx> AutoDerefRef<'tcx> { - pub fn is_identity(&self) -> bool { - self.autoderefs == 0 && self.unsize.is_none() && self.autoref.is_none() - } -} - impl<'tcx> ctxt<'tcx> { pub fn with_freevars(&self, fid: NodeId, f: F) -> T where F: FnOnce(&[Freevar]) -> T, diff --git a/src/librustc/middle/ty/structural_impls.rs b/src/librustc/middle/ty/structural_impls.rs index 94e4672ea9710..0058ccbce3b19 100644 --- a/src/librustc/middle/ty/structural_impls.rs +++ b/src/librustc/middle/ty/structural_impls.rs @@ -641,8 +641,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ItemSubsts<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::AutoRef<'tcx> { - fn fold_with>(&self, folder: &mut F) -> ty::AutoRef<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoRef<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::adjustment::AutoRef<'tcx> { folder.fold_autoref(self) } } diff --git a/src/librustc/middle/ty/sty.rs b/src/librustc/middle/ty/sty.rs index a04cc89ee18a0..3969738a22e86 100644 --- a/src/librustc/middle/ty/sty.rs +++ b/src/librustc/middle/ty/sty.rs @@ -24,6 +24,7 @@ use std::ops; use std::mem; use syntax::abi; use syntax::ast::{Name, NodeId}; +use syntax::parse::token::special_idents; use rustc_front::hir; @@ -504,6 +505,31 @@ pub struct ParamTy { pub name: Name, } +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: &ty::TypeParameterDef) -> ParamTy { + ParamTy::new(def.space, def.index, def.name) + } + + pub fn to_ty<'tcx>(self, tcx: &ty::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 + } +} + /// 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: @@ -844,6 +870,13 @@ impl Region { // Type utilities impl<'tcx> TyS<'tcx> { + pub fn as_opt_param_ty(&self) -> Option { + match self.sty { + ty::TyParam(ref d) => Some(d.clone()), + _ => None, + } + } + pub fn is_nil(&self) -> bool { match self.sty { TyTuple(ref tys) => tys.is_empty(), @@ -868,6 +901,13 @@ impl<'tcx> TyS<'tcx> { pub fn is_bool(&self) -> bool { self.sty == TyBool } + pub fn is_param(&self, space: subst::ParamSpace, index: u32) -> bool { + match self.sty { + ty::TyParam(ref data) => data.space == space && data.idx == index, + _ => false, + } + } + pub fn is_self(&self) -> bool { match self.sty { TyParam(ref p) => p.space == subst::SelfSpace, @@ -1126,4 +1166,47 @@ impl<'tcx> TyS<'tcx> { _ => None } } + + /// 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 { + 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 + } + TyEnum(_, substs) | + TyStruct(_, substs) => { + substs.regions().as_slice().to_vec() + } + TyClosure(_, ref substs) => { + substs.func_substs.regions().as_slice().to_vec() + } + TyProjection(ref data) => { + data.trait_ref.substs.regions().as_slice().to_vec() + } + TyBareFn(..) | + TyBool | + TyChar | + TyInt(_) | + TyUint(_) | + TyFloat(_) | + TyBox(_) | + TyStr | + TyArray(_, _) | + TySlice(_) | + TyRawPtr(_) | + TyTuple(_) | + TyParam(_) | + TyInfer(_) | + TyError => { + vec![] + } + } + } } diff --git a/src/librustc/middle/ty/util.rs b/src/librustc/middle/ty/util.rs new file mode 100644 index 0000000000000..8831461853576 --- /dev/null +++ b/src/librustc/middle/ty/util.rs @@ -0,0 +1,891 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! misc. type-system utilities too small to deserve their own file + +use back::svh::Svh; +use middle::const_eval::{self, ConstVal, ErrKind}; +use middle::const_eval::EvalHint::UncheckedExprHint; +use middle::def_id::DefId; +use middle::subst; +use middle::infer; +use middle::pat_util; +use middle::traits; +use middle::ty::{self, Ty, TypeAndMut, TypeFlags}; +use middle::ty::{Disr, ParameterEnvironment}; +use middle::ty::{HasTypeFlags, RegionEscape}; +use middle::ty::TypeVariants::*; +use util::num::ToPrimitive; + +use std::cmp; +use std::hash::{Hash, SipHasher, Hasher}; +use syntax::ast::Name; +use syntax::codemap::Span; + +use rustc_front::hir; +use rustc_front::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt}; + +pub trait IntTypeExt { + fn to_ty<'tcx>(&self, cx: &ty::ctxt<'tcx>) -> Ty<'tcx>; + fn i64_to_disr(&self, val: i64) -> Option; + fn u64_to_disr(&self, val: u64) -> Option; + fn disr_incr(&self, val: Disr) -> Option; + fn disr_string(&self, val: Disr) -> String; + fn disr_wrap_incr(&self, val: Option) -> Disr; +} + +impl IntTypeExt for attr::IntType { + fn to_ty<'tcx>(&self, cx: &ty::ctxt<'tcx>) -> Ty<'tcx> { + match *self { + SignedInt(hir::TyI8) => cx.types.i8, + SignedInt(hir::TyI16) => cx.types.i16, + SignedInt(hir::TyI32) => cx.types.i32, + SignedInt(hir::TyI64) => cx.types.i64, + SignedInt(hir::TyIs) => cx.types.isize, + UnsignedInt(hir::TyU8) => cx.types.u8, + UnsignedInt(hir::TyU16) => cx.types.u16, + UnsignedInt(hir::TyU32) => cx.types.u32, + UnsignedInt(hir::TyU64) => cx.types.u64, + UnsignedInt(hir::TyUs) => cx.types.usize, + } + } + + fn i64_to_disr(&self, val: i64) -> Option { + match *self { + SignedInt(hir::TyI8) => val.to_i8() .map(|v| v as Disr), + SignedInt(hir::TyI16) => val.to_i16() .map(|v| v as Disr), + SignedInt(hir::TyI32) => val.to_i32() .map(|v| v as Disr), + SignedInt(hir::TyI64) => val.to_i64() .map(|v| v as Disr), + UnsignedInt(hir::TyU8) => val.to_u8() .map(|v| v as Disr), + UnsignedInt(hir::TyU16) => val.to_u16() .map(|v| v as Disr), + UnsignedInt(hir::TyU32) => val.to_u32() .map(|v| v as Disr), + UnsignedInt(hir::TyU64) => val.to_u64() .map(|v| v as Disr), + + UnsignedInt(hir::TyUs) | + SignedInt(hir::TyIs) => unreachable!(), + } + } + + fn u64_to_disr(&self, val: u64) -> Option { + match *self { + SignedInt(hir::TyI8) => val.to_i8() .map(|v| v as Disr), + SignedInt(hir::TyI16) => val.to_i16() .map(|v| v as Disr), + SignedInt(hir::TyI32) => val.to_i32() .map(|v| v as Disr), + SignedInt(hir::TyI64) => val.to_i64() .map(|v| v as Disr), + UnsignedInt(hir::TyU8) => val.to_u8() .map(|v| v as Disr), + UnsignedInt(hir::TyU16) => val.to_u16() .map(|v| v as Disr), + UnsignedInt(hir::TyU32) => val.to_u32() .map(|v| v as Disr), + UnsignedInt(hir::TyU64) => val.to_u64() .map(|v| v as Disr), + + UnsignedInt(hir::TyUs) | + SignedInt(hir::TyIs) => unreachable!(), + } + } + + fn disr_incr(&self, val: Disr) -> Option { + macro_rules! add1 { + ($e:expr) => { $e.and_then(|v|v.checked_add(1)).map(|v| v as Disr) } + } + match *self { + // SignedInt repr means we *want* to reinterpret the bits + // treating the highest bit of Disr as a sign-bit, so + // cast to i64 before range-checking. + SignedInt(hir::TyI8) => add1!((val as i64).to_i8()), + SignedInt(hir::TyI16) => add1!((val as i64).to_i16()), + SignedInt(hir::TyI32) => add1!((val as i64).to_i32()), + SignedInt(hir::TyI64) => add1!(Some(val as i64)), + + UnsignedInt(hir::TyU8) => add1!(val.to_u8()), + UnsignedInt(hir::TyU16) => add1!(val.to_u16()), + UnsignedInt(hir::TyU32) => add1!(val.to_u32()), + UnsignedInt(hir::TyU64) => add1!(Some(val)), + + UnsignedInt(hir::TyUs) | + SignedInt(hir::TyIs) => unreachable!(), + } + } + + // This returns a String because (1.) it is only used for + // rendering an error message and (2.) a string can represent the + // full range from `i64::MIN` through `u64::MAX`. + fn disr_string(&self, val: Disr) -> String { + match *self { + SignedInt(hir::TyI8) => format!("{}", val as i8 ), + SignedInt(hir::TyI16) => format!("{}", val as i16), + SignedInt(hir::TyI32) => format!("{}", val as i32), + SignedInt(hir::TyI64) => format!("{}", val as i64), + UnsignedInt(hir::TyU8) => format!("{}", val as u8 ), + UnsignedInt(hir::TyU16) => format!("{}", val as u16), + UnsignedInt(hir::TyU32) => format!("{}", val as u32), + UnsignedInt(hir::TyU64) => format!("{}", val as u64), + + UnsignedInt(hir::TyUs) | + SignedInt(hir::TyIs) => unreachable!(), + } + } + + fn disr_wrap_incr(&self, val: Option) -> Disr { + macro_rules! add1 { + ($e:expr) => { ($e).wrapping_add(1) as Disr } + } + let val = val.unwrap_or(ty::INITIAL_DISCRIMINANT_VALUE); + match *self { + SignedInt(hir::TyI8) => add1!(val as i8 ), + SignedInt(hir::TyI16) => add1!(val as i16), + SignedInt(hir::TyI32) => add1!(val as i32), + SignedInt(hir::TyI64) => add1!(val as i64), + UnsignedInt(hir::TyU8) => add1!(val as u8 ), + UnsignedInt(hir::TyU16) => add1!(val as u16), + UnsignedInt(hir::TyU32) => add1!(val as u32), + UnsignedInt(hir::TyU64) => add1!(val as u64), + + UnsignedInt(hir::TyUs) | + SignedInt(hir::TyIs) => unreachable!(), + } + } +} + + +#[derive(Copy, Clone)] +pub enum CopyImplementationError { + InfrigingField(Name), + InfrigingVariant(Name), + NotAnAdt, + HasDestructor +} + +/// Describes whether a type is representable. For types that are not +/// representable, 'SelfRecursive' and 'ContainsRecursive' are used to +/// distinguish between types that are recursive with themselves and types that +/// contain a different recursive type. These cases can therefore be treated +/// differently when reporting errors. +/// +/// The ordering of the cases is significant. They are sorted so that cmp::max +/// will keep the "more erroneous" of two values. +#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Debug)] +pub enum Representability { + Representable, + ContainsRecursive, + SelfRecursive, +} + +impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { + pub fn can_type_implement_copy(&self, self_type: Ty<'tcx>, span: Span) + -> Result<(),CopyImplementationError> { + let tcx = self.tcx; + + // FIXME: (@jroesch) float this code up + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(self.clone()), false); + + let adt = match self_type.sty { + ty::TyStruct(struct_def, substs) => { + for field in struct_def.all_fields() { + let field_ty = field.ty(tcx, substs); + if infcx.type_moves_by_default(field_ty, span) { + return Err(CopyImplementationError::InfrigingField( + field.name)) + } + } + struct_def + } + ty::TyEnum(enum_def, substs) => { + for variant in &enum_def.variants { + for field in &variant.fields { + let field_ty = field.ty(tcx, substs); + if infcx.type_moves_by_default(field_ty, span) { + return Err(CopyImplementationError::InfrigingVariant( + variant.name)) + } + } + } + enum_def + } + _ => return Err(CopyImplementationError::NotAnAdt), + }; + + if adt.has_dtor() { + return Err(CopyImplementationError::HasDestructor) + } + + Ok(()) + } +} + +impl<'tcx> ty::ctxt<'tcx> { + pub fn pat_contains_ref_binding(&self, pat: &hir::Pat) -> Option { + pat_util::pat_contains_ref_binding(&self.def_map, pat) + } + + pub fn arm_contains_ref_binding(&self, arm: &hir::Arm) -> Option { + pat_util::arm_contains_ref_binding(&self.def_map, arm) + } + + /// Returns the type of element at index `i` in tuple or tuple-like type `t`. + /// For an enum `t`, `variant` is None only if `t` is a univariant enum. + pub fn positional_element_ty(&self, + ty: Ty<'tcx>, + i: usize, + variant: Option) -> Option> { + match (&ty.sty, variant) { + (&TyStruct(def, substs), None) => { + def.struct_variant().fields.get(i).map(|f| f.ty(self, substs)) + } + (&TyEnum(def, substs), Some(vid)) => { + def.variant_with_id(vid).fields.get(i).map(|f| f.ty(self, substs)) + } + (&TyEnum(def, substs), None) => { + assert!(def.is_univariant()); + def.variants[0].fields.get(i).map(|f| f.ty(self, substs)) + } + (&TyTuple(ref v), None) => v.get(i).cloned(), + _ => None + } + } + + /// Returns the type of element at field `n` in struct or struct-like type `t`. + /// For an enum `t`, `variant` must be some def id. + pub fn named_element_ty(&self, + ty: Ty<'tcx>, + n: Name, + variant: Option) -> Option> { + match (&ty.sty, variant) { + (&TyStruct(def, substs), None) => { + def.struct_variant().find_field_named(n).map(|f| f.ty(self, substs)) + } + (&TyEnum(def, substs), Some(vid)) => { + def.variant_with_id(vid).find_field_named(n).map(|f| f.ty(self, substs)) + } + _ => return None + } + } + + /// Returns `(normalized_type, ty)`, where `normalized_type` is the + /// IntType representation of one of {i64,i32,i16,i8,u64,u32,u16,u8}, + /// and `ty` is the original type (i.e. may include `isize` or + /// `usize`). + pub fn enum_repr_type(&self, opt_hint: Option<&attr::ReprAttr>) + -> (attr::IntType, Ty<'tcx>) { + let repr_type = match opt_hint { + // Feed in the given type + Some(&attr::ReprInt(_, int_t)) => int_t, + // ... but provide sensible default if none provided + // + // NB. Historically `fn enum_variants` generate i64 here, while + // rustc_typeck::check would generate isize. + _ => SignedInt(hir::TyIs), + }; + + let repr_type_ty = repr_type.to_ty(self); + let repr_type = match repr_type { + SignedInt(hir::TyIs) => + SignedInt(self.sess.target.int_type), + UnsignedInt(hir::TyUs) => + UnsignedInt(self.sess.target.uint_type), + other => other + }; + + (repr_type, repr_type_ty) + } + + /// Returns the deeply last field of nested structures, or the same type, + /// if not a structure at all. Corresponds to the only possible unsized + /// field, and its type can be used to determine unsizing strategy. + pub fn struct_tail(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { + while let TyStruct(def, substs) = ty.sty { + match def.struct_variant().fields.last() { + Some(f) => ty = f.ty(self, substs), + None => break + } + } + ty + } + + /// Same as applying struct_tail on `source` and `target`, but only + /// keeps going as long as the two types are instances of the same + /// structure definitions. + /// For `(Foo>, Foo)`, the result will be `(Foo, Trait)`, + /// whereas struct_tail produces `T`, and `Trait`, respectively. + pub fn struct_lockstep_tails(&self, + source: Ty<'tcx>, + target: Ty<'tcx>) + -> (Ty<'tcx>, Ty<'tcx>) { + let (mut a, mut b) = (source, target); + while let (&TyStruct(a_def, a_substs), &TyStruct(b_def, b_substs)) = (&a.sty, &b.sty) { + if a_def != b_def { + break; + } + if let Some(f) = a_def.struct_variant().fields.last() { + a = f.ty(self, a_substs); + b = f.ty(self, b_substs); + } else { + break; + } + } + (a, b) + } + + /// Returns the repeat count for a repeating vector expression. + pub fn eval_repeat_count(&self, count_expr: &hir::Expr) -> usize { + let hint = UncheckedExprHint(self.types.usize); + match const_eval::eval_const_expr_partial(self, count_expr, hint) { + Ok(val) => { + let found = match val { + ConstVal::Uint(count) => return count as usize, + ConstVal::Int(count) if count >= 0 => return count as usize, + const_val => const_val.description(), + }; + span_err!(self.sess, count_expr.span, E0306, + "expected positive integer for repeat count, found {}", + found); + } + Err(err) => { + let err_msg = match count_expr.node { + hir::ExprPath(None, hir::Path { + global: false, + ref segments, + .. + }) if segments.len() == 1 => + format!("found variable"), + _ => match err.kind { + ErrKind::MiscCatchAll => format!("but found {}", err.description()), + _ => format!("but {}", err.description()) + } + }; + span_err!(self.sess, count_expr.span, E0307, + "expected constant integer for repeat count, {}", err_msg); + } + } + 0 + } + + /// Given a set of predicates that apply to an object type, returns + /// the region bounds that the (erased) `Self` type must + /// outlive. Precisely *because* the `Self` type is erased, the + /// parameter `erased_self_ty` must be supplied to indicate what type + /// has been used to represent `Self` in the predicates + /// themselves. This should really be a unique type; `FreshTy(0)` is a + /// popular choice. + /// + /// NB: in some cases, particularly around higher-ranked bounds, + /// this function returns a kind of conservative approximation. + /// That is, all regions returned by this function are definitely + /// required, but there may be other region bounds that are not + /// returned, as well as requirements like `for<'a> T: 'a`. + /// + /// Requires that trait definitions have been processed so that we can + /// elaborate predicates and walk supertraits. + pub fn required_region_bounds(&self, + erased_self_ty: Ty<'tcx>, + predicates: Vec>) + -> Vec { + debug!("required_region_bounds(erased_self_ty={:?}, predicates={:?})", + erased_self_ty, + predicates); + + assert!(!erased_self_ty.has_escaping_regions()); + + traits::elaborate_predicates(self, predicates) + .filter_map(|predicate| { + match predicate { + ty::Predicate::Projection(..) | + ty::Predicate::Trait(..) | + ty::Predicate::Equate(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | + ty::Predicate::RegionOutlives(..) => { + None + } + ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t, r))) => { + // Search for a bound of the form `erased_self_ty + // : 'a`, but be wary of something like `for<'a> + // erased_self_ty : 'a` (we interpret a + // higher-ranked bound like that as 'static, + // though at present the code in `fulfill.rs` + // considers such bounds to be unsatisfiable, so + // it's kind of a moot point since you could never + // construct such an object, but this seems + // correct even if that code changes). + if t == erased_self_ty && !r.has_escaping_regions() { + Some(r) + } else { + None + } + } + } + }) + .collect() + } + + /// Creates a hash of the type `Ty` which will be the same no matter what crate + /// context it's calculated within. This is used by the `type_id` intrinsic. + pub fn hash_crate_independent(&self, ty: Ty<'tcx>, svh: &Svh) -> u64 { + let mut state = SipHasher::new(); + helper(self, ty, svh, &mut state); + return state.finish(); + + fn helper<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh, + state: &mut SipHasher) { + macro_rules! byte { ($b:expr) => { ($b as u8).hash(state) } } + macro_rules! hash { ($e:expr) => { $e.hash(state) } } + + let region = |state: &mut SipHasher, r: ty::Region| { + match r { + ty::ReStatic => {} + ty::ReLateBound(db, ty::BrAnon(i)) => { + db.hash(state); + i.hash(state); + } + ty::ReEmpty | + ty::ReEarlyBound(..) | + ty::ReLateBound(..) | + ty::ReFree(..) | + ty::ReScope(..) | + ty::ReVar(..) | + ty::ReSkolemized(..) => { + tcx.sess.bug("unexpected region found when hashing a type") + } + } + }; + let did = |state: &mut SipHasher, did: DefId| { + let h = if did.is_local() { + svh.clone() + } else { + tcx.sess.cstore.get_crate_hash(did.krate) + }; + h.as_str().hash(state); + did.node.hash(state); + }; + let mt = |state: &mut SipHasher, mt: TypeAndMut| { + mt.mutbl.hash(state); + }; + let fn_sig = |state: &mut SipHasher, sig: &ty::Binder>| { + let sig = tcx.anonymize_late_bound_regions(sig).0; + for a in &sig.inputs { helper(tcx, *a, svh, state); } + if let ty::FnConverging(output) = sig.output { + helper(tcx, output, svh, state); + } + }; + ty.maybe_walk(|ty| { + match ty.sty { + TyBool => byte!(2), + TyChar => byte!(3), + TyInt(i) => { + byte!(4); + hash!(i); + } + TyUint(u) => { + byte!(5); + hash!(u); + } + TyFloat(f) => { + byte!(6); + hash!(f); + } + TyStr => { + byte!(7); + } + TyEnum(d, _) => { + byte!(8); + did(state, d.did); + } + TyBox(_) => { + byte!(9); + } + TyArray(_, n) => { + byte!(10); + n.hash(state); + } + TySlice(_) => { + byte!(11); + } + TyRawPtr(m) => { + byte!(12); + mt(state, m); + } + TyRef(r, m) => { + byte!(13); + region(state, *r); + mt(state, m); + } + TyBareFn(opt_def_id, ref b) => { + byte!(14); + hash!(opt_def_id); + hash!(b.unsafety); + hash!(b.abi); + fn_sig(state, &b.sig); + return false; + } + TyTrait(ref data) => { + byte!(17); + did(state, data.principal_def_id()); + hash!(data.bounds); + + let principal = tcx.anonymize_late_bound_regions(&data.principal).0; + for subty in &principal.substs.types { + helper(tcx, subty, svh, state); + } + + return false; + } + TyStruct(d, _) => { + byte!(18); + did(state, d.did); + } + TyTuple(ref inner) => { + byte!(19); + hash!(inner.len()); + } + TyParam(p) => { + byte!(20); + hash!(p.space); + hash!(p.idx); + hash!(p.name.as_str()); + } + TyInfer(_) => unreachable!(), + TyError => byte!(21), + TyClosure(d, _) => { + byte!(22); + did(state, d); + } + TyProjection(ref data) => { + byte!(23); + did(state, data.trait_ref.def_id); + hash!(data.item_name.as_str()); + } + } + true + }); + } + } + + /// Returns true if this ADT is a dtorck type, i.e. whether it being + /// safe for destruction requires it to be alive + pub fn is_adt_dtorck(&self, adt: ty::AdtDef<'tcx>) -> bool { + let dtor_method = match adt.destructor() { + Some(dtor) => dtor, + None => return false + }; + let impl_did = self.impl_of_method(dtor_method).unwrap_or_else(|| { + self.sess.bug(&format!("no Drop impl for the dtor of `{:?}`", adt)) + }); + let generics = adt.type_scheme(self).generics; + + // In `impl<'a> Drop ...`, we automatically assume + // `'a` is meaningful and thus represents a bound + // through which we could reach borrowed data. + // + // FIXME (pnkfelix): In the future it would be good to + // extend the language to allow the user to express, + // in the impl signature, that a lifetime is not + // actually used (something like `where 'a: ?Live`). + if generics.has_region_params(subst::TypeSpace) { + debug!("typ: {:?} has interesting dtor due to region params", + adt); + return true; + } + + let mut seen_items = Vec::new(); + let mut items_to_inspect = vec![impl_did]; + while let Some(item_def_id) = items_to_inspect.pop() { + if seen_items.contains(&item_def_id) { + continue; + } + + for pred in self.lookup_predicates(item_def_id).predicates { + let result = match pred { + ty::Predicate::Equate(..) | + ty::Predicate::RegionOutlives(..) | + ty::Predicate::TypeOutlives(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | + ty::Predicate::Projection(..) => { + // For now, assume all these where-clauses + // may give drop implementation capabilty + // to access borrowed data. + true + } + + ty::Predicate::Trait(ty::Binder(ref t_pred)) => { + let def_id = t_pred.trait_ref.def_id; + if self.trait_items(def_id).len() != 0 { + // If trait has items, assume it adds + // capability to access borrowed data. + true + } else { + // Trait without items is itself + // uninteresting from POV of dropck. + // + // However, may have parent w/ items; + // so schedule checking of predicates, + items_to_inspect.push(def_id); + // and say "no capability found" for now. + false + } + } + }; + + if result { + debug!("typ: {:?} has interesting dtor due to generic preds, e.g. {:?}", + adt, pred); + return true; + } + } + + seen_items.push(item_def_id); + } + + debug!("typ: {:?} is dtorck-safe", adt); + false + } +} + +impl<'tcx> ty::TyS<'tcx> { + fn impls_bound<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, + bound: ty::BuiltinBound, + span: Span) + -> bool + { + let tcx = param_env.tcx; + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env.clone()), false); + + let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, + self, bound, span); + + debug!("Ty::impls_bound({:?}, {:?}) = {:?}", + self, bound, is_impld); + + is_impld + } + + // FIXME (@jroesch): I made this public to use it, not sure if should be private + pub fn moves_by_default<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, + span: Span) -> bool { + if self.flags.get().intersects(TypeFlags::MOVENESS_CACHED) { + return self.flags.get().intersects(TypeFlags::MOVES_BY_DEFAULT); + } + + assert!(!self.needs_infer()); + + // Fast-path for primitive types + let result = match self.sty { + TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | + TyRawPtr(..) | TyBareFn(..) | TyRef(_, TypeAndMut { + mutbl: hir::MutImmutable, .. + }) => Some(false), + + TyStr | TyBox(..) | TyRef(_, TypeAndMut { + mutbl: hir::MutMutable, .. + }) => Some(true), + + TyArray(..) | TySlice(_) | TyTrait(..) | TyTuple(..) | + TyClosure(..) | TyEnum(..) | TyStruct(..) | + TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None + }.unwrap_or_else(|| !self.impls_bound(param_env, ty::BoundCopy, span)); + + if !self.has_param_types() && !self.has_self_ty() { + self.flags.set(self.flags.get() | if result { + TypeFlags::MOVENESS_CACHED | TypeFlags::MOVES_BY_DEFAULT + } else { + TypeFlags::MOVENESS_CACHED + }); + } + + result + } + + #[inline] + pub fn is_sized<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, + span: Span) -> bool + { + if self.flags.get().intersects(TypeFlags::SIZEDNESS_CACHED) { + return self.flags.get().intersects(TypeFlags::IS_SIZED); + } + + self.is_sized_uncached(param_env, span) + } + + fn is_sized_uncached<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, + span: Span) -> bool { + assert!(!self.needs_infer()); + + // Fast-path for primitive types + let result = match self.sty { + TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | + TyBox(..) | TyRawPtr(..) | TyRef(..) | TyBareFn(..) | + TyArray(..) | TyTuple(..) | TyClosure(..) => Some(true), + + TyStr | TyTrait(..) | TySlice(_) => Some(false), + + TyEnum(..) | TyStruct(..) | TyProjection(..) | TyParam(..) | + TyInfer(..) | TyError => None + }.unwrap_or_else(|| self.impls_bound(param_env, ty::BoundSized, span)); + + if !self.has_param_types() && !self.has_self_ty() { + self.flags.set(self.flags.get() | if result { + TypeFlags::SIZEDNESS_CACHED | TypeFlags::IS_SIZED + } else { + TypeFlags::SIZEDNESS_CACHED + }); + } + + result + } + + + /// Check whether a type is representable. This means it cannot contain unboxed + /// structural recursion. This check is needed for structs and enums. + pub fn is_representable(&'tcx self, cx: &ty::ctxt<'tcx>, sp: Span) -> Representability { + + // Iterate until something non-representable is found + fn find_nonrepresentable<'tcx, It: Iterator>>(cx: &ty::ctxt<'tcx>, + sp: Span, + seen: &mut Vec>, + iter: It) + -> Representability { + iter.fold(Representability::Representable, + |r, ty| cmp::max(r, is_type_structurally_recursive(cx, sp, seen, ty))) + } + + fn are_inner_types_recursive<'tcx>(cx: &ty::ctxt<'tcx>, sp: Span, + seen: &mut Vec>, ty: Ty<'tcx>) + -> Representability { + match ty.sty { + TyTuple(ref ts) => { + find_nonrepresentable(cx, sp, seen, ts.iter().cloned()) + } + // Fixed-length vectors. + // FIXME(#11924) Behavior undecided for zero-length vectors. + TyArray(ty, _) => { + is_type_structurally_recursive(cx, sp, seen, ty) + } + TyStruct(def, substs) | TyEnum(def, substs) => { + find_nonrepresentable(cx, + sp, + seen, + def.all_fields().map(|f| f.ty(cx, substs))) + } + TyClosure(..) => { + // this check is run on type definitions, so we don't expect + // to see closure types + cx.sess.bug(&format!("requires check invoked on inapplicable type: {:?}", ty)) + } + _ => Representability::Representable, + } + } + + fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: ty::AdtDef<'tcx>) -> bool { + match ty.sty { + TyStruct(ty_def, _) | TyEnum(ty_def, _) => { + ty_def == def + } + _ => false + } + } + + fn same_type<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { + match (&a.sty, &b.sty) { + (&TyStruct(did_a, ref substs_a), &TyStruct(did_b, ref substs_b)) | + (&TyEnum(did_a, ref substs_a), &TyEnum(did_b, ref substs_b)) => { + if did_a != did_b { + return false; + } + + let types_a = substs_a.types.get_slice(subst::TypeSpace); + let types_b = substs_b.types.get_slice(subst::TypeSpace); + + let mut pairs = types_a.iter().zip(types_b); + + pairs.all(|(&a, &b)| same_type(a, b)) + } + _ => { + a == b + } + } + } + + // Does the type `ty` directly (without indirection through a pointer) + // contain any types on stack `seen`? + fn is_type_structurally_recursive<'tcx>(cx: &ty::ctxt<'tcx>, + sp: Span, + seen: &mut Vec>, + ty: Ty<'tcx>) -> Representability { + debug!("is_type_structurally_recursive: {:?}", ty); + + match ty.sty { + TyStruct(def, _) | TyEnum(def, _) => { + { + // Iterate through stack of previously seen types. + let mut iter = seen.iter(); + + // The first item in `seen` is the type we are actually curious about. + // We want to return SelfRecursive if this type contains itself. + // It is important that we DON'T take generic parameters into account + // for this check, so that Bar in this example counts as SelfRecursive: + // + // struct Foo; + // struct Bar { x: Bar } + + match iter.next() { + Some(&seen_type) => { + if same_struct_or_enum(seen_type, def) { + debug!("SelfRecursive: {:?} contains {:?}", + seen_type, + ty); + return Representability::SelfRecursive; + } + } + None => {} + } + + // We also need to know whether the first item contains other types + // that are structurally recursive. If we don't catch this case, we + // will recurse infinitely for some inputs. + // + // It is important that we DO take generic parameters into account + // here, so that code like this is considered SelfRecursive, not + // ContainsRecursive: + // + // struct Foo { Option> } + + for &seen_type in iter { + if same_type(ty, seen_type) { + debug!("ContainsRecursive: {:?} contains {:?}", + seen_type, + ty); + return Representability::ContainsRecursive; + } + } + } + + // For structs and enums, track all previously seen types by pushing them + // onto the 'seen' stack. + seen.push(ty); + let out = are_inner_types_recursive(cx, sp, seen, ty); + seen.pop(); + out + } + _ => { + // No need to push in other cases. + are_inner_types_recursive(cx, sp, seen, ty) + } + } + } + + debug!("is_type_representable: {:?}", self); + + // To avoid a stack overflow when checking an enum variant or struct that + // contains a different, structurally recursive type, maintain a stack + // of seen types and check recursion for each of them (issues #3008, #3779). + let mut seen: Vec = Vec::new(); + let r = is_type_structurally_recursive(cx, sp, &mut seen, self); + debug!("is_type_representable: {:?} is {:?}", self, r); + r + } +} diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 99e41bd22b8bb..fee60d46dc001 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -388,23 +388,23 @@ impl<'tcx, 'container> fmt::Debug for ty::AdtDefData<'tcx, 'container> { } } -impl<'tcx> fmt::Debug for ty::AutoAdjustment<'tcx> { +impl<'tcx> fmt::Debug for ty::adjustment::AutoAdjustment<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - ty::AdjustReifyFnPointer => { + ty::adjustment::AdjustReifyFnPointer => { write!(f, "AdjustReifyFnPointer") } - ty::AdjustUnsafeFnPointer => { + ty::adjustment::AdjustUnsafeFnPointer => { write!(f, "AdjustUnsafeFnPointer") } - ty::AdjustDerefRef(ref data) => { + ty::adjustment::AdjustDerefRef(ref data) => { write!(f, "{:?}", data) } } } } -impl<'tcx> fmt::Debug for ty::AutoDerefRef<'tcx> { +impl<'tcx> fmt::Debug for ty::adjustment::AutoDerefRef<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "AutoDerefRef({}, unsize={:?}, {:?})", self.autoderefs, self.unsize, self.autoref) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index c8ffe07660611..4084f13e818f2 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -33,6 +33,7 @@ use middle::{cfg, def, infer, pat_util, stability, traits}; use middle::def_id::DefId; use middle::subst::Substs; use middle::ty::{self, Ty}; +use middle::ty::adjustment; use middle::const_eval::{eval_const_expr_partial, ConstVal}; use middle::const_eval::EvalHint::ExprTypeChecked; use rustc::front::map as hir_map; @@ -1722,13 +1723,15 @@ impl LintPass for UnusedAllocation { } if let Some(adjustment) = cx.tcx.tables.borrow().adjustments.get(&e.id) { - if let ty::AdjustDerefRef(ty::AutoDerefRef { ref autoref, .. }) = *adjustment { + if let adjustment::AdjustDerefRef(adjustment::AutoDerefRef { + ref autoref, .. + }) = *adjustment { match autoref { - &Some(ty::AutoPtr(_, hir::MutImmutable)) => { + &Some(adjustment::AutoPtr(_, hir::MutImmutable)) => { cx.span_lint(UNUSED_ALLOCATION, e.span, "unnecessary allocation, use & instead"); } - &Some(ty::AutoPtr(_, hir::MutMutable)) => { + &Some(adjustment::AutoPtr(_, hir::MutMutable)) => { cx.span_lint(UNUSED_ALLOCATION, e.span, "unnecessary allocation, use &mut instead"); } @@ -2297,7 +2300,7 @@ impl LintPass for UnconditionalRecursion { } // Check for overloaded autoderef method calls. - if let Some(&ty::AdjustDerefRef(ref adj)) = tables.adjustments.get(&id) { + if let Some(&adjustment::AdjustDerefRef(ref adj)) = tables.adjustments.get(&id) { for i in 0..adj.autoderefs { let method_call = ty::MethodCall::autoderef(id, i as u32); if let Some(m) = tables.method_map.get(&method_call) { diff --git a/src/librustc_mir/tcx/expr.rs b/src/librustc_mir/tcx/expr.rs index 6352af39f1489..f15470e7851d4 100644 --- a/src/librustc_mir/tcx/expr.rs +++ b/src/librustc_mir/tcx/expr.rs @@ -320,7 +320,7 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { // Now apply adjustments, if any. match cx.tcx.tables.borrow().adjustments.get(&self.id) { None => { } - Some(&ty::AdjustReifyFnPointer) => { + Some(&ty::adjustment::AdjustReifyFnPointer) => { let adjusted_ty = cx.tcx.expr_ty_adjusted(self); expr = Expr { temp_lifetime: temp_lifetime, @@ -329,7 +329,7 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { kind: ExprKind::ReifyFnPointer { source: expr.to_ref() }, }; } - Some(&ty::AdjustUnsafeFnPointer) => { + Some(&ty::adjustment::AdjustUnsafeFnPointer) => { let adjusted_ty = cx.tcx.expr_ty_adjusted(self); expr = Expr { temp_lifetime: temp_lifetime, @@ -338,7 +338,7 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() }, }; } - Some(&ty::AdjustDerefRef(ref adj)) => { + Some(&ty::adjustment::AdjustDerefRef(ref adj)) => { for i in 0..adj.autoderefs { let i = i as u32; let adjusted_ty = @@ -372,7 +372,7 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { } else if let Some(autoref) = adj.autoref { let adjusted_ty = expr.ty.adjust_for_autoref(cx.tcx, Some(autoref)); match autoref { - ty::AutoPtr(r, m) => { + ty::adjustment::AutoPtr(r, m) => { expr = Expr { temp_lifetime: temp_lifetime, ty: adjusted_ty, @@ -382,7 +382,7 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { arg: expr.to_ref() } }; } - ty::AutoUnsafe(m) => { + ty::adjustment::AutoUnsafe(m) => { // Convert this to a suitable `&foo` and // then an unsafe coercion. Limit the region to be just this // expression. diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index c98760ce02a26..a2d74635b5e1c 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -34,6 +34,8 @@ use trans::monomorphize; use trans::type_::Type; use trans::type_of; use middle::subst::Substs; +use middle::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer}; +use middle::ty::adjustment::AdjustUnsafeFnPointer; use middle::ty::{self, Ty}; use middle::ty::cast::{CastTy,IntTy}; use util::nodemap::NodeMap; @@ -289,14 +291,14 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, &cx.tcx().expr_ty_adjusted(e)); let opt_adj = cx.tcx().tables.borrow().adjustments.get(&e.id).cloned(); match opt_adj { - Some(ty::AdjustReifyFnPointer) => { + Some(AdjustReifyFnPointer) => { // FIXME(#19925) once fn item types are // zero-sized, we'll need to do something here } - Some(ty::AdjustUnsafeFnPointer) => { + Some(AdjustUnsafeFnPointer) => { // purely a type-level thing } - Some(ty::AdjustDerefRef(adj)) => { + Some(AdjustDerefRef(adj)) => { let mut ty = ety; // Save the last autoderef in case we can avoid it. if adj.autoderefs > 0 { diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 59040b9cafef5..7d8996867c016 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -71,7 +71,8 @@ use trans::machine; use trans::meth; use trans::tvec; use trans::type_of; -use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustUnsafeFnPointer}; +use middle::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer}; +use middle::ty::adjustment::{AdjustUnsafeFnPointer, CustomCoerceUnsized}; use middle::ty::{self, Ty}; use middle::ty::MethodCall; use middle::ty::cast::{CastKind, CastTy}; @@ -514,7 +515,7 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; let coerce_index = match kind { - ty::CustomCoerceUnsized::Struct(i) => i + CustomCoerceUnsized::Struct(i) => i }; assert!(coerce_index < src_fields.len() && src_fields.len() == target_fields.len()); diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index cde188fa41e48..69efaa792fe05 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -65,7 +65,9 @@ use check::{autoderef, FnCtxt, UnresolvedTypeAction}; use middle::infer::{self, Coercion}; use middle::traits::{self, ObligationCause}; use middle::traits::{predicate_for_trait_def, report_selection_error}; -use middle::ty::{AutoDerefRef, AdjustDerefRef}; +use middle::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef}; +use middle::ty::adjustment::{AutoPtr, AutoUnsafe, AdjustReifyFnPointer}; +use middle::ty::adjustment::{AdjustUnsafeFnPointer}; use middle::ty::{self, LvaluePreference, TypeAndMut, Ty}; use middle::ty::error::TypeError; use middle::ty::relate::RelateResult; @@ -81,7 +83,7 @@ struct Coerce<'a, 'tcx: 'a> { unsizing_obligations: RefCell>>, } -type CoerceResult<'tcx> = RelateResult<'tcx, Option>>; +type CoerceResult<'tcx> = RelateResult<'tcx, Option>>; impl<'f, 'tcx> Coerce<'f, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { @@ -186,7 +188,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let coercion = Coercion(self.origin.span()); let r_borrow = self.fcx.infcx().next_region_var(coercion); let r_borrow = self.tcx().mk_region(r_borrow); - let autoref = Some(ty::AutoPtr(r_borrow, mutbl_b)); + let autoref = Some(AutoPtr(r_borrow, mutbl_b)); let lvalue_pref = LvaluePreference::from_mutbl(mutbl_b); let mut first_error = None; @@ -264,11 +266,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let coercion = Coercion(self.origin.span()); let r_borrow = self.fcx.infcx().next_region_var(coercion); let region = self.tcx().mk_region(r_borrow); - (mt_a.ty, Some(ty::AutoPtr(region, mt_b.mutbl))) + (mt_a.ty, Some(AutoPtr(region, mt_b.mutbl))) } (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) => { try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl)); - (mt_a.ty, Some(ty::AutoUnsafe(mt_b.mutbl))) + (mt_a.ty, Some(AutoUnsafe(mt_b.mutbl))) } _ => (source, None) }; @@ -360,7 +362,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => { let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a); try!(self.subtype(unsafe_a, b)); - return Ok(Some(ty::AdjustUnsafeFnPointer)); + return Ok(Some(AdjustUnsafeFnPointer)); } _ => {} } @@ -387,7 +389,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::TyBareFn(None, _) => { let a_fn_pointer = self.tcx().mk_fn(None, fn_ty_a); try!(self.subtype(a_fn_pointer, b)); - Ok(Some(ty::AdjustReifyFnPointer)) + Ok(Some(AdjustReifyFnPointer)) } _ => self.subtype(a, b) } @@ -422,7 +424,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { if is_ref { Ok(Some(AdjustDerefRef(AutoDerefRef { autoderefs: 1, - autoref: Some(ty::AutoUnsafe(mutbl_b)), + autoref: Some(AutoUnsafe(mutbl_b)), unsize: None }))) } else { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 048a2b62bcaa3..572ba7a848713 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -16,6 +16,7 @@ use middle::def_id::DefId; use middle::subst::{self}; use middle::traits; use middle::ty::{self, NoPreference, PreferMutLvalue, Ty}; +use middle::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr}; use middle::ty::fold::TypeFoldable; use middle::infer; use middle::infer::InferCtxt; @@ -136,7 +137,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { { let (autoref, unsize) = if let Some(mutbl) = pick.autoref { let region = self.infcx().next_region_var(infer::Autoref(self.span)); - let autoref = ty::AutoPtr(self.tcx().mk_region(region), mutbl); + let autoref = AutoPtr(self.tcx().mk_region(region), mutbl); (Some(autoref), pick.unsize.map(|target| { target.adjust_for_autoref(self.tcx(), Some(autoref)) })) @@ -169,7 +170,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // Write out the final adjustment. self.fcx.write_adjustment(self.self_expr.id, - ty::AdjustDerefRef(ty::AutoDerefRef { + AdjustDerefRef(AutoDerefRef { autoderefs: pick.autoderefs, autoref: autoref, unsize: unsize @@ -488,7 +489,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { .borrow() .adjustments .get(&expr.id) { - Some(&ty::AdjustDerefRef(ref adj)) => adj.autoderefs, + Some(&AdjustDerefRef(ref adj)) => adj.autoderefs, Some(_) | None => 0, }; @@ -527,12 +528,12 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { let adj = self.fcx.inh.tables.borrow().adjustments.get(&base_expr.id) .cloned(); let (autoderefs, unsize) = match adj { - Some(ty::AdjustDerefRef(adr)) => match adr.autoref { + Some(AdjustDerefRef(adr)) => match adr.autoref { None => { assert!(adr.unsize.is_none()); (adr.autoderefs, None) } - Some(ty::AutoPtr(_, _)) => { + Some(AutoPtr(_, _)) => { (adr.autoderefs, adr.unsize.map(|target| { target.builtin_deref(false, NoPreference) .expect("fixup: AutoPtr is not &T").ty @@ -557,7 +558,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { (target, true) } else { (self.fcx.adjust_expr_ty(base_expr, - Some(&ty::AdjustDerefRef(ty::AutoDerefRef { + Some(&AdjustDerefRef(AutoDerefRef { autoderefs: autoderefs, autoref: None, unsize: None diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index e319e37fa3098..1cfb495b36ed7 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -18,6 +18,7 @@ use middle::privacy::{AllPublic, DependsOn, LastPrivate, LastMod}; use middle::subst; use middle::traits; use middle::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef}; +use middle::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr}; use middle::infer; use syntax::ast; @@ -282,9 +283,9 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, match transformed_self_ty.sty { ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ }) => { fcx.write_adjustment(self_expr.id, - ty::AdjustDerefRef(ty::AutoDerefRef { + AdjustDerefRef(AutoDerefRef { autoderefs: autoderefs, - autoref: Some(ty::AutoPtr(region, mutbl)), + autoref: Some(AutoPtr(region, mutbl)), unsize: if unsize { Some(transformed_self_ty) } else { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 3160ed3502578..656a740e9840e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -97,8 +97,10 @@ use middle::ty::{Disr, ParamTy, ParameterEnvironment}; use middle::ty::{LvaluePreference, NoPreference, PreferMutLvalue}; use middle::ty::{self, HasTypeFlags, RegionEscape, ToPolyTraitRef, Ty}; use middle::ty::{MethodCall, MethodCallee}; +use middle::ty::adjustment; use middle::ty::error::TypeError; use middle::ty::fold::{TypeFolder, TypeFoldable}; +use middle::ty::util::Representability; use require_c_abi_if_variadic; use rscope::{ElisionFailureInfo, RegionScope}; use session::Session; @@ -1337,7 +1339,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { derefs: usize) { self.write_adjustment( node_id, - ty::AdjustDerefRef(ty::AutoDerefRef { + adjustment::AdjustDerefRef(adjustment::AutoDerefRef { autoderefs: derefs, autoref: None, unsize: None @@ -1347,7 +1349,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn write_adjustment(&self, node_id: ast::NodeId, - adj: ty::AutoAdjustment<'tcx>) { + adj: adjustment::AutoAdjustment<'tcx>) { debug!("write_adjustment(node_id={}, adj={:?})", node_id, adj); if adj.is_identity() { @@ -1576,7 +1578,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Apply `adjustment` to the type of `expr` pub fn adjust_expr_ty(&self, expr: &hir::Expr, - adjustment: Option<&ty::AutoAdjustment<'tcx>>) + adjustment: Option<&adjustment::AutoAdjustment<'tcx>>) -> Ty<'tcx> { let raw_ty = self.expr_ty(expr); @@ -4170,12 +4172,13 @@ pub fn check_representable(tcx: &ty::ctxt, // contain themselves. For case 2, there must be an inner type that will be // caught by case 1. match rty.is_representable(tcx, sp) { - ty::SelfRecursive => { - span_err!(tcx.sess, sp, E0072, "invalid recursive {} type", designation); - tcx.sess.fileline_help(sp, "wrap the inner value in a box to make it representable"); - return false - } - ty::Representable | ty::ContainsRecursive => (), + Representability::SelfRecursive => { + span_err!(tcx.sess, sp, E0072, "invalid recursive {} type", designation); + tcx.sess.fileline_help( + sp, "wrap the inner value in a box to make it representable"); + return false + } + Representability::Representable | Representability::ContainsRecursive => (), } return true } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index b6ff7b529c556..155caaa8cb0fe 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -94,6 +94,7 @@ use middle::traits; use middle::ty::{self, RegionEscape, ReScope, Ty, MethodCall, HasTypeFlags}; use middle::infer::{self, GenericKind, InferCtxt, SubregionOrigin, VerifyBound}; use middle::pat_util; +use middle::ty::adjustment; use middle::ty::wf::ImpliedBound; use std::mem; @@ -598,7 +599,9 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) { if let Some(adjustment) = adjustment { debug!("adjustment={:?}", adjustment); match adjustment { - ty::AdjustDerefRef(ty::AutoDerefRef {autoderefs, ref autoref, ..}) => { + adjustment::AdjustDerefRef(adjustment::AutoDerefRef { + autoderefs, ref autoref, .. + }) => { let expr_ty = rcx.resolve_node_type(expr.id); constrain_autoderefs(rcx, expr, autoderefs, expr_ty); if let Some(ref autoref) = *autoref { @@ -614,7 +617,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) { } } /* - ty::AutoObject(_, ref bounds, _, _) => { + adjustment::AutoObject(_, ref bounds, _, _) => { // Determine if we are casting `expr` to a trait // instance. If so, we have to be sure that the type // of the source obeys the new region bound. @@ -1221,7 +1224,7 @@ fn link_pattern<'t, 'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, fn link_autoref(rcx: &Rcx, expr: &hir::Expr, autoderefs: usize, - autoref: &ty::AutoRef) + autoref: &adjustment::AutoRef) { debug!("link_autoref(autoref={:?})", autoref); let mc = mc::MemCategorizationContext::new(rcx.fcx.infcx()); @@ -1229,12 +1232,12 @@ fn link_autoref(rcx: &Rcx, debug!("expr_cmt={:?}", expr_cmt); match *autoref { - ty::AutoPtr(r, m) => { + adjustment::AutoPtr(r, m) => { link_region(rcx, expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt); } - ty::AutoUnsafe(m) => { + adjustment::AutoUnsafe(m) => { let r = ty::ReScope(rcx.tcx().region_maps.node_extent(expr.id)); link_region(rcx, expr.span, &r, ty::BorrowKind::from_mutbl(m), expr_cmt); } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index de841a0cc0022..6f8e064c9d819 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -18,6 +18,7 @@ use check::FnCtxt; use middle::def_id::DefId; use middle::pat_util; use middle::ty::{self, Ty, MethodCall, MethodCallee}; +use middle::ty::adjustment; use middle::ty::fold::{TypeFolder,TypeFoldable}; use middle::infer; use write_substs_to_tcx; @@ -268,19 +269,21 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { Some(adjustment) => { let resolved_adjustment = match adjustment { - ty::AdjustReifyFnPointer => ty::AdjustReifyFnPointer, + adjustment::AdjustReifyFnPointer => { + adjustment::AdjustReifyFnPointer + } - ty::AdjustUnsafeFnPointer => { - ty::AdjustUnsafeFnPointer + adjustment::AdjustUnsafeFnPointer => { + adjustment::AdjustUnsafeFnPointer } - ty::AdjustDerefRef(adj) => { + adjustment::AdjustDerefRef(adj) => { for autoderef in 0..adj.autoderefs { let method_call = MethodCall::autoderef(id, autoderef as u32); self.visit_method_map_entry(reason, method_call); } - ty::AdjustDerefRef(ty::AutoDerefRef { + adjustment::AdjustDerefRef(adjustment::AutoDerefRef { autoderefs: adj.autoderefs, autoref: self.resolve(&adj.autoref, reason), unsize: self.resolve(&adj.unsize, reason), diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 8048c302f2c78..9ba6f1398e471 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -20,6 +20,7 @@ use middle::def_id::{DefId, LOCAL_CRATE}; use middle::lang_items::UnsizeTraitLangItem; use middle::subst::{self, Subst}; use middle::traits; +use middle::ty; use middle::ty::RegionEscape; use middle::ty::{ImplContainer, ImplOrTraitItemId, ConstTraitItemId}; use middle::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment}; @@ -29,7 +30,7 @@ use middle::ty::{TyRef, TyStruct, TyTrait, TyTuple}; use middle::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt}; use middle::ty::{TyUint, TyClosure, TyBox, TyBareFn}; use middle::ty::TyProjection; -use middle::ty; +use middle::ty::util::CopyImplementationError; use middle::free_region::FreeRegionMap; use CrateCtxt; use middle::infer::{self, InferCtxt, new_infer_ctxt}; @@ -370,27 +371,27 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { match param_env.can_type_implement_copy(self_type, span) { Ok(()) => {} - Err(ty::FieldDoesNotImplementCopy(name)) => { + Err(CopyImplementationError::InfrigingField(name)) => { span_err!(tcx.sess, span, E0204, "the trait `Copy` may not be \ implemented for this type; field \ `{}` does not implement `Copy`", name) } - Err(ty::VariantDoesNotImplementCopy(name)) => { + Err(CopyImplementationError::InfrigingVariant(name)) => { span_err!(tcx.sess, span, E0205, "the trait `Copy` may not be \ implemented for this type; variant \ `{}` does not implement `Copy`", name) } - Err(ty::TypeIsStructural) => { + Err(CopyImplementationError::NotAnAdt) => { span_err!(tcx.sess, span, E0206, "the trait `Copy` may not be implemented \ for this type; type is not a structure or \ enumeration") } - Err(ty::TypeHasDestructor) => { + Err(CopyImplementationError::HasDestructor) => { span_err!(tcx.sess, span, E0184, "the trait `Copy` may not be implemented for this type; \ the type has a destructor"); @@ -510,7 +511,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } let (i, a, b) = diff_fields[0]; - let kind = ty::CustomCoerceUnsized::Struct(i); + let kind = ty::adjustment::CustomCoerceUnsized::Struct(i); (a, b, coerce_unsized_trait, Some(kind)) } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 0f71c4d8ceb56..f7520ed54b77e 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -76,9 +76,10 @@ use middle::const_eval::{self, ConstVal}; use middle::const_eval::EvalHint::UncheckedExprHint; use middle::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace}; use middle::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; -use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty, TypeScheme, IntTypeExt}; +use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty, TypeScheme}; use middle::ty::{VariantKind}; use middle::ty::fold::{TypeFolder, TypeFoldable}; +use middle::ty::util::IntTypeExt; use middle::infer; use rscope::*; use rustc::front::map as hir_map;