Skip to content

Commit e4501a8

Browse files
committed
handle invalid identifiers
1 parent b0c84c9 commit e4501a8

File tree

2 files changed

+36
-2
lines changed

2 files changed

+36
-2
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Narrowing using `hasattr()`
2+
3+
The builtin function `hasattr()` can be used to narrow nominal and structural types. This is
4+
accomplished using an intersection with a synthesized protocol:
5+
6+
```py
7+
from typing import final
8+
9+
class Foo: ...
10+
11+
@final
12+
class Bar: ...
13+
14+
def f(x: Foo):
15+
if hasattr(x, "spam"):
16+
reveal_type(x) # revealed: Foo & <Protocol with members 'spam'>
17+
reveal_type(x.spam) # revealed: object
18+
19+
if hasattr(x, "not-an-identifier"):
20+
reveal_type(x) # revealed: Foo
21+
22+
def y(x: Bar):
23+
if hasattr(x, "spam"):
24+
reveal_type(x) # revealed: Never
25+
reveal_type(x.spam) # revealed: Never
26+
```

crates/ty_python_semantic/src/types/narrow.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ use crate::types::{
1111
UnionBuilder,
1212
};
1313
use crate::Db;
14+
15+
use ruff_python_stdlib::identifiers::is_identifier;
16+
1417
use itertools::Itertools;
1518
use ruff_python_ast as ast;
1619
use ruff_python_ast::{BoolOp, ExprBoolOp};
@@ -718,11 +721,16 @@ impl<'db> NarrowingConstraintsBuilder<'db> {
718721
if function == KnownFunction::HasAttr {
719722
let attr = inference
720723
.expression_type(second_arg.scoped_expression_id(self.db, scope))
721-
.into_string_literal()?;
724+
.into_string_literal()?
725+
.value(self.db);
726+
727+
if !is_identifier(attr) {
728+
return None;
729+
}
722730

723731
let constraint = Type::synthesized_protocol(
724732
self.db,
725-
[(attr.value(self.db), KnownClass::Object.to_instance(self.db))],
733+
[(attr, KnownClass::Object.to_instance(self.db))],
726734
);
727735

728736
return Some(NarrowingConstraints::from_iter([(

0 commit comments

Comments
 (0)