Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4344,7 +4344,7 @@ dependencies = [
"rustc_hir",
"rustc_index",
"rustc_infer",
"rustc_lint",
"rustc_lint_defs",
"rustc_macros",
"rustc_middle",
"rustc_pattern_analysis",
Expand Down
120 changes: 120 additions & 0 deletions compiler/rustc_borrowck/src/diagnostics/region_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,119 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
}
}

/// For closure/coroutine upvar regions, attempts to find a named lifetime
/// from the parent function's signature that corresponds to the anonymous
/// region `fr`. This handles cases where a parent function's named lifetime
/// (like `'a`) appears in a captured variable's type but gets assigned a
/// separate `RegionVid` without an `external_name` during region renumbering.
///
/// Works by getting the parent function's parameter type (with real named
/// lifetimes via `liberate_late_bound_regions`), then structurally walking
/// both the parent's parameter type and the closure's upvar type to find
/// where `fr` appears and what named lifetime is at the same position.
#[instrument(level = "trace", skip(self))]
fn give_name_if_we_can_match_upvar_args(
&self,
fr: RegionVid,
upvar_index: usize,
) -> Option<RegionName> {
let tcx = self.infcx.tcx;
let defining_ty = self.regioncx.universal_regions().defining_ty;

let closure_def_id = match defining_ty {
DefiningTy::Closure(def_id, _)
| DefiningTy::Coroutine(def_id, _)
| DefiningTy::CoroutineClosure(def_id, _) => def_id,
_ => return None,
};

let parent_def_id = tcx.parent(closure_def_id);

// Only works if the parent is a function with a fn_sig.
if !matches!(tcx.def_kind(parent_def_id), DefKind::Fn | DefKind::AssocFn) {
return None;
}

// Find which parameter index this upvar corresponds to by matching
// the captured variable's HirId against the parent's parameter patterns.
// This only matches simple bindings (not destructuring patterns) and
// only when the upvar is a direct parameter (not a local variable).
let captured_place = self.upvars.get(upvar_index)?;
let upvar_hir_id = captured_place.get_root_variable();
let parent_local_def_id = parent_def_id.as_local()?;
let parent_body = tcx.hir_body_owned_by(parent_local_def_id);
let param_index =
parent_body.params.iter().position(|param| param.pat.hir_id == upvar_hir_id)?;

// Get the parent fn's signature with liberated late-bound regions,
// so we have `ReLateParam` instead of `ReBound`.
let parent_fn_sig = tcx.fn_sig(parent_def_id).instantiate_identity();
let liberated_sig = tcx.liberate_late_bound_regions(parent_def_id, parent_fn_sig);
let parent_param_ty = *liberated_sig.inputs().get(param_index)?;

// Get the upvar's NLL type (with ReVar regions from renumbering).
let upvar_nll_ty = *defining_ty.upvar_tys().get(upvar_index)?;

debug!(
"give_name_if_we_can_match_upvar_args: parent_param_ty={:?}, upvar_nll_ty={:?}",
parent_param_ty, upvar_nll_ty
);

// Collect free regions from both types in structural order.
// This only works when both types have the same structure, i.e.
// the upvar captures the whole variable, not a partial place like
// `x.field`. Bail out if the region counts differ, since that means
// the types diverged and positional correspondence is unreliable.
let mut parent_regions = vec![];
tcx.for_each_free_region(&parent_param_ty, |r| parent_regions.push(r));

let mut nll_regions = vec![];
tcx.for_each_free_region(&upvar_nll_ty, |r| nll_regions.push(r));

if parent_regions.len() != nll_regions.len() {
debug!(
"give_name_if_we_can_match_upvar_args: region count mismatch ({} vs {})",
parent_regions.len(),
nll_regions.len()
);
return None;
}

for (parent_r, nll_r) in iter::zip(&parent_regions, &nll_regions) {
if nll_r.as_var() == fr {
match parent_r.kind() {
ty::ReLateParam(late_param) => {
if let Some(name) = late_param.kind.get_name(tcx) {
let span = late_param
.kind
.get_id()
.and_then(|id| tcx.hir_span_if_local(id))
.unwrap_or(DUMMY_SP);
return Some(RegionName {
name,
source: RegionNameSource::NamedLateParamRegion(span),
});
}
}
ty::ReEarlyParam(ebr) => {
if ebr.is_named() {
let def_id =
tcx.generics_of(parent_def_id).region_param(ebr, tcx).def_id;
let span = tcx.hir_span_if_local(def_id).unwrap_or(DUMMY_SP);
return Some(RegionName {
name: ebr.name,
source: RegionNameSource::NamedEarlyParamRegion(span),
});
}
}
_ => {}
}
}
}

None
}

