rustc_typeck: hook up collect and item/body check to on-demand.

This commit is contained in:
Eduard-Mihai Burtescu 2017-02-14 11:32:00 +02:00
parent 9c3c306800
commit ba11640179
36 changed files with 782 additions and 1097 deletions

View File

@ -159,10 +159,9 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
hir_map::NodeItem(item) => { hir_map::NodeItem(item) => {
match item.node { match item.node {
hir::ItemStruct(..) | hir::ItemUnion(..) => { hir::ItemStruct(..) | hir::ItemUnion(..) => {
self.struct_has_extern_repr = item.attrs.iter().any(|attr| { let def_id = self.tcx.hir.local_def_id(item.id);
attr::find_repr_attrs(self.tcx.sess.diagnostic(), attr) let def = self.tcx.lookup_adt_def(def_id);
.contains(&attr::ReprExtern) self.struct_has_extern_repr = def.repr.c;
});
intravisit::walk_item(self, &item); intravisit::walk_item(self, &item);
} }

View File

@ -173,9 +173,7 @@ impl<'tcx> Rvalue<'tcx> {
Rvalue::Discriminant(ref lval) => { Rvalue::Discriminant(ref lval) => {
let ty = lval.ty(mir, tcx).to_ty(tcx); let ty = lval.ty(mir, tcx).to_ty(tcx);
if let ty::TyAdt(adt_def, _) = ty.sty { if let ty::TyAdt(adt_def, _) = ty.sty {
let repr_hints = tcx.lookup_repr_hints(adt_def.did); Some(adt_def.repr.discr_type().to_ty(tcx))
let repr_type = tcx.enum_repr_type(repr_hints.get(0));
Some(repr_type.to_ty(tcx))
} else { } else {
// Undefined behaviour, bug for now; may want to return something for // Undefined behaviour, bug for now; may want to return something for
// the `discriminant` intrinsic later. // the `discriminant` intrinsic later.

View File

@ -11,11 +11,9 @@
use dep_graph::DepGraph; use dep_graph::DepGraph;
use infer::{InferCtxt, InferOk}; use infer::{InferCtxt, InferOk};
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, TyCtxt, ToPredicate}; use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, TyCtxt, ToPredicate};
use ty::subst::Subst;
use rustc_data_structures::obligation_forest::{ObligationForest, Error}; use rustc_data_structures::obligation_forest::{ObligationForest, Error};
use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor}; use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem;
use syntax::ast; use syntax::ast;
use util::nodemap::{FxHashSet, NodeMap}; use util::nodemap::{FxHashSet, NodeMap};
use hir::def_id::DefId; use hir::def_id::DefId;
@ -23,9 +21,8 @@ use hir::def_id::DefId;
use super::CodeAmbiguity; use super::CodeAmbiguity;
use super::CodeProjectionError; use super::CodeProjectionError;
use super::CodeSelectionError; use super::CodeSelectionError;
use super::{FulfillmentError, FulfillmentErrorCode, SelectionError}; use super::{FulfillmentError, FulfillmentErrorCode};
use super::{ObligationCause, BuiltinDerivedObligation}; use super::{ObligationCause, PredicateObligation, Obligation};
use super::{PredicateObligation, TraitObligation, Obligation};
use super::project; use super::project;
use super::select::SelectionContext; use super::select::SelectionContext;
use super::Unimplemented; use super::Unimplemented;
@ -82,10 +79,6 @@ pub struct FulfillmentContext<'tcx> {
// obligations (otherwise, it's easy to fail to walk to a // obligations (otherwise, it's easy to fail to walk to a
// particular node-id). // particular node-id).
region_obligations: NodeMap<Vec<RegionObligation<'tcx>>>, region_obligations: NodeMap<Vec<RegionObligation<'tcx>>>,
// A list of obligations that need to be deferred to
// a later time for them to be properly fulfilled.
deferred_obligations: Vec<DeferredObligation<'tcx>>,
} }
#[derive(Clone)] #[derive(Clone)]
@ -101,100 +94,12 @@ pub struct PendingPredicateObligation<'tcx> {
pub stalled_on: Vec<Ty<'tcx>>, pub stalled_on: Vec<Ty<'tcx>>,
} }
/// An obligation which cannot be fulfilled in the context
/// it was registered in, such as auto trait obligations on
/// `impl Trait`, which require the concrete type to be
/// available, only guaranteed after finishing type-checking.
#[derive(Clone, Debug)]
pub struct DeferredObligation<'tcx> {
pub predicate: ty::PolyTraitPredicate<'tcx>,
pub cause: ObligationCause<'tcx>
}
impl<'a, 'gcx, 'tcx> DeferredObligation<'tcx> {
/// If possible, create a `DeferredObligation` from
/// a trait predicate which had failed selection,
/// but could succeed later.
pub fn from_select_error(tcx: TyCtxt<'a, 'gcx, 'tcx>,
obligation: &TraitObligation<'tcx>,
selection_err: &SelectionError<'tcx>)
-> Option<DeferredObligation<'tcx>> {
if let Unimplemented = *selection_err {
if DeferredObligation::must_defer(tcx, &obligation.predicate) {
return Some(DeferredObligation {
predicate: obligation.predicate.clone(),
cause: obligation.cause.clone()
});
}
}
None
}
/// Returns true if the given trait predicate can be
/// fulfilled at a later time.
pub fn must_defer(tcx: TyCtxt<'a, 'gcx, 'tcx>,
predicate: &ty::PolyTraitPredicate<'tcx>)
-> bool {
// Auto trait obligations on `impl Trait`.
if tcx.trait_has_default_impl(predicate.def_id()) {
let substs = predicate.skip_binder().trait_ref.substs;
if substs.types().count() == 1 && substs.regions().next().is_none() {
if let ty::TyAnon(..) = predicate.skip_binder().self_ty().sty {
return true;
}
}
}
false
}
/// If possible, return the nested obligations required
/// to fulfill this obligation.
pub fn try_select(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
-> Option<Vec<PredicateObligation<'tcx>>> {
if let ty::TyAnon(def_id, substs) = self.predicate.skip_binder().self_ty().sty {
let ty = if def_id.is_local() {
tcx.maps.ty.borrow().get(&def_id).cloned()
} else {
Some(tcx.item_type(def_id))
};
// We can resolve the `impl Trait` to its concrete type.
if let Some(concrete_ty) = ty.subst(tcx, substs) {
let predicate = ty::TraitRef {
def_id: self.predicate.def_id(),
substs: tcx.mk_substs_trait(concrete_ty, &[])
}.to_predicate();
let original_obligation = Obligation::new(self.cause.clone(),
self.predicate.clone());
let cause = original_obligation.derived_cause(BuiltinDerivedObligation);
return Some(vec![Obligation::new(cause, predicate)]);
}
}
None
}
/// Return the `PredicateObligation` this was created from.
pub fn to_obligation(&self) -> PredicateObligation<'tcx> {
let predicate = ty::Predicate::Trait(self.predicate.clone());
Obligation::new(self.cause.clone(), predicate)
}
/// Return an error as if this obligation had failed.
pub fn to_error(&self) -> FulfillmentError<'tcx> {
FulfillmentError::new(self.to_obligation(), CodeSelectionError(Unimplemented))
}
}
impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
/// Creates a new fulfillment context. /// Creates a new fulfillment context.
pub fn new() -> FulfillmentContext<'tcx> { pub fn new() -> FulfillmentContext<'tcx> {
FulfillmentContext { FulfillmentContext {
predicates: ObligationForest::new(), predicates: ObligationForest::new(),
region_obligations: NodeMap(), region_obligations: NodeMap(),
deferred_obligations: vec![],
} }
} }
@ -294,16 +199,10 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
{ {
self.select_where_possible(infcx)?; self.select_where_possible(infcx)?;
// Fail all of the deferred obligations that haven't
// been otherwise removed from the context.
let deferred_errors = self.deferred_obligations.iter()
.map(|d| d.to_error());
let errors: Vec<_> = let errors: Vec<_> =
self.predicates.to_errors(CodeAmbiguity) self.predicates.to_errors(CodeAmbiguity)
.into_iter() .into_iter()
.map(|e| to_fulfillment_error(e)) .map(|e| to_fulfillment_error(e))
.chain(deferred_errors)
.collect(); .collect();
if errors.is_empty() { if errors.is_empty() {
Ok(()) Ok(())
@ -324,10 +223,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
self.predicates.pending_obligations() self.predicates.pending_obligations()
} }
pub fn take_deferred_obligations(&mut self) -> Vec<DeferredObligation<'tcx>> {
mem::replace(&mut self.deferred_obligations, vec![])
}
/// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it /// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it
/// only attempts to select obligations that haven't been seen before. /// only attempts to select obligations that haven't been seen before.
fn select(&mut self, selcx: &mut SelectionContext<'a, 'gcx, 'tcx>) fn select(&mut self, selcx: &mut SelectionContext<'a, 'gcx, 'tcx>)
@ -343,7 +238,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
let outcome = self.predicates.process_obligations(&mut FulfillProcessor { let outcome = self.predicates.process_obligations(&mut FulfillProcessor {
selcx: selcx, selcx: selcx,
region_obligations: &mut self.region_obligations, region_obligations: &mut self.region_obligations,
deferred_obligations: &mut self.deferred_obligations
}); });
debug!("select: outcome={:?}", outcome); debug!("select: outcome={:?}", outcome);
@ -378,7 +272,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
struct FulfillProcessor<'a, 'b: 'a, 'gcx: 'tcx, 'tcx: 'b> { struct FulfillProcessor<'a, 'b: 'a, 'gcx: 'tcx, 'tcx: 'b> {
selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>, selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
region_obligations: &'a mut NodeMap<Vec<RegionObligation<'tcx>>>, region_obligations: &'a mut NodeMap<Vec<RegionObligation<'tcx>>>,
deferred_obligations: &'a mut Vec<DeferredObligation<'tcx>>
} }
impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, 'tcx> { impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, 'tcx> {
@ -391,8 +284,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
{ {
process_predicate(self.selcx, process_predicate(self.selcx,
obligation, obligation,
self.region_obligations, self.region_obligations)
self.deferred_obligations)
.map(|os| os.map(|os| os.into_iter().map(|o| PendingPredicateObligation { .map(|os| os.map(|os| os.into_iter().map(|o| PendingPredicateObligation {
obligation: o, obligation: o,
stalled_on: vec![] stalled_on: vec![]
@ -432,8 +324,7 @@ fn trait_ref_type_vars<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 't
fn process_predicate<'a, 'gcx, 'tcx>( fn process_predicate<'a, 'gcx, 'tcx>(
selcx: &mut SelectionContext<'a, 'gcx, 'tcx>, selcx: &mut SelectionContext<'a, 'gcx, 'tcx>,
pending_obligation: &mut PendingPredicateObligation<'tcx>, pending_obligation: &mut PendingPredicateObligation<'tcx>,
region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>, region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>)
deferred_obligations: &mut Vec<DeferredObligation<'tcx>>)
-> Result<Option<Vec<PredicateObligation<'tcx>>>, -> Result<Option<Vec<PredicateObligation<'tcx>>>,
FulfillmentErrorCode<'tcx>> FulfillmentErrorCode<'tcx>>
{ {
@ -502,24 +393,10 @@ fn process_predicate<'a, 'gcx, 'tcx>(
info!("selecting trait `{:?}` at depth {} yielded Err", info!("selecting trait `{:?}` at depth {} yielded Err",
data, obligation.recursion_depth); data, obligation.recursion_depth);
let defer = DeferredObligation::from_select_error(selcx.tcx(),
&trait_obligation,
&selection_err);
if let Some(deferred_obligation) = defer {
if let Some(nested) = deferred_obligation.try_select(selcx.tcx()) {
Ok(Some(nested))
} else {
// Pretend that the obligation succeeded,
// but record it for later.
deferred_obligations.push(deferred_obligation);
Ok(Some(vec![]))
}
} else {
Err(CodeSelectionError(selection_err)) Err(CodeSelectionError(selection_err))
} }
} }
} }
}
ty::Predicate::Equate(ref binder) => { ty::Predicate::Equate(ref binder) => {
match selcx.infcx().equality_predicate(&obligation.cause, binder) { match selcx.infcx().equality_predicate(&obligation.cause, binder) {
@ -714,12 +591,6 @@ impl<'a, 'gcx, 'tcx> GlobalFulfilledPredicates<'gcx> {
// already has the required read edges, so we don't need // already has the required read edges, so we don't need
// to add any more edges here. // to add any more edges here.
if data.is_global() { if data.is_global() {
// Don't cache predicates which were fulfilled
// by deferring them for later fulfillment.
if DeferredObligation::must_defer(tcx, data) {
return;
}
if let Some(data) = tcx.lift_to_global(data) { if let Some(data) = tcx.lift_to_global(data) {
if self.set.insert(data.clone()) { if self.set.insert(data.clone()) {
debug!("add_if_global: global predicate `{:?}` added", data); debug!("add_if_global: global predicate `{:?}` added", data);

View File

@ -31,7 +31,6 @@ pub use self::coherence::orphan_check;
pub use self::coherence::overlapping_impls; pub use self::coherence::overlapping_impls;
pub use self::coherence::OrphanCheckErr; pub use self::coherence::OrphanCheckErr;
pub use self::fulfill::{FulfillmentContext, GlobalFulfilledPredicates, RegionObligation}; pub use self::fulfill::{FulfillmentContext, GlobalFulfilledPredicates, RegionObligation};
pub use self::fulfill::DeferredObligation;
pub use self::project::MismatchedProjectionTypes; pub use self::project::MismatchedProjectionTypes;
pub use self::project::{normalize, normalize_projection_type, Normalized}; pub use self::project::{normalize, normalize_projection_type, Normalized};
pub use self::project::{ProjectionCache, ProjectionCacheSnapshot, Reveal}; pub use self::project::{ProjectionCache, ProjectionCacheSnapshot, Reveal};

View File

@ -1478,8 +1478,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// `assemble_candidates_from_object_ty`. // `assemble_candidates_from_object_ty`.
} }
ty::TyParam(..) | ty::TyParam(..) |
ty::TyProjection(..) | ty::TyProjection(..) => {
ty::TyAnon(..) => {
// In these cases, we don't know what the actual // In these cases, we don't know what the actual
// type is. Therefore, we cannot break it down // type is. Therefore, we cannot break it down
// into its constituent types. So we don't // into its constituent types. So we don't
@ -1902,7 +1901,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
ty::TyDynamic(..) | ty::TyDynamic(..) |
ty::TyParam(..) | ty::TyParam(..) |
ty::TyProjection(..) | ty::TyProjection(..) |
ty::TyAnon(..) |
ty::TyInfer(ty::TyVar(_)) | ty::TyInfer(ty::TyVar(_)) |
ty::TyInfer(ty::FreshTy(_)) | ty::TyInfer(ty::FreshTy(_)) |
ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshIntTy(_)) |
@ -1947,6 +1945,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
.map(|f| f.ty(self.tcx(), substs)) .map(|f| f.ty(self.tcx(), substs))
.collect() .collect()
} }
ty::TyAnon(def_id, substs) => {
// We can resolve the `impl Trait` to its concrete type,
// which enforces a DAG between the functions requiring
// the auto trait bounds in question.
vec![self.tcx().item_type(def_id).subst(self.tcx(), substs)]
}
} }
} }

View File

@ -269,20 +269,6 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCause<'a> {
} }
} }
impl<'a, 'tcx> Lift<'tcx> for traits::DeferredObligation<'a> {
type Lifted = traits::DeferredObligation<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
tcx.lift(&self.predicate).and_then(|predicate| {
tcx.lift(&self.cause).map(|cause| {
traits::DeferredObligation {
predicate: predicate,
cause: cause
}
})
})
}
}
// For trans only. // For trans only.
impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> { impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> {
type Lifted = traits::Vtable<'tcx, ()>; type Lifted = traits::Vtable<'tcx, ()>;
@ -589,16 +575,3 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCause<'tcx> {
self.code.visit_with(visitor) self.code.visit_with(visitor)
} }
} }
impl<'tcx> TypeFoldable<'tcx> for traits::DeferredObligation<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
traits::DeferredObligation {
predicate: self.predicate.fold_with(folder),
cause: self.cause.fold_with(folder)
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.predicate.visit_with(visitor) || self.cause.visit_with(visitor)
}
}

View File

@ -38,7 +38,6 @@ use ty::TypeVariants::*;
use ty::layout::{Layout, TargetDataLayout}; use ty::layout::{Layout, TargetDataLayout};
use ty::inhabitedness::DefIdForest; use ty::inhabitedness::DefIdForest;
use ty::maps; use ty::maps;
use util::common::MemoizationMap;
use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet}; use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
use util::nodemap::{FxHashMap, FxHashSet}; use util::nodemap::{FxHashMap, FxHashSet};
use rustc_data_structures::accumulate_vec::AccumulateVec; use rustc_data_structures::accumulate_vec::AccumulateVec;
@ -50,7 +49,6 @@ use std::cell::{Cell, RefCell};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::mem; use std::mem;
use std::ops::Deref; use std::ops::Deref;
use std::rc::Rc;
use std::iter; use std::iter;
use std::cmp::Ordering; use std::cmp::Ordering;
use syntax::abi; use syntax::abi;
@ -242,6 +240,10 @@ pub struct TypeckTables<'tcx> {
/// Lints for the body of this fn generated by typeck. /// Lints for the body of this fn generated by typeck.
pub lints: lint::LintTable, pub lints: lint::LintTable,
/// Set of trait imports actually used in the method resolution.
/// This is used for warning unused imports.
pub used_trait_imports: DefIdSet,
} }
impl<'tcx> TypeckTables<'tcx> { impl<'tcx> TypeckTables<'tcx> {
@ -259,6 +261,7 @@ impl<'tcx> TypeckTables<'tcx> {
fru_field_types: NodeMap(), fru_field_types: NodeMap(),
cast_kinds: NodeMap(), cast_kinds: NodeMap(),
lints: lint::LintTable::new(), lints: lint::LintTable::new(),
used_trait_imports: DefIdSet(),
} }
} }
@ -531,11 +534,6 @@ pub struct GlobalCtxt<'tcx> {
/// shouldn't taint the common path (hence the RefCell). /// shouldn't taint the common path (hence the RefCell).
pub all_traits: RefCell<Option<Vec<DefId>>>, pub all_traits: RefCell<Option<Vec<DefId>>>,
/// Obligations which will have to be checked at the end of
/// type-checking, after all functions have been inferred.
/// The key is the NodeId of the item the obligations were from.
pub deferred_obligations: RefCell<NodeMap<Vec<traits::DeferredObligation<'tcx>>>>,
/// HIR Ty -> Ty lowering cache. /// HIR Ty -> Ty lowering cache.
pub ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>, pub ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
} }
@ -734,7 +732,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
derive_macros: RefCell::new(NodeMap()), derive_macros: RefCell::new(NodeMap()),
stability_interner: RefCell::new(FxHashSet()), stability_interner: RefCell::new(FxHashSet()),
all_traits: RefCell::new(None), all_traits: RefCell::new(None),
deferred_obligations: RefCell::new(NodeMap()),
ast_ty_to_ty_cache: RefCell::new(NodeMap()), ast_ty_to_ty_cache: RefCell::new(NodeMap()),
}, f) }, f)
} }
@ -1449,15 +1446,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
{ {
self.mk_substs(iter::once(s).chain(t.into_iter().cloned()).map(Kind::from)) self.mk_substs(iter::once(s).chain(t.into_iter().cloned()).map(Kind::from))
} }
/// Obtain the representation annotation for a struct definition.
pub fn lookup_repr_hints(self, did: DefId) -> Rc<Vec<attr::ReprAttr>> {
self.maps.repr_hints.memoize(did, || {
Rc::new(self.get_attrs(did).iter().flat_map(|meta| {
attr::find_repr_attrs(self.sess.diagnostic(), meta).into_iter()
}).collect())
})
}
} }
pub trait InternAs<T: ?Sized, R> { pub trait InternAs<T: ?Sized, R> {

View File

@ -1147,7 +1147,7 @@ impl<'a, 'gcx, 'tcx> Layout {
} }
// SIMD vector types. // SIMD vector types.
ty::TyAdt(def, ..) if def.is_simd() => { ty::TyAdt(def, ..) if def.repr.simd => {
let element = ty.simd_type(tcx); let element = ty.simd_type(tcx);
match *element.layout(infcx)? { match *element.layout(infcx)? {
Scalar { value, .. } => { Scalar { value, .. } => {
@ -1227,9 +1227,8 @@ impl<'a, 'gcx, 'tcx> Layout {
let fields = def.variants[0].fields.iter().map(|field| { let fields = def.variants[0].fields.iter().map(|field| {
field.ty(tcx, substs).layout(infcx) field.ty(tcx, substs).layout(infcx)
}).collect::<Result<Vec<_>, _>>()?; }).collect::<Result<Vec<_>, _>>()?;
let packed = tcx.lookup_packed(def.did);
let layout = if def.is_union() { let layout = if def.is_union() {
let mut un = Union::new(dl, packed); let mut un = Union::new(dl, def.repr.packed);
un.extend(dl, fields.iter().map(|&f| Ok(f)), ty)?; un.extend(dl, fields.iter().map(|&f| Ok(f)), ty)?;
UntaggedUnion { variants: un } UntaggedUnion { variants: un }
} else { } else {
@ -1353,9 +1352,7 @@ impl<'a, 'gcx, 'tcx> Layout {
return Err(LayoutError::SizeOverflow(ty)); return Err(LayoutError::SizeOverflow(ty));
} }
let repr_hints = tcx.lookup_repr_hints(def.did); let typeck_ity = Integer::from_attr(dl, def.repr.discr_type());
let repr_type = tcx.enum_repr_type(repr_hints.get(0));
let typeck_ity = Integer::from_attr(dl, repr_type);
if typeck_ity < min_ity { if typeck_ity < min_ity {
// It is a bug if Layout decided on a greater discriminant size than typeck for // It is a bug if Layout decided on a greater discriminant size than typeck for
// some reason at this point (based on values discriminant can take on). Mostly // some reason at this point (based on values discriminant can take on). Mostly

View File

@ -14,28 +14,33 @@ use middle::const_val::ConstVal;
use mir; use mir;
use ty::{self, Ty, TyCtxt}; use ty::{self, Ty, TyCtxt};
use util::common::MemoizationMap; use util::common::MemoizationMap;
use util::nodemap::DefIdSet;
use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::indexed_vec::IndexVec;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use syntax::attr; use syntax_pos::{Span, DUMMY_SP};
use syntax_pos::Span;
trait Key { trait Key {
fn map_crate(&self) -> CrateNum; fn map_crate(&self) -> CrateNum;
fn default_span(&self, tcx: TyCtxt) -> Span;
} }
impl Key for DefId { impl Key for DefId {
fn map_crate(&self) -> CrateNum { fn map_crate(&self) -> CrateNum {
self.krate self.krate
} }
fn default_span(&self, tcx: TyCtxt) -> Span {
tcx.def_span(*self)
}
} }
impl Key for (DefId, DefId) { impl Key for (DefId, DefId) {
fn map_crate(&self) -> CrateNum { fn map_crate(&self) -> CrateNum {
self.0.krate self.0.krate
} }
fn default_span(&self, tcx: TyCtxt) -> Span {
self.1.default_span(tcx)
}
} }
trait Value<'tcx>: Sized { trait Value<'tcx>: Sized {
@ -83,7 +88,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
err.emit(); err.emit();
} }
pub fn cycle_check<F, R>(self, span: Span, query: Query, compute: F) -> R fn cycle_check<F, R>(self, span: Span, query: Query, compute: F) -> R
where F: FnOnce() -> R where F: FnOnce() -> R
{ {
{ {
@ -104,24 +109,29 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
} }
} }
impl Query { trait QueryDescription: DepTrackingMapConfig {
fn describe(&self, tcx: TyCtxt) -> String { fn describe(tcx: TyCtxt, key: Self::Key) -> String;
match *self { }
Query::ty(def_id) => {
impl<M: DepTrackingMapConfig<Key=DefId>> QueryDescription for M {
default fn describe(tcx: TyCtxt, def_id: DefId) -> String {
format!("processing `{}`", tcx.item_path_str(def_id)) format!("processing `{}`", tcx.item_path_str(def_id))
} }
Query::super_predicates(def_id) => { }
impl<'tcx> QueryDescription for queries::super_predicates<'tcx> {
fn describe(tcx: TyCtxt, def_id: DefId) -> String {
format!("computing the supertraits of `{}`", format!("computing the supertraits of `{}`",
tcx.item_path_str(def_id)) tcx.item_path_str(def_id))
} }
Query::type_param_predicates((_, def_id)) => { }
impl<'tcx> QueryDescription for queries::type_param_predicates<'tcx> {
fn describe(tcx: TyCtxt, (_, def_id): (DefId, DefId)) -> String {
let id = tcx.hir.as_local_node_id(def_id).unwrap(); let id = tcx.hir.as_local_node_id(def_id).unwrap();
format!("computing the bounds for type parameter `{}`", format!("computing the bounds for type parameter `{}`",
tcx.hir.ty_param_name(id)) tcx.hir.ty_param_name(id))
} }
_ => bug!("unexpected `{:?}`", self)
}
}
} }
macro_rules! define_maps { macro_rules! define_maps {
@ -152,6 +162,14 @@ macro_rules! define_maps {
$($(#[$attr])* $name($K)),* $($(#[$attr])* $name($K)),*
} }
impl Query {
pub fn describe(&self, tcx: TyCtxt) -> String {
match *self {
$(Query::$name(key) => queries::$name::describe(tcx, key)),*
}
}
}
pub mod queries { pub mod queries {
use std::marker::PhantomData; use std::marker::PhantomData;
@ -186,11 +204,22 @@ macro_rules! define_maps {
} }
} }
impl<$tcx> Maps<$tcx> { impl<'a, $tcx, 'lcx> Maps<$tcx> {
$($(#[$attr])* $($(#[$attr])*
pub fn $name<'a, 'lcx>(&self, tcx: TyCtxt<'a, $tcx, 'lcx>, key: $K) -> $V { pub fn $name(&self,
tcx: TyCtxt<'a, $tcx, 'lcx>,
mut span: Span,
key: $K) -> $V {
self.$name.memoize(key, || { self.$name.memoize(key, || {
(self.providers[key.map_crate()].$name)(tcx.global_tcx(), key) // FIXME(eddyb) Get more valid Span's on queries.
if span == DUMMY_SP {
span = key.default_span(tcx);
}
tcx.cycle_check(span, Query::$name(key), || {
let provider = self.providers[key.map_crate()].$name;
provider(tcx.global_tcx(), key)
})
}) })
})* })*
} }
@ -246,9 +275,6 @@ define_maps! { <'tcx>
/// Methods in these implementations don't need to be exported. /// Methods in these implementations don't need to be exported.
pub inherent_impls: InherentImpls(DefId) -> Vec<DefId>, pub inherent_impls: InherentImpls(DefId) -> Vec<DefId>,
/// Caches the representation hints for struct definitions.
pub repr_hints: ReprHints(DefId) -> Rc<Vec<attr::ReprAttr>>,
/// Maps from the def-id of a function/method or const/static /// Maps from the def-id of a function/method or const/static
/// to its MIR. Mutation is done at an item granularity to /// to its MIR. Mutation is done at an item granularity to
/// allow MIR optimization passes to function and still /// allow MIR optimization passes to function and still
@ -272,10 +298,6 @@ define_maps! { <'tcx>
pub typeck_tables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>, pub typeck_tables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>,
/// Set of trait imports actually used in the method resolution.
/// This is used for warning unused imports.
pub used_trait_imports: UsedTraitImports(DefId) -> DefIdSet,
/// Results of evaluating monomorphic constants embedded in /// Results of evaluating monomorphic constants embedded in
/// other items, such as enum variant explicit discriminants. /// other items, such as enum variant explicit discriminants.
pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result<ConstVal, ()> pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result<ConstVal, ()>

View File

@ -1296,10 +1296,9 @@ bitflags! {
const IS_DTORCK = 1 << 1, // is this a dtorck type? const IS_DTORCK = 1 << 1, // is this a dtorck type?
const IS_DTORCK_VALID = 1 << 2, const IS_DTORCK_VALID = 1 << 2,
const IS_PHANTOM_DATA = 1 << 3, const IS_PHANTOM_DATA = 1 << 3,
const IS_SIMD = 1 << 4, const IS_FUNDAMENTAL = 1 << 4,
const IS_FUNDAMENTAL = 1 << 5, const IS_UNION = 1 << 5,
const IS_UNION = 1 << 6, const IS_BOX = 1 << 6,
const IS_BOX = 1 << 7,
} }
} }
@ -1384,18 +1383,29 @@ pub struct ReprOptions {
impl ReprOptions { impl ReprOptions {
pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions { pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions {
let mut ret = ReprOptions::default(); let mut ret = ReprOptions::default();
let attrs = tcx.lookup_repr_hints(did);
for r in attrs.iter() { for attr in tcx.get_attrs(did).iter() {
match *r { for r in attr::find_repr_attrs(tcx.sess.diagnostic(), attr) {
match r {
attr::ReprExtern => ret.c = true, attr::ReprExtern => ret.c = true,
attr::ReprPacked => ret.packed = true, attr::ReprPacked => ret.packed = true,
attr::ReprSimd => ret.simd = true, attr::ReprSimd => ret.simd = true,
attr::ReprInt(i) => ret.int = Some(i), attr::ReprInt(i) => ret.int = Some(i),
attr::ReprAny => (),
} }
} }
}
// FIXME(eddyb) This is deprecated and should be removed.
if tcx.has_attr(did, "simd") {
ret.simd = true;
}
ret ret
} }
pub fn discr_type(&self) -> attr::IntType {
self.int.unwrap_or(attr::SignedInt(ast::IntTy::Is))
}
} }
impl<'a, 'gcx, 'tcx> AdtDef { impl<'a, 'gcx, 'tcx> AdtDef {
@ -1409,9 +1419,6 @@ impl<'a, 'gcx, 'tcx> AdtDef {
if attr::contains_name(&attrs, "fundamental") { if attr::contains_name(&attrs, "fundamental") {
flags = flags | AdtFlags::IS_FUNDAMENTAL; flags = flags | AdtFlags::IS_FUNDAMENTAL;
} }
if tcx.lookup_simd(did) {
flags = flags | AdtFlags::IS_SIMD;
}
if Some(did) == tcx.lang_items.phantom_data() { if Some(did) == tcx.lang_items.phantom_data() {
flags = flags | AdtFlags::IS_PHANTOM_DATA; flags = flags | AdtFlags::IS_PHANTOM_DATA;
} }
@ -1500,11 +1507,6 @@ impl<'a, 'gcx, 'tcx> AdtDef {
self.flags.get().intersects(AdtFlags::IS_FUNDAMENTAL) self.flags.get().intersects(AdtFlags::IS_FUNDAMENTAL)
} }
#[inline]
pub fn is_simd(&self) -> bool {
self.flags.get().intersects(AdtFlags::IS_SIMD)
}
/// Returns true if this is PhantomData<T>. /// Returns true if this is PhantomData<T>.
#[inline] #[inline]
pub fn is_phantom_data(&self) -> bool { pub fn is_phantom_data(&self) -> bool {
@ -1584,8 +1586,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>) pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
-> impl Iterator<Item=ConstInt> + 'a { -> impl Iterator<Item=ConstInt> + 'a {
let repr_hints = tcx.lookup_repr_hints(self.did); let repr_type = self.repr.discr_type();
let repr_type = tcx.enum_repr_type(repr_hints.get(0));
let initial = repr_type.initial_discriminant(tcx.global_tcx()); let initial = repr_type.initial_discriminant(tcx.global_tcx());
let mut prev_discr = None::<ConstInt>; let mut prev_discr = None::<ConstInt>;
self.variants.iter().map(move |v| { self.variants.iter().map(move |v| {
@ -1946,25 +1947,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
} }
pub fn item_tables(self, def_id: DefId) -> &'gcx TypeckTables<'gcx> { pub fn item_tables(self, def_id: DefId) -> &'gcx TypeckTables<'gcx> {
self.maps.typeck_tables.memoize(def_id, || { self.maps.typeck_tables(self, DUMMY_SP, def_id)
if def_id.is_local() {
// Closures' tables come from their outermost function,
// as they are part of the same "inference environment".
let outer_def_id = self.closure_base_def_id(def_id);
if outer_def_id != def_id {
return self.item_tables(outer_def_id);
}
bug!("No def'n found for {:?} in tcx.tables", def_id);
}
// Cross-crate side-tables only exist alongside serialized HIR.
self.sess.cstore.maybe_get_item_body(self.global_tcx(), def_id).map(|_| {
self.maps.typeck_tables.borrow()[&def_id]
}).unwrap_or_else(|| {
bug!("tcx.item_tables({:?}): missing from metadata", def_id)
})
})
} }
pub fn expr_span(self, id: NodeId) -> Span { pub fn expr_span(self, id: NodeId) -> Span {
@ -2072,12 +2055,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
} }
pub fn custom_coerce_unsized_kind(self, did: DefId) -> adjustment::CustomCoerceUnsized { pub fn custom_coerce_unsized_kind(self, did: DefId) -> adjustment::CustomCoerceUnsized {
self.maps.custom_coerce_unsized_kind(self, did) self.maps.custom_coerce_unsized_kind(self, DUMMY_SP, did)
} }
pub fn associated_item(self, def_id: DefId) -> AssociatedItem { pub fn associated_item(self, def_id: DefId) -> AssociatedItem {
if !def_id.is_local() { if !def_id.is_local() {
return self.maps.associated_item(self, def_id); return self.maps.associated_item(self, DUMMY_SP, def_id);
} }
self.maps.associated_item.memoize(def_id, || { self.maps.associated_item.memoize(def_id, || {
@ -2182,7 +2165,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn associated_item_def_ids(self, def_id: DefId) -> Rc<Vec<DefId>> { pub fn associated_item_def_ids(self, def_id: DefId) -> Rc<Vec<DefId>> {
if !def_id.is_local() { if !def_id.is_local() {
return self.maps.associated_item_def_ids(self, def_id); return self.maps.associated_item_def_ids(self, DUMMY_SP, def_id);
} }
self.maps.associated_item_def_ids.memoize(def_id, || { self.maps.associated_item_def_ids.memoize(def_id, || {
@ -2217,7 +2200,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
/// Returns the trait-ref corresponding to a given impl, or None if it is /// Returns the trait-ref corresponding to a given impl, or None if it is
/// an inherent impl. /// an inherent impl.
pub fn impl_trait_ref(self, id: DefId) -> Option<TraitRef<'gcx>> { pub fn impl_trait_ref(self, id: DefId) -> Option<TraitRef<'gcx>> {
self.maps.impl_trait_ref(self, id) self.maps.impl_trait_ref(self, DUMMY_SP, id)
} }
// Returns `ty::VariantDef` if `def` refers to a struct, // Returns `ty::VariantDef` if `def` refers to a struct,
@ -2296,37 +2279,37 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
// If the given item is in an external crate, looks up its type and adds it to // If the given item is in an external crate, looks up its type and adds it to
// the type cache. Returns the type parameters and type. // the type cache. Returns the type parameters and type.
pub fn item_type(self, did: DefId) -> Ty<'gcx> { pub fn item_type(self, did: DefId) -> Ty<'gcx> {
self.maps.ty(self, did) self.maps.ty(self, DUMMY_SP, did)
} }
/// Given the did of a trait, returns its canonical trait ref. /// Given the did of a trait, returns its canonical trait ref.
pub fn lookup_trait_def(self, did: DefId) -> &'gcx TraitDef { pub fn lookup_trait_def(self, did: DefId) -> &'gcx TraitDef {
self.maps.trait_def(self, did) self.maps.trait_def(self, DUMMY_SP, did)
} }
/// Given the did of an ADT, return a reference to its definition. /// Given the did of an ADT, return a reference to its definition.
pub fn lookup_adt_def(self, did: DefId) -> &'gcx AdtDef { pub fn lookup_adt_def(self, did: DefId) -> &'gcx AdtDef {
self.maps.adt_def(self, did) self.maps.adt_def(self, DUMMY_SP, did)
} }
/// Given the did of an item, returns its generics. /// Given the did of an item, returns its generics.
pub fn item_generics(self, did: DefId) -> &'gcx Generics { pub fn item_generics(self, did: DefId) -> &'gcx Generics {
self.maps.generics(self, did) self.maps.generics(self, DUMMY_SP, did)
} }
/// Given the did of an item, returns its full set of predicates. /// Given the did of an item, returns its full set of predicates.
pub fn item_predicates(self, did: DefId) -> GenericPredicates<'gcx> { pub fn item_predicates(self, did: DefId) -> GenericPredicates<'gcx> {
self.maps.predicates(self, did) self.maps.predicates(self, DUMMY_SP, did)
} }
/// Given the did of a trait, returns its superpredicates. /// Given the did of a trait, returns its superpredicates.
pub fn item_super_predicates(self, did: DefId) -> GenericPredicates<'gcx> { pub fn item_super_predicates(self, did: DefId) -> GenericPredicates<'gcx> {
self.maps.super_predicates(self, did) self.maps.super_predicates(self, DUMMY_SP, did)
} }
/// Given the did of an item, returns its MIR, borrowed immutably. /// Given the did of an item, returns its MIR, borrowed immutably.
pub fn item_mir(self, did: DefId) -> Ref<'gcx, Mir<'gcx>> { pub fn item_mir(self, did: DefId) -> Ref<'gcx, Mir<'gcx>> {
self.maps.mir(self, did).borrow() self.maps.mir(self, DUMMY_SP, did).borrow()
} }
/// If `type_needs_drop` returns true, then `ty` is definitely /// If `type_needs_drop` returns true, then `ty` is definitely
@ -2377,19 +2360,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.get_attrs(did).iter().any(|item| item.check_name(attr)) self.get_attrs(did).iter().any(|item| item.check_name(attr))
} }
/// Determine whether an item is annotated with `#[repr(packed)]`
pub fn lookup_packed(self, did: DefId) -> bool {
self.lookup_repr_hints(did).contains(&attr::ReprPacked)
}
/// Determine whether an item is annotated with `#[simd]`
pub fn lookup_simd(self, did: DefId) -> bool {
self.has_attr(did, "simd")
|| self.lookup_repr_hints(did).contains(&attr::ReprSimd)
}
pub fn item_variances(self, item_id: DefId) -> Rc<Vec<ty::Variance>> { pub fn item_variances(self, item_id: DefId) -> Rc<Vec<ty::Variance>> {
self.maps.variances(self, item_id) self.maps.variances(self, DUMMY_SP, item_id)
} }
pub fn trait_has_default_impl(self, trait_def_id: DefId) -> bool { pub fn trait_has_default_impl(self, trait_def_id: DefId) -> bool {
@ -2464,11 +2436,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
} }
pub fn closure_kind(self, def_id: DefId) -> ty::ClosureKind { pub fn closure_kind(self, def_id: DefId) -> ty::ClosureKind {
self.maps.closure_kind(self, def_id) self.maps.closure_kind(self, DUMMY_SP, def_id)
} }
pub fn closure_type(self, def_id: DefId) -> ty::PolyFnSig<'tcx> { pub fn closure_type(self, def_id: DefId) -> ty::PolyFnSig<'tcx> {
self.maps.closure_type(self, def_id) self.maps.closure_type(self, DUMMY_SP, def_id)
} }
/// Given the def_id of an impl, return the def_id of the trait it implements. /// Given the def_id of an impl, return the def_id of the trait it implements.

View File

@ -1077,7 +1077,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
#[inline] #[inline]
pub fn is_simd(&self) -> bool { pub fn is_simd(&self) -> bool {
match self.sty { match self.sty {
TyAdt(def, _) => def.is_simd(), TyAdt(def, _) => def.repr.simd,
_ => false _ => false
} }
} }

View File

@ -232,21 +232,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
} }
} }
/// Returns the IntType representation.
/// This used to ensure `int_ty` doesn't contain `usize` and `isize`
/// by converting them to their actual types. That doesn't happen anymore.
pub fn enum_repr_type(self, opt_hint: Option<&attr::ReprAttr>) -> attr::IntType {
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(ast::IntTy::Is),
}
}
/// Returns the deeply last field of nested structures, or the same type, /// Returns the deeply last field of nested structures, or the same type,
/// if not a structure at all. Corresponds to the only possible unsized /// if not a structure at all. Corresponds to the only possible unsized
/// field, and its type can be used to determine unsizing strategy. /// field, and its type can be used to determine unsizing strategy.

View File

@ -677,9 +677,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
// Additionally, we do not want to switch on the // Additionally, we do not want to switch on the
// discriminant after it is free-ed, because that // discriminant after it is free-ed, because that
// way lies only trouble. // way lies only trouble.
let repr_hints = self.tcx.lookup_repr_hints(adt.did); let discr_ty = adt.repr.discr_type().to_ty(self.tcx);
let repr_type = self.tcx.enum_repr_type(repr_hints.get(0));
let discr_ty = repr_type.to_ty(self.tcx);
let discr = Lvalue::Local(self.patch.new_temp(discr_ty)); let discr = Lvalue::Local(self.patch.new_temp(discr_ty));
let switch_block = self.patch.new_block(BasicBlockData { let switch_block = self.patch.new_block(BasicBlockData {
statements: vec![ statements: vec![

View File

@ -902,8 +902,7 @@ fn infer<'a, 'tcx>(i: ConstInt,
(&ty::TyUint(ity), i) => Err(TypeMismatch(ity.to_string(), i)), (&ty::TyUint(ity), i) => Err(TypeMismatch(ity.to_string(), i)),
(&ty::TyAdt(adt, _), i) if adt.is_enum() => { (&ty::TyAdt(adt, _), i) if adt.is_enum() => {
let hints = tcx.lookup_repr_hints(adt.did); let int_ty = adt.repr.discr_type();
let int_ty = tcx.enum_repr_type(hints.iter().next());
infer(i, tcx, &int_ty.to_ty(tcx).sty) infer(i, tcx, &int_ty.to_ty(tcx).sty)
}, },
(_, i) => Err(BadType(ConstVal::Integral(i))), (_, i) => Err(BadType(ConstVal::Integral(i))),
@ -1093,8 +1092,7 @@ fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind,
}, },
None => Ok(Integral(Infer(n as u128))), None => Ok(Integral(Infer(n as u128))),
Some(&ty::TyAdt(adt, _)) => { Some(&ty::TyAdt(adt, _)) => {
let hints = tcx.lookup_repr_hints(adt.did); let int_ty = adt.repr.discr_type();
let int_ty = tcx.enum_repr_type(hints.iter().next());
infer(Infer(n as u128), tcx, &int_ty.to_ty(tcx).sty).map(Integral) infer(Infer(n as u128), tcx, &int_ty.to_ty(tcx).sty).map(Integral)
}, },
Some(ty_hint) => bug!("bad ty_hint: {:?}, {:?}", ty_hint, lit), Some(ty_hint) => bug!("bad ty_hint: {:?}, {:?}", ty_hint, lit),

View File

@ -257,6 +257,12 @@ pub struct DirtyCleanMetadataVisitor<'a, 'tcx:'a, 'm> {
impl<'a, 'tcx, 'm> ItemLikeVisitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { impl<'a, 'tcx, 'm> ItemLikeVisitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> {
fn visit_item(&mut self, item: &'tcx hir::Item) { fn visit_item(&mut self, item: &'tcx hir::Item) {
self.check_item(item.id, item.span); self.check_item(item.id, item.span);
if let hir::ItemEnum(ref def, _) = item.node {
for v in &def.variants {
self.check_item(v.node.data.id(), v.span);
}
}
} }
fn visit_trait_item(&mut self, item: &hir::TraitItem) { fn visit_trait_item(&mut self, item: &hir::TraitItem) {

View File

@ -381,6 +381,17 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
false false
} }
fn is_ffi_safe(ty: attr::IntType) -> bool {
match ty {
attr::SignedInt(ast::IntTy::I8) | attr::UnsignedInt(ast::UintTy::U8) |
attr::SignedInt(ast::IntTy::I16) | attr::UnsignedInt(ast::UintTy::U16) |
attr::SignedInt(ast::IntTy::I32) | attr::UnsignedInt(ast::UintTy::U32) |
attr::SignedInt(ast::IntTy::I64) | attr::UnsignedInt(ast::UintTy::U64) |
attr::SignedInt(ast::IntTy::I128) | attr::UnsignedInt(ast::UintTy::U128) => true,
attr::SignedInt(ast::IntTy::Is) | attr::UnsignedInt(ast::UintTy::Us) => false
}
}
impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
/// Check if the given type is "ffi-safe" (has a stable, well-defined /// Check if the given type is "ffi-safe" (has a stable, well-defined
/// representation which can be exported to C code). /// representation which can be exported to C code).
@ -406,7 +417,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
} }
match def.adt_kind() { match def.adt_kind() {
AdtKind::Struct => { AdtKind::Struct => {
if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { if !def.repr.c {
return FfiUnsafe("found struct without foreign-function-safe \ return FfiUnsafe("found struct without foreign-function-safe \
representation annotation in foreign module, \ representation annotation in foreign module, \
consider adding a #[repr(C)] attribute to the type"); consider adding a #[repr(C)] attribute to the type");
@ -440,7 +451,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
if all_phantom { FfiPhantom } else { FfiSafe } if all_phantom { FfiPhantom } else { FfiSafe }
} }
AdtKind::Union => { AdtKind::Union => {
if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { if !def.repr.c {
return FfiUnsafe("found union without foreign-function-safe \ return FfiUnsafe("found union without foreign-function-safe \
representation annotation in foreign module, \ representation annotation in foreign module, \
consider adding a #[repr(C)] attribute to the type"); consider adding a #[repr(C)] attribute to the type");
@ -479,9 +490,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
// Check for a repr() attribute to specify the size of the // Check for a repr() attribute to specify the size of the
// discriminant. // discriminant.
let repr_hints = cx.lookup_repr_hints(def.did); if !def.repr.c && def.repr.int.is_none() {
match &repr_hints[..] {
&[] => {
// Special-case types like `Option<extern fn()>`. // Special-case types like `Option<extern fn()>`.
if !is_repr_nullable_ptr(cx, def, substs) { if !is_repr_nullable_ptr(cx, def, substs) {
return FfiUnsafe("found enum without foreign-function-safe \ return FfiUnsafe("found enum without foreign-function-safe \
@ -490,8 +499,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
attribute to the type"); attribute to the type");
} }
} }
&[ref hint] => {
if !hint.is_ffi_safe() { if let Some(int_ty) = def.repr.int {
if !is_ffi_safe(int_ty) {
// FIXME: This shouldn't be reachable: we should check // FIXME: This shouldn't be reachable: we should check
// this earlier. // this earlier.
return FfiUnsafe("enum has unexpected #[repr(...)] attribute"); return FfiUnsafe("enum has unexpected #[repr(...)] attribute");
@ -503,12 +513,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
// The layout of enum variants is implicitly repr(C). // The layout of enum variants is implicitly repr(C).
// FIXME: Is that correct? // FIXME: Is that correct?
} }
_ => {
// FIXME: This shouldn't be reachable: we should check
// this earlier.
return FfiUnsafe("enum has too many #[repr(...)] attributes");
}
}
// Check the contained variants. // Check the contained variants.
for variant in &def.variants { for variant in &def.variants {

View File

@ -101,6 +101,7 @@ provide! { <'tcx> tcx, def_id, cdata
mir mir
} }
typeck_tables => { cdata.item_body_tables(def_id.index, tcx) }
closure_kind => { cdata.closure_kind(def_id.index) } closure_kind => { cdata.closure_kind(def_id.index) }
closure_type => { cdata.closure_ty(def_id.index, tcx) } closure_type => { cdata.closure_ty(def_id.index, tcx) }
} }

View File

@ -780,16 +780,19 @@ impl<'a, 'tcx> CrateMetadata {
if self.is_proc_macro(id) { return None; } if self.is_proc_macro(id) { return None; }
self.entry(id).ast.map(|ast| { self.entry(id).ast.map(|ast| {
let def_id = self.local_def_id(id); let def_id = self.local_def_id(id);
let ast = ast.decode(self); let body = ast.decode(self).body.decode(self);
let tables = ast.tables.decode((self, tcx));
tcx.maps.typeck_tables.borrow_mut().insert(def_id, tcx.alloc_tables(tables));
let body = ast.body.decode((self, tcx));
tcx.hir.intern_inlined_body(def_id, body) tcx.hir.intern_inlined_body(def_id, body)
}) })
} }
pub fn item_body_tables(&self,
id: DefIndex,
tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> &'tcx ty::TypeckTables<'tcx> {
let ast = self.entry(id).ast.unwrap().decode(self);
tcx.alloc_tables(ast.tables.decode((self, tcx)))
}
pub fn item_body_nested_bodies(&self, id: DefIndex) -> BTreeMap<hir::BodyId, hir::Body> { pub fn item_body_nested_bodies(&self, id: DefIndex) -> BTreeMap<hir::BodyId, hir::Body> {
self.entry(id).ast.into_iter().flat_map(|ast| { self.entry(id).ast.into_iter().flat_map(|ast| {
ast.decode(self).nested_bodies.decode(self).map(|body| (body.id(), body)) ast.decode(self).nested_bodies.decode(self).map(|body| (body.id(), body))

View File

@ -36,7 +36,7 @@ use syntax::ast::{self, CRATE_NODE_ID};
use syntax::codemap::Spanned; use syntax::codemap::Spanned;
use syntax::attr; use syntax::attr;
use syntax::symbol::Symbol; use syntax::symbol::Symbol;
use syntax_pos; use syntax_pos::{self, DUMMY_SP};
use rustc::hir::{self, PatKind}; use rustc::hir::{self, PatKind};
use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::itemlikevisit::ItemLikeVisitor;
@ -264,7 +264,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
discr: variant.discr, discr: variant.discr,
evaluated_discr: match variant.discr { evaluated_discr: match variant.discr {
ty::VariantDiscr::Explicit(def_id) => { ty::VariantDiscr::Explicit(def_id) => {
tcx.maps.monomorphic_const_eval.borrow()[&def_id].clone().ok() tcx.maps.monomorphic_const_eval(tcx, DUMMY_SP, def_id).ok()
} }
ty::VariantDiscr::Relative(_) => None ty::VariantDiscr::Relative(_) => None
}, },

View File

@ -209,9 +209,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
} }
debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}", debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}",
num_enum_variants, values, variants); num_enum_variants, values, variants);
let repr_hints = tcx.lookup_repr_hints(adt_def.did); let discr_ty = adt_def.repr.discr_type().to_ty(tcx);
let repr_type = tcx.enum_repr_type(repr_hints.get(0));
let discr_ty = repr_type.to_ty(tcx);
let discr = self.temp(discr_ty); let discr = self.temp(discr_ty);
self.cfg.push_assign(block, source_info, &discr, self.cfg.push_assign(block, source_info, &discr,
Rvalue::Discriminant(lvalue.clone())); Rvalue::Discriminant(lvalue.clone()));

View File

@ -11,17 +11,6 @@
//! Conversion from AST representation of types to the ty.rs //! Conversion from AST representation of types to the ty.rs
//! representation. The main routine here is `ast_ty_to_ty()`: each use //! representation. The main routine here is `ast_ty_to_ty()`: each use
//! is parameterized by an instance of `AstConv`. //! is parameterized by an instance of `AstConv`.
//!
//! The parameterization of `ast_ty_to_ty()` is because it behaves
//! somewhat differently during the collect and check phases,
//! particularly with respect to looking up the types of top-level
//! items. In the collect phase, the crate context is used as the
//! `AstConv` instance; in this phase, the `get_item_type()`
//! function triggers a recursive call to `type_of_item()`
//! (note that `ast_ty_to_ty()` will detect recursive types and report
//! an error). In the check phase, when the FnCtxt is used as the
//! `AstConv`, `get_item_type()` just looks up the item type in
//! `tcx.types` (using `TyCtxt::item_type`).
use rustc_const_eval::eval_length; use rustc_const_eval::eval_length;
use rustc_data_structures::accumulate_vec::AccumulateVec; use rustc_data_structures::accumulate_vec::AccumulateVec;
@ -51,18 +40,10 @@ pub trait AstConv<'gcx, 'tcx> {
/// A cache used for the result of `ast_ty_to_ty_cache` /// A cache used for the result of `ast_ty_to_ty_cache`
fn ast_ty_to_ty_cache(&self) -> &RefCell<NodeMap<Ty<'tcx>>>; fn ast_ty_to_ty_cache(&self) -> &RefCell<NodeMap<Ty<'tcx>>>;
/// Identify the type for an item, like a type alias, fn, or struct.
fn get_item_type(&self, span: Span, id: DefId) -> Ty<'tcx>;
/// Ensure that the super-predicates for the trait with the given
/// id are available and also for the transitive set of
/// super-predicates.
fn ensure_super_predicates(&self, span: Span, id: DefId);
/// Returns the set of bounds in scope for the type parameter with /// Returns the set of bounds in scope for the type parameter with
/// the given id. /// the given id.
fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) fn get_type_parameter_bounds(&self, span: Span, def_id: DefId)
-> Vec<ty::Predicate<'tcx>>; -> ty::GenericPredicates<'tcx>;
/// Return an (optional) substitution to convert bound type parameters that /// Return an (optional) substitution to convert bound type parameters that
/// are in scope into free ones. This function should only return Some /// are in scope into free ones. This function should only return Some
@ -262,7 +243,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF); let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF);
let default_needs_object_self = |p: &ty::TypeParameterDef| { let default_needs_object_self = |p: &ty::TypeParameterDef| {
if is_object && p.has_default { if is_object && p.has_default {
if self.get_item_type(span, p.def_id).has_self_ty() { if tcx.maps.ty(tcx, span, p.def_id).has_self_ty() {
// There is no suitable inference default for a type parameter // There is no suitable inference default for a type parameter
// that references self, in an object type. // that references self, in an object type.
return true; return true;
@ -329,7 +310,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
tcx.types.err tcx.types.err
} else { } else {
// This is a default type parameter. // This is a default type parameter.
self.get_item_type(span, def.def_id).subst_spanned(tcx, substs, Some(span)) tcx.maps.ty(tcx, span, def.def_id).subst_spanned(tcx, substs, Some(span))
} }
} else { } else {
// We've already errored above about the mismatch. // We've already errored above about the mismatch.
@ -591,8 +572,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
// Otherwise, we have to walk through the supertraits to find // Otherwise, we have to walk through the supertraits to find
// those that do. // those that do.
self.ensure_super_predicates(binding.span, trait_ref.def_id());
let candidates = let candidates =
traits::supertraits(tcx, trait_ref.clone()) traits::supertraits(tcx, trait_ref.clone())
.filter(|r| self.trait_defines_associated_type_named(r.def_id(), binding.item_name)); .filter(|r| self.trait_defines_associated_type_named(r.def_id(), binding.item_name));
@ -620,7 +599,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
-> Ty<'tcx> -> Ty<'tcx>
{ {
let substs = self.ast_path_substs_for_ty(span, did, item_segment); let substs = self.ast_path_substs_for_ty(span, did, item_segment);
self.get_item_type(span, did).subst(self.tcx(), substs) self.tcx().maps.ty(self.tcx(), span, did).subst(self.tcx(), substs)
} }
/// Transform a PolyTraitRef into a PolyExistentialTraitRef by /// Transform a PolyTraitRef into a PolyExistentialTraitRef by
@ -677,9 +656,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
}) })
}); });
// ensure the super predicates
self.ensure_super_predicates(span, principal.def_id());
// check that there are no gross object safety violations, // check that there are no gross object safety violations,
// most importantly, that the supertraits don't contain Self, // most importantly, that the supertraits don't contain Self,
// to avoid ICE-s. // to avoid ICE-s.
@ -776,12 +752,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
let tcx = self.tcx(); let tcx = self.tcx();
let bounds: Vec<_> = self.get_type_parameter_bounds(span, ty_param_def_id) let bounds: Vec<_> = self.get_type_parameter_bounds(span, ty_param_def_id)
.into_iter().filter_map(|p| p.to_opt_poly_trait_ref()).collect(); .predicates.into_iter().filter_map(|p| p.to_opt_poly_trait_ref()).collect();
// Ensure the super predicates.
for b in &bounds {
self.ensure_super_predicates(span, b.def_id());
}
// Check that there is exactly one way to find an associated type with the // Check that there is exactly one way to find an associated type with the
// correct name. // correct name.
@ -880,28 +851,20 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
(_, Def::SelfTy(Some(_), Some(impl_def_id))) => { (_, Def::SelfTy(Some(_), Some(impl_def_id))) => {
// `Self` in an impl of a trait - we have a concrete self type and a // `Self` in an impl of a trait - we have a concrete self type and a
// trait reference. // trait reference.
// FIXME: Self type is not always computed when we are here because type parameter let trait_ref = match tcx.impl_trait_ref(impl_def_id) {
// bounds may affect Self type and have to be converted before it. Some(trait_ref) => trait_ref,
let trait_ref = if impl_def_id.is_local() { None => {
tcx.maps.impl_trait_ref.borrow().get(&impl_def_id) // A cycle error occurred, most likely.
.cloned().and_then(|x| x)
} else {
tcx.impl_trait_ref(impl_def_id)
};
let trait_ref = if let Some(trait_ref) = trait_ref {
trait_ref
} else {
tcx.sess.span_err(span, "`Self` type is used before it's determined");
return (tcx.types.err, Def::Err); return (tcx.types.err, Def::Err);
}
}; };
let trait_ref = if let Some(free_substs) = self.get_free_substs() { let trait_ref = if let Some(free_substs) = self.get_free_substs() {
trait_ref.subst(tcx, free_substs) trait_ref.subst(tcx, free_substs)
} else { } else {
trait_ref trait_ref
}; };
self.ensure_super_predicates(span, trait_ref.def_id);
let candidates = let candidates =
traits::supertraits(tcx, ty::Binder(trait_ref)) traits::supertraits(tcx, ty::Binder(trait_ref))
.filter(|r| self.trait_defines_associated_type_named(r.def_id(), .filter(|r| self.trait_defines_associated_type_named(r.def_id(),
@ -1022,7 +985,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
assert_eq!(opt_self_ty, None); assert_eq!(opt_self_ty, None);
tcx.prohibit_type_params(&path.segments); tcx.prohibit_type_params(&path.segments);
let ty = self.get_item_type(span, def_id); let ty = tcx.maps.ty(tcx, span, def_id);
if let Some(free_substs) = self.get_free_substs() { if let Some(free_substs) = self.get_free_substs() {
ty.subst(tcx, free_substs) ty.subst(tcx, free_substs)
} else { } else {
@ -1137,9 +1100,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
hir::TyTraitObject(ref bounds, ref lifetime) => { hir::TyTraitObject(ref bounds, ref lifetime) => {
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime) self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime)
} }
hir::TyImplTrait(ref bounds) => { hir::TyImplTrait(_) => {
use collect::{compute_bounds, SizedByDefault};
// Figure out if we can allow an `impl Trait` here, by walking up // Figure out if we can allow an `impl Trait` here, by walking up
// to a `fn` or inherent `impl` method, going only through `Ty` // to a `fn` or inherent `impl` method, going only through `Ty`
// or `TraitRef` nodes (as nothing else should be in types) and // or `TraitRef` nodes (as nothing else should be in types) and
@ -1179,22 +1140,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
// Create the anonymized type. // Create the anonymized type.
if allow { if allow {
let def_id = tcx.hir.local_def_id(ast_ty.id); let def_id = tcx.hir.local_def_id(ast_ty.id);
tcx.item_generics(def_id); tcx.mk_anon(def_id, Substs::identity_for_item(tcx, def_id))
let substs = Substs::identity_for_item(tcx, def_id);
let ty = tcx.mk_anon(tcx.hir.local_def_id(ast_ty.id), substs);
// Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
let bounds = compute_bounds(self, ty, bounds,
SizedByDefault::Yes,
ast_ty.span);
let predicates = bounds.predicates(tcx, ty);
let predicates = tcx.lift_to_global(&predicates).unwrap();
tcx.maps.predicates.borrow_mut().insert(def_id, ty::GenericPredicates {
parent: None,
predicates: predicates
});
ty
} else { } else {
span_err!(tcx.sess, ast_ty.span, E0562, span_err!(tcx.sess, ast_ty.span, E0562,
"`impl Trait` not allowed outside of function \ "`impl Trait` not allowed outside of function \
@ -1353,10 +1299,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
debug!("compute_opt_region_bound(existential_predicates={:?})", debug!("compute_opt_region_bound(existential_predicates={:?})",
existential_predicates); existential_predicates);
if let Some(principal) = existential_predicates.principal() {
self.ensure_super_predicates(span, principal.def_id());
}
// No explicit region bound specified. Therefore, examine trait // No explicit region bound specified. Therefore, examine trait
// bounds and see if we can derive region bounds from those. // bounds and see if we can derive region bounds from those.
let derived_region_bounds = let derived_region_bounds =

View File

@ -139,7 +139,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if let Some(import_id) = pick.import_id { if let Some(import_id) = pick.import_id {
let import_def_id = self.tcx.hir.local_def_id(import_id); let import_def_id = self.tcx.hir.local_def_id(import_id);
debug!("used_trait_import: {:?}", import_def_id); debug!("used_trait_import: {:?}", import_def_id);
self.used_trait_imports.borrow_mut().insert(import_def_id); self.tables.borrow_mut().used_trait_imports.insert(import_def_id);
} }
self.tcx.check_stability(pick.item.def_id, call_expr.id, span); self.tcx.check_stability(pick.item.def_id, call_expr.id, span);
@ -333,7 +333,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if let Some(import_id) = pick.import_id { if let Some(import_id) = pick.import_id {
let import_def_id = self.tcx.hir.local_def_id(import_id); let import_def_id = self.tcx.hir.local_def_id(import_id);
debug!("used_trait_import: {:?}", import_def_id); debug!("used_trait_import: {:?}", import_def_id);
self.used_trait_imports.borrow_mut().insert(import_def_id); self.tables.borrow_mut().used_trait_imports.insert(import_def_id);
} }
let def = pick.item.def(); let def = pick.item.def();

View File

@ -95,13 +95,14 @@ use rustc::ty::{self, Ty, TyCtxt, Visibility};
use rustc::ty::{MethodCall, MethodCallee}; use rustc::ty::{MethodCall, MethodCallee};
use rustc::ty::adjustment; use rustc::ty::adjustment;
use rustc::ty::fold::{BottomUpFolder, TypeFoldable}; use rustc::ty::fold::{BottomUpFolder, TypeFoldable};
use rustc::ty::maps::Providers;
use rustc::ty::util::{Representability, IntTypeExt}; use rustc::ty::util::{Representability, IntTypeExt};
use require_c_abi_if_variadic; use require_c_abi_if_variadic;
use session::{Session, CompileResult}; use session::{Session, CompileResult};
use TypeAndSubsts; use TypeAndSubsts;
use lint; use lint;
use util::common::{ErrorReported, indenter}; use util::common::{ErrorReported, indenter};
use util::nodemap::{DefIdMap, DefIdSet, FxHashMap, FxHashSet, NodeMap}; use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap};
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::cmp; use std::cmp;
@ -109,7 +110,6 @@ use std::mem::replace;
use std::ops::{self, Deref}; use std::ops::{self, Deref};
use syntax::abi::Abi; use syntax::abi::Abi;
use syntax::ast; use syntax::ast;
use syntax::attr;
use syntax::codemap::{self, original_sp, Spanned}; use syntax::codemap::{self, original_sp, Spanned};
use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::feature_gate::{GateIssue, emit_feature_err};
use syntax::ptr::P; use syntax::ptr::P;
@ -174,16 +174,7 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
// associated fresh inference variable. Writeback resolves these // associated fresh inference variable. Writeback resolves these
// variables to get the concrete type, which can be used to // variables to get the concrete type, which can be used to
// deanonymize TyAnon, after typeck is done with all functions. // deanonymize TyAnon, after typeck is done with all functions.
anon_types: RefCell<DefIdMap<Ty<'tcx>>>, anon_types: RefCell<NodeMap<Ty<'tcx>>>,
// Obligations which will have to be checked at the end of
// type-checking, after all functions have been inferred.
deferred_obligations: RefCell<Vec<traits::DeferredObligation<'tcx>>>,
// a set of trait import def-ids that we use during method
// resolution; during writeback, this is written into
// `tcx.used_trait_imports` for this item def-id
used_trait_imports: RefCell<FxHashSet<DefId>>,
} }
impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> {
@ -507,9 +498,7 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
locals: RefCell::new(NodeMap()), locals: RefCell::new(NodeMap()),
deferred_call_resolutions: RefCell::new(DefIdMap()), deferred_call_resolutions: RefCell::new(DefIdMap()),
deferred_cast_checks: RefCell::new(Vec::new()), deferred_cast_checks: RefCell::new(Vec::new()),
anon_types: RefCell::new(DefIdMap()), anon_types: RefCell::new(NodeMap()),
deferred_obligations: RefCell::new(Vec::new()),
used_trait_imports: RefCell::new(DefIdSet()),
} }
} }
@ -545,7 +534,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
fn visit_ty(&mut self, t: &'tcx hir::Ty) { fn visit_ty(&mut self, t: &'tcx hir::Ty) {
match t.node { match t.node {
hir::TyArray(_, length) => { hir::TyArray(_, length) => {
check_const_with_type(self.tcx, length, self.tcx.types.usize, length.node_id); self.tcx.item_tables(self.tcx.hir.local_def_id(length.node_id));
} }
_ => {} _ => {}
} }
@ -556,7 +545,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
fn visit_expr(&mut self, e: &'tcx hir::Expr) { fn visit_expr(&mut self, e: &'tcx hir::Expr) {
match e.node { match e.node {
hir::ExprRepeat(_, count) => { hir::ExprRepeat(_, count) => {
check_const_with_type(self.tcx, count, self.tcx.types.usize, count.node_id); self.tcx.item_tables(self.tcx.hir.local_def_id(count.node_id));
} }
_ => {} _ => {}
} }
@ -568,8 +557,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> { impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item) { fn visit_item(&mut self, item: &'tcx hir::Item) {
match item.node { match item.node {
hir::ItemFn(ref decl, .., body_id) => { hir::ItemFn(..) => {
check_bare_fn(self.tcx, &decl, body_id, item.id, item.span); self.tcx.item_tables(self.tcx.hir.local_def_id(item.id));
} }
_ => { } _ => { }
} }
@ -577,11 +566,9 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
match trait_item.node { match trait_item.node {
hir::TraitItemKind::Const(_, Some(expr)) => { hir::TraitItemKind::Const(_, Some(_)) |
check_const(self.tcx, expr, trait_item.id) hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => {
} self.tcx.item_tables(self.tcx.hir.local_def_id(trait_item.id));
hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body_id)) => {
check_bare_fn(self.tcx, &sig.decl, body_id, trait_item.id, trait_item.span);
} }
hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) | hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
hir::TraitItemKind::Const(_, None) | hir::TraitItemKind::Const(_, None) |
@ -593,11 +580,9 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
match impl_item.node { match impl_item.node {
hir::ImplItemKind::Const(_, expr) => { hir::ImplItemKind::Const(..) |
check_const(self.tcx, expr, impl_item.id) hir::ImplItemKind::Method(..) => {
} self.tcx.item_tables(self.tcx.hir.local_def_id(impl_item.id));
hir::ImplItemKind::Method(ref sig, body_id) => {
check_bare_fn(self.tcx, &sig.decl, body_id, impl_item.id, impl_item.span);
} }
hir::ImplItemKind::Type(_) => { hir::ImplItemKind::Type(_) => {
// Nothing to do here. // Nothing to do here.
@ -625,26 +610,6 @@ pub fn check_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult
tcx.sess.track_errors(|| { tcx.sess.track_errors(|| {
let mut visit = CheckItemBodiesVisitor { tcx: tcx }; let mut visit = CheckItemBodiesVisitor { tcx: tcx };
tcx.visit_all_item_likes_in_krate(DepNode::TypeckTables, &mut visit); tcx.visit_all_item_likes_in_krate(DepNode::TypeckTables, &mut visit);
// Process deferred obligations, now that all functions
// bodies have been fully inferred.
for (&item_id, obligations) in tcx.deferred_obligations.borrow().iter() {
// Use the same DepNode as for the body of the original function/item.
let def_id = tcx.hir.local_def_id(item_id);
let _task = tcx.dep_graph.in_task(DepNode::TypeckTables(def_id));
let param_env = ParameterEnvironment::for_item(tcx, item_id);
tcx.infer_ctxt(param_env, Reveal::NotSpecializable).enter(|infcx| {
let mut fulfillment_cx = traits::FulfillmentContext::new();
for obligation in obligations.iter().map(|o| o.to_obligation()) {
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
}
if let Err(errors) = fulfillment_cx.select_all_or_error(&infcx) {
infcx.report_fulfillment_errors(&errors);
}
});
}
}) })
} }
@ -668,20 +633,107 @@ pub fn check_drop_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult
}) })
} }
fn check_bare_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn provide(providers: &mut Providers) {
decl: &'tcx hir::FnDecl, *providers = Providers {
body_id: hir::BodyId, typeck_tables,
fn_id: ast::NodeId, closure_type,
span: Span) { closure_kind,
..*providers
};
}
fn closure_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> ty::PolyFnSig<'tcx> {
let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
tcx.item_tables(def_id).closure_tys[&node_id]
}
fn closure_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> ty::ClosureKind {
let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
tcx.item_tables(def_id).closure_kinds[&node_id]
}
fn typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> &'tcx ty::TypeckTables<'tcx> {
// Closures' tables come from their outermost function,
// as they are part of the same "inference environment".
let outer_def_id = tcx.closure_base_def_id(def_id);
if outer_def_id != def_id {
return tcx.item_tables(outer_def_id);
}
let id = tcx.hir.as_local_node_id(def_id).unwrap();
let span = tcx.hir.span(id);
let unsupported = || {
span_bug!(span, "can't type-check body of {:?}", def_id);
};
// Figure out what primary body this item has.
let mut fn_decl = None;
let body_id = match tcx.hir.get(id) {
hir::map::NodeItem(item) => {
match item.node {
hir::ItemConst(_, body) |
hir::ItemStatic(_, _, body) => body,
hir::ItemFn(ref decl, .., body) => {
fn_decl = Some(decl);
body
}
_ => unsupported()
}
}
hir::map::NodeTraitItem(item) => {
match item.node {
hir::TraitItemKind::Const(_, Some(body)) => body,
hir::TraitItemKind::Method(ref sig,
hir::TraitMethod::Provided(body)) => {
fn_decl = Some(&sig.decl);
body
}
_ => unsupported()
}
}
hir::map::NodeImplItem(item) => {
match item.node {
hir::ImplItemKind::Const(_, body) => body,
hir::ImplItemKind::Method(ref sig, body) => {
fn_decl = Some(&sig.decl);
body
}
_ => unsupported()
}
}
hir::map::NodeExpr(expr) => {
// FIXME(eddyb) Closures should have separate
// function definition IDs and expression IDs.
// Type-checking should not let closures get
// this far in a constant position.
// Assume that everything other than closures
// is a constant "initializer" expression.
match expr.node {
hir::ExprClosure(..) => {
// We should've bailed out above for closures.
span_bug!(expr.span, "unexpected closure")
}
_ => hir::BodyId { node_id: expr.id }
}
}
_ => unsupported()
};
let body = tcx.hir.body(body_id); let body = tcx.hir.body(body_id);
let fn_sig = tcx.item_type(tcx.hir.local_def_id(fn_id)).fn_sig(); Inherited::build(tcx, id).enter(|inh| {
let fcx = if let Some(decl) = fn_decl {
let fn_sig = tcx.item_type(def_id).fn_sig();
check_abi(tcx, span, fn_sig.abi()); check_abi(tcx, span, fn_sig.abi());
Inherited::build(tcx, fn_id).enter(|inh| {
// Compute the fty from point of view of inside fn. // Compute the fty from point of view of inside fn.
let fn_scope = inh.tcx.region_maps.call_site_extent(fn_id, body_id.node_id); let fn_scope = inh.tcx.region_maps.call_site_extent(id, body_id.node_id);
let fn_sig = let fn_sig =
fn_sig.subst(inh.tcx, &inh.parameter_environment.free_substs); fn_sig.subst(inh.tcx, &inh.parameter_environment.free_substs);
let fn_sig = let fn_sig =
@ -689,17 +741,37 @@ fn check_bare_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let fn_sig = let fn_sig =
inh.normalize_associated_types_in(body.value.span, body_id.node_id, &fn_sig); inh.normalize_associated_types_in(body.value.span, body_id.node_id, &fn_sig);
let fcx = check_fn(&inh, fn_sig, decl, fn_id, body); check_fn(&inh, fn_sig, decl, id, body)
} else {
let expected_type = tcx.item_type(def_id);
let fcx = FnCtxt::new(&inh, None, body.value.id);
fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
// Gather locals in statics (because of block expressions).
// This is technically unnecessary because locals in static items are forbidden,
// but prevents type checking from blowing up before const checking can properly
// emit an error.
GatherLocalsVisitor { fcx: &fcx }.visit_body(body);
fcx.check_expr_coercable_to_type(&body.value, expected_type);
fcx
};
fcx.select_all_obligations_and_apply_defaults(); fcx.select_all_obligations_and_apply_defaults();
fcx.closure_analyze(body); fcx.closure_analyze(body);
fcx.select_obligations_where_possible(); fcx.select_obligations_where_possible();
fcx.check_casts(); fcx.check_casts();
fcx.select_all_obligations_or_error(); // Casts can introduce new obligations. fcx.select_all_obligations_or_error();
fcx.regionck_fn(fn_id, body); if fn_decl.is_some() {
fcx.resolve_type_vars_in_body(body); fcx.regionck_fn(id, body);
}); } else {
fcx.regionck_expr(body);
}
fcx.resolve_type_vars_in_body(body)
})
} }
fn check_abi<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span, abi: Abi) { fn check_abi<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span, abi: Abi) {
@ -772,7 +844,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
_: hir::BodyId, _: Span, _: ast::NodeId) { } _: hir::BodyId, _: Span, _: ast::NodeId) { }
} }
/// Helper used by check_bare_fn and check_expr_fn. Does the grungy work of checking a function /// Helper used for fns and closures. Does the grungy work of checking a function
/// body and returns the function context used for that purpose, since in the case of a fn item /// body and returns the function context used for that purpose, since in the case of a fn item
/// there is still a bit more to do. /// there is still a bit more to do.
/// ///
@ -835,7 +907,7 @@ fn check_struct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let def_id = tcx.hir.local_def_id(id); let def_id = tcx.hir.local_def_id(id);
check_representable(tcx, span, def_id); check_representable(tcx, span, def_id);
if tcx.lookup_simd(def_id) { if tcx.lookup_adt_def(def_id).repr.simd {
check_simd(tcx, span, def_id); check_simd(tcx, span, def_id);
} }
} }
@ -853,8 +925,10 @@ pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item
let _indenter = indenter(); let _indenter = indenter();
match it.node { match it.node {
// Consts can play a role in type-checking, so they are included here. // Consts can play a role in type-checking, so they are included here.
hir::ItemStatic(.., e) | hir::ItemStatic(..) |
hir::ItemConst(_, e) => check_const(tcx, e, it.id), hir::ItemConst(..) => {
tcx.item_tables(tcx.hir.local_def_id(it.id));
}
hir::ItemEnum(ref enum_definition, _) => { hir::ItemEnum(ref enum_definition, _) => {
check_enum_variants(tcx, check_enum_variants(tcx,
it.span, it.span,
@ -1197,42 +1271,6 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
} }
} }
/// Checks a constant with a given type.
fn check_const_with_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
body: hir::BodyId,
expected_type: Ty<'tcx>,
id: ast::NodeId) {
let body = tcx.hir.body(body);
Inherited::build(tcx, id).enter(|inh| {
let fcx = FnCtxt::new(&inh, None, body.value.id);
fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
// Gather locals in statics (because of block expressions).
// This is technically unnecessary because locals in static items are forbidden,
// but prevents type checking from blowing up before const checking can properly
// emit an error.
GatherLocalsVisitor { fcx: &fcx }.visit_body(body);
fcx.check_expr_coercable_to_type(&body.value, expected_type);
fcx.select_all_obligations_and_apply_defaults();
fcx.closure_analyze(body);
fcx.select_obligations_where_possible();
fcx.check_casts();
fcx.select_all_obligations_or_error();
fcx.regionck_expr(body);
fcx.resolve_type_vars_in_body(body);
});
}
fn check_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
body: hir::BodyId,
id: ast::NodeId) {
let decl_ty = tcx.item_type(tcx.hir.local_def_id(id));
check_const_with_type(tcx, body, decl_ty, id);
}
/// Checks whether a type can be represented in memory. In particular, it /// Checks whether a type can be represented in memory. In particular, it
/// identifies types that contain themselves without indirection through a /// identifies types that contain themselves without indirection through a
/// pointer, which would mean their size is unbounded. /// pointer, which would mean their size is unbounded.
@ -1293,9 +1331,9 @@ pub fn check_enum_variants<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
vs: &'tcx [hir::Variant], vs: &'tcx [hir::Variant],
id: ast::NodeId) { id: ast::NodeId) {
let def_id = tcx.hir.local_def_id(id); let def_id = tcx.hir.local_def_id(id);
let hint = *tcx.lookup_repr_hints(def_id).get(0).unwrap_or(&attr::ReprAny); let def = tcx.lookup_adt_def(def_id);
if hint != attr::ReprAny && vs.is_empty() { if vs.is_empty() && tcx.has_attr(def_id, "repr") {
struct_span_err!( struct_span_err!(
tcx.sess, sp, E0084, tcx.sess, sp, E0084,
"unsupported representation for zero-variant enum") "unsupported representation for zero-variant enum")
@ -1303,7 +1341,7 @@ pub fn check_enum_variants<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
.emit(); .emit();
} }
let repr_type_ty = tcx.enum_repr_type(Some(&hint)).to_ty(tcx); let repr_type_ty = def.repr.discr_type().to_ty(tcx);
if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 { if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 {
if !tcx.sess.features.borrow().i128_type { if !tcx.sess.features.borrow().i128_type {
emit_feature_err(&tcx.sess.parse_sess, emit_feature_err(&tcx.sess.parse_sess,
@ -1313,13 +1351,10 @@ pub fn check_enum_variants<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
for v in vs { for v in vs {
if let Some(e) = v.node.disr_expr { if let Some(e) = v.node.disr_expr {
check_const_with_type(tcx, e, repr_type_ty, e.node_id); tcx.item_tables(tcx.hir.local_def_id(e.node_id));
} }
} }
let def_id = tcx.hir.local_def_id(id);
let def = tcx.lookup_adt_def(def_id);
let mut disr_vals: Vec<ConstInt> = Vec::new(); let mut disr_vals: Vec<ConstInt> = Vec::new();
for (discr, v) in def.discriminants(tcx).zip(vs) { for (discr, v) in def.discriminants(tcx).zip(vs) {
// Check for duplicate discriminant values // Check for duplicate discriminant values
@ -1353,20 +1388,12 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
&self.ast_ty_to_ty_cache &self.ast_ty_to_ty_cache
} }
fn get_item_type(&self, _: Span, id: DefId) -> Ty<'tcx> {
self.tcx().item_type(id)
}
fn ensure_super_predicates(&self, _: Span, _: DefId) {
// all super predicates are ensured during collect pass
}
fn get_free_substs(&self) -> Option<&Substs<'tcx>> { fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
Some(&self.parameter_environment.free_substs) Some(&self.parameter_environment.free_substs)
} }
fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) fn get_type_parameter_bounds(&self, _: Span, def_id: DefId)
-> Vec<ty::Predicate<'tcx>> -> ty::GenericPredicates<'tcx>
{ {
let tcx = self.tcx; let tcx = self.tcx;
let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
@ -1374,7 +1401,9 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
let item_def_id = tcx.hir.local_def_id(item_id); let item_def_id = tcx.hir.local_def_id(item_id);
let generics = tcx.item_generics(item_def_id); let generics = tcx.item_generics(item_def_id);
let index = generics.type_param_to_index[&def_id.index]; let index = generics.type_param_to_index[&def_id.index];
self.parameter_environment.caller_bounds.iter().filter(|predicate| { ty::GenericPredicates {
parent: None,
predicates: self.parameter_environment.caller_bounds.iter().filter(|predicate| {
match **predicate { match **predicate {
ty::Predicate::Trait(ref data) => { ty::Predicate::Trait(ref data) => {
data.0.self_ty().is_param(index) data.0.self_ty().is_param(index)
@ -1383,6 +1412,7 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
} }
}).cloned().collect() }).cloned().collect()
} }
}
fn re_infer(&self, span: Span, def: Option<&ty::RegionParameterDef>) fn re_infer(&self, span: Span, def: Option<&ty::RegionParameterDef>)
-> Option<&'tcx ty::Region> { -> Option<&'tcx ty::Region> {
@ -1666,12 +1696,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if let ty::TyAnon(def_id, substs) = ty.sty { if let ty::TyAnon(def_id, substs) = ty.sty {
// Use the same type variable if the exact same TyAnon appears more // Use the same type variable if the exact same TyAnon appears more
// than once in the return type (e.g. if it's pased to a type alias). // than once in the return type (e.g. if it's pased to a type alias).
if let Some(ty_var) = self.anon_types.borrow().get(&def_id) { let id = self.tcx.hir.as_local_node_id(def_id).unwrap();
if let Some(ty_var) = self.anon_types.borrow().get(&id) {
return ty_var; return ty_var;
} }
let span = self.tcx.def_span(def_id); let span = self.tcx.def_span(def_id);
let ty_var = self.next_ty_var(TypeVariableOrigin::TypeInference(span)); let ty_var = self.next_ty_var(TypeVariableOrigin::TypeInference(span));
self.anon_types.borrow_mut().insert(def_id, ty_var); self.anon_types.borrow_mut().insert(id, ty_var);
let item_predicates = self.tcx.item_predicates(def_id); let item_predicates = self.tcx.item_predicates(def_id);
let bounds = item_predicates.instantiate(self.tcx, substs); let bounds = item_predicates.instantiate(self.tcx, substs);
@ -2206,11 +2237,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); let mut fulfillment_cx = self.fulfillment_cx.borrow_mut();
// Steal the deferred obligations before the fulfillment
// context can turn all of them into errors.
let obligations = fulfillment_cx.take_deferred_obligations();
self.deferred_obligations.borrow_mut().extend(obligations);
match fulfillment_cx.select_all_or_error(self) { match fulfillment_cx.select_all_or_error(self) {
Ok(()) => { } Ok(()) => { }
Err(errors) => { self.report_fulfillment_errors(&errors); } Err(errors) => { self.report_fulfillment_errors(&errors); }

View File

@ -14,7 +14,6 @@
use self::ResolveReason::*; use self::ResolveReason::*;
use check::FnCtxt; use check::FnCtxt;
use hir::def_id::DefId;
use rustc::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee}; use rustc::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee};
use rustc::ty::adjustment; use rustc::ty::adjustment;
use rustc::ty::fold::{TypeFolder,TypeFoldable}; use rustc::ty::fold::{TypeFolder,TypeFoldable};
@ -34,7 +33,8 @@ use rustc::hir;
// Entry point // Entry point
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body) { pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body)
-> &'gcx ty::TypeckTables<'gcx> {
assert_eq!(self.writeback_errors.get(), false); assert_eq!(self.writeback_errors.get(), false);
let item_id = self.tcx.hir.body_owner(body.id()); let item_id = self.tcx.hir.body_owner(body.id());
@ -50,18 +50,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
wbcx.visit_liberated_fn_sigs(); wbcx.visit_liberated_fn_sigs();
wbcx.visit_fru_field_types(); wbcx.visit_fru_field_types();
wbcx.visit_anon_types(); wbcx.visit_anon_types();
wbcx.visit_deferred_obligations(item_id);
wbcx.visit_type_nodes(); wbcx.visit_type_nodes();
wbcx.visit_cast_types(); wbcx.visit_cast_types();
wbcx.visit_lints(); wbcx.visit_lints();
let tables = self.tcx.alloc_tables(wbcx.tables); let used_trait_imports = mem::replace(&mut self.tables.borrow_mut().used_trait_imports,
self.tcx.maps.typeck_tables.borrow_mut().insert(item_def_id, tables);
let used_trait_imports = mem::replace(&mut *self.used_trait_imports.borrow_mut(),
DefIdSet()); DefIdSet());
debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports); debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
self.tcx.maps.used_trait_imports.borrow_mut().insert(item_def_id, used_trait_imports); wbcx.tables.used_trait_imports = used_trait_imports;
self.tcx.alloc_tables(wbcx.tables)
} }
} }
@ -282,20 +280,18 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
} }
} }
fn visit_closures(&self) { fn visit_closures(&mut self) {
if self.fcx.writeback_errors.get() { if self.fcx.writeback_errors.get() {
return return
} }
for (&id, closure_ty) in self.fcx.tables.borrow().closure_tys.iter() { for (&id, closure_ty) in self.fcx.tables.borrow().closure_tys.iter() {
let closure_ty = self.resolve(closure_ty, ResolvingClosure(id)); let closure_ty = self.resolve(closure_ty, ResolvingClosure(id));
let def_id = self.tcx().hir.local_def_id(id); self.tables.closure_tys.insert(id, closure_ty);
self.tcx().maps.closure_type.borrow_mut().insert(def_id, closure_ty);
} }
for (&id, &closure_kind) in self.fcx.tables.borrow().closure_kinds.iter() { for (&id, &closure_kind) in self.fcx.tables.borrow().closure_kinds.iter() {
let def_id = self.tcx().hir.local_def_id(id); self.tables.closure_kinds.insert(id, closure_kind);
self.tcx().maps.closure_kind.borrow_mut().insert(def_id, closure_kind);
} }
} }
@ -316,14 +312,14 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
self.fcx.tables.borrow_mut().lints.transfer(&mut self.tables.lints); self.fcx.tables.borrow_mut().lints.transfer(&mut self.tables.lints);
} }
fn visit_anon_types(&self) { fn visit_anon_types(&mut self) {
if self.fcx.writeback_errors.get() { if self.fcx.writeback_errors.get() {
return return
} }
let gcx = self.tcx().global_tcx(); let gcx = self.tcx().global_tcx();
for (&def_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() { for (&node_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() {
let reason = ResolvingAnonTy(def_id); let reason = ResolvingAnonTy(node_id);
let inside_ty = self.resolve(&concrete_ty, reason); let inside_ty = self.resolve(&concrete_ty, reason);
// Convert the type from the function into a type valid outside // Convert the type from the function into a type valid outside
@ -361,7 +357,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
} }
}); });
gcx.maps.ty.borrow_mut().insert(def_id, outside_ty); self.tables.node_types.insert(node_id, outside_ty);
} }
} }
@ -483,19 +479,6 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
} }
} }
fn visit_deferred_obligations(&mut self, item_id: ast::NodeId) {
let deferred_obligations = self.fcx.deferred_obligations.borrow();
let obligations: Vec<_> = deferred_obligations.iter().map(|obligation| {
let reason = ResolvingDeferredObligation(obligation.cause.span);
self.resolve(obligation, reason)
}).collect();
if !obligations.is_empty() {
assert!(self.fcx.tcx.deferred_obligations.borrow_mut()
.insert(item_id, obligations).is_none());
}
}
fn visit_type_nodes(&self) { fn visit_type_nodes(&self) {
for (&id, ty) in self.fcx.ast_ty_to_ty_cache.borrow().iter() { for (&id, ty) in self.fcx.ast_ty_to_ty_cache.borrow().iter() {
let ty = self.resolve(ty, ResolvingTyNode(id)); let ty = self.resolve(ty, ResolvingTyNode(id));
@ -528,8 +511,7 @@ enum ResolveReason {
ResolvingClosure(ast::NodeId), ResolvingClosure(ast::NodeId),
ResolvingFnSig(ast::NodeId), ResolvingFnSig(ast::NodeId),
ResolvingFieldTypes(ast::NodeId), ResolvingFieldTypes(ast::NodeId),
ResolvingAnonTy(DefId), ResolvingAnonTy(ast::NodeId),
ResolvingDeferredObligation(Span),
ResolvingTyNode(ast::NodeId), ResolvingTyNode(ast::NodeId),
} }
@ -545,13 +527,10 @@ impl<'a, 'gcx, 'tcx> ResolveReason {
ResolvingClosure(id) | ResolvingClosure(id) |
ResolvingFnSig(id) | ResolvingFnSig(id) |
ResolvingFieldTypes(id) | ResolvingFieldTypes(id) |
ResolvingTyNode(id) => { ResolvingTyNode(id) |
ResolvingAnonTy(id) => {
tcx.hir.span(id) tcx.hir.span(id)
} }
ResolvingAnonTy(did) => {
tcx.def_span(did)
}
ResolvingDeferredObligation(span) => span
} }
} }
} }
@ -626,7 +605,6 @@ impl<'cx, 'gcx, 'tcx> Resolver<'cx, 'gcx, 'tcx> {
ResolvingFnSig(_) | ResolvingFnSig(_) |
ResolvingFieldTypes(_) | ResolvingFieldTypes(_) |
ResolvingDeferredObligation(_) |
ResolvingTyNode(_) => { ResolvingTyNode(_) => {
// any failures here should also fail when // any failures here should also fail when
// resolving the patterns, closure types, or // resolving the patterns, closure types, or

View File

@ -70,7 +70,8 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
let item_def_id = tcx.hir.local_def_id(item_id); let item_def_id = tcx.hir.local_def_id(item_id);
// this will have been written by the main typeck pass // this will have been written by the main typeck pass
if let Some(imports) = tcx.maps.used_trait_imports.borrow().get(&item_def_id) { if let Some(tables) = tcx.maps.typeck_tables.borrow().get(&item_def_id) {
let imports = &tables.used_trait_imports;
debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports); debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports);
used_trait_imports.extend(imports); used_trait_imports.extend(imports);
} else { } else {

View File

@ -47,10 +47,6 @@ item, we may need to compute the *type scheme* or *trait definition*
for other items. for other items.
There are some shortcomings in this design: There are some shortcomings in this design:
- Before walking the set of supertraits for a given trait, you must
call `ensure_super_predicates` on that trait def-id. Otherwise,
`item_super_predicates` will result in ICEs.
- Because the item generics include defaults, cycles through type - Because the item generics include defaults, cycles through type
parameter defaults are illegal even if those defaults are never parameter defaults are illegal even if those defaults are never
employed. This is not necessarily a bug. employed. This is not necessarily a bug.
@ -66,7 +62,7 @@ use middle::resolve_lifetime as rl;
use rustc_const_eval::EvalHint::UncheckedExprHint; use rustc_const_eval::EvalHint::UncheckedExprHint;
use rustc_const_eval::{ConstContext, report_const_eval_err}; use rustc_const_eval::{ConstContext, report_const_eval_err};
use rustc::ty::subst::Substs; use rustc::ty::subst::Substs;
use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContainer, ReprOptions}; use rustc::ty::{ToPredicate, ReprOptions};
use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
use rustc::ty::maps::Providers; use rustc::ty::maps::Providers;
use rustc::ty::util::IntTypeExt; use rustc::ty::util::IntTypeExt;
@ -80,6 +76,7 @@ use std::cell::RefCell;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use syntax::{abi, ast, attr}; use syntax::{abi, ast, attr};
use syntax::codemap::Spanned;
use syntax::symbol::{Symbol, keywords}; use syntax::symbol::{Symbol, keywords};
use syntax_pos::{Span, DUMMY_SP}; use syntax_pos::{Span, DUMMY_SP};
@ -98,9 +95,14 @@ pub fn collect_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
pub fn provide(providers: &mut Providers) { pub fn provide(providers: &mut Providers) {
*providers = Providers { *providers = Providers {
ty,
generics, generics,
predicates,
super_predicates,
type_param_predicates,
trait_def, trait_def,
adt_def, adt_def,
impl_trait_ref,
..*providers ..*providers
}; };
} }
@ -190,7 +192,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> {
for param in &generics.ty_params { for param in &generics.ty_params {
if param.default.is_some() { if param.default.is_some() {
let def_id = self.tcx.hir.local_def_id(param.id); let def_id = self.tcx.hir.local_def_id(param.id);
type_of_def_id(self.tcx, def_id); self.tcx.item_type(def_id);
} }
} }
intravisit::walk_generics(self, generics); intravisit::walk_generics(self, generics);
@ -200,7 +202,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> {
if let hir::ExprClosure(..) = expr.node { if let hir::ExprClosure(..) = expr.node {
let def_id = self.tcx.hir.local_def_id(expr.id); let def_id = self.tcx.hir.local_def_id(expr.id);
self.tcx.item_generics(def_id); self.tcx.item_generics(def_id);
type_of_def_id(self.tcx, def_id); self.tcx.item_type(def_id);
} }
intravisit::walk_expr(self, expr); intravisit::walk_expr(self, expr);
} }
@ -209,6 +211,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> {
if let hir::TyImplTrait(..) = ty.node { if let hir::TyImplTrait(..) = ty.node {
let def_id = self.tcx.hir.local_def_id(ty.id); let def_id = self.tcx.hir.local_def_id(ty.id);
self.tcx.item_generics(def_id); self.tcx.item_generics(def_id);
self.tcx.item_predicates(def_id);
} }
intravisit::walk_ty(self, ty); intravisit::walk_ty(self, ty);
} }
@ -254,42 +257,12 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
&self.tcx.ast_ty_to_ty_cache &self.tcx.ast_ty_to_ty_cache
} }
fn get_item_type(&self, span: Span, id: DefId) -> Ty<'tcx> {
self.tcx.cycle_check(span, ty::maps::Query::ty(id), || {
type_of_def_id(self.tcx, id)
})
}
/// Ensure that the (transitive) super predicates for
/// `trait_def_id` are available. This will report a cycle error
/// if a trait `X` (transitively) extends itself in some form.
fn ensure_super_predicates(&self,
span: Span,
trait_def_id: DefId) {
if !trait_def_id.is_local() {
// If this trait comes from an external crate, then all of the
// supertraits it may depend on also must come from external
// crates, and hence all of them already have their
// super-predicates "converted" (and available from crate
// meta-data), so there is no need to transitively test them.
return;
}
self.tcx.maps.super_predicates.memoize(trait_def_id, || {
self.tcx.cycle_check(span, ty::maps::Query::super_predicates(trait_def_id), || {
super_predicates(self.tcx, trait_def_id)
})
});
}
fn get_type_parameter_bounds(&self, fn get_type_parameter_bounds(&self,
span: Span, span: Span,
def_id: DefId) def_id: DefId)
-> Vec<ty::Predicate<'tcx>> -> ty::GenericPredicates<'tcx>
{ {
self.tcx.cycle_check(span, self.tcx.maps.type_param_predicates(self.tcx, span, (self.item_def_id, def_id))
ty::maps::Query::type_param_predicates((self.item_def_id, def_id)),
|| get_type_parameter_bounds(self.tcx, self.item_def_id, def_id))
} }
fn get_free_substs(&self) -> Option<&Substs<'tcx>> { fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
@ -343,11 +316,9 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
} }
} }
fn get_type_parameter_bounds<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
item_def_id: DefId, (item_def_id, def_id): (DefId, DefId))
def_id: DefId) -> ty::GenericPredicates<'tcx> {
-> Vec<ty::Predicate<'tcx>>
{
use rustc::hir::map::*; use rustc::hir::map::*;
use rustc::hir::*; use rustc::hir::*;
@ -369,7 +340,10 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
tcx.item_generics(item_def_id).parent tcx.item_generics(item_def_id).parent
}; };
let mut results = parent.map_or(vec![], |parent| { let mut result = parent.map_or(ty::GenericPredicates {
parent: None,
predicates: vec![]
}, |parent| {
let icx = ItemCtxt::new(tcx, parent); let icx = ItemCtxt::new(tcx, parent);
icx.get_type_parameter_bounds(DUMMY_SP, def_id) icx.get_type_parameter_bounds(DUMMY_SP, def_id)
}); });
@ -379,14 +353,14 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
NodeTraitItem(item) => { NodeTraitItem(item) => {
match item.node { match item.node {
TraitItemKind::Method(ref sig, _) => &sig.generics, TraitItemKind::Method(ref sig, _) => &sig.generics,
_ => return results _ => return result
} }
} }
NodeImplItem(item) => { NodeImplItem(item) => {
match item.node { match item.node {
ImplItemKind::Method(ref sig, _) => &sig.generics, ImplItemKind::Method(ref sig, _) => &sig.generics,
_ => return results _ => return result
} }
} }
@ -401,30 +375,31 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
ItemTrait(_, ref generics, ..) => { ItemTrait(_, ref generics, ..) => {
// Implied `Self: Trait` and supertrait bounds. // Implied `Self: Trait` and supertrait bounds.
if param_id == item_node_id { if param_id == item_node_id {
results.push(ty::TraitRef { result.predicates.push(ty::TraitRef {
def_id: item_def_id, def_id: item_def_id,
substs: Substs::identity_for_item(tcx, item_def_id) substs: Substs::identity_for_item(tcx, item_def_id)
}.to_predicate()); }.to_predicate());
} }
generics generics
} }
_ => return results _ => return result
} }
} }
NodeForeignItem(item) => { NodeForeignItem(item) => {
match item.node { match item.node {
ForeignItemFn(_, _, ref generics) => generics, ForeignItemFn(_, _, ref generics) => generics,
_ => return results _ => return result
} }
} }
_ => return results _ => return result
}; };
let icx = ItemCtxt::new(tcx, item_def_id); let icx = ItemCtxt::new(tcx, item_def_id);
results.extend(icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty)); result.predicates.extend(
results icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty));
result
} }
impl<'a, 'tcx> ItemCtxt<'a, 'tcx> { impl<'a, 'tcx> ItemCtxt<'a, 'tcx> {
@ -483,63 +458,6 @@ fn is_param<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
} }
} }
fn convert_field<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
field: &hir::StructField,
ty_f: &'tcx ty::FieldDef)
{
tcx.item_generics(ty_f.did);
let tt = ItemCtxt::new(tcx, ty_f.did).to_ty(&field.ty);
tcx.maps.ty.borrow_mut().insert(ty_f.did, tt);
tcx.maps.predicates.borrow_mut().insert(ty_f.did, ty::GenericPredicates {
parent: Some(tcx.hir.get_parent_did(field.id)),
predicates: vec![]
});
}
fn convert_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
id: ast::NodeId,
sig: &hir::MethodSig) {
let def_id = tcx.hir.local_def_id(id);
let fty = AstConv::ty_of_fn(&ItemCtxt::new(tcx, def_id), sig.unsafety, sig.abi, &sig.decl);
let substs = Substs::identity_for_item(tcx, def_id);
let fty = tcx.mk_fn_def(def_id, substs, fty);
tcx.maps.ty.borrow_mut().insert(def_id, fty);
ty_generic_predicates(tcx, def_id, &sig.generics);
}
fn convert_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
container: AssociatedItemContainer,
id: ast::NodeId,
ty: ty::Ty<'tcx>)
{
let predicates = ty::GenericPredicates {
parent: Some(container.id()),
predicates: vec![]
};
let def_id = tcx.hir.local_def_id(id);
tcx.maps.predicates.borrow_mut().insert(def_id, predicates);
tcx.maps.ty.borrow_mut().insert(def_id, ty);
}
fn convert_associated_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
container: AssociatedItemContainer,
id: ast::NodeId,
ty: Option<Ty<'tcx>>)
{
let predicates = ty::GenericPredicates {
parent: Some(container.id()),
predicates: vec![]
};
let def_id = tcx.hir.local_def_id(id);
tcx.maps.predicates.borrow_mut().insert(def_id, predicates);
if let Some(ty) = ty {
tcx.maps.ty.borrow_mut().insert(def_id, ty);
}
}
fn ensure_no_ty_param_bounds(tcx: TyCtxt, fn ensure_no_ty_param_bounds(tcx: TyCtxt,
span: Span, span: Span,
generics: &hir::Generics, generics: &hir::Generics,
@ -582,195 +500,125 @@ fn ensure_no_ty_param_bounds(tcx: TyCtxt,
fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) { fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) {
debug!("convert: item {} with id {}", it.name, it.id); debug!("convert: item {} with id {}", it.name, it.id);
let def_id = tcx.hir.local_def_id(it.id); let def_id = tcx.hir.local_def_id(it.id);
let icx = ItemCtxt::new(tcx, def_id);
match it.node { match it.node {
// These don't define types. // These don't define types.
hir::ItemExternCrate(_) | hir::ItemUse(..) | hir::ItemMod(_) => { hir::ItemExternCrate(_) | hir::ItemUse(..) | hir::ItemMod(_) => {
} }
hir::ItemForeignMod(ref foreign_mod) => { hir::ItemForeignMod(ref foreign_mod) => {
for item in &foreign_mod.items { for item in &foreign_mod.items {
convert_foreign_item(tcx, item); let def_id = tcx.hir.local_def_id(item.id);
tcx.item_generics(def_id);
tcx.item_type(def_id);
tcx.item_predicates(def_id);
} }
} }
hir::ItemEnum(ref enum_definition, _) => { hir::ItemEnum(ref enum_definition, _) => {
tcx.item_generics(def_id); tcx.item_generics(def_id);
predicates_of_item(tcx, it); tcx.item_type(def_id);
let ty = type_of_def_id(tcx, def_id); tcx.item_predicates(def_id);
convert_enum_variant_types(tcx, convert_enum_variant_types(tcx, def_id, &enum_definition.variants);
tcx.lookup_adt_def(tcx.hir.local_def_id(it.id)),
ty,
&enum_definition.variants);
}, },
hir::ItemDefaultImpl(_, ref ast_trait_ref) => { hir::ItemDefaultImpl(..) => {
let trait_ref = if let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
AstConv::instantiate_mono_trait_ref(&icx,
ast_trait_ref,
tcx.mk_self_type());
tcx.record_trait_has_default_impl(trait_ref.def_id); tcx.record_trait_has_default_impl(trait_ref.def_id);
tcx.maps.impl_trait_ref.borrow_mut().insert(tcx.hir.local_def_id(it.id),
Some(trait_ref));
} }
hir::ItemImpl(.., ref opt_trait_ref, _, _) => { }
hir::ItemImpl(..) => {
tcx.item_generics(def_id); tcx.item_generics(def_id);
let selfty = type_of_def_id(tcx, def_id); tcx.item_type(def_id);
tcx.impl_trait_ref(def_id);
let trait_ref = opt_trait_ref.as_ref().map(|ast_trait_ref| { tcx.item_predicates(def_id);
AstConv::instantiate_mono_trait_ref(&icx, ast_trait_ref, selfty)
});
tcx.maps.impl_trait_ref.borrow_mut().insert(def_id, trait_ref);
predicates_of_item(tcx, it);
}, },
hir::ItemTrait(..) => { hir::ItemTrait(..) => {
tcx.item_generics(def_id); tcx.item_generics(def_id);
tcx.lookup_trait_def(def_id); tcx.lookup_trait_def(def_id);
icx.ensure_super_predicates(it.span, def_id); tcx.maps.super_predicates(tcx, it.span, def_id);
predicates_of_item(tcx, it); tcx.item_predicates(def_id);
}, },
hir::ItemStruct(ref struct_def, _) | hir::ItemStruct(ref struct_def, _) |
hir::ItemUnion(ref struct_def, _) => { hir::ItemUnion(ref struct_def, _) => {
tcx.item_generics(def_id); tcx.item_generics(def_id);
predicates_of_item(tcx, it); tcx.item_type(def_id);
let ty = type_of_def_id(tcx, def_id); tcx.item_predicates(def_id);
let variant = tcx.lookup_adt_def(def_id).struct_variant(); for f in struct_def.fields() {
let def_id = tcx.hir.local_def_id(f.id);
for (f, ty_f) in struct_def.fields().iter().zip(variant.fields.iter()) { tcx.item_generics(def_id);
convert_field(tcx, f, ty_f) tcx.item_type(def_id);
tcx.item_predicates(def_id);
} }
if !struct_def.is_struct() { if !struct_def.is_struct() {
convert_variant_ctor(tcx, struct_def.id(), variant, ty); convert_variant_ctor(tcx, struct_def.id());
} }
}, },
hir::ItemTy(_, ref generics) => { hir::ItemTy(_, ref generics) => {
ensure_no_ty_param_bounds(tcx, it.span, generics, "type"); ensure_no_ty_param_bounds(tcx, it.span, generics, "type");
tcx.item_generics(def_id); tcx.item_generics(def_id);
predicates_of_item(tcx, it); tcx.item_type(def_id);
type_of_def_id(tcx, def_id); tcx.item_predicates(def_id);
}, },
_ => { _ => {
tcx.item_generics(def_id); tcx.item_generics(def_id);
predicates_of_item(tcx, it); tcx.item_type(def_id);
type_of_def_id(tcx, def_id); tcx.item_predicates(def_id);
}, },
} }
} }
fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item: &hir::TraitItem) { fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item: &hir::TraitItem) {
// we can lookup details about the trait because items are visited
// before trait-items
let trait_def_id = tcx.hir.get_parent_did(trait_item.id);
let def_id = tcx.hir.local_def_id(trait_item.id); let def_id = tcx.hir.local_def_id(trait_item.id);
tcx.item_generics(def_id);
match trait_item.node { match trait_item.node {
hir::TraitItemKind::Const(ref ty, _) => { hir::TraitItemKind::Const(..) |
tcx.item_generics(def_id); hir::TraitItemKind::Type(_, Some(_)) |
let ty = ItemCtxt::new(tcx, def_id).to_ty(&ty); hir::TraitItemKind::Method(..) => {
convert_associated_const(tcx, tcx.item_type(def_id);
TraitContainer(trait_def_id),
trait_item.id,
ty);
} }
hir::TraitItemKind::Type(_, ref opt_ty) => { hir::TraitItemKind::Type(_, None) => {}
tcx.item_generics(def_id); };
let typ = opt_ty.as_ref().map(|ty| ItemCtxt::new(tcx, def_id).to_ty(&ty)); tcx.item_predicates(def_id);
convert_associated_type(tcx, TraitContainer(trait_def_id), trait_item.id, typ);
}
hir::TraitItemKind::Method(ref sig, _) => {
convert_method(tcx, trait_item.id, sig);
}
}
} }
fn convert_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item: &hir::ImplItem) { fn convert_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item: &hir::ImplItem) {
// we can lookup details about the impl because items are visited
// before impl-items
let impl_def_id = tcx.hir.get_parent_did(impl_item.id);
let def_id = tcx.hir.local_def_id(impl_item.id); let def_id = tcx.hir.local_def_id(impl_item.id);
match impl_item.node {
hir::ImplItemKind::Const(ref ty, _) => {
tcx.item_generics(def_id); tcx.item_generics(def_id);
let ty = ItemCtxt::new(tcx, def_id).to_ty(&ty); tcx.item_type(def_id);
convert_associated_const(tcx, tcx.item_predicates(def_id);
ImplContainer(impl_def_id),
impl_item.id,
ty);
}
hir::ImplItemKind::Type(ref ty) => {
tcx.item_generics(def_id);
if tcx.impl_trait_ref(impl_def_id).is_none() {
span_err!(tcx.sess, impl_item.span, E0202,
"associated types are not allowed in inherent impls");
}
let typ = ItemCtxt::new(tcx, def_id).to_ty(ty);
convert_associated_type(tcx, ImplContainer(impl_def_id), impl_item.id, Some(typ));
}
hir::ImplItemKind::Method(ref sig, _) => {
convert_method(tcx, impl_item.id, sig);
}
}
} }
fn convert_variant_ctor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn convert_variant_ctor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ctor_id: ast::NodeId, ctor_id: ast::NodeId) {
variant: &'tcx ty::VariantDef,
ty: Ty<'tcx>) {
let def_id = tcx.hir.local_def_id(ctor_id); let def_id = tcx.hir.local_def_id(ctor_id);
tcx.item_generics(def_id); tcx.item_generics(def_id);
let ctor_ty = match variant.ctor_kind { tcx.item_type(def_id);
CtorKind::Fictive | CtorKind::Const => ty, tcx.item_predicates(def_id);
CtorKind::Fn => {
let inputs = variant.fields.iter().map(|field| tcx.item_type(field.did));
let substs = Substs::identity_for_item(tcx, def_id);
tcx.mk_fn_def(def_id, substs, ty::Binder(tcx.mk_fn_sig(
inputs,
ty,
false,
hir::Unsafety::Normal,
abi::Abi::Rust
)))
}
};
tcx.maps.ty.borrow_mut().insert(def_id, ctor_ty);
tcx.maps.predicates.borrow_mut().insert(def_id, ty::GenericPredicates {
parent: Some(tcx.hir.get_parent_did(ctor_id)),
predicates: vec![]
});
} }
fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def: &'tcx ty::AdtDef, def_id: DefId,
ty: Ty<'tcx>,
variants: &[hir::Variant]) { variants: &[hir::Variant]) {
let repr_hints = tcx.lookup_repr_hints(def.did); let def = tcx.lookup_adt_def(def_id);
let repr_type = tcx.enum_repr_type(repr_hints.get(0)); let repr_type = def.repr.discr_type();
let initial = repr_type.initial_discriminant(tcx); let initial = repr_type.initial_discriminant(tcx);
let mut prev_discr = None::<ConstInt>; let mut prev_discr = None::<ConstInt>;
// fill the discriminant values and field types // fill the discriminant values and field types
for (variant, ty_variant) in variants.iter().zip(def.variants.iter()) { for variant in variants {
let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr()); let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr());
prev_discr = Some(if let Some(e) = variant.node.disr_expr { prev_discr = Some(if let Some(e) = variant.node.disr_expr {
let result = evaluate_disr_expr(tcx, repr_type, e);
let expr_did = tcx.hir.local_def_id(e.node_id); let expr_did = tcx.hir.local_def_id(e.node_id);
tcx.maps.monomorphic_const_eval.borrow_mut() let result = tcx.maps.monomorphic_const_eval.memoize(expr_did, || {
.insert(expr_did, result.map(ConstVal::Integral)); evaluate_disr_expr(tcx, repr_type, e).map(ConstVal::Integral)
});
result.ok() match result {
Ok(ConstVal::Integral(x)) => Some(x),
_ => None
}
} else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) { } else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) {
Some(discr) Some(discr)
} else { } else {
@ -784,13 +632,16 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
None None
}.unwrap_or(wrapped_discr)); }.unwrap_or(wrapped_discr));
for (f, ty_f) in variant.node.data.fields().iter().zip(ty_variant.fields.iter()) { for f in variant.node.data.fields() {
convert_field(tcx, f, ty_f) let def_id = tcx.hir.local_def_id(f.id);
tcx.item_generics(def_id);
tcx.item_type(def_id);
tcx.item_predicates(def_id);
} }
// Convert the ctor, if any. This also registers the variant as // Convert the ctor, if any. This also registers the variant as
// an item. // an item.
convert_variant_ctor(tcx, variant.node.data.id(), ty_variant, ty); convert_variant_ctor(tcx, variant.node.data.id());
} }
} }
@ -985,7 +836,7 @@ fn super_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// Now require that immediate supertraits are converted, // Now require that immediate supertraits are converted,
// which will, in turn, reach indirect supertraits. // which will, in turn, reach indirect supertraits.
for bound in superbounds.iter().filter_map(|p| p.to_opt_poly_trait_ref()) { for bound in superbounds.iter().filter_map(|p| p.to_opt_poly_trait_ref()) {
icx.ensure_super_predicates(item.span, bound.def_id()); tcx.maps.super_predicates(tcx, item.span, bound.def_id());
} }
ty::GenericPredicates { ty::GenericPredicates {
@ -1212,24 +1063,51 @@ fn generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}) })
} }
fn type_of_def_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId) def_id: DefId)
-> Ty<'tcx> { -> Ty<'tcx> {
let node_id = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
id
} else {
return tcx.item_type(def_id);
};
tcx.maps.ty.memoize(def_id, || {
use rustc::hir::map::*; use rustc::hir::map::*;
use rustc::hir::*; use rustc::hir::*;
// Alway bring in generics, as computing the type needs them. let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
tcx.item_generics(def_id);
let icx = ItemCtxt::new(tcx, def_id); let icx = ItemCtxt::new(tcx, def_id);
match tcx.hir.get(node_id) { match tcx.hir.get(node_id) {
NodeTraitItem(item) => {
match item.node {
TraitItemKind::Method(ref sig, _) => {
let fty = AstConv::ty_of_fn(&icx, sig.unsafety, sig.abi, &sig.decl);
let substs = Substs::identity_for_item(tcx, def_id);
tcx.mk_fn_def(def_id, substs, fty)
}
TraitItemKind::Const(ref ty, _) |
TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty),
TraitItemKind::Type(_, None) => {
span_bug!(item.span, "associated type missing default");
}
}
}
NodeImplItem(item) => {
match item.node {
ImplItemKind::Method(ref sig, _) => {
let fty = AstConv::ty_of_fn(&icx, sig.unsafety, sig.abi, &sig.decl);
let substs = Substs::identity_for_item(tcx, def_id);
tcx.mk_fn_def(def_id, substs, fty)
}
ImplItemKind::Const(ref ty, _) => icx.to_ty(ty),
ImplItemKind::Type(ref ty) => {
if tcx.impl_trait_ref(tcx.hir.get_parent_did(node_id)).is_none() {
span_err!(tcx.sess, item.span, E0202,
"associated types are not allowed in inherent impls");
}
icx.to_ty(ty)
}
}
}
NodeItem(item) => { NodeItem(item) => {
match item.node { match item.node {
ItemStatic(ref t, ..) | ItemConst(ref t, _) | ItemStatic(ref t, ..) | ItemConst(ref t, _) |
@ -1261,6 +1139,7 @@ fn type_of_def_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
} }
} }
} }
NodeForeignItem(foreign_item) => { NodeForeignItem(foreign_item) => {
let abi = tcx.hir.get_foreign_abi(node_id); let abi = tcx.hir.get_foreign_abi(node_id);
@ -1271,6 +1150,30 @@ fn type_of_def_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ForeignItemStatic(ref t, _) => icx.to_ty(t) ForeignItemStatic(ref t, _) => icx.to_ty(t)
} }
} }
NodeStructCtor(&ref def) |
NodeVariant(&Spanned { node: hir::Variant_ { data: ref def, .. }, .. }) => {
let ty = tcx.item_type(tcx.hir.get_parent_did(node_id));
match *def {
VariantData::Unit(..) | VariantData::Struct(..) => ty,
VariantData::Tuple(ref fields, _) => {
let inputs = fields.iter().map(|f| {
tcx.item_type(tcx.hir.local_def_id(f.id))
});
let substs = Substs::identity_for_item(tcx, def_id);
tcx.mk_fn_def(def_id, substs, ty::Binder(tcx.mk_fn_sig(
inputs,
ty,
false,
hir::Unsafety::Normal,
abi::Abi::Rust
)))
}
}
}
NodeField(field) => icx.to_ty(&field.ty),
NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => { NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => {
tcx.mk_closure(def_id, Substs::for_item( tcx.mk_closure(def_id, Substs::for_item(
tcx, def_id, tcx, def_id,
@ -1281,52 +1184,58 @@ fn type_of_def_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|def, _| tcx.mk_param_from_def(def) |def, _| tcx.mk_param_from_def(def)
)) ))
} }
NodeExpr(_) => match tcx.hir.get(tcx.hir.get_parent_node(node_id)) {
NodeTy(&hir::Ty { node: TyArray(_, body), .. }) |
NodeExpr(&hir::Expr { node: ExprRepeat(_, body), .. })
if body.node_id == node_id => tcx.types.usize,
NodeVariant(&Spanned { node: Variant_ { disr_expr: Some(e), .. }, .. })
if e.node_id == node_id => {
tcx.lookup_adt_def(tcx.hir.get_parent_did(node_id))
.repr.discr_type().to_ty(tcx)
}
x => {
bug!("unexpected expr parent in type_of_def_id(): {:?}", x);
}
},
NodeTyParam(&hir::TyParam { default: Some(ref ty), .. }) => { NodeTyParam(&hir::TyParam { default: Some(ref ty), .. }) => {
icx.to_ty(ty) icx.to_ty(ty)
} }
NodeTy(&hir::Ty { node: TyImplTrait(..), .. }) => {
let owner = tcx.hir.get_parent_did(node_id);
tcx.item_tables(owner).node_id_to_type(node_id)
}
x => { x => {
bug!("unexpected sort of node in type_of_def_id(): {:?}", x); bug!("unexpected sort of node in type_of_def_id(): {:?}", x);
} }
} }
}
fn impl_trait_ref<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> Option<ty::TraitRef<'tcx>> {
let icx = ItemCtxt::new(tcx, def_id);
let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
match tcx.hir.expect_item(node_id).node {
hir::ItemDefaultImpl(_, ref ast_trait_ref) => {
Some(AstConv::instantiate_mono_trait_ref(&icx,
ast_trait_ref,
tcx.mk_self_type()))
}
hir::ItemImpl(.., ref opt_trait_ref, _, _) => {
opt_trait_ref.as_ref().map(|ast_trait_ref| {
let selfty = tcx.item_type(def_id);
AstConv::instantiate_mono_trait_ref(&icx, ast_trait_ref, selfty)
}) })
} }
_ => bug!()
fn predicates_of_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) {
let def_id = tcx.hir.local_def_id(it.id);
let no_generics = hir::Generics::empty();
let generics = match it.node {
hir::ItemFn(.., ref generics, _) |
hir::ItemTy(_, ref generics) |
hir::ItemEnum(_, ref generics) |
hir::ItemStruct(_, ref generics) |
hir::ItemUnion(_, ref generics) |
hir::ItemTrait(_, ref generics, _, _) |
hir::ItemImpl(_, _, ref generics, ..) => generics,
_ => &no_generics
};
ty_generic_predicates(tcx, def_id, generics);
} }
fn convert_foreign_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
it: &hir::ForeignItem)
{
// For reasons I cannot fully articulate, I do so hate the AST
// map, and I regard each time that I use it as a personal and
// moral failing, but at the moment it seems like the only
// convenient way to extract the ABI. - ndm
let def_id = tcx.hir.local_def_id(it.id);
tcx.item_generics(def_id);
type_of_def_id(tcx, def_id);
let no_generics = hir::Generics::empty();
let generics = match it.node {
hir::ForeignItemFn(_, _, ref generics) => generics,
hir::ForeignItemStatic(..) => &no_generics
};
ty_generic_predicates(tcx, def_id, generics);
} }
// Is it marked with ?Sized // Is it marked with ?Sized
@ -1389,37 +1298,87 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx>(
.filter(move |l| !tcx.named_region_map.late_bound.contains(&l.lifetime.id)) .filter(move |l| !tcx.named_region_map.late_bound.contains(&l.lifetime.id))
} }
fn ty_generic_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId, def_id: DefId)
ast_generics: &hir::Generics) { -> ty::GenericPredicates<'tcx> {
use rustc::hir::map::*;
use rustc::hir::*;
let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
let node = tcx.hir.get(node_id);
let mut is_trait = None;
let icx = ItemCtxt::new(tcx, def_id); let icx = ItemCtxt::new(tcx, def_id);
let no_generics = hir::Generics::empty();
let ast_generics = match node {
NodeTraitItem(item) => {
match item.node {
TraitItemKind::Method(ref sig, _) => &sig.generics,
_ => &no_generics
}
}
NodeImplItem(item) => {
match item.node {
ImplItemKind::Method(ref sig, _) => &sig.generics,
_ => &no_generics
}
}
NodeItem(item) => {
match item.node {
ItemFn(.., ref generics, _) |
ItemImpl(_, _, ref generics, ..) |
ItemTy(_, ref generics) |
ItemEnum(_, ref generics) |
ItemStruct(_, ref generics) |
ItemUnion(_, ref generics) => {
generics
}
ItemTrait(_, ref generics, .., ref items) => {
is_trait = Some((ty::TraitRef {
def_id: def_id,
substs: Substs::identity_for_item(tcx, def_id)
}, items));
generics
}
_ => &no_generics
}
}
NodeForeignItem(item) => {
match item.node {
ForeignItemStatic(..) => &no_generics,
ForeignItemFn(_, _, ref generics) => generics
}
}
NodeTy(&Ty { node: TyImplTrait(ref bounds), span, .. }) => {
let substs = Substs::identity_for_item(tcx, def_id);
let anon_ty = tcx.mk_anon(def_id, substs);
// Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
let bounds = compute_bounds(&icx, anon_ty, bounds,
SizedByDefault::Yes,
span);
return ty::GenericPredicates {
parent: None,
predicates: bounds.predicates(tcx, anon_ty)
};
}
_ => &no_generics
};
let generics = tcx.item_generics(def_id); let generics = tcx.item_generics(def_id);
let parent_count = generics.parent_count() as u32; let parent_count = generics.parent_count() as u32;
let has_own_self = generics.has_self && parent_count == 0; let has_own_self = generics.has_self && parent_count == 0;
let mut predicates = vec![]; let mut predicates = vec![];
let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
let (is_trait, is_impl) = match tcx.hir.get(node_id) {
hir::map::NodeItem(item) => {
match item.node {
hir::ItemTrait(.., ref items) => {
(Some((ty::TraitRef {
def_id: def_id,
substs: Substs::identity_for_item(tcx, def_id)
}, items)), None)
}
hir::ItemImpl(..) => {
let self_ty = type_of_def_id(tcx, def_id);
let trait_ref = tcx.impl_trait_ref(def_id);
(None, Some((self_ty, trait_ref)))
}
_ => (None, None)
}
}
_ => (None, None)
};
// Below we'll consider the bounds on the type parameters (including `Self`) // Below we'll consider the bounds on the type parameters (including `Self`)
// and the explicit where-clauses, but to get the full set of predicates // and the explicit where-clauses, but to get the full set of predicates
// on a trait we need to add in the supertrait bounds and bounds found on // on a trait we need to add in the supertrait bounds and bounds found on
@ -1543,16 +1502,18 @@ fn ty_generic_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// before uses of `U`. This avoids false ambiguity errors // before uses of `U`. This avoids false ambiguity errors
// in trait checking. See `setup_constraining_predicates` // in trait checking. See `setup_constraining_predicates`
// for details. // for details.
if let Some((self_ty, trait_ref)) = is_impl { if let NodeItem(&Item { node: ItemImpl(..), .. }) = node {
let self_ty = tcx.item_type(def_id);
let trait_ref = tcx.impl_trait_ref(def_id);
ctp::setup_constraining_predicates(&mut predicates, ctp::setup_constraining_predicates(&mut predicates,
trait_ref, trait_ref,
&mut ctp::parameters_for_impl(self_ty, trait_ref)); &mut ctp::parameters_for_impl(self_ty, trait_ref));
} }
tcx.maps.predicates.borrow_mut().insert(def_id, ty::GenericPredicates { ty::GenericPredicates {
parent: generics.parent, parent: generics.parent,
predicates: predicates predicates: predicates
}); }
} }
pub enum SizedByDefault { Yes, No, } pub enum SizedByDefault { Yes, No, }

