From 2f48bfa88c1c742ed058fc8af096d8cedc138434 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Tue, 20 Jul 2021 18:06:39 -0700 Subject: [PATCH 1/6] Improve errors for recursive type aliases --- compiler/rustc_middle/src/query/mod.rs | 13 ++++++++++++- compiler/rustc_query_system/src/query/job.rs | 12 ++++++++---- .../ambiguous-associated-type2.stderr | 2 +- .../coherence-inherited-assoc-ty-cycle-err.stderr | 2 +- .../cycle-trait-default-type-trait.stderr | 4 ++-- src/test/ui/infinite/infinite-struct.stderr | 2 +- .../ui/infinite/infinite-tag-type-recursion.stderr | 2 +- .../ui/infinite/infinite-vec-type-recursion.stderr | 4 ++-- src/test/ui/issues/issue-20772.stderr | 2 +- src/test/ui/issues/issue-20825.stderr | 2 +- src/test/ui/issues/issue-21177.stderr | 2 +- src/test/ui/issues/issue-34373.stderr | 2 +- src/test/ui/resolve/issue-23305.stderr | 2 +- src/test/ui/resolve/resolve-self-in-impl.stderr | 10 +++++----- 14 files changed, 38 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 85b1274da10ed..8e3db669f501f 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -116,7 +116,18 @@ rustc_queries! { /// Records the type of every item. query type_of(key: DefId) -> Ty<'tcx> { - desc { |tcx| "computing type of `{}`", tcx.def_path_str(key) } + desc { |tcx| + "{action} `{path}`", + action = { + use rustc_hir::def::DefKind; + match tcx.def_kind(key) { + DefKind::TyAlias => "expanding type alias", + DefKind::TraitAlias => "expanding trait alias", + _ => "computing type of", + } + }, + path = tcx.def_path_str(key), + } cache_on_disk_if { key.is_local() } } diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index a967670280ff2..b7ac42546dda3 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -591,10 +591,14 @@ pub(crate) fn report_cycle<'a>( err.span_note(span, &format!("...which requires {}...", query.description)); } - err.note(&format!( - "...which again requires {}, completing the cycle", - stack[0].query.description - )); + if stack.len() == 1 { + err.note(&format!("...which immediately requires {} again", stack[0].query.description)); + } else { + err.note(&format!( + "...which again requires {}, completing the cycle", + stack[0].query.description + )); + } if let Some((span, query)) = usage { err.span_note(fix_span(span, &query), &format!("cycle used when {}", query.description)); diff --git a/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr b/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr index e72ef0e4b332e..4162cdaa8dcd8 100644 --- a/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr +++ b/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr @@ -4,7 +4,7 @@ error[E0391]: cycle detected when computing the super traits of `Baz` with assoc LL | trait Baz: Foo + Bar {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: ...which again requires computing the super traits of `Baz` with associated type name `Item`, completing the cycle + = note: ...which immediately requires computing the super traits of `Baz` with associated type name `Item` again note: cycle used when computing the super traits of `Baz` --> $DIR/ambiguous-associated-type2.rs:7:1 | diff --git a/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr b/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr index f3edf1c350f50..97f3c759355d4 100644 --- a/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr +++ b/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr @@ -14,7 +14,7 @@ error[E0391]: cycle detected when building specialization graph of trait `Trait` LL | trait Trait { type Assoc; } | ^^^^^^^^^^^^^^ | - = note: ...which again requires building specialization graph of trait `Trait`, completing the cycle + = note: ...which immediately requires building specialization graph of trait `Trait` again note: cycle used when coherence checking all impls of trait `Trait` --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:9:1 | diff --git a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr index 58c458709a839..fc842fada5a0d 100644 --- a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr +++ b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr @@ -4,7 +4,7 @@ error[E0391]: cycle detected when computing type of `Foo::X` LL | trait Foo> { | ^^^ | - = note: ...which again requires computing type of `Foo::X`, completing the cycle + = note: ...which immediately requires computing type of `Foo::X` again note: cycle used when collecting item types in top-level module --> $DIR/cycle-trait-default-type-trait.rs:4:1 | @@ -17,7 +17,7 @@ error[E0391]: cycle detected when computing type of `Foo::X` LL | trait Foo> { | ^^^ | - = note: ...which again requires computing type of `Foo::X`, completing the cycle + = note: ...which immediately requires computing type of `Foo::X` again note: cycle used when collecting item types in top-level module --> $DIR/cycle-trait-default-type-trait.rs:4:1 | diff --git a/src/test/ui/infinite/infinite-struct.stderr b/src/test/ui/infinite/infinite-struct.stderr index 7ffb51061b7dd..369645f9030fb 100644 --- a/src/test/ui/infinite/infinite-struct.stderr +++ b/src/test/ui/infinite/infinite-struct.stderr @@ -18,7 +18,7 @@ error[E0391]: cycle detected when computing drop-check constraints for `Take` LL | struct Take(Take); | ^^^^^^^^^^^^^^^^^^ | - = note: ...which again requires computing drop-check constraints for `Take`, completing the cycle + = note: ...which immediately requires computing drop-check constraints for `Take` again = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: Take } }` error: aborting due to 2 previous errors diff --git a/src/test/ui/infinite/infinite-tag-type-recursion.stderr b/src/test/ui/infinite/infinite-tag-type-recursion.stderr index 1f147e070b4d1..61b5e94677526 100644 --- a/src/test/ui/infinite/infinite-tag-type-recursion.stderr +++ b/src/test/ui/infinite/infinite-tag-type-recursion.stderr @@ -17,7 +17,7 @@ error[E0391]: cycle detected when computing drop-check constraints for `MList` LL | enum MList { Cons(isize, MList), Nil } | ^^^^^^^^^^ | - = note: ...which again requires computing drop-check constraints for `MList`, completing the cycle + = note: ...which immediately requires computing drop-check constraints for `MList` again = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: MList } }` error: aborting due to 2 previous errors diff --git a/src/test/ui/infinite/infinite-vec-type-recursion.stderr b/src/test/ui/infinite/infinite-vec-type-recursion.stderr index 77adefeb124e3..d9039243f8d92 100644 --- a/src/test/ui/infinite/infinite-vec-type-recursion.stderr +++ b/src/test/ui/infinite/infinite-vec-type-recursion.stderr @@ -1,10 +1,10 @@ -error[E0391]: cycle detected when computing type of `X` +error[E0391]: cycle detected when expanding type alias `X` --> $DIR/infinite-vec-type-recursion.rs:1:14 | LL | type X = Vec; | ^ | - = note: ...which again requires computing type of `X`, completing the cycle + = note: ...which immediately requires expanding type alias `X` again note: cycle used when collecting item types in top-level module --> $DIR/infinite-vec-type-recursion.rs:1:1 | diff --git a/src/test/ui/issues/issue-20772.stderr b/src/test/ui/issues/issue-20772.stderr index 4aecc7eab4628..c964dc41dceaf 100644 --- a/src/test/ui/issues/issue-20772.stderr +++ b/src/test/ui/issues/issue-20772.stderr @@ -6,7 +6,7 @@ LL | | LL | | {} | |__^ | - = note: ...which again requires computing the super traits of `T` with associated type name `Item`, completing the cycle + = note: ...which immediately requires computing the super traits of `T` with associated type name `Item` again note: cycle used when computing the super traits of `T` --> $DIR/issue-20772.rs:1:1 | diff --git a/src/test/ui/issues/issue-20825.stderr b/src/test/ui/issues/issue-20825.stderr index ccbe06d9c0d56..be2bbd448007b 100644 --- a/src/test/ui/issues/issue-20825.stderr +++ b/src/test/ui/issues/issue-20825.stderr @@ -4,7 +4,7 @@ error[E0391]: cycle detected when computing the super traits of `Processor` with LL | pub trait Processor: Subscriber { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: ...which again requires computing the super traits of `Processor` with associated type name `Input`, completing the cycle + = note: ...which immediately requires computing the super traits of `Processor` with associated type name `Input` again note: cycle used when computing the super traits of `Processor` --> $DIR/issue-20825.rs:5:1 | diff --git a/src/test/ui/issues/issue-21177.stderr b/src/test/ui/issues/issue-21177.stderr index 59cc6550a8bd6..6877a18460509 100644 --- a/src/test/ui/issues/issue-21177.stderr +++ b/src/test/ui/issues/issue-21177.stderr @@ -4,7 +4,7 @@ error[E0391]: cycle detected when computing the bounds for type parameter `T` LL | fn foo>() { } | ^^^^ | - = note: ...which again requires computing the bounds for type parameter `T`, completing the cycle + = note: ...which immediately requires computing the bounds for type parameter `T` again note: cycle used when computing explicit predicates of `foo` --> $DIR/issue-21177.rs:6:21 | diff --git a/src/test/ui/issues/issue-34373.stderr b/src/test/ui/issues/issue-34373.stderr index e8c1e8f966973..8be3cfa72fb26 100644 --- a/src/test/ui/issues/issue-34373.stderr +++ b/src/test/ui/issues/issue-34373.stderr @@ -4,7 +4,7 @@ error[E0391]: cycle detected when computing type of `Foo::T` LL | pub struct Foo>>; | ^^^^^^^^^^ | -note: ...which requires computing type of `DefaultFoo`... +note: ...which requires expanding type alias `DefaultFoo`... --> $DIR/issue-34373.rs:8:19 | LL | type DefaultFoo = Foo; diff --git a/src/test/ui/resolve/issue-23305.stderr b/src/test/ui/resolve/issue-23305.stderr index 525b5cf7d8417..0dcf0184db107 100644 --- a/src/test/ui/resolve/issue-23305.stderr +++ b/src/test/ui/resolve/issue-23305.stderr @@ -4,7 +4,7 @@ error[E0391]: cycle detected when computing type of ` {} | ^^^^ | - = note: ...which again requires computing type of ``, completing the cycle + = note: ...which immediately requires computing type of `` again note: cycle used when collecting item types in top-level module --> $DIR/issue-23305.rs:1:1 | diff --git a/src/test/ui/resolve/resolve-self-in-impl.stderr b/src/test/ui/resolve/resolve-self-in-impl.stderr index 5b5c1834cad19..7f623e47353b9 100644 --- a/src/test/ui/resolve/resolve-self-in-impl.stderr +++ b/src/test/ui/resolve/resolve-self-in-impl.stderr @@ -4,7 +4,7 @@ error[E0391]: cycle detected when computing type of ``, completing the cycle + = note: ...which immediately requires computing type of `` again note: cycle used when collecting item types in top-level module --> $DIR/resolve-self-in-impl.rs:1:1 | @@ -23,7 +23,7 @@ error[E0391]: cycle detected when computing type of ` {} | ^^^^ | - = note: ...which again requires computing type of ``, completing the cycle + = note: ...which immediately requires computing type of `` again note: cycle used when collecting item types in top-level module --> $DIR/resolve-self-in-impl.rs:1:1 | @@ -42,7 +42,7 @@ error[E0391]: cycle detected when computing type of ``, completing the cycle + = note: ...which immediately requires computing type of `` again note: cycle used when collecting item types in top-level module --> $DIR/resolve-self-in-impl.rs:1:1 | @@ -61,7 +61,7 @@ error[E0391]: cycle detected when computing type of ` {} | ^^^^ | - = note: ...which again requires computing type of ``, completing the cycle + = note: ...which immediately requires computing type of `` again note: cycle used when collecting item types in top-level module --> $DIR/resolve-self-in-impl.rs:1:1 | @@ -80,7 +80,7 @@ error[E0391]: cycle detected when computing trait implemented by ` for S {} | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: ...which again requires computing trait implemented by ``, completing the cycle + = note: ...which immediately requires computing trait implemented by `` again note: cycle used when collecting item types in top-level module --> $DIR/resolve-self-in-impl.rs:1:1 | From cd0fc444fb0edb4df0bd8091706d3819313a9df4 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 19 Aug 2021 20:30:33 -0700 Subject: [PATCH 2/6] Note that type aliases cannot be recursive --- compiler/rustc_query_impl/src/keys.rs | 13 +++++++++ compiler/rustc_query_impl/src/lib.rs | 2 ++ compiler/rustc_query_impl/src/plumbing.rs | 7 ++++- compiler/rustc_query_impl/src/util.rs | 18 ++++++++++++ compiler/rustc_query_system/src/query/job.rs | 14 ++++++++- compiler/rustc_query_system/src/query/mod.rs | 29 +++++++++++++++++++ .../infinite-vec-type-recursion.stderr | 3 ++ 7 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 compiler/rustc_query_impl/src/util.rs diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs index 38ab26d66ac6a..40b820c8d8eed 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 { + 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 { + 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 { + Some(*self) + } } impl Key for ty::WithOptConstParam { diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 5022bf265328a..bb0e65111596c 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 5774d021373bb..476085c8725ea 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::() }; - 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 0000000000000..517c107b5d9af --- /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 b7ac42546dda3..f8ba0babab08a 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 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 7288aaef8f20b..dffe7f3689ff4 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, + /// 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, /// 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, + def_kind: Option, _hash: impl FnOnce() -> u64, ) -> Self { Self { name, description, span, + def_kind, #[cfg(parallel_compiler)] hash: _hash(), } diff --git a/src/test/ui/infinite/infinite-vec-type-recursion.stderr b/src/test/ui/infinite/infinite-vec-type-recursion.stderr index d9039243f8d92..1e487a5b11c2a 100644 --- a/src/test/ui/infinite/infinite-vec-type-recursion.stderr +++ b/src/test/ui/infinite/infinite-vec-type-recursion.stderr @@ -5,6 +5,9 @@ LL | type X = Vec; | ^ | = note: ...which immediately requires expanding type alias `X` again + = note: type aliases cannot be recursive + = help: consider using a struct, enum, or union instead to break the cycle + = help: see for more information note: cycle used when collecting item types in top-level module --> $DIR/infinite-vec-type-recursion.rs:1:1 | From bf360dc2729780084de0035aeb7047288a3b5f9d Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sat, 21 Aug 2021 13:14:13 -0700 Subject: [PATCH 3/6] Add test of recursive trait aliases --- .../infinite-trait-alias-recursion.rs | 10 +++++ .../infinite-trait-alias-recursion.stderr | 41 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 src/test/ui/infinite/infinite-trait-alias-recursion.rs create mode 100644 src/test/ui/infinite/infinite-trait-alias-recursion.stderr diff --git a/src/test/ui/infinite/infinite-trait-alias-recursion.rs b/src/test/ui/infinite/infinite-trait-alias-recursion.rs new file mode 100644 index 0000000000000..ec86744e68c53 --- /dev/null +++ b/src/test/ui/infinite/infinite-trait-alias-recursion.rs @@ -0,0 +1,10 @@ +#![feature(trait_alias)] + +trait T1 = T2; +//~^ ERROR cycle detected when computing the super predicates of `T1` + +trait T2 = T3; + +trait T3 = T1 + T3; + +fn main() {} diff --git a/src/test/ui/infinite/infinite-trait-alias-recursion.stderr b/src/test/ui/infinite/infinite-trait-alias-recursion.stderr new file mode 100644 index 0000000000000..c8e67740d7902 --- /dev/null +++ b/src/test/ui/infinite/infinite-trait-alias-recursion.stderr @@ -0,0 +1,41 @@ +error[E0391]: cycle detected when computing the super predicates of `T1` + --> $DIR/infinite-trait-alias-recursion.rs:3:1 + | +LL | trait T1 = T2; + | ^^^^^^^^^^^^^^ + | +note: ...which requires computing the super traits of `T1`... + --> $DIR/infinite-trait-alias-recursion.rs:3:12 + | +LL | trait T1 = T2; + | ^^ +note: ...which requires computing the super predicates of `T2`... + --> $DIR/infinite-trait-alias-recursion.rs:6:1 + | +LL | trait T2 = T3; + | ^^^^^^^^^^^^^^ +note: ...which requires computing the super traits of `T2`... + --> $DIR/infinite-trait-alias-recursion.rs:6:12 + | +LL | trait T2 = T3; + | ^^ +note: ...which requires computing the super predicates of `T3`... + --> $DIR/infinite-trait-alias-recursion.rs:8:1 + | +LL | trait T3 = T1 + T3; + | ^^^^^^^^^^^^^^^^^^^ +note: ...which requires computing the super traits of `T3`... + --> $DIR/infinite-trait-alias-recursion.rs:8:12 + | +LL | trait T3 = T1 + T3; + | ^^ + = note: ...which again requires computing the super predicates of `T1`, completing the cycle +note: cycle used when collecting item types in top-level module + --> $DIR/infinite-trait-alias-recursion.rs:3:1 + | +LL | trait T1 = T2; + | ^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. From c8619647359903a707891e7d40f68264d1e6ed94 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sat, 21 Aug 2021 14:19:59 -0700 Subject: [PATCH 4/6] Note that trait aliases cannot be recursive --- compiler/rustc_query_impl/src/keys.rs | 4 +++ compiler/rustc_query_system/src/query/job.rs | 25 ++++++++++++------- .../infinite-trait-alias-recursion.stderr | 1 + 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs index 40b820c8d8eed..88ab7597eac1a 100644 --- a/compiler/rustc_query_impl/src/keys.rs +++ b/compiler/rustc_query_impl/src/keys.rs @@ -178,6 +178,10 @@ impl Key for (DefId, Option) { fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.0) } + #[inline(always)] + fn key_as_def_id(&self) -> Option { + Some(self.0) + } } impl Key for (DefId, LocalDefId, Ident) { diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index f8ba0babab08a..63a8f0624759c 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -600,16 +600,23 @@ 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) - }) + if 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 for more information"); + }) { + if stack.iter().all(|entry| { + entry + .query + .def_kind + .map_or(false, |def_kind| matches!(def_kind, SimpleDefKind::TyAlias)) + }) { + err.note("type aliases cannot be recursive"); + err.help("consider using a struct, enum, or union instead to break the cycle"); + err.help("see for more information"); + } else { + err.note("trait aliases cannot be recursive"); + } } if let Some((span, query)) = usage { diff --git a/src/test/ui/infinite/infinite-trait-alias-recursion.stderr b/src/test/ui/infinite/infinite-trait-alias-recursion.stderr index c8e67740d7902..5ecaedb3cb2cd 100644 --- a/src/test/ui/infinite/infinite-trait-alias-recursion.stderr +++ b/src/test/ui/infinite/infinite-trait-alias-recursion.stderr @@ -30,6 +30,7 @@ note: ...which requires computing the super traits of `T3`... LL | trait T3 = T1 + T3; | ^^ = note: ...which again requires computing the super predicates of `T1`, completing the cycle + = note: trait aliases cannot be recursive note: cycle used when collecting item types in top-level module --> $DIR/infinite-trait-alias-recursion.rs:3:1 | From c3df8328241bc0b10a5a77fae532aec795869c20 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sat, 21 Aug 2021 14:37:24 -0700 Subject: [PATCH 5/6] Add test for type alias mutual recursion --- .../infinite-type-alias-mutual-recursion.rs | 6 ++++ ...nfinite-type-alias-mutual-recursion.stderr | 34 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/test/ui/infinite/infinite-type-alias-mutual-recursion.rs create mode 100644 src/test/ui/infinite/infinite-type-alias-mutual-recursion.stderr diff --git a/src/test/ui/infinite/infinite-type-alias-mutual-recursion.rs b/src/test/ui/infinite/infinite-type-alias-mutual-recursion.rs new file mode 100644 index 0000000000000..5381eedcfacfc --- /dev/null +++ b/src/test/ui/infinite/infinite-type-alias-mutual-recursion.rs @@ -0,0 +1,6 @@ +type X1 = X2; +//~^ ERROR cycle detected when expanding type alias `X1` +type X2 = X3; +type X3 = X1; + +fn main() {} diff --git a/src/test/ui/infinite/infinite-type-alias-mutual-recursion.stderr b/src/test/ui/infinite/infinite-type-alias-mutual-recursion.stderr new file mode 100644 index 0000000000000..7f82b294434f1 --- /dev/null +++ b/src/test/ui/infinite/infinite-type-alias-mutual-recursion.stderr @@ -0,0 +1,34 @@ +error[E0391]: cycle detected when expanding type alias `X1` + --> $DIR/infinite-type-alias-mutual-recursion.rs:1:11 + | +LL | type X1 = X2; + | ^^ + | +note: ...which requires expanding type alias `X2`... + --> $DIR/infinite-type-alias-mutual-recursion.rs:3:11 + | +LL | type X2 = X3; + | ^^ +note: ...which requires expanding type alias `X3`... + --> $DIR/infinite-type-alias-mutual-recursion.rs:4:11 + | +LL | type X3 = X1; + | ^^ + = note: ...which again requires expanding type alias `X1`, completing the cycle + = note: type aliases cannot be recursive + = help: consider using a struct, enum, or union instead to break the cycle + = help: see for more information +note: cycle used when collecting item types in top-level module + --> $DIR/infinite-type-alias-mutual-recursion.rs:1:1 + | +LL | / type X1 = X2; +LL | | +LL | | type X2 = X3; +LL | | type X3 = X1; +LL | | +LL | | fn main() {} + | |____________^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. From d96234bed72e1935d8ab9a0c7a7e70027c86ad77 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sun, 29 Aug 2021 19:02:47 -0700 Subject: [PATCH 6/6] Retrieve `DefKind` from HIR map to reduce chance of cycles `tcx.def_kind()` could theoretically invoke another query, which could cause an infinite query loop. Accessing the HIR map directly makes that less likely to happen. I also changed it to use `as_local()` (`tcx.def_kind()` seems to implicitly call `expect_local()`) and `opt_def_kind()` to reduce the chance of panicking on valid code. --- compiler/rustc_query_impl/src/plumbing.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 476085c8725ea..90a6ba474b405 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -338,10 +338,12 @@ macro_rules! define_queries { 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 def_kind = def_id + .and_then(|def_id| def_id.as_local()) + // Use `tcx.hir().opt_def_kind()` to reduce the chance of + // accidentally triggering an infinite query loop. + .and_then(|def_id| tcx.hir().opt_def_kind(def_id)) + .map(|def_kind| $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();