1
Fork 0

Rollup merge of #115294 - compiler-errors:cycle-err, r=oli-obk

More precisely detect cycle errors from type_of on opaque

Not sure if this still needs work. Just putting it up for initial impressions, since it seems that a few people are frustrated with the increased error verbosity due to #113320.

Essentially we introduce a new sub-query for `type_of` specifically for opaques which returns a value that is able to distinguish "has errors" from "due to cycle recovery".

Fixes #115188

r? `@oli-obk`
This commit is contained in:
Matthias Krüger 2023-08-28 19:53:56 +02:00 committed by GitHub
commit b4c63f06e8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 297 additions and 309 deletions

View file

@ -56,6 +56,7 @@ pub fn provide(providers: &mut Providers) {
resolve_bound_vars::provide(providers);
*providers = Providers {
type_of: type_of::type_of,
type_of_opaque: type_of::type_of_opaque,
item_bounds: item_bounds::item_bounds,
explicit_item_bounds: item_bounds::explicit_item_bounds,
generics_of: generics_of::generics_of,

View file

@ -1,7 +1,8 @@
use rustc_errors::{Applicability, StashKey};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::HirId;
use rustc_middle::query::plumbing::CyclePlaceholder;
use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
@ -388,86 +389,62 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
}
},
Node::Item(item) => {
match item.kind {
ItemKind::Static(ty, .., body_id) => {
if is_suggestable_infer_ty(ty) {
infer_placeholder_type(
tcx,
def_id,
body_id,
ty.span,
item.ident,
"static variable",
)
} else {
icx.to_ty(ty)
}
}
ItemKind::Const(ty, _, body_id) => {
if is_suggestable_infer_ty(ty) {
infer_placeholder_type(
tcx, def_id, body_id, ty.span, item.ident, "constant",
)
} else {
icx.to_ty(ty)
}
}
ItemKind::TyAlias(self_ty, _) => icx.to_ty(self_ty),
ItemKind::Impl(hir::Impl { self_ty, .. }) => match self_ty.find_self_aliases() {
spans if spans.len() > 0 => {
let guar = tcx.sess.emit_err(crate::errors::SelfInImplSelf {
span: spans.into(),
note: (),
});
Ty::new_error(tcx, guar)
}
_ => icx.to_ty(*self_ty),
},
ItemKind::Fn(..) => {
let args = ty::GenericArgs::identity_for_item(tcx, def_id);
Ty::new_fn_def(tcx, def_id.to_def_id(), args)
}
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
let def = tcx.adt_def(def_id);
let args = ty::GenericArgs::identity_for_item(tcx, def_id);
Ty::new_adt(tcx, def, args)
}
ItemKind::OpaqueTy(OpaqueTy {
origin: hir::OpaqueTyOrigin::TyAlias { .. },
..
}) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id),
// Opaque types desugared from `impl Trait`.
ItemKind::OpaqueTy(&OpaqueTy {
origin:
hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner),
in_trait,
..
}) => {
if in_trait && !tcx.defaultness(owner).has_value() {
span_bug!(
tcx.def_span(def_id),
"tried to get type of this RPITIT with no definition"
);
}
opaque::find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
}
ItemKind::Trait(..)
| ItemKind::TraitAlias(..)
| ItemKind::Macro(..)
| ItemKind::Mod(..)
| ItemKind::ForeignMod { .. }
| ItemKind::GlobalAsm(..)
| ItemKind::ExternCrate(..)
| ItemKind::Use(..) => {
span_bug!(
item.span,
"compute_type_of_item: unexpected item type: {:?}",
item.kind
);
Node::Item(item) => match item.kind {
ItemKind::Static(ty, .., body_id) => {
if is_suggestable_infer_ty(ty) {
infer_placeholder_type(
tcx,
def_id,
body_id,
ty.span,
item.ident,
"static variable",
)
} else {
icx.to_ty(ty)
}
}
}
ItemKind::Const(ty, _, body_id) => {
if is_suggestable_infer_ty(ty) {
infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant")
} else {
icx.to_ty(ty)
}
}
ItemKind::TyAlias(self_ty, _) => icx.to_ty(self_ty),
ItemKind::Impl(hir::Impl { self_ty, .. }) => match self_ty.find_self_aliases() {
spans if spans.len() > 0 => {
let guar = tcx
.sess
.emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: () });
Ty::new_error(tcx, guar)
}
_ => icx.to_ty(*self_ty),
},
ItemKind::Fn(..) => {
let args = ty::GenericArgs::identity_for_item(tcx, def_id);
Ty::new_fn_def(tcx, def_id.to_def_id(), args)
}
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
let def = tcx.adt_def(def_id);
let args = ty::GenericArgs::identity_for_item(tcx, def_id);
Ty::new_adt(tcx, def, args)
}
ItemKind::OpaqueTy(..) => tcx.type_of_opaque(def_id).map_or_else(
|CyclePlaceholder(guar)| Ty::new_error(tcx, guar),
|ty| ty.instantiate_identity(),
),
ItemKind::Trait(..)
| ItemKind::TraitAlias(..)
| ItemKind::Macro(..)
| ItemKind::Mod(..)
| ItemKind::ForeignMod { .. }
| ItemKind::GlobalAsm(..)
| ItemKind::ExternCrate(..)
| ItemKind::Use(..) => {
span_bug!(item.span, "compute_type_of_item: unexpected item type: {:?}", item.kind);
}
},
Node::ForeignItem(foreign_item) => match foreign_item.kind {
ForeignItemKind::Fn(..) => {
@ -514,6 +491,51 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
ty::EarlyBinder::bind(output)
}
pub(super) fn type_of_opaque(
tcx: TyCtxt<'_>,
def_id: DefId,
) -> Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
if let Some(def_id) = def_id.as_local() {
use rustc_hir::*;
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
Ok(ty::EarlyBinder::bind(match tcx.hir().get(hir_id) {
Node::Item(item) => match item.kind {
ItemKind::OpaqueTy(OpaqueTy {
origin: hir::OpaqueTyOrigin::TyAlias { .. },
..
}) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id),
// Opaque types desugared from `impl Trait`.
ItemKind::OpaqueTy(&OpaqueTy {
origin:
hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner),
in_trait,
..
}) => {
if in_trait && !tcx.defaultness(owner).has_value() {
span_bug!(
tcx.def_span(def_id),
"tried to get type of this RPITIT with no definition"
);
}
opaque::find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
}
_ => {
span_bug!(item.span, "type_of_opaque: unexpected item type: {:?}", item.kind);
}
},
x => {
bug!("unexpected sort of node in type_of_opaque(): {:?}", x);
}
}))
} else {
// Foreign opaque type will go through the foreign provider
// and load the type from metadata.
Ok(tcx.type_of(def_id))
}
}
fn infer_placeholder_type<'a>(
tcx: TyCtxt<'a>,
def_id: LocalDefId,

