[ty] Add backreferences to TypedDict items in diagnostics (#20262)

## Summary

Add backreferences to the original item declaration in TypedDict
diagnostics.

Thanks to @AlexWaygood for the suggestion.

## Test Plan

Updated snapshots
This commit is contained in:
David Peter 2025-09-05 12:38:37 +02:00 committed by GitHub
parent 9e45bfa9fd
commit 8ade6c4eaf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 146 additions and 149 deletions

View file

@ -486,6 +486,9 @@ type DeclaredTypeAndConflictingTypes<'db> = (
pub(crate) struct PlaceFromDeclarationsResult<'db> {
place_and_quals: PlaceAndQualifiers<'db>,
conflicting_types: Option<Box<indexmap::set::Slice<Type<'db>>>>,
/// Contains `Some(declaration)` if the declared type originates from exactly one declaration.
/// This field is used for backreferences in diagnostics.
pub(crate) single_declaration: Option<Definition<'db>>,
}
impl<'db> PlaceFromDeclarationsResult<'db> {
@ -496,6 +499,7 @@ impl<'db> PlaceFromDeclarationsResult<'db> {
PlaceFromDeclarationsResult {
place_and_quals,
conflicting_types: Some(conflicting_types),
single_declaration: None,
}
}
@ -513,21 +517,6 @@ impl<'db> PlaceFromDeclarationsResult<'db> {
}
}
impl<'db> From<PlaceAndQualifiers<'db>> for PlaceFromDeclarationsResult<'db> {
fn from(place_and_quals: PlaceAndQualifiers<'db>) -> Self {
PlaceFromDeclarationsResult {
place_and_quals,
conflicting_types: None,
}
}
}
impl<'db> From<Place<'db>> for PlaceFromDeclarationsResult<'db> {
fn from(place: Place<'db>) -> Self {
PlaceFromDeclarationsResult::from(PlaceAndQualifiers::from(place))
}
}
/// A type with declaredness information, and a set of type qualifiers.
///
/// This is used to represent the result of looking up the declared type. Consider this
@ -1216,6 +1205,8 @@ fn place_from_declarations_impl<'db>(
let reachability_constraints = declarations.reachability_constraints;
let boundness_analysis = declarations.boundness_analysis;
let mut declarations = declarations.peekable();
let mut first_declaration = None;
let mut exactly_one_declaration = false;
let is_non_exported = |declaration: Definition<'db>| {
requires_explicit_reexport.is_yes() && !is_reexported(db, declaration)
@ -1246,6 +1237,13 @@ fn place_from_declarations_impl<'db>(
return None;
}
if first_declaration.is_none() {
first_declaration = Some(declaration);
exactly_one_declaration = true;
} else {
exactly_one_declaration = false;
}
let static_reachability =
reachability_constraints.evaluate(db, predicates, reachability_constraint);
@ -1302,10 +1300,18 @@ fn place_from_declarations_impl<'db>(
if let Some(conflicting) = conflicting {
PlaceFromDeclarationsResult::conflict(place_and_quals, conflicting)
} else {
place_and_quals.into()
PlaceFromDeclarationsResult {
place_and_quals,
conflicting_types: None,
single_declaration: first_declaration.filter(|_| exactly_one_declaration),
}
}
} else {
Place::Unbound.into()
PlaceFromDeclarationsResult {
place_and_quals: Place::Unbound.into(),
conflicting_types: None,
single_declaration: None,
}
}
}