1
Fork 0

Auto merge of #125468 - BoxyUwU:remove_defid_from_regionparam, r=compiler-errors

Remove `DefId` from `EarlyParamRegion`

Currently we represent usages of `Region` parameters via the `ReEarlyParam` or `ReLateParam` variants. The `ReEarlyParam` is effectively equivalent to `TyKind::Param` and `ConstKind::Param` (i.e. it stores a `Symbol` and a `u32` index) however it also stores a `DefId` for the definition of the lifetime parameter.

This was used in roughly two places:
- Borrowck diagnostics instead of threading the appropriate `body_id` down to relevant locations. Interestingly there were already some places that had to pass down a `DefId` manually.
- Some opaque type checking logic was using the `DefId` field to track captured lifetimes

I've split this PR up into a commit for generate rote changes to diagnostics code to pass around a `DefId` manually everywhere, and another commit for the opaque type related changes which likely require more careful review as they might change the semantics of lints/errors.

Instead of manually passing the `DefId` around everywhere I previously tried to bundle it in with `TypeErrCtxt` but ran into issues with some call sites of `infcx.err_ctxt` being unable to provide a `DefId`, particularly places involved with trait solving and normalization. It might be worth investigating adding some new wrapper type to pass this around everywhere but I think this might be acceptable for now.

This pr also has the effect of reducing the size of `EarlyParamRegion` from 16 bytes -> 8 bytes. I wouldn't expect this to have any direct performance improvement however, other variants of `RegionKind` over `8` bytes are all because they contain a `BoundRegionKind` which is, as far as I know, mostly there for diagnostics. If we're ever able to remove this it would shrink the `RegionKind` type from `24` bytes to `12` (and with clever bit packing we might be able to get it to `8` bytes). I am curious what the performance impact would be of removing interning of `Region`'s if we ever manage to shrink `RegionKind` that much.

Sidenote: by removing the `DefId` the `Debug` output for `Region` has gotten significantly nicer. As an example see this opaque type debug print before vs after this PR:
`Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), [DefId(0:9 ~ impl_trait_captures[aeb9]::foo::'a)_'a/#0, T, DefId(0:9 ~ impl_trait_captures[aeb9]::foo::'a)_'a/#0])`
`Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), ['a/#0, T, 'a/#0])`

r? `@compiler-errors` (I would like someone who understands the opaque type setup to atleast review the type system commit, but the rest is likely reviewable by anyone)
This commit is contained in:
bors 2024-05-27 06:36:57 +00:00
commit fec98b3bbc
31 changed files with 320 additions and 212 deletions

View file

@ -1950,14 +1950,22 @@ declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMEN
impl ExplicitOutlivesRequirements {
fn lifetimes_outliving_lifetime<'tcx>(
tcx: TyCtxt<'tcx>,
inferred_outlives: &'tcx [(ty::Clause<'tcx>, Span)],
def_id: DefId,
item: DefId,
lifetime: DefId,
) -> Vec<ty::Region<'tcx>> {
let item_generics = tcx.generics_of(item);
inferred_outlives
.iter()
.filter_map(|(clause, _)| match clause.kind().skip_binder() {
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a {
ty::ReEarlyParam(ebr) if ebr.def_id == def_id => Some(b),
ty::ReEarlyParam(ebr)
if item_generics.region_param(ebr, tcx).def_id == lifetime =>
{
Some(b)
}
_ => None,
},
_ => None,
@ -1986,9 +1994,12 @@ impl ExplicitOutlivesRequirements {
bounds: &hir::GenericBounds<'_>,
inferred_outlives: &[ty::Region<'tcx>],
predicate_span: Span,
item: DefId,
) -> Vec<(usize, Span)> {
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
let item_generics = tcx.generics_of(item);
bounds
.iter()
.enumerate()
@ -2000,7 +2011,7 @@ impl ExplicitOutlivesRequirements {
let is_inferred = match tcx.named_bound_var(lifetime.hir_id) {
Some(ResolvedArg::EarlyBound(def_id)) => inferred_outlives
.iter()
.any(|r| matches!(**r, ty::ReEarlyParam(ebr) if { ebr.def_id == def_id })),
.any(|r| matches!(**r, ty::ReEarlyParam(ebr) if { item_generics.region_param(ebr, tcx).def_id == def_id })),
_ => false,
};
@ -2109,7 +2120,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
{
(
Self::lifetimes_outliving_lifetime(
cx.tcx,
inferred_outlives,
item.owner_id.to_def_id(),
region_def_id,
),
&predicate.bounds,
@ -2152,6 +2165,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
bounds,
&relevant_lifetimes,
predicate_span,
item.owner_id.to_def_id(),
);
bound_count += bound_spans.len();

View file

@ -5,11 +5,11 @@ use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_macros::LintDiagnostic;
use rustc_middle::bug;
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
use rustc_middle::ty::{
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
};
use rustc_middle::{bug, span_bug};
use rustc_session::{declare_lint, declare_lint_pass};
use rustc_span::{sym, BytePos, Span};
@ -303,20 +303,12 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
ResolvedArg::EarlyBound(def_id) | ResolvedArg::LateBound(_, _, def_id),
) => {
if self.tcx.def_kind(self.tcx.parent(def_id)) == DefKind::OpaqueTy {
let (ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. })
| ty::ReLateParam(ty::LateParamRegion {
bound_region: ty::BoundRegionKind::BrNamed(def_id, _),
..
})) = self
let def_id = self
.tcx
.map_opaque_lifetime_to_parent_lifetime(def_id.expect_local())
.kind()
else {
span_bug!(
self.tcx.def_span(def_id),
"variable should have been duplicated from a parent"
);
};
.opt_param_def_id(self.tcx, self.parent_def_id.to_def_id())
.expect("variable should have been duplicated from parent");
explicitly_captured.insert(def_id);
} else {
explicitly_captured.insert(def_id);