View file

@ -1,4 +1,5 @@
use crate::mir;
use crate::query::CyclePlaceholder;
use crate::traits;
use crate::ty::{self, Ty};
use std::mem::{size_of, transmute_copy, MaybeUninit};
@ -142,6 +143,10 @@ impl EraseType for Result<&'_ ty::List<Ty<'_>>, ty::util::AlwaysRequiresDrop> {
[u8; size_of::<Result<&'static ty::List<Ty<'static>>, ty::util::AlwaysRequiresDrop>>()];
}
impl EraseType for Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
type Result = [u8; size_of::<Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder>>()];
}
impl<T> EraseType for Option<&'_ T> {
type Result = [u8; size_of::<Option<&'static ()>>()];
}

View file

@ -26,7 +26,7 @@ use crate::mir::interpret::{
use crate::mir::interpret::{LitToConstError, LitToConstInput};
use crate::mir::mono::CodegenUnit;
use crate::query::erase::{erase, restore, Erase};
use crate::query::plumbing::{query_ensure, query_get_at, DynamicQuery};
use crate::query::plumbing::{query_ensure, query_get_at, CyclePlaceholder, DynamicQuery};
use crate::thir;
use crate::traits::query::{
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
@ -243,6 +243,16 @@ rustc_queries! {
feedable
}
/// Specialized instance of `type_of` that detects cycles that are due to
/// revealing opaque because of an auto trait bound. Unless `CyclePlaceholder` needs
/// to be handled separately, call `type_of` instead.
query type_of_opaque(key: DefId) -> Result<ty::EarlyBinder<Ty<'tcx>>, CyclePlaceholder> {
desc { |tcx|
"computing type of opaque `{path}`",
path = tcx.def_path_str(key),
}
}
query collect_return_position_impl_trait_in_trait_tys(key: DefId)
-> Result<&'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed>
{

View file

@ -19,7 +19,7 @@ use rustc_query_system::dep_graph::SerializedDepNodeIndex;
pub(crate) use rustc_query_system::query::QueryJobId;
use rustc_query_system::query::*;
use rustc_query_system::HandleCycleError;
use rustc_span::{Span, DUMMY_SP};
use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
use std::ops::Deref;
pub struct QueryKeyStringCache {
@ -52,7 +52,8 @@ pub struct DynamicQuery<'tcx, C: QueryCache> {
pub loadable_from_disk:
fn(tcx: TyCtxt<'tcx>, key: &C::Key, index: SerializedDepNodeIndex) -> bool,
pub hash_result: HashResult<C::Value>,
pub value_from_cycle_error: fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> C::Value,
pub value_from_cycle_error:
fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>], guar: ErrorGuaranteed) -> C::Value,
pub format_value: fn(&C::Value) -> String,
}
@ -629,3 +630,6 @@ impl<'tcx> TyCtxtAt<'tcx> {
.unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id))
}
}
#[derive(Copy, Clone, Debug, HashStable)]
pub struct CyclePlaceholder(pub ErrorGuaranteed);