View File

@ -287,6 +287,7 @@ fn check_for_entry_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
pub fn provide(providers: &mut Providers) { pub fn provide(providers: &mut Providers) {
collect::provide(providers); collect::provide(providers);
check::provide(providers);
} }
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)

View File

@ -909,25 +909,12 @@ fn int_type_of_word(s: &str) -> Option<IntType> {
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)] #[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
pub enum ReprAttr { pub enum ReprAttr {
ReprAny,
ReprInt(IntType), ReprInt(IntType),
ReprExtern, ReprExtern,
ReprPacked, ReprPacked,
ReprSimd, ReprSimd,
} }
impl ReprAttr {
pub fn is_ffi_safe(&self) -> bool {
match *self {
ReprAny => false,
ReprInt(ity) => ity.is_ffi_safe(),
ReprExtern => true,
ReprPacked => false,
ReprSimd => true,
}
}
}
#[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)] #[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
pub enum IntType { pub enum IntType {
SignedInt(ast::IntTy), SignedInt(ast::IntTy),
@ -942,16 +929,6 @@ impl IntType {
UnsignedInt(..) => false UnsignedInt(..) => false
} }
} }
fn is_ffi_safe(self) -> bool {
match self {
SignedInt(ast::IntTy::I8) | UnsignedInt(ast::UintTy::U8) |
SignedInt(ast::IntTy::I16) | UnsignedInt(ast::UintTy::U16) |
SignedInt(ast::IntTy::I32) | UnsignedInt(ast::UintTy::U32) |
SignedInt(ast::IntTy::I64) | UnsignedInt(ast::UintTy::U64) |
SignedInt(ast::IntTy::I128) | UnsignedInt(ast::UintTy::U128) => true,
SignedInt(ast::IntTy::Is) | UnsignedInt(ast::UintTy::Us) => false
}
}
} }
pub trait HasAttrs: Sized { pub trait HasAttrs: Sized {

View File

@ -773,7 +773,7 @@ fn find_repr_type_name(diagnostic: &Handler, type_attrs: &[ast::Attribute]) -> &
for a in type_attrs { for a in type_attrs {
for r in &attr::find_repr_attrs(diagnostic, a) { for r in &attr::find_repr_attrs(diagnostic, a) {
repr_type_name = match *r { repr_type_name = match *r {
attr::ReprAny | attr::ReprPacked | attr::ReprSimd => continue, attr::ReprPacked | attr::ReprSimd => continue,
attr::ReprExtern => "i32", attr::ReprExtern => "i32",
attr::ReprInt(attr::SignedInt(ast::IntTy::Is)) => "isize", attr::ReprInt(attr::SignedInt(ast::IntTy::Is)) => "isize",

View File

@ -13,7 +13,6 @@
trait Foo<X = Box<Foo>> { trait Foo<X = Box<Foo>> {
//~^ ERROR unsupported cyclic reference //~^ ERROR unsupported cyclic reference
//~| ERROR unsupported cyclic reference
} }
fn main() { } fn main() { }

View File

@ -52,23 +52,20 @@ fn after() -> impl Fn(i32) {
// independently resolved and only require the concrete // independently resolved and only require the concrete
// return type, which can't depend on the obligation. // return type, which can't depend on the obligation.
fn cycle1() -> impl Clone { fn cycle1() -> impl Clone {
//~^ ERROR unsupported cyclic reference between types/traits detected
//~| cyclic reference
//~| NOTE the cycle begins when processing `cycle1`...
//~| NOTE ...which then requires processing `cycle1::{{impl-Trait}}`...
//~| NOTE ...which then again requires processing `cycle1`, completing the cycle.
send(cycle2().clone()); send(cycle2().clone());
//~^ ERROR the trait bound `std::rc::Rc<std::string::String>: std::marker::Send` is not satisfied
//~| NOTE the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::string::String>`
//~| NOTE `std::rc::Rc<std::string::String>` cannot be sent between threads safely
//~| NOTE required because it appears within the type `impl std::clone::Clone`
//~| NOTE required by `send`
Rc::new(Cell::new(5)) Rc::new(Cell::new(5))
} }
fn cycle2() -> impl Clone { fn cycle2() -> impl Clone {
//~^ NOTE ...which then requires processing `cycle2::{{impl-Trait}}`...
//~| NOTE ...which then requires processing `cycle2`...
send(cycle1().clone()); send(cycle1().clone());
//~^ ERROR the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied
//~| NOTE the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::cell::Cell<i32>>`
//~| NOTE `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
//~| NOTE required because it appears within the type `impl std::clone::Clone`
//~| NOTE required by `send`
Rc::new(String::from("foo")) Rc::new(String::from("foo"))
} }

View File

@ -49,17 +49,6 @@ impl Leak for i32 {
fn leak(self) -> i32 { self } fn leak(self) -> i32 { self }
} }
trait CheckIfSend: Sized {
type T: Default;
fn check(self) -> Self::T { Default::default() }
}
impl<T> CheckIfSend for T {
default type T = ();
}
impl<T: Send> CheckIfSend for T {
type T = bool;
}
fn main() { fn main() {
let _: u32 = hide(0_u32); let _: u32 = hide(0_u32);
//~^ ERROR mismatched types //~^ ERROR mismatched types
@ -73,12 +62,6 @@ fn main() {
//~| found type `<impl Foo as Leak>::T` //~| found type `<impl Foo as Leak>::T`
//~| expected i32, found associated type //~| expected i32, found associated type
let _: bool = CheckIfSend::check(hide(0_i32));
//~^ ERROR mismatched types
//~| expected type `bool`
//~| found type `<impl Foo as CheckIfSend>::T`
//~| expected bool, found associated type
let mut x = (hide(0_u32), hide(0_i32)); let mut x = (hide(0_u32), hide(0_i32));
x = (x.1, x = (x.1,
//~^ ERROR mismatched types //~^ ERROR mismatched types

View File

@ -26,6 +26,6 @@ impl Tr for Self {} //~ ERROR unsupported cyclic reference between types/traits
impl Tr for S<Self> {} //~ ERROR unsupported cyclic reference between types/traits detected impl Tr for S<Self> {} //~ ERROR unsupported cyclic reference between types/traits detected
impl Self {} //~ ERROR unsupported cyclic reference between types/traits detected impl Self {} //~ ERROR unsupported cyclic reference between types/traits detected
impl S<Self> {} //~ ERROR unsupported cyclic reference between types/traits detected impl S<Self> {} //~ ERROR unsupported cyclic reference between types/traits detected
impl Tr<Self::A> for S {} //~ ERROR `Self` type is used before it's determined impl Tr<Self::A> for S {} //~ ERROR unsupported cyclic reference between types/traits detected
fn main() {} fn main() {}

View File

@ -112,10 +112,13 @@ enum EnumChangeValueCStyleVariant0 {
#[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_dirty(label="HirBody", cfg="cfail2")] #[rustc_dirty(label="HirBody", cfg="cfail2")]
#[rustc_clean(label="HirBody", cfg="cfail3")] #[rustc_clean(label="HirBody", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail3")]
enum EnumChangeValueCStyleVariant0 { enum EnumChangeValueCStyleVariant0 {
Variant1, Variant1,
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
Variant2 = 22, Variant2 = 22,
} }

View File

@ -29,16 +29,3 @@ fn after() -> impl FnMut(i32) {
let mut p = Box::new(0); let mut p = Box::new(0);
move |x| *p = x move |x| *p = x
} }
// Cycles should work as the deferred obligations are
// independently resolved and only require the concrete
// return type, which can't depend on the obligation.
fn cycle1() -> impl Clone {
send(cycle2().clone());
5
}
fn cycle2() -> impl Clone {
send(cycle1().clone());
String::from("foo")
}

View File

@ -28,6 +28,17 @@ impl<T> Leak<T> for T {
fn leak(self) -> T { self } fn leak(self) -> T { self }
} }
trait CheckIfSend: Sized {
type T: Default;
fn check(self) -> Self::T { Default::default() }
}
impl<T> CheckIfSend for T {
default type T = ();
}
impl<T: Send> CheckIfSend for T {
type T = bool;
}
fn lucky_seven() -> impl Fn(usize) -> u8 { fn lucky_seven() -> impl Fn(usize) -> u8 {
let a = [1, 2, 3, 4, 5, 6, 7]; let a = [1, 2, 3, 4, 5, 6, 7];
move |i| a[i] move |i| a[i]
@ -40,4 +51,6 @@ fn main() {
assert_eq!(std::mem::size_of_val(&lucky_seven()), 7); assert_eq!(std::mem::size_of_val(&lucky_seven()), 7);
assert_eq!(Leak::<i32>::leak(hide(5_i32)), 5_i32); assert_eq!(Leak::<i32>::leak(hide(5_i32)), 5_i32);
assert_eq!(CheckIfSend::check(hide(0_i32)), false);
} }