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/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 abf2d5f3625dc..0bd4434857abd 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -27,7 +27,8 @@ use metadata::tydecode; use metadata::tydecode::{DefIdSource, NominalType, TypeWithId}; use metadata::tydecode::{RegionParameter, ClosureSource}; use metadata::tyencode; -use middle::cast; +use middle::ty::adjustment; +use middle::ty::cast; use middle::check_const::ConstQualif; use middle::def; use middle::def_id::{DefId, LOCAL_CRATE}; @@ -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 37e144281760f..661299cd7f3fc 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; @@ -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/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..2447a8cee7bbb 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -43,10 +43,10 @@ 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::{self, Ty}; +use middle::ty::error::TypeError; +use middle::ty::fold::{TypeFolder, TypeFoldable}; +use middle::ty::relate::{Relate, RelateResult, TypeRelation}; use syntax::codemap::Span; use rustc_front::hir; @@ -56,7 +56,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 +108,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 +293,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 +319,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) } } } @@ -363,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 { @@ -381,16 +381,16 @@ 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)) + TypeError::IntMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b)) } fn float_unification_error<'tcx>(a_is_expected: bool, v: (hir::FloatTy, hir::FloatTy)) - -> ty::TypeError<'tcx> + -> TypeError<'tcx> { let (a, b) = v; - TypeError::FloatMismatch(ty_relate::expected_found_bool(a_is_expected, &a, &b)) + 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/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/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..b0fce71d3f061 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -14,9 +14,10 @@ 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::{self, Binder}; +use middle::ty::error::TypeError; +use middle::ty::fold::TypeFoldable; +use middle::ty::relate::{Relate, RelateResult, TypeRelation}; use syntax::codemap::Span; use util::nodemap::{FnvHashMap, FnvHashSet}; @@ -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/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..ffb631e105b3a 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -30,10 +30,12 @@ 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_fold::{self, TypeFolder, TypeFoldable}; -use middle::ty_relate::{Relate, RelateResult, TypeRelation}; +use middle::ty::adjustment; +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}; use std::cell::{RefCell, Ref}; use std::fmt; @@ -171,9 +173,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 +481,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} } } @@ -583,7 +585,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 +605,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 +614,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 { @@ -656,7 +658,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) { @@ -1149,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); @@ -1312,7 +1315,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 +1326,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 +1352,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 +1371,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 +1388,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 +1409,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))) } @@ -1484,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 } @@ -1555,7 +1557,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 d81f8e0ae9093..1fc5294877065 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -23,11 +23,12 @@ 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_relate::RelateResult; +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/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/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/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..29032f0c4719a 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -10,9 +10,7 @@ use middle::infer::InferCtxt; use middle::ty::{self, RegionEscape, Ty, HasTypeFlags}; -use middle::wf; -use std::fmt; use syntax::ast; use util::common::ErrorReported; use util::nodemap::{FnvHashSet, NodeMap}; @@ -496,8 +494,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 @@ -510,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 667cad8fc88ae..14765e861c32d 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; @@ -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 @@ -168,7 +169,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 cacefbb1a8551..a2c09f88ab331 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -24,12 +24,10 @@ 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; -use std::fmt; - pub type PolyProjectionObligation<'tcx> = Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>; @@ -51,7 +49,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)] @@ -265,7 +263,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() => { // (*) @@ -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/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/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.rs b/src/librustc/middle/ty.rs deleted file mode 100644 index 7f61526a8f903..0000000000000 --- a/src/librustc/middle/ty.rs +++ /dev/null @@ -1,7512 +0,0 @@ -// Copyright 2012-2014 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. - -// FIXME: (@jroesch) @eddyb should remove this when he renames ctxt -#![allow(non_camel_case_types)] - -pub use self::InferTy::*; -pub use self::ImplOrTraitItemId::*; -pub use self::ClosureKind::*; -pub use self::Variance::*; -pub use self::AutoAdjustment::*; -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::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; -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::{self, TypeFoldable, TypeFolder}; -use middle::ty_walk::{self, TypeWalker}; -use util::common::{memoized, ErrorReported}; -use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet}; -use util::nodemap::FnvHashMap; -use util::num::ToPrimitive; - -use arena::TypedArena; -use std::borrow::{Borrow, Cow}; -use std::cell::{Cell, RefCell, Ref}; -use std::cmp; -use std::fmt; -use std::hash::{Hash, SipHasher, Hasher}; -use std::iter; -use std::marker::PhantomData; -use std::mem; -use std::ops; -use std::rc::Rc; -use std::slice; -use std::vec::IntoIter; -use collections::enum_set::{self, EnumSet, CLike}; -use core::nonzero::NonZero; -use std::collections::{HashMap, HashSet}; -use rustc_data_structures::ivar; -use syntax::abi; -use syntax::ast::{self, CrateNum, Name, NodeId}; -use syntax::codemap::Span; -use syntax::parse::token::{InternedString, special_idents}; - -use rustc_front::hir; -use rustc_front::hir::{ItemImpl, ItemTrait}; -use rustc_front::hir::{MutImmutable, MutMutable, Visibility}; -use rustc_front::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt}; - -pub type Disr = u64; - -pub const INITIAL_DISCRIMINANT_VALUE: Disr = 0; - -// Data types - -/// The complete set of all analyses described in this module. This is -/// produced by the driver and fed to trans and later passes. -pub struct CrateAnalysis { - pub export_map: ExportMap, - pub exported_items: middle::privacy::ExportedItems, - pub public_items: middle::privacy::PublicItems, - pub reachable: NodeSet, - pub name: String, - pub glob_map: Option, -} - - -#[derive(Copy, Clone)] -pub enum DtorKind { - NoDtor, - TraitDtor(bool) -} - -impl DtorKind { - pub fn is_present(&self) -> bool { - match *self { - TraitDtor(..) => true, - _ => false - } - } - - pub fn has_drop_flag(&self) -> bool { - match self { - &NoDtor => false, - &TraitDtor(flag) => flag - } - } -} - -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), - ImplContainer(DefId), -} - -impl ImplOrTraitItemContainer { - pub fn id(&self) -> DefId { - match *self { - TraitContainer(id) => id, - ImplContainer(id) => id, - } - } -} - -#[derive(Clone)] -pub enum ImplOrTraitItem<'tcx> { - ConstTraitItem(Rc>), - MethodTraitItem(Rc>), - TypeTraitItem(Rc>), -} - -impl<'tcx> ImplOrTraitItem<'tcx> { - fn id(&self) -> ImplOrTraitItemId { - match *self { - ConstTraitItem(ref associated_const) => { - ConstTraitItemId(associated_const.def_id) - } - MethodTraitItem(ref method) => MethodTraitItemId(method.def_id), - TypeTraitItem(ref associated_type) => { - TypeTraitItemId(associated_type.def_id) - } - } - } - - pub fn def_id(&self) -> DefId { - match *self { - ConstTraitItem(ref associated_const) => associated_const.def_id, - MethodTraitItem(ref method) => method.def_id, - TypeTraitItem(ref associated_type) => associated_type.def_id, - } - } - - pub fn name(&self) -> Name { - match *self { - ConstTraitItem(ref associated_const) => associated_const.name, - MethodTraitItem(ref method) => method.name, - TypeTraitItem(ref associated_type) => associated_type.name, - } - } - - pub fn vis(&self) -> hir::Visibility { - match *self { - ConstTraitItem(ref associated_const) => associated_const.vis, - MethodTraitItem(ref method) => method.vis, - TypeTraitItem(ref associated_type) => associated_type.vis, - } - } - - pub fn container(&self) -> ImplOrTraitItemContainer { - match *self { - ConstTraitItem(ref associated_const) => associated_const.container, - MethodTraitItem(ref method) => method.container, - TypeTraitItem(ref associated_type) => associated_type.container, - } - } - - pub fn as_opt_method(&self) -> Option>> { - match *self { - MethodTraitItem(ref m) => Some((*m).clone()), - _ => None, - } - } -} - -#[derive(Clone, Copy, Debug)] -pub enum ImplOrTraitItemId { - ConstTraitItemId(DefId), - MethodTraitItemId(DefId), - TypeTraitItemId(DefId), -} - -impl ImplOrTraitItemId { - pub fn def_id(&self) -> DefId { - match *self { - ConstTraitItemId(def_id) => def_id, - MethodTraitItemId(def_id) => def_id, - TypeTraitItemId(def_id) => def_id, - } - } -} - -#[derive(Clone, Debug)] -pub struct Method<'tcx> { - pub name: Name, - pub generics: Generics<'tcx>, - pub predicates: GenericPredicates<'tcx>, - pub fty: BareFnTy<'tcx>, - pub explicit_self: ExplicitSelfCategory, - pub vis: hir::Visibility, - pub def_id: DefId, - pub container: ImplOrTraitItemContainer, - - // If this method is provided, we need to know where it came from - pub provided_source: Option -} - -impl<'tcx> Method<'tcx> { - pub fn new(name: Name, - generics: ty::Generics<'tcx>, - predicates: GenericPredicates<'tcx>, - fty: BareFnTy<'tcx>, - explicit_self: ExplicitSelfCategory, - vis: hir::Visibility, - def_id: DefId, - container: ImplOrTraitItemContainer, - provided_source: Option) - -> Method<'tcx> { - Method { - name: name, - generics: generics, - predicates: predicates, - fty: fty, - explicit_self: explicit_self, - vis: vis, - def_id: def_id, - container: container, - provided_source: provided_source - } - } - - pub fn container_id(&self) -> DefId { - match self.container { - TraitContainer(id) => id, - ImplContainer(id) => id, - } - } -} - -#[derive(Clone, Copy, Debug)] -pub struct AssociatedConst<'tcx> { - pub name: Name, - pub ty: Ty<'tcx>, - pub vis: hir::Visibility, - pub def_id: DefId, - pub container: ImplOrTraitItemContainer, - pub default: Option, -} - -#[derive(Clone, Copy, Debug)] -pub struct AssociatedType<'tcx> { - pub name: Name, - pub ty: Option>, - pub vis: hir::Visibility, - pub def_id: DefId, - 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, - pub regions: VecPerParamSpace, -} - -#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Copy)] -pub enum Variance { - Covariant, // T <: T iff A <: B -- e.g., function return type - Invariant, // T <: T iff B == A -- e.g., type of mutable cell - Contravariant, // T <: T iff B <: A -- e.g., function param type - 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 - 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. - pub def_id: DefId, - pub ty: Ty<'tcx>, - pub substs: &'tcx subst::Substs<'tcx> -} - -/// With method calls, we store some extra information in -/// side tables (i.e method_map). We use -/// MethodCall as a key to index into these tables instead of -/// just directly using the expression's NodeId. The reason -/// for this being that we may apply adjustments (coercions) -/// with the resulting expression also needing to use the -/// side tables. The problem with this is that we don't -/// assign a separate NodeId to this new expression -/// and so it would clash with the base expression if both -/// needed to add to the side tables. Thus to disambiguate -/// we also keep track of whether there's an adjustment in -/// our key. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -pub struct MethodCall { - pub expr_id: NodeId, - pub autoderef: u32 -} - -impl MethodCall { - pub fn expr(id: NodeId) -> MethodCall { - MethodCall { - expr_id: id, - autoderef: 0 - } - } - - pub fn autoderef(expr_id: NodeId, autoderef: u32) -> MethodCall { - MethodCall { - expr_id: expr_id, - autoderef: 1 + autoderef - } - } -} - -// maps from an expression id that corresponds to a method call to the details -// of the method to be invoked -pub type MethodMap<'tcx> = FnvHashMap>; - -// Contains information needed to resolve types and (in the future) look up -// the types of AST nodes. -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct CReaderCacheKey { - pub cnum: CrateNum, - pub pos: usize, - pub len: usize -} - -/// A restriction that certain types must be the same size. The use of -/// `transmute` gives rise to these restrictions. These generally -/// cannot be checked until trans; therefore, each call to `transmute` -/// will push one or more such restriction into the -/// `transmute_restrictions` vector during `intrinsicck`. They are -/// then checked during `trans` by the fn `check_intrinsics`. -#[derive(Copy, Clone)] -pub struct TransmuteRestriction<'tcx> { - /// The span whence the restriction comes. - pub span: Span, - - /// The type being transmuted from. - pub original_from: Ty<'tcx>, - - /// The type being transmuted to. - pub original_to: Ty<'tcx>, - - /// The type being transmuted from, with all type parameters - /// substituted for an arbitrary representative. Not to be shown - /// to the end user. - pub substituted_from: Ty<'tcx>, - - /// The type being transmuted to, with all type parameters - /// substituted for an arbitrary representative. Not to be shown - /// to the end user. - pub substituted_to: Ty<'tcx>, - - /// NodeId of the transmute intrinsic. - 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, -/// but longer-term this enum is expected to expand to also -/// include data for fragmented paths. -#[derive(Copy, Clone, Debug)] -pub enum FragmentInfo { - Moved { var: NodeId, move_expr: NodeId }, - 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 -// recursing over the type itself. -bitflags! { - flags TypeFlags: u32 { - const HAS_PARAMS = 1 << 0, - const HAS_SELF = 1 << 1, - const HAS_TY_INFER = 1 << 2, - const HAS_RE_INFER = 1 << 3, - const HAS_RE_EARLY_BOUND = 1 << 4, - const HAS_FREE_REGIONS = 1 << 5, - const HAS_TY_ERR = 1 << 6, - const HAS_PROJECTION = 1 << 7, - const HAS_TY_CLOSURE = 1 << 8, - - // true if there are "names" of types and regions and so forth - // that are local to a particular fn - const HAS_LOCAL_NAMES = 1 << 9, - - const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits | - TypeFlags::HAS_SELF.bits | - TypeFlags::HAS_RE_EARLY_BOUND.bits, - - // Flags representing the nominal content of a type, - // computed by FlagsComputation. If you add a new nominal - // flag, it should be added here too. - const NOMINAL_FLAGS = TypeFlags::HAS_PARAMS.bits | - TypeFlags::HAS_SELF.bits | - TypeFlags::HAS_TY_INFER.bits | - TypeFlags::HAS_RE_INFER.bits | - TypeFlags::HAS_RE_EARLY_BOUND.bits | - TypeFlags::HAS_FREE_REGIONS.bits | - TypeFlags::HAS_TY_ERR.bits | - TypeFlags::HAS_PROJECTION.bits | - TypeFlags::HAS_TY_CLOSURE.bits | - TypeFlags::HAS_LOCAL_NAMES.bits, - - // Caches for type_is_sized, type_moves_by_default - const SIZEDNESS_CACHED = 1 << 16, - const IS_SIZED = 1 << 17, - const MOVENESS_CACHED = 1 << 18, - const MOVES_BY_DEFAULT = 1 << 19, - } -} - -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, - - // the maximal depth of any bound regions appearing in this type. - 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 { - // (self as *const _) == (other as *const _) - (self as *const TyS<'tcx>) == (other as *const TyS<'tcx>) - } -} -impl<'tcx> Eq for TyS<'tcx> {} - -impl<'tcx> Hash for TyS<'tcx> { - fn hash(&self, s: &mut H) { - (self as *const TyS).hash(s) - } -} - -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. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct UpvarId { - pub var_id: NodeId, - pub closure_expr_id: NodeId, -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable, Copy)] -pub enum BorrowKind { - /// Data must be immutable and is aliasable. - ImmBorrow, - - /// Data must be immutable but not aliasable. This kind of borrow - /// cannot currently be expressed by the user and is used only in - /// implicit closure bindings. It is needed when you the closure - /// is borrowing or mutating a mutable referent, e.g.: - /// - /// let x: &mut isize = ...; - /// let y = || *x += 5; - /// - /// If we were to try to translate this closure into a more explicit - /// form, we'd encounter an error with the code as written: - /// - /// struct Env { x: & &mut isize } - /// let x: &mut isize = ...; - /// let y = (&mut Env { &x }, fn_ptr); // Closure is pair of env and fn - /// fn fn_ptr(env: &mut Env) { **env.x += 5; } - /// - /// This is then illegal because you cannot mutate a `&mut` found - /// in an aliasable location. To solve, you'd have to translate with - /// an `&mut` borrow: - /// - /// struct Env { x: & &mut isize } - /// let x: &mut isize = ...; - /// let y = (&mut Env { &mut x }, fn_ptr); // changed from &x to &mut x - /// fn fn_ptr(env: &mut Env) { **env.x += 5; } - /// - /// Now the assignment to `**env.x` is legal, but creating a - /// mutable pointer to `x` is not because `x` is not mutable. We - /// could fix this by declaring `x` as `let mut x`. This is ok in - /// user code, if awkward, but extra weird for closures, since the - /// borrow is hidden. - /// - /// So we introduce a "unique imm" borrow -- the referent is - /// immutable, but not aliasable. This solves the problem. For - /// simplicity, we don't give users the way to express this - /// borrow, it's just used when translating closures. - UniqueImmBorrow, - - /// Data is mutable and not aliasable. - MutBorrow -} - -/// Information describing the capture of an upvar. This is computed -/// during `typeck`, specifically by `regionck`. -#[derive(PartialEq, Clone, Debug, Copy)] -pub enum UpvarCapture { - /// Upvar is captured by value. This is always true when the - /// closure is labeled `move`, but can also be true in other cases - /// depending on inference. - ByValue, - - /// Upvar is captured by reference. - ByRef(UpvarBorrow), -} - -#[derive(PartialEq, Clone, Copy)] -pub struct UpvarBorrow { - /// The kind of borrow: by-ref upvars have access to shared - /// immutable borrows, which are not part of the normal language - /// syntax. - pub kind: BorrowKind, - - /// Region of the resulting reference. - pub region: ty::Region, -} - -pub type UpvarCaptureMap = FnvHashMap; - -#[derive(Copy, Clone)] -pub struct ClosureUpvar<'tcx> { - pub def: def::Def, - pub span: Span, - 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 -/// this is `None`, then the default is inherited from the -/// surrounding context. See RFC #599 for details. -#[derive(Copy, Clone)] -pub enum ObjectLifetimeDefault { - /// Require an explicit annotation. Occurs when multiple - /// `T:'a` constraints are found. - Ambiguous, - - /// Use the base default, typically 'static, but in a fn body it is a fresh variable - BaseDefault, - - /// Use the given region as the default. - Specific(Region), -} - -#[derive(Clone)] -pub struct TypeParameterDef<'tcx> { - pub name: Name, - pub def_id: DefId, - pub space: subst::ParamSpace, - pub index: u32, - pub default_def_id: DefId, // for use in error reporing about defaults - pub default: Option>, - pub object_lifetime_default: ObjectLifetimeDefault, -} - -#[derive(Clone)] -pub struct RegionParameterDef { - pub name: Name, - pub def_id: DefId, - pub space: subst::ParamSpace, - pub index: u32, - pub bounds: Vec, -} - -impl RegionParameterDef { - pub fn to_early_bound_region(&self) -> ty::Region { - ty::ReEarlyBound(ty::EarlyBoundRegion { - param_id: self.def_id.node, - space: self.space, - index: self.index, - name: self.name, - }) - } - pub fn to_bound_region(&self) -> ty::BoundRegion { - ty::BoundRegion::BrNamed(self.def_id, self.name) - } -} - -/// Information about the formal type/lifetime parameters associated -/// with an item or method. Analogous to hir::Generics. -#[derive(Clone, Debug)] -pub struct Generics<'tcx> { - pub types: VecPerParamSpace>, - pub regions: VecPerParamSpace, -} - -impl<'tcx> Generics<'tcx> { - pub fn empty() -> Generics<'tcx> { - Generics { - types: VecPerParamSpace::empty(), - regions: VecPerParamSpace::empty(), - } - } - - pub fn is_empty(&self) -> bool { - self.types.is_empty() && self.regions.is_empty() - } - - pub fn has_type_params(&self, space: subst::ParamSpace) -> bool { - !self.types.is_empty_in(space) - } - - pub fn has_region_params(&self, space: subst::ParamSpace) -> bool { - !self.regions.is_empty_in(space) - } -} - -/// Bounds on generics. -#[derive(Clone)] -pub struct GenericPredicates<'tcx> { - pub predicates: VecPerParamSpace>, -} - -impl<'tcx> GenericPredicates<'tcx> { - pub fn empty() -> GenericPredicates<'tcx> { - GenericPredicates { - predicates: VecPerParamSpace::empty(), - } - } - - pub fn instantiate(&self, tcx: &ctxt<'tcx>, substs: &Substs<'tcx>) - -> InstantiatedPredicates<'tcx> { - InstantiatedPredicates { - predicates: self.predicates.subst(tcx, substs), - } - } - - pub fn instantiate_supertrait(&self, - tcx: &ctxt<'tcx>, - poly_trait_ref: &ty::PolyTraitRef<'tcx>) - -> InstantiatedPredicates<'tcx> - { - InstantiatedPredicates { - predicates: self.predicates.map(|pred| pred.subst_supertrait(tcx, poly_trait_ref)) - } - } -} - -#[derive(Clone, PartialEq, Eq, Hash)] -pub enum Predicate<'tcx> { - /// Corresponds to `where Foo : Bar`. `Foo` here would be - /// the `Self` type of the trait reference and `A`, `B`, and `C` - /// would be the parameters in the `TypeSpace`. - Trait(PolyTraitPredicate<'tcx>), - - /// where `T1 == T2`. - Equate(PolyEquatePredicate<'tcx>), - - /// where 'a : 'b - RegionOutlives(PolyRegionOutlivesPredicate), - - /// where T : 'a - TypeOutlives(PolyTypeOutlivesPredicate<'tcx>), - - /// where ::Name == X, approximately. - /// See `ProjectionPredicate` struct for details. - Projection(PolyProjectionPredicate<'tcx>), - - /// no syntax: T WF - WellFormed(Ty<'tcx>), - - /// trait must be object-safe - ObjectSafe(DefId), -} - -impl<'tcx> Predicate<'tcx> { - /// Performs a substitution suitable for going from a - /// poly-trait-ref to supertraits that must hold if that - /// poly-trait-ref holds. This is slightly different from a normal - /// substitution in terms of what happens with bound regions. See - /// lengthy comment below for details. - pub fn subst_supertrait(&self, - tcx: &ctxt<'tcx>, - trait_ref: &ty::PolyTraitRef<'tcx>) - -> ty::Predicate<'tcx> - { - // The interaction between HRTB and supertraits is not entirely - // obvious. Let me walk you (and myself) through an example. - // - // Let's start with an easy case. Consider two traits: - // - // trait Foo<'a> : Bar<'a,'a> { } - // trait Bar<'b,'c> { } - // - // Now, if we have a trait reference `for<'x> T : Foo<'x>`, then - // we can deduce that `for<'x> T : Bar<'x,'x>`. Basically, if we - // knew that `Foo<'x>` (for any 'x) then we also know that - // `Bar<'x,'x>` (for any 'x). This more-or-less falls out from - // normal substitution. - // - // In terms of why this is sound, the idea is that whenever there - // is an impl of `T:Foo<'a>`, it must show that `T:Bar<'a,'a>` - // holds. So if there is an impl of `T:Foo<'a>` that applies to - // all `'a`, then we must know that `T:Bar<'a,'a>` holds for all - // `'a`. - // - // Another example to be careful of is this: - // - // trait Foo1<'a> : for<'b> Bar1<'a,'b> { } - // trait Bar1<'b,'c> { } - // - // Here, if we have `for<'x> T : Foo1<'x>`, then what do we know? - // The answer is that we know `for<'x,'b> T : Bar1<'x,'b>`. The - // reason is similar to the previous example: any impl of - // `T:Foo1<'x>` must show that `for<'b> T : Bar1<'x, 'b>`. So - // basically we would want to collapse the bound lifetimes from - // the input (`trait_ref`) and the supertraits. - // - // To achieve this in practice is fairly straightforward. Let's - // consider the more complicated scenario: - // - // - We start out with `for<'x> T : Foo1<'x>`. In this case, `'x` - // has a De Bruijn index of 1. We want to produce `for<'x,'b> T : Bar1<'x,'b>`, - // where both `'x` and `'b` would have a DB index of 1. - // The substitution from the input trait-ref is therefore going to be - // `'a => 'x` (where `'x` has a DB index of 1). - // - The super-trait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an - // early-bound parameter and `'b' is a late-bound parameter with a - // DB index of 1. - // - If we replace `'a` with `'x` from the input, it too will have - // a DB index of 1, and thus we'll have `for<'x,'b> Bar1<'x,'b>` - // just as we wanted. - // - // There is only one catch. If we just apply the substitution `'a - // => 'x` to `for<'b> Bar1<'a,'b>`, the substitution code will - // adjust the DB index because we substituting into a binder (it - // tries to be so smart...) resulting in `for<'x> for<'b> - // Bar1<'x,'b>` (we have no syntax for this, so use your - // imagination). Basically the 'x will have DB index of 2 and 'b - // will have DB index of 1. Not quite what we want. So we apply - // the substitution to the *contents* of the trait reference, - // rather than the trait reference itself (put another way, the - // substitution code expects equal binding levels in the values - // from the substitution and the value being substituted into, and - // this trick achieves that). - - let substs = &trait_ref.0.substs; - match *self { - Predicate::Trait(ty::Binder(ref data)) => - Predicate::Trait(ty::Binder(data.subst(tcx, substs))), - Predicate::Equate(ty::Binder(ref data)) => - Predicate::Equate(ty::Binder(data.subst(tcx, substs))), - Predicate::RegionOutlives(ty::Binder(ref data)) => - Predicate::RegionOutlives(ty::Binder(data.subst(tcx, substs))), - Predicate::TypeOutlives(ty::Binder(ref data)) => - Predicate::TypeOutlives(ty::Binder(data.subst(tcx, substs))), - Predicate::Projection(ty::Binder(ref data)) => - Predicate::Projection(ty::Binder(data.subst(tcx, substs))), - Predicate::WellFormed(data) => - Predicate::WellFormed(data.subst(tcx, substs)), - Predicate::ObjectSafe(trait_def_id) => - Predicate::ObjectSafe(trait_def_id), - } - } -} - -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct TraitPredicate<'tcx> { - pub trait_ref: TraitRef<'tcx> -} -pub type PolyTraitPredicate<'tcx> = ty::Binder>; - -impl<'tcx> TraitPredicate<'tcx> { - pub fn def_id(&self) -> DefId { - self.trait_ref.def_id - } - - pub fn input_types(&self) -> &[Ty<'tcx>] { - self.trait_ref.substs.types.as_slice() - } - - pub fn self_ty(&self) -> Ty<'tcx> { - self.trait_ref.self_ty() - } -} - -impl<'tcx> PolyTraitPredicate<'tcx> { - pub fn def_id(&self) -> DefId { - self.0.def_id() - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct EquatePredicate<'tcx>(pub Ty<'tcx>, pub Ty<'tcx>); // `0 == 1` -pub type PolyEquatePredicate<'tcx> = ty::Binder>; - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct OutlivesPredicate(pub A, pub B); // `A : B` -pub type PolyOutlivesPredicate = ty::Binder>; -pub type PolyRegionOutlivesPredicate = PolyOutlivesPredicate; -pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate, ty::Region>; - -/// This kind of predicate has no *direct* correspondent in the -/// syntax, but it roughly corresponds to the syntactic forms: -/// -/// 1. `T : TraitRef<..., Item=Type>` -/// 2. `>::Item == Type` (NYI) -/// -/// In particular, form #1 is "desugared" to the combination of a -/// normal trait predicate (`T : TraitRef<...>`) and one of these -/// predicates. Form #2 is a broader form in that it also permits -/// equality between arbitrary types. Processing an instance of Form -/// #2 eventually yields one of these `ProjectionPredicate` -/// instances to normalize the LHS. -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct ProjectionPredicate<'tcx> { - pub projection_ty: ProjectionTy<'tcx>, - pub ty: Ty<'tcx>, -} - -pub type PolyProjectionPredicate<'tcx> = Binder>; - -impl<'tcx> PolyProjectionPredicate<'tcx> { - pub fn item_name(&self) -> Name { - self.0.projection_ty.item_name // safe to skip the binder to access a name - } - - pub fn sort_key(&self) -> (DefId, Name) { - self.0.projection_ty.sort_key() - } -} - -/// 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>; -} - -impl<'tcx> ToPolyTraitRef<'tcx> for TraitRef<'tcx> { - fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { - assert!(!self.has_escaping_regions()); - ty::Binder(self.clone()) - } -} - -impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> { - fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { - self.map_bound_ref(|trait_pred| trait_pred.trait_ref.clone()) - } -} - -impl<'tcx> ToPolyTraitRef<'tcx> for PolyProjectionPredicate<'tcx> { - fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { - // Note: unlike with TraitRef::to_poly_trait_ref(), - // self.0.trait_ref is permitted to have escaping regions. - // This is because here `self` has a `Binder` and so does our - // return value, so we are preserving the number of binding - // levels. - ty::Binder(self.0.projection_ty.trait_ref.clone()) - } -} - -pub trait ToPredicate<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx>; -} - -impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx> { - // we're about to add a binder, so let's check that we don't - // accidentally capture anything, or else that might be some - // weird debruijn accounting. - assert!(!self.has_escaping_regions()); - - ty::Predicate::Trait(ty::Binder(ty::TraitPredicate { - trait_ref: self.clone() - })) - } -} - -impl<'tcx> ToPredicate<'tcx> for PolyTraitRef<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx> { - ty::Predicate::Trait(self.to_poly_trait_predicate()) - } -} - -impl<'tcx> ToPredicate<'tcx> for PolyEquatePredicate<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx> { - Predicate::Equate(self.clone()) - } -} - -impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate { - fn to_predicate(&self) -> Predicate<'tcx> { - Predicate::RegionOutlives(self.clone()) - } -} - -impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx> { - Predicate::TypeOutlives(self.clone()) - } -} - -impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx> { - Predicate::Projection(self.clone()) - } -} - -impl<'tcx> Predicate<'tcx> { - /// Iterates over the types in this predicate. Note that in all - /// cases this is skipping over a binder, so late-bound regions - /// with depth 0 are bound by the predicate. - pub fn walk_tys(&self) -> IntoIter> { - let vec: Vec<_> = match *self { - ty::Predicate::Trait(ref data) => { - data.0.trait_ref.substs.types.as_slice().to_vec() - } - ty::Predicate::Equate(ty::Binder(ref data)) => { - vec![data.0, data.1] - } - ty::Predicate::TypeOutlives(ty::Binder(ref data)) => { - vec![data.0] - } - ty::Predicate::RegionOutlives(..) => { - vec![] - } - ty::Predicate::Projection(ref data) => { - let trait_inputs = data.0.projection_ty.trait_ref.substs.types.as_slice(); - trait_inputs.iter() - .cloned() - .chain(Some(data.0.ty)) - .collect() - } - ty::Predicate::WellFormed(data) => { - vec![data] - } - ty::Predicate::ObjectSafe(_trait_def_id) => { - vec![] - } - }; - - // The only reason to collect into a vector here is that I was - // too lazy to make the full (somewhat complicated) iterator - // type that would be needed here. But I wanted this fn to - // return an iterator conceptually, rather than a `Vec`, so as - // to be closer to `Ty::walk`. - vec.into_iter() - } - - pub fn has_escaping_regions(&self) -> bool { - match *self { - Predicate::Trait(ref trait_ref) => trait_ref.has_escaping_regions(), - Predicate::Equate(ref p) => p.has_escaping_regions(), - Predicate::RegionOutlives(ref p) => p.has_escaping_regions(), - Predicate::TypeOutlives(ref p) => p.has_escaping_regions(), - Predicate::Projection(ref p) => p.has_escaping_regions(), - Predicate::WellFormed(p) => p.has_escaping_regions(), - Predicate::ObjectSafe(_trait_def_id) => false, - } - } - - pub fn to_opt_poly_trait_ref(&self) -> Option> { - match *self { - Predicate::Trait(ref t) => { - Some(t.to_poly_trait_ref()) - } - Predicate::Projection(..) | - Predicate::Equate(..) | - Predicate::RegionOutlives(..) | - Predicate::WellFormed(..) | - Predicate::ObjectSafe(..) | - Predicate::TypeOutlives(..) => { - None - } - } - } -} - -/// Represents the bounds declared on a particular set of type -/// parameters. Should eventually be generalized into a flag list of -/// where clauses. You can obtain a `InstantiatedPredicates` list from a -/// `GenericPredicates` by using the `instantiate` method. Note that this method -/// reflects an important semantic invariant of `InstantiatedPredicates`: while -/// the `GenericPredicates` are expressed in terms of the bound type -/// parameters of the impl/trait/whatever, an `InstantiatedPredicates` instance -/// represented a set of bounds for some particular instantiation, -/// meaning that the generic parameters have been substituted with -/// their values. -/// -/// Example: -/// -/// struct Foo> { ... } -/// -/// Here, the `GenericPredicates` for `Foo` would contain a list of bounds like -/// `[[], [U:Bar]]`. Now if there were some particular reference -/// like `Foo`, then the `InstantiatedPredicates` would be `[[], -/// [usize:Bar]]`. -#[derive(Clone)] -pub struct InstantiatedPredicates<'tcx> { - pub predicates: VecPerParamSpace>, -} - -impl<'tcx> InstantiatedPredicates<'tcx> { - pub fn empty() -> InstantiatedPredicates<'tcx> { - InstantiatedPredicates { predicates: VecPerParamSpace::empty() } - } - - pub fn has_escaping_regions(&self) -> bool { - self.predicates.any(|p| p.has_escaping_regions()) - } - - pub fn is_empty(&self) -> bool { - self.predicates.is_empty() - } -} - -impl<'tcx> TraitRef<'tcx> { - pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>) -> TraitRef<'tcx> { - TraitRef { def_id: def_id, substs: substs } - } - - pub fn self_ty(&self) -> Ty<'tcx> { - self.substs.self_ty().unwrap() - } - - pub fn input_types(&self) -> &[Ty<'tcx>] { - // Select only the "input types" from a trait-reference. For - // now this is all the types that appear in the - // trait-reference, but it should eventually exclude - // associated types. - self.substs.types.as_slice() - } -} - -/// When type checking, we use the `ParameterEnvironment` to track -/// details about the type/lifetime parameters that are in scope. -/// It primarily stores the bounds information. -/// -/// Note: This information might seem to be redundant with the data in -/// `tcx.ty_param_defs`, but it is not. That table contains the -/// parameter definitions from an "outside" perspective, but this -/// struct will contain the bounds for a parameter as seen from inside -/// the function body. Currently the only real distinction is that -/// bound lifetime parameters are replaced with free ones, but in the -/// future I hope to refine the representation of types so as to make -/// more distinctions clearer. -#[derive(Clone)] -pub struct ParameterEnvironment<'a, 'tcx:'a> { - pub tcx: &'a ctxt<'tcx>, - - /// See `construct_free_substs` for details. - pub free_substs: Substs<'tcx>, - - /// Each type parameter has an implicit region bound that - /// indicates it must outlive at least the function body (the user - /// may specify stronger requirements). This field indicates the - /// region of the callee. - pub implicit_region_bound: ty::Region, - - /// Obligations that the caller must satisfy. This is basically - /// the set of bounds on the in-scope type parameters, translated - /// into Obligations, and elaborated and normalized. - pub caller_bounds: Vec>, - - /// Caches the results of trait selection. This cache is used - /// for things that have to do with the parameters in scope. - pub selection_cache: traits::SelectionCache<'tcx>, - - /// Scope that is attached to free regions for this scope. This - /// is usually the id of the fn body, but for more abstract scopes - /// like structs we often use the node-id of the struct. - /// - /// FIXME(#3696). It would be nice to refactor so that free - /// regions don't have this implicit scope and instead introduce - /// relationships in the environment. - pub free_id: ast::NodeId, -} - -impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { - pub fn with_caller_bounds(&self, - caller_bounds: Vec>) - -> ParameterEnvironment<'a,'tcx> - { - ParameterEnvironment { - tcx: self.tcx, - free_substs: self.free_substs.clone(), - implicit_region_bound: self.implicit_region_bound, - caller_bounds: caller_bounds, - selection_cache: traits::SelectionCache::new(), - free_id: self.free_id, - } - } - - pub fn for_item(cx: &'a ctxt<'tcx>, id: NodeId) -> ParameterEnvironment<'a, 'tcx> { - match cx.map.find(id) { - Some(ast_map::NodeImplItem(ref impl_item)) => { - match impl_item.node { - hir::TypeImplItem(_) => { - // associated types don't have their own entry (for some reason), - // so for now just grab environment for the impl - let impl_id = cx.map.get_parent(id); - let impl_def_id = DefId::local(impl_id); - let scheme = cx.lookup_item_type(impl_def_id); - let predicates = cx.lookup_predicates(impl_def_id); - cx.construct_parameter_environment(impl_item.span, - &scheme.generics, - &predicates, - id) - } - hir::ConstImplItem(_, _) => { - let def_id = DefId::local(id); - let scheme = cx.lookup_item_type(def_id); - let predicates = cx.lookup_predicates(def_id); - cx.construct_parameter_environment(impl_item.span, - &scheme.generics, - &predicates, - id) - } - hir::MethodImplItem(_, ref body) => { - let method_def_id = DefId::local(id); - match cx.impl_or_trait_item(method_def_id) { - MethodTraitItem(ref method_ty) => { - let method_generics = &method_ty.generics; - let method_bounds = &method_ty.predicates; - cx.construct_parameter_environment( - impl_item.span, - method_generics, - method_bounds, - body.id) - } - _ => { - cx.sess - .bug("ParameterEnvironment::for_item(): \ - got non-method item from impl method?!") - } - } - } - } - } - Some(ast_map::NodeTraitItem(trait_item)) => { - match trait_item.node { - hir::TypeTraitItem(..) => { - // associated types don't have their own entry (for some reason), - // so for now just grab environment for the trait - let trait_id = cx.map.get_parent(id); - let trait_def_id = DefId::local(trait_id); - let trait_def = cx.lookup_trait_def(trait_def_id); - let predicates = cx.lookup_predicates(trait_def_id); - cx.construct_parameter_environment(trait_item.span, - &trait_def.generics, - &predicates, - id) - } - hir::ConstTraitItem(..) => { - let def_id = DefId::local(id); - let scheme = cx.lookup_item_type(def_id); - let predicates = cx.lookup_predicates(def_id); - cx.construct_parameter_environment(trait_item.span, - &scheme.generics, - &predicates, - id) - } - hir::MethodTraitItem(_, ref body) => { - // for the body-id, use the id of the body - // block, unless this is a trait method with - // no default, then fallback to the method id. - let body_id = body.as_ref().map(|b| b.id).unwrap_or(id); - let method_def_id = DefId::local(id); - - match cx.impl_or_trait_item(method_def_id) { - MethodTraitItem(ref method_ty) => { - let method_generics = &method_ty.generics; - let method_bounds = &method_ty.predicates; - cx.construct_parameter_environment( - trait_item.span, - method_generics, - method_bounds, - body_id) - } - _ => { - cx.sess - .bug("ParameterEnvironment::for_item(): \ - got non-method item from provided \ - method?!") - } - } - } - } - } - Some(ast_map::NodeItem(item)) => { - match item.node { - hir::ItemFn(_, _, _, _, _, ref body) => { - // We assume this is a function. - let fn_def_id = DefId::local(id); - let fn_scheme = cx.lookup_item_type(fn_def_id); - let fn_predicates = cx.lookup_predicates(fn_def_id); - - cx.construct_parameter_environment(item.span, - &fn_scheme.generics, - &fn_predicates, - body.id) - } - hir::ItemEnum(..) | - hir::ItemStruct(..) | - hir::ItemImpl(..) | - hir::ItemConst(..) | - hir::ItemStatic(..) => { - let def_id = DefId::local(id); - let scheme = cx.lookup_item_type(def_id); - let predicates = cx.lookup_predicates(def_id); - cx.construct_parameter_environment(item.span, - &scheme.generics, - &predicates, - id) - } - hir::ItemTrait(..) => { - let def_id = DefId::local(id); - let trait_def = cx.lookup_trait_def(def_id); - let predicates = cx.lookup_predicates(def_id); - cx.construct_parameter_environment(item.span, - &trait_def.generics, - &predicates, - id) - } - _ => { - cx.sess.span_bug(item.span, - "ParameterEnvironment::from_item(): - can't create a parameter \ - environment for this kind of item") - } - } - } - Some(ast_map::NodeExpr(..)) => { - // This is a convenience to allow closures to work. - ParameterEnvironment::for_item(cx, cx.map.get_parent(id)) - } - _ => { - cx.sess.bug(&format!("ParameterEnvironment::from_item(): \ - `{}` is not an item", - cx.map.node_to_string(id))) - } - } - } - - 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 -/// set of generic types that the type is, well, generic over. In Rust -/// terms, it is the "type" of a fn item or struct -- this type will -/// include various generic parameters that must be substituted when -/// the item/struct is referenced. That is called converting the type -/// scheme to a monotype. -/// -/// - `generics`: the set of type parameters and their bounds -/// - `ty`: the base types, which may reference the parameters defined -/// in `generics` -/// -/// Note that TypeSchemes are also sometimes called "polytypes" (and -/// in fact this struct used to carry that name, so you may find some -/// stray references in a comment or something). We try to reserve the -/// "poly" prefix to refer to higher-ranked things, as in -/// `PolyTraitRef`. -/// -/// Note that each item also comes with predicates, see -/// `lookup_predicates`. -#[derive(Clone, Debug)] -pub struct TypeScheme<'tcx> { - pub generics: Generics<'tcx>, - pub ty: Ty<'tcx>, -} - -bitflags! { - flags TraitFlags: u32 { - const NO_TRAIT_FLAGS = 0, - const HAS_DEFAULT_IMPL = 1 << 0, - const IS_OBJECT_SAFE = 1 << 1, - const OBJECT_SAFETY_VALID = 1 << 2, - const IMPLS_VALID = 1 << 3, - } -} - -/// As `TypeScheme` but for a trait ref. -pub struct TraitDef<'tcx> { - pub unsafety: hir::Unsafety, - - /// If `true`, then this trait had the `#[rustc_paren_sugar]` - /// attribute, indicating that it should be used with `Foo()` - /// sugar. This is a temporary thing -- eventually any trait wil - /// be usable with the sugar (or without it). - pub paren_sugar: bool, - - /// Generic type definitions. Note that `Self` is listed in here - /// as having a single bound, the trait itself (e.g., in the trait - /// `Eq`, there is a single bound `Self : Eq`). This is so that - /// default methods get to assume that the `Self` parameters - /// implements the trait. - pub generics: Generics<'tcx>, - - pub trait_ref: TraitRef<'tcx>, - - /// A list of the associated types defined in this trait. Useful - /// for resolving `X::Foo` type markers. - pub associated_type_names: Vec, - - // Impls of this trait. To allow for quicker lookup, the impls are indexed - // by a simplified version of their Self type: impls with a simplifiable - // Self are stored in nonblanket_impls keyed by it, while all other impls - // are stored in blanket_impls. - - /// Impls of the trait. - pub nonblanket_impls: RefCell< - FnvHashMap> - >, - - /// Blanket impls associated with the trait. - pub blanket_impls: RefCell>, - - /// Various flags - pub flags: Cell -} - -impl<'tcx> TraitDef<'tcx> { - // returns None if not yet calculated - pub fn object_safety(&self) -> Option { - if self.flags.get().intersects(TraitFlags::OBJECT_SAFETY_VALID) { - Some(self.flags.get().intersects(TraitFlags::IS_OBJECT_SAFE)) - } else { - None - } - } - - pub fn set_object_safety(&self, is_safe: bool) { - assert!(self.object_safety().map(|cs| cs == is_safe).unwrap_or(true)); - self.flags.set( - self.flags.get() | if is_safe { - TraitFlags::OBJECT_SAFETY_VALID | TraitFlags::IS_OBJECT_SAFE - } else { - TraitFlags::OBJECT_SAFETY_VALID - } - ); - } - - /// Records a trait-to-implementation mapping. - pub fn record_impl(&self, - tcx: &ctxt<'tcx>, - impl_def_id: DefId, - impl_trait_ref: TraitRef<'tcx>) { - debug!("TraitDef::record_impl for {:?}, from {:?}", - self, impl_trait_ref); - - // We don't want to borrow_mut after we already populated all impls, - // so check if an impl is present with an immutable borrow first. - if let Some(sty) = fast_reject::simplify_type(tcx, - impl_trait_ref.self_ty(), false) { - if let Some(is) = self.nonblanket_impls.borrow().get(&sty) { - if is.contains(&impl_def_id) { - return // duplicate - skip - } - } - - self.nonblanket_impls.borrow_mut().entry(sty).or_insert(vec![]).push(impl_def_id) - } else { - if self.blanket_impls.borrow().contains(&impl_def_id) { - return // duplicate - skip - } - self.blanket_impls.borrow_mut().push(impl_def_id) - } - } - - - pub fn for_each_impl(&self, tcx: &ctxt<'tcx>, mut f: F) { - tcx.populate_implementations_for_trait_if_necessary(self.trait_ref.def_id); - - for &impl_def_id in self.blanket_impls.borrow().iter() { - f(impl_def_id); - } - - for v in self.nonblanket_impls.borrow().values() { - for &impl_def_id in v { - f(impl_def_id); - } - } - } - - /// Iterate over every impl that could possibly match the - /// self-type `self_ty`. - pub fn for_each_relevant_impl(&self, - tcx: &ctxt<'tcx>, - self_ty: Ty<'tcx>, - mut f: F) - { - tcx.populate_implementations_for_trait_if_necessary(self.trait_ref.def_id); - - for &impl_def_id in self.blanket_impls.borrow().iter() { - f(impl_def_id); - } - - // simplify_type(.., false) basically replaces type parameters and - // projections with infer-variables. This is, of course, done on - // the impl trait-ref when it is instantiated, but not on the - // predicate trait-ref which is passed here. - // - // for example, if we match `S: Copy` against an impl like - // `impl Copy for Option`, we replace the type variable - // in `Option` with an infer variable, to `Option<_>` (this - // doesn't actually change fast_reject output), but we don't - // replace `S` with anything - this impl of course can't be - // selected, and as there are hundreds of similar impls, - // considering them would significantly harm performance. - if let Some(simp) = fast_reject::simplify_type(tcx, self_ty, true) { - if let Some(impls) = self.nonblanket_impls.borrow().get(&simp) { - for &impl_def_id in impls { - f(impl_def_id); - } - } - } else { - for v in self.nonblanket_impls.borrow().values() { - for &impl_def_id in v { - f(impl_def_id); - } - } - } - } - -} - -bitflags! { - flags AdtFlags: u32 { - const NO_ADT_FLAGS = 0, - const IS_ENUM = 1 << 0, - const IS_DTORCK = 1 << 1, // is this a dtorck type? - const IS_DTORCK_VALID = 1 << 2, - const IS_PHANTOM_DATA = 1 << 3, - const IS_SIMD = 1 << 4, - const IS_FUNDAMENTAL = 1 << 5, - const IS_NO_DROP_FLAG = 1 << 6, - } -} - -pub type AdtDef<'tcx> = &'tcx AdtDefData<'tcx, 'static>; -pub type VariantDef<'tcx> = &'tcx VariantDefData<'tcx, 'static>; -pub type FieldDef<'tcx> = &'tcx FieldDefData<'tcx, 'static>; - -// See comment on AdtDefData for explanation -pub type AdtDefMaster<'tcx> = &'tcx AdtDefData<'tcx, 'tcx>; -pub type VariantDefMaster<'tcx> = &'tcx VariantDefData<'tcx, 'tcx>; -pub type FieldDefMaster<'tcx> = &'tcx FieldDefData<'tcx, 'tcx>; - -pub struct VariantDefData<'tcx, 'container: 'tcx> { - pub did: DefId, - pub name: Name, // struct's name if this is a struct - pub disr_val: Disr, - pub fields: Vec> -} - -pub struct FieldDefData<'tcx, 'container: 'tcx> { - /// The field's DefId. NOTE: the fields of tuple-like enum variants - /// are not real items, and don't have entries in tcache etc. - pub did: DefId, - /// special_idents::unnamed_field.name - /// if this is a tuple-like field - pub name: Name, - pub vis: hir::Visibility, - /// TyIVar is used here to allow for variance (see the doc at - /// AdtDefData). - ty: TyIVar<'tcx, 'container> -} - -/// The definition of an abstract data type - a struct or enum. -/// -/// These are all interned (by intern_adt_def) into the adt_defs -/// table. -/// -/// Because of the possibility of nested tcx-s, this type -/// needs 2 lifetimes: the traditional variant lifetime ('tcx) -/// bounding the lifetime of the inner types is of course necessary. -/// However, it is not sufficient - types from a child tcx must -/// not be leaked into the master tcx by being stored in an AdtDefData. -/// -/// The 'container lifetime ensures that by outliving the container -/// tcx and preventing shorter-lived types from being inserted. When -/// write access is not needed, the 'container lifetime can be -/// erased to 'static, which can be done by the AdtDef wrapper. -pub struct AdtDefData<'tcx, 'container: 'tcx> { - pub did: DefId, - pub variants: Vec>, - destructor: Cell>, - flags: Cell, -} - -impl<'tcx, 'container> PartialEq for AdtDefData<'tcx, 'container> { - // AdtDefData are always interned and this is part of TyS equality - #[inline] - fn eq(&self, other: &Self) -> bool { self as *const _ == other as *const _ } -} - -impl<'tcx, 'container> Eq for AdtDefData<'tcx, 'container> {} - -impl<'tcx, 'container> Hash for AdtDefData<'tcx, 'container> { - #[inline] - fn hash(&self, s: &mut H) { - (self as *const AdtDefData).hash(s) - } -} - - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum AdtKind { Struct, Enum } - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum VariantKind { Dict, Tuple, Unit } - -impl<'tcx, 'container> AdtDefData<'tcx, 'container> { - fn new(tcx: &ctxt<'tcx>, - did: DefId, - kind: AdtKind, - variants: Vec>) -> Self { - let mut flags = AdtFlags::NO_ADT_FLAGS; - let attrs = tcx.get_attrs(did); - if attr::contains_name(&attrs, "fundamental") { - flags = flags | AdtFlags::IS_FUNDAMENTAL; - } - if attr::contains_name(&attrs, "unsafe_no_drop_flag") { - flags = flags | AdtFlags::IS_NO_DROP_FLAG; - } - if tcx.lookup_simd(did) { - flags = flags | AdtFlags::IS_SIMD; - } - if Some(did) == tcx.lang_items.phantom_data() { - flags = flags | AdtFlags::IS_PHANTOM_DATA; - } - if let AdtKind::Enum = kind { - flags = flags | AdtFlags::IS_ENUM; - } - AdtDefData { - did: did, - variants: variants, - flags: Cell::new(flags), - destructor: Cell::new(None) - } - } - - fn calculate_dtorck(&'tcx self, tcx: &ctxt<'tcx>) { - if tcx.is_adt_dtorck(self) { - self.flags.set(self.flags.get() | AdtFlags::IS_DTORCK); - } - self.flags.set(self.flags.get() | AdtFlags::IS_DTORCK_VALID) - } - - /// Returns the kind of the ADT - Struct or Enum. - #[inline] - pub fn adt_kind(&self) -> AdtKind { - if self.flags.get().intersects(AdtFlags::IS_ENUM) { - AdtKind::Enum - } else { - AdtKind::Struct - } - } - - /// Returns whether this is a dtorck type. If this returns - /// true, this type being safe for destruction requires it to be - /// alive; Otherwise, only the contents are required to be. - #[inline] - pub fn is_dtorck(&'tcx self, tcx: &ctxt<'tcx>) -> bool { - if !self.flags.get().intersects(AdtFlags::IS_DTORCK_VALID) { - self.calculate_dtorck(tcx) - } - self.flags.get().intersects(AdtFlags::IS_DTORCK) - } - - /// Returns whether this type is #[fundamental] for the purposes - /// of coherence checking. - #[inline] - pub fn is_fundamental(&self) -> bool { - self.flags.get().intersects(AdtFlags::IS_FUNDAMENTAL) - } - - #[inline] - pub fn is_simd(&self) -> bool { - self.flags.get().intersects(AdtFlags::IS_SIMD) - } - - /// Returns true if this is PhantomData. - #[inline] - pub fn is_phantom_data(&self) -> bool { - self.flags.get().intersects(AdtFlags::IS_PHANTOM_DATA) - } - - /// Returns whether this type has a destructor. - pub fn has_dtor(&self) -> bool { - match self.dtor_kind() { - NoDtor => false, - TraitDtor(..) => true - } - } - - /// Asserts this is a struct and returns the struct's unique - /// variant. - pub fn struct_variant(&self) -> &VariantDefData<'tcx, 'container> { - assert!(self.adt_kind() == AdtKind::Struct); - &self.variants[0] - } - - #[inline] - pub fn type_scheme(&self, tcx: &ctxt<'tcx>) -> TypeScheme<'tcx> { - tcx.lookup_item_type(self.did) - } - - #[inline] - pub fn predicates(&self, tcx: &ctxt<'tcx>) -> GenericPredicates<'tcx> { - tcx.lookup_predicates(self.did) - } - - /// Returns an iterator over all fields contained - /// by this ADT. - #[inline] - pub fn all_fields(&self) -> - iter::FlatMap< - slice::Iter>, - slice::Iter>, - for<'s> fn(&'s VariantDefData<'tcx, 'container>) - -> slice::Iter<'s, FieldDefData<'tcx, 'container>> - > { - self.variants.iter().flat_map(VariantDefData::fields_iter) - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.variants.is_empty() - } - - #[inline] - pub fn is_univariant(&self) -> bool { - self.variants.len() == 1 - } - - pub fn is_payloadfree(&self) -> bool { - !self.variants.is_empty() && - self.variants.iter().all(|v| v.fields.is_empty()) - } - - pub fn variant_with_id(&self, vid: DefId) -> &VariantDefData<'tcx, 'container> { - self.variants - .iter() - .find(|v| v.did == vid) - .expect("variant_with_id: unknown variant") - } - - pub fn variant_index_with_id(&self, vid: DefId) -> usize { - self.variants - .iter() - .position(|v| v.did == vid) - .expect("variant_index_with_id: unknown variant") - } - - pub fn variant_of_def(&self, def: def::Def) -> &VariantDefData<'tcx, 'container> { - match def { - def::DefVariant(_, vid, _) => self.variant_with_id(vid), - def::DefStruct(..) | def::DefTy(..) => self.struct_variant(), - _ => panic!("unexpected def {:?} in variant_of_def", def) - } - } - - pub fn destructor(&self) -> Option { - self.destructor.get() - } - - pub fn set_destructor(&self, dtor: DefId) { - assert!(self.destructor.get().is_none()); - self.destructor.set(Some(dtor)); - } - - pub fn dtor_kind(&self) -> DtorKind { - match self.destructor.get() { - Some(_) => { - TraitDtor(!self.flags.get().intersects(AdtFlags::IS_NO_DROP_FLAG)) - } - None => NoDtor, - } - } -} - -impl<'tcx, 'container> VariantDefData<'tcx, 'container> { - #[inline] - fn fields_iter(&self) -> slice::Iter> { - self.fields.iter() - } - - pub fn kind(&self) -> VariantKind { - match self.fields.get(0) { - None => VariantKind::Unit, - Some(&FieldDefData { name, .. }) if name == special_idents::unnamed_field.name => { - VariantKind::Tuple - } - Some(_) => VariantKind::Dict - } - } - - pub fn is_tuple_struct(&self) -> bool { - self.kind() == VariantKind::Tuple - } - - #[inline] - pub fn find_field_named(&self, - name: ast::Name) - -> Option<&FieldDefData<'tcx, 'container>> { - self.fields.iter().find(|f| f.name == name) - } - - #[inline] - pub fn field_named(&self, name: ast::Name) -> &FieldDefData<'tcx, 'container> { - self.find_field_named(name).unwrap() - } -} - -impl<'tcx, 'container> FieldDefData<'tcx, 'container> { - pub fn new(did: DefId, - name: Name, - vis: hir::Visibility) -> Self { - FieldDefData { - did: did, - name: name, - vis: vis, - ty: TyIVar::new() - } - } - - pub fn ty(&self, tcx: &ctxt<'tcx>, subst: &Substs<'tcx>) -> Ty<'tcx> { - self.unsubst_ty().subst(tcx, subst) - } - - pub fn unsubst_ty(&self) -> Ty<'tcx> { - self.ty.unwrap() - } - - pub fn fulfill_ty(&self, ty: Ty<'container>) { - self.ty.fulfill(ty); - } -} - -/// Records the substitutions used to translate the polytype for an -/// item into the monotype of an item reference. -#[derive(Clone)] -pub struct ItemSubsts<'tcx> { - pub substs: Substs<'tcx>, -} - -#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)] -pub enum ClosureKind { - // Warning: Ordering is significant here! The ordering is chosen - // because the trait Fn is a subtrait of FnMut and so in turn, and - // hence we order it so that Fn < FnMut < FnOnce. - FnClosureKind, - FnMutClosureKind, - FnOnceClosureKind, -} - -impl ClosureKind { - pub fn trait_did(&self, cx: &ctxt) -> DefId { - let result = match *self { - FnClosureKind => cx.lang_items.require(FnTraitLangItem), - FnMutClosureKind => { - cx.lang_items.require(FnMutTraitLangItem) - } - FnOnceClosureKind => { - cx.lang_items.require(FnOnceTraitLangItem) - } - }; - match result { - Ok(trait_did) => trait_did, - Err(err) => cx.sess.fatal(&err[..]), - } - } - - /// True if this a type that impls this closure kind - /// must also implement `other`. - pub fn extends(self, other: ty::ClosureKind) -> bool { - match (self, other) { - (FnClosureKind, FnClosureKind) => true, - (FnClosureKind, FnMutClosureKind) => true, - (FnClosureKind, FnOnceClosureKind) => true, - (FnMutClosureKind, FnMutClosureKind) => true, - (FnMutClosureKind, FnOnceClosureKind) => true, - (FnOnceClosureKind, FnOnceClosureKind) => true, - _ => false, - } - } -} - -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)), - } - } -} - -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 } - } - - fn for_sty(st: &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: &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) - } - - &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> { - ty_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. - /// - /// 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 - } -} - -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) - } - - 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> 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) - -> 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, - NoPreference -} - -impl LvaluePreference { - pub fn from_mutbl(m: hir::Mutability) -> Self { - match m { - hir::MutMutable => PreferMutLvalue, - hir::MutImmutable => NoPreference, - } - } -} - -/// 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 - } - - 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, - 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 }) - } - } - } - - 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 -/// 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 -/// into the map by the `typeck::collect` phase. If the def-id is external, -/// then we have to go consult the crate loading code (and cache the result for -/// the future). -fn lookup_locally_or_in_crate_store(descr: &str, - def_id: DefId, - map: &RefCell>, - load_external: F) -> V where - V: Clone, - F: FnOnce() -> V, -{ - match map.borrow().get(&def_id).cloned() { - Some(v) => { return v; } - None => { } - } - - if def_id.is_local() { - panic!("No def'n found for {:?} in tcx.{}", def_id, descr); - } - let v = load_external(); - map.borrow_mut().insert(def_id, v.clone()); - v -} - -impl BorrowKind { - pub fn from_mutbl(m: hir::Mutability) -> BorrowKind { - match m { - hir::MutMutable => MutBorrow, - hir::MutImmutable => ImmBorrow, - } - } - - /// Returns a mutability `m` such that an `&m T` pointer could be used to obtain this borrow - /// kind. Because borrow kinds are richer than mutabilities, we sometimes have to pick a - /// mutability that is stronger than necessary so that it at least *would permit* the borrow in - /// question. - pub fn to_mutbl_lossy(self) -> hir::Mutability { - match self { - MutBorrow => hir::MutMutable, - ImmBorrow => hir::MutImmutable, - - // We have no type corresponding to a unique imm borrow, so - // use `&mut`. It gives all the capabilities of an `&uniq` - // and hence is a safe "over approximation". - UniqueImmBorrow => hir::MutMutable, - } - } - - pub fn to_user_str(&self) -> &'static str { - match *self { - MutBorrow => "mutable", - ImmBorrow => "immutable", - UniqueImmBorrow => "uniquely immutable", - } - } -} - -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, - None => self.sess.bug( - &format!("node_id_to_type: no type for node `{}`", - self.map.node_to_string(id))) - } - } - - pub fn node_id_to_type_opt(&self, id: NodeId) -> Option> { - self.tables.borrow().node_types.get(&id).cloned() - } - - pub fn node_id_item_substs(&self, id: NodeId) -> ItemSubsts<'tcx> { - match self.tables.borrow().item_substs.get(&id) { - None => ItemSubsts::empty(), - Some(ts) => ts.clone(), - } - } - - // Returns the type of a pattern as a monotype. Like @expr_ty, this function - // doesn't provide type parameter substitutions. - pub fn pat_ty(&self, pat: &hir::Pat) -> Ty<'tcx> { - self.node_id_to_type(pat.id) - } - pub fn pat_ty_opt(&self, pat: &hir::Pat) -> Option> { - self.node_id_to_type_opt(pat.id) - } - - // Returns the type of an expression as a monotype. - // - // NB (1): This is the PRE-ADJUSTMENT TYPE for the expression. That is, in - // some cases, we insert `AutoAdjustment` annotations such as auto-deref or - // auto-ref. The type returned by this function does not consider such - // adjustments. See `expr_ty_adjusted()` instead. - // - // NB (2): This type doesn't provide type parameter substitutions; e.g. if you - // ask for the type of "id" in "id(3)", it will return "fn(&isize) -> isize" - // instead of "fn(ty) -> T with T = isize". - pub fn expr_ty(&self, expr: &hir::Expr) -> Ty<'tcx> { - self.node_id_to_type(expr.id) - } - - pub fn expr_ty_opt(&self, expr: &hir::Expr) -> Option> { - self.node_id_to_type_opt(expr.id) - } - - /// Returns the type of `expr`, considering any `AutoAdjustment` - /// entry recorded for that expression. - /// - /// It would almost certainly be better to store the adjusted ty in with - /// the `AutoAdjustment`, but I opted not to do this because it would - /// require serializing and deserializing the type and, although that's not - /// hard to do, I just hate that code so much I didn't want to touch it - /// unless it was to fix it properly, which seemed a distraction from the - /// thread at hand! -nmatsakis - pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> Ty<'tcx> { - self.expr_ty(expr) - .adjust(self, expr.span, expr.id, - self.tables.borrow().adjustments.get(&expr.id), - |method_call| { - self.tables.borrow().method_map.get(&method_call).map(|method| method.ty) - }) - } - - pub fn expr_span(&self, id: NodeId) -> Span { - match self.map.find(id) { - Some(ast_map::NodeExpr(e)) => { - e.span - } - Some(f) => { - self.sess.bug(&format!("Node id {} is not an expr: {:?}", - id, f)); - } - None => { - self.sess.bug(&format!("Node id {} is not present \ - in the node map", id)); - } - } - } - - pub fn local_var_name_str(&self, id: NodeId) -> InternedString { - match self.map.find(id) { - Some(ast_map::NodeLocal(pat)) => { - match pat.node { - hir::PatIdent(_, ref path1, _) => path1.node.name.as_str(), - _ => { - self.sess.bug(&format!("Variable id {} maps to {:?}, not local", id, pat)); - }, - } - }, - r => self.sess.bug(&format!("Variable id {} maps to {:?}, not local", id, r)), - } - } - - pub fn resolve_expr(&self, expr: &hir::Expr) -> def::Def { - match self.def_map.borrow().get(&expr.id) { - Some(def) => def.full_def(), - None => { - self.sess.span_bug(expr.span, &format!( - "no def-map entry for expr {}", expr.id)); - } - } - } - - pub fn expr_is_lval(&self, expr: &hir::Expr) -> bool { - match expr.node { - hir::ExprPath(..) => { - // We can't use resolve_expr here, as this needs to run on broken - // programs. We don't need to through - associated items are all - // rvalues. - match self.def_map.borrow().get(&expr.id) { - Some(&def::PathResolution { - base_def: def::DefStatic(..), .. - }) | Some(&def::PathResolution { - base_def: def::DefUpvar(..), .. - }) | Some(&def::PathResolution { - base_def: def::DefLocal(..), .. - }) => { - true - } - - Some(..) => false, - - None => self.sess.span_bug(expr.span, &format!( - "no def for path {}", expr.id)) - } - } - - hir::ExprUnary(hir::UnDeref, _) | - hir::ExprField(..) | - hir::ExprTupField(..) | - hir::ExprIndex(..) => { - true - } - - hir::ExprCall(..) | - hir::ExprMethodCall(..) | - hir::ExprStruct(..) | - hir::ExprRange(..) | - hir::ExprTup(..) | - hir::ExprIf(..) | - hir::ExprMatch(..) | - hir::ExprClosure(..) | - hir::ExprBlock(..) | - hir::ExprRepeat(..) | - hir::ExprVec(..) | - hir::ExprBreak(..) | - hir::ExprAgain(..) | - hir::ExprRet(..) | - hir::ExprWhile(..) | - hir::ExprLoop(..) | - hir::ExprAssign(..) | - hir::ExprInlineAsm(..) | - 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")); - } - _ => {} - } - } - - pub fn provided_source(&self, id: DefId) -> Option { - self.provided_method_sources.borrow().get(&id).cloned() - } - - pub fn provided_trait_methods(&self, id: DefId) -> Vec>> { - if id.is_local() { - if let ItemTrait(_, _, _, ref ms) = self.map.expect_item(id.node).node { - ms.iter().filter_map(|ti| { - if let hir::MethodTraitItem(_, Some(_)) = ti.node { - match self.impl_or_trait_item(DefId::local(ti.id)) { - MethodTraitItem(m) => Some(m), - _ => { - self.sess.bug("provided_trait_methods(): \ - non-method item found from \ - looking up provided method?!") - } - } - } else { - None - } - }).collect() - } else { - self.sess.bug(&format!("provided_trait_methods: `{:?}` is not a trait", id)) - } - } else { - csearch::get_provided_trait_methods(self, id) - } - } - - pub fn associated_consts(&self, id: DefId) -> Vec>> { - if id.is_local() { - match self.map.expect_item(id.node).node { - ItemTrait(_, _, _, ref tis) => { - tis.iter().filter_map(|ti| { - if let hir::ConstTraitItem(_, _) = ti.node { - match self.impl_or_trait_item(DefId::local(ti.id)) { - ConstTraitItem(ac) => Some(ac), - _ => { - self.sess.bug("associated_consts(): \ - non-const item found from \ - looking up a constant?!") - } - } - } else { - None - } - }).collect() - } - ItemImpl(_, _, _, _, _, ref iis) => { - iis.iter().filter_map(|ii| { - if let hir::ConstImplItem(_, _) = ii.node { - match self.impl_or_trait_item(DefId::local(ii.id)) { - ConstTraitItem(ac) => Some(ac), - _ => { - self.sess.bug("associated_consts(): \ - non-const item found from \ - looking up a constant?!") - } - } - } else { - None - } - }).collect() - } - _ => { - self.sess.bug(&format!("associated_consts: `{:?}` is not a trait \ - or impl", id)) - } - } - } else { - csearch::get_associated_consts(self, id) - } - } - - pub fn trait_items(&self, trait_did: DefId) -> Rc>> { - let mut trait_items = self.trait_items_cache.borrow_mut(); - match trait_items.get(&trait_did).cloned() { - Some(trait_items) => trait_items, - None => { - let def_ids = self.trait_item_def_ids(trait_did); - let items: Rc> = - Rc::new(def_ids.iter() - .map(|d| self.impl_or_trait_item(d.def_id())) - .collect()); - trait_items.insert(trait_did, items.clone()); - items - } - } - } - - pub fn trait_impl_polarity(&self, id: DefId) -> Option { - if id.is_local() { - match self.map.find(id.node) { - Some(ast_map::NodeItem(item)) => { - match item.node { - hir::ItemImpl(_, polarity, _, _, _, _) => Some(polarity), - _ => None - } - } - _ => None - } - } else { - csearch::get_impl_polarity(self, id) - } - } - - pub fn custom_coerce_unsized_kind(&self, did: DefId) -> 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") - } else { - (None, "local") - }; - - match kind { - Some(kind) => kind, - None => { - self.sess.bug(&format!("custom_coerce_unsized_kind: \ - {} impl `{}` is missing its kind", - src, self.item_path_str(did))); - } - } - }) - } - - pub fn impl_or_trait_item(&self, id: DefId) -> ImplOrTraitItem<'tcx> { - lookup_locally_or_in_crate_store( - "impl_or_trait_items", id, &self.impl_or_trait_items, - || csearch::get_impl_or_trait_item(self, id)) - } - - pub fn trait_item_def_ids(&self, id: DefId) -> Rc> { - lookup_locally_or_in_crate_store( - "trait_item_def_ids", id, &self.trait_item_def_ids, - || Rc::new(csearch::get_trait_item_def_ids(&self.sess.cstore, id))) - } - - /// Returns the trait-ref corresponding to a given impl, or None if it is - /// an inherent impl. - pub fn impl_trait_ref(&self, id: DefId) -> Option> { - lookup_locally_or_in_crate_store( - "impl_trait_refs", id, &self.impl_trait_refs, - || csearch::get_impl_trait(self, id)) - } - - /// Returns whether this DefId refers to an impl - pub fn is_impl(&self, id: DefId) -> bool { - if id.is_local() { - if let Some(ast_map::NodeItem( - &hir::Item { node: hir::ItemImpl(..), .. })) = self.map.find(id.node) { - true - } else { - false - } - } else { - csearch::is_impl(&self.sess.cstore, id) - } - } - - pub fn trait_ref_to_def_id(&self, tr: &hir::TraitRef) -> DefId { - 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)) - } - - pub fn with_path(&self, id: DefId, f: F) -> T where - F: FnOnce(ast_map::PathElems) -> T, - { - if id.is_local() { - self.map.with_path(id.node, f) - } else { - f(csearch::get_item_path(self, id).iter().cloned().chain(LinkedPath::empty())) - } - } - - pub fn item_name(&self, id: DefId) -> ast::Name { - if id.is_local() { - self.map.get_path_elem(id.node).name() - } else { - csearch::get_item_name(self, id) - } - } - - /// 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); - } - - // If the given item is in an external crate, looks up its type and adds it to - // the type cache. Returns the type parameters and type. - pub fn lookup_item_type(&self, did: DefId) -> TypeScheme<'tcx> { - lookup_locally_or_in_crate_store( - "tcache", did, &self.tcache, - || csearch::get_type(self, did)) - } - - /// Given the did of a trait, returns its canonical trait ref. - 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)) - ) - } - - /// Given the did of an ADT, return a master reference to its - /// definition. Unless you are planning on fulfilling the ADT's fields, - /// use lookup_adt_def instead. - pub fn lookup_adt_def_master(&self, did: DefId) -> AdtDefMaster<'tcx> { - lookup_locally_or_in_crate_store( - "adt_defs", did, &self.adt_defs, - || csearch::get_adt_def(self, did) - ) - } - - /// Given the did of an ADT, return a reference to its definition. - pub fn lookup_adt_def(&self, did: DefId) -> AdtDef<'tcx> { - // when reverse-variance goes away, a transmute:: - // woud be needed here. - self.lookup_adt_def_master(did) - } - - /// Return the list of all interned ADT definitions - pub fn adt_defs(&self) -> Vec> { - self.adt_defs.borrow().values().cloned().collect() - } - - /// Given the did of an item, returns its full set of predicates. - pub fn lookup_predicates(&self, did: DefId) -> GenericPredicates<'tcx> { - lookup_locally_or_in_crate_store( - "predicates", did, &self.predicates, - || csearch::get_predicates(self, did)) - } - - /// Given the did of a trait, returns its superpredicates. - pub fn lookup_super_predicates(&self, did: DefId) -> GenericPredicates<'tcx> { - lookup_locally_or_in_crate_store( - "super_predicates", did, &self.super_predicates, - || csearch::get_super_predicates(self, did)) - } - - /// Get the attributes of a definition. - pub fn get_attrs(&self, did: DefId) -> Cow<'tcx, [hir::Attribute]> { - if did.is_local() { - Cow::Borrowed(self.map.attrs(did.node)) - } else { - Cow::Owned(csearch::get_item_attrs(&self.sess.cstore, did)) - } - } - - /// Determine whether an item is annotated with an attribute - pub fn has_attr(&self, did: DefId, attr: &str) -> bool { - self.get_attrs(did).iter().any(|item| item.check_name(attr)) - } - - /// Determine whether an item is annotated with `#[repr(packed)]` - pub fn lookup_packed(&self, did: DefId) -> bool { - self.lookup_repr_hints(did).contains(&attr::ReprPacked) - } - - /// Determine whether an item is annotated with `#[simd]` - pub fn lookup_simd(&self, did: DefId) -> bool { - self.has_attr(did, "simd") - || self.lookup_repr_hints(did).contains(&attr::ReprSimd) - } - - /// Obtain the representation annotation for a struct definition. - pub fn lookup_repr_hints(&self, did: DefId) -> Rc> { - memoized(&self.repr_hint_cache, did, |did: DefId| { - Rc::new(if did.is_local() { - self.get_attrs(did).iter().flat_map(|meta| { - attr::find_repr_attrs(self.sess.diagnostic(), meta).into_iter() - }).collect() - } else { - csearch::get_repr_attrs(&self.sess.cstore, did) - }) - }) - } - - - /// 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, - || Rc::new(csearch::get_item_variances(&self.sess.cstore, item_id))) - } - - pub fn trait_has_default_impl(&self, trait_def_id: DefId) -> bool { - self.populate_implementations_for_trait_if_necessary(trait_def_id); - - let def = self.lookup_trait_def(trait_def_id); - def.flags.get().intersects(TraitFlags::HAS_DEFAULT_IMPL) - } - - /// Records a trait-to-implementation mapping. - pub fn record_trait_has_default_impl(&self, trait_def_id: DefId) { - let def = self.lookup_trait_def(trait_def_id); - def.flags.set(def.flags.get() | TraitFlags::HAS_DEFAULT_IMPL) - } - - /// Load primitive inherent implementations if necessary - pub fn populate_implementations_for_primitive_if_necessary(&self, - primitive_def_id: DefId) { - if primitive_def_id.is_local() { - return - } - - if self.populated_external_primitive_impls.borrow().contains(&primitive_def_id) { - return - } - - debug!("populate_implementations_for_primitive_if_necessary: searching for {:?}", - primitive_def_id); - - let impl_items = csearch::get_impl_items(&self.sess.cstore, primitive_def_id); - - // Store the implementation info. - self.impl_items.borrow_mut().insert(primitive_def_id, impl_items); - self.populated_external_primitive_impls.borrow_mut().insert(primitive_def_id); - } - - /// Populates the type context with all the inherent implementations for - /// the given type if necessary. - pub fn populate_inherent_implementations_for_type_if_necessary(&self, - type_id: DefId) { - if type_id.is_local() { - return - } - - if self.populated_external_types.borrow().contains(&type_id) { - return - } - - debug!("populate_inherent_implementations_for_type_if_necessary: searching for {:?}", - type_id); - - let mut inherent_impls = Vec::new(); - csearch::each_inherent_implementation_for_type(&self.sess.cstore, type_id, |impl_def_id| { - // Record the implementation. - inherent_impls.push(impl_def_id); - - // Store the implementation info. - let impl_items = csearch::get_impl_items(&self.sess.cstore, impl_def_id); - self.impl_items.borrow_mut().insert(impl_def_id, impl_items); - }); - - self.inherent_impls.borrow_mut().insert(type_id, Rc::new(inherent_impls)); - self.populated_external_types.borrow_mut().insert(type_id); - } - - /// Populates the type context with all the implementations for the given - /// trait if necessary. - pub fn populate_implementations_for_trait_if_necessary(&self, trait_id: DefId) { - if trait_id.is_local() { - return - } - - let def = self.lookup_trait_def(trait_id); - if def.flags.get().intersects(TraitFlags::IMPLS_VALID) { - return; - } - - debug!("populate_implementations_for_trait_if_necessary: searching for {:?}", def); - - if csearch::is_defaulted_trait(&self.sess.cstore, trait_id) { - self.record_trait_has_default_impl(trait_id); - } - - csearch::each_implementation_for_trait(&self.sess.cstore, trait_id, |impl_def_id| { - let impl_items = csearch::get_impl_items(&self.sess.cstore, impl_def_id); - let trait_ref = self.impl_trait_ref(impl_def_id).unwrap(); - // Record the trait->implementation mapping. - def.record_impl(self, impl_def_id, trait_ref); - - // For any methods that use a default implementation, add them to - // the map. This is a bit unfortunate. - for impl_item_def_id in &impl_items { - let method_def_id = impl_item_def_id.def_id(); - match self.impl_or_trait_item(method_def_id) { - MethodTraitItem(method) => { - if let Some(source) = method.provided_source { - self.provided_method_sources - .borrow_mut() - .insert(method_def_id, source); - } - } - _ => {} - } - } - - // Store the implementation info. - self.impl_items.borrow_mut().insert(impl_def_id, impl_items); - }); - - def.flags.set(def.flags.get() | TraitFlags::IMPLS_VALID); - } - - /// Given the def_id of an impl, return the def_id of the trait it implements. - /// If it implements no trait, return `None`. - pub fn trait_id_of_impl(&self, def_id: DefId) -> Option { - self.impl_trait_ref(def_id).map(|tr| tr.def_id) - } - - /// If the given def ID describes a method belonging to an impl, return the - /// ID of the impl that the method belongs to. Otherwise, return `None`. - pub fn impl_of_method(&self, def_id: DefId) -> Option { - if def_id.krate != LOCAL_CRATE { - return match csearch::get_impl_or_trait_item(self, - def_id).container() { - TraitContainer(_) => None, - ImplContainer(def_id) => Some(def_id), - }; - } - match self.impl_or_trait_items.borrow().get(&def_id).cloned() { - Some(trait_item) => { - match trait_item.container() { - TraitContainer(_) => None, - ImplContainer(def_id) => Some(def_id), - } - } - None => None - } - } - - /// If the given def ID describes an item belonging to a trait (either a - /// default method or an implementation of a trait method), return the ID of - /// the trait that the method belongs to. Otherwise, return `None`. - pub fn trait_of_item(&self, def_id: DefId) -> Option { - if def_id.krate != LOCAL_CRATE { - return csearch::get_trait_of_item(&self.sess.cstore, def_id, self); - } - match self.impl_or_trait_items.borrow().get(&def_id).cloned() { - Some(impl_or_trait_item) => { - match impl_or_trait_item.container() { - TraitContainer(def_id) => Some(def_id), - ImplContainer(def_id) => self.trait_id_of_impl(def_id), - } - } - None => None - } - } - - /// If the given def ID describes an item belonging to a trait, (either a - /// default method or an implementation of a trait method), return the ID of - /// the method inside trait definition (this means that if the given def ID - /// is already that of the original trait method, then the return value is - /// the same). - /// Otherwise, return `None`. - pub fn trait_item_of_item(&self, def_id: DefId) -> Option { - let impl_item = match self.impl_or_trait_items.borrow().get(&def_id) { - Some(m) => m.clone(), - None => return None, - }; - let name = impl_item.name(); - match self.trait_of_item(def_id) { - Some(trait_did) => { - self.trait_items(trait_did).iter() - .find(|item| item.name() == name) - .map(|item| item.id()) - } - None => None - } - } - - /// 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) - -> ParameterEnvironment<'a,'tcx> { - ty::ParameterEnvironment { tcx: self, - free_substs: Substs::empty(), - caller_bounds: Vec::new(), - implicit_region_bound: ty::ReEmpty, - selection_cache: traits::SelectionCache::new(), - - // for an empty parameter - // environment, there ARE no free - // regions, so it shouldn't matter - // what we use for the free id - free_id: ast::DUMMY_NODE_ID } - } - - /// Constructs and returns a substitution that can be applied to move from - /// the "outer" view of a type or method to the "inner" view. - /// In general, this means converting from bound parameters to - /// free parameters. Since we currently represent bound/free type - /// parameters in the same way, this only has an effect on regions. - pub fn construct_free_substs(&self, generics: &Generics<'tcx>, - free_id: NodeId) -> Substs<'tcx> { - // map T => T - let mut types = VecPerParamSpace::empty(); - for def in generics.types.as_slice() { - debug!("construct_parameter_environment(): push_types_from_defs: def={:?}", - def); - types.push(def.space, self.mk_param_from_def(def)); - } - - let free_id_outlive = self.region_maps.item_extent(free_id); - - // map bound 'a => free 'a - let mut regions = VecPerParamSpace::empty(); - for def in generics.regions.as_slice() { - let region = - ReFree(FreeRegion { scope: free_id_outlive, - bound_region: BrNamed(def.def_id, def.name) }); - debug!("push_region_params {:?}", region); - regions.push(def.space, region); - } - - Substs { - types: types, - regions: subst::NonerasedRegions(regions) - } - } - - /// See `ParameterEnvironment` struct def'n for details - pub fn construct_parameter_environment<'a>(&'a self, - span: Span, - generics: &ty::Generics<'tcx>, - generic_predicates: &ty::GenericPredicates<'tcx>, - free_id: NodeId) - -> ParameterEnvironment<'a, 'tcx> - { - // - // Construct the free substs. - // - - let free_substs = self.construct_free_substs(generics, free_id); - let free_id_outlive = self.region_maps.item_extent(free_id); - - // - // Compute the bounds on Self and the type parameters. - // - - let bounds = generic_predicates.instantiate(self, &free_substs); - let bounds = self.liberate_late_bound_regions(free_id_outlive, &ty::Binder(bounds)); - let predicates = bounds.predicates.into_vec(); - - debug!("construct_parameter_environment: free_id={:?} free_subst={:?} predicates={:?}", - free_id, - free_substs, - predicates); - - // - // Finally, we have to normalize the bounds in the environment, in - // case they contain any associated type projections. This process - // can yield errors if the put in illegal associated types, like - // `::Bar` where `i32` does not implement `Foo`. We - // report these errors right here; this doesn't actually feel - // right to me, because constructing the environment feels like a - // kind of a "idempotent" action, but I'm not sure where would be - // a better place. In practice, we construct environments for - // every fn once during type checking, and we'll abort if there - // are any errors at that point, so after type checking you can be - // sure that this will succeed without errors anyway. - // - - let unnormalized_env = ty::ParameterEnvironment { - tcx: self, - free_substs: free_substs, - implicit_region_bound: ty::ReScope(free_id_outlive), - caller_bounds: predicates, - selection_cache: traits::SelectionCache::new(), - free_id: free_id, - }; - - let cause = traits::ObligationCause::misc(span, free_id); - traits::normalize_param_env_or_error(unnormalized_env, cause) - } - - pub fn is_method_call(&self, expr_id: NodeId) -> bool { - self.tables.borrow().method_map.contains_key(&MethodCall::expr(expr_id)) - } - - pub fn is_overloaded_autoderef(&self, expr_id: NodeId, autoderefs: u32) -> bool { - self.tables.borrow().method_map.contains_key(&MethodCall::autoderef(expr_id, - autoderefs)) - } - - 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. -#[derive(Clone, Copy, Eq, PartialEq, Debug)] -pub enum ExplicitSelfCategory { - StaticExplicitSelfCategory, - ByValueExplicitSelfCategory, - ByReferenceExplicitSelfCategory(Region, hir::Mutability), - ByBoxExplicitSelfCategory, -} - -/// A free variable referred to in a function. -#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] -pub struct Freevar { - /// The variable being accessed free. - pub def: def::Def, - - // First span where it is accessed (there can be multiple). - pub span: Span -} - -pub type FreevarMap = NodeMap>; - -pub type CaptureModeMap = NodeMap; - -// Trait method resolution -pub type TraitMap = NodeMap>; - -// Map from the NodeId of a glob import to a list of items which are actually -// 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, - { - match self.freevars.borrow().get(&fid) { - None => f(&[]), - Some(d) => f(&d[..]) - } - } - - /// 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> - { - ty_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 = ty_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> - { - ty_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(ty_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>) - -> subst::Substs<'tcx> - { - /*! - * Substitutes the values for the receiver's type parameters - * that are found in method, leaving the method's type parameters - * intact. - */ - - let meth_tps: Vec = - method.generics.types.get_slice(subst::FnSpace) - .iter() - .map(|def| self.mk_param_from_def(def)) - .collect(); - let meth_regions: Vec = - method.generics.regions.get_slice(subst::FnSpace) - .iter() - .map(|def| def.to_early_bound_region()) - .collect(); - trait_ref.substs.clone().with_method(meth_tps, meth_regions) - } -} - -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: -/// -/// for<'a> fn(x: for<'b> fn(&'a isize, &'b isize)) -/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope -/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ inner scope -/// -/// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the -/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner -/// fn type*, that type has an escaping region: `'a`. -/// -/// Note that what I'm calling an "escaping region" is often just called a "free region". However, -/// we already use the term "free region". It refers to the regions that we use to represent bound -/// regions on a fn definition while we are typechecking its body. -/// -/// To clarify, conceptually there is no particular difference between an "escaping" region and a -/// "free" region. However, there is a big difference in practice. Basically, when "entering" a -/// binding level, one is generally required to do some sort of processing to a bound region, such -/// as replacing it with a fresh/skolemized region, or making an entry in the environment to -/// represent the scope to which it is attached, etc. An escaping region represents a bound region -/// for which this processing has not yet been done. -pub trait RegionEscape { - fn has_escaping_regions(&self) -> bool { - self.has_regions_escaping_depth(0) - } - - 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 { - self.has_type_flags(TypeFlags::HAS_PROJECTION) - } - fn references_error(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_ERR) - } - fn has_param_types(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_PARAMS) - } - fn has_self_ty(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_SELF) - } - fn has_infer_types(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_INFER) - } - fn needs_infer(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER) - } - fn needs_subst(&self) -> bool { - self.has_type_flags(TypeFlags::NEEDS_SUBST) - } - fn has_closure_types(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_CLOSURE) - } - fn has_erasable_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_RE_EARLY_BOUND | - TypeFlags::HAS_RE_INFER | - TypeFlags::HAS_FREE_REGIONS) - } - /// Indicates whether this value references only 'global' - /// types/lifetimes that are the same regardless of what fn we are - /// in. This is used for caching. Errs on the side of returning - /// false. - fn is_global(&self) -> bool { - !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_match.rs b/src/librustc/middle/ty/_match.rs similarity index 93% rename from src/librustc/middle/ty_match.rs rename to src/librustc/middle/ty/_match.rs index 4aa0e553a7aa6..5a3ad9095ad2c 100644 --- a/src/librustc/middle/ty_match.rs +++ b/src/librustc/middle/ty/_match.rs @@ -9,7 +9,8 @@ // except according to those terms. use middle::ty::{self, Ty}; -use middle::ty_relate::{self, Relate, TypeRelation, RelateResult}; +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 /// substituted with values so as to make it equal to A. Matching is @@ -73,7 +74,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(TypeError::Sorts(relate::expected_found(self, &a, &b))) } (&ty::TyError, _) | (_, &ty::TyError) => { @@ -81,7 +82,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/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/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/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..e3b6da56680da --- /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/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/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 similarity index 51% rename from src/librustc/middle/ty_fold.rs rename to src/librustc/middle/ty/fold.rs index c6d213583af20..751bac28ce4c2 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty/fold.rs @@ -34,16 +34,12 @@ //! 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::adjustment; +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 +70,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`. @@ -133,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) } @@ -142,428 +139,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 } @@ -711,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) } } @@ -754,6 +341,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 +402,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 +443,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 +544,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 new file mode 100644 index 0000000000000..dff423b35dd0a --- /dev/null +++ b/src/librustc/middle/ty/mod.rs @@ -0,0 +1,2828 @@ +// 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::ImplOrTraitItemId::*; +pub use self::ClosureKind::*; +pub use self::Variance::*; +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::LvaluePreference::*; + +use front::map as ast_map; +use front::map::LinkedPath; +use metadata::csearch; +use middle; +use middle::def::{self, ExportMap}; +use middle::def_id::{DefId, LOCAL_CRATE}; +use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; +use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace}; +use middle::traits; +use middle::ty; +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 std::borrow::{Borrow, Cow}; +use std::cell::{Cell, RefCell}; +use std::hash::{Hash, Hasher}; +use std::iter; +use std::rc::Rc; +use std::slice; +use std::vec::IntoIter; +use std::collections::{HashMap, HashSet}; +use syntax::ast::{self, CrateNum, Name, NodeId}; +use syntax::codemap::Span; +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}; + +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 adjustment; +pub mod cast; +pub mod error; +pub mod fast_reject; +pub mod fold; +pub mod _match; +pub mod outlives; +pub mod relate; +pub mod walk; +pub mod wf; +pub mod util; + +mod contents; +mod context; +mod flags; +mod ivar; +mod structural_impls; +mod sty; + +pub type Disr = u64; +pub const INITIAL_DISCRIMINANT_VALUE: Disr = 0; + +// Data types + +/// The complete set of all analyses described in this module. This is +/// produced by the driver and fed to trans and later passes. +pub struct CrateAnalysis { + pub export_map: ExportMap, + pub exported_items: middle::privacy::ExportedItems, + pub public_items: middle::privacy::PublicItems, + pub reachable: NodeSet, + pub name: String, + pub glob_map: Option, +} + + +#[derive(Copy, Clone)] +pub enum DtorKind { + NoDtor, + TraitDtor(bool) +} + +impl DtorKind { + pub fn is_present(&self) -> bool { + match *self { + TraitDtor(..) => true, + _ => false + } + } + + pub fn has_drop_flag(&self) -> bool { + match self { + &NoDtor => false, + &TraitDtor(flag) => flag + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum ImplOrTraitItemContainer { + TraitContainer(DefId), + ImplContainer(DefId), +} + +impl ImplOrTraitItemContainer { + pub fn id(&self) -> DefId { + match *self { + TraitContainer(id) => id, + ImplContainer(id) => id, + } + } +} + +#[derive(Clone)] +pub enum ImplOrTraitItem<'tcx> { + ConstTraitItem(Rc>), + MethodTraitItem(Rc>), + TypeTraitItem(Rc>), +} + +impl<'tcx> ImplOrTraitItem<'tcx> { + fn id(&self) -> ImplOrTraitItemId { + match *self { + ConstTraitItem(ref associated_const) => { + ConstTraitItemId(associated_const.def_id) + } + MethodTraitItem(ref method) => MethodTraitItemId(method.def_id), + TypeTraitItem(ref associated_type) => { + TypeTraitItemId(associated_type.def_id) + } + } + } + + pub fn def_id(&self) -> DefId { + match *self { + ConstTraitItem(ref associated_const) => associated_const.def_id, + MethodTraitItem(ref method) => method.def_id, + TypeTraitItem(ref associated_type) => associated_type.def_id, + } + } + + pub fn name(&self) -> Name { + match *self { + ConstTraitItem(ref associated_const) => associated_const.name, + MethodTraitItem(ref method) => method.name, + TypeTraitItem(ref associated_type) => associated_type.name, + } + } + + pub fn vis(&self) -> hir::Visibility { + match *self { + ConstTraitItem(ref associated_const) => associated_const.vis, + MethodTraitItem(ref method) => method.vis, + TypeTraitItem(ref associated_type) => associated_type.vis, + } + } + + pub fn container(&self) -> ImplOrTraitItemContainer { + match *self { + ConstTraitItem(ref associated_const) => associated_const.container, + MethodTraitItem(ref method) => method.container, + TypeTraitItem(ref associated_type) => associated_type.container, + } + } + + pub fn as_opt_method(&self) -> Option>> { + match *self { + MethodTraitItem(ref m) => Some((*m).clone()), + _ => None, + } + } +} + +#[derive(Clone, Copy, Debug)] +pub enum ImplOrTraitItemId { + ConstTraitItemId(DefId), + MethodTraitItemId(DefId), + TypeTraitItemId(DefId), +} + +impl ImplOrTraitItemId { + pub fn def_id(&self) -> DefId { + match *self { + ConstTraitItemId(def_id) => def_id, + MethodTraitItemId(def_id) => def_id, + TypeTraitItemId(def_id) => def_id, + } + } +} + +#[derive(Clone, Debug)] +pub struct Method<'tcx> { + pub name: Name, + pub generics: Generics<'tcx>, + pub predicates: GenericPredicates<'tcx>, + pub fty: BareFnTy<'tcx>, + pub explicit_self: ExplicitSelfCategory, + pub vis: hir::Visibility, + pub def_id: DefId, + pub container: ImplOrTraitItemContainer, + + // If this method is provided, we need to know where it came from + pub provided_source: Option +} + +impl<'tcx> Method<'tcx> { + pub fn new(name: Name, + generics: ty::Generics<'tcx>, + predicates: GenericPredicates<'tcx>, + fty: BareFnTy<'tcx>, + explicit_self: ExplicitSelfCategory, + vis: hir::Visibility, + def_id: DefId, + container: ImplOrTraitItemContainer, + provided_source: Option) + -> Method<'tcx> { + Method { + name: name, + generics: generics, + predicates: predicates, + fty: fty, + explicit_self: explicit_self, + vis: vis, + def_id: def_id, + container: container, + provided_source: provided_source + } + } + + pub fn container_id(&self) -> DefId { + match self.container { + TraitContainer(id) => id, + ImplContainer(id) => id, + } + } +} + +#[derive(Clone, Copy, Debug)] +pub struct AssociatedConst<'tcx> { + pub name: Name, + pub ty: Ty<'tcx>, + pub vis: hir::Visibility, + pub def_id: DefId, + pub container: ImplOrTraitItemContainer, + pub default: Option, +} + +#[derive(Clone, Copy, Debug)] +pub struct AssociatedType<'tcx> { + pub name: Name, + pub ty: Option>, + pub vis: hir::Visibility, + pub def_id: DefId, + pub container: ImplOrTraitItemContainer, +} + +#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)] +pub struct ItemVariances { + pub types: VecPerParamSpace, + pub regions: VecPerParamSpace, +} + +#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Copy)] +pub enum Variance { + Covariant, // T <: T iff A <: B -- e.g., function return type + Invariant, // T <: T iff B == A -- e.g., type of mutable cell + Contravariant, // T <: T iff B <: A -- e.g., function param type + Bivariant, // T <: T -- e.g., unused type parameter +} + +#[derive(Clone, Copy, Debug)] +pub struct MethodCallee<'tcx> { + /// Impl method ID, for inherent methods, or trait method ID, otherwise. + pub def_id: DefId, + pub ty: Ty<'tcx>, + pub substs: &'tcx subst::Substs<'tcx> +} + +/// With method calls, we store some extra information in +/// side tables (i.e method_map). We use +/// MethodCall as a key to index into these tables instead of +/// just directly using the expression's NodeId. The reason +/// for this being that we may apply adjustments (coercions) +/// with the resulting expression also needing to use the +/// side tables. The problem with this is that we don't +/// assign a separate NodeId to this new expression +/// and so it would clash with the base expression if both +/// needed to add to the side tables. Thus to disambiguate +/// we also keep track of whether there's an adjustment in +/// our key. +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub struct MethodCall { + pub expr_id: NodeId, + pub autoderef: u32 +} + +impl MethodCall { + pub fn expr(id: NodeId) -> MethodCall { + MethodCall { + expr_id: id, + autoderef: 0 + } + } + + pub fn autoderef(expr_id: NodeId, autoderef: u32) -> MethodCall { + MethodCall { + expr_id: expr_id, + autoderef: 1 + autoderef + } + } +} + +// maps from an expression id that corresponds to a method call to the details +// of the method to be invoked +pub type MethodMap<'tcx> = FnvHashMap>; + +// Contains information needed to resolve types and (in the future) look up +// the types of AST nodes. +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct CReaderCacheKey { + pub cnum: CrateNum, + pub pos: usize, + pub len: usize +} + +/// A restriction that certain types must be the same size. The use of +/// `transmute` gives rise to these restrictions. These generally +/// cannot be checked until trans; therefore, each call to `transmute` +/// will push one or more such restriction into the +/// `transmute_restrictions` vector during `intrinsicck`. They are +/// then checked during `trans` by the fn `check_intrinsics`. +#[derive(Copy, Clone)] +pub struct TransmuteRestriction<'tcx> { + /// The span whence the restriction comes. + pub span: Span, + + /// The type being transmuted from. + pub original_from: Ty<'tcx>, + + /// The type being transmuted to. + pub original_to: Ty<'tcx>, + + /// The type being transmuted from, with all type parameters + /// substituted for an arbitrary representative. Not to be shown + /// to the end user. + pub substituted_from: Ty<'tcx>, + + /// The type being transmuted to, with all type parameters + /// substituted for an arbitrary representative. Not to be shown + /// to the end user. + pub substituted_to: Ty<'tcx>, + + /// NodeId of the transmute intrinsic. + pub id: NodeId, +} + +/// Describes the fragment-state associated with a NodeId. +/// +/// Currently only unfragmented paths have entries in the table, +/// but longer-term this enum is expected to expand to also +/// include data for fragmented paths. +#[derive(Copy, Clone, Debug)] +pub enum FragmentInfo { + Moved { var: NodeId, move_expr: NodeId }, + Assigned { var: NodeId, assign_expr: NodeId, assignee_id: NodeId }, +} + +// 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 +// recursing over the type itself. +bitflags! { + flags TypeFlags: u32 { + const HAS_PARAMS = 1 << 0, + const HAS_SELF = 1 << 1, + const HAS_TY_INFER = 1 << 2, + const HAS_RE_INFER = 1 << 3, + const HAS_RE_EARLY_BOUND = 1 << 4, + const HAS_FREE_REGIONS = 1 << 5, + const HAS_TY_ERR = 1 << 6, + const HAS_PROJECTION = 1 << 7, + const HAS_TY_CLOSURE = 1 << 8, + + // true if there are "names" of types and regions and so forth + // that are local to a particular fn + const HAS_LOCAL_NAMES = 1 << 9, + + const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits | + TypeFlags::HAS_SELF.bits | + TypeFlags::HAS_RE_EARLY_BOUND.bits, + + // Flags representing the nominal content of a type, + // computed by FlagsComputation. If you add a new nominal + // flag, it should be added here too. + const NOMINAL_FLAGS = TypeFlags::HAS_PARAMS.bits | + TypeFlags::HAS_SELF.bits | + TypeFlags::HAS_TY_INFER.bits | + TypeFlags::HAS_RE_INFER.bits | + TypeFlags::HAS_RE_EARLY_BOUND.bits | + TypeFlags::HAS_FREE_REGIONS.bits | + TypeFlags::HAS_TY_ERR.bits | + TypeFlags::HAS_PROJECTION.bits | + TypeFlags::HAS_TY_CLOSURE.bits | + TypeFlags::HAS_LOCAL_NAMES.bits, + + // Caches for type_is_sized, type_moves_by_default + const SIZEDNESS_CACHED = 1 << 16, + const IS_SIZED = 1 << 17, + const MOVENESS_CACHED = 1 << 18, + const MOVES_BY_DEFAULT = 1 << 19, + } +} + +pub struct TyS<'tcx> { + pub sty: TypeVariants<'tcx>, + pub flags: Cell, + + // the maximal depth of any bound regions appearing in this type. + region_depth: u32, +} + +impl<'tcx> PartialEq for TyS<'tcx> { + #[inline] + fn eq(&self, other: &TyS<'tcx>) -> bool { + // (self as *const _) == (other as *const _) + (self as *const TyS<'tcx>) == (other as *const TyS<'tcx>) + } +} +impl<'tcx> Eq for TyS<'tcx> {} + +impl<'tcx> Hash for TyS<'tcx> { + fn hash(&self, s: &mut H) { + (self as *const TyS).hash(s) + } +} + +pub type Ty<'tcx> = &'tcx TyS<'tcx>; + +/// 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. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct UpvarId { + pub var_id: NodeId, + pub closure_expr_id: NodeId, +} + +#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable, Copy)] +pub enum BorrowKind { + /// Data must be immutable and is aliasable. + ImmBorrow, + + /// Data must be immutable but not aliasable. This kind of borrow + /// cannot currently be expressed by the user and is used only in + /// implicit closure bindings. It is needed when you the closure + /// is borrowing or mutating a mutable referent, e.g.: + /// + /// let x: &mut isize = ...; + /// let y = || *x += 5; + /// + /// If we were to try to translate this closure into a more explicit + /// form, we'd encounter an error with the code as written: + /// + /// struct Env { x: & &mut isize } + /// let x: &mut isize = ...; + /// let y = (&mut Env { &x }, fn_ptr); // Closure is pair of env and fn + /// fn fn_ptr(env: &mut Env) { **env.x += 5; } + /// + /// This is then illegal because you cannot mutate a `&mut` found + /// in an aliasable location. To solve, you'd have to translate with + /// an `&mut` borrow: + /// + /// struct Env { x: & &mut isize } + /// let x: &mut isize = ...; + /// let y = (&mut Env { &mut x }, fn_ptr); // changed from &x to &mut x + /// fn fn_ptr(env: &mut Env) { **env.x += 5; } + /// + /// Now the assignment to `**env.x` is legal, but creating a + /// mutable pointer to `x` is not because `x` is not mutable. We + /// could fix this by declaring `x` as `let mut x`. This is ok in + /// user code, if awkward, but extra weird for closures, since the + /// borrow is hidden. + /// + /// So we introduce a "unique imm" borrow -- the referent is + /// immutable, but not aliasable. This solves the problem. For + /// simplicity, we don't give users the way to express this + /// borrow, it's just used when translating closures. + UniqueImmBorrow, + + /// Data is mutable and not aliasable. + MutBorrow +} + +/// Information describing the capture of an upvar. This is computed +/// during `typeck`, specifically by `regionck`. +#[derive(PartialEq, Clone, Debug, Copy)] +pub enum UpvarCapture { + /// Upvar is captured by value. This is always true when the + /// closure is labeled `move`, but can also be true in other cases + /// depending on inference. + ByValue, + + /// Upvar is captured by reference. + ByRef(UpvarBorrow), +} + +#[derive(PartialEq, Clone, Copy)] +pub struct UpvarBorrow { + /// The kind of borrow: by-ref upvars have access to shared + /// immutable borrows, which are not part of the normal language + /// syntax. + pub kind: BorrowKind, + + /// Region of the resulting reference. + pub region: ty::Region, +} + +pub type UpvarCaptureMap = FnvHashMap; + +#[derive(Copy, Clone)] +pub struct ClosureUpvar<'tcx> { + pub def: def::Def, + pub span: Span, + pub ty: Ty<'tcx>, +} + +#[derive(Clone, Copy, PartialEq)] +pub enum IntVarValue { + IntType(hir::IntTy), + UintType(hir::UintTy), +} + +/// 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 +/// this is `None`, then the default is inherited from the +/// surrounding context. See RFC #599 for details. +#[derive(Copy, Clone)] +pub enum ObjectLifetimeDefault { + /// Require an explicit annotation. Occurs when multiple + /// `T:'a` constraints are found. + Ambiguous, + + /// Use the base default, typically 'static, but in a fn body it is a fresh variable + BaseDefault, + + /// Use the given region as the default. + Specific(Region), +} + +#[derive(Clone)] +pub struct TypeParameterDef<'tcx> { + pub name: Name, + pub def_id: DefId, + pub space: subst::ParamSpace, + pub index: u32, + pub default_def_id: DefId, // for use in error reporing about defaults + pub default: Option>, + pub object_lifetime_default: ObjectLifetimeDefault, +} + +#[derive(Clone)] +pub struct RegionParameterDef { + pub name: Name, + pub def_id: DefId, + pub space: subst::ParamSpace, + pub index: u32, + pub bounds: Vec, +} + +impl RegionParameterDef { + pub fn to_early_bound_region(&self) -> ty::Region { + ty::ReEarlyBound(ty::EarlyBoundRegion { + param_id: self.def_id.node, + space: self.space, + index: self.index, + name: self.name, + }) + } + pub fn to_bound_region(&self) -> ty::BoundRegion { + ty::BoundRegion::BrNamed(self.def_id, self.name) + } +} + +/// Information about the formal type/lifetime parameters associated +/// with an item or method. Analogous to hir::Generics. +#[derive(Clone, Debug)] +pub struct Generics<'tcx> { + pub types: VecPerParamSpace>, + pub regions: VecPerParamSpace, +} + +impl<'tcx> Generics<'tcx> { + pub fn empty() -> Generics<'tcx> { + Generics { + types: VecPerParamSpace::empty(), + regions: VecPerParamSpace::empty(), + } + } + + pub fn is_empty(&self) -> bool { + self.types.is_empty() && self.regions.is_empty() + } + + pub fn has_type_params(&self, space: subst::ParamSpace) -> bool { + !self.types.is_empty_in(space) + } + + pub fn has_region_params(&self, space: subst::ParamSpace) -> bool { + !self.regions.is_empty_in(space) + } +} + +/// Bounds on generics. +#[derive(Clone)] +pub struct GenericPredicates<'tcx> { + pub predicates: VecPerParamSpace>, +} + +impl<'tcx> GenericPredicates<'tcx> { + pub fn empty() -> GenericPredicates<'tcx> { + GenericPredicates { + predicates: VecPerParamSpace::empty(), + } + } + + pub fn instantiate(&self, tcx: &ctxt<'tcx>, substs: &Substs<'tcx>) + -> InstantiatedPredicates<'tcx> { + InstantiatedPredicates { + predicates: self.predicates.subst(tcx, substs), + } + } + + pub fn instantiate_supertrait(&self, + tcx: &ctxt<'tcx>, + poly_trait_ref: &ty::PolyTraitRef<'tcx>) + -> InstantiatedPredicates<'tcx> + { + InstantiatedPredicates { + predicates: self.predicates.map(|pred| pred.subst_supertrait(tcx, poly_trait_ref)) + } + } +} + +#[derive(Clone, PartialEq, Eq, Hash)] +pub enum Predicate<'tcx> { + /// Corresponds to `where Foo : Bar`. `Foo` here would be + /// the `Self` type of the trait reference and `A`, `B`, and `C` + /// would be the parameters in the `TypeSpace`. + Trait(PolyTraitPredicate<'tcx>), + + /// where `T1 == T2`. + Equate(PolyEquatePredicate<'tcx>), + + /// where 'a : 'b + RegionOutlives(PolyRegionOutlivesPredicate), + + /// where T : 'a + TypeOutlives(PolyTypeOutlivesPredicate<'tcx>), + + /// where ::Name == X, approximately. + /// See `ProjectionPredicate` struct for details. + Projection(PolyProjectionPredicate<'tcx>), + + /// no syntax: T WF + WellFormed(Ty<'tcx>), + + /// trait must be object-safe + ObjectSafe(DefId), +} + +impl<'tcx> Predicate<'tcx> { + /// Performs a substitution suitable for going from a + /// poly-trait-ref to supertraits that must hold if that + /// poly-trait-ref holds. This is slightly different from a normal + /// substitution in terms of what happens with bound regions. See + /// lengthy comment below for details. + pub fn subst_supertrait(&self, + tcx: &ctxt<'tcx>, + trait_ref: &ty::PolyTraitRef<'tcx>) + -> ty::Predicate<'tcx> + { + // The interaction between HRTB and supertraits is not entirely + // obvious. Let me walk you (and myself) through an example. + // + // Let's start with an easy case. Consider two traits: + // + // trait Foo<'a> : Bar<'a,'a> { } + // trait Bar<'b,'c> { } + // + // Now, if we have a trait reference `for<'x> T : Foo<'x>`, then + // we can deduce that `for<'x> T : Bar<'x,'x>`. Basically, if we + // knew that `Foo<'x>` (for any 'x) then we also know that + // `Bar<'x,'x>` (for any 'x). This more-or-less falls out from + // normal substitution. + // + // In terms of why this is sound, the idea is that whenever there + // is an impl of `T:Foo<'a>`, it must show that `T:Bar<'a,'a>` + // holds. So if there is an impl of `T:Foo<'a>` that applies to + // all `'a`, then we must know that `T:Bar<'a,'a>` holds for all + // `'a`. + // + // Another example to be careful of is this: + // + // trait Foo1<'a> : for<'b> Bar1<'a,'b> { } + // trait Bar1<'b,'c> { } + // + // Here, if we have `for<'x> T : Foo1<'x>`, then what do we know? + // The answer is that we know `for<'x,'b> T : Bar1<'x,'b>`. The + // reason is similar to the previous example: any impl of + // `T:Foo1<'x>` must show that `for<'b> T : Bar1<'x, 'b>`. So + // basically we would want to collapse the bound lifetimes from + // the input (`trait_ref`) and the supertraits. + // + // To achieve this in practice is fairly straightforward. Let's + // consider the more complicated scenario: + // + // - We start out with `for<'x> T : Foo1<'x>`. In this case, `'x` + // has a De Bruijn index of 1. We want to produce `for<'x,'b> T : Bar1<'x,'b>`, + // where both `'x` and `'b` would have a DB index of 1. + // The substitution from the input trait-ref is therefore going to be + // `'a => 'x` (where `'x` has a DB index of 1). + // - The super-trait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an + // early-bound parameter and `'b' is a late-bound parameter with a + // DB index of 1. + // - If we replace `'a` with `'x` from the input, it too will have + // a DB index of 1, and thus we'll have `for<'x,'b> Bar1<'x,'b>` + // just as we wanted. + // + // There is only one catch. If we just apply the substitution `'a + // => 'x` to `for<'b> Bar1<'a,'b>`, the substitution code will + // adjust the DB index because we substituting into a binder (it + // tries to be so smart...) resulting in `for<'x> for<'b> + // Bar1<'x,'b>` (we have no syntax for this, so use your + // imagination). Basically the 'x will have DB index of 2 and 'b + // will have DB index of 1. Not quite what we want. So we apply + // the substitution to the *contents* of the trait reference, + // rather than the trait reference itself (put another way, the + // substitution code expects equal binding levels in the values + // from the substitution and the value being substituted into, and + // this trick achieves that). + + let substs = &trait_ref.0.substs; + match *self { + Predicate::Trait(ty::Binder(ref data)) => + Predicate::Trait(ty::Binder(data.subst(tcx, substs))), + Predicate::Equate(ty::Binder(ref data)) => + Predicate::Equate(ty::Binder(data.subst(tcx, substs))), + Predicate::RegionOutlives(ty::Binder(ref data)) => + Predicate::RegionOutlives(ty::Binder(data.subst(tcx, substs))), + Predicate::TypeOutlives(ty::Binder(ref data)) => + Predicate::TypeOutlives(ty::Binder(data.subst(tcx, substs))), + Predicate::Projection(ty::Binder(ref data)) => + Predicate::Projection(ty::Binder(data.subst(tcx, substs))), + Predicate::WellFormed(data) => + Predicate::WellFormed(data.subst(tcx, substs)), + Predicate::ObjectSafe(trait_def_id) => + Predicate::ObjectSafe(trait_def_id), + } + } +} + +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct TraitPredicate<'tcx> { + pub trait_ref: TraitRef<'tcx> +} +pub type PolyTraitPredicate<'tcx> = ty::Binder>; + +impl<'tcx> TraitPredicate<'tcx> { + pub fn def_id(&self) -> DefId { + self.trait_ref.def_id + } + + pub fn input_types(&self) -> &[Ty<'tcx>] { + self.trait_ref.substs.types.as_slice() + } + + pub fn self_ty(&self) -> Ty<'tcx> { + self.trait_ref.self_ty() + } +} + +impl<'tcx> PolyTraitPredicate<'tcx> { + pub fn def_id(&self) -> DefId { + self.0.def_id() + } +} + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct EquatePredicate<'tcx>(pub Ty<'tcx>, pub Ty<'tcx>); // `0 == 1` +pub type PolyEquatePredicate<'tcx> = ty::Binder>; + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct OutlivesPredicate(pub A, pub B); // `A : B` +pub type PolyOutlivesPredicate = ty::Binder>; +pub type PolyRegionOutlivesPredicate = PolyOutlivesPredicate; +pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate, ty::Region>; + +/// This kind of predicate has no *direct* correspondent in the +/// syntax, but it roughly corresponds to the syntactic forms: +/// +/// 1. `T : TraitRef<..., Item=Type>` +/// 2. `>::Item == Type` (NYI) +/// +/// In particular, form #1 is "desugared" to the combination of a +/// normal trait predicate (`T : TraitRef<...>`) and one of these +/// predicates. Form #2 is a broader form in that it also permits +/// equality between arbitrary types. Processing an instance of Form +/// #2 eventually yields one of these `ProjectionPredicate` +/// instances to normalize the LHS. +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct ProjectionPredicate<'tcx> { + pub projection_ty: ProjectionTy<'tcx>, + pub ty: Ty<'tcx>, +} + +pub type PolyProjectionPredicate<'tcx> = Binder>; + +impl<'tcx> PolyProjectionPredicate<'tcx> { + pub fn item_name(&self) -> Name { + self.0.projection_ty.item_name // safe to skip the binder to access a name + } + + pub fn sort_key(&self) -> (DefId, Name) { + self.0.projection_ty.sort_key() + } +} + +pub trait ToPolyTraitRef<'tcx> { + fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>; +} + +impl<'tcx> ToPolyTraitRef<'tcx> for TraitRef<'tcx> { + fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { + assert!(!self.has_escaping_regions()); + ty::Binder(self.clone()) + } +} + +impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> { + fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { + self.map_bound_ref(|trait_pred| trait_pred.trait_ref.clone()) + } +} + +impl<'tcx> ToPolyTraitRef<'tcx> for PolyProjectionPredicate<'tcx> { + fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { + // Note: unlike with TraitRef::to_poly_trait_ref(), + // self.0.trait_ref is permitted to have escaping regions. + // This is because here `self` has a `Binder` and so does our + // return value, so we are preserving the number of binding + // levels. + ty::Binder(self.0.projection_ty.trait_ref.clone()) + } +} + +pub trait ToPredicate<'tcx> { + fn to_predicate(&self) -> Predicate<'tcx>; +} + +impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { + fn to_predicate(&self) -> Predicate<'tcx> { + // we're about to add a binder, so let's check that we don't + // accidentally capture anything, or else that might be some + // weird debruijn accounting. + assert!(!self.has_escaping_regions()); + + ty::Predicate::Trait(ty::Binder(ty::TraitPredicate { + trait_ref: self.clone() + })) + } +} + +impl<'tcx> ToPredicate<'tcx> for PolyTraitRef<'tcx> { + fn to_predicate(&self) -> Predicate<'tcx> { + ty::Predicate::Trait(self.to_poly_trait_predicate()) + } +} + +impl<'tcx> ToPredicate<'tcx> for PolyEquatePredicate<'tcx> { + fn to_predicate(&self) -> Predicate<'tcx> { + Predicate::Equate(self.clone()) + } +} + +impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate { + fn to_predicate(&self) -> Predicate<'tcx> { + Predicate::RegionOutlives(self.clone()) + } +} + +impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { + fn to_predicate(&self) -> Predicate<'tcx> { + Predicate::TypeOutlives(self.clone()) + } +} + +impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { + fn to_predicate(&self) -> Predicate<'tcx> { + Predicate::Projection(self.clone()) + } +} + +impl<'tcx> Predicate<'tcx> { + /// Iterates over the types in this predicate. Note that in all + /// cases this is skipping over a binder, so late-bound regions + /// with depth 0 are bound by the predicate. + pub fn walk_tys(&self) -> IntoIter> { + let vec: Vec<_> = match *self { + ty::Predicate::Trait(ref data) => { + data.0.trait_ref.substs.types.as_slice().to_vec() + } + ty::Predicate::Equate(ty::Binder(ref data)) => { + vec![data.0, data.1] + } + ty::Predicate::TypeOutlives(ty::Binder(ref data)) => { + vec![data.0] + } + ty::Predicate::RegionOutlives(..) => { + vec![] + } + ty::Predicate::Projection(ref data) => { + let trait_inputs = data.0.projection_ty.trait_ref.substs.types.as_slice(); + trait_inputs.iter() + .cloned() + .chain(Some(data.0.ty)) + .collect() + } + ty::Predicate::WellFormed(data) => { + vec![data] + } + ty::Predicate::ObjectSafe(_trait_def_id) => { + vec![] + } + }; + + // The only reason to collect into a vector here is that I was + // too lazy to make the full (somewhat complicated) iterator + // type that would be needed here. But I wanted this fn to + // return an iterator conceptually, rather than a `Vec`, so as + // to be closer to `Ty::walk`. + vec.into_iter() + } + + pub fn has_escaping_regions(&self) -> bool { + match *self { + Predicate::Trait(ref trait_ref) => trait_ref.has_escaping_regions(), + Predicate::Equate(ref p) => p.has_escaping_regions(), + Predicate::RegionOutlives(ref p) => p.has_escaping_regions(), + Predicate::TypeOutlives(ref p) => p.has_escaping_regions(), + Predicate::Projection(ref p) => p.has_escaping_regions(), + Predicate::WellFormed(p) => p.has_escaping_regions(), + Predicate::ObjectSafe(_trait_def_id) => false, + } + } + + pub fn to_opt_poly_trait_ref(&self) -> Option> { + match *self { + Predicate::Trait(ref t) => { + Some(t.to_poly_trait_ref()) + } + Predicate::Projection(..) | + Predicate::Equate(..) | + Predicate::RegionOutlives(..) | + Predicate::WellFormed(..) | + Predicate::ObjectSafe(..) | + Predicate::TypeOutlives(..) => { + None + } + } + } +} + +/// Represents the bounds declared on a particular set of type +/// parameters. Should eventually be generalized into a flag list of +/// where clauses. You can obtain a `InstantiatedPredicates` list from a +/// `GenericPredicates` by using the `instantiate` method. Note that this method +/// reflects an important semantic invariant of `InstantiatedPredicates`: while +/// the `GenericPredicates` are expressed in terms of the bound type +/// parameters of the impl/trait/whatever, an `InstantiatedPredicates` instance +/// represented a set of bounds for some particular instantiation, +/// meaning that the generic parameters have been substituted with +/// their values. +/// +/// Example: +/// +/// struct Foo> { ... } +/// +/// Here, the `GenericPredicates` for `Foo` would contain a list of bounds like +/// `[[], [U:Bar]]`. Now if there were some particular reference +/// like `Foo`, then the `InstantiatedPredicates` would be `[[], +/// [usize:Bar]]`. +#[derive(Clone)] +pub struct InstantiatedPredicates<'tcx> { + pub predicates: VecPerParamSpace>, +} + +impl<'tcx> InstantiatedPredicates<'tcx> { + pub fn empty() -> InstantiatedPredicates<'tcx> { + InstantiatedPredicates { predicates: VecPerParamSpace::empty() } + } + + pub fn has_escaping_regions(&self) -> bool { + self.predicates.any(|p| p.has_escaping_regions()) + } + + pub fn is_empty(&self) -> bool { + self.predicates.is_empty() + } +} + +impl<'tcx> TraitRef<'tcx> { + pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>) -> TraitRef<'tcx> { + TraitRef { def_id: def_id, substs: substs } + } + + pub fn self_ty(&self) -> Ty<'tcx> { + self.substs.self_ty().unwrap() + } + + pub fn input_types(&self) -> &[Ty<'tcx>] { + // Select only the "input types" from a trait-reference. For + // now this is all the types that appear in the + // trait-reference, but it should eventually exclude + // associated types. + self.substs.types.as_slice() + } +} + +/// When type checking, we use the `ParameterEnvironment` to track +/// details about the type/lifetime parameters that are in scope. +/// It primarily stores the bounds information. +/// +/// Note: This information might seem to be redundant with the data in +/// `tcx.ty_param_defs`, but it is not. That table contains the +/// parameter definitions from an "outside" perspective, but this +/// struct will contain the bounds for a parameter as seen from inside +/// the function body. Currently the only real distinction is that +/// bound lifetime parameters are replaced with free ones, but in the +/// future I hope to refine the representation of types so as to make +/// more distinctions clearer. +#[derive(Clone)] +pub struct ParameterEnvironment<'a, 'tcx:'a> { + pub tcx: &'a ctxt<'tcx>, + + /// See `construct_free_substs` for details. + pub free_substs: Substs<'tcx>, + + /// Each type parameter has an implicit region bound that + /// indicates it must outlive at least the function body (the user + /// may specify stronger requirements). This field indicates the + /// region of the callee. + pub implicit_region_bound: ty::Region, + + /// Obligations that the caller must satisfy. This is basically + /// the set of bounds on the in-scope type parameters, translated + /// into Obligations, and elaborated and normalized. + pub caller_bounds: Vec>, + + /// Caches the results of trait selection. This cache is used + /// for things that have to do with the parameters in scope. + pub selection_cache: traits::SelectionCache<'tcx>, + + /// Scope that is attached to free regions for this scope. This + /// is usually the id of the fn body, but for more abstract scopes + /// like structs we often use the node-id of the struct. + /// + /// FIXME(#3696). It would be nice to refactor so that free + /// regions don't have this implicit scope and instead introduce + /// relationships in the environment. + pub free_id: ast::NodeId, +} + +impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { + pub fn with_caller_bounds(&self, + caller_bounds: Vec>) + -> ParameterEnvironment<'a,'tcx> + { + ParameterEnvironment { + tcx: self.tcx, + free_substs: self.free_substs.clone(), + implicit_region_bound: self.implicit_region_bound, + caller_bounds: caller_bounds, + selection_cache: traits::SelectionCache::new(), + free_id: self.free_id, + } + } + + pub fn for_item(cx: &'a ctxt<'tcx>, id: NodeId) -> ParameterEnvironment<'a, 'tcx> { + match cx.map.find(id) { + Some(ast_map::NodeImplItem(ref impl_item)) => { + match impl_item.node { + hir::TypeImplItem(_) => { + // associated types don't have their own entry (for some reason), + // so for now just grab environment for the impl + let impl_id = cx.map.get_parent(id); + let impl_def_id = DefId::local(impl_id); + let scheme = cx.lookup_item_type(impl_def_id); + let predicates = cx.lookup_predicates(impl_def_id); + cx.construct_parameter_environment(impl_item.span, + &scheme.generics, + &predicates, + id) + } + hir::ConstImplItem(_, _) => { + let def_id = DefId::local(id); + let scheme = cx.lookup_item_type(def_id); + let predicates = cx.lookup_predicates(def_id); + cx.construct_parameter_environment(impl_item.span, + &scheme.generics, + &predicates, + id) + } + hir::MethodImplItem(_, ref body) => { + let method_def_id = DefId::local(id); + match cx.impl_or_trait_item(method_def_id) { + MethodTraitItem(ref method_ty) => { + let method_generics = &method_ty.generics; + let method_bounds = &method_ty.predicates; + cx.construct_parameter_environment( + impl_item.span, + method_generics, + method_bounds, + body.id) + } + _ => { + cx.sess + .bug("ParameterEnvironment::for_item(): \ + got non-method item from impl method?!") + } + } + } + } + } + Some(ast_map::NodeTraitItem(trait_item)) => { + match trait_item.node { + hir::TypeTraitItem(..) => { + // associated types don't have their own entry (for some reason), + // so for now just grab environment for the trait + let trait_id = cx.map.get_parent(id); + let trait_def_id = DefId::local(trait_id); + let trait_def = cx.lookup_trait_def(trait_def_id); + let predicates = cx.lookup_predicates(trait_def_id); + cx.construct_parameter_environment(trait_item.span, + &trait_def.generics, + &predicates, + id) + } + hir::ConstTraitItem(..) => { + let def_id = DefId::local(id); + let scheme = cx.lookup_item_type(def_id); + let predicates = cx.lookup_predicates(def_id); + cx.construct_parameter_environment(trait_item.span, + &scheme.generics, + &predicates, + id) + } + hir::MethodTraitItem(_, ref body) => { + // for the body-id, use the id of the body + // block, unless this is a trait method with + // no default, then fallback to the method id. + let body_id = body.as_ref().map(|b| b.id).unwrap_or(id); + let method_def_id = DefId::local(id); + + match cx.impl_or_trait_item(method_def_id) { + MethodTraitItem(ref method_ty) => { + let method_generics = &method_ty.generics; + let method_bounds = &method_ty.predicates; + cx.construct_parameter_environment( + trait_item.span, + method_generics, + method_bounds, + body_id) + } + _ => { + cx.sess + .bug("ParameterEnvironment::for_item(): \ + got non-method item from provided \ + method?!") + } + } + } + } + } + Some(ast_map::NodeItem(item)) => { + match item.node { + hir::ItemFn(_, _, _, _, _, ref body) => { + // We assume this is a function. + let fn_def_id = DefId::local(id); + let fn_scheme = cx.lookup_item_type(fn_def_id); + let fn_predicates = cx.lookup_predicates(fn_def_id); + + cx.construct_parameter_environment(item.span, + &fn_scheme.generics, + &fn_predicates, + body.id) + } + hir::ItemEnum(..) | + hir::ItemStruct(..) | + hir::ItemImpl(..) | + hir::ItemConst(..) | + hir::ItemStatic(..) => { + let def_id = DefId::local(id); + let scheme = cx.lookup_item_type(def_id); + let predicates = cx.lookup_predicates(def_id); + cx.construct_parameter_environment(item.span, + &scheme.generics, + &predicates, + id) + } + hir::ItemTrait(..) => { + let def_id = DefId::local(id); + let trait_def = cx.lookup_trait_def(def_id); + let predicates = cx.lookup_predicates(def_id); + cx.construct_parameter_environment(item.span, + &trait_def.generics, + &predicates, + id) + } + _ => { + cx.sess.span_bug(item.span, + "ParameterEnvironment::from_item(): + can't create a parameter \ + environment for this kind of item") + } + } + } + Some(ast_map::NodeExpr(..)) => { + // This is a convenience to allow closures to work. + ParameterEnvironment::for_item(cx, cx.map.get_parent(id)) + } + _ => { + cx.sess.bug(&format!("ParameterEnvironment::from_item(): \ + `{}` is not an item", + cx.map.node_to_string(id))) + } + } + } +} + +/// A "type scheme", in ML terminology, is a type combined with some +/// set of generic types that the type is, well, generic over. In Rust +/// terms, it is the "type" of a fn item or struct -- this type will +/// include various generic parameters that must be substituted when +/// the item/struct is referenced. That is called converting the type +/// scheme to a monotype. +/// +/// - `generics`: the set of type parameters and their bounds +/// - `ty`: the base types, which may reference the parameters defined +/// in `generics` +/// +/// Note that TypeSchemes are also sometimes called "polytypes" (and +/// in fact this struct used to carry that name, so you may find some +/// stray references in a comment or something). We try to reserve the +/// "poly" prefix to refer to higher-ranked things, as in +/// `PolyTraitRef`. +/// +/// Note that each item also comes with predicates, see +/// `lookup_predicates`. +#[derive(Clone, Debug)] +pub struct TypeScheme<'tcx> { + pub generics: Generics<'tcx>, + pub ty: Ty<'tcx>, +} + +bitflags! { + flags TraitFlags: u32 { + const NO_TRAIT_FLAGS = 0, + const HAS_DEFAULT_IMPL = 1 << 0, + const IS_OBJECT_SAFE = 1 << 1, + const OBJECT_SAFETY_VALID = 1 << 2, + const IMPLS_VALID = 1 << 3, + } +} + +/// As `TypeScheme` but for a trait ref. +pub struct TraitDef<'tcx> { + pub unsafety: hir::Unsafety, + + /// If `true`, then this trait had the `#[rustc_paren_sugar]` + /// attribute, indicating that it should be used with `Foo()` + /// sugar. This is a temporary thing -- eventually any trait wil + /// be usable with the sugar (or without it). + pub paren_sugar: bool, + + /// Generic type definitions. Note that `Self` is listed in here + /// as having a single bound, the trait itself (e.g., in the trait + /// `Eq`, there is a single bound `Self : Eq`). This is so that + /// default methods get to assume that the `Self` parameters + /// implements the trait. + pub generics: Generics<'tcx>, + + pub trait_ref: TraitRef<'tcx>, + + /// A list of the associated types defined in this trait. Useful + /// for resolving `X::Foo` type markers. + pub associated_type_names: Vec, + + // Impls of this trait. To allow for quicker lookup, the impls are indexed + // by a simplified version of their Self type: impls with a simplifiable + // Self are stored in nonblanket_impls keyed by it, while all other impls + // are stored in blanket_impls. + + /// Impls of the trait. + pub nonblanket_impls: RefCell< + FnvHashMap> + >, + + /// Blanket impls associated with the trait. + pub blanket_impls: RefCell>, + + /// Various flags + pub flags: Cell +} + +impl<'tcx> TraitDef<'tcx> { + // returns None if not yet calculated + pub fn object_safety(&self) -> Option { + if self.flags.get().intersects(TraitFlags::OBJECT_SAFETY_VALID) { + Some(self.flags.get().intersects(TraitFlags::IS_OBJECT_SAFE)) + } else { + None + } + } + + pub fn set_object_safety(&self, is_safe: bool) { + assert!(self.object_safety().map(|cs| cs == is_safe).unwrap_or(true)); + self.flags.set( + self.flags.get() | if is_safe { + TraitFlags::OBJECT_SAFETY_VALID | TraitFlags::IS_OBJECT_SAFE + } else { + TraitFlags::OBJECT_SAFETY_VALID + } + ); + } + + /// Records a trait-to-implementation mapping. + pub fn record_impl(&self, + tcx: &ctxt<'tcx>, + impl_def_id: DefId, + impl_trait_ref: TraitRef<'tcx>) { + debug!("TraitDef::record_impl for {:?}, from {:?}", + self, impl_trait_ref); + + // We don't want to borrow_mut after we already populated all impls, + // so check if an impl is present with an immutable borrow first. + if let Some(sty) = fast_reject::simplify_type(tcx, + impl_trait_ref.self_ty(), false) { + if let Some(is) = self.nonblanket_impls.borrow().get(&sty) { + if is.contains(&impl_def_id) { + return // duplicate - skip + } + } + + self.nonblanket_impls.borrow_mut().entry(sty).or_insert(vec![]).push(impl_def_id) + } else { + if self.blanket_impls.borrow().contains(&impl_def_id) { + return // duplicate - skip + } + self.blanket_impls.borrow_mut().push(impl_def_id) + } + } + + + pub fn for_each_impl(&self, tcx: &ctxt<'tcx>, mut f: F) { + tcx.populate_implementations_for_trait_if_necessary(self.trait_ref.def_id); + + for &impl_def_id in self.blanket_impls.borrow().iter() { + f(impl_def_id); + } + + for v in self.nonblanket_impls.borrow().values() { + for &impl_def_id in v { + f(impl_def_id); + } + } + } + + /// Iterate over every impl that could possibly match the + /// self-type `self_ty`. + pub fn for_each_relevant_impl(&self, + tcx: &ctxt<'tcx>, + self_ty: Ty<'tcx>, + mut f: F) + { + tcx.populate_implementations_for_trait_if_necessary(self.trait_ref.def_id); + + for &impl_def_id in self.blanket_impls.borrow().iter() { + f(impl_def_id); + } + + // simplify_type(.., false) basically replaces type parameters and + // projections with infer-variables. This is, of course, done on + // the impl trait-ref when it is instantiated, but not on the + // predicate trait-ref which is passed here. + // + // for example, if we match `S: Copy` against an impl like + // `impl Copy for Option`, we replace the type variable + // in `Option` with an infer variable, to `Option<_>` (this + // doesn't actually change fast_reject output), but we don't + // replace `S` with anything - this impl of course can't be + // selected, and as there are hundreds of similar impls, + // considering them would significantly harm performance. + if let Some(simp) = fast_reject::simplify_type(tcx, self_ty, true) { + if let Some(impls) = self.nonblanket_impls.borrow().get(&simp) { + for &impl_def_id in impls { + f(impl_def_id); + } + } + } else { + for v in self.nonblanket_impls.borrow().values() { + for &impl_def_id in v { + f(impl_def_id); + } + } + } + } + +} + +bitflags! { + flags AdtFlags: u32 { + const NO_ADT_FLAGS = 0, + const IS_ENUM = 1 << 0, + const IS_DTORCK = 1 << 1, // is this a dtorck type? + const IS_DTORCK_VALID = 1 << 2, + const IS_PHANTOM_DATA = 1 << 3, + const IS_SIMD = 1 << 4, + const IS_FUNDAMENTAL = 1 << 5, + const IS_NO_DROP_FLAG = 1 << 6, + } +} + +pub type AdtDef<'tcx> = &'tcx AdtDefData<'tcx, 'static>; +pub type VariantDef<'tcx> = &'tcx VariantDefData<'tcx, 'static>; +pub type FieldDef<'tcx> = &'tcx FieldDefData<'tcx, 'static>; + +// See comment on AdtDefData for explanation +pub type AdtDefMaster<'tcx> = &'tcx AdtDefData<'tcx, 'tcx>; +pub type VariantDefMaster<'tcx> = &'tcx VariantDefData<'tcx, 'tcx>; +pub type FieldDefMaster<'tcx> = &'tcx FieldDefData<'tcx, 'tcx>; + +pub struct VariantDefData<'tcx, 'container: 'tcx> { + pub did: DefId, + pub name: Name, // struct's name if this is a struct + pub disr_val: Disr, + pub fields: Vec> +} + +pub struct FieldDefData<'tcx, 'container: 'tcx> { + /// The field's DefId. NOTE: the fields of tuple-like enum variants + /// are not real items, and don't have entries in tcache etc. + pub did: DefId, + /// special_idents::unnamed_field.name + /// if this is a tuple-like field + pub name: Name, + pub vis: hir::Visibility, + /// TyIVar is used here to allow for variance (see the doc at + /// AdtDefData). + ty: ivar::TyIVar<'tcx, 'container> +} + +/// The definition of an abstract data type - a struct or enum. +/// +/// These are all interned (by intern_adt_def) into the adt_defs +/// table. +/// +/// Because of the possibility of nested tcx-s, this type +/// needs 2 lifetimes: the traditional variant lifetime ('tcx) +/// bounding the lifetime of the inner types is of course necessary. +/// However, it is not sufficient - types from a child tcx must +/// not be leaked into the master tcx by being stored in an AdtDefData. +/// +/// The 'container lifetime ensures that by outliving the container +/// tcx and preventing shorter-lived types from being inserted. When +/// write access is not needed, the 'container lifetime can be +/// erased to 'static, which can be done by the AdtDef wrapper. +pub struct AdtDefData<'tcx, 'container: 'tcx> { + pub did: DefId, + pub variants: Vec>, + destructor: Cell>, + flags: Cell, +} + +impl<'tcx, 'container> PartialEq for AdtDefData<'tcx, 'container> { + // AdtDefData are always interned and this is part of TyS equality + #[inline] + fn eq(&self, other: &Self) -> bool { self as *const _ == other as *const _ } +} + +impl<'tcx, 'container> Eq for AdtDefData<'tcx, 'container> {} + +impl<'tcx, 'container> Hash for AdtDefData<'tcx, 'container> { + #[inline] + fn hash(&self, s: &mut H) { + (self as *const AdtDefData).hash(s) + } +} + + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum AdtKind { Struct, Enum } + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum VariantKind { Dict, Tuple, Unit } + +impl<'tcx, 'container> AdtDefData<'tcx, 'container> { + fn new(tcx: &ctxt<'tcx>, + did: DefId, + kind: AdtKind, + variants: Vec>) -> Self { + let mut flags = AdtFlags::NO_ADT_FLAGS; + let attrs = tcx.get_attrs(did); + if attr::contains_name(&attrs, "fundamental") { + flags = flags | AdtFlags::IS_FUNDAMENTAL; + } + if attr::contains_name(&attrs, "unsafe_no_drop_flag") { + flags = flags | AdtFlags::IS_NO_DROP_FLAG; + } + if tcx.lookup_simd(did) { + flags = flags | AdtFlags::IS_SIMD; + } + if Some(did) == tcx.lang_items.phantom_data() { + flags = flags | AdtFlags::IS_PHANTOM_DATA; + } + if let AdtKind::Enum = kind { + flags = flags | AdtFlags::IS_ENUM; + } + AdtDefData { + did: did, + variants: variants, + flags: Cell::new(flags), + destructor: Cell::new(None) + } + } + + fn calculate_dtorck(&'tcx self, tcx: &ctxt<'tcx>) { + if tcx.is_adt_dtorck(self) { + self.flags.set(self.flags.get() | AdtFlags::IS_DTORCK); + } + self.flags.set(self.flags.get() | AdtFlags::IS_DTORCK_VALID) + } + + /// Returns the kind of the ADT - Struct or Enum. + #[inline] + pub fn adt_kind(&self) -> AdtKind { + if self.flags.get().intersects(AdtFlags::IS_ENUM) { + AdtKind::Enum + } else { + AdtKind::Struct + } + } + + /// Returns whether this is a dtorck type. If this returns + /// true, this type being safe for destruction requires it to be + /// alive; Otherwise, only the contents are required to be. + #[inline] + pub fn is_dtorck(&'tcx self, tcx: &ctxt<'tcx>) -> bool { + if !self.flags.get().intersects(AdtFlags::IS_DTORCK_VALID) { + self.calculate_dtorck(tcx) + } + self.flags.get().intersects(AdtFlags::IS_DTORCK) + } + + /// Returns whether this type is #[fundamental] for the purposes + /// of coherence checking. + #[inline] + pub fn is_fundamental(&self) -> bool { + self.flags.get().intersects(AdtFlags::IS_FUNDAMENTAL) + } + + #[inline] + pub fn is_simd(&self) -> bool { + self.flags.get().intersects(AdtFlags::IS_SIMD) + } + + /// Returns true if this is PhantomData. + #[inline] + pub fn is_phantom_data(&self) -> bool { + self.flags.get().intersects(AdtFlags::IS_PHANTOM_DATA) + } + + /// Returns whether this type has a destructor. + pub fn has_dtor(&self) -> bool { + match self.dtor_kind() { + NoDtor => false, + TraitDtor(..) => true + } + } + + /// Asserts this is a struct and returns the struct's unique + /// variant. + pub fn struct_variant(&self) -> &VariantDefData<'tcx, 'container> { + assert!(self.adt_kind() == AdtKind::Struct); + &self.variants[0] + } + + #[inline] + pub fn type_scheme(&self, tcx: &ctxt<'tcx>) -> TypeScheme<'tcx> { + tcx.lookup_item_type(self.did) + } + + #[inline] + pub fn predicates(&self, tcx: &ctxt<'tcx>) -> GenericPredicates<'tcx> { + tcx.lookup_predicates(self.did) + } + + /// Returns an iterator over all fields contained + /// by this ADT. + #[inline] + pub fn all_fields(&self) -> + iter::FlatMap< + slice::Iter>, + slice::Iter>, + for<'s> fn(&'s VariantDefData<'tcx, 'container>) + -> slice::Iter<'s, FieldDefData<'tcx, 'container>> + > { + self.variants.iter().flat_map(VariantDefData::fields_iter) + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.variants.is_empty() + } + + #[inline] + pub fn is_univariant(&self) -> bool { + self.variants.len() == 1 + } + + pub fn is_payloadfree(&self) -> bool { + !self.variants.is_empty() && + self.variants.iter().all(|v| v.fields.is_empty()) + } + + pub fn variant_with_id(&self, vid: DefId) -> &VariantDefData<'tcx, 'container> { + self.variants + .iter() + .find(|v| v.did == vid) + .expect("variant_with_id: unknown variant") + } + + pub fn variant_index_with_id(&self, vid: DefId) -> usize { + self.variants + .iter() + .position(|v| v.did == vid) + .expect("variant_index_with_id: unknown variant") + } + + pub fn variant_of_def(&self, def: def::Def) -> &VariantDefData<'tcx, 'container> { + match def { + def::DefVariant(_, vid, _) => self.variant_with_id(vid), + def::DefStruct(..) | def::DefTy(..) => self.struct_variant(), + _ => panic!("unexpected def {:?} in variant_of_def", def) + } + } + + pub fn destructor(&self) -> Option { + self.destructor.get() + } + + pub fn set_destructor(&self, dtor: DefId) { + assert!(self.destructor.get().is_none()); + self.destructor.set(Some(dtor)); + } + + pub fn dtor_kind(&self) -> DtorKind { + match self.destructor.get() { + Some(_) => { + TraitDtor(!self.flags.get().intersects(AdtFlags::IS_NO_DROP_FLAG)) + } + None => NoDtor, + } + } +} + +impl<'tcx, 'container> VariantDefData<'tcx, 'container> { + #[inline] + fn fields_iter(&self) -> slice::Iter> { + self.fields.iter() + } + + pub fn kind(&self) -> VariantKind { + match self.fields.get(0) { + None => VariantKind::Unit, + Some(&FieldDefData { name, .. }) if name == special_idents::unnamed_field.name => { + VariantKind::Tuple + } + Some(_) => VariantKind::Dict + } + } + + pub fn is_tuple_struct(&self) -> bool { + self.kind() == VariantKind::Tuple + } + + #[inline] + pub fn find_field_named(&self, + name: ast::Name) + -> Option<&FieldDefData<'tcx, 'container>> { + self.fields.iter().find(|f| f.name == name) + } + + #[inline] + pub fn field_named(&self, name: ast::Name) -> &FieldDefData<'tcx, 'container> { + self.find_field_named(name).unwrap() + } +} + +impl<'tcx, 'container> FieldDefData<'tcx, 'container> { + pub fn new(did: DefId, + name: Name, + vis: hir::Visibility) -> Self { + FieldDefData { + did: did, + name: name, + vis: vis, + ty: ivar::TyIVar::new() + } + } + + pub fn ty(&self, tcx: &ctxt<'tcx>, subst: &Substs<'tcx>) -> Ty<'tcx> { + self.unsubst_ty().subst(tcx, subst) + } + + pub fn unsubst_ty(&self) -> Ty<'tcx> { + self.ty.unwrap() + } + + pub fn fulfill_ty(&self, ty: Ty<'container>) { + self.ty.fulfill(ty); + } +} + +/// Records the substitutions used to translate the polytype for an +/// item into the monotype of an item reference. +#[derive(Clone)] +pub struct ItemSubsts<'tcx> { + pub substs: Substs<'tcx>, +} + +#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)] +pub enum ClosureKind { + // Warning: Ordering is significant here! The ordering is chosen + // because the trait Fn is a subtrait of FnMut and so in turn, and + // hence we order it so that Fn < FnMut < FnOnce. + FnClosureKind, + FnMutClosureKind, + FnOnceClosureKind, +} + +impl ClosureKind { + pub fn trait_did(&self, cx: &ctxt) -> DefId { + let result = match *self { + FnClosureKind => cx.lang_items.require(FnTraitLangItem), + FnMutClosureKind => { + cx.lang_items.require(FnMutTraitLangItem) + } + FnOnceClosureKind => { + cx.lang_items.require(FnOnceTraitLangItem) + } + }; + match result { + Ok(trait_did) => trait_did, + Err(err) => cx.sess.fatal(&err[..]), + } + } + + /// True if this a type that impls this closure kind + /// must also implement `other`. + pub fn extends(self, other: ty::ClosureKind) -> bool { + match (self, other) { + (FnClosureKind, FnClosureKind) => true, + (FnClosureKind, FnMutClosureKind) => true, + (FnClosureKind, FnOnceClosureKind) => true, + (FnMutClosureKind, FnMutClosureKind) => true, + (FnMutClosureKind, FnOnceClosureKind) => true, + (FnOnceClosureKind, FnOnceClosureKind) => true, + _ => false, + } + } +} + +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) + } + + /// 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<'tcx> ItemSubsts<'tcx> { + pub fn empty() -> ItemSubsts<'tcx> { + ItemSubsts { substs: Substs::empty() } + } + + pub fn is_noop(&self) -> bool { + self.substs.is_noop() + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum LvaluePreference { + PreferMutLvalue, + NoPreference +} + +impl LvaluePreference { + pub fn from_mutbl(m: hir::Mutability) -> Self { + match m { + hir::MutMutable => PreferMutLvalue, + hir::MutImmutable => NoPreference, + } + } +} + +/// 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 +/// into the map by the `typeck::collect` phase. If the def-id is external, +/// then we have to go consult the crate loading code (and cache the result for +/// the future). +fn lookup_locally_or_in_crate_store(descr: &str, + def_id: DefId, + map: &RefCell>, + load_external: F) -> V where + V: Clone, + F: FnOnce() -> V, +{ + match map.borrow().get(&def_id).cloned() { + Some(v) => { return v; } + None => { } + } + + if def_id.is_local() { + panic!("No def'n found for {:?} in tcx.{}", def_id, descr); + } + let v = load_external(); + map.borrow_mut().insert(def_id, v.clone()); + v +} + +impl BorrowKind { + pub fn from_mutbl(m: hir::Mutability) -> BorrowKind { + match m { + hir::MutMutable => MutBorrow, + hir::MutImmutable => ImmBorrow, + } + } + + /// Returns a mutability `m` such that an `&m T` pointer could be used to obtain this borrow + /// kind. Because borrow kinds are richer than mutabilities, we sometimes have to pick a + /// mutability that is stronger than necessary so that it at least *would permit* the borrow in + /// question. + pub fn to_mutbl_lossy(self) -> hir::Mutability { + match self { + MutBorrow => hir::MutMutable, + ImmBorrow => hir::MutImmutable, + + // We have no type corresponding to a unique imm borrow, so + // use `&mut`. It gives all the capabilities of an `&uniq` + // and hence is a safe "over approximation". + UniqueImmBorrow => hir::MutMutable, + } + } + + pub fn to_user_str(&self) -> &'static str { + match *self { + MutBorrow => "mutable", + ImmBorrow => "immutable", + UniqueImmBorrow => "uniquely immutable", + } + } +} + +impl<'tcx> ctxt<'tcx> { + pub fn node_id_to_type(&self, id: NodeId) -> Ty<'tcx> { + match self.node_id_to_type_opt(id) { + Some(ty) => ty, + None => self.sess.bug( + &format!("node_id_to_type: no type for node `{}`", + self.map.node_to_string(id))) + } + } + + pub fn node_id_to_type_opt(&self, id: NodeId) -> Option> { + self.tables.borrow().node_types.get(&id).cloned() + } + + pub fn node_id_item_substs(&self, id: NodeId) -> ItemSubsts<'tcx> { + match self.tables.borrow().item_substs.get(&id) { + None => ItemSubsts::empty(), + Some(ts) => ts.clone(), + } + } + + // Returns the type of a pattern as a monotype. Like @expr_ty, this function + // doesn't provide type parameter substitutions. + pub fn pat_ty(&self, pat: &hir::Pat) -> Ty<'tcx> { + self.node_id_to_type(pat.id) + } + pub fn pat_ty_opt(&self, pat: &hir::Pat) -> Option> { + self.node_id_to_type_opt(pat.id) + } + + // Returns the type of an expression as a monotype. + // + // NB (1): This is the PRE-ADJUSTMENT TYPE for the expression. That is, in + // some cases, we insert `AutoAdjustment` annotations such as auto-deref or + // auto-ref. The type returned by this function does not consider such + // adjustments. See `expr_ty_adjusted()` instead. + // + // NB (2): This type doesn't provide type parameter substitutions; e.g. if you + // ask for the type of "id" in "id(3)", it will return "fn(&isize) -> isize" + // instead of "fn(ty) -> T with T = isize". + pub fn expr_ty(&self, expr: &hir::Expr) -> Ty<'tcx> { + self.node_id_to_type(expr.id) + } + + pub fn expr_ty_opt(&self, expr: &hir::Expr) -> Option> { + self.node_id_to_type_opt(expr.id) + } + + /// Returns the type of `expr`, considering any `AutoAdjustment` + /// entry recorded for that expression. + /// + /// It would almost certainly be better to store the adjusted ty in with + /// the `AutoAdjustment`, but I opted not to do this because it would + /// require serializing and deserializing the type and, although that's not + /// hard to do, I just hate that code so much I didn't want to touch it + /// unless it was to fix it properly, which seemed a distraction from the + /// thread at hand! -nmatsakis + pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> Ty<'tcx> { + self.expr_ty(expr) + .adjust(self, expr.span, expr.id, + self.tables.borrow().adjustments.get(&expr.id), + |method_call| { + self.tables.borrow().method_map.get(&method_call).map(|method| method.ty) + }) + } + + pub fn expr_span(&self, id: NodeId) -> Span { + match self.map.find(id) { + Some(ast_map::NodeExpr(e)) => { + e.span + } + Some(f) => { + self.sess.bug(&format!("Node id {} is not an expr: {:?}", + id, f)); + } + None => { + self.sess.bug(&format!("Node id {} is not present \ + in the node map", id)); + } + } + } + + pub fn local_var_name_str(&self, id: NodeId) -> InternedString { + match self.map.find(id) { + Some(ast_map::NodeLocal(pat)) => { + match pat.node { + hir::PatIdent(_, ref path1, _) => path1.node.name.as_str(), + _ => { + self.sess.bug(&format!("Variable id {} maps to {:?}, not local", id, pat)); + }, + } + }, + r => self.sess.bug(&format!("Variable id {} maps to {:?}, not local", id, r)), + } + } + + pub fn resolve_expr(&self, expr: &hir::Expr) -> def::Def { + match self.def_map.borrow().get(&expr.id) { + Some(def) => def.full_def(), + None => { + self.sess.span_bug(expr.span, &format!( + "no def-map entry for expr {}", expr.id)); + } + } + } + + pub fn expr_is_lval(&self, expr: &hir::Expr) -> bool { + match expr.node { + hir::ExprPath(..) => { + // We can't use resolve_expr here, as this needs to run on broken + // programs. We don't need to through - associated items are all + // rvalues. + match self.def_map.borrow().get(&expr.id) { + Some(&def::PathResolution { + base_def: def::DefStatic(..), .. + }) | Some(&def::PathResolution { + base_def: def::DefUpvar(..), .. + }) | Some(&def::PathResolution { + base_def: def::DefLocal(..), .. + }) => { + true + } + + Some(..) => false, + + None => self.sess.span_bug(expr.span, &format!( + "no def for path {}", expr.id)) + } + } + + hir::ExprUnary(hir::UnDeref, _) | + hir::ExprField(..) | + hir::ExprTupField(..) | + hir::ExprIndex(..) => { + true + } + + hir::ExprCall(..) | + hir::ExprMethodCall(..) | + hir::ExprStruct(..) | + hir::ExprRange(..) | + hir::ExprTup(..) | + hir::ExprIf(..) | + hir::ExprMatch(..) | + hir::ExprClosure(..) | + hir::ExprBlock(..) | + hir::ExprRepeat(..) | + hir::ExprVec(..) | + hir::ExprBreak(..) | + hir::ExprAgain(..) | + hir::ExprRet(..) | + hir::ExprWhile(..) | + hir::ExprLoop(..) | + hir::ExprAssign(..) | + hir::ExprInlineAsm(..) | + 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 provided_source(&self, id: DefId) -> Option { + self.provided_method_sources.borrow().get(&id).cloned() + } + + pub fn provided_trait_methods(&self, id: DefId) -> Vec>> { + if id.is_local() { + if let ItemTrait(_, _, _, ref ms) = self.map.expect_item(id.node).node { + ms.iter().filter_map(|ti| { + if let hir::MethodTraitItem(_, Some(_)) = ti.node { + match self.impl_or_trait_item(DefId::local(ti.id)) { + MethodTraitItem(m) => Some(m), + _ => { + self.sess.bug("provided_trait_methods(): \ + non-method item found from \ + looking up provided method?!") + } + } + } else { + None + } + }).collect() + } else { + self.sess.bug(&format!("provided_trait_methods: `{:?}` is not a trait", id)) + } + } else { + csearch::get_provided_trait_methods(self, id) + } + } + + pub fn associated_consts(&self, id: DefId) -> Vec>> { + if id.is_local() { + match self.map.expect_item(id.node).node { + ItemTrait(_, _, _, ref tis) => { + tis.iter().filter_map(|ti| { + if let hir::ConstTraitItem(_, _) = ti.node { + match self.impl_or_trait_item(DefId::local(ti.id)) { + ConstTraitItem(ac) => Some(ac), + _ => { + self.sess.bug("associated_consts(): \ + non-const item found from \ + looking up a constant?!") + } + } + } else { + None + } + }).collect() + } + ItemImpl(_, _, _, _, _, ref iis) => { + iis.iter().filter_map(|ii| { + if let hir::ConstImplItem(_, _) = ii.node { + match self.impl_or_trait_item(DefId::local(ii.id)) { + ConstTraitItem(ac) => Some(ac), + _ => { + self.sess.bug("associated_consts(): \ + non-const item found from \ + looking up a constant?!") + } + } + } else { + None + } + }).collect() + } + _ => { + self.sess.bug(&format!("associated_consts: `{:?}` is not a trait \ + or impl", id)) + } + } + } else { + csearch::get_associated_consts(self, id) + } + } + + pub fn trait_items(&self, trait_did: DefId) -> Rc>> { + let mut trait_items = self.trait_items_cache.borrow_mut(); + match trait_items.get(&trait_did).cloned() { + Some(trait_items) => trait_items, + None => { + let def_ids = self.trait_item_def_ids(trait_did); + let items: Rc> = + Rc::new(def_ids.iter() + .map(|d| self.impl_or_trait_item(d.def_id())) + .collect()); + trait_items.insert(trait_did, items.clone()); + items + } + } + } + + pub fn trait_impl_polarity(&self, id: DefId) -> Option { + if id.is_local() { + match self.map.find(id.node) { + Some(ast_map::NodeItem(item)) => { + match item.node { + hir::ItemImpl(_, polarity, _, _, _, _) => Some(polarity), + _ => None + } + } + _ => None + } + } else { + csearch::get_impl_polarity(self, id) + } + } + + 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") + } else { + (None, "local") + }; + + match kind { + Some(kind) => kind, + None => { + self.sess.bug(&format!("custom_coerce_unsized_kind: \ + {} impl `{}` is missing its kind", + src, self.item_path_str(did))); + } + } + }) + } + + pub fn impl_or_trait_item(&self, id: DefId) -> ImplOrTraitItem<'tcx> { + lookup_locally_or_in_crate_store( + "impl_or_trait_items", id, &self.impl_or_trait_items, + || csearch::get_impl_or_trait_item(self, id)) + } + + pub fn trait_item_def_ids(&self, id: DefId) -> Rc> { + lookup_locally_or_in_crate_store( + "trait_item_def_ids", id, &self.trait_item_def_ids, + || Rc::new(csearch::get_trait_item_def_ids(&self.sess.cstore, id))) + } + + /// Returns the trait-ref corresponding to a given impl, or None if it is + /// an inherent impl. + pub fn impl_trait_ref(&self, id: DefId) -> Option> { + lookup_locally_or_in_crate_store( + "impl_trait_refs", id, &self.impl_trait_refs, + || csearch::get_impl_trait(self, id)) + } + + /// Returns whether this DefId refers to an impl + pub fn is_impl(&self, id: DefId) -> bool { + if id.is_local() { + if let Some(ast_map::NodeItem( + &hir::Item { node: hir::ItemImpl(..), .. })) = self.map.find(id.node) { + true + } else { + false + } + } else { + csearch::is_impl(&self.sess.cstore, id) + } + } + + pub fn trait_ref_to_def_id(&self, tr: &hir::TraitRef) -> DefId { + self.def_map.borrow().get(&tr.ref_id).expect("no def-map entry for trait").def_id() + } + + pub fn item_path_str(&self, id: DefId) -> String { + self.with_path(id, |path| ast_map::path_to_string(path)) + } + + pub fn with_path(&self, id: DefId, f: F) -> T where + F: FnOnce(ast_map::PathElems) -> T, + { + if id.is_local() { + self.map.with_path(id.node, f) + } else { + f(csearch::get_item_path(self, id).iter().cloned().chain(LinkedPath::empty())) + } + } + + pub fn item_name(&self, id: DefId) -> ast::Name { + if id.is_local() { + self.map.get_path_elem(id.node).name() + } else { + csearch::get_item_name(self, id) + } + } + + // Register a given item type + pub fn register_item_type(&self, did: DefId, ty: TypeScheme<'tcx>) { + self.tcache.borrow_mut().insert(did, ty); + } + + // If the given item is in an external crate, looks up its type and adds it to + // the type cache. Returns the type parameters and type. + pub fn lookup_item_type(&self, did: DefId) -> TypeScheme<'tcx> { + lookup_locally_or_in_crate_store( + "tcache", did, &self.tcache, + || csearch::get_type(self, did)) + } + + /// Given the did of a trait, returns its canonical trait ref. + pub fn lookup_trait_def(&self, did: DefId) -> &'tcx TraitDef<'tcx> { + lookup_locally_or_in_crate_store( + "trait_defs", did, &self.trait_defs, + || self.alloc_trait_def(csearch::get_trait_def(self, did)) + ) + } + + /// Given the did of an ADT, return a master reference to its + /// definition. Unless you are planning on fulfilling the ADT's fields, + /// use lookup_adt_def instead. + pub fn lookup_adt_def_master(&self, did: DefId) -> AdtDefMaster<'tcx> { + lookup_locally_or_in_crate_store( + "adt_defs", did, &self.adt_defs, + || csearch::get_adt_def(self, did) + ) + } + + /// Given the did of an ADT, return a reference to its definition. + pub fn lookup_adt_def(&self, did: DefId) -> AdtDef<'tcx> { + // when reverse-variance goes away, a transmute:: + // woud be needed here. + self.lookup_adt_def_master(did) + } + + /// Return the list of all interned ADT definitions + pub fn adt_defs(&self) -> Vec> { + self.adt_defs.borrow().values().cloned().collect() + } + + /// Given the did of an item, returns its full set of predicates. + pub fn lookup_predicates(&self, did: DefId) -> GenericPredicates<'tcx> { + lookup_locally_or_in_crate_store( + "predicates", did, &self.predicates, + || csearch::get_predicates(self, did)) + } + + /// Given the did of a trait, returns its superpredicates. + pub fn lookup_super_predicates(&self, did: DefId) -> GenericPredicates<'tcx> { + lookup_locally_or_in_crate_store( + "super_predicates", did, &self.super_predicates, + || csearch::get_super_predicates(self, did)) + } + + /// Get the attributes of a definition. + pub fn get_attrs(&self, did: DefId) -> Cow<'tcx, [hir::Attribute]> { + if did.is_local() { + Cow::Borrowed(self.map.attrs(did.node)) + } else { + Cow::Owned(csearch::get_item_attrs(&self.sess.cstore, did)) + } + } + + /// Determine whether an item is annotated with an attribute + pub fn has_attr(&self, did: DefId, attr: &str) -> bool { + self.get_attrs(did).iter().any(|item| item.check_name(attr)) + } + + /// Determine whether an item is annotated with `#[repr(packed)]` + pub fn lookup_packed(&self, did: DefId) -> bool { + self.lookup_repr_hints(did).contains(&attr::ReprPacked) + } + + /// Determine whether an item is annotated with `#[simd]` + pub fn lookup_simd(&self, did: DefId) -> bool { + self.has_attr(did, "simd") + || self.lookup_repr_hints(did).contains(&attr::ReprSimd) + } + + /// Obtain the representation annotation for a struct definition. + pub fn lookup_repr_hints(&self, did: DefId) -> Rc> { + memoized(&self.repr_hint_cache, did, |did: DefId| { + Rc::new(if did.is_local() { + self.get_attrs(did).iter().flat_map(|meta| { + attr::find_repr_attrs(self.sess.diagnostic(), meta).into_iter() + }).collect() + } else { + csearch::get_repr_attrs(&self.sess.cstore, did) + }) + }) + } + + pub fn item_variances(&self, item_id: DefId) -> Rc { + lookup_locally_or_in_crate_store( + "item_variance_map", item_id, &self.item_variance_map, + || Rc::new(csearch::get_item_variances(&self.sess.cstore, item_id))) + } + + pub fn trait_has_default_impl(&self, trait_def_id: DefId) -> bool { + self.populate_implementations_for_trait_if_necessary(trait_def_id); + + let def = self.lookup_trait_def(trait_def_id); + def.flags.get().intersects(TraitFlags::HAS_DEFAULT_IMPL) + } + + /// Records a trait-to-implementation mapping. + pub fn record_trait_has_default_impl(&self, trait_def_id: DefId) { + let def = self.lookup_trait_def(trait_def_id); + def.flags.set(def.flags.get() | TraitFlags::HAS_DEFAULT_IMPL) + } + + /// Load primitive inherent implementations if necessary + pub fn populate_implementations_for_primitive_if_necessary(&self, + primitive_def_id: DefId) { + if primitive_def_id.is_local() { + return + } + + if self.populated_external_primitive_impls.borrow().contains(&primitive_def_id) { + return + } + + debug!("populate_implementations_for_primitive_if_necessary: searching for {:?}", + primitive_def_id); + + let impl_items = csearch::get_impl_items(&self.sess.cstore, primitive_def_id); + + // Store the implementation info. + self.impl_items.borrow_mut().insert(primitive_def_id, impl_items); + self.populated_external_primitive_impls.borrow_mut().insert(primitive_def_id); + } + + /// Populates the type context with all the inherent implementations for + /// the given type if necessary. + pub fn populate_inherent_implementations_for_type_if_necessary(&self, + type_id: DefId) { + if type_id.is_local() { + return + } + + if self.populated_external_types.borrow().contains(&type_id) { + return + } + + debug!("populate_inherent_implementations_for_type_if_necessary: searching for {:?}", + type_id); + + let mut inherent_impls = Vec::new(); + csearch::each_inherent_implementation_for_type(&self.sess.cstore, type_id, |impl_def_id| { + // Record the implementation. + inherent_impls.push(impl_def_id); + + // Store the implementation info. + let impl_items = csearch::get_impl_items(&self.sess.cstore, impl_def_id); + self.impl_items.borrow_mut().insert(impl_def_id, impl_items); + }); + + self.inherent_impls.borrow_mut().insert(type_id, Rc::new(inherent_impls)); + self.populated_external_types.borrow_mut().insert(type_id); + } + + /// Populates the type context with all the implementations for the given + /// trait if necessary. + pub fn populate_implementations_for_trait_if_necessary(&self, trait_id: DefId) { + if trait_id.is_local() { + return + } + + let def = self.lookup_trait_def(trait_id); + if def.flags.get().intersects(TraitFlags::IMPLS_VALID) { + return; + } + + debug!("populate_implementations_for_trait_if_necessary: searching for {:?}", def); + + if csearch::is_defaulted_trait(&self.sess.cstore, trait_id) { + self.record_trait_has_default_impl(trait_id); + } + + csearch::each_implementation_for_trait(&self.sess.cstore, trait_id, |impl_def_id| { + let impl_items = csearch::get_impl_items(&self.sess.cstore, impl_def_id); + let trait_ref = self.impl_trait_ref(impl_def_id).unwrap(); + // Record the trait->implementation mapping. + def.record_impl(self, impl_def_id, trait_ref); + + // For any methods that use a default implementation, add them to + // the map. This is a bit unfortunate. + for impl_item_def_id in &impl_items { + let method_def_id = impl_item_def_id.def_id(); + match self.impl_or_trait_item(method_def_id) { + MethodTraitItem(method) => { + if let Some(source) = method.provided_source { + self.provided_method_sources + .borrow_mut() + .insert(method_def_id, source); + } + } + _ => {} + } + } + + // Store the implementation info. + self.impl_items.borrow_mut().insert(impl_def_id, impl_items); + }); + + def.flags.set(def.flags.get() | TraitFlags::IMPLS_VALID); + } + + /// Given the def_id of an impl, return the def_id of the trait it implements. + /// If it implements no trait, return `None`. + pub fn trait_id_of_impl(&self, def_id: DefId) -> Option { + self.impl_trait_ref(def_id).map(|tr| tr.def_id) + } + + /// If the given def ID describes a method belonging to an impl, return the + /// ID of the impl that the method belongs to. Otherwise, return `None`. + pub fn impl_of_method(&self, def_id: DefId) -> Option { + if def_id.krate != LOCAL_CRATE { + return match csearch::get_impl_or_trait_item(self, + def_id).container() { + TraitContainer(_) => None, + ImplContainer(def_id) => Some(def_id), + }; + } + match self.impl_or_trait_items.borrow().get(&def_id).cloned() { + Some(trait_item) => { + match trait_item.container() { + TraitContainer(_) => None, + ImplContainer(def_id) => Some(def_id), + } + } + None => None + } + } + + /// If the given def ID describes an item belonging to a trait (either a + /// default method or an implementation of a trait method), return the ID of + /// the trait that the method belongs to. Otherwise, return `None`. + pub fn trait_of_item(&self, def_id: DefId) -> Option { + if def_id.krate != LOCAL_CRATE { + return csearch::get_trait_of_item(&self.sess.cstore, def_id, self); + } + match self.impl_or_trait_items.borrow().get(&def_id).cloned() { + Some(impl_or_trait_item) => { + match impl_or_trait_item.container() { + TraitContainer(def_id) => Some(def_id), + ImplContainer(def_id) => self.trait_id_of_impl(def_id), + } + } + None => None + } + } + + /// If the given def ID describes an item belonging to a trait, (either a + /// default method or an implementation of a trait method), return the ID of + /// the method inside trait definition (this means that if the given def ID + /// is already that of the original trait method, then the return value is + /// the same). + /// Otherwise, return `None`. + pub fn trait_item_of_item(&self, def_id: DefId) -> Option { + let impl_item = match self.impl_or_trait_items.borrow().get(&def_id) { + Some(m) => m.clone(), + None => return None, + }; + let name = impl_item.name(); + match self.trait_of_item(def_id) { + Some(trait_did) => { + self.trait_items(trait_did).iter() + .find(|item| item.name() == name) + .map(|item| item.id()) + } + None => None + } + } + + /// 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) + -> ParameterEnvironment<'a,'tcx> { + ty::ParameterEnvironment { tcx: self, + free_substs: Substs::empty(), + caller_bounds: Vec::new(), + implicit_region_bound: ty::ReEmpty, + selection_cache: traits::SelectionCache::new(), + + // for an empty parameter + // environment, there ARE no free + // regions, so it shouldn't matter + // what we use for the free id + free_id: ast::DUMMY_NODE_ID } + } + + /// Constructs and returns a substitution that can be applied to move from + /// the "outer" view of a type or method to the "inner" view. + /// In general, this means converting from bound parameters to + /// free parameters. Since we currently represent bound/free type + /// parameters in the same way, this only has an effect on regions. + pub fn construct_free_substs(&self, generics: &Generics<'tcx>, + free_id: NodeId) -> Substs<'tcx> { + // map T => T + let mut types = VecPerParamSpace::empty(); + for def in generics.types.as_slice() { + debug!("construct_parameter_environment(): push_types_from_defs: def={:?}", + def); + types.push(def.space, self.mk_param_from_def(def)); + } + + let free_id_outlive = self.region_maps.item_extent(free_id); + + // map bound 'a => free 'a + let mut regions = VecPerParamSpace::empty(); + for def in generics.regions.as_slice() { + let region = + ReFree(FreeRegion { scope: free_id_outlive, + bound_region: BrNamed(def.def_id, def.name) }); + debug!("push_region_params {:?}", region); + regions.push(def.space, region); + } + + Substs { + types: types, + regions: subst::NonerasedRegions(regions) + } + } + + /// See `ParameterEnvironment` struct def'n for details + pub fn construct_parameter_environment<'a>(&'a self, + span: Span, + generics: &ty::Generics<'tcx>, + generic_predicates: &ty::GenericPredicates<'tcx>, + free_id: NodeId) + -> ParameterEnvironment<'a, 'tcx> + { + // + // Construct the free substs. + // + + let free_substs = self.construct_free_substs(generics, free_id); + let free_id_outlive = self.region_maps.item_extent(free_id); + + // + // Compute the bounds on Self and the type parameters. + // + + let bounds = generic_predicates.instantiate(self, &free_substs); + let bounds = self.liberate_late_bound_regions(free_id_outlive, &ty::Binder(bounds)); + let predicates = bounds.predicates.into_vec(); + + debug!("construct_parameter_environment: free_id={:?} free_subst={:?} predicates={:?}", + free_id, + free_substs, + predicates); + + // + // Finally, we have to normalize the bounds in the environment, in + // case they contain any associated type projections. This process + // can yield errors if the put in illegal associated types, like + // `::Bar` where `i32` does not implement `Foo`. We + // report these errors right here; this doesn't actually feel + // right to me, because constructing the environment feels like a + // kind of a "idempotent" action, but I'm not sure where would be + // a better place. In practice, we construct environments for + // every fn once during type checking, and we'll abort if there + // are any errors at that point, so after type checking you can be + // sure that this will succeed without errors anyway. + // + + let unnormalized_env = ty::ParameterEnvironment { + tcx: self, + free_substs: free_substs, + implicit_region_bound: ty::ReScope(free_id_outlive), + caller_bounds: predicates, + selection_cache: traits::SelectionCache::new(), + free_id: free_id, + }; + + let cause = traits::ObligationCause::misc(span, free_id); + traits::normalize_param_env_or_error(unnormalized_env, cause) + } + + pub fn is_method_call(&self, expr_id: NodeId) -> bool { + self.tables.borrow().method_map.contains_key(&MethodCall::expr(expr_id)) + } + + pub fn is_overloaded_autoderef(&self, expr_id: NodeId, autoderefs: u32) -> bool { + self.tables.borrow().method_map.contains_key(&MethodCall::autoderef(expr_id, + autoderefs)) + } + + pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option { + Some(self.tables.borrow().upvar_capture_map.get(&upvar_id).unwrap().clone()) + } +} + +/// The category of explicit self. +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +pub enum ExplicitSelfCategory { + StaticExplicitSelfCategory, + ByValueExplicitSelfCategory, + ByReferenceExplicitSelfCategory(Region, hir::Mutability), + ByBoxExplicitSelfCategory, +} + +/// A free variable referred to in a function. +#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] +pub struct Freevar { + /// The variable being accessed free. + pub def: def::Def, + + // First span where it is accessed (there can be multiple). + pub span: Span +} + +pub type FreevarMap = NodeMap>; + +pub type CaptureModeMap = NodeMap; + +// Trait method resolution +pub type TraitMap = NodeMap>; + +// Map from the NodeId of a glob import to a list of items which are actually +// imported. +pub type GlobMap = HashMap>; + +impl<'tcx> ctxt<'tcx> { + pub fn with_freevars(&self, fid: NodeId, f: F) -> T where + F: FnOnce(&[Freevar]) -> T, + { + match self.freevars.borrow().get(&fid) { + None => f(&[]), + Some(d) => f(&d[..]) + } + } + + pub fn make_substs_for_receiver_types(&self, + trait_ref: &ty::TraitRef<'tcx>, + method: &ty::Method<'tcx>) + -> subst::Substs<'tcx> + { + /*! + * Substitutes the values for the receiver's type parameters + * that are found in method, leaving the method's type parameters + * intact. + */ + + let meth_tps: Vec = + method.generics.types.get_slice(subst::FnSpace) + .iter() + .map(|def| self.mk_param_from_def(def)) + .collect(); + let meth_regions: Vec = + method.generics.regions.get_slice(subst::FnSpace) + .iter() + .map(|def| def.to_early_bound_region()) + .collect(); + trait_ref.substs.clone().with_method(meth_tps, meth_regions) + } +} + +/// 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: +/// +/// for<'a> fn(x: for<'b> fn(&'a isize, &'b isize)) +/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope +/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ inner scope +/// +/// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the +/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner +/// fn type*, that type has an escaping region: `'a`. +/// +/// Note that what I'm calling an "escaping region" is often just called a "free region". However, +/// we already use the term "free region". It refers to the regions that we use to represent bound +/// regions on a fn definition while we are typechecking its body. +/// +/// To clarify, conceptually there is no particular difference between an "escaping" region and a +/// "free" region. However, there is a big difference in practice. Basically, when "entering" a +/// binding level, one is generally required to do some sort of processing to a bound region, such +/// as replacing it with a fresh/skolemized region, or making an entry in the environment to +/// represent the scope to which it is attached, etc. An escaping region represents a bound region +/// for which this processing has not yet been done. +pub trait RegionEscape { + fn has_escaping_regions(&self) -> bool { + self.has_regions_escaping_depth(0) + } + + fn has_regions_escaping_depth(&self, depth: u32) -> bool; +} + +pub trait HasTypeFlags { + fn has_type_flags(&self, flags: TypeFlags) -> bool; + fn has_projection_types(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_PROJECTION) + } + fn references_error(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_ERR) + } + fn has_param_types(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_PARAMS) + } + fn has_self_ty(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_SELF) + } + fn has_infer_types(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_INFER) + } + fn needs_infer(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER) + } + fn needs_subst(&self) -> bool { + self.has_type_flags(TypeFlags::NEEDS_SUBST) + } + fn has_closure_types(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_CLOSURE) + } + fn has_erasable_regions(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_RE_EARLY_BOUND | + TypeFlags::HAS_RE_INFER | + TypeFlags::HAS_FREE_REGIONS) + } + /// Indicates whether this value references only 'global' + /// types/lifetimes that are the same regardless of what fn we are + /// in. This is used for caching. Errs on the side of returning + /// false. + fn is_global(&self) -> bool { + !self.has_type_flags(TypeFlags::HAS_LOCAL_NAMES) + } +} 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 98% rename from src/librustc/middle/ty_relate/mod.rs rename to src/librustc/middle/ty/relate.rs index d2d612ece6f80..ff0a9789cf1f8 100644 --- a/src/librustc/middle/ty_relate/mod.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_fold::TypeFoldable; +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..0058ccbce3b19 --- /dev/null +++ b/src/librustc/middle/ty/structural_impls.rs @@ -0,0 +1,813 @@ +// 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> 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::adjustment::AutoRef<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::adjustment::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> 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..3969738a22e86 --- /dev/null +++ b/src/librustc/middle/ty/sty.rs @@ -0,0 +1,1212 @@ +// 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 syntax::parse::token::special_idents; + +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, +} + +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: +/// +/// 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 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(), + _ => 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_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, + _ => 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 + } + } + + /// 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/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..fee60d46dc001 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 = ty_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::adjustment::AutoAdjustment<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + ty::adjustment::AdjustReifyFnPointer => { + write!(f, "AdjustReifyFnPointer") + } + ty::adjustment::AdjustUnsafeFnPointer => { + write!(f, "AdjustUnsafeFnPointer") + } + ty::adjustment::AdjustDerefRef(ref data) => { + write!(f, "{:?}", data) + } + } + } +} + +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) + } +} + +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_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_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/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..a2d74635b5e1c 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -33,9 +33,11 @@ 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::adjustment::{AdjustDerefRef, AdjustReifyFnPointer}; +use middle::ty::adjustment::AdjustUnsafeFnPointer; use middle::ty::{self, Ty}; +use middle::ty::cast::{CastTy,IntTy}; use util::nodemap::NodeMap; use rustc_front::hir; @@ -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 3a7fa040e4f8c..7d8996867c016 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -71,10 +71,11 @@ 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::adjustment::{AdjustDerefRef, AdjustReifyFnPointer}; +use middle::ty::adjustment::{AdjustUnsafeFnPointer, CustomCoerceUnsized}; 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; @@ -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()); @@ -2045,8 +2046,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..a9322bf2197b0 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,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); @@ -2249,7 +2246,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..69efaa792fe05 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -65,9 +65,12 @@ 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::{self, LvaluePreference, TypeAndMut, Ty, TypeError}; -use middle::ty_relate::RelateResult; +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; use util::common::indent; use std::cell::RefCell; @@ -80,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> { @@ -185,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; @@ -263,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) }; @@ -359,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)); } _ => {} } @@ -386,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) } @@ -421,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/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/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..572ba7a848713 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -16,7 +16,8 @@ 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::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr}; +use middle::ty::fold::TypeFoldable; use middle::infer; use middle::infer::InferCtxt; use syntax::codemap::Span; @@ -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/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..656a740e9840e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -97,7 +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_fold::{TypeFolder, TypeFoldable}; +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; @@ -1336,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 @@ -1346,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() { @@ -1575,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); @@ -1627,7 +1630,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 +1639,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 +1654,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 +1664,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 +1769,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 +1805,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 +1978,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); @@ -4166,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 844e143b9fa5b..155caaa8cb0fe 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -88,14 +88,14 @@ 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::adjustment; +use middle::ty::wf::ImpliedBound; use std::mem; use std::rc::Rc; @@ -420,7 +420,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); @@ -599,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 { @@ -615,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. @@ -1222,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()); @@ -1230,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); } @@ -1527,31 +1529,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 +1561,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..6f8e064c9d819 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -18,7 +18,8 @@ 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::adjustment; +use middle::ty::fold::{TypeFolder,TypeFoldable}; use middle::infer; use write_substs_to_tcx; use write_ty_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 8683afe44735a..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"); @@ -446,7 +447,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) }; @@ -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 f0b68e5e9025f..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::{self, TypeFolder, TypeFoldable}; +use middle::ty::fold::{TypeFolder, TypeFoldable}; +use middle::ty::util::IntTypeExt; use middle::infer; use rscope::*; use rustc::front::map as hir_map; @@ -2374,7 +2375,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); 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) }