View file

@ -1,4 +1,5 @@
use crate::dep_graph::DepKind;
use crate::query::plumbing::CyclePlaceholder;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
use rustc_hir as hir;
@ -8,20 +9,38 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_query_system::query::QueryInfo;
use rustc_query_system::Value;
use rustc_span::def_id::LocalDefId;
use rustc_span::Span;
use rustc_span::{ErrorGuaranteed, Span};
use std::fmt::Write;
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Ty<'_> {
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo<DepKind>]) -> Self {
fn from_cycle_error(
tcx: TyCtxt<'tcx>,
_: &[QueryInfo<DepKind>],
guar: ErrorGuaranteed,
) -> Self {
// SAFETY: This is never called when `Self` is not `Ty<'tcx>`.
// FIXME: Represent the above fact in the trait system somehow.
unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(Ty::new_misc_error(tcx)) }
unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(Ty::new_error(tcx, guar)) }
}
}
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
fn from_cycle_error(
_tcx: TyCtxt<'tcx>,
_: &[QueryInfo<DepKind>],
guar: ErrorGuaranteed,
) -> Self {
Err(CyclePlaceholder(guar))
}
}
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::SymbolName<'_> {
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo<DepKind>]) -> Self {
fn from_cycle_error(
tcx: TyCtxt<'tcx>,
_: &[QueryInfo<DepKind>],
_guar: ErrorGuaranteed,
) -> Self {
// SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`.
// FIXME: Represent the above fact in the trait system somehow.
unsafe {
@ -33,8 +52,12 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::SymbolName<'_> {
}
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::Binder<'_, ty::FnSig<'_>> {
fn from_cycle_error(tcx: TyCtxt<'tcx>, stack: &[QueryInfo<DepKind>]) -> Self {
let err = Ty::new_misc_error(tcx);
fn from_cycle_error(
tcx: TyCtxt<'tcx>,
stack: &[QueryInfo<DepKind>],
guar: ErrorGuaranteed,
) -> Self {
let err = Ty::new_error(tcx, guar);
let arity = if let Some(frame) = stack.get(0)
&& frame.query.dep_kind == DepKind::fn_sig
@ -63,7 +86,11 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::Binder<'_, ty::FnSig<'_>> {
}
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability {
fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
fn from_cycle_error(
tcx: TyCtxt<'tcx>,
cycle: &[QueryInfo<DepKind>],
_guar: ErrorGuaranteed,
) -> Self {
let mut item_and_field_ids = Vec::new();
let mut representable_ids = FxHashSet::default();
for info in cycle {
@ -95,22 +122,35 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability {
}
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<Ty<'_>> {
fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle))
fn from_cycle_error(
tcx: TyCtxt<'tcx>,
cycle: &[QueryInfo<DepKind>],
guar: ErrorGuaranteed,
) -> Self {
ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle, guar))
}
}
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> {
fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle))
fn from_cycle_error(
tcx: TyCtxt<'tcx>,
cycle: &[QueryInfo<DepKind>],
guar: ErrorGuaranteed,
) -> Self {
ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle, guar))
}
}
impl<'tcx, T> Value<TyCtxt<'tcx>, DepKind> for Result<T, &'_ ty::layout::LayoutError<'_>> {
fn from_cycle_error(_tcx: TyCtxt<'tcx>, _cycle: &[QueryInfo<DepKind>]) -> Self {
fn from_cycle_error(
_tcx: TyCtxt<'tcx>,
_cycle: &[QueryInfo<DepKind>],
_guar: ErrorGuaranteed,
) -> Self {
// tcx.arena.alloc cannot be used because we are not allowed to use &'tcx LayoutError under
// min_specialization. Since this is an error path anyways, leaking doesn't matter (and really,
// tcx.arena.alloc is pretty much equal to leaking).
// FIXME: `Cycle` should carry the ErrorGuaranteed
Err(Box::leak(Box::new(ty::layout::LayoutError::Cycle)))
}
}

View file

@ -41,7 +41,7 @@ use rustc_query_system::query::{
};
use rustc_query_system::HandleCycleError;
use rustc_query_system::Value;
use rustc_span::Span;
use rustc_span::{ErrorGuaranteed, Span};
#[macro_use]
mod plumbing;
@ -146,8 +146,9 @@ where
self,
tcx: TyCtxt<'tcx>,
cycle: &[QueryInfo<DepKind>],
guar: ErrorGuaranteed,
) -> Self::Value {
(self.dynamic.value_from_cycle_error)(tcx, cycle)
(self.dynamic.value_from_cycle_error)(tcx, cycle, guar)
}
#[inline(always)]

