Skip to content

[ty] Respect subclass shadowing for inherited NamedTuple fields - #24640

Merged
charliermarsh merged 1 commit into
mainfrom
charlie/named-tuple-shadowing
Apr 14, 2026
Merged

charliermarsh merged 1 commit into
mainfrom
charlie/named-tuple-shadowing

Conversation

@charliermarsh

Copy link
Copy Markdown
Member

Summary

Closes astral-sh/ty#3273.

@astral-sh-bot astral-sh-bot Bot added the ty The ty type checker label Apr 14, 2026
@astral-sh-bot

astral-sh-bot Bot commented Apr 14, 2026 •

Copy link
Copy Markdown

Typing conformance results

No changes detected ✅

Current numbers
The percentage of diagnostics emitted that were expected errors held steady at 87.94%. The percentage of expected errors that received a diagnostic held steady at 83.21%. The number of fully passing files held steady at 79/133.

@astral-sh-bot

astral-sh-bot Bot commented Apr 14, 2026 •

Copy link
Copy Markdown

Memory usage report

Summary

Project Old New Diff Outcome
prefect 708.07MB 709.24MB +0.17% (1.17MB) ⏫
sphinx 261.94MB 262.61MB +0.25% (682.39kB) ⏫
trio 117.33MB 117.49MB +0.13% (160.66kB) ⏫
flake8 47.82MB 47.90MB +0.16% (78.50kB) ⏫

Significant changes

Click to expand detailed breakdown

prefect

Name Old New Diff Outcome
Type<'db>::member_lookup_with_policy_ 16.13MB 17.22MB +6.75% (1.09MB) ⏫
infer_scope_types_impl 54.20MB 54.22MB +0.04% (20.70kB) ⏫
infer_expression_types_impl 62.02MB 62.04MB +0.03% (19.57kB) ⏫
infer_expression_type_impl 13.15MB 13.17MB +0.12% (16.41kB) ⏫
infer_definition_types 89.80MB 89.81MB +0.01% (9.75kB) ⏫
StaticClassLiteral<'db>::implicit_attribute_inner_ 9.94MB 9.94MB +0.06% (6.27kB) ⏫
all_narrowing_constraints_for_expression 7.15MB 7.15MB +0.04% (3.14kB) ⏫
code_generator_of_static_class 1.36MB 1.36MB +0.17% (2.34kB) ⏫
all_negative_narrowing_constraints_for_expression 2.62MB 2.62MB +0.06% (1.52kB) ⏫
Type<'db>::class_member_with_policy_ 17.42MB 17.42MB +0.01% (1.08kB) ⏫
code_generator_of_static_class::interned_arguments 707.06kB 708.05kB +0.14% (1008.00B) ⏫
StaticClassLiteral<'db>::implicit_attribute_inner_::interned_arguments 5.32MB 5.32MB -0.01% (768.00B) ⏫
GenericAlias<'db>::variance_of_ 579.40kB 579.96kB +0.10% (576.00B) ⏫
FunctionType<'db>::signature_ 4.02MB 4.02MB +0.01% (288.00B) ⏫
StaticClassLiteral<'db>::is_typed_dict_ 627.14kB 627.38kB +0.04% (240.00B) ⏫
... 9 more

sphinx

Name Old New Diff Outcome
Type<'db>::member_lookup_with_policy_ 6.25MB 6.89MB +10.26% (656.02kB) ⏫
infer_scope_types_impl 15.44MB 15.45MB +0.08% (12.61kB) ⏫
infer_expression_types_impl 20.91MB 20.92MB +0.02% (4.50kB) ⏫
infer_expression_type_impl 2.90MB 2.91MB +0.14% (4.31kB) ⏫
infer_definition_types 23.76MB 23.76MB +0.01% (1.69kB) ⏫
all_narrowing_constraints_for_expression 2.34MB 2.34MB +0.04% (1.05kB) ⏫
StaticClassLiteral<'db>::implicit_attribute_inner_ 2.36MB 2.36MB +0.04% (1.03kB) ⏫
code_generator_of_static_class 518.59kB 519.52kB +0.18% (960.00B) ⏫
StaticClassLiteral<'db>::implicit_attribute_inner_::interned_arguments 1.93MB 1.93MB -0.03% (576.00B) ⏫
code_generator_of_static_class::interned_arguments 258.89kB 259.31kB +0.16% (432.00B) ⏫
StaticClassLiteral<'db>::is_typed_dict_ 182.48kB 182.80kB +0.17% (324.00B) ⏫
all_negative_narrowing_constraints_for_expression 1.00MB 1.00MB +0.01% (72.00B) ⏫

trio

Name Old New Diff Outcome
Type<'db>::member_lookup_with_policy_ 1.80MB 1.95MB +8.01% (147.87kB) ⏫
infer_scope_types_impl 4.75MB 4.75MB +0.08% (3.84kB) ⏫
code_generator_of_static_class 209.39kB 211.96kB +1.23% (2.57kB) ⏫
infer_expression_types_impl 7.03MB 7.03MB +0.03% (1.90kB) ⏫
infer_expression_type_impl 1.31MB 1.31MB +0.13% (1.69kB) ⏫
code_generator_of_static_class::interned_arguments 103.36kB 104.55kB +1.16% (1.20kB) ⏫
StaticClassLiteral<'db>::is_typed_dict_ 66.52kB 67.26kB +1.11% (756.00B) ⏫
infer_definition_types 7.61MB 7.61MB +0.01% (528.00B) ⏫
all_narrowing_constraints_for_expression 592.11kB 592.32kB +0.04% (216.00B) ⏫
StaticClassLiteral<'db>::implicit_attribute_inner_ 745.97kB 746.18kB +0.03% (208.00B) ⏫
StaticClassLiteral<'db>::implicit_attribute_inner_::interned_arguments 602.44kB 602.25kB -0.03% (192.00B) ⏫
all_negative_narrowing_constraints_for_expression 184.44kB 184.51kB +0.04% (72.00B) ⏫
loop_header_reachability 131.76kB 131.79kB +0.02% (24.00B) ⏫
infer_unpack_types 143.38kB 143.41kB +0.02% (24.00B) ⏫

