From 5a95acb8aba07ea8e5255893aa4e01e5ba5c2349 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 14 Sep 2015 14:55:56 +0300 Subject: [PATCH] split ty::util and ty::adjustment --- src/librustc/metadata/csearch.rs | 8 +- src/librustc/metadata/decoder.rs | 8 +- src/librustc/middle/astencode.rs | 58 +- src/librustc/middle/check_const.rs | 9 +- src/librustc/middle/expr_use_visitor.rs | 15 +- src/librustc/middle/infer/mod.rs | 7 +- src/librustc/middle/mem_categorization.rs | 11 +- src/librustc/middle/ty/adjustment.rs | 249 ++++ src/librustc/middle/ty/context.rs | 4 +- src/librustc/middle/ty/fold.rs | 14 +- src/librustc/middle/ty/mod.rs | 1203 +------------------ src/librustc/middle/ty/structural_impls.rs | 4 +- src/librustc/middle/ty/sty.rs | 83 ++ src/librustc/middle/ty/util.rs | 891 ++++++++++++++ src/librustc/util/ppaux.rs | 10 +- src/librustc_lint/builtin.rs | 11 +- src/librustc_mir/tcx/expr.rs | 10 +- src/librustc_trans/trans/consts.rs | 8 +- src/librustc_trans/trans/expr.rs | 5 +- src/librustc_typeck/check/coercion.rs | 18 +- src/librustc_typeck/check/method/confirm.rs | 13 +- src/librustc_typeck/check/method/mod.rs | 5 +- src/librustc_typeck/check/mod.rs | 21 +- src/librustc_typeck/check/regionck.rs | 13 +- src/librustc_typeck/check/writeback.rs | 13 +- src/librustc_typeck/coherence/mod.rs | 13 +- src/librustc_typeck/collect.rs | 3 +- 27 files changed, 1387 insertions(+), 1320 deletions(-) create mode 100644 src/librustc/middle/ty/adjustment.rs create mode 100644 src/librustc/middle/ty/util.rs diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index c539bfc5964..e1cb9bd0e77 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 309a18feb9a..e2cf50cf30a 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 ac2dd545982..0bd4434857a 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -27,6 +27,7 @@ use metadata::tydecode::{DefIdSource, NominalType, TypeWithId}; use metadata::tydecode::{RegionParameter, ClosureSource}; use metadata::tyencode; +use middle::ty::adjustment; use middle::ty::cast; use middle::check_const::ConstQualif; use middle::def; @@ -646,11 +647,11 @@ fn emit_existential_bounds<'b>(&mut self, ecx: &e::EncodeContext<'b,'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 @@ fn emit_substs<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, } 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 @@ fn emit_auto_adjustment<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, } 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 @@ fn emit_autoref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, } 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 @@ fn read_substs<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, '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 @@ fn read_closure_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, '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 @@ fn read_upvar_capture(&mut self, dcx: &DecodeContext) -> ty::UpvarCapture { }).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 @@ fn read_auto_deref_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) } 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 @@ fn read_autoref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) 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 48c8cca76b0..661299cd7f3 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -798,8 +798,13 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, /// Check the adjustments of an expression fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) { match v.tcx.tables.borrow().adjustments.get(&e.id) { - None | Some(&ty::AdjustReifyFnPointer) | Some(&ty::AdjustUnsafeFnPointer) => {} - Some(&ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs, .. })) => { + None | + Some(&ty::adjustment::AdjustReifyFnPointer) | + Some(&ty::adjustment::AdjustUnsafeFnPointer) => {} + + Some(&ty::adjustment::AdjustDerefRef( + ty::adjustment::AutoDerefRef { autoderefs, .. } + )) => { if (0..autoderefs as u32).any(|autoderef| { v.tcx.is_overloaded_autoderef(e.id, autoderef) }) { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index d2bb31f10bd..a8fed5eab16 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -25,6 +25,7 @@ use middle::infer; use middle::mem_categorization as mc; use middle::ty; +use middle::ty::adjustment; use rustc_front::hir; @@ -726,8 +727,8 @@ fn walk_adjustment(&mut self, expr: &hir::Expr) { 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 @@ fn walk_adjustment(&mut self, expr: &hir::Expr) { 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 @@ fn walk_autoderefs(&mut self, 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 @@ fn walk_autoderefref(&mut self, 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 @@ fn walk_autoref(&mut self, }; match *autoref { - ty::AutoPtr(r, m) => { + adjustment::AutoPtr(r, m) => { self.delegate.borrow(expr.id, expr.span, cmt_base, @@ -837,7 +838,7 @@ fn walk_autoref(&mut self, AutoRef); } - ty::AutoUnsafe(m) => { + adjustment::AutoUnsafe(m) => { debug!("walk_autoref: expr.id={} cmt_base={:?}", expr.id, cmt_base); diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index b9e9ee5e244..ffb631e105b 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -30,6 +30,7 @@ use middle::subst::Subst; use middle::traits::{self, FulfillmentContext, Normalized, SelectionContext, ObligationCause}; +use middle::ty::adjustment; use middle::ty::{TyVid, IntVid, FloatVid, RegionVid}; use middle::ty::{self, Ty, HasTypeFlags}; use middle::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; @@ -1151,7 +1152,7 @@ pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> ty::Region { /// Apply `adjustment` to the type of `expr` pub fn adjust_expr_ty(&self, expr: &hir::Expr, - adjustment: Option<&ty::AutoAdjustment<'tcx>>) + adjustment: Option<&adjustment::AutoAdjustment<'tcx>>) -> Ty<'tcx> { let raw_ty = self.expr_ty(expr); @@ -1485,9 +1486,9 @@ pub fn node_method_id(&self, method_call: ty::MethodCall) .map(|method| method.def_id) } - pub fn adjustments(&self) -> Ref>> { + pub fn adjustments(&self) -> Ref>> { fn project_adjustments<'a, 'tcx>(tables: &'a ty::Tables<'tcx>) - -> &'a NodeMap> { + -> &'a NodeMap> { &tables.adjustments } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 51005ef8b97..dd2f48d25b4 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -77,6 +77,7 @@ 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 @@ pub fn cat_expr(&self, expr: &hir::Expr) -> McResult> { Some(adjustment) => { match *adjustment { - ty::AdjustDerefRef( - ty::AutoDerefRef { + adjustment::AdjustDerefRef( + adjustment::AutoDerefRef { autoref: None, unsize: None, autoderefs, ..}) => { // Equivalent to *expr or something similar. self.cat_expr_autoderefd(expr, autoderefs) } - ty::AdjustReifyFnPointer | - ty::AdjustUnsafeFnPointer | - ty::AdjustDerefRef(_) => { + adjustment::AdjustReifyFnPointer | + adjustment::AdjustUnsafeFnPointer | + adjustment::AdjustDerefRef(_) => { debug!("cat_expr({:?}): {:?}", adjustment, expr); diff --git a/src/librustc/middle/ty/adjustment.rs b/src/librustc/middle/ty/adjustment.rs new file mode 100644 index 00000000000..cadab499c07 --- /dev/null +++ b/src/librustc/middle/ty/adjustment.rs @@ -0,0 +1,249 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use self::AutoAdjustment::*; +pub use self::AutoRef::*; + +use middle::ty::{self, Ty, TypeAndMut}; +use middle::ty::HasTypeFlags; +use middle::ty::LvaluePreference::{NoPreference}; + +use syntax::ast; +use syntax::codemap::Span; + +use rustc_front::hir; + +#[derive(Copy, Clone)] +pub enum AutoAdjustment<'tcx> { + AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type + AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer + AdjustDerefRef(AutoDerefRef<'tcx>), +} + +/// Represents coercing a pointer to a different kind of pointer - where 'kind' +/// here means either or both of raw vs borrowed vs unique and fat vs thin. +/// +/// We transform pointers by following the following steps in order: +/// 1. Deref the pointer `self.autoderefs` times (may be 0). +/// 2. If `autoref` is `Some(_)`, then take the address and produce either a +/// `&` or `*` pointer. +/// 3. If `unsize` is `Some(_)`, then apply the unsize transformation, +/// which will do things like convert thin pointers to fat +/// pointers, or convert structs containing thin pointers to +/// structs containing fat pointers, or convert between fat +/// pointers. We don't store the details of how the transform is +/// done (in fact, we don't know that, because it might depend on +/// the precise type parameters). We just store the target +/// type. Trans figures out what has to be done at monomorphization +/// time based on the precise source/target type at hand. +/// +/// To make that more concrete, here are some common scenarios: +/// +/// 1. The simplest cases are where the pointer is not adjusted fat vs thin. +/// Here the pointer will be dereferenced N times (where a dereference can +/// happen to to raw or borrowed pointers or any smart pointer which implements +/// Deref, including Box<_>). The number of dereferences is given by +/// `autoderefs`. It can then be auto-referenced zero or one times, indicated +/// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is +/// None. +/// +/// 2. A thin-to-fat coercon involves unsizing the underlying data. We start +/// with a thin pointer, deref a number of times, unsize the underlying data, +/// then autoref. The 'unsize' phase may change a fixed length array to a +/// dynamically sized one, a concrete object to a trait object, or statically +/// sized struct to a dyncamically sized one. E.g., &[i32; 4] -> &[i32] is +/// represented by: +/// +/// ``` +/// AutoDerefRef { +/// autoderefs: 1, // &[i32; 4] -> [i32; 4] +/// autoref: Some(AutoPtr), // [i32] -> &[i32] +/// unsize: Some([i32]), // [i32; 4] -> [i32] +/// } +/// ``` +/// +/// Note that for a struct, the 'deep' unsizing of the struct is not recorded. +/// E.g., `struct Foo { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]> +/// The autoderef and -ref are the same as in the above example, but the type +/// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about +/// the underlying conversions from `[i32; 4]` to `[i32]`. +/// +/// 3. Coercing a `Box` to `Box` is an interesting special case. In +/// that case, we have the pointer we need coming in, so there are no +/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation. +/// At some point, of course, `Box` should move out of the compiler, in which +/// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> -> +/// Box<[i32]> is represented by: +/// +/// ``` +/// AutoDerefRef { +/// autoderefs: 0, +/// autoref: None, +/// unsize: Some(Box<[i32]>), +/// } +/// ``` +#[derive(Copy, Clone)] +pub struct AutoDerefRef<'tcx> { + /// Step 1. Apply a number of dereferences, producing an lvalue. + pub autoderefs: usize, + + /// Step 2. Optionally produce a pointer/reference from the value. + pub autoref: Option>, + + /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to + /// `&[T]`. The stored type is the target pointer type. Note that + /// the source could be a thin or fat pointer. + pub unsize: Option>, +} + +impl<'tcx> AutoAdjustment<'tcx> { + pub fn is_identity(&self) -> bool { + match *self { + AdjustReifyFnPointer | + AdjustUnsafeFnPointer => false, + AdjustDerefRef(ref r) => r.is_identity(), + } + } +} +impl<'tcx> AutoDerefRef<'tcx> { + pub fn is_identity(&self) -> bool { + self.autoderefs == 0 && self.unsize.is_none() && self.autoref.is_none() + } +} + + +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum AutoRef<'tcx> { + /// Convert from T to &T. + AutoPtr(&'tcx ty::Region, hir::Mutability), + + /// Convert from T to *T. + /// Value to thin pointer. + AutoUnsafe(hir::Mutability), +} + +#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] +pub enum CustomCoerceUnsized { + /// Records the index of the field being coerced. + Struct(usize) +} + +impl<'tcx> ty::TyS<'tcx> { + /// See `expr_ty_adjusted` + pub fn adjust(&'tcx self, cx: &ty::ctxt<'tcx>, + span: Span, + expr_id: ast::NodeId, + adjustment: Option<&AutoAdjustment<'tcx>>, + mut method_type: F) + -> Ty<'tcx> where + F: FnMut(ty::MethodCall) -> Option>, + { + if let ty::TyError = self.sty { + return self; + } + + return match adjustment { + Some(adjustment) => { + match *adjustment { + AdjustReifyFnPointer => { + match self.sty { + ty::TyBareFn(Some(_), b) => { + cx.mk_fn(None, b) + } + _ => { + cx.sess.bug( + &format!("AdjustReifyFnPointer adjustment on non-fn-item: \ + {:?}", self)); + } + } + } + + AdjustUnsafeFnPointer => { + match self.sty { + ty::TyBareFn(None, b) => cx.safe_to_unsafe_fn_ty(b), + ref b => { + cx.sess.bug( + &format!("AdjustReifyFnPointer adjustment on non-fn-item: \ + {:?}", + b)); + } + } + } + + AdjustDerefRef(ref adj) => { + let mut adjusted_ty = self; + + if !adjusted_ty.references_error() { + for i in 0..adj.autoderefs { + adjusted_ty = + adjusted_ty.adjust_for_autoderef(cx, + expr_id, + span, + i as u32, + &mut method_type); + } + } + + if let Some(target) = adj.unsize { + target + } else { + adjusted_ty.adjust_for_autoref(cx, adj.autoref) + } + } + } + } + None => self + }; + } + + pub fn adjust_for_autoderef(&'tcx self, + cx: &ty::ctxt<'tcx>, + expr_id: ast::NodeId, + expr_span: Span, + autoderef: u32, // how many autoderefs so far? + mut method_type: F) + -> Ty<'tcx> where + F: FnMut(ty::MethodCall) -> Option>, + { + let method_call = ty::MethodCall::autoderef(expr_id, autoderef); + let mut adjusted_ty = self; + if let Some(method_ty) = method_type(method_call) { + // Method calls always have all late-bound regions + // fully instantiated. + let fn_ret = cx.no_late_bound_regions(&method_ty.fn_ret()).unwrap(); + adjusted_ty = fn_ret.unwrap(); + } + match adjusted_ty.builtin_deref(true, NoPreference) { + Some(mt) => mt.ty, + None => { + cx.sess.span_bug( + expr_span, + &format!("the {}th autoderef failed: {}", + autoderef, + adjusted_ty) + ); + } + } + } + + pub fn adjust_for_autoref(&'tcx self, cx: &ty::ctxt<'tcx>, + autoref: Option>) + -> Ty<'tcx> { + match autoref { + None => self, + Some(AutoPtr(r, m)) => { + cx.mk_ref(r, TypeAndMut { ty: self, mutbl: m }) + } + Some(AutoUnsafe(m)) => { + cx.mk_ptr(TypeAndMut { ty: self, mutbl: m }) + } + } + } +} diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs index 4d57e0980ef..e3b6da56680 100644 --- a/src/librustc/middle/ty/context.rs +++ b/src/librustc/middle/ty/context.rs @@ -106,7 +106,7 @@ pub struct Tables<'tcx> { /// other items. pub item_substs: NodeMap>, - pub adjustments: NodeMap>, + pub adjustments: NodeMap>, pub method_map: ty::MethodMap<'tcx>, @@ -308,7 +308,7 @@ pub struct ctxt<'tcx> { pub const_qualif_map: RefCell>, /// Caches CoerceUnsized kinds for impls on custom types. - pub custom_coerce_unsized_kinds: RefCell>, + pub custom_coerce_unsized_kinds: RefCell>, /// Maps a cast expression to its kind. This is keyed on the /// *from* expression of the cast, not the cast itself. diff --git a/src/librustc/middle/ty/fold.rs b/src/librustc/middle/ty/fold.rs index 9de58369a63..751bac28ce4 100644 --- a/src/librustc/middle/ty/fold.rs +++ b/src/librustc/middle/ty/fold.rs @@ -36,6 +36,7 @@ use middle::region; use middle::subst; +use middle::ty::adjustment; use middle::ty::{self, Binder, Ty, HasTypeFlags, RegionEscape}; use std::fmt; @@ -128,7 +129,8 @@ fn fold_existential_bounds(&mut self, s: &ty::ExistentialBounds<'tcx>) super_fold_existential_bounds(self, s) } - fn fold_autoref(&mut self, ar: &ty::AutoRef<'tcx>) -> ty::AutoRef<'tcx> { + fn fold_autoref(&mut self, ar: &adjustment::AutoRef<'tcx>) + -> adjustment::AutoRef<'tcx> { super_fold_autoref(self, ar) } @@ -296,15 +298,15 @@ pub fn super_fold_existential_bounds<'tcx, T: TypeFolder<'tcx>>( } pub fn super_fold_autoref<'tcx, T: TypeFolder<'tcx>>(this: &mut T, - autoref: &ty::AutoRef<'tcx>) - -> ty::AutoRef<'tcx> + autoref: &adjustment::AutoRef<'tcx>) + -> adjustment::AutoRef<'tcx> { match *autoref { - ty::AutoPtr(r, m) => { + adjustment::AutoPtr(r, m) => { let r = r.fold_with(this); - ty::AutoPtr(this.tcx().mk_region(r), m) + adjustment::AutoPtr(this.tcx().mk_region(r), m) } - ty::AutoUnsafe(m) => ty::AutoUnsafe(m) + adjustment::AutoUnsafe(m) => adjustment::AutoUnsafe(m) } } diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs index ab1160d7deb..dff423b35dd 100644 --- a/src/librustc/middle/ty/mod.rs +++ b/src/librustc/middle/ty/mod.rs @@ -11,30 +11,21 @@ pub use self::ImplOrTraitItemId::*; pub use self::ClosureKind::*; pub use self::Variance::*; -pub use self::AutoAdjustment::*; -pub use self::Representability::*; -pub use self::AutoRef::*; pub use self::DtorKind::*; pub use self::ExplicitSelfCategory::*; pub use self::ImplOrTraitItemContainer::*; pub use self::BorrowKind::*; pub use self::ImplOrTraitItem::*; pub use self::IntVarValue::*; -pub use self::CopyImplementationError::*; pub use self::LvaluePreference::*; -use back::svh::Svh; use front::map as ast_map; use front::map::LinkedPath; use metadata::csearch; use middle; -use middle::const_eval::{self, ConstVal, ErrKind}; -use middle::const_eval::EvalHint::UncheckedExprHint; use middle::def::{self, ExportMap}; use middle::def_id::{DefId, LOCAL_CRATE}; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; -use middle::infer; -use middle::pat_util; use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace}; use middle::traits; use middle::ty; @@ -43,12 +34,10 @@ use util::common::memoized; use util::nodemap::{NodeMap, NodeSet, DefIdMap}; use util::nodemap::FnvHashMap; -use util::num::ToPrimitive; use std::borrow::{Borrow, Cow}; use std::cell::{Cell, RefCell}; -use std::cmp; -use std::hash::{Hash, SipHasher, Hasher}; +use std::hash::{Hash, Hasher}; use std::iter; use std::rc::Rc; use std::slice; @@ -61,7 +50,7 @@ use rustc_front::hir; use rustc_front::hir::{ItemImpl, ItemTrait}; use rustc_front::hir::{MutImmutable, MutMutable, Visibility}; -use rustc_front::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt}; +use rustc_front::attr::{self, AttrMetaMethods}; pub use self::sty::{Binder, DebruijnIndex}; pub use self::sty::{BuiltinBound, BuiltinBounds, ExistentialBounds}; @@ -86,6 +75,7 @@ pub use self::context::{ctxt, tls}; pub use self::context::{CtxtArenas, Lift, Tables}; +pub mod adjustment; pub mod cast; pub mod error; pub mod fast_reject; @@ -95,6 +85,7 @@ pub mod relate; pub mod walk; pub mod wf; +pub mod util; mod contents; mod context; @@ -104,7 +95,6 @@ mod sty; pub type Disr = u64; - pub const INITIAL_DISCRIMINANT_VALUE: Disr = 0; // Data types @@ -143,126 +133,6 @@ pub fn has_drop_flag(&self) -> bool { } } -pub trait IntTypeExt { - fn to_ty<'tcx>(&self, cx: &ctxt<'tcx>) -> Ty<'tcx>; - fn i64_to_disr(&self, val: i64) -> Option; - fn u64_to_disr(&self, val: u64) -> Option; - fn disr_incr(&self, val: Disr) -> Option; - fn disr_string(&self, val: Disr) -> String; - fn disr_wrap_incr(&self, val: Option) -> Disr; -} - -impl IntTypeExt for attr::IntType { - fn to_ty<'tcx>(&self, cx: &ctxt<'tcx>) -> Ty<'tcx> { - match *self { - SignedInt(hir::TyI8) => cx.types.i8, - SignedInt(hir::TyI16) => cx.types.i16, - SignedInt(hir::TyI32) => cx.types.i32, - SignedInt(hir::TyI64) => cx.types.i64, - SignedInt(hir::TyIs) => cx.types.isize, - UnsignedInt(hir::TyU8) => cx.types.u8, - UnsignedInt(hir::TyU16) => cx.types.u16, - UnsignedInt(hir::TyU32) => cx.types.u32, - UnsignedInt(hir::TyU64) => cx.types.u64, - UnsignedInt(hir::TyUs) => cx.types.usize, - } - } - - fn i64_to_disr(&self, val: i64) -> Option { - match *self { - SignedInt(hir::TyI8) => val.to_i8() .map(|v| v as Disr), - SignedInt(hir::TyI16) => val.to_i16() .map(|v| v as Disr), - SignedInt(hir::TyI32) => val.to_i32() .map(|v| v as Disr), - SignedInt(hir::TyI64) => val.to_i64() .map(|v| v as Disr), - UnsignedInt(hir::TyU8) => val.to_u8() .map(|v| v as Disr), - UnsignedInt(hir::TyU16) => val.to_u16() .map(|v| v as Disr), - UnsignedInt(hir::TyU32) => val.to_u32() .map(|v| v as Disr), - UnsignedInt(hir::TyU64) => val.to_u64() .map(|v| v as Disr), - - UnsignedInt(hir::TyUs) | - SignedInt(hir::TyIs) => unreachable!(), - } - } - - fn u64_to_disr(&self, val: u64) -> Option { - match *self { - SignedInt(hir::TyI8) => val.to_i8() .map(|v| v as Disr), - SignedInt(hir::TyI16) => val.to_i16() .map(|v| v as Disr), - SignedInt(hir::TyI32) => val.to_i32() .map(|v| v as Disr), - SignedInt(hir::TyI64) => val.to_i64() .map(|v| v as Disr), - UnsignedInt(hir::TyU8) => val.to_u8() .map(|v| v as Disr), - UnsignedInt(hir::TyU16) => val.to_u16() .map(|v| v as Disr), - UnsignedInt(hir::TyU32) => val.to_u32() .map(|v| v as Disr), - UnsignedInt(hir::TyU64) => val.to_u64() .map(|v| v as Disr), - - UnsignedInt(hir::TyUs) | - SignedInt(hir::TyIs) => unreachable!(), - } - } - - fn disr_incr(&self, val: Disr) -> Option { - macro_rules! add1 { - ($e:expr) => { $e.and_then(|v|v.checked_add(1)).map(|v| v as Disr) } - } - match *self { - // SignedInt repr means we *want* to reinterpret the bits - // treating the highest bit of Disr as a sign-bit, so - // cast to i64 before range-checking. - SignedInt(hir::TyI8) => add1!((val as i64).to_i8()), - SignedInt(hir::TyI16) => add1!((val as i64).to_i16()), - SignedInt(hir::TyI32) => add1!((val as i64).to_i32()), - SignedInt(hir::TyI64) => add1!(Some(val as i64)), - - UnsignedInt(hir::TyU8) => add1!(val.to_u8()), - UnsignedInt(hir::TyU16) => add1!(val.to_u16()), - UnsignedInt(hir::TyU32) => add1!(val.to_u32()), - UnsignedInt(hir::TyU64) => add1!(Some(val)), - - UnsignedInt(hir::TyUs) | - SignedInt(hir::TyIs) => unreachable!(), - } - } - - // This returns a String because (1.) it is only used for - // rendering an error message and (2.) a string can represent the - // full range from `i64::MIN` through `u64::MAX`. - fn disr_string(&self, val: Disr) -> String { - match *self { - SignedInt(hir::TyI8) => format!("{}", val as i8 ), - SignedInt(hir::TyI16) => format!("{}", val as i16), - SignedInt(hir::TyI32) => format!("{}", val as i32), - SignedInt(hir::TyI64) => format!("{}", val as i64), - UnsignedInt(hir::TyU8) => format!("{}", val as u8 ), - UnsignedInt(hir::TyU16) => format!("{}", val as u16), - UnsignedInt(hir::TyU32) => format!("{}", val as u32), - UnsignedInt(hir::TyU64) => format!("{}", val as u64), - - UnsignedInt(hir::TyUs) | - SignedInt(hir::TyIs) => unreachable!(), - } - } - - fn disr_wrap_incr(&self, val: Option) -> Disr { - macro_rules! add1 { - ($e:expr) => { ($e).wrapping_add(1) as Disr } - } - let val = val.unwrap_or(ty::INITIAL_DISCRIMINANT_VALUE); - match *self { - SignedInt(hir::TyI8) => add1!(val as i8 ), - SignedInt(hir::TyI16) => add1!(val as i16), - SignedInt(hir::TyI32) => add1!(val as i32), - SignedInt(hir::TyI64) => add1!(val as i64), - UnsignedInt(hir::TyU8) => add1!(val as u8 ), - UnsignedInt(hir::TyU16) => add1!(val as u16), - UnsignedInt(hir::TyU32) => add1!(val as u32), - UnsignedInt(hir::TyU64) => add1!(val as u64), - - UnsignedInt(hir::TyUs) | - SignedInt(hir::TyIs) => unreachable!(), - } - } -} - #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum ImplOrTraitItemContainer { TraitContainer(DefId), @@ -435,105 +305,6 @@ pub enum Variance { Bivariant, // T <: T -- e.g., unused type parameter } -#[derive(Copy, Clone)] -pub enum AutoAdjustment<'tcx> { - AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type - AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer - AdjustDerefRef(AutoDerefRef<'tcx>), -} - -/// Represents coercing a pointer to a different kind of pointer - where 'kind' -/// here means either or both of raw vs borrowed vs unique and fat vs thin. -/// -/// We transform pointers by following the following steps in order: -/// 1. Deref the pointer `self.autoderefs` times (may be 0). -/// 2. If `autoref` is `Some(_)`, then take the address and produce either a -/// `&` or `*` pointer. -/// 3. If `unsize` is `Some(_)`, then apply the unsize transformation, -/// which will do things like convert thin pointers to fat -/// pointers, or convert structs containing thin pointers to -/// structs containing fat pointers, or convert between fat -/// pointers. We don't store the details of how the transform is -/// done (in fact, we don't know that, because it might depend on -/// the precise type parameters). We just store the target -/// type. Trans figures out what has to be done at monomorphization -/// time based on the precise source/target type at hand. -/// -/// To make that more concrete, here are some common scenarios: -/// -/// 1. The simplest cases are where the pointer is not adjusted fat vs thin. -/// Here the pointer will be dereferenced N times (where a dereference can -/// happen to to raw or borrowed pointers or any smart pointer which implements -/// Deref, including Box<_>). The number of dereferences is given by -/// `autoderefs`. It can then be auto-referenced zero or one times, indicated -/// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is -/// None. -/// -/// 2. A thin-to-fat coercon involves unsizing the underlying data. We start -/// with a thin pointer, deref a number of times, unsize the underlying data, -/// then autoref. The 'unsize' phase may change a fixed length array to a -/// dynamically sized one, a concrete object to a trait object, or statically -/// sized struct to a dyncamically sized one. E.g., &[i32; 4] -> &[i32] is -/// represented by: -/// -/// ``` -/// AutoDerefRef { -/// autoderefs: 1, // &[i32; 4] -> [i32; 4] -/// autoref: Some(AutoPtr), // [i32] -> &[i32] -/// unsize: Some([i32]), // [i32; 4] -> [i32] -/// } -/// ``` -/// -/// Note that for a struct, the 'deep' unsizing of the struct is not recorded. -/// E.g., `struct Foo { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]> -/// The autoderef and -ref are the same as in the above example, but the type -/// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about -/// the underlying conversions from `[i32; 4]` to `[i32]`. -/// -/// 3. Coercing a `Box` to `Box` is an interesting special case. In -/// that case, we have the pointer we need coming in, so there are no -/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation. -/// At some point, of course, `Box` should move out of the compiler, in which -/// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> -> -/// Box<[i32]> is represented by: -/// -/// ``` -/// AutoDerefRef { -/// autoderefs: 0, -/// autoref: None, -/// unsize: Some(Box<[i32]>), -/// } -/// ``` -#[derive(Copy, Clone)] -pub struct AutoDerefRef<'tcx> { - /// Step 1. Apply a number of dereferences, producing an lvalue. - pub autoderefs: usize, - - /// Step 2. Optionally produce a pointer/reference from the value. - pub autoref: Option>, - - /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to - /// `&[T]`. The stored type is the target pointer type. Note that - /// the source could be a thin or fat pointer. - pub unsize: Option>, -} - -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum AutoRef<'tcx> { - /// Convert from T to &T. - AutoPtr(&'tcx Region, hir::Mutability), - - /// Convert from T to *T. - /// Value to thin pointer. - AutoUnsafe(hir::Mutability), -} - -#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] -pub enum CustomCoerceUnsized { - /// Records the index of the field being coerced. - Struct(usize) -} - #[derive(Clone, Copy, Debug)] pub struct MethodCallee<'tcx> { /// Impl method ID, for inherent methods, or trait method ID, otherwise. @@ -1502,52 +1273,6 @@ pub fn for_item(cx: &'a ctxt<'tcx>, id: NodeId) -> ParameterEnvironment<'a, 'tcx } } } - - pub fn can_type_implement_copy(&self, self_type: Ty<'tcx>, span: Span) - -> Result<(),CopyImplementationError> { - let tcx = self.tcx; - - // FIXME: (@jroesch) float this code up - let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(self.clone()), false); - - let adt = match self_type.sty { - ty::TyStruct(struct_def, substs) => { - for field in struct_def.all_fields() { - let field_ty = field.ty(tcx, substs); - if infcx.type_moves_by_default(field_ty, span) { - return Err(FieldDoesNotImplementCopy(field.name)) - } - } - struct_def - } - ty::TyEnum(enum_def, substs) => { - for variant in &enum_def.variants { - for field in &variant.fields { - let field_ty = field.ty(tcx, substs); - if infcx.type_moves_by_default(field_ty, span) { - return Err(VariantDoesNotImplementCopy(variant.name)) - } - } - } - enum_def - } - _ => return Err(TypeIsStructural), - }; - - if adt.has_dtor() { - return Err(TypeHasDestructor) - } - - Ok(()) - } -} - -#[derive(Copy, Clone)] -pub enum CopyImplementationError { - FieldDoesNotImplementCopy(Name), - VariantDoesNotImplementCopy(Name), - TypeIsStructural, - TypeHasDestructor, } /// A "type scheme", in ML terminology, is a type combined with some @@ -2093,16 +1818,6 @@ pub fn extends(self, other: ty::ClosureKind) -> bool { } } -impl<'tcx> ctxt<'tcx> { - pub fn pat_contains_ref_binding(&self, pat: &hir::Pat) -> Option { - pat_util::pat_contains_ref_binding(&self.def_map, pat) - } - - pub fn arm_contains_ref_binding(&self, arm: &hir::Arm) -> Option { - pat_util::arm_contains_ref_binding(&self.def_map, arm) - } -} - impl<'tcx> TyS<'tcx> { /// Iterator that walks `self` and any types reachable from /// `self`, in depth-first order. Note that just walks the types @@ -2125,63 +1840,6 @@ pub fn walk_shallow(&'tcx self) -> IntoIter> { walk::walk_shallow(self) } - pub fn as_opt_param_ty(&self) -> Option { - match self.sty { - ty::TyParam(ref d) => Some(d.clone()), - _ => None, - } - } - - pub fn is_param(&self, space: ParamSpace, index: u32) -> bool { - match self.sty { - ty::TyParam(ref data) => data.space == space && data.idx == index, - _ => false, - } - } - - /// Returns the regions directly referenced from this type (but - /// not types reachable from this type via `walk_tys`). This - /// ignores late-bound regions binders. - pub fn regions(&self) -> Vec { - match self.sty { - TyRef(region, _) => { - vec![*region] - } - TyTrait(ref obj) => { - let mut v = vec![obj.bounds.region_bound]; - v.push_all(obj.principal.skip_binder().substs.regions().as_slice()); - v - } - TyEnum(_, substs) | - TyStruct(_, substs) => { - substs.regions().as_slice().to_vec() - } - TyClosure(_, ref substs) => { - substs.func_substs.regions().as_slice().to_vec() - } - TyProjection(ref data) => { - data.trait_ref.substs.regions().as_slice().to_vec() - } - TyBareFn(..) | - TyBool | - TyChar | - TyInt(_) | - TyUint(_) | - TyFloat(_) | - TyBox(_) | - TyStr | - TyArray(_, _) | - TySlice(_) | - TyRawPtr(_) | - TyTuple(_) | - TyParam(_) | - TyInfer(_) | - TyError => { - vec![] - } - } - } - /// Walks `ty` and any types appearing within `ty`, invoking the /// callback `f` on each type. If the callback returns false, then the /// children of the current type are ignored. @@ -2199,31 +1857,6 @@ pub fn maybe_walk(&'tcx self, mut f: F) } } -impl ParamTy { - pub fn new(space: subst::ParamSpace, - index: u32, - name: Name) - -> ParamTy { - ParamTy { space: space, idx: index, name: name } - } - - pub fn for_self() -> ParamTy { - ParamTy::new(subst::SelfSpace, 0, special_idents::type_self.name) - } - - pub fn for_def(def: &TypeParameterDef) -> ParamTy { - ParamTy::new(def.space, def.index, def.name) - } - - pub fn to_ty<'tcx>(self, tcx: &ctxt<'tcx>) -> Ty<'tcx> { - tcx.mk_param(self.space, self.idx, self.name) - } - - pub fn is_self(&self) -> bool { - self.space == subst::SelfSpace && self.idx == 0 - } -} - impl<'tcx> ItemSubsts<'tcx> { pub fn empty() -> ItemSubsts<'tcx> { ItemSubsts { substs: Substs::empty() } @@ -2234,99 +1867,6 @@ pub fn is_noop(&self) -> bool { } } -impl<'tcx> TyS<'tcx> { - fn impls_bound<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, - bound: ty::BuiltinBound, - span: Span) - -> bool - { - let tcx = param_env.tcx; - let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env.clone()), false); - - let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, - self, bound, span); - - debug!("Ty::impls_bound({:?}, {:?}) = {:?}", - self, bound, is_impld); - - is_impld - } - - // FIXME (@jroesch): I made this public to use it, not sure if should be private - pub fn moves_by_default<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, - span: Span) -> bool { - if self.flags.get().intersects(TypeFlags::MOVENESS_CACHED) { - return self.flags.get().intersects(TypeFlags::MOVES_BY_DEFAULT); - } - - assert!(!self.needs_infer()); - - // Fast-path for primitive types - let result = match self.sty { - TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | - TyRawPtr(..) | TyBareFn(..) | TyRef(_, TypeAndMut { - mutbl: hir::MutImmutable, .. - }) => Some(false), - - TyStr | TyBox(..) | TyRef(_, TypeAndMut { - mutbl: hir::MutMutable, .. - }) => Some(true), - - TyArray(..) | TySlice(_) | TyTrait(..) | TyTuple(..) | - TyClosure(..) | TyEnum(..) | TyStruct(..) | - TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None - }.unwrap_or_else(|| !self.impls_bound(param_env, ty::BoundCopy, span)); - - if !self.has_param_types() && !self.has_self_ty() { - self.flags.set(self.flags.get() | if result { - TypeFlags::MOVENESS_CACHED | TypeFlags::MOVES_BY_DEFAULT - } else { - TypeFlags::MOVENESS_CACHED - }); - } - - result - } - - #[inline] - pub fn is_sized<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, - span: Span) -> bool - { - if self.flags.get().intersects(TypeFlags::SIZEDNESS_CACHED) { - return self.flags.get().intersects(TypeFlags::IS_SIZED); - } - - self.is_sized_uncached(param_env, span) - } - - fn is_sized_uncached<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, - span: Span) -> bool { - assert!(!self.needs_infer()); - - // Fast-path for primitive types - let result = match self.sty { - TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | - TyBox(..) | TyRawPtr(..) | TyRef(..) | TyBareFn(..) | - TyArray(..) | TyTuple(..) | TyClosure(..) => Some(true), - - TyStr | TyTrait(..) | TySlice(_) => Some(false), - - TyEnum(..) | TyStruct(..) | TyProjection(..) | TyParam(..) | - TyInfer(..) | TyError => None - }.unwrap_or_else(|| self.impls_bound(param_env, ty::BoundSized, span)); - - if !self.has_param_types() && !self.has_self_ty() { - self.flags.set(self.flags.get() | if result { - TypeFlags::SIZEDNESS_CACHED | TypeFlags::IS_SIZED - } else { - TypeFlags::SIZEDNESS_CACHED - }); - } - - result - } -} - #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum LvaluePreference { PreferMutLvalue, @@ -2342,283 +1882,6 @@ pub fn from_mutbl(m: hir::Mutability) -> Self { } } -/// Describes whether a type is representable. For types that are not -/// representable, 'SelfRecursive' and 'ContainsRecursive' are used to -/// distinguish between types that are recursive with themselves and types that -/// contain a different recursive type. These cases can therefore be treated -/// differently when reporting errors. -/// -/// The ordering of the cases is significant. They are sorted so that cmp::max -/// will keep the "more erroneous" of two values. -#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Debug)] -pub enum Representability { - Representable, - ContainsRecursive, - SelfRecursive, -} - -impl<'tcx> TyS<'tcx> { - /// Check whether a type is representable. This means it cannot contain unboxed - /// structural recursion. This check is needed for structs and enums. - pub fn is_representable(&'tcx self, cx: &ctxt<'tcx>, sp: Span) -> Representability { - - // Iterate until something non-representable is found - fn find_nonrepresentable<'tcx, It: Iterator>>(cx: &ctxt<'tcx>, sp: Span, - seen: &mut Vec>, - iter: It) - -> Representability { - iter.fold(Representable, - |r, ty| cmp::max(r, is_type_structurally_recursive(cx, sp, seen, ty))) - } - - fn are_inner_types_recursive<'tcx>(cx: &ctxt<'tcx>, sp: Span, - seen: &mut Vec>, ty: Ty<'tcx>) - -> Representability { - match ty.sty { - TyTuple(ref ts) => { - find_nonrepresentable(cx, sp, seen, ts.iter().cloned()) - } - // Fixed-length vectors. - // FIXME(#11924) Behavior undecided for zero-length vectors. - TyArray(ty, _) => { - is_type_structurally_recursive(cx, sp, seen, ty) - } - TyStruct(def, substs) | TyEnum(def, substs) => { - find_nonrepresentable(cx, - sp, - seen, - def.all_fields().map(|f| f.ty(cx, substs))) - } - TyClosure(..) => { - // this check is run on type definitions, so we don't expect - // to see closure types - cx.sess.bug(&format!("requires check invoked on inapplicable type: {:?}", ty)) - } - _ => Representable, - } - } - - fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: AdtDef<'tcx>) -> bool { - match ty.sty { - TyStruct(ty_def, _) | TyEnum(ty_def, _) => { - ty_def == def - } - _ => false - } - } - - fn same_type<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - match (&a.sty, &b.sty) { - (&TyStruct(did_a, ref substs_a), &TyStruct(did_b, ref substs_b)) | - (&TyEnum(did_a, ref substs_a), &TyEnum(did_b, ref substs_b)) => { - if did_a != did_b { - return false; - } - - let types_a = substs_a.types.get_slice(subst::TypeSpace); - let types_b = substs_b.types.get_slice(subst::TypeSpace); - - let mut pairs = types_a.iter().zip(types_b); - - pairs.all(|(&a, &b)| same_type(a, b)) - } - _ => { - a == b - } - } - } - - // Does the type `ty` directly (without indirection through a pointer) - // contain any types on stack `seen`? - fn is_type_structurally_recursive<'tcx>(cx: &ctxt<'tcx>, sp: Span, - seen: &mut Vec>, - ty: Ty<'tcx>) -> Representability { - debug!("is_type_structurally_recursive: {:?}", ty); - - match ty.sty { - TyStruct(def, _) | TyEnum(def, _) => { - { - // Iterate through stack of previously seen types. - let mut iter = seen.iter(); - - // The first item in `seen` is the type we are actually curious about. - // We want to return SelfRecursive if this type contains itself. - // It is important that we DON'T take generic parameters into account - // for this check, so that Bar in this example counts as SelfRecursive: - // - // struct Foo; - // struct Bar { x: Bar } - - match iter.next() { - Some(&seen_type) => { - if same_struct_or_enum(seen_type, def) { - debug!("SelfRecursive: {:?} contains {:?}", - seen_type, - ty); - return SelfRecursive; - } - } - None => {} - } - - // We also need to know whether the first item contains other types - // that are structurally recursive. If we don't catch this case, we - // will recurse infinitely for some inputs. - // - // It is important that we DO take generic parameters into account - // here, so that code like this is considered SelfRecursive, not - // ContainsRecursive: - // - // struct Foo { Option> } - - for &seen_type in iter { - if same_type(ty, seen_type) { - debug!("ContainsRecursive: {:?} contains {:?}", - seen_type, - ty); - return ContainsRecursive; - } - } - } - - // For structs and enums, track all previously seen types by pushing them - // onto the 'seen' stack. - seen.push(ty); - let out = are_inner_types_recursive(cx, sp, seen, ty); - seen.pop(); - out - } - _ => { - // No need to push in other cases. - are_inner_types_recursive(cx, sp, seen, ty) - } - } - } - - debug!("is_type_representable: {:?}", self); - - // To avoid a stack overflow when checking an enum variant or struct that - // contains a different, structurally recursive type, maintain a stack - // of seen types and check recursion for each of them (issues #3008, #3779). - let mut seen: Vec = Vec::new(); - let r = is_type_structurally_recursive(cx, sp, &mut seen, self); - debug!("is_type_representable: {:?} is {:?}", self, r); - r - } - - /// See `expr_ty_adjusted` - pub fn adjust(&'tcx self, cx: &ctxt<'tcx>, - span: Span, - expr_id: NodeId, - adjustment: Option<&AutoAdjustment<'tcx>>, - mut method_type: F) - -> Ty<'tcx> where - F: FnMut(MethodCall) -> Option>, - { - if let TyError = self.sty { - return self; - } - - return match adjustment { - Some(adjustment) => { - match *adjustment { - AdjustReifyFnPointer => { - match self.sty { - ty::TyBareFn(Some(_), b) => { - cx.mk_fn(None, b) - } - _ => { - cx.sess.bug( - &format!("AdjustReifyFnPointer adjustment on non-fn-item: \ - {:?}", self)); - } - } - } - - AdjustUnsafeFnPointer => { - match self.sty { - ty::TyBareFn(None, b) => cx.safe_to_unsafe_fn_ty(b), - ref b => { - cx.sess.bug( - &format!("AdjustReifyFnPointer adjustment on non-fn-item: \ - {:?}", - b)); - } - } - } - - AdjustDerefRef(ref adj) => { - let mut adjusted_ty = self; - - if !adjusted_ty.references_error() { - for i in 0..adj.autoderefs { - adjusted_ty = - adjusted_ty.adjust_for_autoderef(cx, - expr_id, - span, - i as u32, - &mut method_type); - } - } - - if let Some(target) = adj.unsize { - target - } else { - adjusted_ty.adjust_for_autoref(cx, adj.autoref) - } - } - } - } - None => self - }; - } - - pub fn adjust_for_autoderef(&'tcx self, - cx: &ctxt<'tcx>, - expr_id: ast::NodeId, - expr_span: Span, - autoderef: u32, // how many autoderefs so far? - mut method_type: F) - -> Ty<'tcx> where - F: FnMut(MethodCall) -> Option>, - { - let method_call = MethodCall::autoderef(expr_id, autoderef); - let mut adjusted_ty = self; - if let Some(method_ty) = method_type(method_call) { - // Method calls always have all late-bound regions - // fully instantiated. - let fn_ret = cx.no_late_bound_regions(&method_ty.fn_ret()).unwrap(); - adjusted_ty = fn_ret.unwrap(); - } - match adjusted_ty.builtin_deref(true, NoPreference) { - Some(mt) => mt.ty, - None => { - cx.sess.span_bug( - expr_span, - &format!("the {}th autoderef failed: {}", - autoderef, - adjusted_ty) - ); - } - } - } - - pub fn adjust_for_autoref(&'tcx self, cx: &ctxt<'tcx>, - autoref: Option>) - -> Ty<'tcx> { - match autoref { - None => self, - Some(AutoPtr(r, m)) => { - cx.mk_ref(r, TypeAndMut { ty: self, mutbl: m }) - } - Some(AutoUnsafe(m)) => { - cx.mk_ptr(TypeAndMut { ty: self, mutbl: m }) - } - } - } - -} - /// Helper for looking things up in the various maps that are populated during /// typeck::collect (e.g., `cx.impl_or_trait_items`, `cx.tcache`, etc). All of /// these share the pattern that if the id is local, it should have been loaded @@ -2679,45 +1942,6 @@ pub fn to_user_str(&self) -> &'static str { } impl<'tcx> ctxt<'tcx> { - /// Returns the type of element at index `i` in tuple or tuple-like type `t`. - /// For an enum `t`, `variant` is None only if `t` is a univariant enum. - pub fn positional_element_ty(&self, - ty: Ty<'tcx>, - i: usize, - variant: Option) -> Option> { - match (&ty.sty, variant) { - (&TyStruct(def, substs), None) => { - def.struct_variant().fields.get(i).map(|f| f.ty(self, substs)) - } - (&TyEnum(def, substs), Some(vid)) => { - def.variant_with_id(vid).fields.get(i).map(|f| f.ty(self, substs)) - } - (&TyEnum(def, substs), None) => { - assert!(def.is_univariant()); - def.variants[0].fields.get(i).map(|f| f.ty(self, substs)) - } - (&TyTuple(ref v), None) => v.get(i).cloned(), - _ => None - } - } - - /// Returns the type of element at field `n` in struct or struct-like type `t`. - /// For an enum `t`, `variant` must be some def id. - pub fn named_element_ty(&self, - ty: Ty<'tcx>, - n: Name, - variant: Option) -> Option> { - match (&ty.sty, variant) { - (&TyStruct(def, substs), None) => { - def.struct_variant().find_field_named(n).map(|f| f.ty(self, substs)) - } - (&TyEnum(def, substs), Some(vid)) => { - def.variant_with_id(vid).find_field_named(n).map(|f| f.ty(self, substs)) - } - _ => return None - } - } - pub fn node_id_to_type(&self, id: NodeId) -> Ty<'tcx> { match self.node_id_to_type_opt(id) { Some(ty) => ty, @@ -2992,7 +2216,7 @@ pub fn trait_impl_polarity(&self, id: DefId) -> Option { } } - pub fn custom_coerce_unsized_kind(&self, did: DefId) -> CustomCoerceUnsized { + pub fn custom_coerce_unsized_kind(&self, did: DefId) -> adjustment::CustomCoerceUnsized { memoized(&self.custom_coerce_unsized_kinds, did, |did: DefId| { let (kind, src) = if did.krate != LOCAL_CRATE { (csearch::get_custom_coerce_unsized_kind(self, did), "external") @@ -3071,35 +2295,6 @@ pub fn item_name(&self, id: DefId) -> ast::Name { } } - /// Returns `(normalized_type, ty)`, where `normalized_type` is the - /// IntType representation of one of {i64,i32,i16,i8,u64,u32,u16,u8}, - /// and `ty` is the original type (i.e. may include `isize` or - /// `usize`). - pub fn enum_repr_type(&self, opt_hint: Option<&attr::ReprAttr>) - -> (attr::IntType, Ty<'tcx>) { - let repr_type = match opt_hint { - // Feed in the given type - Some(&attr::ReprInt(_, int_t)) => int_t, - // ... but provide sensible default if none provided - // - // NB. Historically `fn enum_variants` generate i64 here, while - // rustc_typeck::check would generate isize. - _ => SignedInt(hir::TyIs), - }; - - let repr_type_ty = repr_type.to_ty(self); - let repr_type = match repr_type { - SignedInt(hir::TyIs) => - SignedInt(self.sess.target.int_type), - UnsignedInt(hir::TyUs) => - UnsignedInt(self.sess.target.uint_type), - other => other - }; - - (repr_type, repr_type_ty) - } - - // Register a given item type pub fn register_item_type(&self, did: DefId, ty: TypeScheme<'tcx>) { self.tcache.borrow_mut().insert(did, ty); @@ -3195,155 +2390,6 @@ pub fn lookup_repr_hints(&self, did: DefId) -> Rc> { }) } - - /// Returns the deeply last field of nested structures, or the same type, - /// if not a structure at all. Corresponds to the only possible unsized - /// field, and its type can be used to determine unsizing strategy. - pub fn struct_tail(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { - while let TyStruct(def, substs) = ty.sty { - match def.struct_variant().fields.last() { - Some(f) => ty = f.ty(self, substs), - None => break - } - } - ty - } - - /// Same as applying struct_tail on `source` and `target`, but only - /// keeps going as long as the two types are instances of the same - /// structure definitions. - /// For `(Foo>, Foo)`, the result will be `(Foo, Trait)`, - /// whereas struct_tail produces `T`, and `Trait`, respectively. - pub fn struct_lockstep_tails(&self, - source: Ty<'tcx>, - target: Ty<'tcx>) - -> (Ty<'tcx>, Ty<'tcx>) { - let (mut a, mut b) = (source, target); - while let (&TyStruct(a_def, a_substs), &TyStruct(b_def, b_substs)) = (&a.sty, &b.sty) { - if a_def != b_def { - break; - } - if let Some(f) = a_def.struct_variant().fields.last() { - a = f.ty(self, a_substs); - b = f.ty(self, b_substs); - } else { - break; - } - } - (a, b) - } - - // Returns the repeat count for a repeating vector expression. - pub fn eval_repeat_count(&self, count_expr: &hir::Expr) -> usize { - let hint = UncheckedExprHint(self.types.usize); - match const_eval::eval_const_expr_partial(self, count_expr, hint) { - Ok(val) => { - let found = match val { - ConstVal::Uint(count) => return count as usize, - ConstVal::Int(count) if count >= 0 => return count as usize, - const_val => const_val.description(), - }; - span_err!(self.sess, count_expr.span, E0306, - "expected positive integer for repeat count, found {}", - found); - } - Err(err) => { - let err_msg = match count_expr.node { - hir::ExprPath(None, hir::Path { - global: false, - ref segments, - .. - }) if segments.len() == 1 => - format!("found variable"), - _ => match err.kind { - ErrKind::MiscCatchAll => format!("but found {}", err.description()), - _ => format!("but {}", err.description()) - } - }; - span_err!(self.sess, count_expr.span, E0307, - "expected constant integer for repeat count, {}", err_msg); - } - } - 0 - } - - // Iterate over a type parameter's bounded traits and any supertraits - // of those traits, ignoring kinds. - // Here, the supertraits are the transitive closure of the supertrait - // relation on the supertraits from each bounded trait's constraint - // list. - pub fn each_bound_trait_and_supertraits(&self, - bounds: &[PolyTraitRef<'tcx>], - mut f: F) - -> bool where - F: FnMut(PolyTraitRef<'tcx>) -> bool, - { - for bound_trait_ref in traits::transitive_bounds(self, bounds) { - if !f(bound_trait_ref) { - return false; - } - } - return true; - } - - /// Given a set of predicates that apply to an object type, returns - /// the region bounds that the (erased) `Self` type must - /// outlive. Precisely *because* the `Self` type is erased, the - /// parameter `erased_self_ty` must be supplied to indicate what type - /// has been used to represent `Self` in the predicates - /// themselves. This should really be a unique type; `FreshTy(0)` is a - /// popular choice. - /// - /// NB: in some cases, particularly around higher-ranked bounds, - /// this function returns a kind of conservative approximation. - /// That is, all regions returned by this function are definitely - /// required, but there may be other region bounds that are not - /// returned, as well as requirements like `for<'a> T: 'a`. - /// - /// Requires that trait definitions have been processed so that we can - /// elaborate predicates and walk supertraits. - pub fn required_region_bounds(&self, - erased_self_ty: Ty<'tcx>, - predicates: Vec>) - -> Vec { - debug!("required_region_bounds(erased_self_ty={:?}, predicates={:?})", - erased_self_ty, - predicates); - - assert!(!erased_self_ty.has_escaping_regions()); - - traits::elaborate_predicates(self, predicates) - .filter_map(|predicate| { - match predicate { - ty::Predicate::Projection(..) | - ty::Predicate::Trait(..) | - ty::Predicate::Equate(..) | - ty::Predicate::WellFormed(..) | - ty::Predicate::ObjectSafe(..) | - ty::Predicate::RegionOutlives(..) => { - None - } - ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t, r))) => { - // Search for a bound of the form `erased_self_ty - // : 'a`, but be wary of something like `for<'a> - // erased_self_ty : 'a` (we interpret a - // higher-ranked bound like that as 'static, - // though at present the code in `fulfill.rs` - // considers such bounds to be unsatisfiable, so - // it's kind of a moot point since you could never - // construct such an object, but this seems - // correct even if that code changes). - if t == erased_self_ty && !r.has_escaping_regions() { - Some(r) - } else { - None - } - } - } - }) - .collect() - } - pub fn item_variances(&self, item_id: DefId) -> Rc { lookup_locally_or_in_crate_store( "item_variance_map", item_id, &self.item_variance_map, @@ -3527,148 +2573,6 @@ pub fn trait_item_of_item(&self, def_id: DefId) -> Option { } } - /// Creates a hash of the type `Ty` which will be the same no matter what crate - /// context it's calculated within. This is used by the `type_id` intrinsic. - pub fn hash_crate_independent(&self, ty: Ty<'tcx>, svh: &Svh) -> u64 { - let mut state = SipHasher::new(); - helper(self, ty, svh, &mut state); - return state.finish(); - - fn helper<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh, - state: &mut SipHasher) { - macro_rules! byte { ($b:expr) => { ($b as u8).hash(state) } } - macro_rules! hash { ($e:expr) => { $e.hash(state) } } - - let region = |state: &mut SipHasher, r: Region| { - match r { - ReStatic => {} - ReLateBound(db, BrAnon(i)) => { - db.hash(state); - i.hash(state); - } - ReEmpty | - ReEarlyBound(..) | - ReLateBound(..) | - ReFree(..) | - ReScope(..) | - ReVar(..) | - ReSkolemized(..) => { - tcx.sess.bug("unexpected region found when hashing a type") - } - } - }; - let did = |state: &mut SipHasher, did: DefId| { - let h = if did.is_local() { - svh.clone() - } else { - tcx.sess.cstore.get_crate_hash(did.krate) - }; - h.as_str().hash(state); - did.node.hash(state); - }; - let mt = |state: &mut SipHasher, mt: TypeAndMut| { - mt.mutbl.hash(state); - }; - let fn_sig = |state: &mut SipHasher, sig: &Binder>| { - let sig = tcx.anonymize_late_bound_regions(sig).0; - for a in &sig.inputs { helper(tcx, *a, svh, state); } - if let ty::FnConverging(output) = sig.output { - helper(tcx, output, svh, state); - } - }; - ty.maybe_walk(|ty| { - match ty.sty { - TyBool => byte!(2), - TyChar => byte!(3), - TyInt(i) => { - byte!(4); - hash!(i); - } - TyUint(u) => { - byte!(5); - hash!(u); - } - TyFloat(f) => { - byte!(6); - hash!(f); - } - TyStr => { - byte!(7); - } - TyEnum(d, _) => { - byte!(8); - did(state, d.did); - } - TyBox(_) => { - byte!(9); - } - TyArray(_, n) => { - byte!(10); - n.hash(state); - } - TySlice(_) => { - byte!(11); - } - TyRawPtr(m) => { - byte!(12); - mt(state, m); - } - TyRef(r, m) => { - byte!(13); - region(state, *r); - mt(state, m); - } - TyBareFn(opt_def_id, ref b) => { - byte!(14); - hash!(opt_def_id); - hash!(b.unsafety); - hash!(b.abi); - fn_sig(state, &b.sig); - return false; - } - TyTrait(ref data) => { - byte!(17); - did(state, data.principal_def_id()); - hash!(data.bounds); - - let principal = tcx.anonymize_late_bound_regions(&data.principal).0; - for subty in &principal.substs.types { - helper(tcx, subty, svh, state); - } - - return false; - } - TyStruct(d, _) => { - byte!(18); - did(state, d.did); - } - TyTuple(ref inner) => { - byte!(19); - hash!(inner.len()); - } - TyParam(p) => { - byte!(20); - hash!(p.space); - hash!(p.idx); - hash!(p.name.as_str()); - } - TyInfer(_) => unreachable!(), - TyError => byte!(21), - TyClosure(d, _) => { - byte!(22); - did(state, d); - } - TyProjection(ref data) => { - byte!(23); - did(state, data.trait_ref.def_id); - hash!(data.item_name.as_str()); - } - } - true - }); - } - } - /// Construct a parameter environment suitable for static contexts or other contexts where there /// are no free type/lifetime parameters in scope. pub fn empty_parameter_environment<'a>(&'a self) @@ -3786,87 +2690,6 @@ pub fn is_overloaded_autoderef(&self, expr_id: NodeId, autoderefs: u32) -> bool pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option { Some(self.tables.borrow().upvar_capture_map.get(&upvar_id).unwrap().clone()) } - - - /// Returns true if this ADT is a dtorck type, i.e. whether it being - /// safe for destruction requires it to be alive - fn is_adt_dtorck(&self, adt: AdtDef<'tcx>) -> bool { - let dtor_method = match adt.destructor() { - Some(dtor) => dtor, - None => return false - }; - let impl_did = self.impl_of_method(dtor_method).unwrap_or_else(|| { - self.sess.bug(&format!("no Drop impl for the dtor of `{:?}`", adt)) - }); - let generics = adt.type_scheme(self).generics; - - // In `impl<'a> Drop ...`, we automatically assume - // `'a` is meaningful and thus represents a bound - // through which we could reach borrowed data. - // - // FIXME (pnkfelix): In the future it would be good to - // extend the language to allow the user to express, - // in the impl signature, that a lifetime is not - // actually used (something like `where 'a: ?Live`). - if generics.has_region_params(subst::TypeSpace) { - debug!("typ: {:?} has interesting dtor due to region params", - adt); - return true; - } - - let mut seen_items = Vec::new(); - let mut items_to_inspect = vec![impl_did]; - while let Some(item_def_id) = items_to_inspect.pop() { - if seen_items.contains(&item_def_id) { - continue; - } - - for pred in self.lookup_predicates(item_def_id).predicates { - let result = match pred { - ty::Predicate::Equate(..) | - ty::Predicate::RegionOutlives(..) | - ty::Predicate::TypeOutlives(..) | - ty::Predicate::WellFormed(..) | - ty::Predicate::ObjectSafe(..) | - ty::Predicate::Projection(..) => { - // For now, assume all these where-clauses - // may give drop implementation capabilty - // to access borrowed data. - true - } - - ty::Predicate::Trait(ty::Binder(ref t_pred)) => { - let def_id = t_pred.trait_ref.def_id; - if self.trait_items(def_id).len() != 0 { - // If trait has items, assume it adds - // capability to access borrowed data. - true - } else { - // Trait without items is itself - // uninteresting from POV of dropck. - // - // However, may have parent w/ items; - // so schedule checking of predicates, - items_to_inspect.push(def_id); - // and say "no capability found" for now. - false - } - } - }; - - if result { - debug!("typ: {:?} has interesting dtor due to generic preds, e.g. {:?}", - adt, pred); - return true; - } - } - - seen_items.push(item_def_id); - } - - debug!("typ: {:?} is dtorck-safe", adt); - false - } } /// The category of explicit self. @@ -3899,22 +2722,6 @@ pub struct Freevar { // imported. pub type GlobMap = HashMap>; -impl<'tcx> AutoAdjustment<'tcx> { - pub fn is_identity(&self) -> bool { - match *self { - AdjustReifyFnPointer | - AdjustUnsafeFnPointer => false, - AdjustDerefRef(ref r) => r.is_identity(), - } - } -} - -impl<'tcx> AutoDerefRef<'tcx> { - pub fn is_identity(&self) -> bool { - self.autoderefs == 0 && self.unsize.is_none() && self.autoref.is_none() - } -} - impl<'tcx> ctxt<'tcx> { pub fn with_freevars(&self, fid: NodeId, f: F) -> T where F: FnOnce(&[Freevar]) -> T, diff --git a/src/librustc/middle/ty/structural_impls.rs b/src/librustc/middle/ty/structural_impls.rs index 94e4672ea97..0058ccbce3b 100644 --- a/src/librustc/middle/ty/structural_impls.rs +++ b/src/librustc/middle/ty/structural_impls.rs @@ -641,8 +641,8 @@ fn fold_with>(&self, folder: &mut F) -> ty::ItemSubsts<'tcx> } } -impl<'tcx> TypeFoldable<'tcx> for ty::AutoRef<'tcx> { - fn fold_with>(&self, folder: &mut F) -> ty::AutoRef<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoRef<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::adjustment::AutoRef<'tcx> { folder.fold_autoref(self) } } diff --git a/src/librustc/middle/ty/sty.rs b/src/librustc/middle/ty/sty.rs index a04cc89ee18..3969738a22e 100644 --- a/src/librustc/middle/ty/sty.rs +++ b/src/librustc/middle/ty/sty.rs @@ -24,6 +24,7 @@ use std::mem; use syntax::abi; use syntax::ast::{Name, NodeId}; +use syntax::parse::token::special_idents; use rustc_front::hir; @@ -504,6 +505,31 @@ pub struct ParamTy { pub name: Name, } +impl ParamTy { + pub fn new(space: subst::ParamSpace, + index: u32, + name: Name) + -> ParamTy { + ParamTy { space: space, idx: index, name: name } + } + + pub fn for_self() -> ParamTy { + ParamTy::new(subst::SelfSpace, 0, special_idents::type_self.name) + } + + pub fn for_def(def: &ty::TypeParameterDef) -> ParamTy { + ParamTy::new(def.space, def.index, def.name) + } + + pub fn to_ty<'tcx>(self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { + tcx.mk_param(self.space, self.idx, self.name) + } + + pub fn is_self(&self) -> bool { + self.space == subst::SelfSpace && self.idx == 0 + } +} + /// A [De Bruijn index][dbi] is a standard means of representing /// regions (and perhaps later types) in a higher-ranked setting. In /// particular, imagine a type like this: @@ -844,6 +870,13 @@ pub fn from_depth(&self, depth: u32) -> Region { // Type utilities impl<'tcx> TyS<'tcx> { + pub fn as_opt_param_ty(&self) -> Option { + match self.sty { + ty::TyParam(ref d) => Some(d.clone()), + _ => None, + } + } + pub fn is_nil(&self) -> bool { match self.sty { TyTuple(ref tys) => tys.is_empty(), @@ -868,6 +901,13 @@ pub fn is_ty_var(&self) -> bool { pub fn is_bool(&self) -> bool { self.sty == TyBool } + pub fn is_param(&self, space: subst::ParamSpace, index: u32) -> bool { + match self.sty { + ty::TyParam(ref data) => data.space == space && data.idx == index, + _ => false, + } + } + pub fn is_self(&self) -> bool { match self.sty { TyParam(ref p) => p.space == subst::SelfSpace, @@ -1126,4 +1166,47 @@ pub fn ty_adt_def(&self) -> Option> { _ => 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 00000000000..88314618535 --- /dev/null +++ b/src/librustc/middle/ty/util.rs @@ -0,0 +1,891 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! misc. type-system utilities too small to deserve their own file + +use back::svh::Svh; +use middle::const_eval::{self, ConstVal, ErrKind}; +use middle::const_eval::EvalHint::UncheckedExprHint; +use middle::def_id::DefId; +use middle::subst; +use middle::infer; +use middle::pat_util; +use middle::traits; +use middle::ty::{self, Ty, TypeAndMut, TypeFlags}; +use middle::ty::{Disr, ParameterEnvironment}; +use middle::ty::{HasTypeFlags, RegionEscape}; +use middle::ty::TypeVariants::*; +use util::num::ToPrimitive; + +use std::cmp; +use std::hash::{Hash, SipHasher, Hasher}; +use syntax::ast::Name; +use syntax::codemap::Span; + +use rustc_front::hir; +use rustc_front::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt}; + +pub trait IntTypeExt { + fn to_ty<'tcx>(&self, cx: &ty::ctxt<'tcx>) -> Ty<'tcx>; + fn i64_to_disr(&self, val: i64) -> Option; + fn u64_to_disr(&self, val: u64) -> Option; + fn disr_incr(&self, val: Disr) -> Option; + fn disr_string(&self, val: Disr) -> String; + fn disr_wrap_incr(&self, val: Option) -> Disr; +} + +impl IntTypeExt for attr::IntType { + fn to_ty<'tcx>(&self, cx: &ty::ctxt<'tcx>) -> Ty<'tcx> { + match *self { + SignedInt(hir::TyI8) => cx.types.i8, + SignedInt(hir::TyI16) => cx.types.i16, + SignedInt(hir::TyI32) => cx.types.i32, + SignedInt(hir::TyI64) => cx.types.i64, + SignedInt(hir::TyIs) => cx.types.isize, + UnsignedInt(hir::TyU8) => cx.types.u8, + UnsignedInt(hir::TyU16) => cx.types.u16, + UnsignedInt(hir::TyU32) => cx.types.u32, + UnsignedInt(hir::TyU64) => cx.types.u64, + UnsignedInt(hir::TyUs) => cx.types.usize, + } + } + + fn i64_to_disr(&self, val: i64) -> Option { + match *self { + SignedInt(hir::TyI8) => val.to_i8() .map(|v| v as Disr), + SignedInt(hir::TyI16) => val.to_i16() .map(|v| v as Disr), + SignedInt(hir::TyI32) => val.to_i32() .map(|v| v as Disr), + SignedInt(hir::TyI64) => val.to_i64() .map(|v| v as Disr), + UnsignedInt(hir::TyU8) => val.to_u8() .map(|v| v as Disr), + UnsignedInt(hir::TyU16) => val.to_u16() .map(|v| v as Disr), + UnsignedInt(hir::TyU32) => val.to_u32() .map(|v| v as Disr), + UnsignedInt(hir::TyU64) => val.to_u64() .map(|v| v as Disr), + + UnsignedInt(hir::TyUs) | + SignedInt(hir::TyIs) => unreachable!(), + } + } + + fn u64_to_disr(&self, val: u64) -> Option { + match *self { + SignedInt(hir::TyI8) => val.to_i8() .map(|v| v as Disr), + SignedInt(hir::TyI16) => val.to_i16() .map(|v| v as Disr), + SignedInt(hir::TyI32) => val.to_i32() .map(|v| v as Disr), + SignedInt(hir::TyI64) => val.to_i64() .map(|v| v as Disr), + UnsignedInt(hir::TyU8) => val.to_u8() .map(|v| v as Disr), + UnsignedInt(hir::TyU16) => val.to_u16() .map(|v| v as Disr), + UnsignedInt(hir::TyU32) => val.to_u32() .map(|v| v as Disr), + UnsignedInt(hir::TyU64) => val.to_u64() .map(|v| v as Disr), + + UnsignedInt(hir::TyUs) | + SignedInt(hir::TyIs) => unreachable!(), + } + } + + fn disr_incr(&self, val: Disr) -> Option { + macro_rules! add1 { + ($e:expr) => { $e.and_then(|v|v.checked_add(1)).map(|v| v as Disr) } + } + match *self { + // SignedInt repr means we *want* to reinterpret the bits + // treating the highest bit of Disr as a sign-bit, so + // cast to i64 before range-checking. + SignedInt(hir::TyI8) => add1!((val as i64).to_i8()), + SignedInt(hir::TyI16) => add1!((val as i64).to_i16()), + SignedInt(hir::TyI32) => add1!((val as i64).to_i32()), + SignedInt(hir::TyI64) => add1!(Some(val as i64)), + + UnsignedInt(hir::TyU8) => add1!(val.to_u8()), + UnsignedInt(hir::TyU16) => add1!(val.to_u16()), + UnsignedInt(hir::TyU32) => add1!(val.to_u32()), + UnsignedInt(hir::TyU64) => add1!(Some(val)), + + UnsignedInt(hir::TyUs) | + SignedInt(hir::TyIs) => unreachable!(), + } + } + + // This returns a String because (1.) it is only used for + // rendering an error message and (2.) a string can represent the + // full range from `i64::MIN` through `u64::MAX`. + fn disr_string(&self, val: Disr) -> String { + match *self { + SignedInt(hir::TyI8) => format!("{}", val as i8 ), + SignedInt(hir::TyI16) => format!("{}", val as i16), + SignedInt(hir::TyI32) => format!("{}", val as i32), + SignedInt(hir::TyI64) => format!("{}", val as i64), + UnsignedInt(hir::TyU8) => format!("{}", val as u8 ), + UnsignedInt(hir::TyU16) => format!("{}", val as u16), + UnsignedInt(hir::TyU32) => format!("{}", val as u32), + UnsignedInt(hir::TyU64) => format!("{}", val as u64), + + UnsignedInt(hir::TyUs) | + SignedInt(hir::TyIs) => unreachable!(), + } + } + + fn disr_wrap_incr(&self, val: Option) -> Disr { + macro_rules! add1 { + ($e:expr) => { ($e).wrapping_add(1) as Disr } + } + let val = val.unwrap_or(ty::INITIAL_DISCRIMINANT_VALUE); + match *self { + SignedInt(hir::TyI8) => add1!(val as i8 ), + SignedInt(hir::TyI16) => add1!(val as i16), + SignedInt(hir::TyI32) => add1!(val as i32), + SignedInt(hir::TyI64) => add1!(val as i64), + UnsignedInt(hir::TyU8) => add1!(val as u8 ), + UnsignedInt(hir::TyU16) => add1!(val as u16), + UnsignedInt(hir::TyU32) => add1!(val as u32), + UnsignedInt(hir::TyU64) => add1!(val as u64), + + UnsignedInt(hir::TyUs) | + SignedInt(hir::TyIs) => unreachable!(), + } + } +} + + +#[derive(Copy, Clone)] +pub enum CopyImplementationError { + InfrigingField(Name), + InfrigingVariant(Name), + NotAnAdt, + HasDestructor +} + +/// Describes whether a type is representable. For types that are not +/// representable, 'SelfRecursive' and 'ContainsRecursive' are used to +/// distinguish between types that are recursive with themselves and types that +/// contain a different recursive type. These cases can therefore be treated +/// differently when reporting errors. +/// +/// The ordering of the cases is significant. They are sorted so that cmp::max +/// will keep the "more erroneous" of two values. +#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Debug)] +pub enum Representability { + Representable, + ContainsRecursive, + SelfRecursive, +} + +impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { + pub fn can_type_implement_copy(&self, self_type: Ty<'tcx>, span: Span) + -> Result<(),CopyImplementationError> { + let tcx = self.tcx; + + // FIXME: (@jroesch) float this code up + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(self.clone()), false); + + let adt = match self_type.sty { + ty::TyStruct(struct_def, substs) => { + for field in struct_def.all_fields() { + let field_ty = field.ty(tcx, substs); + if infcx.type_moves_by_default(field_ty, span) { + return Err(CopyImplementationError::InfrigingField( + field.name)) + } + } + struct_def + } + ty::TyEnum(enum_def, substs) => { + for variant in &enum_def.variants { + for field in &variant.fields { + let field_ty = field.ty(tcx, substs); + if infcx.type_moves_by_default(field_ty, span) { + return Err(CopyImplementationError::InfrigingVariant( + variant.name)) + } + } + } + enum_def + } + _ => return Err(CopyImplementationError::NotAnAdt), + }; + + if adt.has_dtor() { + return Err(CopyImplementationError::HasDestructor) + } + + Ok(()) + } +} + +impl<'tcx> ty::ctxt<'tcx> { + pub fn pat_contains_ref_binding(&self, pat: &hir::Pat) -> Option { + pat_util::pat_contains_ref_binding(&self.def_map, pat) + } + + pub fn arm_contains_ref_binding(&self, arm: &hir::Arm) -> Option { + pat_util::arm_contains_ref_binding(&self.def_map, arm) + } + + /// Returns the type of element at index `i` in tuple or tuple-like type `t`. + /// For an enum `t`, `variant` is None only if `t` is a univariant enum. + pub fn positional_element_ty(&self, + ty: Ty<'tcx>, + i: usize, + variant: Option) -> Option> { + match (&ty.sty, variant) { + (&TyStruct(def, substs), None) => { + def.struct_variant().fields.get(i).map(|f| f.ty(self, substs)) + } + (&TyEnum(def, substs), Some(vid)) => { + def.variant_with_id(vid).fields.get(i).map(|f| f.ty(self, substs)) + } + (&TyEnum(def, substs), None) => { + assert!(def.is_univariant()); + def.variants[0].fields.get(i).map(|f| f.ty(self, substs)) + } + (&TyTuple(ref v), None) => v.get(i).cloned(), + _ => None + } + } + + /// Returns the type of element at field `n` in struct or struct-like type `t`. + /// For an enum `t`, `variant` must be some def id. + pub fn named_element_ty(&self, + ty: Ty<'tcx>, + n: Name, + variant: Option) -> Option> { + match (&ty.sty, variant) { + (&TyStruct(def, substs), None) => { + def.struct_variant().find_field_named(n).map(|f| f.ty(self, substs)) + } + (&TyEnum(def, substs), Some(vid)) => { + def.variant_with_id(vid).find_field_named(n).map(|f| f.ty(self, substs)) + } + _ => return None + } + } + + /// Returns `(normalized_type, ty)`, where `normalized_type` is the + /// IntType representation of one of {i64,i32,i16,i8,u64,u32,u16,u8}, + /// and `ty` is the original type (i.e. may include `isize` or + /// `usize`). + pub fn enum_repr_type(&self, opt_hint: Option<&attr::ReprAttr>) + -> (attr::IntType, Ty<'tcx>) { + let repr_type = match opt_hint { + // Feed in the given type + Some(&attr::ReprInt(_, int_t)) => int_t, + // ... but provide sensible default if none provided + // + // NB. Historically `fn enum_variants` generate i64 here, while + // rustc_typeck::check would generate isize. + _ => SignedInt(hir::TyIs), + }; + + let repr_type_ty = repr_type.to_ty(self); + let repr_type = match repr_type { + SignedInt(hir::TyIs) => + SignedInt(self.sess.target.int_type), + UnsignedInt(hir::TyUs) => + UnsignedInt(self.sess.target.uint_type), + other => other + }; + + (repr_type, repr_type_ty) + } + + /// Returns the deeply last field of nested structures, or the same type, + /// if not a structure at all. Corresponds to the only possible unsized + /// field, and its type can be used to determine unsizing strategy. + pub fn struct_tail(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { + while let TyStruct(def, substs) = ty.sty { + match def.struct_variant().fields.last() { + Some(f) => ty = f.ty(self, substs), + None => break + } + } + ty + } + + /// Same as applying struct_tail on `source` and `target`, but only + /// keeps going as long as the two types are instances of the same + /// structure definitions. + /// For `(Foo>, Foo)`, the result will be `(Foo, Trait)`, + /// whereas struct_tail produces `T`, and `Trait`, respectively. + pub fn struct_lockstep_tails(&self, + source: Ty<'tcx>, + target: Ty<'tcx>) + -> (Ty<'tcx>, Ty<'tcx>) { + let (mut a, mut b) = (source, target); + while let (&TyStruct(a_def, a_substs), &TyStruct(b_def, b_substs)) = (&a.sty, &b.sty) { + if a_def != b_def { + break; + } + if let Some(f) = a_def.struct_variant().fields.last() { + a = f.ty(self, a_substs); + b = f.ty(self, b_substs); + } else { + break; + } + } + (a, b) + } + + /// Returns the repeat count for a repeating vector expression. + pub fn eval_repeat_count(&self, count_expr: &hir::Expr) -> usize { + let hint = UncheckedExprHint(self.types.usize); + match const_eval::eval_const_expr_partial(self, count_expr, hint) { + Ok(val) => { + let found = match val { + ConstVal::Uint(count) => return count as usize, + ConstVal::Int(count) if count >= 0 => return count as usize, + const_val => const_val.description(), + }; + span_err!(self.sess, count_expr.span, E0306, + "expected positive integer for repeat count, found {}", + found); + } + Err(err) => { + let err_msg = match count_expr.node { + hir::ExprPath(None, hir::Path { + global: false, + ref segments, + .. + }) if segments.len() == 1 => + format!("found variable"), + _ => match err.kind { + ErrKind::MiscCatchAll => format!("but found {}", err.description()), + _ => format!("but {}", err.description()) + } + }; + span_err!(self.sess, count_expr.span, E0307, + "expected constant integer for repeat count, {}", err_msg); + } + } + 0 + } + + /// Given a set of predicates that apply to an object type, returns + /// the region bounds that the (erased) `Self` type must + /// outlive. Precisely *because* the `Self` type is erased, the + /// parameter `erased_self_ty` must be supplied to indicate what type + /// has been used to represent `Self` in the predicates + /// themselves. This should really be a unique type; `FreshTy(0)` is a + /// popular choice. + /// + /// NB: in some cases, particularly around higher-ranked bounds, + /// this function returns a kind of conservative approximation. + /// That is, all regions returned by this function are definitely + /// required, but there may be other region bounds that are not + /// returned, as well as requirements like `for<'a> T: 'a`. + /// + /// Requires that trait definitions have been processed so that we can + /// elaborate predicates and walk supertraits. + pub fn required_region_bounds(&self, + erased_self_ty: Ty<'tcx>, + predicates: Vec>) + -> Vec { + debug!("required_region_bounds(erased_self_ty={:?}, predicates={:?})", + erased_self_ty, + predicates); + + assert!(!erased_self_ty.has_escaping_regions()); + + traits::elaborate_predicates(self, predicates) + .filter_map(|predicate| { + match predicate { + ty::Predicate::Projection(..) | + ty::Predicate::Trait(..) | + ty::Predicate::Equate(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | + ty::Predicate::RegionOutlives(..) => { + None + } + ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t, r))) => { + // Search for a bound of the form `erased_self_ty + // : 'a`, but be wary of something like `for<'a> + // erased_self_ty : 'a` (we interpret a + // higher-ranked bound like that as 'static, + // though at present the code in `fulfill.rs` + // considers such bounds to be unsatisfiable, so + // it's kind of a moot point since you could never + // construct such an object, but this seems + // correct even if that code changes). + if t == erased_self_ty && !r.has_escaping_regions() { + Some(r) + } else { + None + } + } + } + }) + .collect() + } + + /// Creates a hash of the type `Ty` which will be the same no matter what crate + /// context it's calculated within. This is used by the `type_id` intrinsic. + pub fn hash_crate_independent(&self, ty: Ty<'tcx>, svh: &Svh) -> u64 { + let mut state = SipHasher::new(); + helper(self, ty, svh, &mut state); + return state.finish(); + + fn helper<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh, + state: &mut SipHasher) { + macro_rules! byte { ($b:expr) => { ($b as u8).hash(state) } } + macro_rules! hash { ($e:expr) => { $e.hash(state) } } + + let region = |state: &mut SipHasher, r: ty::Region| { + match r { + ty::ReStatic => {} + ty::ReLateBound(db, ty::BrAnon(i)) => { + db.hash(state); + i.hash(state); + } + ty::ReEmpty | + ty::ReEarlyBound(..) | + ty::ReLateBound(..) | + ty::ReFree(..) | + ty::ReScope(..) | + ty::ReVar(..) | + ty::ReSkolemized(..) => { + tcx.sess.bug("unexpected region found when hashing a type") + } + } + }; + let did = |state: &mut SipHasher, did: DefId| { + let h = if did.is_local() { + svh.clone() + } else { + tcx.sess.cstore.get_crate_hash(did.krate) + }; + h.as_str().hash(state); + did.node.hash(state); + }; + let mt = |state: &mut SipHasher, mt: TypeAndMut| { + mt.mutbl.hash(state); + }; + let fn_sig = |state: &mut SipHasher, sig: &ty::Binder>| { + let sig = tcx.anonymize_late_bound_regions(sig).0; + for a in &sig.inputs { helper(tcx, *a, svh, state); } + if let ty::FnConverging(output) = sig.output { + helper(tcx, output, svh, state); + } + }; + ty.maybe_walk(|ty| { + match ty.sty { + TyBool => byte!(2), + TyChar => byte!(3), + TyInt(i) => { + byte!(4); + hash!(i); + } + TyUint(u) => { + byte!(5); + hash!(u); + } + TyFloat(f) => { + byte!(6); + hash!(f); + } + TyStr => { + byte!(7); + } + TyEnum(d, _) => { + byte!(8); + did(state, d.did); + } + TyBox(_) => { + byte!(9); + } + TyArray(_, n) => { + byte!(10); + n.hash(state); + } + TySlice(_) => { + byte!(11); + } + TyRawPtr(m) => { + byte!(12); + mt(state, m); + } + TyRef(r, m) => { + byte!(13); + region(state, *r); + mt(state, m); + } + TyBareFn(opt_def_id, ref b) => { + byte!(14); + hash!(opt_def_id); + hash!(b.unsafety); + hash!(b.abi); + fn_sig(state, &b.sig); + return false; + } + TyTrait(ref data) => { + byte!(17); + did(state, data.principal_def_id()); + hash!(data.bounds); + + let principal = tcx.anonymize_late_bound_regions(&data.principal).0; + for subty in &principal.substs.types { + helper(tcx, subty, svh, state); + } + + return false; + } + TyStruct(d, _) => { + byte!(18); + did(state, d.did); + } + TyTuple(ref inner) => { + byte!(19); + hash!(inner.len()); + } + TyParam(p) => { + byte!(20); + hash!(p.space); + hash!(p.idx); + hash!(p.name.as_str()); + } + TyInfer(_) => unreachable!(), + TyError => byte!(21), + TyClosure(d, _) => { + byte!(22); + did(state, d); + } + TyProjection(ref data) => { + byte!(23); + did(state, data.trait_ref.def_id); + hash!(data.item_name.as_str()); + } + } + true + }); + } + } + + /// Returns true if this ADT is a dtorck type, i.e. whether it being + /// safe for destruction requires it to be alive + pub fn is_adt_dtorck(&self, adt: ty::AdtDef<'tcx>) -> bool { + let dtor_method = match adt.destructor() { + Some(dtor) => dtor, + None => return false + }; + let impl_did = self.impl_of_method(dtor_method).unwrap_or_else(|| { + self.sess.bug(&format!("no Drop impl for the dtor of `{:?}`", adt)) + }); + let generics = adt.type_scheme(self).generics; + + // In `impl<'a> Drop ...`, we automatically assume + // `'a` is meaningful and thus represents a bound + // through which we could reach borrowed data. + // + // FIXME (pnkfelix): In the future it would be good to + // extend the language to allow the user to express, + // in the impl signature, that a lifetime is not + // actually used (something like `where 'a: ?Live`). + if generics.has_region_params(subst::TypeSpace) { + debug!("typ: {:?} has interesting dtor due to region params", + adt); + return true; + } + + let mut seen_items = Vec::new(); + let mut items_to_inspect = vec![impl_did]; + while let Some(item_def_id) = items_to_inspect.pop() { + if seen_items.contains(&item_def_id) { + continue; + } + + for pred in self.lookup_predicates(item_def_id).predicates { + let result = match pred { + ty::Predicate::Equate(..) | + ty::Predicate::RegionOutlives(..) | + ty::Predicate::TypeOutlives(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | + ty::Predicate::Projection(..) => { + // For now, assume all these where-clauses + // may give drop implementation capabilty + // to access borrowed data. + true + } + + ty::Predicate::Trait(ty::Binder(ref t_pred)) => { + let def_id = t_pred.trait_ref.def_id; + if self.trait_items(def_id).len() != 0 { + // If trait has items, assume it adds + // capability to access borrowed data. + true + } else { + // Trait without items is itself + // uninteresting from POV of dropck. + // + // However, may have parent w/ items; + // so schedule checking of predicates, + items_to_inspect.push(def_id); + // and say "no capability found" for now. + false + } + } + }; + + if result { + debug!("typ: {:?} has interesting dtor due to generic preds, e.g. {:?}", + adt, pred); + return true; + } + } + + seen_items.push(item_def_id); + } + + debug!("typ: {:?} is dtorck-safe", adt); + false + } +} + +impl<'tcx> ty::TyS<'tcx> { + fn impls_bound<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, + bound: ty::BuiltinBound, + span: Span) + -> bool + { + let tcx = param_env.tcx; + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env.clone()), false); + + let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, + self, bound, span); + + debug!("Ty::impls_bound({:?}, {:?}) = {:?}", + self, bound, is_impld); + + is_impld + } + + // FIXME (@jroesch): I made this public to use it, not sure if should be private + pub fn moves_by_default<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, + span: Span) -> bool { + if self.flags.get().intersects(TypeFlags::MOVENESS_CACHED) { + return self.flags.get().intersects(TypeFlags::MOVES_BY_DEFAULT); + } + + assert!(!self.needs_infer()); + + // Fast-path for primitive types + let result = match self.sty { + TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | + TyRawPtr(..) | TyBareFn(..) | TyRef(_, TypeAndMut { + mutbl: hir::MutImmutable, .. + }) => Some(false), + + TyStr | TyBox(..) | TyRef(_, TypeAndMut { + mutbl: hir::MutMutable, .. + }) => Some(true), + + TyArray(..) | TySlice(_) | TyTrait(..) | TyTuple(..) | + TyClosure(..) | TyEnum(..) | TyStruct(..) | + TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None + }.unwrap_or_else(|| !self.impls_bound(param_env, ty::BoundCopy, span)); + + if !self.has_param_types() && !self.has_self_ty() { + self.flags.set(self.flags.get() | if result { + TypeFlags::MOVENESS_CACHED | TypeFlags::MOVES_BY_DEFAULT + } else { + TypeFlags::MOVENESS_CACHED + }); + } + + result + } + + #[inline] + pub fn is_sized<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, + span: Span) -> bool + { + if self.flags.get().intersects(TypeFlags::SIZEDNESS_CACHED) { + return self.flags.get().intersects(TypeFlags::IS_SIZED); + } + + self.is_sized_uncached(param_env, span) + } + + fn is_sized_uncached<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, + span: Span) -> bool { + assert!(!self.needs_infer()); + + // Fast-path for primitive types + let result = match self.sty { + TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | + TyBox(..) | TyRawPtr(..) | TyRef(..) | TyBareFn(..) | + TyArray(..) | TyTuple(..) | TyClosure(..) => Some(true), + + TyStr | TyTrait(..) | TySlice(_) => Some(false), + + TyEnum(..) | TyStruct(..) | TyProjection(..) | TyParam(..) | + TyInfer(..) | TyError => None + }.unwrap_or_else(|| self.impls_bound(param_env, ty::BoundSized, span)); + + if !self.has_param_types() && !self.has_self_ty() { + self.flags.set(self.flags.get() | if result { + TypeFlags::SIZEDNESS_CACHED | TypeFlags::IS_SIZED + } else { + TypeFlags::SIZEDNESS_CACHED + }); + } + + result + } + + + /// Check whether a type is representable. This means it cannot contain unboxed + /// structural recursion. This check is needed for structs and enums. + pub fn is_representable(&'tcx self, cx: &ty::ctxt<'tcx>, sp: Span) -> Representability { + + // Iterate until something non-representable is found + fn find_nonrepresentable<'tcx, It: Iterator>>(cx: &ty::ctxt<'tcx>, + sp: Span, + seen: &mut Vec>, + iter: It) + -> Representability { + iter.fold(Representability::Representable, + |r, ty| cmp::max(r, is_type_structurally_recursive(cx, sp, seen, ty))) + } + + fn are_inner_types_recursive<'tcx>(cx: &ty::ctxt<'tcx>, sp: Span, + seen: &mut Vec>, ty: Ty<'tcx>) + -> Representability { + match ty.sty { + TyTuple(ref ts) => { + find_nonrepresentable(cx, sp, seen, ts.iter().cloned()) + } + // Fixed-length vectors. + // FIXME(#11924) Behavior undecided for zero-length vectors. + TyArray(ty, _) => { + is_type_structurally_recursive(cx, sp, seen, ty) + } + TyStruct(def, substs) | TyEnum(def, substs) => { + find_nonrepresentable(cx, + sp, + seen, + def.all_fields().map(|f| f.ty(cx, substs))) + } + TyClosure(..) => { + // this check is run on type definitions, so we don't expect + // to see closure types + cx.sess.bug(&format!("requires check invoked on inapplicable type: {:?}", ty)) + } + _ => Representability::Representable, + } + } + + fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: ty::AdtDef<'tcx>) -> bool { + match ty.sty { + TyStruct(ty_def, _) | TyEnum(ty_def, _) => { + ty_def == def + } + _ => false + } + } + + fn same_type<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { + match (&a.sty, &b.sty) { + (&TyStruct(did_a, ref substs_a), &TyStruct(did_b, ref substs_b)) | + (&TyEnum(did_a, ref substs_a), &TyEnum(did_b, ref substs_b)) => { + if did_a != did_b { + return false; + } + + let types_a = substs_a.types.get_slice(subst::TypeSpace); + let types_b = substs_b.types.get_slice(subst::TypeSpace); + + let mut pairs = types_a.iter().zip(types_b); + + pairs.all(|(&a, &b)| same_type(a, b)) + } + _ => { + a == b + } + } + } + + // Does the type `ty` directly (without indirection through a pointer) + // contain any types on stack `seen`? + fn is_type_structurally_recursive<'tcx>(cx: &ty::ctxt<'tcx>, + sp: Span, + seen: &mut Vec>, + ty: Ty<'tcx>) -> Representability { + debug!("is_type_structurally_recursive: {:?}", ty); + + match ty.sty { + TyStruct(def, _) | TyEnum(def, _) => { + { + // Iterate through stack of previously seen types. + let mut iter = seen.iter(); + + // The first item in `seen` is the type we are actually curious about. + // We want to return SelfRecursive if this type contains itself. + // It is important that we DON'T take generic parameters into account + // for this check, so that Bar in this example counts as SelfRecursive: + // + // struct Foo; + // struct Bar { x: Bar } + + match iter.next() { + Some(&seen_type) => { + if same_struct_or_enum(seen_type, def) { + debug!("SelfRecursive: {:?} contains {:?}", + seen_type, + ty); + return Representability::SelfRecursive; + } + } + None => {} + } + + // We also need to know whether the first item contains other types + // that are structurally recursive. If we don't catch this case, we + // will recurse infinitely for some inputs. + // + // It is important that we DO take generic parameters into account + // here, so that code like this is considered SelfRecursive, not + // ContainsRecursive: + // + // struct Foo { Option> } + + for &seen_type in iter { + if same_type(ty, seen_type) { + debug!("ContainsRecursive: {:?} contains {:?}", + seen_type, + ty); + return Representability::ContainsRecursive; + } + } + } + + // For structs and enums, track all previously seen types by pushing them + // onto the 'seen' stack. + seen.push(ty); + let out = are_inner_types_recursive(cx, sp, seen, ty); + seen.pop(); + out + } + _ => { + // No need to push in other cases. + are_inner_types_recursive(cx, sp, seen, ty) + } + } + } + + debug!("is_type_representable: {:?}", self); + + // To avoid a stack overflow when checking an enum variant or struct that + // contains a different, structurally recursive type, maintain a stack + // of seen types and check recursion for each of them (issues #3008, #3779). + let mut seen: Vec = Vec::new(); + let r = is_type_structurally_recursive(cx, sp, &mut seen, self); + debug!("is_type_representable: {:?} is {:?}", self, r); + r + } +} diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 99e41bd22b8..fee60d46dc0 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -388,23 +388,23 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { } } -impl<'tcx> fmt::Debug for ty::AutoAdjustment<'tcx> { +impl<'tcx> fmt::Debug for ty::adjustment::AutoAdjustment<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - ty::AdjustReifyFnPointer => { + ty::adjustment::AdjustReifyFnPointer => { write!(f, "AdjustReifyFnPointer") } - ty::AdjustUnsafeFnPointer => { + ty::adjustment::AdjustUnsafeFnPointer => { write!(f, "AdjustUnsafeFnPointer") } - ty::AdjustDerefRef(ref data) => { + ty::adjustment::AdjustDerefRef(ref data) => { write!(f, "{:?}", data) } } } } -impl<'tcx> fmt::Debug for ty::AutoDerefRef<'tcx> { +impl<'tcx> fmt::Debug for ty::adjustment::AutoDerefRef<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "AutoDerefRef({}, unsize={:?}, {:?})", self.autoderefs, self.unsize, self.autoref) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index c8ffe076606..4084f13e818 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -33,6 +33,7 @@ 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 @@ fn check_expr(&mut self, cx: &Context, e: &hir::Expr) { } 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 @@ fn expr_refers_to_this_method(tcx: &ty::ctxt, } // 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 6352af39f14..f15470e7851 100644 --- a/src/librustc_mir/tcx/expr.rs +++ b/src/librustc_mir/tcx/expr.rs @@ -320,7 +320,7 @@ fn make_mirror(self, cx: &mut Cx<'a,'tcx>) -> 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 @@ fn make_mirror(self, cx: &mut Cx<'a,'tcx>) -> 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 @@ fn make_mirror(self, cx: &mut Cx<'a,'tcx>) -> 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 @@ fn make_mirror(self, cx: &mut Cx<'a,'tcx>) -> 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 @@ fn make_mirror(self, cx: &mut Cx<'a,'tcx>) -> Expr> { arg: expr.to_ref() } }; } - ty::AutoUnsafe(m) => { + ty::adjustment::AutoUnsafe(m) => { // Convert this to a suitable `&foo` and // then an unsafe coercion. Limit the region to be just this // expression. diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index c98760ce02a..a2d74635b5e 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -34,6 +34,8 @@ use trans::type_::Type; use trans::type_of; use middle::subst::Substs; +use middle::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer}; +use middle::ty::adjustment::AdjustUnsafeFnPointer; use middle::ty::{self, Ty}; use middle::ty::cast::{CastTy,IntTy}; use util::nodemap::NodeMap; @@ -289,14 +291,14 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, &cx.tcx().expr_ty_adjusted(e)); let opt_adj = cx.tcx().tables.borrow().adjustments.get(&e.id).cloned(); match opt_adj { - Some(ty::AdjustReifyFnPointer) => { + Some(AdjustReifyFnPointer) => { // FIXME(#19925) once fn item types are // zero-sized, we'll need to do something here } - Some(ty::AdjustUnsafeFnPointer) => { + Some(AdjustUnsafeFnPointer) => { // purely a type-level thing } - Some(ty::AdjustDerefRef(adj)) => { + Some(AdjustDerefRef(adj)) => { let mut ty = ety; // Save the last autoderef in case we can avoid it. if adj.autoderefs > 0 { diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 59040b9cafe..7d8996867c0 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -71,7 +71,8 @@ use trans::meth; use trans::tvec; use trans::type_of; -use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustUnsafeFnPointer}; +use middle::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer}; +use middle::ty::adjustment::{AdjustUnsafeFnPointer, CustomCoerceUnsized}; use middle::ty::{self, Ty}; use middle::ty::MethodCall; use middle::ty::cast::{CastKind, CastTy}; @@ -514,7 +515,7 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; let coerce_index = match kind { - ty::CustomCoerceUnsized::Struct(i) => i + CustomCoerceUnsized::Struct(i) => i }; assert!(coerce_index < src_fields.len() && src_fields.len() == target_fields.len()); diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index cde188fa41e..69efaa792fe 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -65,7 +65,9 @@ use middle::infer::{self, Coercion}; use middle::traits::{self, ObligationCause}; use middle::traits::{predicate_for_trait_def, report_selection_error}; -use middle::ty::{AutoDerefRef, AdjustDerefRef}; +use middle::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef}; +use middle::ty::adjustment::{AutoPtr, AutoUnsafe, AdjustReifyFnPointer}; +use middle::ty::adjustment::{AdjustUnsafeFnPointer}; use middle::ty::{self, LvaluePreference, TypeAndMut, Ty}; use middle::ty::error::TypeError; use middle::ty::relate::RelateResult; @@ -81,7 +83,7 @@ struct Coerce<'a, 'tcx: 'a> { unsizing_obligations: RefCell>>, } -type CoerceResult<'tcx> = RelateResult<'tcx, Option>>; +type CoerceResult<'tcx> = RelateResult<'tcx, Option>>; impl<'f, 'tcx> Coerce<'f, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { @@ -186,7 +188,7 @@ fn coerce_borrowed_pointer(&self, let coercion = Coercion(self.origin.span()); let r_borrow = self.fcx.infcx().next_region_var(coercion); let r_borrow = self.tcx().mk_region(r_borrow); - let autoref = Some(ty::AutoPtr(r_borrow, mutbl_b)); + let autoref = Some(AutoPtr(r_borrow, mutbl_b)); let lvalue_pref = LvaluePreference::from_mutbl(mutbl_b); let mut first_error = None; @@ -264,11 +266,11 @@ fn coerce_unsized(&self, let coercion = Coercion(self.origin.span()); let r_borrow = self.fcx.infcx().next_region_var(coercion); let region = self.tcx().mk_region(r_borrow); - (mt_a.ty, Some(ty::AutoPtr(region, mt_b.mutbl))) + (mt_a.ty, Some(AutoPtr(region, mt_b.mutbl))) } (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) => { try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl)); - (mt_a.ty, Some(ty::AutoUnsafe(mt_b.mutbl))) + (mt_a.ty, Some(AutoUnsafe(mt_b.mutbl))) } _ => (source, None) }; @@ -360,7 +362,7 @@ fn coerce_from_fn_pointer(&self, (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => { let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a); try!(self.subtype(unsafe_a, b)); - return Ok(Some(ty::AdjustUnsafeFnPointer)); + return Ok(Some(AdjustUnsafeFnPointer)); } _ => {} } @@ -387,7 +389,7 @@ fn coerce_from_fn_item(&self, ty::TyBareFn(None, _) => { let a_fn_pointer = self.tcx().mk_fn(None, fn_ty_a); try!(self.subtype(a_fn_pointer, b)); - Ok(Some(ty::AdjustReifyFnPointer)) + Ok(Some(AdjustReifyFnPointer)) } _ => self.subtype(a, b) } @@ -422,7 +424,7 @@ fn coerce_unsafe_ptr(&self, if is_ref { Ok(Some(AdjustDerefRef(AutoDerefRef { autoderefs: 1, - autoref: Some(ty::AutoUnsafe(mutbl_b)), + autoref: Some(AutoUnsafe(mutbl_b)), unsize: None }))) } else { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 048a2b62bca..572ba7a8487 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -16,6 +16,7 @@ use middle::subst::{self}; use middle::traits; use middle::ty::{self, NoPreference, PreferMutLvalue, Ty}; +use middle::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr}; use middle::ty::fold::TypeFoldable; use middle::infer; use middle::infer::InferCtxt; @@ -136,7 +137,7 @@ fn adjust_self_ty(&mut self, { 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 @@ fn adjust_self_ty(&mut self, // 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 @@ fn fixup_derefs_on_method_receiver_if_necessary(&self, .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 @@ fn fixup_derefs_on_method_receiver_if_necessary(&self, 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 @@ fn fixup_derefs_on_method_receiver_if_necessary(&self, (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 e319e37fa30..1cfb495b36e 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -18,6 +18,7 @@ use middle::subst; use middle::traits; use middle::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef}; +use middle::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr}; use middle::infer; use syntax::ast; @@ -282,9 +283,9 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, match transformed_self_ty.sty { ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ }) => { fcx.write_adjustment(self_expr.id, - ty::AdjustDerefRef(ty::AutoDerefRef { + AdjustDerefRef(AutoDerefRef { autoderefs: autoderefs, - autoref: Some(ty::AutoPtr(region, mutbl)), + autoref: Some(AutoPtr(region, mutbl)), unsize: if unsize { Some(transformed_self_ty) } else { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 3160ed35025..656a740e984 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -97,8 +97,10 @@ use middle::ty::{LvaluePreference, NoPreference, PreferMutLvalue}; use middle::ty::{self, HasTypeFlags, RegionEscape, ToPolyTraitRef, Ty}; use middle::ty::{MethodCall, MethodCallee}; +use middle::ty::adjustment; use middle::ty::error::TypeError; use middle::ty::fold::{TypeFolder, TypeFoldable}; +use middle::ty::util::Representability; use require_c_abi_if_variadic; use rscope::{ElisionFailureInfo, RegionScope}; use session::Session; @@ -1337,7 +1339,7 @@ pub fn write_autoderef_adjustment(&self, derefs: usize) { self.write_adjustment( node_id, - ty::AdjustDerefRef(ty::AutoDerefRef { + adjustment::AdjustDerefRef(adjustment::AutoDerefRef { autoderefs: derefs, autoref: None, unsize: None @@ -1347,7 +1349,7 @@ pub fn write_autoderef_adjustment(&self, pub fn write_adjustment(&self, node_id: ast::NodeId, - adj: ty::AutoAdjustment<'tcx>) { + adj: adjustment::AutoAdjustment<'tcx>) { debug!("write_adjustment(node_id={}, adj={:?})", node_id, adj); if adj.is_identity() { @@ -1576,7 +1578,7 @@ pub fn expr_ty(&self, ex: &hir::Expr) -> Ty<'tcx> { /// Apply `adjustment` to the type of `expr` pub fn adjust_expr_ty(&self, expr: &hir::Expr, - adjustment: Option<&ty::AutoAdjustment<'tcx>>) + adjustment: Option<&adjustment::AutoAdjustment<'tcx>>) -> Ty<'tcx> { let raw_ty = self.expr_ty(expr); @@ -4170,12 +4172,13 @@ pub fn check_representable(tcx: &ty::ctxt, // contain themselves. For case 2, there must be an inner type that will be // caught by case 1. match rty.is_representable(tcx, sp) { - ty::SelfRecursive => { - span_err!(tcx.sess, sp, E0072, "invalid recursive {} type", designation); - tcx.sess.fileline_help(sp, "wrap the inner value in a box to make it representable"); - return false - } - ty::Representable | ty::ContainsRecursive => (), + Representability::SelfRecursive => { + span_err!(tcx.sess, sp, E0072, "invalid recursive {} type", designation); + tcx.sess.fileline_help( + sp, "wrap the inner value in a box to make it representable"); + return false + } + Representability::Representable | Representability::ContainsRecursive => (), } return true } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index b6ff7b529c5..155caaa8cb0 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -94,6 +94,7 @@ use middle::ty::{self, RegionEscape, ReScope, Ty, MethodCall, HasTypeFlags}; use middle::infer::{self, GenericKind, InferCtxt, SubregionOrigin, VerifyBound}; use middle::pat_util; +use middle::ty::adjustment; use middle::ty::wf::ImpliedBound; use std::mem; @@ -598,7 +599,9 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) { if let Some(adjustment) = adjustment { debug!("adjustment={:?}", adjustment); match adjustment { - ty::AdjustDerefRef(ty::AutoDerefRef {autoderefs, ref autoref, ..}) => { + adjustment::AdjustDerefRef(adjustment::AutoDerefRef { + autoderefs, ref autoref, .. + }) => { let expr_ty = rcx.resolve_node_type(expr.id); constrain_autoderefs(rcx, expr, autoderefs, expr_ty); if let Some(ref autoref) = *autoref { @@ -614,7 +617,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) { } } /* - ty::AutoObject(_, ref bounds, _, _) => { + adjustment::AutoObject(_, ref bounds, _, _) => { // Determine if we are casting `expr` to a trait // instance. If so, we have to be sure that the type // of the source obeys the new region bound. @@ -1221,7 +1224,7 @@ fn link_pattern<'t, 'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, fn link_autoref(rcx: &Rcx, expr: &hir::Expr, autoderefs: usize, - autoref: &ty::AutoRef) + autoref: &adjustment::AutoRef) { debug!("link_autoref(autoref={:?})", autoref); let mc = mc::MemCategorizationContext::new(rcx.fcx.infcx()); @@ -1229,12 +1232,12 @@ fn link_autoref(rcx: &Rcx, debug!("expr_cmt={:?}", expr_cmt); match *autoref { - ty::AutoPtr(r, m) => { + adjustment::AutoPtr(r, m) => { link_region(rcx, expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt); } - ty::AutoUnsafe(m) => { + adjustment::AutoUnsafe(m) => { let r = ty::ReScope(rcx.tcx().region_maps.node_extent(expr.id)); link_region(rcx, expr.span, &r, ty::BorrowKind::from_mutbl(m), expr_cmt); } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index de841a0cc00..6f8e064c9d8 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -18,6 +18,7 @@ use middle::def_id::DefId; use middle::pat_util; use middle::ty::{self, Ty, MethodCall, MethodCallee}; +use middle::ty::adjustment; use middle::ty::fold::{TypeFolder,TypeFoldable}; use middle::infer; use write_substs_to_tcx; @@ -268,19 +269,21 @@ fn visit_adjustments(&self, reason: ResolveReason, id: ast::NodeId) { 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 8048c302f2c..9ba6f1398e4 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -20,6 +20,7 @@ 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::{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 @@ fn check_implementations_of_copy(&self) { match param_env.can_type_implement_copy(self_type, span) { Ok(()) => {} - Err(ty::FieldDoesNotImplementCopy(name)) => { + Err(CopyImplementationError::InfrigingField(name)) => { span_err!(tcx.sess, span, E0204, "the trait `Copy` may not be \ implemented for this type; field \ `{}` does not implement `Copy`", name) } - Err(ty::VariantDoesNotImplementCopy(name)) => { + Err(CopyImplementationError::InfrigingVariant(name)) => { span_err!(tcx.sess, span, E0205, "the trait `Copy` may not be \ implemented for this type; variant \ `{}` does not implement `Copy`", name) } - Err(ty::TypeIsStructural) => { + Err(CopyImplementationError::NotAnAdt) => { span_err!(tcx.sess, span, E0206, "the trait `Copy` may not be implemented \ for this type; type is not a structure or \ enumeration") } - Err(ty::TypeHasDestructor) => { + Err(CopyImplementationError::HasDestructor) => { span_err!(tcx.sess, span, E0184, "the trait `Copy` may not be implemented for this type; \ the type has a destructor"); @@ -510,7 +511,7 @@ fn check_implementations_of_coerce_unsized(&self) { } 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 0f71c4d8ceb..f7520ed54b7 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -76,9 +76,10 @@ use middle::const_eval::EvalHint::UncheckedExprHint; use middle::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace}; use middle::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; -use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty, TypeScheme, IntTypeExt}; +use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty, TypeScheme}; use middle::ty::{VariantKind}; use middle::ty::fold::{TypeFolder, TypeFoldable}; +use middle::ty::util::IntTypeExt; use middle::infer; use rscope::*; use rustc::front::map as hir_map; -- 2.44.0