View file

@ -605,8 +605,8 @@ macro_rules! define_queries {
} {
|_tcx, _key, _prev_index, _index| None
}),
value_from_cycle_error: |tcx, cycle| {
let result: queries::$name::Value<'tcx> = Value::from_cycle_error(tcx, cycle);
value_from_cycle_error: |tcx, cycle, guar| {
let result: queries::$name::Value<'tcx> = Value::from_cycle_error(tcx, cycle, guar);
erase(result)
},
loadable_from_disk: |_tcx, _key, _index| {

View file

@ -8,6 +8,7 @@ use crate::query::DepNodeIndex;
use crate::query::{QueryContext, QueryInfo, QueryState};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_span::ErrorGuaranteed;
use std::fmt::Debug;
use std::hash::Hash;
@ -57,6 +58,7 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy {
self,
tcx: Qcx::DepContext,
cycle: &[QueryInfo<Qcx::DepKind>],
guar: ErrorGuaranteed,
) -> Self::Value;
fn anon(self) -> bool;

View file

@ -148,8 +148,8 @@ where
use HandleCycleError::*;
match query.handle_cycle_error() {
Error => {
error.emit();
query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle)
let guar = error.emit();
query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle, guar)
}
Fatal => {
error.emit();
@ -157,8 +157,8 @@ where
unreachable!()
}
DelayBug => {
error.delay_as_bug();
query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle)
let guar = error.delay_as_bug();
query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle, guar)
}
}
}

View file

@ -1,12 +1,14 @@
use rustc_span::ErrorGuaranteed;
use crate::dep_graph::{DepContext, DepKind};
use crate::query::QueryInfo;
pub trait Value<Tcx: DepContext, D: DepKind>: Sized {
fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo<D>]) -> Self;
fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo<D>], guar: ErrorGuaranteed) -> Self;
}
impl<Tcx: DepContext, T, D: DepKind> Value<Tcx, D> for T {
default fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo<D>]) -> T {
default fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo<D>], _guar: ErrorGuaranteed) -> T {
tcx.sess().abort_if_errors();
// Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's
// non-trivial to define it earlier.

View file

@ -2346,14 +2346,15 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
}
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
let ty = self.tcx().type_of(def_id);
if ty.skip_binder().references_error() {
return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id));
}
// We can resolve the `impl Trait` to its concrete type,
// which enforces a DAG between the functions requiring
// the auto trait bounds in question.
t.rebind(vec![ty.instantiate(self.tcx(), args)])
match self.tcx().type_of_opaque(def_id) {
Ok(ty) => t.rebind(vec![ty.instantiate(self.tcx(), args)]),
Err(_) => {
return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id));
}
}
}
})
}