/// Finds an argument that contains `fr` and label it with a fully
/// elaborated type, returning something like `'1`. Result looks
/// like:
Expand Down Expand Up @@ -644,6 +757,13 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
#[instrument(level = "trace", skip(self))]
fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Option<RegionName> {
let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?;

// Before synthesizing an anonymous name like `'1`, try to find a
// named lifetime from the parent function's signature that matches.
if let Some(region_name) = self.give_name_if_we_can_match_upvar_args(fr, upvar_index) {
return Some(region_name);
}

let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region(
self.infcx.tcx,
self.upvars,
Expand Down
9 changes: 0 additions & 9 deletions compiler/rustc_middle/src/query/job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,8 @@ use parking_lot::{Condvar, Mutex};
use rustc_span::Span;

use crate::query::plumbing::CycleError;
use crate::query::stack::QueryStackFrame;
use crate::ty::TyCtxt;

/// Represents a span and a query key.
#[derive(Clone, Debug)]
pub struct QueryInfo<'tcx> {
/// The span corresponding to the reason for which this query was required.
pub span: Span,
pub frame: QueryStackFrame<'tcx>,
}

/// A value uniquely identifying an active query job.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct QueryJobId(pub NonZero<u64>);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use rustc_hir::def_id::LocalDefId;

pub use self::caches::{DefIdCache, DefaultCache, QueryCache, SingleCache, VecCache};
pub use self::job::{QueryInfo, QueryJob, QueryJobId, QueryLatch, QueryWaiter};
pub use self::job::{QueryJob, QueryJobId, QueryLatch, QueryWaiter};
pub use self::keys::{AsLocalQueryKey, LocalCrate, QueryKey};
pub use self::plumbing::{
ActiveKeyStatus, CycleError, EnsureMode, IntoQueryParam, QueryMode, QueryState, TyCtxtAt,
Expand Down
12 changes: 7 additions & 5 deletions compiler/rustc_middle/src/query/plumbing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ use rustc_data_structures::sync::{AtomicU64, WorkerLocal};
use rustc_errors::Diag;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::hir_id::OwnerId;
use rustc_span::Span;
use rustc_span::{Span, Spanned};
pub use sealed::IntoQueryParam;

use crate::dep_graph::{DepKind, DepNodeIndex, SerializedDepNodeIndex};
use crate::ich::StableHashingContext;
use crate::queries::{ExternProviders, Providers, QueryArenas, QueryVTables, TaggedQueryKey};
use crate::query::on_disk_cache::OnDiskCache;
use crate::query::stack::QueryStackFrame;
use crate::query::{QueryCache, QueryInfo, QueryJob};
use crate::query::{QueryCache, QueryJob};
use crate::ty::TyCtxt;

/// For a particular query, keeps track of "active" keys, i.e. keys whose
Expand Down Expand Up @@ -50,11 +50,13 @@ pub enum ActiveKeyStatus<'tcx> {
Poisoned,
}

#[derive(Clone, Debug)]
#[derive(Debug)]
pub struct CycleError<'tcx> {
/// The query and related span that uses the cycle.
pub usage: Option<(Span, QueryStackFrame<'tcx>)>,
pub cycle: Vec<QueryInfo<'tcx>>,
pub usage: Option<Spanned<QueryStackFrame<'tcx>>>,

/// The span here corresponds to the reason for which this query was required.
pub cycle: Vec<Spanned<QueryStackFrame<'tcx>>>,
}

#[derive(Debug)]
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ rustc_errors = { path = "../rustc_errors" }
rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
rustc_infer = { path = "../rustc_infer" }
rustc_lint = { path = "../rustc_lint" }
rustc_lint_defs = { path = "../rustc_lint_defs" }
rustc_macros = { path = "../rustc_macros" }
rustc_middle = { path = "../rustc_middle" }
rustc_pattern_analysis = { path = "../rustc_pattern_analysis" }
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/thir/pattern/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rustc_hir::def::*;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{self as hir, BindingMode, ByRef, HirId, MatchSource};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::Level;
use rustc_lint_defs::Level;
use rustc_middle::bug;
use rustc_middle::thir::visit::Visitor;
use rustc_middle::thir::*;
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_mir_build/src/thir/pattern/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, pluralize};
use rustc_hir::{BindingMode, ByRef, HirId, Mutability};
use rustc_lint as lint;
use rustc_lint_defs::builtin::RUST_2024_INCOMPATIBLE_PAT;
use rustc_middle::ty::{self, Rust2024IncompatiblePatInfo, TyCtxt};
use rustc_span::{Ident, Span};

