Skip to content

Commit cd0fc44

Browse files
committed
Note that type aliases cannot be recursive
1 parent 2f48bfa commit cd0fc44

File tree

7 files changed

+84
-2
lines changed

7 files changed

+84
-2
lines changed

compiler/rustc_query_impl/src/keys.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ pub trait Key {
2020
/// In the event that a cycle occurs, if no explicit span has been
2121
/// given for a query with key `self`, what span should we use?
2222
fn default_span(&self, tcx: TyCtxt<'_>) -> Span;
23+
24+
/// If the key is a [`DefId`] or `DefId`--equivalent, return that `DefId`.
25+
/// Otherwise, return `None`.
26+
fn key_as_def_id(&self) -> Option<DefId> {
27+
None
28+
}
2329
}
2430

2531
impl Key for () {
@@ -95,6 +101,9 @@ impl Key for LocalDefId {
95101
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
96102
self.to_def_id().default_span(tcx)
97103
}
104+
fn key_as_def_id(&self) -> Option<DefId> {
105+
Some(self.to_def_id())
106+
}
98107
}
99108

100109
impl Key for DefId {
@@ -105,6 +114,10 @@ impl Key for DefId {
105114
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
106115
tcx.def_span(*self)
107116
}
117+
#[inline(always)]
118+
fn key_as_def_id(&self) -> Option<DefId> {
119+
Some(*self)
120+
}
108121
}
109122

110123
impl Key for ty::WithOptConstParam<LocalDefId> {

compiler/rustc_query_impl/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ pub use on_disk_cache::OnDiskCache;
5151
mod profiling_support;
5252
pub use self::profiling_support::alloc_self_profile_query_strings;
5353

54+
mod util;
55+
5456
rustc_query_append! { [define_queries!][<'tcx>] }
5557

5658
impl<'tcx> Queries<'tcx> {

compiler/rustc_query_impl/src/plumbing.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,11 @@ macro_rules! define_queries {
337337
} else {
338338
Some(key.default_span(*tcx))
339339
};
340+
let def_id = key.key_as_def_id();
341+
let def_kind = def_id.map(|def_id| {
342+
let def_kind = tcx.def_kind(def_id);
343+
$crate::util::def_kind_to_simple_def_kind(def_kind)
344+
});
340345
let hash = || {
341346
let mut hcx = tcx.create_stable_hashing_context();
342347
let mut hasher = StableHasher::new();
@@ -345,7 +350,7 @@ macro_rules! define_queries {
345350
hasher.finish::<u64>()
346351
};
347352

348-
QueryStackFrame::new(name, description, span, hash)
353+
QueryStackFrame::new(name, description, span, def_kind, hash)
349354
})*
350355
}
351356

compiler/rustc_query_impl/src/util.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use rustc_hir::def::DefKind;
2+
use rustc_query_system::query::SimpleDefKind;
3+
4+
/// Convert a [`DefKind`] to a [`SimpleDefKind`].
5+
///
6+
/// *See [`SimpleDefKind`]'s docs for more information.*
7+
pub(crate) fn def_kind_to_simple_def_kind(def_kind: DefKind) -> SimpleDefKind {
8+
match def_kind {
9+
DefKind::Struct => SimpleDefKind::Struct,
10+
DefKind::Enum => SimpleDefKind::Enum,
11+
DefKind::Union => SimpleDefKind::Union,
12+
DefKind::Trait => SimpleDefKind::Trait,
13+
DefKind::TyAlias => SimpleDefKind::TyAlias,
14+
DefKind::TraitAlias => SimpleDefKind::TraitAlias,
15+
16+
_ => SimpleDefKind::Other,
17+
}
18+
}

compiler/rustc_query_system/src/query/job.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::dep_graph::DepContext;
22
use crate::query::plumbing::CycleError;
3-
use crate::query::{QueryContext, QueryStackFrame};
3+
use crate::query::{QueryContext, QueryStackFrame, SimpleDefKind};
44

55
use rustc_data_structures::fx::FxHashMap;
66
use rustc_errors::{struct_span_err, Diagnostic, DiagnosticBuilder, Handler, Level};
@@ -600,6 +600,18 @@ pub(crate) fn report_cycle<'a>(
600600
));
601601
}
602602

603+
if !stack.is_empty()
604+
&& stack.iter().all(|entry| {
605+
entry.query.def_kind.map_or(false, |def_kind| {
606+
matches!(def_kind, SimpleDefKind::TyAlias | SimpleDefKind::TraitAlias)
607+
})
608+
})
609+
{
610+
err.note("type aliases cannot be recursive");
611+
err.help("consider using a struct, enum, or union instead to break the cycle");
612+
err.help("see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information");
613+
}
614+
603615
if let Some((span, query)) = usage {
604616
err.span_note(fix_span(span, &query), &format!("cycle used when {}", query.description));
605617
}

compiler/rustc_query_system/src/query/mod.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,24 +29,53 @@ pub struct QueryStackFrame {
2929
pub name: &'static str,
3030
pub description: String,
3131
span: Option<Span>,
32+
/// The `DefKind` this query frame is associated with, if applicable.
33+
///
34+
/// We can't use `rustc_hir::def::DefKind` because `rustc_hir` is not
35+
/// available in `rustc_query_system`. Instead, we have a simplified
36+
/// custom version of it, called [`SimpleDefKind`].
37+
def_kind: Option<SimpleDefKind>,
3238
/// This hash is used to deterministically pick
3339
/// a query to remove cycles in the parallel compiler.
3440
#[cfg(parallel_compiler)]
3541
hash: u64,
3642
}
3743

44+
/// A simplified version of `rustc_hir::def::DefKind`.
45+
///
46+
/// It was added to help improve cycle errors caused by recursive type aliases.
47+
/// As of August 2021, `rustc_query_system` cannot depend on `rustc_hir`
48+
/// because it would create a dependency cycle. So, instead, a simplified
49+
/// version of `DefKind` was added to `rustc_query_system`.
50+
///
51+
/// `DefKind`s are converted to `SimpleDefKind`s in `rustc_query_impl`.
52+
#[derive(Debug, Copy, Clone)]
53+
pub enum SimpleDefKind {
54+
Struct,
55+
Enum,
56+
Union,
57+
Trait,
58+
TyAlias,
59+
TraitAlias,
60+
61+
// FIXME: add more from `rustc_hir::def::DefKind` and then remove `Other`
62+
Other,
63+
}
64+
3865
impl QueryStackFrame {
3966
#[inline]
4067
pub fn new(
4168
name: &'static str,
4269
description: String,
4370
span: Option<Span>,
71+
def_kind: Option<SimpleDefKind>,
4472
_hash: impl FnOnce() -> u64,
4573
) -> Self {
4674
Self {
4775
name,
4876
description,
4977
span,
78+
def_kind,
5079
#[cfg(parallel_compiler)]
5180
hash: _hash(),
5281
}

src/test/ui/infinite/infinite-vec-type-recursion.stderr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ LL | type X = Vec<X>;
55
| ^
66
|
77
= note: ...which immediately requires expanding type alias `X` again
8+
= note: type aliases cannot be recursive
9+
= help: consider using a struct, enum, or union instead to break the cycle
10+
= help: see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information
811
note: cycle used when collecting item types in top-level module
912
--> $DIR/infinite-vec-type-recursion.rs:1:1
1013
|

0 commit comments

Comments
 (0)