From ba11640179bbde334b525146d3a164999412cc73 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 14 Feb 2017 11:32:00 +0200 Subject: [PATCH] rustc_typeck: hook up collect and item/body check to on-demand. --- src/librustc/middle/dead.rs | 7 +- src/librustc/mir/tcx.rs | 4 +- src/librustc/traits/fulfill.rs | 139 +-- src/librustc/traits/mod.rs | 1 - src/librustc/traits/select.rs | 11 +- src/librustc/traits/structural_impls.rs | 27 - src/librustc/ty/context.rs | 22 +- src/librustc/ty/layout.rs | 9 +- src/librustc/ty/maps.rs | 84 +- src/librustc/ty/mod.rs | 104 +-- src/librustc/ty/sty.rs | 2 +- src/librustc/ty/util.rs | 15 - .../borrowck/mir/elaborate_drops.rs | 4 +- src/librustc_const_eval/eval.rs | 6 +- .../persist/dirty_clean.rs | 6 + src/librustc_lint/types.rs | 56 +- src/librustc_metadata/cstore_impl.rs | 1 + src/librustc_metadata/decoder.rs | 15 +- src/librustc_metadata/encoder.rs | 4 +- src/librustc_mir/build/matches/test.rs | 4 +- src/librustc_typeck/astconv.rs | 88 +- src/librustc_typeck/check/method/mod.rs | 4 +- src/librustc_typeck/check/mod.rs | 306 ++++--- src/librustc_typeck/check/writeback.rs | 54 +- src/librustc_typeck/check_unused.rs | 3 +- src/librustc_typeck/collect.rs | 809 +++++++++--------- src/librustc_typeck/lib.rs | 1 + src/libsyntax/attr.rs | 23 - src/libsyntax_ext/deriving/generic/mod.rs | 2 +- .../cycle-trait-default-type-trait.rs | 1 - .../impl-trait/auto-trait-leak.rs | 17 +- src/test/compile-fail/impl-trait/equality.rs | 17 - src/test/compile-fail/resolve-self-in-impl.rs | 2 +- src/test/incremental/hashes/enum_defs.rs | 5 +- .../run-pass/impl-trait/auto-trait-leak.rs | 13 - src/test/run-pass/impl-trait/equality.rs | 13 + 36 files changed, 782 insertions(+), 1097 deletions(-) diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 592e4cb9235..cc6d6e88dee 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -159,10 +159,9 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { hir_map::NodeItem(item) => { match item.node { hir::ItemStruct(..) | hir::ItemUnion(..) => { - self.struct_has_extern_repr = item.attrs.iter().any(|attr| { - attr::find_repr_attrs(self.tcx.sess.diagnostic(), attr) - .contains(&attr::ReprExtern) - }); + let def_id = self.tcx.hir.local_def_id(item.id); + let def = self.tcx.lookup_adt_def(def_id); + self.struct_has_extern_repr = def.repr.c; intravisit::walk_item(self, &item); } diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 527f1152770..50a80305bee 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -173,9 +173,7 @@ impl<'tcx> Rvalue<'tcx> { Rvalue::Discriminant(ref lval) => { let ty = lval.ty(mir, tcx).to_ty(tcx); if let ty::TyAdt(adt_def, _) = ty.sty { - let repr_hints = tcx.lookup_repr_hints(adt_def.did); - let repr_type = tcx.enum_repr_type(repr_hints.get(0)); - Some(repr_type.to_ty(tcx)) + Some(adt_def.repr.discr_type().to_ty(tcx)) } else { // Undefined behaviour, bug for now; may want to return something for // the `discriminant` intrinsic later. diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index c31ab2372b6..b87d1846437 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -11,11 +11,9 @@ use dep_graph::DepGraph; use infer::{InferCtxt, InferOk}; 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::{ForestObligation, ObligationProcessor}; use std::marker::PhantomData; -use std::mem; use syntax::ast; use util::nodemap::{FxHashSet, NodeMap}; use hir::def_id::DefId; @@ -23,9 +21,8 @@ use hir::def_id::DefId; use super::CodeAmbiguity; use super::CodeProjectionError; use super::CodeSelectionError; -use super::{FulfillmentError, FulfillmentErrorCode, SelectionError}; -use super::{ObligationCause, BuiltinDerivedObligation}; -use super::{PredicateObligation, TraitObligation, Obligation}; +use super::{FulfillmentError, FulfillmentErrorCode}; +use super::{ObligationCause, PredicateObligation, Obligation}; use super::project; use super::select::SelectionContext; use super::Unimplemented; @@ -82,10 +79,6 @@ pub struct FulfillmentContext<'tcx> { // obligations (otherwise, it's easy to fail to walk to a // particular node-id). region_obligations: NodeMap>>, - - // A list of obligations that need to be deferred to - // a later time for them to be properly fulfilled. - deferred_obligations: Vec>, } #[derive(Clone)] @@ -101,100 +94,12 @@ pub struct PendingPredicateObligation<'tcx> { pub stalled_on: Vec>, } -/// 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> { - 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>> { - 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> { /// Creates a new fulfillment context. pub fn new() -> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), region_obligations: NodeMap(), - deferred_obligations: vec![], } } @@ -294,16 +199,10 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { { 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<_> = self.predicates.to_errors(CodeAmbiguity) .into_iter() .map(|e| to_fulfillment_error(e)) - .chain(deferred_errors) .collect(); if errors.is_empty() { Ok(()) @@ -324,10 +223,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { self.predicates.pending_obligations() } - pub fn take_deferred_obligations(&mut self) -> Vec> { - mem::replace(&mut self.deferred_obligations, vec![]) - } - /// 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. 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 { selcx: selcx, region_obligations: &mut self.region_obligations, - deferred_obligations: &mut self.deferred_obligations }); debug!("select: outcome={:?}", outcome); @@ -378,7 +272,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { struct FulfillProcessor<'a, 'b: 'a, 'gcx: 'tcx, 'tcx: 'b> { selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>, region_obligations: &'a mut NodeMap>>, - deferred_obligations: &'a mut Vec> } 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, obligation, - self.region_obligations, - self.deferred_obligations) + self.region_obligations) .map(|os| os.map(|os| os.into_iter().map(|o| PendingPredicateObligation { obligation: o, 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>( selcx: &mut SelectionContext<'a, 'gcx, 'tcx>, pending_obligation: &mut PendingPredicateObligation<'tcx>, - region_obligations: &mut NodeMap>>, - deferred_obligations: &mut Vec>) + region_obligations: &mut NodeMap>>) -> Result>>, FulfillmentErrorCode<'tcx>> { @@ -502,21 +393,7 @@ fn process_predicate<'a, 'gcx, 'tcx>( info!("selecting trait `{:?}` at depth {} yielded Err", 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)) } } } @@ -714,12 +591,6 @@ impl<'a, 'gcx, 'tcx> GlobalFulfilledPredicates<'gcx> { // already has the required read edges, so we don't need // to add any more edges here. 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 self.set.insert(data.clone()) { debug!("add_if_global: global predicate `{:?}` added", data); diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 58ab713ef27..117e16da26c 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -31,7 +31,6 @@ pub use self::coherence::orphan_check; pub use self::coherence::overlapping_impls; pub use self::coherence::OrphanCheckErr; pub use self::fulfill::{FulfillmentContext, GlobalFulfilledPredicates, RegionObligation}; -pub use self::fulfill::DeferredObligation; pub use self::project::MismatchedProjectionTypes; pub use self::project::{normalize, normalize_projection_type, Normalized}; pub use self::project::{ProjectionCache, ProjectionCacheSnapshot, Reveal}; diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index e12ebb6d515..4c4ace0d8ba 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1478,8 +1478,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // `assemble_candidates_from_object_ty`. } ty::TyParam(..) | - ty::TyProjection(..) | - ty::TyAnon(..) => { + ty::TyProjection(..) => { // In these cases, we don't know what the actual // type is. Therefore, we cannot break it down // into its constituent types. So we don't @@ -1902,7 +1901,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyDynamic(..) | ty::TyParam(..) | ty::TyProjection(..) | - ty::TyAnon(..) | ty::TyInfer(ty::TyVar(_)) | ty::TyInfer(ty::FreshTy(_)) | ty::TyInfer(ty::FreshIntTy(_)) | @@ -1947,6 +1945,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { .map(|f| f.ty(self.tcx(), substs)) .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)] + } } } diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index dedb126d7ff..717c171db2a 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -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 { - tcx.lift(&self.predicate).and_then(|predicate| { - tcx.lift(&self.cause).map(|cause| { - traits::DeferredObligation { - predicate: predicate, - cause: cause - } - }) - }) - } -} - // For trans only. impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> { type Lifted = traits::Vtable<'tcx, ()>; @@ -589,16 +575,3 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCause<'tcx> { 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>(&self, visitor: &mut V) -> bool { - self.predicate.visit_with(visitor) || self.cause.visit_with(visitor) - } -} diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index f1945fd57ef..318c866a59f 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -38,7 +38,6 @@ use ty::TypeVariants::*; use ty::layout::{Layout, TargetDataLayout}; use ty::inhabitedness::DefIdForest; use ty::maps; -use util::common::MemoizationMap; use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet}; use util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::accumulate_vec::AccumulateVec; @@ -50,7 +49,6 @@ use std::cell::{Cell, RefCell}; use std::hash::{Hash, Hasher}; use std::mem; use std::ops::Deref; -use std::rc::Rc; use std::iter; use std::cmp::Ordering; use syntax::abi; @@ -242,6 +240,10 @@ pub struct TypeckTables<'tcx> { /// Lints for the body of this fn generated by typeck. 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> { @@ -259,6 +261,7 @@ impl<'tcx> TypeckTables<'tcx> { fru_field_types: NodeMap(), cast_kinds: NodeMap(), 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). pub all_traits: RefCell>>, - /// 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>>>, - /// HIR Ty -> Ty lowering cache. pub ast_ty_to_ty_cache: RefCell>>, } @@ -734,7 +732,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { derive_macros: RefCell::new(NodeMap()), stability_interner: RefCell::new(FxHashSet()), all_traits: RefCell::new(None), - deferred_obligations: RefCell::new(NodeMap()), ast_ty_to_ty_cache: RefCell::new(NodeMap()), }, 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)) } - - /// Obtain the representation annotation for a struct definition. - pub fn lookup_repr_hints(self, did: DefId) -> Rc> { - 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 { diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 5829ae195c9..3773796e47d 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1147,7 +1147,7 @@ impl<'a, 'gcx, 'tcx> Layout { } // SIMD vector types. - ty::TyAdt(def, ..) if def.is_simd() => { + ty::TyAdt(def, ..) if def.repr.simd => { let element = ty.simd_type(tcx); match *element.layout(infcx)? { Scalar { value, .. } => { @@ -1227,9 +1227,8 @@ impl<'a, 'gcx, 'tcx> Layout { let fields = def.variants[0].fields.iter().map(|field| { field.ty(tcx, substs).layout(infcx) }).collect::, _>>()?; - let packed = tcx.lookup_packed(def.did); 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)?; UntaggedUnion { variants: un } } else { @@ -1353,9 +1352,7 @@ impl<'a, 'gcx, 'tcx> Layout { return Err(LayoutError::SizeOverflow(ty)); } - let repr_hints = tcx.lookup_repr_hints(def.did); - let repr_type = tcx.enum_repr_type(repr_hints.get(0)); - let typeck_ity = Integer::from_attr(dl, repr_type); + let typeck_ity = Integer::from_attr(dl, def.repr.discr_type()); if typeck_ity < min_ity { // 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 diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 6958df093d0..ce4d1f5ec97 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -14,28 +14,33 @@ use middle::const_val::ConstVal; use mir; use ty::{self, Ty, TyCtxt}; use util::common::MemoizationMap; -use util::nodemap::DefIdSet; use rustc_data_structures::indexed_vec::IndexVec; use std::cell::RefCell; use std::rc::Rc; -use syntax::attr; -use syntax_pos::Span; +use syntax_pos::{Span, DUMMY_SP}; trait Key { fn map_crate(&self) -> CrateNum; + fn default_span(&self, tcx: TyCtxt) -> Span; } impl Key for DefId { fn map_crate(&self) -> CrateNum { self.krate } + fn default_span(&self, tcx: TyCtxt) -> Span { + tcx.def_span(*self) + } } impl Key for (DefId, DefId) { fn map_crate(&self) -> CrateNum { self.0.krate } + fn default_span(&self, tcx: TyCtxt) -> Span { + self.1.default_span(tcx) + } } trait Value<'tcx>: Sized { @@ -83,7 +88,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { err.emit(); } - pub fn cycle_check(self, span: Span, query: Query, compute: F) -> R + fn cycle_check(self, span: Span, query: Query, compute: F) -> R where F: FnOnce() -> R { { @@ -104,23 +109,28 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } -impl Query { - fn describe(&self, tcx: TyCtxt) -> String { - match *self { - Query::ty(def_id) => { - format!("processing `{}`", tcx.item_path_str(def_id)) - } - Query::super_predicates(def_id) => { - format!("computing the supertraits of `{}`", - tcx.item_path_str(def_id)) - } - Query::type_param_predicates((_, def_id)) => { - let id = tcx.hir.as_local_node_id(def_id).unwrap(); - format!("computing the bounds for type parameter `{}`", - tcx.hir.ty_param_name(id)) - } - _ => bug!("unexpected `{:?}`", self) - } +trait QueryDescription: DepTrackingMapConfig { + fn describe(tcx: TyCtxt, key: Self::Key) -> String; +} + +impl> QueryDescription for M { + default fn describe(tcx: TyCtxt, def_id: DefId) -> String { + format!("processing `{}`", tcx.item_path_str(def_id)) + } +} + +impl<'tcx> QueryDescription for queries::super_predicates<'tcx> { + fn describe(tcx: TyCtxt, def_id: DefId) -> String { + format!("computing the supertraits of `{}`", + tcx.item_path_str(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(); + format!("computing the bounds for type parameter `{}`", + tcx.hir.ty_param_name(id)) } } @@ -152,6 +162,14 @@ macro_rules! define_maps { $($(#[$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 { use std::marker::PhantomData; @@ -186,11 +204,22 @@ macro_rules! define_maps { } } - impl<$tcx> Maps<$tcx> { + impl<'a, $tcx, 'lcx> Maps<$tcx> { $($(#[$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.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. pub inherent_impls: InherentImpls(DefId) -> Vec, - /// Caches the representation hints for struct definitions. - pub repr_hints: ReprHints(DefId) -> Rc>, - /// Maps from the def-id of a function/method or const/static /// to its MIR. Mutation is done at an item granularity to /// allow MIR optimization passes to function and still @@ -272,10 +298,6 @@ define_maps! { <'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 /// other items, such as enum variant explicit discriminants. pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 01be4288146..357d12bc4dd 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1296,10 +1296,9 @@ bitflags! { const IS_DTORCK = 1 << 1, // is this a dtorck type? const IS_DTORCK_VALID = 1 << 2, const IS_PHANTOM_DATA = 1 << 3, - const IS_SIMD = 1 << 4, - const IS_FUNDAMENTAL = 1 << 5, - const IS_UNION = 1 << 6, - const IS_BOX = 1 << 7, + const IS_FUNDAMENTAL = 1 << 4, + const IS_UNION = 1 << 5, + const IS_BOX = 1 << 6, } } @@ -1384,18 +1383,29 @@ pub struct ReprOptions { impl ReprOptions { pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions { let mut ret = ReprOptions::default(); - let attrs = tcx.lookup_repr_hints(did); - for r in attrs.iter() { - match *r { - attr::ReprExtern => ret.c = true, - attr::ReprPacked => ret.packed = true, - attr::ReprSimd => ret.simd = true, - attr::ReprInt(i) => ret.int = Some(i), - attr::ReprAny => (), + + for attr in tcx.get_attrs(did).iter() { + for r in attr::find_repr_attrs(tcx.sess.diagnostic(), attr) { + match r { + attr::ReprExtern => ret.c = true, + attr::ReprPacked => ret.packed = true, + attr::ReprSimd => ret.simd = true, + attr::ReprInt(i) => ret.int = Some(i), + } } } + + // FIXME(eddyb) This is deprecated and should be removed. + if tcx.has_attr(did, "simd") { + ret.simd = true; + } + ret } + + pub fn discr_type(&self) -> attr::IntType { + self.int.unwrap_or(attr::SignedInt(ast::IntTy::Is)) + } } impl<'a, 'gcx, 'tcx> AdtDef { @@ -1409,9 +1419,6 @@ impl<'a, 'gcx, 'tcx> AdtDef { if attr::contains_name(&attrs, "fundamental") { flags = flags | AdtFlags::IS_FUNDAMENTAL; } - if tcx.lookup_simd(did) { - flags = flags | AdtFlags::IS_SIMD; - } if Some(did) == tcx.lang_items.phantom_data() { flags = flags | AdtFlags::IS_PHANTOM_DATA; } @@ -1500,11 +1507,6 @@ impl<'a, 'gcx, 'tcx> AdtDef { self.flags.get().intersects(AdtFlags::IS_FUNDAMENTAL) } - #[inline] - pub fn is_simd(&self) -> bool { - self.flags.get().intersects(AdtFlags::IS_SIMD) - } - /// Returns true if this is PhantomData. #[inline] pub fn is_phantom_data(&self) -> bool { @@ -1584,8 +1586,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> impl Iterator + 'a { - let repr_hints = tcx.lookup_repr_hints(self.did); - let repr_type = tcx.enum_repr_type(repr_hints.get(0)); + let repr_type = self.repr.discr_type(); let initial = repr_type.initial_discriminant(tcx.global_tcx()); let mut prev_discr = None::; 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> { - self.maps.typeck_tables.memoize(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) - }) - }) + self.maps.typeck_tables(self, DUMMY_SP, def_id) } 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 { - 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 { 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, || { @@ -2182,7 +2165,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn associated_item_def_ids(self, def_id: DefId) -> Rc> { 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, || { @@ -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 /// an inherent impl. pub fn impl_trait_ref(self, id: DefId) -> Option> { - 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, @@ -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 // the type cache. Returns the type parameters and type. 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. 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. 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. 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. 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. 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. 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 @@ -2377,19 +2360,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { 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> { - 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 { @@ -2464,11 +2436,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } 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> { - 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. diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 3d6c1da8830..aa2990679b6 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1077,7 +1077,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { #[inline] pub fn is_simd(&self) -> bool { match self.sty { - TyAdt(def, _) => def.is_simd(), + TyAdt(def, _) => def.repr.simd, _ => false } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index bda76550f34..d1c22651a9e 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -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, /// if not a structure at all. Corresponds to the only possible unsized /// field, and its type can be used to determine unsizing strategy. diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index c64b25032c9..f8c0044774a 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -677,9 +677,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { // Additionally, we do not want to switch on the // discriminant after it is free-ed, because that // way lies only trouble. - let repr_hints = self.tcx.lookup_repr_hints(adt.did); - let repr_type = self.tcx.enum_repr_type(repr_hints.get(0)); - let discr_ty = repr_type.to_ty(self.tcx); + let discr_ty = adt.repr.discr_type().to_ty(self.tcx); let discr = Lvalue::Local(self.patch.new_temp(discr_ty)); let switch_block = self.patch.new_block(BasicBlockData { statements: vec![ diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 967705c7481..eadb49a0731 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -902,8 +902,7 @@ fn infer<'a, 'tcx>(i: ConstInt, (&ty::TyUint(ity), i) => Err(TypeMismatch(ity.to_string(), i)), (&ty::TyAdt(adt, _), i) if adt.is_enum() => { - let hints = tcx.lookup_repr_hints(adt.did); - let int_ty = tcx.enum_repr_type(hints.iter().next()); + let int_ty = adt.repr.discr_type(); infer(i, tcx, &int_ty.to_ty(tcx).sty) }, (_, 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))), Some(&ty::TyAdt(adt, _)) => { - let hints = tcx.lookup_repr_hints(adt.did); - let int_ty = tcx.enum_repr_type(hints.iter().next()); + let int_ty = adt.repr.discr_type(); infer(Infer(n as u128), tcx, &int_ty.to_ty(tcx).sty).map(Integral) }, Some(ty_hint) => bug!("bad ty_hint: {:?}, {:?}", ty_hint, lit), diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index a0bcb54af32..156f8b9e7c4 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -257,6 +257,12 @@ pub struct DirtyCleanMetadataVisitor<'a, 'tcx:'a, 'm> { impl<'a, 'tcx, 'm> ItemLikeVisitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { fn visit_item(&mut self, item: &'tcx hir::Item) { 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) { diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index dd7f751338d..3301a98968e 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -381,6 +381,17 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, 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> { /// Check if the given type is "ffi-safe" (has a stable, well-defined /// representation which can be exported to C code). @@ -406,7 +417,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } match def.adt_kind() { AdtKind::Struct => { - if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { + if !def.repr.c { return FfiUnsafe("found struct without foreign-function-safe \ representation annotation in foreign module, \ 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 } } AdtKind::Union => { - if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { + if !def.repr.c { return FfiUnsafe("found union without foreign-function-safe \ representation annotation in foreign module, \ consider adding a #[repr(C)] attribute to the type"); @@ -479,35 +490,28 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // Check for a repr() attribute to specify the size of the // discriminant. - let repr_hints = cx.lookup_repr_hints(def.did); - match &repr_hints[..] { - &[] => { - // Special-case types like `Option`. - if !is_repr_nullable_ptr(cx, def, substs) { - return FfiUnsafe("found enum without foreign-function-safe \ - representation annotation in foreign \ - module, consider adding a #[repr(...)] \ - attribute to the type"); - } + if !def.repr.c && def.repr.int.is_none() { + // Special-case types like `Option`. + if !is_repr_nullable_ptr(cx, def, substs) { + return FfiUnsafe("found enum without foreign-function-safe \ + representation annotation in foreign \ + module, consider adding a #[repr(...)] \ + attribute to the type"); } - &[ref hint] => { - if !hint.is_ffi_safe() { - // FIXME: This shouldn't be reachable: we should check - // this earlier. - return FfiUnsafe("enum has unexpected #[repr(...)] attribute"); - } + } - // Enum with an explicitly sized discriminant; either - // a C-style enum or a discriminated union. - - // The layout of enum variants is implicitly repr(C). - // FIXME: Is that correct? - } - _ => { + if let Some(int_ty) = def.repr.int { + if !is_ffi_safe(int_ty) { // FIXME: This shouldn't be reachable: we should check // this earlier. - return FfiUnsafe("enum has too many #[repr(...)] attributes"); + return FfiUnsafe("enum has unexpected #[repr(...)] attribute"); } + + // Enum with an explicitly sized discriminant; either + // a C-style enum or a discriminated union. + + // The layout of enum variants is implicitly repr(C). + // FIXME: Is that correct? } // Check the contained variants. diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 770591bc17a..fc7b50f11da 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -101,6 +101,7 @@ provide! { <'tcx> tcx, def_id, cdata mir } + typeck_tables => { cdata.item_body_tables(def_id.index, tcx) } closure_kind => { cdata.closure_kind(def_id.index) } closure_type => { cdata.closure_ty(def_id.index, tcx) } } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 0e92c492e4b..e81d752fde0 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -780,16 +780,19 @@ impl<'a, 'tcx> CrateMetadata { if self.is_proc_macro(id) { return None; } self.entry(id).ast.map(|ast| { let def_id = self.local_def_id(id); - let ast = ast.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)); + let body = ast.decode(self).body.decode(self); 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 { self.entry(id).ast.into_iter().flat_map(|ast| { ast.decode(self).nested_bodies.decode(self).map(|body| (body.id(), body)) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index ed1cff31f2f..f5fd7a152a8 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -36,7 +36,7 @@ use syntax::ast::{self, CRATE_NODE_ID}; use syntax::codemap::Spanned; use syntax::attr; use syntax::symbol::Symbol; -use syntax_pos; +use syntax_pos::{self, DUMMY_SP}; use rustc::hir::{self, PatKind}; use rustc::hir::itemlikevisit::ItemLikeVisitor; @@ -264,7 +264,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { discr: variant.discr, evaluated_discr: match variant.discr { 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 }, diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 3256bdf9c25..fa8d7ffccde 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -209,9 +209,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}", num_enum_variants, values, variants); - let repr_hints = tcx.lookup_repr_hints(adt_def.did); - let repr_type = tcx.enum_repr_type(repr_hints.get(0)); - let discr_ty = repr_type.to_ty(tcx); + let discr_ty = adt_def.repr.discr_type().to_ty(tcx); let discr = self.temp(discr_ty); self.cfg.push_assign(block, source_info, &discr, Rvalue::Discriminant(lvalue.clone())); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 54a2c40322e..2d373ca7473 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -11,17 +11,6 @@ //! Conversion from AST representation of types to the ty.rs //! representation. The main routine here is `ast_ty_to_ty()`: each use //! 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_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` fn ast_ty_to_ty_cache(&self) -> &RefCell>>; - /// 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 /// the given id. fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) - -> Vec>; + -> ty::GenericPredicates<'tcx>; /// Return an (optional) substitution to convert bound type parameters that /// 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 default_needs_object_self = |p: &ty::TypeParameterDef| { 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 // that references self, in an object type. return true; @@ -329,7 +310,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { tcx.types.err } else { // 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 { // 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 // those that do. - self.ensure_super_predicates(binding.span, trait_ref.def_id()); - let candidates = traits::supertraits(tcx, trait_ref.clone()) .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> { 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 @@ -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, // most importantly, that the supertraits don't contain Self, // to avoid ICE-s. @@ -776,12 +752,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let tcx = self.tcx(); 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(); - - // Ensure the super predicates. - for b in &bounds { - self.ensure_super_predicates(span, b.def_id()); - } + .predicates.into_iter().filter_map(|p| p.to_opt_poly_trait_ref()).collect(); // Check that there is exactly one way to find an associated type with the // correct name. @@ -880,28 +851,20 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { (_, Def::SelfTy(Some(_), Some(impl_def_id))) => { // `Self` in an impl of a trait - we have a concrete self type and a // trait reference. - // FIXME: Self type is not always computed when we are here because type parameter - // bounds may affect Self type and have to be converted before it. - let trait_ref = if impl_def_id.is_local() { - tcx.maps.impl_trait_ref.borrow().get(&impl_def_id) - .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); + let trait_ref = match tcx.impl_trait_ref(impl_def_id) { + Some(trait_ref) => trait_ref, + None => { + // A cycle error occurred, most likely. + return (tcx.types.err, Def::Err); + } }; + let trait_ref = if let Some(free_substs) = self.get_free_substs() { trait_ref.subst(tcx, free_substs) } else { trait_ref }; - self.ensure_super_predicates(span, trait_ref.def_id); - let candidates = traits::supertraits(tcx, ty::Binder(trait_ref)) .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); 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() { ty.subst(tcx, free_substs) } else { @@ -1137,9 +1100,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { hir::TyTraitObject(ref bounds, ref lifetime) => { self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime) } - hir::TyImplTrait(ref bounds) => { - use collect::{compute_bounds, SizedByDefault}; - + hir::TyImplTrait(_) => { // Figure out if we can allow an `impl Trait` here, by walking up // to a `fn` or inherent `impl` method, going only through `Ty` // 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. if allow { let def_id = tcx.hir.local_def_id(ast_ty.id); - tcx.item_generics(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 + tcx.mk_anon(def_id, Substs::identity_for_item(tcx, def_id)) } else { span_err!(tcx.sess, ast_ty.span, E0562, "`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={:?})", 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 // bounds and see if we can derive region bounds from those. let derived_region_bounds = diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 62438d87d18..4085a171bbe 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -139,7 +139,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(import_id) = pick.import_id { let import_def_id = self.tcx.hir.local_def_id(import_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); @@ -333,7 +333,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(import_id) = pick.import_id { let import_def_id = self.tcx.hir.local_def_id(import_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(); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c6d3af547eb..68d8280d397 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -95,13 +95,14 @@ use rustc::ty::{self, Ty, TyCtxt, Visibility}; use rustc::ty::{MethodCall, MethodCallee}; use rustc::ty::adjustment; use rustc::ty::fold::{BottomUpFolder, TypeFoldable}; +use rustc::ty::maps::Providers; use rustc::ty::util::{Representability, IntTypeExt}; use require_c_abi_if_variadic; use session::{Session, CompileResult}; use TypeAndSubsts; use lint; 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::cmp; @@ -109,7 +110,6 @@ use std::mem::replace; use std::ops::{self, Deref}; use syntax::abi::Abi; use syntax::ast; -use syntax::attr; use syntax::codemap::{self, original_sp, Spanned}; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::ptr::P; @@ -174,16 +174,7 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // associated fresh inference variable. Writeback resolves these // variables to get the concrete type, which can be used to // deanonymize TyAnon, after typeck is done with all functions. - anon_types: RefCell>>, - - // Obligations which will have to be checked at the end of - // type-checking, after all functions have been inferred. - deferred_obligations: RefCell>>, - - // 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>, + anon_types: RefCell>>, } 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()), deferred_call_resolutions: RefCell::new(DefIdMap()), deferred_cast_checks: RefCell::new(Vec::new()), - anon_types: RefCell::new(DefIdMap()), - deferred_obligations: RefCell::new(Vec::new()), - used_trait_imports: RefCell::new(DefIdSet()), + anon_types: RefCell::new(NodeMap()), } } @@ -545,7 +534,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> { fn visit_ty(&mut self, t: &'tcx hir::Ty) { match t.node { 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) { match e.node { 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> { fn visit_item(&mut self, item: &'tcx hir::Item) { match item.node { - hir::ItemFn(ref decl, .., body_id) => { - check_bare_fn(self.tcx, &decl, body_id, item.id, item.span); + hir::ItemFn(..) => { + 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) { match trait_item.node { - hir::TraitItemKind::Const(_, Some(expr)) => { - check_const(self.tcx, expr, 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::Const(_, Some(_)) | + hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => { + self.tcx.item_tables(self.tcx.hir.local_def_id(trait_item.id)); } hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) | 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) { match impl_item.node { - hir::ImplItemKind::Const(_, expr) => { - check_const(self.tcx, expr, 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::Const(..) | + hir::ImplItemKind::Method(..) => { + self.tcx.item_tables(self.tcx.hir.local_def_id(impl_item.id)); } hir::ImplItemKind::Type(_) => { // 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(|| { let mut visit = CheckItemBodiesVisitor { tcx: tcx }; 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,38 +633,145 @@ pub fn check_drop_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult }) } -fn check_bare_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - decl: &'tcx hir::FnDecl, - body_id: hir::BodyId, - fn_id: ast::NodeId, - span: Span) { +pub fn provide(providers: &mut Providers) { + *providers = Providers { + typeck_tables, + closure_type, + 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 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. - let fn_scope = inh.tcx.region_maps.call_site_extent(fn_id, body_id.node_id); - let fn_sig = - fn_sig.subst(inh.tcx, &inh.parameter_environment.free_substs); - let fn_sig = - inh.tcx.liberate_late_bound_regions(fn_scope, &fn_sig); - let fn_sig = - inh.normalize_associated_types_in(body.value.span, body_id.node_id, &fn_sig); + // Compute the fty from point of view of inside fn. + let fn_scope = inh.tcx.region_maps.call_site_extent(id, body_id.node_id); + let fn_sig = + fn_sig.subst(inh.tcx, &inh.parameter_environment.free_substs); + let fn_sig = + inh.tcx.liberate_late_bound_regions(fn_scope, &fn_sig); + let 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.closure_analyze(body); fcx.select_obligations_where_possible(); 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); - fcx.resolve_type_vars_in_body(body); - }); + if fn_decl.is_some() { + 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) { @@ -772,7 +844,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { _: 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 /// 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); 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); } } @@ -853,8 +925,10 @@ pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item let _indenter = indenter(); match it.node { // Consts can play a role in type-checking, so they are included here. - hir::ItemStatic(.., e) | - hir::ItemConst(_, e) => check_const(tcx, e, it.id), + hir::ItemStatic(..) | + hir::ItemConst(..) => { + tcx.item_tables(tcx.hir.local_def_id(it.id)); + } hir::ItemEnum(ref enum_definition, _) => { check_enum_variants(tcx, 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 /// identifies types that contain themselves without indirection through a /// 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], id: ast::NodeId) { 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!( tcx.sess, sp, E0084, "unsupported representation for zero-variant enum") @@ -1303,7 +1341,7 @@ pub fn check_enum_variants<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .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 !tcx.sess.features.borrow().i128_type { 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 { 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 = Vec::new(); for (discr, v) in def.discriminants(tcx).zip(vs) { // 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 } - 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>> { Some(&self.parameter_environment.free_substs) } fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) - -> Vec> + -> ty::GenericPredicates<'tcx> { let tcx = self.tcx; let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); @@ -1374,14 +1401,17 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { let item_def_id = tcx.hir.local_def_id(item_id); let generics = tcx.item_generics(item_def_id); let index = generics.type_param_to_index[&def_id.index]; - self.parameter_environment.caller_bounds.iter().filter(|predicate| { - match **predicate { - ty::Predicate::Trait(ref data) => { - data.0.self_ty().is_param(index) + ty::GenericPredicates { + parent: None, + predicates: self.parameter_environment.caller_bounds.iter().filter(|predicate| { + match **predicate { + ty::Predicate::Trait(ref data) => { + data.0.self_ty().is_param(index) + } + _ => false } - _ => false - } - }).cloned().collect() + }).cloned().collect() + } } fn re_infer(&self, span: Span, def: Option<&ty::RegionParameterDef>) @@ -1666,12 +1696,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let ty::TyAnon(def_id, substs) = ty.sty { // 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). - 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; } let span = self.tcx.def_span(def_id); 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 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(); - // 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) { Ok(()) => { } Err(errors) => { self.report_fulfillment_errors(&errors); } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index f7f004fbaef..4f0cfa8d014 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -14,7 +14,6 @@ use self::ResolveReason::*; use check::FnCtxt; -use hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee}; use rustc::ty::adjustment; use rustc::ty::fold::{TypeFolder,TypeFoldable}; @@ -34,7 +33,8 @@ use rustc::hir; // Entry point 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); 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_fru_field_types(); wbcx.visit_anon_types(); - wbcx.visit_deferred_obligations(item_id); wbcx.visit_type_nodes(); wbcx.visit_cast_types(); wbcx.visit_lints(); - let tables = self.tcx.alloc_tables(wbcx.tables); - 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(), + let used_trait_imports = mem::replace(&mut self.tables.borrow_mut().used_trait_imports, DefIdSet()); 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() { return } for (&id, closure_ty) in self.fcx.tables.borrow().closure_tys.iter() { let closure_ty = self.resolve(closure_ty, ResolvingClosure(id)); - let def_id = self.tcx().hir.local_def_id(id); - self.tcx().maps.closure_type.borrow_mut().insert(def_id, closure_ty); + self.tables.closure_tys.insert(id, closure_ty); } for (&id, &closure_kind) in self.fcx.tables.borrow().closure_kinds.iter() { - let def_id = self.tcx().hir.local_def_id(id); - self.tcx().maps.closure_kind.borrow_mut().insert(def_id, closure_kind); + self.tables.closure_kinds.insert(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); } - fn visit_anon_types(&self) { + fn visit_anon_types(&mut self) { if self.fcx.writeback_errors.get() { return } let gcx = self.tcx().global_tcx(); - for (&def_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() { - let reason = ResolvingAnonTy(def_id); + for (&node_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() { + let reason = ResolvingAnonTy(node_id); let inside_ty = self.resolve(&concrete_ty, reason); // 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) { for (&id, ty) in self.fcx.ast_ty_to_ty_cache.borrow().iter() { let ty = self.resolve(ty, ResolvingTyNode(id)); @@ -528,8 +511,7 @@ enum ResolveReason { ResolvingClosure(ast::NodeId), ResolvingFnSig(ast::NodeId), ResolvingFieldTypes(ast::NodeId), - ResolvingAnonTy(DefId), - ResolvingDeferredObligation(Span), + ResolvingAnonTy(ast::NodeId), ResolvingTyNode(ast::NodeId), } @@ -545,13 +527,10 @@ impl<'a, 'gcx, 'tcx> ResolveReason { ResolvingClosure(id) | ResolvingFnSig(id) | ResolvingFieldTypes(id) | - ResolvingTyNode(id) => { + ResolvingTyNode(id) | + ResolvingAnonTy(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(_) | ResolvingFieldTypes(_) | - ResolvingDeferredObligation(_) | ResolvingTyNode(_) => { // any failures here should also fail when // resolving the patterns, closure types, or diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index 0f992f75fce..3791079dc81 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -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); // 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); used_trait_imports.extend(imports); } else { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 68e42f5b27a..2a95f5f5d08 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -47,10 +47,6 @@ item, we may need to compute the *type scheme* or *trait definition* for other items. 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 parameter defaults are illegal even if those defaults are never 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::{ConstContext, report_const_eval_err}; 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::maps::Providers; use rustc::ty::util::IntTypeExt; @@ -80,6 +76,7 @@ use std::cell::RefCell; use std::collections::BTreeMap; use syntax::{abi, ast, attr}; +use syntax::codemap::Spanned; use syntax::symbol::{Symbol, keywords}; 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) { *providers = Providers { + ty, generics, + predicates, + super_predicates, + type_param_predicates, trait_def, adt_def, + impl_trait_ref, ..*providers }; } @@ -190,7 +192,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> { for param in &generics.ty_params { if param.default.is_some() { 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); @@ -200,7 +202,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> { if let hir::ExprClosure(..) = expr.node { let def_id = self.tcx.hir.local_def_id(expr.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); } @@ -209,6 +211,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> { if let hir::TyImplTrait(..) = ty.node { let def_id = self.tcx.hir.local_def_id(ty.id); self.tcx.item_generics(def_id); + self.tcx.item_predicates(def_id); } 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 } - 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, span: Span, def_id: DefId) - -> Vec> + -> ty::GenericPredicates<'tcx> { - self.tcx.cycle_check(span, - ty::maps::Query::type_param_predicates((self.item_def_id, def_id)), - || get_type_parameter_bounds(self.tcx, self.item_def_id, def_id)) + self.tcx.maps.type_param_predicates(self.tcx, span, (self.item_def_id, def_id)) } fn get_free_substs(&self) -> Option<&Substs<'tcx>> { @@ -343,89 +316,91 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { } } - fn get_type_parameter_bounds<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - item_def_id: DefId, - def_id: DefId) - -> Vec> - { - use rustc::hir::map::*; - use rustc::hir::*; +fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + (item_def_id, def_id): (DefId, DefId)) + -> ty::GenericPredicates<'tcx> { + use rustc::hir::map::*; + use rustc::hir::*; - // In the AST, bounds can derive from two places. Either - // written inline like `` or in a where clause like - // `where T:Foo`. + // In the AST, bounds can derive from two places. Either + // written inline like `` or in a where clause like + // `where T:Foo`. - let param_id = tcx.hir.as_local_node_id(def_id).unwrap(); - let param_owner = tcx.hir.ty_param_owner(param_id); - let param_owner_def_id = tcx.hir.local_def_id(param_owner); - let generics = tcx.item_generics(param_owner_def_id); - let index = generics.type_param_to_index[&def_id.index]; - let ty = tcx.mk_param(index, tcx.hir.ty_param_name(param_id)); + let param_id = tcx.hir.as_local_node_id(def_id).unwrap(); + let param_owner = tcx.hir.ty_param_owner(param_id); + let param_owner_def_id = tcx.hir.local_def_id(param_owner); + let generics = tcx.item_generics(param_owner_def_id); + let index = generics.type_param_to_index[&def_id.index]; + let ty = tcx.mk_param(index, tcx.hir.ty_param_name(param_id)); - // Don't look for bounds where the type parameter isn't in scope. - let parent = if item_def_id == param_owner_def_id { - None - } else { - tcx.item_generics(item_def_id).parent - }; + // Don't look for bounds where the type parameter isn't in scope. + let parent = if item_def_id == param_owner_def_id { + None + } else { + tcx.item_generics(item_def_id).parent + }; - let mut results = parent.map_or(vec![], |parent| { - let icx = ItemCtxt::new(tcx, parent); - icx.get_type_parameter_bounds(DUMMY_SP, def_id) - }); + let mut result = parent.map_or(ty::GenericPredicates { + parent: None, + predicates: vec![] + }, |parent| { + let icx = ItemCtxt::new(tcx, parent); + icx.get_type_parameter_bounds(DUMMY_SP, def_id) + }); - let item_node_id = tcx.hir.as_local_node_id(item_def_id).unwrap(); - let ast_generics = match tcx.hir.get(item_node_id) { - NodeTraitItem(item) => { - match item.node { - TraitItemKind::Method(ref sig, _) => &sig.generics, - _ => return results - } + let item_node_id = tcx.hir.as_local_node_id(item_def_id).unwrap(); + let ast_generics = match tcx.hir.get(item_node_id) { + NodeTraitItem(item) => { + match item.node { + TraitItemKind::Method(ref sig, _) => &sig.generics, + _ => return result } + } - NodeImplItem(item) => { - match item.node { - ImplItemKind::Method(ref sig, _) => &sig.generics, - _ => return results - } + NodeImplItem(item) => { + match item.node { + ImplItemKind::Method(ref sig, _) => &sig.generics, + _ => return result } + } - 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, ..) => { - // Implied `Self: Trait` and supertrait bounds. - if param_id == item_node_id { - results.push(ty::TraitRef { - def_id: item_def_id, - substs: Substs::identity_for_item(tcx, item_def_id) - }.to_predicate()); - } - 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, ..) => { + // Implied `Self: Trait` and supertrait bounds. + if param_id == item_node_id { + result.predicates.push(ty::TraitRef { + def_id: item_def_id, + substs: Substs::identity_for_item(tcx, item_def_id) + }.to_predicate()); } - _ => return results + generics } + _ => return result } + } - NodeForeignItem(item) => { - match item.node { - ForeignItemFn(_, _, ref generics) => generics, - _ => return results - } + NodeForeignItem(item) => { + match item.node { + ForeignItemFn(_, _, ref generics) => generics, + _ => return result } + } - _ => return results - }; + _ => return result + }; - let icx = ItemCtxt::new(tcx, item_def_id); - results.extend(icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty)); - results - } + let icx = ItemCtxt::new(tcx, item_def_id); + result.predicates.extend( + icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty)); + result +} impl<'a, 'tcx> ItemCtxt<'a, 'tcx> { /// Find bounds from hir::Generics. This requires scanning through the @@ -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>) -{ - 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, span: Span, 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) { debug!("convert: item {} with id {}", it.name, it.id); let def_id = tcx.hir.local_def_id(it.id); - let icx = ItemCtxt::new(tcx, def_id); match it.node { // These don't define types. hir::ItemExternCrate(_) | hir::ItemUse(..) | hir::ItemMod(_) => { } hir::ItemForeignMod(ref foreign_mod) => { 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, _) => { tcx.item_generics(def_id); - predicates_of_item(tcx, it); - let ty = type_of_def_id(tcx, def_id); - convert_enum_variant_types(tcx, - tcx.lookup_adt_def(tcx.hir.local_def_id(it.id)), - ty, - &enum_definition.variants); + tcx.item_type(def_id); + tcx.item_predicates(def_id); + convert_enum_variant_types(tcx, def_id, &enum_definition.variants); }, - hir::ItemDefaultImpl(_, ref ast_trait_ref) => { - let trait_ref = - AstConv::instantiate_mono_trait_ref(&icx, - ast_trait_ref, - tcx.mk_self_type()); - - 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::ItemDefaultImpl(..) => { + if let Some(trait_ref) = tcx.impl_trait_ref(def_id) { + tcx.record_trait_has_default_impl(trait_ref.def_id); + } } - hir::ItemImpl(.., ref opt_trait_ref, _, _) => { + hir::ItemImpl(..) => { tcx.item_generics(def_id); - let selfty = type_of_def_id(tcx, def_id); - - let trait_ref = opt_trait_ref.as_ref().map(|ast_trait_ref| { - 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); + tcx.item_type(def_id); + tcx.impl_trait_ref(def_id); + tcx.item_predicates(def_id); }, hir::ItemTrait(..) => { tcx.item_generics(def_id); tcx.lookup_trait_def(def_id); - icx.ensure_super_predicates(it.span, def_id); - predicates_of_item(tcx, it); + tcx.maps.super_predicates(tcx, it.span, def_id); + tcx.item_predicates(def_id); }, hir::ItemStruct(ref struct_def, _) | hir::ItemUnion(ref struct_def, _) => { tcx.item_generics(def_id); - predicates_of_item(tcx, it); - let ty = type_of_def_id(tcx, def_id); + tcx.item_type(def_id); + tcx.item_predicates(def_id); - let variant = tcx.lookup_adt_def(def_id).struct_variant(); - - for (f, ty_f) in struct_def.fields().iter().zip(variant.fields.iter()) { - convert_field(tcx, f, ty_f) + for f in struct_def.fields() { + 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); } 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) => { ensure_no_ty_param_bounds(tcx, it.span, generics, "type"); tcx.item_generics(def_id); - predicates_of_item(tcx, it); - type_of_def_id(tcx, def_id); + tcx.item_type(def_id); + tcx.item_predicates(def_id); }, _ => { tcx.item_generics(def_id); - predicates_of_item(tcx, it); - type_of_def_id(tcx, def_id); + tcx.item_type(def_id); + tcx.item_predicates(def_id); }, } } 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); + tcx.item_generics(def_id); + match trait_item.node { - hir::TraitItemKind::Const(ref ty, _) => { - tcx.item_generics(def_id); - let ty = ItemCtxt::new(tcx, def_id).to_ty(&ty); - convert_associated_const(tcx, - TraitContainer(trait_def_id), - trait_item.id, - ty); + hir::TraitItemKind::Const(..) | + hir::TraitItemKind::Type(_, Some(_)) | + hir::TraitItemKind::Method(..) => { + tcx.item_type(def_id); } - hir::TraitItemKind::Type(_, ref opt_ty) => { - tcx.item_generics(def_id); + hir::TraitItemKind::Type(_, None) => {} + }; - let typ = opt_ty.as_ref().map(|ty| ItemCtxt::new(tcx, def_id).to_ty(&ty)); - - convert_associated_type(tcx, TraitContainer(trait_def_id), trait_item.id, typ); - } - - hir::TraitItemKind::Method(ref sig, _) => { - convert_method(tcx, trait_item.id, sig); - } - } + tcx.item_predicates(def_id); } 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); - match impl_item.node { - hir::ImplItemKind::Const(ref ty, _) => { - tcx.item_generics(def_id); - let ty = ItemCtxt::new(tcx, def_id).to_ty(&ty); - convert_associated_const(tcx, - 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); - } - } + tcx.item_generics(def_id); + tcx.item_type(def_id); + tcx.item_predicates(def_id); } fn convert_variant_ctor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - ctor_id: ast::NodeId, - variant: &'tcx ty::VariantDef, - ty: Ty<'tcx>) { + ctor_id: ast::NodeId) { let def_id = tcx.hir.local_def_id(ctor_id); tcx.item_generics(def_id); - let ctor_ty = match variant.ctor_kind { - CtorKind::Fictive | CtorKind::Const => ty, - 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![] - }); + tcx.item_type(def_id); + tcx.item_predicates(def_id); } fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def: &'tcx ty::AdtDef, - ty: Ty<'tcx>, + def_id: DefId, variants: &[hir::Variant]) { - let repr_hints = tcx.lookup_repr_hints(def.did); - let repr_type = tcx.enum_repr_type(repr_hints.get(0)); + let def = tcx.lookup_adt_def(def_id); + let repr_type = def.repr.discr_type(); let initial = repr_type.initial_discriminant(tcx); let mut prev_discr = None::; // 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()); 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); - tcx.maps.monomorphic_const_eval.borrow_mut() - .insert(expr_did, result.map(ConstVal::Integral)); + let result = tcx.maps.monomorphic_const_eval.memoize(expr_did, || { + 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) { Some(discr) } else { @@ -784,13 +632,16 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, None }.unwrap_or(wrapped_discr)); - for (f, ty_f) in variant.node.data.fields().iter().zip(ty_variant.fields.iter()) { - convert_field(tcx, f, ty_f) + for f in variant.node.data.fields() { + 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 // 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, // which will, in turn, reach indirect supertraits. 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 { @@ -1212,121 +1063,179 @@ fn generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }) } -fn type_of_def_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> 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::*; +fn ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> Ty<'tcx> { + use rustc::hir::map::*; + use rustc::hir::*; - // Alway bring in generics, as computing the type needs them. - tcx.item_generics(def_id); + let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); - let icx = ItemCtxt::new(tcx, def_id); + let icx = ItemCtxt::new(tcx, def_id); - match tcx.hir.get(node_id) { - NodeItem(item) => { - match item.node { - ItemStatic(ref t, ..) | ItemConst(ref t, _) | - ItemTy(ref t, _) | ItemImpl(.., ref t, _) => { - icx.to_ty(t) - } - ItemFn(ref decl, unsafety, _, abi, _, _) => { - let tofd = AstConv::ty_of_fn(&icx, unsafety, abi, &decl); - let substs = Substs::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id, substs, tofd) - } - ItemEnum(..) | - ItemStruct(..) | - ItemUnion(..) => { - let def = tcx.lookup_adt_def(def_id); - let substs = Substs::identity_for_item(tcx, def_id); - tcx.mk_adt(def, substs) - } - ItemDefaultImpl(..) | - ItemTrait(..) | - ItemMod(..) | - ItemForeignMod(..) | - ItemExternCrate(..) | - ItemUse(..) => { - span_bug!( - item.span, - "compute_type_of_item: unexpected item type: {:?}", - item.node); - } + 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) } - } - NodeForeignItem(foreign_item) => { - let abi = tcx.hir.get_foreign_abi(node_id); - - match foreign_item.node { - ForeignItemFn(ref fn_decl, _, _) => { - compute_type_of_foreign_fn_decl(tcx, def_id, fn_decl, abi) - } - ForeignItemStatic(ref t, _) => icx.to_ty(t) + TraitItemKind::Const(ref ty, _) | + TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty), + TraitItemKind::Type(_, None) => { + span_bug!(item.span, "associated type missing default"); } } - NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => { - tcx.mk_closure(def_id, Substs::for_item( - tcx, def_id, - |def, _| { - let region = def.to_early_bound_region_data(); - tcx.mk_region(ty::ReEarlyBound(region)) - }, - |def, _| tcx.mk_param_from_def(def) - )) - } - NodeTyParam(&hir::TyParam { default: Some(ref ty), .. }) => { - icx.to_ty(ty) - } - x => { - bug!("unexpected sort of node in type_of_def_id(): {:?}", x); - } } - }) + + 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) => { + match item.node { + ItemStatic(ref t, ..) | ItemConst(ref t, _) | + ItemTy(ref t, _) | ItemImpl(.., ref t, _) => { + icx.to_ty(t) + } + ItemFn(ref decl, unsafety, _, abi, _, _) => { + let tofd = AstConv::ty_of_fn(&icx, unsafety, abi, &decl); + let substs = Substs::identity_for_item(tcx, def_id); + tcx.mk_fn_def(def_id, substs, tofd) + } + ItemEnum(..) | + ItemStruct(..) | + ItemUnion(..) => { + let def = tcx.lookup_adt_def(def_id); + let substs = Substs::identity_for_item(tcx, def_id); + tcx.mk_adt(def, substs) + } + ItemDefaultImpl(..) | + ItemTrait(..) | + ItemMod(..) | + ItemForeignMod(..) | + ItemExternCrate(..) | + ItemUse(..) => { + span_bug!( + item.span, + "compute_type_of_item: unexpected item type: {:?}", + item.node); + } + } + } + + NodeForeignItem(foreign_item) => { + let abi = tcx.hir.get_foreign_abi(node_id); + + match foreign_item.node { + ForeignItemFn(ref fn_decl, _, _) => { + compute_type_of_foreign_fn_decl(tcx, def_id, fn_decl, abi) + } + 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(..), .. }) => { + tcx.mk_closure(def_id, Substs::for_item( + tcx, def_id, + |def, _| { + let region = def.to_early_bound_region_data(); + tcx.mk_region(ty::ReEarlyBound(region)) + }, + |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), .. }) => { + 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 => { + bug!("unexpected sort of node in type_of_def_id(): {:?}", x); + } + } } -fn predicates_of_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) { - let def_id = tcx.hir.local_def_id(it.id); +fn impl_trait_ref<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> Option> { + let icx = ItemCtxt::new(tcx, def_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); + 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!() + } } // 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)) } -fn ty_generic_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - ast_generics: &hir::Generics) { +fn predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> 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 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 parent_count = generics.parent_count() as u32; let has_own_self = generics.has_self && parent_count == 0; 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`) // 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 @@ -1543,16 +1502,18 @@ fn ty_generic_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // before uses of `U`. This avoids false ambiguity errors // in trait checking. See `setup_constraining_predicates` // 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, 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, predicates: predicates - }); + } } pub enum SizedByDefault { Yes, No, } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 8e6e83bf301..0f425baec10 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -287,6 +287,7 @@ fn check_for_entry_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { pub fn provide(providers: &mut Providers) { collect::provide(providers); + check::provide(providers); } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 455a6a0fb32..096657a6e7a 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -909,25 +909,12 @@ fn int_type_of_word(s: &str) -> Option { #[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)] pub enum ReprAttr { - ReprAny, ReprInt(IntType), ReprExtern, ReprPacked, 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)] pub enum IntType { SignedInt(ast::IntTy), @@ -942,16 +929,6 @@ impl IntType { 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 { diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index ce64aef516f..fe492bd7fc8 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -773,7 +773,7 @@ fn find_repr_type_name(diagnostic: &Handler, type_attrs: &[ast::Attribute]) -> & for a in type_attrs { for r in &attr::find_repr_attrs(diagnostic, a) { repr_type_name = match *r { - attr::ReprAny | attr::ReprPacked | attr::ReprSimd => continue, + attr::ReprPacked | attr::ReprSimd => continue, attr::ReprExtern => "i32", attr::ReprInt(attr::SignedInt(ast::IntTy::Is)) => "isize", diff --git a/src/test/compile-fail/cycle-trait-default-type-trait.rs b/src/test/compile-fail/cycle-trait-default-type-trait.rs index 6825572b26c..e6caeb34a8c 100644 --- a/src/test/compile-fail/cycle-trait-default-type-trait.rs +++ b/src/test/compile-fail/cycle-trait-default-type-trait.rs @@ -13,7 +13,6 @@ trait Foo> { //~^ ERROR unsupported cyclic reference - //~| ERROR unsupported cyclic reference } fn main() { } diff --git a/src/test/compile-fail/impl-trait/auto-trait-leak.rs b/src/test/compile-fail/impl-trait/auto-trait-leak.rs index f055d20e134..13e53cab172 100644 --- a/src/test/compile-fail/impl-trait/auto-trait-leak.rs +++ b/src/test/compile-fail/impl-trait/auto-trait-leak.rs @@ -52,23 +52,20 @@ fn after() -> impl Fn(i32) { // independently resolved and only require the concrete // return type, which can't depend on the obligation. 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()); - //~^ ERROR the trait bound `std::rc::Rc: std::marker::Send` is not satisfied - //~| NOTE the trait `std::marker::Send` is not implemented for `std::rc::Rc` - //~| NOTE `std::rc::Rc` 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)) } fn cycle2() -> impl Clone { + //~^ NOTE ...which then requires processing `cycle2::{{impl-Trait}}`... + //~| NOTE ...which then requires processing `cycle2`... send(cycle1().clone()); - //~^ ERROR the trait bound `std::rc::Rc>: std::marker::Send` is not satisfied - //~| NOTE the trait `std::marker::Send` is not implemented for `std::rc::Rc>` - //~| NOTE `std::rc::Rc>` 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")) } diff --git a/src/test/compile-fail/impl-trait/equality.rs b/src/test/compile-fail/impl-trait/equality.rs index 59ad1132b35..36df4f0eb4d 100644 --- a/src/test/compile-fail/impl-trait/equality.rs +++ b/src/test/compile-fail/impl-trait/equality.rs @@ -49,17 +49,6 @@ impl Leak for i32 { fn leak(self) -> i32 { self } } -trait CheckIfSend: Sized { - type T: Default; - fn check(self) -> Self::T { Default::default() } -} -impl CheckIfSend for T { - default type T = (); -} -impl CheckIfSend for T { - type T = bool; -} - fn main() { let _: u32 = hide(0_u32); //~^ ERROR mismatched types @@ -73,12 +62,6 @@ fn main() { //~| found type `::T` //~| expected i32, found associated type - let _: bool = CheckIfSend::check(hide(0_i32)); - //~^ ERROR mismatched types - //~| expected type `bool` - //~| found type `::T` - //~| expected bool, found associated type - let mut x = (hide(0_u32), hide(0_i32)); x = (x.1, //~^ ERROR mismatched types diff --git a/src/test/compile-fail/resolve-self-in-impl.rs b/src/test/compile-fail/resolve-self-in-impl.rs index 7a5ef3540e9..710d8e11ff0 100644 --- a/src/test/compile-fail/resolve-self-in-impl.rs +++ b/src/test/compile-fail/resolve-self-in-impl.rs @@ -26,6 +26,6 @@ impl Tr for Self {} //~ ERROR unsupported cyclic reference between types/traits impl Tr for S {} //~ ERROR unsupported cyclic reference between types/traits detected impl Self {} //~ ERROR unsupported cyclic reference between types/traits detected impl S {} //~ ERROR unsupported cyclic reference between types/traits detected -impl Tr for S {} //~ ERROR `Self` type is used before it's determined +impl Tr for S {} //~ ERROR unsupported cyclic reference between types/traits detected fn main() {} diff --git a/src/test/incremental/hashes/enum_defs.rs b/src/test/incremental/hashes/enum_defs.rs index da3a953d11e..048ccb529a2 100644 --- a/src/test/incremental/hashes/enum_defs.rs +++ b/src/test/incremental/hashes/enum_defs.rs @@ -112,10 +112,13 @@ enum EnumChangeValueCStyleVariant0 { #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_dirty(label="HirBody", cfg="cfail2")] #[rustc_clean(label="HirBody", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumChangeValueCStyleVariant0 { Variant1, + + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] Variant2 = 22, } diff --git a/src/test/run-pass/impl-trait/auto-trait-leak.rs b/src/test/run-pass/impl-trait/auto-trait-leak.rs index c1201e7fa4f..011d910c5a5 100644 --- a/src/test/run-pass/impl-trait/auto-trait-leak.rs +++ b/src/test/run-pass/impl-trait/auto-trait-leak.rs @@ -29,16 +29,3 @@ fn after() -> impl FnMut(i32) { let mut p = Box::new(0); 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") -} diff --git a/src/test/run-pass/impl-trait/equality.rs b/src/test/run-pass/impl-trait/equality.rs index 72b0e588ff4..ceed454e5ad 100644 --- a/src/test/run-pass/impl-trait/equality.rs +++ b/src/test/run-pass/impl-trait/equality.rs @@ -28,6 +28,17 @@ impl Leak for T { fn leak(self) -> T { self } } +trait CheckIfSend: Sized { + type T: Default; + fn check(self) -> Self::T { Default::default() } +} +impl CheckIfSend for T { + default type T = (); +} +impl CheckIfSend for T { + type T = bool; +} + fn lucky_seven() -> impl Fn(usize) -> u8 { let a = [1, 2, 3, 4, 5, 6, 7]; move |i| a[i] @@ -40,4 +51,6 @@ fn main() { assert_eq!(std::mem::size_of_val(&lucky_seven()), 7); assert_eq!(Leak::::leak(hide(5_i32)), 5_i32); + + assert_eq!(CheckIfSend::check(hide(0_i32)), false); }