Rollup merge of #150141 - BoxyUwU:borrowck_cleanup_1, r=lcnr

Misc cleanups from reading some borrowck code

title

r? lcnr
This commit is contained in:
Jonathan Brouwer 2025-12-24 16:37:10 +01:00 committed by GitHub
commit c772ca3a6a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 99 additions and 118 deletions

View file

@ -1,4 +1,4 @@
//! This query borrow-checks the MIR to (further) ensure it is not broken.
//! This crate implemens MIR typeck and MIR borrowck.
// tidy-alphabetical-start
#![allow(internal_features)]
@ -111,9 +111,9 @@ pub fn provide(providers: &mut Providers) {
*providers = Providers { mir_borrowck, ..*providers };
}
/// Provider for `query mir_borrowck`. Similar to `typeck`, this must
/// only be called for typeck roots which will then borrowck all
/// nested bodies as well.
/// Provider for `query mir_borrowck`. Unlike `typeck`, this must
/// only be called for typeck roots which *similar* to `typeck` will
/// then borrowck all nested bodies as well.
fn mir_borrowck(
tcx: TyCtxt<'_>,
def: LocalDefId,

View file

@ -255,7 +255,7 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
}
// We now apply the closure requirements of nested bodies modulo
// regions. In case a body does not depend on opaque types, we
// opaques. In case a body does not depend on opaque types, we
// eagerly check its region constraints and use the final closure
// requirements.
//

View file

