rustc_typeck: don't use Result for get_type_parameter_bounds and ensure_super_predicates.
This commit is contained in:
parent
4649f7387e
commit
28f1cf4262
@ -109,6 +109,7 @@ pub enum DepNode<D: Clone + Debug> {
|
||||
// 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<D: Clone + Debug> DepNode<D> {
|
||||
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),
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -39,6 +39,7 @@
|
||||
#![feature(rustc_diagnostic_macros)]
|
||||
#![feature(rustc_private)]
|
||||
#![feature(slice_patterns)]
|
||||
#![feature(specialization)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
|
@ -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<F, R>(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<CrateNum, Providers<$tcx>>,
|
||||
pub query_stack: RefCell<Vec<Query>>,
|
||||
pub query_stack: RefCell<Vec<(Span, Query)>>,
|
||||
$($(#[$attr])* pub $name: RefCell<DepTrackingMap<queries::$name<$tcx>>>),*
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
@ -669,7 +669,7 @@ impl Generics {
|
||||
}
|
||||
|
||||
/// Bounds on generics.
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Default)]
|
||||
pub struct GenericPredicates<'tcx> {
|
||||
pub parent: Option<DefId>,
|
||||
pub predicates: Vec<Predicate<'tcx>>,
|
||||
|
@ -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<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>;
|
||||
fn get_type_parameter_bounds(&self, span: Span, def_id: DefId)
|
||||
-> Vec<ty::Predicate<'tcx>>;
|
||||
|
||||
/// 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<ty::PolyTraitRef<'tcx>, 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
|
||||
|
@ -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<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>
|
||||
fn get_type_parameter_bounds(&self, _: Span, def_id: DefId)
|
||||
-> Vec<ty::Predicate<'tcx>>
|
||||
{
|
||||
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>)
|
||||
|
@ -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<F,R>(tcx: TyCtxt,
|
||||
span: Span,
|
||||
query: ty::maps::Query,
|
||||
code: F)
|
||||
-> Result<R,ErrorReported>
|
||||
where F: FnOnce() -> Result<R,ErrorReported>
|
||||
{
|
||||
{
|
||||
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<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>
|
||||
def_id: DefId)
|
||||
-> Vec<ty::Predicate<'tcx>>
|
||||
{
|
||||
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<ty::Predicate<'tcx>>
|
||||
{
|
||||
use rustc::hir::map::*;
|
||||
@ -438,10 +359,12 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
|
||||
// written inline like `<T:Foo>` 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<DefId>
|
||||
{
|
||||
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 {
|
||||
|
@ -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:
|
||||
|
@ -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) {
|
||||
|
@ -26,6 +26,7 @@ struct A<T>
|
||||
where T : Trait,
|
||||
T : Add<T::Item>
|
||||
//~^ ERROR unsupported cyclic reference between types/traits detected
|
||||
//~| ERROR associated type `Item` not found for `T`
|
||||
{
|
||||
data: T
|
||||
}
|
||||
|
@ -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() { }
|
||||
|
@ -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() { }
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
trait T : Iterator<Item=Self::Item>
|
||||
//~^ ERROR unsupported cyclic reference between types/traits detected
|
||||
//~| ERROR associated type `Item` not found for `Self`
|
||||
{}
|
||||
|
||||
fn main() {}
|
||||
|
@ -14,6 +14,7 @@ trait Trait {
|
||||
}
|
||||
|
||||
fn foo<T: Trait<A = T::B>>() { }
|
||||
//~^ 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() { }
|
||||
|
Loading…
Reference in New Issue
Block a user