Expand Down Expand Up @@ -56,7 +56,7 @@ impl<'a> PatMigration<'a> {
err.emit();
} else {
tcx.emit_node_span_lint(
lint::builtin::RUST_2024_INCOMPATIBLE_PAT,
RUST_2024_INCOMPATIBLE_PAT,
pat_id,
spans,
rustc_errors::DiagDecorator(|diag| {
Expand Down
28 changes: 14 additions & 14 deletions compiler/rustc_query_impl/src/from_cycle_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,11 @@ fn fn_sig<'tcx>(
fn check_representability<'tcx>(tcx: TyCtxt<'tcx>, cycle_error: CycleError<'tcx>) -> ! {
let mut item_and_field_ids = Vec::new();
let mut representable_ids = FxHashSet::default();
for info in &cycle_error.cycle {
if info.frame.dep_kind == DepKind::check_representability
&& let Some(field_id) = info.frame.def_id
for frame in &cycle_error.cycle {
if frame.node.dep_kind == DepKind::check_representability
&& let Some(field_id) = frame.node.def_id
&& let Some(field_id) = field_id.as_local()
&& let Some(DefKind::Field) = info.frame.tagged_key.def_kind(tcx)
&& let Some(DefKind::Field) = frame.node.tagged_key.def_kind(tcx)
{
let parent_id = tcx.parent(field_id.to_def_id());
let item_id = match tcx.def_kind(parent_id) {
Expand All @@ -90,8 +90,8 @@ fn check_representability<'tcx>(tcx: TyCtxt<'tcx>, cycle_error: CycleError<'tcx>
item_and_field_ids.push((item_id.expect_local(), field_id));
}
}
for info in &cycle_error.cycle {
if let TaggedQueryKey::check_representability_adt_ty(key) = info.frame.tagged_key
for frame in &cycle_error.cycle {
if let TaggedQueryKey::check_representability_adt_ty(key) = frame.node.tagged_key
&& let Some(adt) = key.ty_adt_def()
&& let Some(def_id) = adt.did().as_local()
&& !item_and_field_ids.iter().any(|&(id, _)| id == def_id)
Expand All @@ -109,9 +109,9 @@ fn variances_of<'tcx>(tcx: TyCtxt<'tcx>, cycle_error: CycleError<'tcx>) -> &'tcx
search_for_cycle_permutation(
&cycle_error.cycle,
|cycle| {
if let Some(info) = cycle.get(0)
&& info.frame.dep_kind == DepKind::variances_of
&& let Some(def_id) = info.frame.def_id
if let Some(frame) = cycle.get(0)
&& frame.node.dep_kind == DepKind::variances_of
&& let Some(def_id) = frame.node.def_id
{
let n = tcx.generics_of(def_id).own_params.len();
ControlFlow::Break(tcx.arena.alloc_from_iter(iter::repeat_n(ty::Bivariant, n)))
Expand All @@ -121,7 +121,7 @@ fn variances_of<'tcx>(tcx: TyCtxt<'tcx>, cycle_error: CycleError<'tcx>) -> &'tcx
},
|| {
span_bug!(
cycle_error.usage.as_ref().unwrap().0,
cycle_error.usage.as_ref().unwrap().span,
"only `variances_of` returns `&[ty::Variance]`"
)
},
Expand Down Expand Up @@ -154,7 +154,7 @@ fn layout_of<'tcx>(
let diag = search_for_cycle_permutation(
&cycle_error.cycle,
|cycle| {
if let TaggedQueryKey::layout_of(key) = cycle[0].frame.tagged_key
if let TaggedQueryKey::layout_of(key) = cycle[0].node.tagged_key
&& let ty::Coroutine(def_id, _) = key.value.kind()
&& let Some(def_id) = def_id.as_local()
&& let def_kind = tcx.def_kind(def_id)
Expand All @@ -178,8 +178,8 @@ fn layout_of<'tcx>(
tcx.def_kind_descr_article(def_kind, def_id.to_def_id()),
tcx.def_kind_descr(def_kind, def_id.to_def_id()),
);
for (i, info) in cycle.iter().enumerate() {
let TaggedQueryKey::layout_of(frame_key) = info.frame.tagged_key else {
for (i, frame) in cycle.iter().enumerate() {
let TaggedQueryKey::layout_of(frame_key) = frame.node.tagged_key else {
continue;
};
let &ty::Coroutine(frame_def_id, _) = frame_key.value.kind() else {
Expand All @@ -189,7 +189,7 @@ fn layout_of<'tcx>(
continue;
};
let frame_span =
info.frame.tagged_key.default_span(tcx, cycle[(i + 1) % cycle.len()].span);
frame.node.tagged_key.default_span(tcx, cycle[(i + 1) % cycle.len()].span);
if frame_span.is_dummy() {
continue;
}
Expand Down
Loading
Loading