flake8

Name Old New Diff Outcome
Type<'db>::member_lookup_with_policy_ 482.61kB 558.21kB +15.67% (75.61kB) ⏫
infer_scope_types_impl 987.32kB 989.38kB +0.21% (2.06kB) ⏫
code_generator_of_static_class 61.05kB 61.57kB +0.84% (528.00B) ⏫
StaticClassLiteral<'db>::implicit_attribute_inner_::interned_arguments 256.31kB 255.84kB -0.18% (480.00B) ⏫
infer_expression_types_impl 1.04MB 1.04MB +0.04% (384.00B) ⏫
StaticClassLiteral<'db>::implicit_attribute_inner_ 310.30kB 309.94kB -0.12% (368.00B) ⏫
infer_expression_type_impl 118.12kB 118.45kB +0.28% (336.00B) ⏫
code_generator_of_static_class::interned_arguments 30.23kB 30.45kB +0.70% (216.00B) ⏫
StaticClassLiteral<'db>::is_typed_dict_ 28.04kB 28.17kB +0.46% (132.00B) ⏫
all_narrowing_constraints_for_expression 83.55kB 83.60kB +0.06% (48.00B) ⏫
infer_definition_types 1.87MB 1.87MB +0.00% (48.00B) ⏫

@astral-sh-bot

astral-sh-bot Bot commented Apr 14, 2026 •

Copy link
Copy Markdown

ecosystem-analyzer results

No diagnostic changes detected ✅

Full report with detailed diff (timing results)

@charliermarsh
charliermarsh force-pushed the charlie/named-tuple-shadowing branch 2 times, most recently from 962b71a to ce7056d Compare April 14, 2026 18:35

@AlexWaygood AlexWaygood left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, I assumed it would be something like this

Comment on lines +2267 to +2268
.keys()
.any(|field_name| field_name == name)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.keys()
.any(|field_name| field_name == name)
.contains_key(name)


/// `NamedTuple` fields are exposed via synthesized descriptors on the class rather than
/// instance attributes. If fields are unknown (dynamic), return `Any` for any attribute.
pub(super) fn own_instance_member(self, db: &'db dyn Db, _name: &str) -> Member<'db> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could also just remove the argument, but I don't feel strongly

diff --git a/crates/ty_python_semantic/src/types/class.rs b/crates/ty_python_semantic/src/types/class.rs
index ea809d830a..b0ca88fb50 100644
--- a/crates/ty_python_semantic/src/types/class.rs
+++ b/crates/ty_python_semantic/src/types/class.rs
@@ -1724,7 +1724,7 @@ impl<'db> ClassType<'db> {
                 dynamic.own_instance_member(db, name)
             }
             Self::NonGeneric(ClassLiteral::DynamicNamedTuple(namedtuple)) => {
-                namedtuple.own_instance_member(db, name)
+                namedtuple.own_instance_member(db)
             }
             Self::NonGeneric(ClassLiteral::DynamicTypedDict(_)) => Member::default(),
             Self::NonGeneric(ClassLiteral::DynamicEnum(enum_lit)) => {
diff --git a/crates/ty_python_semantic/src/types/class/named_tuple.rs b/crates/ty_python_semantic/src/types/class/named_tuple.rs
index a62f36403f..a2026a51a5 100644
--- a/crates/ty_python_semantic/src/types/class/named_tuple.rs
+++ b/crates/ty_python_semantic/src/types/class/named_tuple.rs
@@ -275,7 +275,7 @@ impl<'db> DynamicNamedTupleLiteral<'db> {
     ///
     /// `NamedTuple` fields are exposed via synthesized descriptors on the class rather than
     /// instance attributes. If fields are unknown (dynamic), return `Any` for any attribute.
-    pub(super) fn own_instance_member(self, db: &'db dyn Db, _name: &str) -> Member<'db> {
+    pub(super) fn own_instance_member(self, db: &'db dyn Db) -> Member<'db> {
         if !self.has_known_fields(db) {
             return Member::definitely_declared(Type::any());
         }
@@ -286,7 +286,7 @@ impl<'db> DynamicNamedTupleLiteral<'db> {
     /// Look up an instance member by name (including superclasses).
     pub(crate) fn instance_member(self, db: &'db dyn Db, name: &str) -> PlaceAndQualifiers<'db> {
         // First check own instance members.
-        let result = self.own_instance_member(db, name);
+        let result = self.own_instance_member(db);
         if !result.is_undefined() {
             return result.inner;
         }

@AlexWaygood AlexWaygood self-assigned this Apr 14, 2026
@charliermarsh
charliermarsh marked this pull request as ready for review April 14, 2026 19:18
@astral-sh-bot
astral-sh-bot Bot requested a review from AlexWaygood April 14, 2026 19:18
@charliermarsh
charliermarsh force-pushed the charlie/named-tuple-shadowing branch from ce7056d to f131bb9 Compare April 14, 2026 19:23
@charliermarsh
charliermarsh enabled auto-merge (squash) April 14, 2026 19:24
@charliermarsh
charliermarsh merged commit 1c29188 into main Apr 14, 2026
55 checks passed
@charliermarsh
charliermarsh deleted the charlie/named-tuple-shadowing branch April 14, 2026 19:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ty The ty type checker

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Model inherited NamedTuple field shadowing through normal attribute lookup

2 participants