decoder::get_impl_polarity(&*cdata, def.node)
}
-pub fn get_custom_coerce_unsized_kind<'tcx>(tcx: &ty::ctxt<'tcx>,
- def: DefId)
- -> Option<ty::CustomCoerceUnsized> {
+pub fn get_custom_coerce_unsized_kind<'tcx>(
+ tcx: &ty::ctxt<'tcx>,
+ def: DefId)
+ -> Option<ty::adjustment::CustomCoerceUnsized>
+{
let cstore = &tcx.sess.cstore;
let cdata = cstore.get_crate_data(def.krate);
decoder::get_custom_coerce_unsized_kind(&*cdata, def.node)
}
}
-pub fn get_custom_coerce_unsized_kind<'tcx>(cdata: Cmd,
- id: ast::NodeId)
- -> Option<ty::CustomCoerceUnsized> {
+pub fn get_custom_coerce_unsized_kind<'tcx>(
+ cdata: Cmd,
+ id: ast::NodeId)
+ -> Option<ty::adjustment::CustomCoerceUnsized>
+{
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);
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;
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> {
}
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)))
}
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))
})
}
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| {
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) {
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>)
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,
}).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(),
}
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| {
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()
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 => {
/// 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)
}) {
use middle::infer;
use middle::mem_categorization as mc;
use middle::ty;
+use middle::ty::adjustment;
use rustc_front::hir;
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)");
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);
}
}
fn walk_autoderefref(&mut self,
expr: &hir::Expr,
- adj: &ty::AutoDerefRef<'tcx>) {
+ adj: &adjustment::AutoDerefRef<'tcx>) {
debug!("walk_autoderefref expr={:?} adj={:?}",
expr,
adj);
fn walk_autoref(&mut self,
expr: &hir::Expr,
cmt_base: mc::cmt<'tcx>,
- opt_autoref: Option<ty::AutoRef<'tcx>>)
+ opt_autoref: Option<adjustment::AutoRef<'tcx>>)
-> mc::cmt<'tcx>
{
debug!("walk_autoref(expr.id={} cmt_derefd={:?} opt_autoref={:?})",
};
match *autoref {
- ty::AutoPtr(r, m) => {
+ adjustment::AutoPtr(r, m) => {
self.delegate.borrow(expr.id,
expr.span,
cmt_base,
AutoRef);
}
- ty::AutoUnsafe(m) => {
+ adjustment::AutoUnsafe(m) => {
debug!("walk_autoref: expr.id={} cmt_base={:?}",
expr.id,
cmt_base);
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};
/// 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);
.map(|method| method.def_id)
}
- pub fn adjustments(&self) -> Ref<NodeMap<ty::AutoAdjustment<'tcx>>> {
+ pub fn adjustments(&self) -> Ref<NodeMap<adjustment::AutoAdjustment<'tcx>>> {
fn project_adjustments<'a, 'tcx>(tables: &'a ty::Tables<'tcx>)
- -> &'a NodeMap<ty::AutoAdjustment<'tcx>> {
+ -> &'a NodeMap<adjustment::AutoAdjustment<'tcx>> {
&tables.adjustments
}
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};
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);
--- /dev/null
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+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<T> { 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<T>` to `Box<Trait>` 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<AutoRef<'tcx>>,
+
+ /// 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<Ty<'tcx>>,
+}
+
+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<F>(&'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<Ty<'tcx>>,
+ {
+ 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<F>(&'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<Ty<'tcx>>,
+ {
+ 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<AutoRef<'tcx>>)
+ -> 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 })
+ }
+ }
+ }
+}
/// other items.
pub item_substs: NodeMap<ty::ItemSubsts<'tcx>>,
- pub adjustments: NodeMap<ty::AutoAdjustment<'tcx>>,
+ pub adjustments: NodeMap<ty::adjustment::AutoAdjustment<'tcx>>,
pub method_map: ty::MethodMap<'tcx>,
pub const_qualif_map: RefCell<NodeMap<middle::check_const::ConstQualif>>,
/// Caches CoerceUnsized kinds for impls on custom types.
- pub custom_coerce_unsized_kinds: RefCell<DefIdMap<ty::CustomCoerceUnsized>>,
+ pub custom_coerce_unsized_kinds: RefCell<DefIdMap<ty::adjustment::CustomCoerceUnsized>>,
/// Maps a cast expression to its kind. This is keyed on the
/// *from* expression of the cast, not the cast itself.
use middle::region;
use middle::subst;
+use middle::ty::adjustment;
use middle::ty::{self, Binder, Ty, HasTypeFlags, RegionEscape};
use std::fmt;
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)
}
}
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)
}
}
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;
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;
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};
pub use self::context::{ctxt, tls};
pub use self::context::{CtxtArenas, Lift, Tables};
+pub mod adjustment;
pub mod cast;
pub mod error;
pub mod fast_reject;
pub mod relate;
pub mod walk;
pub mod wf;
+pub mod util;
mod contents;
mod context;
mod sty;
pub type Disr = u64;
-
pub const INITIAL_DISCRIMINANT_VALUE: Disr = 0;
// Data types
}
}
-pub trait IntTypeExt {
- fn to_ty<'tcx>(&self, cx: &ctxt<'tcx>) -> Ty<'tcx>;
- fn i64_to_disr(&self, val: i64) -> Option<Disr>;
- fn u64_to_disr(&self, val: u64) -> Option<Disr>;
- fn disr_incr(&self, val: Disr) -> Option<Disr>;
- fn disr_string(&self, val: Disr) -> String;
- fn disr_wrap_incr(&self, val: Option<Disr>) -> 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<Disr> {
- 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<Disr> {
- 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<Disr> {
- 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>) -> 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),
Bivariant, // T<A> <: T<B> -- 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<T> { 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<T>` to `Box<Trait>` 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<AutoRef<'tcx>>,
-
- /// 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<Ty<'tcx>>,
-}
-
-#[derive(Copy, Clone, PartialEq, Debug)]
-pub enum AutoRef<'tcx> {
- /// Convert from T to &T.
- AutoPtr(&'tcx Region, hir::Mutability),
-
- /// Convert from T to *T.
- /// Value to thin pointer.
- AutoUnsafe(hir::Mutability),
-}
-
-#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
-pub enum CustomCoerceUnsized {
- /// Records the index of the field being coerced.
- Struct(usize)
-}
-
#[derive(Clone, Copy, Debug)]
pub struct MethodCallee<'tcx> {
/// Impl method ID, for inherent methods, or trait method ID, otherwise.
}
}
}
-
- pub 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
}
}
-impl<'tcx> ctxt<'tcx> {
- pub fn pat_contains_ref_binding(&self, pat: &hir::Pat) -> Option<hir::Mutability> {
- pat_util::pat_contains_ref_binding(&self.def_map, pat)
- }
-
- pub fn arm_contains_ref_binding(&self, arm: &hir::Arm) -> Option<hir::Mutability> {
- 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
walk::walk_shallow(self)
}
- pub fn as_opt_param_ty(&self) -> Option<ty::ParamTy> {
- match self.sty {
- ty::TyParam(ref d) => Some(d.clone()),
- _ => None,
- }
- }
-
- pub fn is_param(&self, space: ParamSpace, index: u32) -> bool {
- match self.sty {
- ty::TyParam(ref data) => data.space == space && data.idx == index,
- _ => false,
- }
- }
-
- /// Returns the regions directly referenced from this type (but
- /// not types reachable from this type via `walk_tys`). This
- /// ignores late-bound regions binders.
- pub fn regions(&self) -> Vec<ty::Region> {
- match self.sty {
- TyRef(region, _) => {
- vec![*region]
- }
- TyTrait(ref obj) => {
- let mut v = vec![obj.bounds.region_bound];
- v.push_all(obj.principal.skip_binder().substs.regions().as_slice());
- v
- }
- 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.
}
}
-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() }
}
}
-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,
}
}
-/// 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<Item=Ty<'tcx>>>(cx: &ctxt<'tcx>, sp: Span,
- seen: &mut Vec<Ty<'tcx>>,
- 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<'tcx>>, 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<'tcx>>,
- 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<T> in this example counts as SelfRecursive:
- //
- // struct Foo;
- // struct Bar<T> { x: Bar<Foo> }
-
- 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<Option<Foo>> }
-
- 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<Ty> = 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<F>(&'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<Ty<'tcx>>,
- {
- 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<F>(&'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<Ty<'tcx>>,
- {
- 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<AutoRef<'tcx>>)
- -> 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
}
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<DefId>) -> Option<Ty<'tcx>> {
- 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<DefId>) -> Option<Ty<'tcx>> {
- 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,
}
}
- 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")
}
}
- /// 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);
})
}
-
- /// 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<T>>, Foo<Trait>)`, the result will be `(Foo<T>, 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<F>(&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<ty::Predicate<'tcx>>)
- -> Vec<ty::Region> {
- 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<ItemVariances> {
lookup_locally_or_in_crate_store(
"item_variance_map", item_id, &self.item_variance_map,
}
}
- /// 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<FnSig<'tcx>>| {
- 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)
pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
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.
// imported.
pub type GlobMap = HashMap<NodeId, HashSet<Name>>;
-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<T, F>(&self, fid: NodeId, f: F) -> T where
F: FnOnce(&[Freevar]) -> T,
}
}
-impl<'tcx> TypeFoldable<'tcx> for ty::AutoRef<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::AutoRef<'tcx> {
+impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoRef<'tcx> {
+ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::adjustment::AutoRef<'tcx> {
folder.fold_autoref(self)
}
}
use std::mem;
use syntax::abi;
use syntax::ast::{Name, NodeId};
+use syntax::parse::token::special_idents;
use rustc_front::hir;
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:
// Type utilities
impl<'tcx> TyS<'tcx> {
+ pub fn as_opt_param_ty(&self) -> Option<ty::ParamTy> {
+ 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(),
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,
_ => 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<ty::Region> {
+ match self.sty {
+ TyRef(region, _) => {
+ vec![*region]
+ }
+ TyTrait(ref obj) => {
+ let mut v = vec![obj.bounds.region_bound];
+ v.push_all(obj.principal.skip_binder().substs.regions().as_slice());
+ v
+ }
+ 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![]
+ }
+ }
+ }
}
--- /dev/null
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! 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<Disr>;
+ fn u64_to_disr(&self, val: u64) -> Option<Disr>;
+ fn disr_incr(&self, val: Disr) -> Option<Disr>;
+ fn disr_string(&self, val: Disr) -> String;
+ fn disr_wrap_incr(&self, val: Option<Disr>) -> 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<Disr> {
+ 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<Disr> {
+ 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<Disr> {
+ 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>) -> 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<hir::Mutability> {
+ pat_util::pat_contains_ref_binding(&self.def_map, pat)
+ }
+
+ pub fn arm_contains_ref_binding(&self, arm: &hir::Arm) -> Option<hir::Mutability> {
+ pat_util::arm_contains_ref_binding(&self.def_map, arm)
+ }
+
+ /// 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<DefId>) -> Option<Ty<'tcx>> {
+ 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<DefId>) -> Option<Ty<'tcx>> {
+ 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<T>>, Foo<Trait>)`, the result will be `(Foo<T>, 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<ty::Predicate<'tcx>>)
+ -> Vec<ty::Region> {
+ 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<ty::FnSig<'tcx>>| {
+ 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<Item=Ty<'tcx>>>(cx: &ty::ctxt<'tcx>,
+ sp: Span,
+ seen: &mut Vec<Ty<'tcx>>,
+ 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<'tcx>>, 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<'tcx>>,
+ 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<T> in this example counts as SelfRecursive:
+ //
+ // struct Foo;
+ // struct Bar<T> { x: Bar<Foo> }
+
+ 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<Option<Foo>> }
+
+ 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<Ty> = Vec::new();
+ let r = is_type_structurally_recursive(cx, sp, &mut seen, self);
+ debug!("is_type_representable: {:?} is {:?}", self, r);
+ r
+ }
+}
}
}
-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)
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;
}
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");
}
}
// 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) {
// 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,
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,
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 =
} 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,
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.
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;
&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 {
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};
};
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());
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;
unsizing_obligations: RefCell<Vec<traits::PredicateObligation<'tcx>>>,
}
-type CoerceResult<'tcx> = RelateResult<'tcx, Option<ty::AutoAdjustment<'tcx>>>;
+type CoerceResult<'tcx> = RelateResult<'tcx, Option<AutoAdjustment<'tcx>>>;
impl<'f, 'tcx> Coerce<'f, 'tcx> {
fn tcx(&self) -> &ty::ctxt<'tcx> {
let coercion = Coercion(self.origin.span());
let r_borrow = self.fcx.infcx().next_region_var(coercion);
let r_borrow = self.tcx().mk_region(r_borrow);
- let autoref = Some(ty::AutoPtr(r_borrow, mutbl_b));
+ let autoref = Some(AutoPtr(r_borrow, mutbl_b));
let lvalue_pref = LvaluePreference::from_mutbl(mutbl_b);
let mut first_error = None;
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)
};
(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));
}
_ => {}
}
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)
}
if is_ref {
Ok(Some(AdjustDerefRef(AutoDerefRef {
autoderefs: 1,
- autoref: Some(ty::AutoUnsafe(mutbl_b)),
+ autoref: Some(AutoUnsafe(mutbl_b)),
unsize: None
})))
} else {
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;
{
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))
}))
// 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
.borrow()
.adjustments
.get(&expr.id) {
- Some(&ty::AdjustDerefRef(ref adj)) => adj.autoderefs,
+ Some(&AdjustDerefRef(ref adj)) => adj.autoderefs,
Some(_) | None => 0,
};
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
(target, true)
} else {
(self.fcx.adjust_expr_ty(base_expr,
- Some(&ty::AdjustDerefRef(ty::AutoDerefRef {
+ Some(&AdjustDerefRef(AutoDerefRef {
autoderefs: autoderefs,
autoref: None,
unsize: None
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;
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 {
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;
derefs: usize) {
self.write_adjustment(
node_id,
- ty::AdjustDerefRef(ty::AutoDerefRef {
+ adjustment::AdjustDerefRef(adjustment::AutoDerefRef {
autoderefs: derefs,
autoref: None,
unsize: None
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() {
/// 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);
// 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
}
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;
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 {
}
}
/*
- 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.
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());
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);
}
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;
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),
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};
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};
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");
}
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))
}
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;