Skip to content

Commit 4e97337

Browse files
committed
Auto merge of #142030 - oli-obk:wfck-less-hir, r=compiler-errors
Start moving wf checking away from HIR I'm trying to only access the HIR in the error path. My hope is that once we move significant portions of wfcheck off HIR that incremental will be able to cache wfcheck queries significantly better. I think I am reaching a blocker because we normally need to provide good spans to `ObligationCause`, so that the trait solver can report good errors. In some cases I have been able to use bad spans and improve them depending on the `ObligationCauseCode` (by loading HIR in the case where we actually want to error). To scale that further we'll likely need to remove spans from the `ObligationCause` entirely (leaving it to some variants of `ObligationCauseCode` to have a span when they can't recompute the information later). Unsure this is the right approach, but we've already been using it. I will create an MCP about it, but that should not affect this PR, which is fairly limited in where it does those kind of tricks. Especially b862d88 is interesting here, because I think it improves spans in all cases
2 parents 076a0a2 + 422eea2 commit 4e97337

File tree

124 files changed

+1149
-1012
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

124 files changed

+1149
-1012
lines changed

compiler/rustc_hir/src/hir.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4834,6 +4834,10 @@ impl<'hir> Node<'hir> {
48344834
ImplItemKind::Type(ty) => Some(ty),
48354835
_ => None,
48364836
},
4837+
Node::ForeignItem(it) => match it.kind {
4838+
ForeignItemKind::Static(ty, ..) => Some(ty),
4839+
_ => None,
4840+
},
48374841
_ => None,
48384842
}
48394843
}

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 193 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_errors::{EmissionGuarantee, MultiSpan};
1010
use rustc_hir::def::{CtorKind, DefKind};
1111
use rustc_hir::{LangItem, Node, intravisit};
1212
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
13-
use rustc_infer::traits::{Obligation, ObligationCauseCode};
13+
use rustc_infer::traits::{Obligation, ObligationCauseCode, WellFormedLoc};
1414
use rustc_lint_defs::builtin::{
1515
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, UNSUPPORTED_CALLING_CONVENTIONS,
1616
};
@@ -36,6 +36,10 @@ use {rustc_attr_data_structures as attrs, rustc_hir as hir};
3636

3737
use super::compare_impl_item::check_type_bounds;
3838
use super::*;
39+
use crate::check::wfcheck::{
40+
check_associated_item, check_trait_item, check_variances_for_type_defn, check_where_clauses,
41+
enter_wf_checking_ctxt,
42+
};
3943

4044
fn add_abi_diag_help<T: EmissionGuarantee>(abi: ExternAbi, diag: &mut Diag<'_, T>) {
4145
if let ExternAbi::Cdecl { unwind } = abi {
@@ -729,7 +733,8 @@ fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) {
729733
}
730734
}
731735

732-
pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
736+
pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
737+
let mut res = Ok(());
733738
let generics = tcx.generics_of(def_id);
734739

735740
for param in &generics.own_params {
@@ -754,15 +759,39 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
754759
}
755760

