Auto merge of #98222 - cjgillot:single-wf, r=michaelwoerister
Only keep a single query for well-formed checking There are currently 3 queries to perform wf checks on different item-likes. This complexity is not required. This PR replaces the query by: - one query per item; - one query to invoke it for a whole module. This allows to remove HIR `ParItemLikeVisitor`.
This commit is contained in:
commit
5ffa8f67b7
30 changed files with 257 additions and 458 deletions
|
@ -32,11 +32,6 @@ use rustc_ty_utils::representability::{self, Representability};
|
|||
use std::iter;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
pub fn check_wf_new(tcx: TyCtxt<'_>) {
|
||||
let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx);
|
||||
tcx.hir().par_visit_all_item_likes(&visit);
|
||||
}
|
||||
|
||||
pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
|
||||
match tcx.sess.target.is_abi_supported(abi) {
|
||||
Some(true) => (),
|
||||
|
@ -754,7 +749,7 @@ fn check_opaque_meets_bounds<'tcx>(
|
|||
});
|
||||
}
|
||||
|
||||
pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
|
||||
fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
|
||||
debug!(
|
||||
"check_item_type(it.def_id={:?}, it.name={})",
|
||||
id.def_id,
|
||||
|
@ -1543,12 +1538,6 @@ pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) use wfcheck::check_item_well_formed;
|
||||
|
||||
pub(super) use wfcheck::check_trait_item as check_trait_item_well_formed;
|
||||
|
||||
pub(super) use wfcheck::check_impl_item as check_impl_item_well_formed;
|
||||
|
||||
fn async_opaque_type_cycle_error(tcx: TyCtxt<'_>, span: Span) -> ErrorGuaranteed {
|
||||
struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing")
|
||||
.span_label(span, "recursive `async fn`")
|
||||
|
|
|
@ -93,11 +93,7 @@ mod upvar;
|
|||
mod wfcheck;
|
||||
pub mod writeback;
|
||||
|
||||
use check::{
|
||||
check_abi, check_fn, check_impl_item_well_formed, check_item_well_formed, check_mod_item_types,
|
||||
check_trait_item_well_formed,
|
||||
};
|
||||
pub use check::{check_item_type, check_wf_new};
|
||||
use check::{check_abi, check_fn, check_mod_item_types};
|
||||
pub use diverges::Diverges;
|
||||
pub use expectation::Expectation;
|
||||
pub use fn_ctxt::*;
|
||||
|
@ -245,6 +241,7 @@ impl<'tcx> EnclosingBreakables<'tcx> {
|
|||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
method::provide(providers);
|
||||
wfcheck::provide(providers);
|
||||
*providers = Providers {
|
||||
typeck_item_bodies,
|
||||
typeck_const_arg,
|
||||
|
@ -253,9 +250,6 @@ pub fn provide(providers: &mut Providers) {
|
|||
has_typeck_results,
|
||||
adt_destructor,
|
||||
used_trait_imports,
|
||||
check_item_well_formed,
|
||||
check_trait_item_well_formed,
|
||||
check_impl_item_well_formed,
|
||||
check_mod_item_types,
|
||||
region_scope_tree,
|
||||
..*providers
|
||||
|
|
|
@ -7,21 +7,18 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
|||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit as hir_visit;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::itemlikevisit::ParItemLikeVisitor;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::ItemKind;
|
||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc_infer::infer::outlives::obligations::TypeOutlives;
|
||||
use rustc_infer::infer::region_constraints::GenericKind;
|
||||
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
|
||||
use rustc_middle::ty::trait_def::TraitSpecializationKind;
|
||||
use rustc_middle::ty::{
|
||||
self, AdtKind, EarlyBinder, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable,
|
||||
TypeSuperFoldable, TypeVisitor,
|
||||
self, AdtKind, DefIdTree, EarlyBinder, GenericParamDefKind, ToPredicate, Ty, TyCtxt,
|
||||
TypeFoldable, TypeSuperFoldable, TypeVisitor,
|
||||
};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
|
@ -70,6 +67,23 @@ impl<'tcx> CheckWfFcxBuilder<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
let node = tcx.hir().expect_owner(def_id);
|
||||
match node {
|
||||
hir::OwnerNode::Crate(_) => {}
|
||||
hir::OwnerNode::Item(item) => check_item(tcx, item),
|
||||
hir::OwnerNode::TraitItem(item) => check_trait_item(tcx, item),
|
||||
hir::OwnerNode::ImplItem(item) => check_impl_item(tcx, item),
|
||||
hir::OwnerNode::ForeignItem(item) => check_foreign_item(tcx, item),
|
||||
}
|
||||
|
||||
if let Some(generics) = node.generics() {
|
||||
for param in generics.params {
|
||||
check_param_wf(tcx, param)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks that the field types (in a struct def'n) or argument types (in an enum def'n) are
|
||||
/// well-formed, meaning that they do not require any constraints not declared in the struct
|
||||
/// definition itself. For example, this definition would be illegal:
|
||||
|
@ -84,8 +98,8 @@ impl<'tcx> CheckWfFcxBuilder<'tcx> {
|
|||
/// not included it frequently leads to confusing errors in fn bodies. So it's better to check
|
||||
/// the types first.
|
||||
#[instrument(skip(tcx), level = "debug")]
|
||||
pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
let item = tcx.hir().expect_item(def_id);
|
||||
fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||
let def_id = item.def_id;
|
||||
|
||||
debug!(
|
||||
?item.def_id,
|
||||
|
@ -156,20 +170,6 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
hir::ItemKind::Const(ty, ..) => {
|
||||
check_item_type(tcx, item.def_id, ty.span, false);
|
||||
}
|
||||
hir::ItemKind::ForeignMod { items, .. } => {
|
||||
for it in items.iter() {
|
||||
let it = tcx.hir().foreign_item(it.id);
|
||||
match it.kind {
|
||||
hir::ForeignItemKind::Fn(decl, ..) => {
|
||||
check_item_fn(tcx, it.def_id, it.ident, it.span, decl)
|
||||
}
|
||||
hir::ForeignItemKind::Static(ty, ..) => {
|
||||
check_item_type(tcx, it.def_id, ty.span, true)
|
||||
}
|
||||
hir::ForeignItemKind::Type => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::ItemKind::Struct(ref struct_def, ref ast_generics) => {
|
||||
check_type_defn(tcx, item, false, |fcx| vec![fcx.non_enum_variant(struct_def)]);
|
||||
|
||||
|
@ -191,13 +191,31 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
hir::ItemKind::TraitAlias(..) => {
|
||||
check_trait(tcx, item);
|
||||
}
|
||||
// `ForeignItem`s are handled separately.
|
||||
hir::ItemKind::ForeignMod { .. } => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
let trait_item = tcx.hir().expect_trait_item(def_id);
|
||||
fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) {
|
||||
let def_id = item.def_id;
|
||||
|
||||
debug!(
|
||||
?item.def_id,
|
||||
item.name = ? tcx.def_path_str(def_id.to_def_id())
|
||||
);
|
||||
|
||||
match item.kind {
|
||||
hir::ForeignItemKind::Fn(decl, ..) => {
|
||||
check_item_fn(tcx, item.def_id, item.ident, item.span, decl)
|
||||
}
|
||||
hir::ForeignItemKind::Static(ty, ..) => check_item_type(tcx, item.def_id, ty.span, true),
|
||||
hir::ForeignItemKind::Type => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
|
||||
let def_id = trait_item.def_id;
|
||||
|
||||
let (method_sig, span) = match trait_item.kind {
|
||||
hir::TraitItemKind::Fn(ref sig, _) => (Some(sig), trait_item.span),
|
||||
|
@ -207,7 +225,7 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
check_object_unsafe_self_trait_by_name(tcx, trait_item);
|
||||
check_associated_item(tcx, trait_item.def_id, span, method_sig);
|
||||
|
||||
let encl_trait_def_id = tcx.hir().get_parent_item(hir_id);
|
||||
let encl_trait_def_id = tcx.local_parent(def_id);
|
||||
let encl_trait = tcx.hir().expect_item(encl_trait_def_id);
|
||||
let encl_trait_def_id = encl_trait.def_id.to_def_id();
|
||||
let fn_lang_item_name = if Some(encl_trait_def_id) == tcx.lang_items().fn_trait() {
|
||||
|
@ -764,8 +782,8 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem
|
|||
}
|
||||
}
|
||||
|
||||
pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
let impl_item = tcx.hir().expect_impl_item(def_id);
|
||||
fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) {
|
||||
let def_id = impl_item.def_id;
|
||||
|
||||
let (method_sig, span) = match impl_item.kind {
|
||||
hir::ImplItemKind::Fn(ref sig, _) => (Some(sig), impl_item.span),
|
||||
|
@ -774,7 +792,7 @@ pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
_ => (None, impl_item.span),
|
||||
};
|
||||
|
||||
check_associated_item(tcx, impl_item.def_id, span, method_sig);
|
||||
check_associated_item(tcx, def_id, span, method_sig);
|
||||
}
|
||||
|
||||
fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
|
||||
|
@ -1822,67 +1840,12 @@ fn check_false_global_bounds(fcx: &FnCtxt<'_, '_>, mut span: Span, id: hir::HirI
|
|||
fcx.select_all_obligations_or_error();
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CheckTypeWellFormedVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> CheckTypeWellFormedVisitor<'tcx> {
|
||||
pub fn new(tcx: TyCtxt<'tcx>) -> CheckTypeWellFormedVisitor<'tcx> {
|
||||
CheckTypeWellFormedVisitor { tcx }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ParItemLikeVisitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> {
|
||||
fn visit_item(&self, i: &'tcx hir::Item<'tcx>) {
|
||||
Visitor::visit_item(&mut self.clone(), i);
|
||||
}
|
||||
|
||||
fn visit_trait_item(&self, trait_item: &'tcx hir::TraitItem<'tcx>) {
|
||||
Visitor::visit_trait_item(&mut self.clone(), trait_item);
|
||||
}
|
||||
|
||||
fn visit_impl_item(&self, impl_item: &'tcx hir::ImplItem<'tcx>) {
|
||||
Visitor::visit_impl_item(&mut self.clone(), impl_item);
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&self, foreign_item: &'tcx hir::ForeignItem<'tcx>) {
|
||||
Visitor::visit_foreign_item(&mut self.clone(), foreign_item)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.tcx.hir()
|
||||
}
|
||||
|
||||
#[instrument(skip(self, i), level = "debug")]
|
||||
fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) {
|
||||
trace!(?i);
|
||||
self.tcx.ensure().check_item_well_formed(i.def_id);
|
||||
hir_visit::walk_item(self, i);
|
||||
}
|
||||
|
||||
#[instrument(skip(self, trait_item), level = "debug")]
|
||||
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
|
||||
trace!(?trait_item);
|
||||
self.tcx.ensure().check_trait_item_well_formed(trait_item.def_id);
|
||||
hir_visit::walk_trait_item(self, trait_item);
|
||||
}
|
||||
|
||||
#[instrument(skip(self, impl_item), level = "debug")]
|
||||
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
|
||||
trace!(?impl_item);
|
||||
self.tcx.ensure().check_impl_item_well_formed(impl_item.def_id);
|
||||
hir_visit::walk_impl_item(self, impl_item);
|
||||
}
|
||||
|
||||
fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
|
||||
check_param_wf(self.tcx, p);
|
||||
hir_visit::walk_generic_param(self, p);
|
||||
}
|
||||
fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalDefId) {
|
||||
let items = tcx.hir_module_items(module);
|
||||
items.par_items(|item| tcx.ensure().check_well_formed(item.def_id));
|
||||
items.par_impl_items(|item| tcx.ensure().check_well_formed(item.def_id));
|
||||
items.par_trait_items(|item| tcx.ensure().check_well_formed(item.def_id));
|
||||
items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.def_id));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1967,3 +1930,7 @@ fn error_392(
|
|||
err.span_label(span, "unused parameter");
|
||||
err
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
*providers = Providers { check_mod_type_wf, check_well_formed, ..*providers };
|
||||
}
|
||||
|
|
|
@ -54,13 +54,6 @@ mod min_specialization;
|
|||
/// impl<'a> Trait<Foo> for Bar { type X = &'a i32; }
|
||||
/// // ^ 'a is unused and appears in assoc type, error
|
||||
/// ```
|
||||
pub fn impl_wf_check(tcx: TyCtxt<'_>) {
|
||||
// We will tag this as part of the WF check -- logically, it is,
|
||||
// but it's one that we must perform earlier than the rest of
|
||||
// WfCheck.
|
||||
tcx.hir().for_each_module(|module| tcx.ensure().check_mod_impl_wf(module))
|
||||
}
|
||||
|
||||
fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||
let min_specialization = tcx.features().min_specialization;
|
||||
let module = tcx.hir_module_items(module_def_id);
|
||||
|
|
|
@ -509,7 +509,9 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
|
|||
}
|
||||
|
||||
tcx.sess.track_errors(|| {
|
||||
tcx.sess.time("impl_wf_inference", || impl_wf_check::impl_wf_check(tcx));
|
||||
tcx.sess.time("impl_wf_inference", || {
|
||||
tcx.hir().for_each_module(|module| tcx.ensure().check_mod_impl_wf(module))
|
||||
});
|
||||
})?;
|
||||
|
||||
tcx.sess.track_errors(|| {
|
||||
|
@ -531,7 +533,9 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
|
|||
}
|
||||
|
||||
tcx.sess.track_errors(|| {
|
||||
tcx.sess.time("wf_checking", || check::check_wf_new(tcx));
|
||||
tcx.sess.time("wf_checking", || {
|
||||
tcx.hir().par_for_each_module(|module| tcx.ensure().check_mod_type_wf(module))
|
||||
});
|
||||
})?;
|
||||
|
||||
// NOTE: This is copy/pasted in librustdoc/core.rs and should be kept in sync.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue