about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_query_impl/src/keys.rs13
-rw-r--r--compiler/rustc_query_impl/src/lib.rs2
-rw-r--r--compiler/rustc_query_impl/src/plumbing.rs7
-rw-r--r--compiler/rustc_query_impl/src/util.rs18
-rw-r--r--compiler/rustc_query_system/src/query/job.rs14
-rw-r--r--compiler/rustc_query_system/src/query/mod.rs29
6 files changed, 81 insertions, 2 deletions
diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs
index 38ab26d66ac..40b820c8d8e 100644
--- a/compiler/rustc_query_impl/src/keys.rs
+++ b/compiler/rustc_query_impl/src/keys.rs
@@ -20,6 +20,12 @@ pub trait Key {
     /// In the event that a cycle occurs, if no explicit span has been
     /// given for a query with key `self`, what span should we use?
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span;
+
+    /// If the key is a [`DefId`] or `DefId`--equivalent, return that `DefId`.
+    /// Otherwise, return `None`.
+    fn key_as_def_id(&self) -> Option<DefId> {
+        None
+    }
 }
 
 impl Key for () {
@@ -95,6 +101,9 @@ impl Key for LocalDefId {
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.to_def_id().default_span(tcx)
     }
+    fn key_as_def_id(&self) -> Option<DefId> {
+        Some(self.to_def_id())
+    }
 }
 
 impl Key for DefId {
@@ -105,6 +114,10 @@ impl Key for DefId {
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         tcx.def_span(*self)
     }
+    #[inline(always)]
+    fn key_as_def_id(&self) -> Option<DefId> {
+        Some(*self)
+    }
 }
 
 impl Key for ty::WithOptConstParam<LocalDefId> {
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 5022bf26532..bb0e6511159 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -51,6 +51,8 @@ pub use on_disk_cache::OnDiskCache;
 mod profiling_support;
 pub use self::profiling_support::alloc_self_profile_query_strings;
 
+mod util;
+
 rustc_query_append! { [define_queries!][<'tcx>] }
 
 impl<'tcx> Queries<'tcx> {
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index 5774d021373..476085c8725 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -337,6 +337,11 @@ macro_rules! define_queries {
                 } else {
                     Some(key.default_span(*tcx))
                 };
+                let def_id = key.key_as_def_id();
+                let def_kind = def_id.map(|def_id| {
+                    let def_kind = tcx.def_kind(def_id);
+                    $crate::util::def_kind_to_simple_def_kind(def_kind)
+                });
                 let hash = || {
                     let mut hcx = tcx.create_stable_hashing_context();
                     let mut hasher = StableHasher::new();
@@ -345,7 +350,7 @@ macro_rules! define_queries {
                     hasher.finish::<u64>()
                 };
 
-                QueryStackFrame::new(name, description, span, hash)
+                QueryStackFrame::new(name, description, span, def_kind, hash)
             })*
         }
 
diff --git a/compiler/rustc_query_impl/src/util.rs b/compiler/rustc_query_impl/src/util.rs
new file mode 100644
index 00000000000..517c107b5d9
--- /dev/null
+++ b/compiler/rustc_query_impl/src/util.rs
@@ -0,0 +1,18 @@
+use rustc_hir::def::DefKind;
+use rustc_query_system::query::SimpleDefKind;
+
+/// Convert a [`DefKind`] to a [`SimpleDefKind`].
+///
+/// *See [`SimpleDefKind`]'s docs for more information.*
+pub(crate) fn def_kind_to_simple_def_kind(def_kind: DefKind) -> SimpleDefKind {
+    match def_kind {
+        DefKind::Struct => SimpleDefKind::Struct,
+        DefKind::Enum => SimpleDefKind::Enum,
+        DefKind::Union => SimpleDefKind::Union,
+        DefKind::Trait => SimpleDefKind::Trait,
+        DefKind::TyAlias => SimpleDefKind::TyAlias,
+        DefKind::TraitAlias => SimpleDefKind::TraitAlias,
+
+        _ => SimpleDefKind::Other,
+    }
+}
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index b7ac42546dd..f8ba0babab0 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -1,6 +1,6 @@
 use crate::dep_graph::DepContext;
 use crate::query::plumbing::CycleError;
-use crate::query::{QueryContext, QueryStackFrame};
+use crate::query::{QueryContext, QueryStackFrame, SimpleDefKind};
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{struct_span_err, Diagnostic, DiagnosticBuilder, Handler, Level};
@@ -600,6 +600,18 @@ pub(crate) fn report_cycle<'a>(
         ));
     }
 
+    if !stack.is_empty()
+        && stack.iter().all(|entry| {
+            entry.query.def_kind.map_or(false, |def_kind| {
+                matches!(def_kind, SimpleDefKind::TyAlias | SimpleDefKind::TraitAlias)
+            })
+        })
+    {
+        err.note("type aliases cannot be recursive");
+        err.help("consider using a struct, enum, or union instead to break the cycle");
+        err.help("see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information");
+    }
+
     if let Some((span, query)) = usage {
         err.span_note(fix_span(span, &query), &format!("cycle used when {}", query.description));
     }
diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs
index 7288aaef8f2..dffe7f3689f 100644
--- a/compiler/rustc_query_system/src/query/mod.rs
+++ b/compiler/rustc_query_system/src/query/mod.rs
@@ -29,24 +29,53 @@ pub struct QueryStackFrame {
     pub name: &'static str,
     pub description: String,
     span: Option<Span>,
+    /// The `DefKind` this query frame is associated with, if applicable.
+    ///
+    /// We can't use `rustc_hir::def::DefKind` because `rustc_hir` is not
+    /// available in `rustc_query_system`. Instead, we have a simplified
+    /// custom version of it, called [`SimpleDefKind`].
+    def_kind: Option<SimpleDefKind>,
     /// This hash is used to deterministically pick
     /// a query to remove cycles in the parallel compiler.
     #[cfg(parallel_compiler)]
     hash: u64,
 }
 
+/// A simplified version of `rustc_hir::def::DefKind`.
+///
+/// It was added to help improve cycle errors caused by recursive type aliases.
+/// As of August 2021, `rustc_query_system` cannot depend on `rustc_hir`
+/// because it would create a dependency cycle. So, instead, a simplified
+/// version of `DefKind` was added to `rustc_query_system`.
+///
+/// `DefKind`s are converted to `SimpleDefKind`s in `rustc_query_impl`.
+#[derive(Debug, Copy, Clone)]
+pub enum SimpleDefKind {
+    Struct,
+    Enum,
+    Union,
+    Trait,
+    TyAlias,
+    TraitAlias,
+
+    // FIXME: add more from `rustc_hir::def::DefKind` and then remove `Other`
+    Other,
+}
+
 impl QueryStackFrame {
     #[inline]
     pub fn new(
         name: &'static str,
         description: String,
         span: Option<Span>,
+        def_kind: Option<SimpleDefKind>,
         _hash: impl FnOnce() -> u64,
     ) -> Self {
         Self {
             name,
             description,
             span,
+            def_kind,
             #[cfg(parallel_compiler)]
             hash: _hash(),
         }