@ -1,13 +1,12 @@
//! Code to extract the universally quantified regions declared on a
//! function and the relationships between them. For example:
//! function. For example:
//!
//! ```
//! fn foo<'a, 'b, 'c: 'b>() { }
//! ```
//!
//! here we would return a map assigning each of `{'a, 'b, 'c}`
//! to an index, as well as the `FreeRegionMap` which can compute
//! relationships between them.
//! to an index.
//!
//! The code in this file doesn't *do anything* with those results; it
//! just returns them for other code to use.
@ -271,8 +270,7 @@ impl<'tcx> UniversalRegions<'tcx> {
/// Creates a new and fully initialized `UniversalRegions` that
/// contains indices for all the free regions found in the given
/// MIR -- that is, all the regions that appear in the function's
/// signature. This will also compute the relationships that are
/// known between those regions.
/// signature.
pub(crate) fn new(infcx: &BorrowckInferCtxt<'tcx>, mir_def: LocalDefId) -> Self {
UniversalRegionsBuilder { infcx, mir_def }.build()
}
@ -648,17 +646,14 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(..) => {
let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id);
if self.mir_def.to_def_id() == typeck_root_def_id
// Do not ICE when checking default_field_values consts with lifetimes (#135649)
&& DefKind::Field != tcx.def_kind(tcx.parent(typeck_root_def_id))
{
if self.mir_def.to_def_id() == typeck_root_def_id {
let args = self.infcx.replace_free_regions_with_nll_infer_vars(
NllRegionVariableOrigin::FreeRegion,
identity_args,
);
DefiningTy::Const(self.mir_def.to_def_id(), args)
} else {
// FIXME this line creates a dependency between borrowck and typeck.
// FIXME: this line creates a query dependency between borrowck and typeck.
//
// This is required for `AscribeUserType` canonical query, which will call
// `type_of(inline_const_def_id)`. That `type_of` would inject erased lifetimes
@ -699,30 +694,14 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
let tcx = self.infcx.tcx;
let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.to_def_id());
let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id);
let fr_args = match defining_ty {
DefiningTy::Closure(_, args)
| DefiningTy::CoroutineClosure(_, args)
| DefiningTy::Coroutine(_, args)
| DefiningTy::InlineConst(_, args) => {
// In the case of closures, we rely on the fact that
// the first N elements in the ClosureArgs are
// inherited from the `typeck_root_def_id`.
// Therefore, when we zip together (below) with
// `identity_args`, we will get only those regions
// that correspond to early-bound regions declared on
// the `typeck_root_def_id`.
assert!(args.len() >= identity_args.len());
assert_eq!(args.regions().count(), identity_args.regions().count());
args
}
DefiningTy::FnDef(_, args) | DefiningTy::Const(_, args) => args,
DefiningTy::GlobalAsm(_) => ty::List::empty(),
};
let renumbered_args = defining_ty.args();
let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static));
let arg_mapping = iter::zip(identity_args.regions(), fr_args.regions().map(|r| r.as_var()));
// This relies on typeck roots being generics_of parents with their
// parameters at the start of nested bodies' generics.
assert!(renumbered_args.len() >= identity_args.len());
let arg_mapping =
iter::zip(identity_args.regions(), renumbered_args.regions().map(|r| r.as_var()));
UniversalRegionIndices {
indices: global_mapping.chain(arg_mapping).collect(),
@ -862,8 +841,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
};
// FIXME(#129952): We probably want a more principled approach here.
if let Err(terr) = inputs_and_output.skip_binder().error_reported() {
self.infcx.set_tainted_by_errors(terr);
if let Err(e) = inputs_and_output.error_reported() {
self.infcx.set_tainted_by_errors(e);
}
inputs_and_output

View file

@ -10,6 +10,7 @@ use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, DefiningScopeKind, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::{bug, span_bug};
use rustc_span::{DUMMY_SP, Ident, Span};
use tracing::instrument;
use super::{HirPlaceholderCollector, ItemCtxt, bad_placeholder};
use crate::check::wfcheck::check_static_item;
@ -17,85 +18,7 @@ use crate::hir_ty_lowering::HirTyLowerer;
mod opaque;
fn anon_const_type_of<'tcx>(icx: &ItemCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
use hir::*;
use rustc_middle::ty::Ty;
let tcx = icx.tcx;
let hir_id = tcx.local_def_id_to_hir_id(def_id);
let node = tcx.hir_node(hir_id);
let Node::AnonConst(&AnonConst { span, .. }) = node else {
span_bug!(
tcx.def_span(def_id),
"expected anon const in `anon_const_type_of`, got {node:?}"
);
};
let parent_node_id = tcx.parent_hir_id(hir_id);
let parent_node = tcx.hir_node(parent_node_id);
match parent_node {
// Anon consts "inside" the type system.
Node::ConstArg(&ConstArg {
hir_id: arg_hir_id,
kind: ConstArgKind::Anon(&AnonConst { hir_id: anon_hir_id, .. }),
..
}) if anon_hir_id == hir_id => const_arg_anon_type_of(icx, arg_hir_id, span),
Node::Variant(Variant { disr_expr: Some(e), .. }) if e.hir_id == hir_id => {
tcx.adt_def(tcx.hir_get_parent_item(hir_id)).repr().discr_type().to_ty(tcx)
}
Node::Field(&hir::FieldDef { default: Some(c), def_id: field_def_id, .. })
if c.hir_id == hir_id =>
{
tcx.type_of(field_def_id).instantiate_identity()
}
_ => Ty::new_error_with_message(
tcx,
span,
format!("unexpected anon const parent in type_of(): {parent_node:?}"),
),
}
}
fn const_arg_anon_type_of<'tcx>(icx: &ItemCtxt<'tcx>, arg_hir_id: HirId, span: Span) -> Ty<'tcx> {
use hir::*;
use rustc_middle::ty::Ty;
let tcx = icx.tcx;
match tcx.parent_hir_node(arg_hir_id) {
// Array length const arguments do not have `type_of` fed as there is never a corresponding
// generic parameter definition.
Node::Ty(&hir::Ty { kind: TyKind::Array(_, ref constant), .. })
| Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
if constant.hir_id == arg_hir_id =>
{
tcx.types.usize
}
Node::TyPat(pat) => {
let node = match tcx.parent_hir_node(pat.hir_id) {
// Or patterns can be nested one level deep
Node::TyPat(p) => tcx.parent_hir_node(p.hir_id),
other => other,
};
let hir::TyKind::Pat(ty, _) = node.expect_ty().kind else { bug!() };
icx.lower_ty(ty)
}
// This is not a `bug!` as const arguments in path segments that did not resolve to anything
// will result in `type_of` never being fed.
_ => Ty::new_error_with_message(
tcx,
span,
"`type_of` called on const argument's anon const before the const argument was lowered",
),
}
}
#[instrument(level = "debug", skip(tcx), ret)]
pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, Ty<'_>> {
use rustc_hir::*;
use rustc_middle::ty::Ty;
@ -408,6 +331,85 @@ pub(super) fn type_of_opaque_hir_typeck(
}
}
fn anon_const_type_of<'tcx>(icx: &ItemCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
use hir::*;
use rustc_middle::ty::Ty;
let tcx = icx.tcx;
let hir_id = tcx.local_def_id_to_hir_id(def_id);
let node = tcx.hir_node(hir_id);
let Node::AnonConst(&AnonConst { span, .. }) = node else {
span_bug!(
tcx.def_span(def_id),
"expected anon const in `anon_const_type_of`, got {node:?}"
);
};
let parent_node_id = tcx.parent_hir_id(hir_id);
let parent_node = tcx.hir_node(parent_node_id);
match parent_node {
// Anon consts "inside" the type system.
Node::ConstArg(&ConstArg {
hir_id: arg_hir_id,
kind: ConstArgKind::Anon(&AnonConst { hir_id: anon_hir_id, .. }),
..
}) if anon_hir_id == hir_id => const_arg_anon_type_of(icx, arg_hir_id, span),
Node::Variant(Variant { disr_expr: Some(e), .. }) if e.hir_id == hir_id => {
tcx.adt_def(tcx.hir_get_parent_item(hir_id)).repr().discr_type().to_ty(tcx)
}
Node::Field(&hir::FieldDef { default: Some(c), def_id: field_def_id, .. })
if c.hir_id == hir_id =>
{
tcx.type_of(field_def_id).instantiate_identity()
}
_ => Ty::new_error_with_message(
tcx,
span,
format!("unexpected anon const parent in type_of(): {parent_node:?}"),
),
}
}
fn const_arg_anon_type_of<'tcx>(icx: &ItemCtxt<'tcx>, arg_hir_id: HirId, span: Span) -> Ty<'tcx> {
use hir::*;
use rustc_middle::ty::Ty;
let tcx = icx.tcx;
match tcx.parent_hir_node(arg_hir_id) {
// Array length const arguments do not have `type_of` fed as there is never a corresponding
// generic parameter definition.
Node::Ty(&hir::Ty { kind: TyKind::Array(_, ref constant), .. })
| Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
if constant.hir_id == arg_hir_id =>
{
tcx.types.usize
}
Node::TyPat(pat) => {
let node = match tcx.parent_hir_node(pat.hir_id) {
// Or patterns can be nested one level deep
Node::TyPat(p) => tcx.parent_hir_node(p.hir_id),
other => other,
};
let hir::TyKind::Pat(ty, _) = node.expect_ty().kind else { bug!() };
icx.lower_ty(ty)
}
// This is not a `bug!` as const arguments in path segments that did not resolve to anything
// will result in `type_of` never being fed.
_ => Ty::new_error_with_message(
tcx,
span,
"`type_of` called on const argument's anon const before the const argument was lowered",
),
}
}
fn infer_placeholder_type<'tcx>(
cx: &dyn HirTyLowerer<'tcx>,
def_id: LocalDefId,