From 28f1cf4262074dfdb5f83a24cf81dbabf37a1d94 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 11 Feb 2017 19:26:13 +0200 Subject: [PATCH] rustc_typeck: don't use Result for get_type_parameter_bounds and ensure_super_predicates. --- src/librustc/dep_graph/dep_node.rs | 4 + src/librustc/diagnostics.rs | 17 ++ src/librustc/hir/map/mod.rs | 24 ++ src/librustc/lib.rs | 1 + src/librustc/ty/maps.rs | 97 ++++++- src/librustc/ty/mod.rs | 2 +- src/librustc_typeck/astconv.rs | 56 ++-- src/librustc_typeck/check/mod.rs | 43 ++- src/librustc_typeck/collect.rs | 255 ++++++------------ src/librustc_typeck/diagnostics.rs | 17 -- src/librustc_typeck/lib.rs | 25 -- .../cycle-projection-based-on-where-clause.rs | 1 + .../cycle-trait-supertrait-indirect.rs | 6 +- src/test/compile-fail/issue-12511.rs | 7 +- src/test/compile-fail/issue-20772.rs | 1 + src/test/compile-fail/issue-21177.rs | 3 +- 16 files changed, 265 insertions(+), 294 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 8da032f5935..769c08a81ef 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -109,6 +109,7 @@ pub enum DepNode { // predicates for an item wind up in `ItemSignature`). AssociatedItems(D), ItemSignature(D), + TypeParamPredicates((D, D)), SizedConstraint(D), AssociatedItemDefIds(D), InherentImpls(D), @@ -259,6 +260,9 @@ impl DepNode { TransInlinedItem(ref d) => op(d).map(TransInlinedItem), AssociatedItems(ref d) => op(d).map(AssociatedItems), ItemSignature(ref d) => op(d).map(ItemSignature), + TypeParamPredicates((ref item, ref param)) => { + Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param))))) + } SizedConstraint(ref d) => op(d).map(SizedConstraint), AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds), InherentImpls(ref d) => op(d).map(InherentImpls), diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index cf51dad5142..458a774c956 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1390,6 +1390,23 @@ error. To resolve it, add an `else` block having the same type as the `if` block. "##, +E0391: r##" +This error indicates that some types or traits depend on each other +and therefore cannot be constructed. + +The following example contains a circular dependency between two traits: + +```compile_fail,E0391 +trait FirstTrait : SecondTrait { + +} + +trait SecondTrait : FirstTrait { + +} +``` +"##, + E0398: r##" In Rust 1.3, the default object lifetime bounds are expected to change, as described in RFC #1156 [1]. You are getting a warning because the compiler diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 9f31b5b456b..13b786541c5 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -437,6 +437,30 @@ impl<'hir> Map<'hir> { self.local_def_id(self.body_owner(id)) } + pub fn ty_param_owner(&self, id: NodeId) -> NodeId { + match self.get(id) { + NodeItem(&Item { node: ItemTrait(..), .. }) => id, + NodeTyParam(_) => self.get_parent_node(id), + _ => { + bug!("ty_param_owner: {} not a type parameter", + self.node_to_string(id)) + } + } + } + + pub fn ty_param_name(&self, id: NodeId) -> Name { + match self.get(id) { + NodeItem(&Item { node: ItemTrait(..), .. }) => { + keywords::SelfType.name() + } + NodeTyParam(tp) => tp.name, + _ => { + bug!("ty_param_name: {} not a type parameter", + self.node_to_string(id)) + } + } + } + /// Get the attributes on the krate. This is preferable to /// invoking `krate.attrs` because it registers a tighter /// dep-graph access. diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index d144f7575a2..60d03ccfe24 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -39,6 +39,7 @@ #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(slice_patterns)] +#![feature(specialization)] #![feature(staged_api)] #![feature(unboxed_closures)] diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index aeb7a207c44..dc87bb43c26 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -20,6 +20,7 @@ use rustc_data_structures::indexed_vec::IndexVec; use std::cell::RefCell; use std::rc::Rc; use syntax::attr; +use syntax_pos::Span; trait Key { fn map_crate(&self) -> CrateNum; @@ -31,13 +32,105 @@ impl Key for DefId { } } +impl Key for (DefId, DefId) { + fn map_crate(&self) -> CrateNum { + self.0.krate + } +} + +trait Value<'tcx>: Sized { + fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self; +} + +impl<'tcx, T> Value<'tcx> for T { + default fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> T { + tcx.sess.abort_if_errors(); + bug!("Value::from_cycle_error called without errors"); + } +} + +impl<'tcx, T: Default> Value<'tcx> for T { + default fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> T { + T::default() + } +} + +impl<'tcx> Value<'tcx> for Ty<'tcx> { + fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { + tcx.types.err + } +} + +impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { + fn report_cycle(self, span: Span, cycle: &[(Span, Query)]) { + assert!(!cycle.is_empty()); + + let mut err = struct_span_err!(self.sess, span, E0391, + "unsupported cyclic reference between types/traits detected"); + err.span_label(span, &format!("cyclic reference")); + + err.span_note(cycle[0].0, &format!("the cycle begins when {}...", + cycle[0].1.describe(self))); + + for &(span, ref query) in &cycle[1..] { + err.span_note(span, &format!("...which then requires {}...", + query.describe(self))); + } + + err.note(&format!("...which then again requires {}, completing the cycle.", + cycle[0].1.describe(self))); + + err.emit(); + } + + pub fn cycle_check(self, span: Span, query: Query, compute: F) -> R + where F: FnOnce() -> R + { + { + let mut stack = self.maps.query_stack.borrow_mut(); + if let Some((i, _)) = stack.iter().enumerate().rev() + .find(|&(_, &(_, ref q))| *q == query) { + let cycle = &stack[i..]; + self.report_cycle(span, cycle); + return R::from_cycle_error(self.global_tcx()); + } + stack.push((span, query)); + } + + let result = compute(); + + self.maps.query_stack.borrow_mut().pop(); + result + } +} + +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) + } + } +} + macro_rules! define_maps { (<$tcx:tt> $($(#[$attr:meta])* pub $name:ident: $node:ident($K:ty) -> $V:ty),*) => { pub struct Maps<$tcx> { providers: IndexVec>, - pub query_stack: RefCell>, + pub query_stack: RefCell>, $($(#[$attr])* pub $name: RefCell>>),* } @@ -129,7 +222,7 @@ define_maps! { <'tcx> /// To avoid cycles within the predicates of a single item we compute /// per-type-parameter predicates for resolving `T::AssocTy`. - pub type_param_predicates: ItemSignature(DefId) + pub type_param_predicates: TypeParamPredicates((DefId, DefId)) -> ty::GenericPredicates<'tcx>, pub trait_def: ItemSignature(DefId) -> &'tcx ty::TraitDef, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 97476489a8a..9d4e17138a0 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -669,7 +669,7 @@ impl Generics { } /// Bounds on generics. -#[derive(Clone)] +#[derive(Clone, Default)] pub struct GenericPredicates<'tcx> { pub parent: Option, pub predicates: Vec>, diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index cf93ef21f5d..ef0dcd4c774 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -64,13 +64,12 @@ pub trait AstConv<'gcx, '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) - -> Result<(), ErrorReported>; + 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: ast::NodeId) - -> Result>, ErrorReported>; + fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) + -> Vec>; /// Return an (optional) substitution to convert bound type parameters that /// are in scope into free ones. This function should only return Some @@ -599,7 +598,7 @@ 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())?; + self.ensure_super_predicates(binding.span, trait_ref.def_id()); let candidates = traits::supertraits(tcx, trait_ref.clone()) @@ -685,10 +684,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { }) }); - // ensure the super predicates and stop if we encountered an error - if self.ensure_super_predicates(span, principal.def_id()).is_err() { - return tcx.types.err; - } + // 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, @@ -774,29 +771,23 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } // Search for a bound on a type parameter which includes the associated item - // given by assoc_name. ty_param_node_id is the node id for the type parameter - // (which might be `Self`, but only if it is the `Self` of a trait, not an - // impl). This function will fail if there are no suitable bounds or there is + // given by `assoc_name`. `ty_param_def_id` is the `DefId` for the type parameter + // This function will fail if there are no suitable bounds or there is // any ambiguity. fn find_bound_for_assoc_item(&self, - ty_param_node_id: ast::NodeId, - ty_param_name: ast::Name, + ty_param_def_id: DefId, assoc_name: ast::Name, span: Span) -> Result, ErrorReported> { let tcx = self.tcx(); - let bounds = match self.get_type_parameter_bounds(span, ty_param_node_id) { - Ok(v) => v, - Err(ErrorReported) => { - return Err(ErrorReported); - } - }; + 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 and stop if we encountered an error. - if bounds.iter().any(|b| self.ensure_super_predicates(span, b.def_id()).is_err()) { - return Err(ErrorReported); + // Ensure the super predicates. + for b in &bounds { + self.ensure_super_predicates(span, b.def_id()); } // Check that there is exactly one way to find an associated type with the @@ -805,8 +796,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { traits::transitive_bounds(tcx, &bounds) .filter(|b| self.trait_defines_associated_type_named(b.def_id(), assoc_name)); + let param_node_id = tcx.hir.as_local_node_id(ty_param_def_id).unwrap(); + let param_name = tcx.hir.ty_param_name(param_node_id); self.one_bound_for_assoc_type(suitable_bounds, - &ty_param_name.as_str(), + ¶m_name.as_str(), &assoc_name.as_str(), span) } @@ -914,9 +907,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { trait_ref }; - if self.ensure_super_predicates(span, trait_ref.def_id).is_err() { - return (tcx.types.err, Def::Err); - } + self.ensure_super_predicates(span, trait_ref.def_id); let candidates = traits::supertraits(tcx, ty::Binder(trait_ref)) @@ -933,12 +924,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } (&ty::TyParam(_), Def::SelfTy(Some(param_did), None)) | (&ty::TyParam(_), Def::TyParam(param_did)) => { - let param_node_id = tcx.hir.as_local_node_id(param_did).unwrap(); - let param_name = ::ty_param_name(tcx, param_node_id); - match self.find_bound_for_assoc_item(param_node_id, - param_name, - assoc_name, - span) { + match self.find_bound_for_assoc_item(param_did, assoc_name, span) { Ok(bound) => bound, Err(ErrorReported) => return (tcx.types.err, Def::Err), } @@ -1375,9 +1361,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { existential_predicates); if let Some(principal) = existential_predicates.principal() { - if let Err(ErrorReported) = self.ensure_super_predicates(span, principal.def_id()) { - return Some(tcx.mk_region(ty::ReStatic)); - } + self.ensure_super_predicates(span, principal.def_id()); } // No explicit region bound specified. Therefore, examine trait diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d52516e0ae5..d2cd766fdf0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -91,7 +91,7 @@ use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; use rustc::ty::{ParamTy, ParameterEnvironment}; use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue}; -use rustc::ty::{self, Ty, TyCtxt, Visibility, ToPolyTraitRef}; +use rustc::ty::{self, Ty, TyCtxt, Visibility}; use rustc::ty::{MethodCall, MethodCallee}; use rustc::ty::adjustment; use rustc::ty::fold::{BottomUpFolder, TypeFoldable}; @@ -1366,44 +1366,31 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { self.tcx().lookup_trait_def(id) } - fn ensure_super_predicates(&self, _: Span, _: DefId) -> Result<(), ErrorReported> { + fn ensure_super_predicates(&self, _: Span, _: DefId) { // all super predicates are ensured during collect pass - Ok(()) } fn get_free_substs(&self) -> Option<&Substs<'tcx>> { Some(&self.parameter_environment.free_substs) } - fn get_type_parameter_bounds(&self, - _: Span, - node_id: ast::NodeId) - -> Result>, ErrorReported> + fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) + -> Vec> { let tcx = self.tcx; - let item_id = ::ty_param_owner(tcx, node_id); + let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); + let item_id = tcx.hir.ty_param_owner(node_id); 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[&tcx.hir.local_def_id(node_id).index]; - let r = self.parameter_environment - .caller_bounds - .iter() - .filter_map(|predicate| { - match *predicate { - ty::Predicate::Trait(ref data) => { - if data.0.self_ty().is_param(index) { - Some(data.to_poly_trait_ref()) - } else { - None - } - } - _ => { - None - } - } - }) - .collect(); - Ok(r) + 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) + } + _ => false + } + }).cloned().collect() } fn re_infer(&self, span: Span, def: Option<&ty::RegionParameterDef>) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 95fd123b7df..ff9c1cc7d36 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -70,7 +70,7 @@ use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContai use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; use rustc::ty::util::IntTypeExt; use rustc::dep_graph::DepNode; -use util::common::{ErrorReported, MemoizationMap}; +use util::common::MemoizationMap; use util::nodemap::{NodeMap, FxHashMap}; use rustc_const_math::ConstInt; @@ -80,7 +80,7 @@ use std::collections::BTreeMap; use syntax::{abi, ast, attr}; use syntax::symbol::{Symbol, keywords}; -use syntax_pos::Span; +use syntax_pos::{Span, DUMMY_SP}; use rustc::hir::{self, map as hir_map}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; @@ -231,91 +231,6 @@ impl<'a, 'tcx> ItemCtxt<'a, 'tcx> { } } - fn cycle_check(tcx: TyCtxt, - span: Span, - query: ty::maps::Query, - code: F) - -> Result - where F: FnOnce() -> Result - { - { - let mut stack = tcx.maps.query_stack.borrow_mut(); - if let Some((i, _)) = stack.iter().enumerate().rev().find(|&(_, q)| *q == query) { - let cycle = &stack[i..]; - report_cycle(tcx, span, cycle); - return Err(ErrorReported); - } - stack.push(query); - } - - let result = code(); - - tcx.maps.query_stack.borrow_mut().pop(); - result - } - - fn report_cycle(tcx: TyCtxt, - span: Span, - cycle: &[ty::maps::Query]) - { - assert!(!cycle.is_empty()); - - let mut err = struct_span_err!(tcx.sess, span, E0391, - "unsupported cyclic reference between types/traits detected"); - err.span_label(span, &format!("cyclic reference")); - - let describe = |query: ty::maps::Query| { - match query { - ty::maps::Query::ty(def_id) => { - format!("processing `{}`", tcx.item_path_str(def_id)) - } - ty::maps::Query::super_predicates(def_id) => { - format!("computing the supertraits of `{}`", - tcx.item_path_str(def_id)) - } - ty::maps::Query::type_param_predicates(def_id) => { - let id = tcx.hir.as_local_node_id(def_id).unwrap(); - format!("the cycle begins when computing the bounds \ - for type parameter `{}`", - ::ty_param_name(tcx, id)) - } - query => span_bug!(span, "unexpected `{:?}`", query) - } - }; - - err.note(&format!("the cycle begins when {}...", - describe(cycle[0]))); - - for &query in &cycle[1..] { - err.note(&format!("...which then requires {}...", - describe(query))); - } - - err.note(&format!("...which then again requires {}, completing the cycle.", - describe(cycle[0]))); - - err.emit(); - } - - /// 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<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - span: Span, - trait_def_id: DefId) - -> Result<(), ErrorReported> - { - cycle_check(tcx, span, ty::maps::Query::super_predicates(trait_def_id), || { - let def_ids = ensure_super_predicates_step(tcx, trait_def_id); - - for def_id in def_ids { - ensure_super_predicates(tcx, span, def_id)?; - } - - Ok(()) - }) - } - impl<'a,'tcx> ItemCtxt<'a,'tcx> { fn to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> { AstConv::ast_ty_to_ty(self, ast_ty) @@ -334,9 +249,9 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { } fn get_item_type(&self, span: Span, id: DefId) -> Ty<'tcx> { - cycle_check(self.tcx, span, ty::maps::Query::ty(id), || { - Ok(type_of_def_id(self.tcx, id)) - }).unwrap_or(self.tcx.types.err) + self.tcx.cycle_check(span, ty::maps::Query::ty(id), || { + type_of_def_id(self.tcx, id) + }) } fn get_trait_def(&self, def_id: DefId) -> &'tcx ty::TraitDef { @@ -349,30 +264,36 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { } } + /// 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) - -> Result<(), ErrorReported> - { - debug!("ensure_super_predicates(trait_def_id={:?})", - trait_def_id); + 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; + } - ensure_super_predicates(self.tcx, span, trait_def_id) + 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, - node_id: ast::NodeId) - -> Result>, ErrorReported> + def_id: DefId) + -> Vec> { - let def_id = self.tcx.hir.local_def_id(node_id); - cycle_check(self.tcx, span, ty::maps::Query::type_param_predicates(def_id), || { - let v = get_type_parameter_bounds(self.tcx, self.item_def_id, node_id) - .into_iter() - .filter_map(|p| p.to_opt_poly_trait_ref()) - .collect(); - Ok(v) - }) + 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)) } fn get_free_substs(&self) -> Option<&Substs<'tcx>> { @@ -428,7 +349,7 @@ 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, - param_id: ast::NodeId) + def_id: DefId) -> Vec> { use rustc::hir::map::*; @@ -438,10 +359,12 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { // written inline like `` or in a where clause like // `where T:Foo`. - let param_owner_def_id = tcx.hir.local_def_id(::ty_param_owner(tcx, 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 = generics_of_def_id(tcx, param_owner_def_id); - let index = generics.type_param_to_index[&tcx.hir.local_def_id(param_id).index]; - let ty = tcx.mk_param(index, ::ty_param_name(tcx, param_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 { @@ -450,8 +373,9 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { generics_of_def_id(tcx, item_def_id).parent }; - let mut results = parent.map_or(vec![], |def_id| { - get_type_parameter_bounds(tcx, def_id, param_id) + let mut results = parent.map_or(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(); @@ -706,8 +630,7 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) { hir::ItemTrait(..) => { generics_of_def_id(tcx, def_id); trait_def_of_item(tcx, it); - let _: Result<(), ErrorReported> = // any error is already reported, can ignore - ensure_super_predicates(tcx, it.span, def_id); + icx.ensure_super_predicates(it.span, def_id); predicates_of_item(tcx, it); }, hir::ItemStruct(ref struct_def, _) | @@ -1025,82 +948,54 @@ fn convert_enum_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } /// Ensures that the super-predicates of the trait with def-id -/// trait_def_id are converted and stored. This does NOT ensure that -/// the transitive super-predicates are converted; that is the job of -/// the `ensure_super_predicates()` method in the `AstConv` impl -/// above. Returns a list of trait def-ids that must be ensured as -/// well to guarantee that the transitive superpredicates are -/// converted. -fn ensure_super_predicates_step<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - trait_def_id: DefId) - -> Vec -{ - debug!("ensure_super_predicates_step(trait_def_id={:?})", trait_def_id); +/// trait_def_id are converted and stored. This also ensures that +/// the transitive super-predicates are converted; +fn super_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + trait_def_id: DefId) + -> ty::GenericPredicates<'tcx> { + debug!("super_predicates(trait_def_id={:?})", trait_def_id); + let trait_node_id = tcx.hir.as_local_node_id(trait_def_id).unwrap(); - let trait_node_id = if let Some(n) = tcx.hir.as_local_node_id(trait_def_id) { - n - } else { - // 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 Vec::new(); + let item = match tcx.hir.get(trait_node_id) { + hir_map::NodeItem(item) => item, + _ => bug!("trait_node_id {} is not an item", trait_node_id) }; - let superpredicates = tcx.maps.super_predicates.borrow().get(&trait_def_id).cloned(); - let superpredicates = superpredicates.unwrap_or_else(|| { - let item = match tcx.hir.get(trait_node_id) { - hir_map::NodeItem(item) => item, - _ => bug!("trait_node_id {} is not an item", trait_node_id) - }; + let (generics, bounds) = match item.node { + hir::ItemTrait(_, ref generics, ref supertraits, _) => (generics, supertraits), + _ => span_bug!(item.span, + "super_predicates invoked on non-trait"), + }; - let (generics, bounds) = match item.node { - hir::ItemTrait(_, ref generics, ref supertraits, _) => (generics, supertraits), - _ => span_bug!(item.span, - "ensure_super_predicates_step invoked on non-trait"), - }; + let icx = ItemCtxt::new(tcx, trait_def_id); - let icx = ItemCtxt::new(tcx, trait_def_id); + // Convert the bounds that follow the colon, e.g. `Bar+Zed` in `trait Foo : Bar+Zed`. + let self_param_ty = tcx.mk_self_type(); + let superbounds1 = compute_bounds(&icx, + self_param_ty, + bounds, + SizedByDefault::No, + item.span); - // Convert the bounds that follow the colon, e.g. `Bar+Zed` in `trait Foo : Bar+Zed`. - let self_param_ty = tcx.mk_self_type(); - let superbounds1 = compute_bounds(&icx, - self_param_ty, - bounds, - SizedByDefault::No, - item.span); + let superbounds1 = superbounds1.predicates(tcx, self_param_ty); - let superbounds1 = superbounds1.predicates(tcx, self_param_ty); + // Convert any explicit superbounds in the where clause, + // e.g. `trait Foo where Self : Bar`: + let superbounds2 = icx.type_parameter_bounds_in_generics(generics, item.id, self_param_ty); - // Convert any explicit superbounds in the where clause, - // e.g. `trait Foo where Self : Bar`: - let superbounds2 = icx.type_parameter_bounds_in_generics(generics, item.id, self_param_ty); + // Combine the two lists to form the complete set of superbounds: + let superbounds: Vec<_> = superbounds1.into_iter().chain(superbounds2).collect(); - // Combine the two lists to form the complete set of superbounds: - let superbounds = superbounds1.into_iter().chain(superbounds2).collect(); - let superpredicates = ty::GenericPredicates { - parent: None, - predicates: superbounds - }; - debug!("superpredicates for trait {:?} = {:?}", - tcx.hir.local_def_id(item.id), - superpredicates); + // 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.borrow_mut().insert(trait_def_id, superpredicates.clone()); - - superpredicates - }); - - let def_ids: Vec<_> = superpredicates.predicates - .iter() - .filter_map(|p| p.to_opt_poly_trait_ref()) - .map(|tr| tr.def_id()) - .collect(); - - debug!("ensure_super_predicates_step: def_ids={:?}", def_ids); - - def_ids + ty::GenericPredicates { + parent: None, + predicates: superbounds + } } fn trait_def_of_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) -> &'tcx ty::TraitDef { diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 1ff6944d98d..e8cb25cec4f 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -3417,23 +3417,6 @@ impl Bar for *mut Foo { ``` "##, -E0391: r##" -This error indicates that some types or traits depend on each other -and therefore cannot be constructed. - -The following example contains a circular dependency between two traits: - -```compile_fail,E0391 -trait FirstTrait : SecondTrait { - -} - -trait SecondTrait : FirstTrait { - -} -``` -"##, - E0392: r##" This error indicates that a type or lifetime parameter has been declared but not actually used. Here is an example that demonstrates the error: diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index ddd8d9259cc..c3c1952415b 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -116,7 +116,6 @@ use util::common::time; use syntax::ast; use syntax::abi::Abi; -use syntax::symbol::keywords; use syntax_pos::Span; use std::iter; @@ -170,30 +169,6 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }) } -fn ty_param_owner(tcx: TyCtxt, id: ast::NodeId) -> ast::NodeId { - match tcx.hir.get(id) { - hir::map::NodeItem(&hir::Item { node: hir::ItemTrait(..), .. }) => id, - hir::map::NodeTyParam(_) => tcx.hir.get_parent_node(id), - _ => { - bug!("ty_param_owner: {} not a type parameter", - tcx.hir.node_to_string(id)) - } - } -} - -fn ty_param_name(tcx: TyCtxt, id: ast::NodeId) -> ast::Name { - match tcx.hir.get(id) { - hir::map::NodeItem(&hir::Item { node: hir::ItemTrait(..), .. }) => { - keywords::SelfType.name() - } - hir::map::NodeTyParam(tp) => tp.name, - _ => { - bug!("ty_param_name: {} not a type parameter", - tcx.hir.node_to_string(id)) - } - } -} - fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: ast::NodeId, main_span: Span) { diff --git a/src/test/compile-fail/cycle-projection-based-on-where-clause.rs b/src/test/compile-fail/cycle-projection-based-on-where-clause.rs index 5ca0700ce6e..7af2f11bd28 100644 --- a/src/test/compile-fail/cycle-projection-based-on-where-clause.rs +++ b/src/test/compile-fail/cycle-projection-based-on-where-clause.rs @@ -26,6 +26,7 @@ struct A where T : Trait, T : Add //~^ ERROR unsupported cyclic reference between types/traits detected + //~| ERROR associated type `Item` not found for `T` { data: T } diff --git a/src/test/compile-fail/cycle-trait-supertrait-indirect.rs b/src/test/compile-fail/cycle-trait-supertrait-indirect.rs index c9bfde3f4ed..905d546e99a 100644 --- a/src/test/compile-fail/cycle-trait-supertrait-indirect.rs +++ b/src/test/compile-fail/cycle-trait-supertrait-indirect.rs @@ -12,14 +12,16 @@ // a direct participant in the cycle. trait A: B { - //~^ ERROR unsupported cyclic reference + //~^ NOTE the cycle begins when computing the supertraits of `B`... } trait B: C { - //~^ ERROR unsupported cyclic reference + //~^ NOTE ...which then requires computing the supertraits of `C`... } trait C: B { } //~^ ERROR unsupported cyclic reference + //~| cyclic reference + //~| NOTE ...which then again requires computing the supertraits of `B`, completing the cycle fn main() { } diff --git a/src/test/compile-fail/issue-12511.rs b/src/test/compile-fail/issue-12511.rs index 35697e68734..0c3073a7701 100644 --- a/src/test/compile-fail/issue-12511.rs +++ b/src/test/compile-fail/issue-12511.rs @@ -9,11 +9,14 @@ // except according to those terms. trait t1 : t2 { -//~^ ERROR: unsupported cyclic reference between types/traits detected +//~^ NOTE the cycle begins when computing the supertraits of `t1`... +//~| NOTE ...which then requires computing the supertraits of `t2`... } trait t2 : t1 { -//~^ ERROR: unsupported cyclic reference between types/traits detected +//~^ ERROR unsupported cyclic reference between types/traits detected +//~| cyclic reference +//~| NOTE ...which then again requires computing the supertraits of `t1`, completing the cycle } fn main() { } diff --git a/src/test/compile-fail/issue-20772.rs b/src/test/compile-fail/issue-20772.rs index 44c92f946f0..7ae4250d420 100644 --- a/src/test/compile-fail/issue-20772.rs +++ b/src/test/compile-fail/issue-20772.rs @@ -10,6 +10,7 @@ trait T : Iterator //~^ ERROR unsupported cyclic reference between types/traits detected +//~| ERROR associated type `Item` not found for `Self` {} fn main() {} diff --git a/src/test/compile-fail/issue-21177.rs b/src/test/compile-fail/issue-21177.rs index 5ad9a12362d..f49b7195383 100644 --- a/src/test/compile-fail/issue-21177.rs +++ b/src/test/compile-fail/issue-21177.rs @@ -14,6 +14,7 @@ trait Trait { } fn foo>() { } -//~^ ERROR: unsupported cyclic reference between types/traits detected +//~^ ERROR unsupported cyclic reference between types/traits detected +//~| ERROR associated type `B` not found for `T` fn main() { }