Skip to content

Commit 922a031

Browse files
authored
[ty] Fix invalid-match-pattern false positives (#23338)
## Summary Any `type` type can only be inhabited by class objects; any `type | <dynamic type>` union could materialize to a class object; and any `<class object> & <dynamic type>` intersection is a subtype of a class object. So using a value that inhabits any of these types as a class pattern should not cause us to emit the `invalid-match-pattern` diagnostic. This PR fixes several false positives that showed up in the ecosystem report in #22939 ## Test Plan mdtests added
1 parent f76fe59 commit 922a031

2 files changed

Lines changed: 15 additions & 5 deletions

File tree

crates/ty_python_semantic/resources/mdtest/conditional/match.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,10 @@ then uses `isinstance` to check the match.
444444
If the match pattern is not an instance of `type`, we raise a diagnostic:
445445

446446
```py
447-
def _(val):
447+
from typing import Any
448+
from ty_extensions import Intersection
449+
450+
def _(val, Valid1: type | Any, Valid2: Intersection[type, Any], Valid3: type[Any], Valid4: type[int]):
448451
Invalid1 = "foo"
449452

450453
match val:
@@ -455,7 +458,16 @@ def _(val):
455458

456459
match val:
457460
# error: [invalid-match-pattern] "`<types.UnionType special-form 'int | str'>` cannot be used in a class pattern because it is not a type"
458-
case Invalid2(): ...
461+
case Invalid2():
462+
pass
463+
case Valid1(): # fine
464+
pass
465+
case Valid2(): # fine
466+
pass
467+
case Valid3(): # fine
468+
pass
469+
case Valid4(): # fine
470+
pass
459471
```
460472

461473
We also raise a diagnostic if the class cannot be used with `isinstance`:

crates/ty_python_semantic/src/types/infer/builder.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5070,9 +5070,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
50705070
protocol_class,
50715071
);
50725072
}
5073-
} else if !cls_ty.is_dynamic()
5074-
&& !cls_ty.is_subtype_of(self.db(), KnownClass::Type.to_instance(self.db()))
5075-
{
5073+
} else if !cls_ty.is_assignable_to(self.db(), KnownClass::Type.to_instance(self.db())) {
50765074
report_invalid_class_match_pattern(&self.context, &*pattern.cls, cls_ty);
50775075
}
50785076
}

0 commit comments

Comments
 (0)