Auto merge of #153383 - nnethercote:overhaul-ensure_ok, r=Zalathar

Overhaul `ensure_ok`

The interaction of `ensure_ok` and the `return_result_from_ensure_ok` query modifier is weird and hacky. This PR cleans it up. Details in the individual commits.

r? @Zalathar
This commit is contained in:
bors
2026-03-08 07:03:35 +00:00
29 changed files with 151 additions and 149 deletions
@@ -294,7 +294,7 @@ fn has_ambiguous_copy(&mut self, ty: Ty<'tcx>) -> bool {
// Avoid bogus move errors because of an incoherent `Copy` impl.
self.infcx.type_implements_trait(copy_def_id, [ty], self.infcx.param_env).may_apply()
&& self.infcx.tcx.coherent_trait(copy_def_id).is_err()
&& self.infcx.tcx.ensure_result().coherent_trait(copy_def_id).is_err()
}
fn report_cannot_move_from_static(&mut self, place: Place<'tcx>, span: Span) -> Diag<'infcx> {
+1 -1
View File
@@ -121,7 +121,7 @@ fn mir_borrowck(
// We should eagerly check stalled coroutine obligations from HIR typeck.
// Not doing so leads to silent normalization failures later, which will
// fail to register opaque types in the next solver.
tcx.check_coroutine_obligations(def)?;
tcx.ensure_result().check_coroutine_obligations(def)?;
let input_body: &Body<'_> = &input_body.borrow();
if let Some(guar) = input_body.tainted_by_errors {
@@ -334,7 +334,7 @@ fn check_static(&mut self, def_id: DefId, span: Span) {
self.tcx.dcx().span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef`");
}
if let Some(def_id) = def_id.as_local()
&& let Err(guar) = self.tcx.ensure_ok().check_well_formed(hir::OwnerId { def_id })
&& let Err(guar) = self.tcx.ensure_result().check_well_formed(hir::OwnerId { def_id })
{
self.error_emitted = Some(guar);
}
@@ -52,7 +52,7 @@ pub(crate) fn check_drop_impl(
}
}
tcx.ensure_ok().orphan_check_impl(drop_impl_did)?;
tcx.ensure_result().orphan_check_impl(drop_impl_did)?;
let self_ty = tcx.type_of(drop_impl_did).instantiate_identity();
@@ -96,7 +96,7 @@ pub(crate) fn check_negative_auto_trait_impl<'tcx>(
tcx.dcx().span_delayed_bug(tcx.def_span(impl_def_id), "default impl cannot be negative");
}
tcx.ensure_ok().orphan_check_impl(impl_def_id)?;
tcx.ensure_result().orphan_check_impl(impl_def_id)?;
match impl_trait_ref.self_ty().kind() {
ty::Adt(adt_def, adt_to_impl_args) => {
@@ -825,7 +825,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
if of_trait {
let impl_trait_header = tcx.impl_trait_header(def_id);
res = res.and(
tcx.ensure_ok()
tcx.ensure_result()
.coherent_trait(impl_trait_header.trait_ref.instantiate_identity().def_id),
);
@@ -1256,8 +1256,7 @@ fn check_impl_items_against_trait<'tcx>(
Err(ErrorGuaranteed { .. }) => continue,
};
let res = tcx.ensure_ok().compare_impl_item(impl_item.expect_local());
let res = tcx.ensure_result().compare_impl_item(impl_item.expect_local());
if res.is_ok() {
match ty_impl_item.kind {
ty::AssocKind::Fn { .. } => {
@@ -2458,7 +2458,7 @@ pub(super) fn check_type_bounds<'tcx>(
) -> Result<(), ErrorGuaranteed> {
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
// other `Foo` impls are incoherent.
tcx.ensure_ok().coherent_trait(impl_trait_ref.def_id)?;
tcx.ensure_result().coherent_trait(impl_trait_ref.def_id)?;
let param_env = tcx.param_env(impl_ty.def_id);
debug!(?param_env);
@@ -936,7 +936,7 @@ pub(crate) fn check_associated_item(
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
// other `Foo` impls are incoherent.
tcx.ensure_ok().coherent_trait(tcx.parent(item.trait_item_or_self()?))?;
tcx.ensure_result().coherent_trait(tcx.parent(item.trait_item_or_self()?))?;
let self_ty = match item.container {
ty::AssocContainer::Trait => tcx.types.self_param,
@@ -1328,9 +1328,9 @@ fn check_impl<'tcx>(
// therefore don't need to be WF (the trait's `Self: Trait` predicate
// won't hold).
let trait_ref = tcx.impl_trait_ref(item.owner_id).instantiate_identity();
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
// other `Foo` impls are incoherent.
tcx.ensure_ok().coherent_trait(trait_ref.def_id)?;
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in
// case other `Foo` impls are incoherent.
tcx.ensure_result().coherent_trait(trait_ref.def_id)?;
let trait_span = of_trait.trait_ref.path.span;
let trait_ref = wfcx.deeply_normalize(
trait_span,
@@ -2334,15 +2334,22 @@ fn check_false_global_bounds(&mut self) {
pub(super) fn check_type_wf(tcx: TyCtxt<'_>, (): ()) -> Result<(), ErrorGuaranteed> {
let items = tcx.hir_crate_items(());
let res = items
.par_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id))
.and(items.par_impl_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)))
.and(items.par_trait_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)))
.and(
items.par_foreign_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)),
)
.and(items.par_nested_bodies(|item| tcx.ensure_ok().check_well_formed(item)))
.and(items.par_opaques(|item| tcx.ensure_ok().check_well_formed(item)));
let res =
items
.par_items(|item| tcx.ensure_result().check_well_formed(item.owner_id.def_id))
.and(
items.par_impl_items(|item| {
tcx.ensure_result().check_well_formed(item.owner_id.def_id)
}),
)
.and(items.par_trait_items(|item| {
tcx.ensure_result().check_well_formed(item.owner_id.def_id)
}))
.and(items.par_foreign_items(|item| {
tcx.ensure_result().check_well_formed(item.owner_id.def_id)
}))
.and(items.par_nested_bodies(|item| tcx.ensure_result().check_well_formed(item)))
.and(items.par_opaques(|item| tcx.ensure_result().check_well_formed(item)));
super::entry::check_for_entry_fn(tcx);
res
@@ -226,7 +226,7 @@ fn visit_implementation_of_coerce_unsized(checker: &Checker<'_>) -> Result<(), E
// Just compute this for the side-effects, in particular reporting
// errors; other parts of the code may demand it for the info of
// course.
tcx.ensure_ok().coerce_unsized_info(impl_did)
tcx.ensure_result().coerce_unsized_info(impl_did)
}
fn is_from_coerce_pointee_derive(tcx: TyCtxt<'_>, span: Span) -> bool {
@@ -259,7 +259,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
tcx.require_lang_item(LangItem::CoerceUnsized, span),
source,
|impl_def_id| {
res = res.and(tcx.ensure_ok().coerce_unsized_info(impl_def_id));
res = res.and(tcx.ensure_result().coerce_unsized_info(impl_def_id));
},
);
res?;
@@ -160,7 +160,7 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed>
}
// Trigger building the specialization graph for the trait. This will detect and report any
// overlap errors.
let mut res = tcx.ensure_ok().specialization_graph_of(def_id);
let mut res = tcx.ensure_result().specialization_graph_of(def_id);
for &impl_def_id in impls {
let impl_header = tcx.impl_trait_header(impl_def_id);
@@ -171,7 +171,7 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed>
.and(check_impl(tcx, impl_def_id, trait_ref, trait_def, impl_header.polarity))
.and(check_object_overlap(tcx, impl_def_id, trait_ref))
.and(unsafety::check_item(tcx, impl_def_id, impl_header, trait_def))
.and(tcx.ensure_ok().orphan_check_impl(impl_def_id))
.and(tcx.ensure_result().orphan_check_impl(impl_def_id))
.and(builtin::check_trait(tcx, def_id, impl_def_id, impl_header));
}
@@ -63,7 +63,7 @@ pub(crate) fn check_impl_wf(
// Check that the args are constrained. We queryfied the check for ty/const params
// since unconstrained type/const params cause ICEs in projection, so we want to
// detect those specifically and project those to `TyKind::Error`.
let mut res = tcx.ensure_ok().enforce_impl_non_lifetime_params_are_constrained(impl_def_id);
let mut res = tcx.ensure_result().enforce_impl_non_lifetime_params_are_constrained(impl_def_id);
res = res.and(enforce_impl_lifetime_params_are_constrained(tcx, impl_def_id, of_trait));
if of_trait && tcx.features().min_specialization() {
+4 -4
View File
@@ -172,14 +172,14 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
// what we are intending to discard, to help future type-based refactoring.
type R = Result<(), ErrorGuaranteed>;
let _: R = tcx.ensure_ok().check_type_wf(());
let _: R = tcx.ensure_result().check_type_wf(());
for &trait_def_id in tcx.all_local_trait_impls(()).keys() {
let _: R = tcx.ensure_ok().coherent_trait(trait_def_id);
let _: R = tcx.ensure_result().coherent_trait(trait_def_id);
}
// these queries are executed for side-effects (error reporting):
let _: R = tcx.ensure_ok().crate_inherent_impls_validity_check(());
let _: R = tcx.ensure_ok().crate_inherent_impls_overlap_check(());
let _: R = tcx.ensure_result().crate_inherent_impls_validity_check(());
let _: R = tcx.ensure_result().crate_inherent_impls_overlap_check(());
});
tcx.sess.time("emit_ast_lowering_delayed_lints", || {
+1 -1
View File
@@ -50,7 +50,7 @@ pub(crate) fn check_legal_trait_for_method_call(
};
return Err(tcx.dcx().emit_err(errors::ExplicitDestructorCall { span, sugg }));
}
tcx.ensure_ok().coherent_trait(trait_id)
tcx.ensure_result().coherent_trait(trait_id)
}
#[derive(Debug)]
+1 -1
View File
@@ -778,7 +778,7 @@ fn coerce_unsized_old_solver(
// for local impls, since upstream impls should be valid.
if impl_source.impl_def_id.is_local()
&& let Err(guar) =
self.tcx.ensure_ok().coerce_unsized_info(impl_source.impl_def_id)
self.tcx.ensure_result().coerce_unsized_info(impl_source.impl_def_id)
{
self.fcx.set_tainted_by_errors(guar);
}
+24 -12
View File
@@ -150,7 +150,6 @@ struct QueryModifiers {
eval_always: Option<Ident>,
feedable: Option<Ident>,
no_hash: Option<Ident>,
return_result_from_ensure_ok: Option<Ident>,
separate_provide_extern: Option<Ident>,
// tidy-alphabetical-end
}
@@ -167,7 +166,6 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
let mut depth_limit = None;
let mut separate_provide_extern = None;
let mut feedable = None;
let mut return_result_from_ensure_ok = None;
while !input.is_empty() {
let modifier: Ident = input.parse()?;
@@ -211,8 +209,6 @@ macro_rules! try_insert {
try_insert!(separate_provide_extern = modifier);
} else if modifier == "feedable" {
try_insert!(feedable = modifier);
} else if modifier == "return_result_from_ensure_ok" {
try_insert!(return_result_from_ensure_ok = modifier);
} else {
return Err(Error::new(modifier.span(), "unknown query modifier"));
}
@@ -232,11 +228,29 @@ macro_rules! try_insert {
depth_limit,
separate_provide_extern,
feedable,
return_result_from_ensure_ok,
})
}
fn make_modifiers_stream(query: &Query, modifiers: &QueryModifiers) -> proc_macro2::TokenStream {
// Does `ret_ty` match `Result<_, ErrorGuaranteed>`?
fn returns_error_guaranteed(ret_ty: &ReturnType) -> bool {
use ::syn::*;
if let ReturnType::Type(_, ret_ty) = ret_ty
&& let Type::Path(type_path) = ret_ty.as_ref()
&& let Some(PathSegment { ident, arguments }) = type_path.path.segments.last()
&& ident == "Result"
&& let PathArguments::AngleBracketed(args) = arguments
&& args.args.len() == 2
&& let GenericArgument::Type(ty) = &args.args[1]
&& let Type::Path(type_path) = ty
&& type_path.path.is_ident("ErrorGuaranteed")
{
true
} else {
false
}
}
fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream {
let QueryModifiers {
// tidy-alphabetical-start
anon,
@@ -249,10 +263,9 @@ fn make_modifiers_stream(query: &Query, modifiers: &QueryModifiers) -> proc_macr
eval_always,
feedable,
no_hash,
return_result_from_ensure_ok,
separate_provide_extern,
// tidy-alphabetical-end
} = modifiers;
} = &query.modifiers;
let anon = anon.is_some();
let arena_cache = arena_cache.is_some();
@@ -270,7 +283,7 @@ fn make_modifiers_stream(query: &Query, modifiers: &QueryModifiers) -> proc_macr
let eval_always = eval_always.is_some();
let feedable = feedable.is_some();
let no_hash = no_hash.is_some();
let return_result_from_ensure_ok = return_result_from_ensure_ok.is_some();
let returns_error_guaranteed = returns_error_guaranteed(&query.return_ty);
let separate_provide_extern = separate_provide_extern.is_some();
// Giving an input span to the modifier names in the modifier list seems
@@ -289,7 +302,7 @@ fn make_modifiers_stream(query: &Query, modifiers: &QueryModifiers) -> proc_macr
eval_always: #eval_always,
feedable: #feedable,
no_hash: #no_hash,
return_result_from_ensure_ok: #return_result_from_ensure_ok,
returns_error_guaranteed: #returns_error_guaranteed,
separate_provide_extern: #separate_provide_extern,
// tidy-alphabetical-end
}
@@ -406,7 +419,6 @@ macro_rules! doc_link {
depth_limit,
separate_provide_extern,
feedable,
return_result_from_ensure_ok,
);
let name = &query.name;
@@ -479,7 +491,7 @@ macro_rules! assert {
ReturnType::Type(..) => quote! { #return_ty },
};
let modifiers_stream = make_modifiers_stream(&query, modifiers);
let modifiers_stream = make_modifiers_stream(&query);
// Add the query to the group
query_stream.extend(quote! {
+2 -18
View File
@@ -40,9 +40,6 @@
//! - `depth_limit`: Impose a recursion depth limit on the query to prevent stack overflows.
//! - `separate_provide_extern`: Use separate provider functions for local and external crates.
//! - `feedable`: Allow the query result to be set from another query ("fed" externally).
//! - `return_result_from_ensure_ok`: When called via `tcx.ensure_ok()`, return `Result<(), ErrorGuaranteed>` instead of `()`.
//! If the query needs to be executed and returns an error, the error is returned to the caller.
//! Only valid for queries returning `Result<_, ErrorGuaranteed>`.
//!
//! For the up-to-date list, see the `QueryModifiers` struct in
//! [`rustc_macros/src/query.rs`](https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_macros/src/query.rs)
@@ -717,7 +714,6 @@
query check_coroutine_obligations(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
desc { "verify auto trait bounds for coroutine interior type `{}`", tcx.def_path_str(key) }
return_result_from_ensure_ok
}
/// Used in case `mir_borrowck` fails to prove an obligation. We generally assume that
@@ -1165,9 +1161,8 @@
}
/// Checks well-formedness of tail calls (`become f()`).
query check_tail_calls(key: LocalDefId) -> Result<(), rustc_errors::ErrorGuaranteed> {
query check_tail_calls(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
desc { "tail-call-checking `{}`", tcx.def_path_str(key) }
return_result_from_ensure_ok
}
/// Returns the types assumed to be well formed while "inside" of the given item.
@@ -1239,7 +1234,6 @@
query check_type_wf(key: ()) -> Result<(), ErrorGuaranteed> {
desc { "checking that types are well-formed" }
return_result_from_ensure_ok
}
/// Caches `CoerceUnsized` kinds for impls on custom types.
@@ -1247,7 +1241,6 @@
desc { "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
separate_provide_extern
return_result_from_ensure_ok
}
query typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> {
@@ -1262,7 +1255,6 @@
query coherent_trait(def_id: DefId) -> Result<(), ErrorGuaranteed> {
desc { "coherence checking all impls of trait `{}`", tcx.def_path_str(def_id) }
return_result_from_ensure_ok
}
/// Borrow-checks the given typeck root, e.g. functions, const/static items,
@@ -1294,7 +1286,6 @@
/// </div>
query crate_inherent_impls_validity_check(_: ()) -> Result<(), ErrorGuaranteed> {
desc { "check for inherent impls that should not be defined in crate" }
return_result_from_ensure_ok
}
/// Checks all types in the crate for overlap in their inherent impls. Reports errors.
@@ -1306,7 +1297,6 @@
/// </div>
query crate_inherent_impls_overlap_check(_: ()) -> Result<(), ErrorGuaranteed> {
desc { "check for overlap between inherent impls defined in this crate" }
return_result_from_ensure_ok
}
/// Checks whether all impls in the crate pass the overlap check, returning
@@ -1316,7 +1306,6 @@
"checking whether impl `{}` follows the orphan rules",
tcx.def_path_str(key),
}
return_result_from_ensure_ok
}
/// Return the set of (transitive) callees that may result in a recursive call to `key`,
@@ -1421,9 +1410,8 @@
desc { "converting literal to const" }
}
query check_match(key: LocalDefId) -> Result<(), rustc_errors::ErrorGuaranteed> {
query check_match(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
desc { "match-checking `{}`", tcx.def_path_str(key) }
return_result_from_ensure_ok
}
/// Performs part of the privacy check and computes effective visibilities.
@@ -1652,7 +1640,6 @@
query specialization_graph_of(trait_id: DefId) -> Result<&'tcx specialization_graph::Graph, ErrorGuaranteed> {
desc { "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) }
cache_on_disk_if { true }
return_result_from_ensure_ok
}
query dyn_compatibility_violations(trait_id: DefId) -> &'tcx [DynCompatibilityViolation] {
desc { "determining dyn-compatibility of trait `{}`", tcx.def_path_str(trait_id) }
@@ -1931,12 +1918,10 @@
query check_well_formed(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
desc { "checking that `{}` is well-formed", tcx.def_path_str(key) }
return_result_from_ensure_ok
}
query enforce_impl_non_lifetime_params_are_constrained(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
desc { "checking that `{}`'s generics are constrained by the impl header", tcx.def_path_str(key) }
return_result_from_ensure_ok
}
// The `DefId`s of all non-generic functions and statics in the given crate
@@ -2698,7 +2683,6 @@
/// Any other def id will ICE.
query compare_impl_item(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
desc { "checking assoc item `{}` is compatible with trait definition", tcx.def_path_str(key) }
return_result_from_ensure_ok
}
query deduced_param_attrs(def_id: DefId) -> &'tcx [DeducedParamAttrs] {
+28 -27
View File
@@ -1,7 +1,6 @@
//! Helper functions that serve as the immediate implementation of
//! `tcx.$query(..)` and its variations.
use rustc_data_structures::assert_matches;
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
use crate::dep_graph;
@@ -48,10 +47,10 @@ pub(crate) fn query_get_at<'tcx, C>(
}
}
/// Shared implementation of `tcx.ensure_ok().$query(..)` for most queries,
/// and `tcx.ensure_done().$query(..)` for all queries.
/// Shared implementation of `tcx.ensure_ok().$query(..)` and
/// `tcx.ensure_done().$query(..)` for all queries.
#[inline]
pub(crate) fn query_ensure<'tcx, C>(
pub(crate) fn query_ensure_ok_or_done<'tcx, C>(
tcx: TyCtxt<'tcx>,
query: &'tcx QueryVTable<'tcx, C>,
key: C::Key,
@@ -59,41 +58,43 @@ pub(crate) fn query_ensure<'tcx, C>(
) where
C: QueryCache,
{
if try_get_cached(tcx, &query.cache, &key).is_none() {
(query.execute_query_fn)(tcx, DUMMY_SP, key, QueryMode::Ensure { ensure_mode });
match try_get_cached(tcx, &query.cache, &key) {
Some(_value) => {}
None => {
(query.execute_query_fn)(tcx, DUMMY_SP, key, QueryMode::Ensure { ensure_mode });
}
}
}
/// Shared implementation of `tcx.ensure_ok().$query(..)` for queries that
/// have the `return_result_from_ensure_ok` modifier.
/// Implementation of `tcx.ensure_result().$query(..)` for queries that
/// return `Result<_, ErrorGuaranteed>`.
#[inline]
pub(crate) fn query_ensure_error_guaranteed<'tcx, C, T>(
pub(crate) fn query_ensure_result<'tcx, C, T>(
tcx: TyCtxt<'tcx>,
query: &'tcx QueryVTable<'tcx, C>,
key: C::Key,
// This arg is needed to match the signature of `query_ensure`,
// but should always be `EnsureMode::Ok`.
ensure_mode: EnsureMode,
) -> Result<(), ErrorGuaranteed>
where
C: QueryCache<Value = Erased<Result<T, ErrorGuaranteed>>>,
Result<T, ErrorGuaranteed>: Erasable,
{
assert_matches!(ensure_mode, EnsureMode::Ok);
if let Some(res) = try_get_cached(tcx, &query.cache, &key) {
erase::restore_val(res).map(drop)
} else {
(query.execute_query_fn)(tcx, DUMMY_SP, key, QueryMode::Ensure { ensure_mode })
.map(erase::restore_val)
.map(|res| res.map(drop))
// Either we actually executed the query, which means we got a full `Result`,
// or we can just assume the query succeeded, because it was green in the
// incremental cache. If it is green, that means that the previous compilation
// that wrote to the incremental cache compiles successfully. That is only
// possible if the cache entry was `Ok(())`, so we emit that here, without
// actually encoding the `Result` in the cache or loading it from there.
.unwrap_or(Ok(()))
match try_get_cached(tcx, &query.cache, &key) {
Some(value) => erase::restore_val(value).map(drop),
None => (query.execute_query_fn)(
tcx,
DUMMY_SP,
key,
QueryMode::Ensure { ensure_mode: EnsureMode::Ok },
)
.map(erase::restore_val)
.map(|value| value.map(drop))
// Either we actually executed the query, which means we got a full `Result`,
// or we can just assume the query succeeded, because it was green in the
// incremental cache. If it is green, that means that the previous compilation
// that wrote to the incremental cache compiles successfully. That is only
// possible if the cache entry was `Ok(())`, so we emit that here, without
// actually encoding the `Result` in the cache or loading it from there.
.unwrap_or(Ok(())),
}
}
+1 -1
View File
@@ -5,7 +5,7 @@
pub use self::keys::{AsLocalQueryKey, LocalCrate, QueryKey};
pub use self::plumbing::{
ActiveKeyStatus, CycleError, CycleErrorHandling, EnsureMode, IntoQueryParam, QueryMode,
QueryState, TyCtxtAt, TyCtxtEnsureDone, TyCtxtEnsureOk,
QueryState, TyCtxtAt, TyCtxtEnsureDone, TyCtxtEnsureOk, TyCtxtEnsureResult,
};
pub use self::stack::{QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra};
pub use crate::queries::Providers;
@@ -58,20 +58,6 @@
/// Don't hash the result, instead just mark a query red if it runs
pub(crate) struct no_hash;
/// # `return_result_from_ensure_ok` query modifier
///
/// When this query is called via `tcx.ensure_ok()`, it returns
/// `Result<(), ErrorGuaranteed>` instead of `()`. If the query needs to
/// be executed, and that execution returns an error, the error result is
/// returned to the caller.
///
/// If execution is skipped, a synthetic `Ok(())` is returned, on the
/// assumption that a query with all-green inputs must have succeeded.
///
/// Can only be applied to queries with a return value of
/// `Result<_, ErrorGuaranteed>`.
pub(crate) struct return_result_from_ensure_ok;
/// # `separate_provide_extern` query modifier
///
/// Use a separate query provider for local and extern crates
+41 -28
View File
@@ -208,6 +208,12 @@ pub struct TyCtxtEnsureOk<'tcx> {
pub tcx: TyCtxt<'tcx>,
}
#[derive(Copy, Clone)]
#[must_use]
pub struct TyCtxtEnsureResult<'tcx> {
pub tcx: TyCtxt<'tcx>,
}
#[derive(Copy, Clone)]
#[must_use]
pub struct TyCtxtEnsureDone<'tcx> {
@@ -215,6 +221,8 @@ pub struct TyCtxtEnsureDone<'tcx> {
}
impl<'tcx> TyCtxt<'tcx> {
/// FIXME: `ensure_ok`'s effects are subtle. Is this comment fully accurate?
///
/// Wrapper that calls queries in a special "ensure OK" mode, for callers
/// that don't need the return value and just want to invoke a query for
/// its potential side-effect of emitting fatal errors.
@@ -235,17 +243,21 @@ impl<'tcx> TyCtxt<'tcx> {
///
/// Therefore, this call mode is not appropriate for callers that want to
/// ensure that the query is _never_ executed in the future.
///
/// ## `return_result_from_ensure_ok`
/// If a query has the `return_result_from_ensure_ok` modifier, calls via
/// `ensure_ok` will instead return `Result<(), ErrorGuaranteed>`. If the
/// query needs to be executed, and execution returns an error, that error
/// is returned to the caller.
#[inline(always)]
pub fn ensure_ok(self) -> TyCtxtEnsureOk<'tcx> {
TyCtxtEnsureOk { tcx: self }
}
/// This is a variant of `ensure_ok` only usable with queries that return
/// `Result<_, ErrorGuaranteed>`. Queries calls through this function will
/// return `Result<(), ErrorGuaranteed>`. I.e. the error status is returned
/// but nothing else. As with `ensure_ok`, this can be more efficient than
/// a normal query call.
#[inline(always)]
pub fn ensure_result(self) -> TyCtxtEnsureResult<'tcx> {
TyCtxtEnsureResult { tcx: self }
}
/// Wrapper that calls queries in a special "ensure done" mode, for callers
/// that don't need the return value and just want to guarantee that the
/// query won't be executed in the future, by executing it now if necessary.
@@ -299,7 +311,7 @@ fn $name:ident($($K:tt)*) -> $V:ty
eval_always: $eval_always:literal,
feedable: $feedable:literal,
no_hash: $no_hash:literal,
return_result_from_ensure_ok: $return_result_from_ensure_ok:literal,
returns_error_guaranteed: $returns_error_guaranteed:literal,
separate_provide_extern: $separate_provide_extern:literal,
}
)*
@@ -325,15 +337,6 @@ pub mod $name {
#[cfg(not($separate_provide_extern))]
pub type LocalKey<'tcx> = Key<'tcx>;
/// Return type of the `.ensure_ok()` method for this query,
/// which has the `return_result_from_ensure_ok` modifier.
#[cfg($return_result_from_ensure_ok)]
pub type EnsureOkReturnType = Result<(), rustc_errors::ErrorGuaranteed>;
/// Return type of the `.ensure_ok()` method for this query,
/// which does _not_ have the `return_result_from_ensure_ok` modifier.
#[cfg(not($return_result_from_ensure_ok))]
pub type EnsureOkReturnType = ();
/// Type returned from query providers and loaded from disk-cache.
#[cfg($arena_cache)]
pub type ProvidedValue<'tcx> =
@@ -425,17 +428,8 @@ impl<'tcx> $crate::query::TyCtxtEnsureOk<'tcx> {
$(
$(#[$attr])*
#[inline(always)]
pub fn $name(
self,
key: query_helper_param_ty!($($K)*),
) -> $crate::queries::$name::EnsureOkReturnType {
#[cfg($return_result_from_ensure_ok)]
let ensure_fn = crate::query::inner::query_ensure_error_guaranteed;
#[cfg(not($return_result_from_ensure_ok))]
let ensure_fn = crate::query::inner::query_ensure;
ensure_fn(
pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
crate::query::inner::query_ensure_ok_or_done(
self.tcx,
&self.tcx.query_system.query_vtables.$name,
$crate::query::IntoQueryParam::into_query_param(key),
@@ -445,12 +439,31 @@ pub fn $name(
)*
}
// Only defined when the `ensure_result` modifier is present.
impl<'tcx> $crate::query::TyCtxtEnsureResult<'tcx> {
$(
#[cfg($returns_error_guaranteed)]
$(#[$attr])*
#[inline(always)]
pub fn $name(
self,
key: query_helper_param_ty!($($K)*),
) -> Result<(), rustc_errors::ErrorGuaranteed> {
crate::query::inner::query_ensure_result(
self.tcx,
&self.tcx.query_system.query_vtables.$name,
$crate::query::IntoQueryParam::into_query_param(key),
)
}
)*
}
impl<'tcx> $crate::query::TyCtxtEnsureDone<'tcx> {
$(
$(#[$attr])*
#[inline(always)]
pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
crate::query::inner::query_ensure(
crate::query::inner::query_ensure_ok_or_done(
self.tcx,
&self.tcx.query_system.query_vtables.$name,
$crate::query::IntoQueryParam::into_query_param(key),
+2 -2
View File
@@ -402,7 +402,7 @@ pub fn calculate_dtor(
validate: impl Fn(Self, LocalDefId) -> Result<(), ErrorGuaranteed>,
) -> Option<ty::Destructor> {
let drop_trait = self.lang_items().drop_trait()?;
self.ensure_ok().coherent_trait(drop_trait).ok()?;
self.ensure_result().coherent_trait(drop_trait).ok()?;
let mut dtor_candidate = None;
// `Drop` impls can only be written in the same crate as the adt, and cannot be blanket impls
@@ -449,7 +449,7 @@ pub fn calculate_async_dtor(
validate: impl Fn(Self, LocalDefId) -> Result<(), ErrorGuaranteed>,
) -> Option<ty::AsyncDestructor> {
let async_drop_trait = self.lang_items().async_drop_trait()?;
self.ensure_ok().coherent_trait(async_drop_trait).ok()?;
self.ensure_result().coherent_trait(async_drop_trait).ok()?;
let mut dtor_candidate = None;
// `AsyncDrop` impls can only be written in the same crate as the adt, and cannot be blanket impls
+2 -2
View File
@@ -68,11 +68,11 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>(
/// be called by the query `mir_built`.
pub(crate) fn build_mir_inner_impl<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> {
tcx.ensure_done().thir_abstract_const(def);
if let Err(e) = tcx.ensure_ok().check_match(def) {
if let Err(e) = tcx.ensure_result().check_match(def) {
return construct_error(tcx, def, e);
}
if let Err(err) = tcx.ensure_ok().check_tail_calls(def) {
if let Err(err) = tcx.ensure_result().check_tail_calls(def) {
return construct_error(tcx, def, err);
}
+1 -1
View File
@@ -562,7 +562,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
| DefKind::Static { .. }
| DefKind::Const { .. }
| DefKind::AssocConst { .. } => {
if let Err(guar) = tcx.ensure_ok().check_well_formed(root.expect_local()) {
if let Err(guar) = tcx.ensure_result().check_well_formed(root.expect_local()) {
body.tainted_by_errors = Some(guar);
}
}
@@ -141,7 +141,7 @@ fn $name:ident($K:ty) -> $V:ty
eval_always: $eval_always:literal,
feedable: $feedable:literal,
no_hash: $no_hash:literal,
return_result_from_ensure_ok: $return_result_from_ensure_ok:literal,
returns_error_guaranteed: $returns_error_guaranteed:literal,
separate_provide_extern: $separate_provide_extern:literal,
}
)*
+1 -1
View File
@@ -325,7 +325,7 @@ fn $name:ident($K:ty) -> $V:ty
eval_always: $eval_always:literal,
feedable: $feedable:literal,
no_hash: $no_hash:literal,
return_result_from_ensure_ok: $return_result_from_ensure_ok:literal,
returns_error_guaranteed: $returns_error_guaranteed:literal,
separate_provide_extern: $separate_provide_extern:literal,
}
)*
@@ -185,9 +185,9 @@ pub(super) fn maybe_report_ambiguity(
return e;
}
if let Err(guar) = self.tcx.ensure_ok().coherent_trait(trait_pred.def_id()) {
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
// other `Foo` impls are incoherent.
if let Err(guar) = self.tcx.ensure_result().coherent_trait(trait_pred.def_id()) {
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for
// Foo` in case other `Foo` impls are incoherent.
return guar;
}
@@ -522,7 +522,7 @@ pub(super) fn maybe_report_ambiguity(
if let Err(guar) = self
.tcx
.ensure_ok()
.ensure_result()
.coherent_trait(self.tcx.parent(data.projection_term.def_id))
{
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
@@ -563,7 +563,7 @@ fn decorate<'tcx, G: EmissionGuarantee>(
match used_to_be_allowed {
None => {
let reported = if overlap.with_impl.is_local()
|| tcx.ensure_ok().orphan_check_impl(impl_def_id).is_ok()
|| tcx.ensure_result().orphan_check_impl(impl_def_id).is_ok()
{
let mut err = tcx.dcx().struct_span_err(impl_span, msg());
err.code(E0119);
@@ -367,7 +367,7 @@ pub(crate) fn assoc_def(
// Ensure that the impl is constrained, otherwise projection may give us
// bad unconstrained infer vars.
if let Some(impl_def_id) = impl_def_id.as_local() {
tcx.ensure_ok().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?;
tcx.ensure_result().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?;
}
let item = tcx.associated_item(impl_item_id);
@@ -390,7 +390,7 @@ pub(crate) fn assoc_def(
if let ty::AssocContainer::TraitImpl(_) = assoc_item.item.container
&& let Some(impl_def_id) = assoc_item.item.container_id(tcx).as_local()
{
tcx.ensure_ok().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?;
tcx.ensure_result().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?;
}
Ok(assoc_item)
+1 -1
View File
@@ -230,7 +230,7 @@ fn resolve_associated_item<'tcx>(
if trait_item_id != leaf_def.item.def_id
&& let Some(leaf_def_item) = leaf_def.item.def_id.as_local()
{
tcx.ensure_ok().compare_impl_item(leaf_def_item)?;
tcx.ensure_result().compare_impl_item(leaf_def_item)?;
}
Some(ty::Instance::new_raw(leaf_def.item.def_id, args))
+1 -1
View File
@@ -351,7 +351,7 @@ pub(crate) fn run_global_ctxt(
// (see `override_queries` in the `config`)
// NOTE: These are copy/pasted from typeck/lib.rs and should be kept in sync with those changes.
let _ = tcx.sess.time("wf_checking", || tcx.ensure_ok().check_type_wf(()));
tcx.sess.time("wf_checking", || tcx.ensure_ok().check_type_wf(()));
tcx.dcx().abort_if_errors();