756761
match tcx.def_kind(def_id) {
757-
DefKind::Static { .. } => {
758-
check_static_inhabited(tcx, def_id);
759-
check_static_linkage(tcx, def_id);
762+
def_kind @ (DefKind::Static { .. } | DefKind::Const) => {
763+
tcx.ensure_ok().generics_of(def_id);
764+
tcx.ensure_ok().type_of(def_id);
765+
tcx.ensure_ok().predicates_of(def_id);
766+
match def_kind {
767+
DefKind::Static { .. } => {
768+
check_static_inhabited(tcx, def_id);
769+
check_static_linkage(tcx, def_id);
770+
res = res.and(wfcheck::check_static_item(tcx, def_id));
771+
772+
// Only `Node::Item` and `Node::ForeignItem` still have HIR based
773+
// checks. Returning early here does not miss any checks and
774+
// avoids this query from having a direct dependency edge on the HIR
775+
return res;
776+
}
777+
DefKind::Const => {}
778+
_ => unreachable!(),
779+
}
760780
}
761-
DefKind::Const => {}
762781
DefKind::Enum => {
782+
tcx.ensure_ok().generics_of(def_id);
783+
tcx.ensure_ok().type_of(def_id);
784+
tcx.ensure_ok().predicates_of(def_id);
785+
crate::collect::lower_enum_variant_types(tcx, def_id.to_def_id());
763786
check_enum(tcx, def_id);
787+
check_variances_for_type_defn(tcx, def_id);
764788
}
765789
DefKind::Fn => {
790+
tcx.ensure_ok().generics_of(def_id);
791+
tcx.ensure_ok().type_of(def_id);
792+
tcx.ensure_ok().predicates_of(def_id);
793+
tcx.ensure_ok().fn_sig(def_id);
794+
tcx.ensure_ok().codegen_fn_attrs(def_id);
766795
if let Some(i) = tcx.intrinsic(def_id) {
767796
intrinsic::check_intrinsic_type(
768797
tcx,
@@ -773,17 +802,31 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
773802
}
774803
}
775804
DefKind::Impl { of_trait } => {
805+
tcx.ensure_ok().generics_of(def_id);
806+
tcx.ensure_ok().type_of(def_id);
807+
tcx.ensure_ok().impl_trait_header(def_id);
808+
tcx.ensure_ok().predicates_of(def_id);
809+
tcx.ensure_ok().associated_items(def_id);
776810
if of_trait && let Some(impl_trait_header) = tcx.impl_trait_header(def_id) {
777-
if tcx
778-
.ensure_ok()
779-
.coherent_trait(impl_trait_header.trait_ref.instantiate_identity().def_id)
780-
.is_ok()
781-
{
811+
res = res.and(
812+
tcx.ensure_ok()
813+
.coherent_trait(impl_trait_header.trait_ref.instantiate_identity().def_id),
814+
);
815+
816+
if res.is_ok() {
817+
// Checking this only makes sense if the all trait impls satisfy basic
818+
// requirements (see `coherent_trait` query), otherwise
819+
// we run into infinite recursions a lot.
782820
check_impl_items_against_trait(tcx, def_id, impl_trait_header);
783821
}
784822
}
785823
}
786824
DefKind::Trait => {
825+
tcx.ensure_ok().generics_of(def_id);
826+
tcx.ensure_ok().trait_def(def_id);
827+
tcx.ensure_ok().explicit_super_predicates_of(def_id);
828+
tcx.ensure_ok().predicates_of(def_id);
829+
tcx.ensure_ok().associated_items(def_id);
787830
let assoc_items = tcx.associated_items(def_id);
788831
check_on_unimplemented(tcx, def_id);
789832

@@ -802,11 +845,33 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
802845
}
803846
}
804847
}
805-
DefKind::Struct => {
806-
check_struct(tcx, def_id);
848+
DefKind::TraitAlias => {
849+
tcx.ensure_ok().generics_of(def_id);
850+
tcx.ensure_ok().explicit_implied_predicates_of(def_id);
851+
tcx.ensure_ok().explicit_super_predicates_of(def_id);
852+
tcx.ensure_ok().predicates_of(def_id);
807853
}
808-
DefKind::Union => {
809-
check_union(tcx, def_id);
854+
def_kind @ (DefKind::Struct | DefKind::Union) => {
855+
tcx.ensure_ok().generics_of(def_id);
856+
tcx.ensure_ok().type_of(def_id);
857+
tcx.ensure_ok().predicates_of(def_id);
858+
859+
let adt = tcx.adt_def(def_id).non_enum_variant();
860+
for f in adt.fields.iter() {
861+
tcx.ensure_ok().generics_of(f.did);
862+
tcx.ensure_ok().type_of(f.did);
863+
tcx.ensure_ok().predicates_of(f.did);
864+
}
865+
866+
if let Some((_, ctor_def_id)) = adt.ctor {
867+
crate::collect::lower_variant_ctor(tcx, ctor_def_id.expect_local());
868+
}
869+
match def_kind {
870+
DefKind::Struct => check_struct(tcx, def_id),
871+
DefKind::Union => check_union(tcx, def_id),
872+
_ => unreachable!(),
873+
}
874+
check_variances_for_type_defn(tcx, def_id);
810875
}
811876
DefKind::OpaqueTy => {
812877
check_opaque_precise_captures(tcx, def_id);
@@ -831,14 +896,37 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
831896
tcx.ensure_ok().explicit_implied_const_bounds(def_id);
832897
tcx.ensure_ok().const_conditions(def_id);
833898
}
899+
900+
// Only `Node::Item` and `Node::ForeignItem` still have HIR based
901+
// checks. Returning early here does not miss any checks and
902+
// avoids this query from having a direct dependency edge on the HIR
903+
return res;
834904
}
835905
DefKind::TyAlias => {
906+
tcx.ensure_ok().generics_of(def_id);
907+
tcx.ensure_ok().type_of(def_id);
908+
tcx.ensure_ok().predicates_of(def_id);
836909
check_type_alias_type_params_are_used(tcx, def_id);
910+
if tcx.type_alias_is_lazy(def_id) {
911+
res = res.and(enter_wf_checking_ctxt(tcx, def_id, |wfcx| {
912+
let ty = tcx.type_of(def_id).instantiate_identity();
913+
let span = tcx.def_span(def_id);
914+
let item_ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(def_id)), ty);
915+
wfcx.register_wf_obligation(
916+
span,
917+
Some(WellFormedLoc::Ty(def_id)),
918+
item_ty.into(),
919+
);
920+
check_where_clauses(wfcx, def_id);
921+
Ok(())
922+
}));
923+
check_variances_for_type_defn(tcx, def_id);
924+
}
837925
}
838926
DefKind::ForeignMod => {
839927
let it = tcx.hir_expect_item(def_id);
840928
let hir::ItemKind::ForeignMod { abi, items } = it.kind else {
841-
return;
929+
return Ok(());
842930
};
843931

844932
check_abi(tcx, it.hir_id(), it.span, abi);
@@ -877,15 +965,23 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
877965
}
878966

879967
let item = tcx.hir_foreign_item(item.id);
880-
match &item.kind {
881-
hir::ForeignItemKind::Fn(sig, _, _) => {
968+
tcx.ensure_ok().generics_of(item.owner_id);
969+
tcx.ensure_ok().type_of(item.owner_id);
970+
tcx.ensure_ok().predicates_of(item.owner_id);
971+
if tcx.is_conditionally_const(def_id) {
972+
tcx.ensure_ok().explicit_implied_const_bounds(def_id);
973+
tcx.ensure_ok().const_conditions(def_id);
974+
}
975+
match item.kind {
976+
hir::ForeignItemKind::Fn(sig, ..) => {
977+
tcx.ensure_ok().codegen_fn_attrs(item.owner_id);
978+
tcx.ensure_ok().fn_sig(item.owner_id);
882979
require_c_abi_if_c_variadic(tcx, sig.decl, abi, item.span);
883980
}
884981
hir::ForeignItemKind::Static(..) => {
885-
check_static_inhabited(tcx, def_id);
886-
check_static_linkage(tcx, def_id);
982+
tcx.ensure_ok().codegen_fn_attrs(item.owner_id);
887983
}
888-
_ => {}
984+
_ => (),
889985
}
890986
}
891987
}
@@ -897,9 +993,85 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
897993
// We do not call `type_of` for closures here as that
898994
// depends on typecheck and would therefore hide
899995
// any further errors in case one typeck fails.
996+
997+
// Only `Node::Item` and `Node::ForeignItem` still have HIR based
998+
// checks. Returning early here does not miss any checks and
999+
// avoids this query from having a direct dependency edge on the HIR
1000+
return res;
1001+
}
1002+
DefKind::AssocFn => {
1003+
tcx.ensure_ok().codegen_fn_attrs(def_id);
1004+
tcx.ensure_ok().type_of(def_id);
1005+
tcx.ensure_ok().fn_sig(def_id);
1006+
tcx.ensure_ok().predicates_of(def_id);
1007+
res = res.and(check_associated_item(tcx, def_id));
1008+
let assoc_item = tcx.associated_item(def_id);
1009+
match assoc_item.container {
1010+
ty::AssocItemContainer::Impl => {}
1011+
ty::AssocItemContainer::Trait => {
1012+
res = res.and(check_trait_item(tcx, def_id));
1013+
}
1014+
}
1015+
1016+
// Only `Node::Item` and `Node::ForeignItem` still have HIR based
1017+
// checks. Returning early here does not miss any checks and
1018+
// avoids this query from having a direct dependency edge on the HIR
1019+
return res;
1020+
}
1021+
DefKind::AssocConst => {
1022+
tcx.ensure_ok().type_of(def_id);
1023+
tcx.ensure_ok().predicates_of(def_id);
1024+
res = res.and(check_associated_item(tcx, def_id));
1025+
let assoc_item = tcx.associated_item(def_id);
1026+
match assoc_item.container {
1027+
ty::AssocItemContainer::Impl => {}
1028+
ty::AssocItemContainer::Trait => {
1029+
res = res.and(check_trait_item(tcx, def_id));
1030+
}
1031+
}
1032+
1033+
// Only `Node::Item` and `Node::ForeignItem` still have HIR based
1034+
// checks. Returning early here does not miss any checks and
1035+
// avoids this query from having a direct dependency edge on the HIR
1036+
return res;
9001037
}
1038+
DefKind::AssocTy => {
1039+
tcx.ensure_ok().predicates_of(def_id);
1040+
res = res.and(check_associated_item(tcx, def_id));
1041+
1042+
let assoc_item = tcx.associated_item(def_id);
1043+
let has_type = match assoc_item.container {
1044+
ty::AssocItemContainer::Impl => true,
1045+
ty::AssocItemContainer::Trait => {
1046+
tcx.ensure_ok().item_bounds(def_id);
1047+
tcx.ensure_ok().item_self_bounds(def_id);
1048+
res = res.and(check_trait_item(tcx, def_id));
1049+
assoc_item.defaultness(tcx).has_value()
1050+
}
1051+
};
1052+
if has_type {
1053+
tcx.ensure_ok().type_of(def_id);
1054+
}
1055+
1056+
// Only `Node::Item` and `Node::ForeignItem` still have HIR based
1057+
// checks. Returning early here does not miss any checks and
1058+
// avoids this query from having a direct dependency edge on the HIR
1059+
return res;
1060+
}
1061+
1062+
// Only `Node::Item` and `Node::ForeignItem` still have HIR based
1063+
// checks. Returning early here does not miss any checks and
1064+
// avoids this query from having a direct dependency edge on the HIR
1065+
DefKind::AnonConst | DefKind::InlineConst => return res,
9011066
_ => {}
9021067
}
1068+
let node = tcx.hir_node_by_def_id(def_id);
1069+
res.and(match node {
1070+
hir::Node::Crate(_) => bug!("check_well_formed cannot be applied to the crate root"),
1071+
hir::Node::Item(item) => wfcheck::check_item(tcx, item),
1072+
hir::Node::ForeignItem(item) => wfcheck::check_foreign_item(tcx, item),
1073+
_ => unreachable!("{node:?}"),
1074+
})
9031075
}
9041076

9051077
pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, def_id: LocalDefId) {

0 commit comments

Comments
 (0)