Skip to content

Commit 9be1e82

Browse files
committed
Record unbound in attrs after fallback mechanism
1 parent ecbe2a4 commit 9be1e82

File tree

1 file changed

+81
-8
lines changed
  • crates/ty_python_semantic/src/types

1 file changed

+81
-8
lines changed

crates/ty_python_semantic/src/types/infer.rs

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7107,7 +7107,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
71077107
}
71087108

71097109
fn narrow_expr_with_applicable_constraints<'r>(
7110-
&self,
7110+
&mut self,
71117111
target: impl Into<ast::ExprRef<'r>>,
71127112
target_ty: Type<'db>,
71137113
constraint_keys: &[(FileScopeId, ConstraintKey)],
@@ -7141,7 +7141,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
71417141

71427142
let mut assigned_type = None;
71437143
if let Some(place_expr) = PlaceExpr::try_from_expr(attribute) {
7144-
let (resolved, keys) = self.record_place_load(
7144+
let (resolved, keys) = self.infer_place_load(
71457145
PlaceExprRef::from(&place_expr),
71467146
ast::ExprRef::Attribute(attribute),
71477147
);
@@ -7151,10 +7151,16 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
71517151
}
71527152
}
71537153

7154-
let resolved_type = value_type
7155-
.member(db, &attr.id)
7156-
.map_type(|ty| self.narrow_expr_with_applicable_constraints(attribute, ty, &constraint_keys))
7157-
.unwrap_with_diagnostic(|lookup_error| match lookup_error {
7154+
let fallback_place = value_type.member(db, &attr.id);
7155+
if !fallback_place.place.is_definitely_bound() {
7156+
self.all_definitely_bound = false;
7157+
eprintln!("attribute: {:?} was not bound", attribute);
7158+
}
7159+
7160+
let resolved_type =
7161+
fallback_place.map_type(|ty| {
7162+
self.narrow_expr_with_applicable_constraints(attribute, ty, &constraint_keys)
7163+
}).unwrap_with_diagnostic(|lookup_error| match lookup_error {
71587164
LookupError::Unbound(_) => {
71597165
let report_unresolved_attribute = self.is_reachable(attribute);
71607166

@@ -11516,8 +11522,8 @@ mod tests {
1151611522
1151711523
class Toggle:
1151811524
def __init__(self: "Toggle"):
11519-
if self.x:
11520-
self.x: Literal[False] = False
11525+
if not self.x:
11526+
self.x: Literal[True] = True
1152111527
"#,
1152211528
)
1152311529
.unwrap();
@@ -11545,6 +11551,73 @@ mod tests {
1154511551
assert_eq!(cycles.len(), 1);
1154611552
}
1154711553

11554+
#[test]
11555+
fn analyze_cycles_gridout() {
11556+
let mut db = setup_db();
11557+
let filename = "src/gridout.py";
11558+
db.write_dedented(
11559+
filename,
11560+
r#"
11561+
EMPTY = b""
11562+
class GridOut:
11563+
def __init__(self: "GridOut") -> None:
11564+
self._buffer_pos = 0
11565+
self._buffer = b""
11566+
def readchunk(self: "GridOut") -> bytes:
11567+
if not len(self._buffer) - self._buffer_pos:
11568+
raise Exception("truncated chunk")
11569+
self._buffer_pos = 0
11570+
return EMPTY
11571+
def _read_size_or_line(self: "GridOut", size: int = -1) -> bytes:
11572+
if size > self._position:
11573+
size = self._position
11574+
if size == 0:
11575+
return bytes()
11576+
received = 0
11577+
needed = size - received
11578+
while received < size:
11579+
if self._buffer:
11580+
buf = self._buffer
11581+
chunk_start = self._buffer_pos
11582+
chunk_data = buf[self._buffer_pos :]
11583+
self._buffer = EMPTY
11584+
else:
11585+
buf = self.readchunk()
11586+
chunk_start = 0
11587+
chunk_data = buf
11588+
needed = buf.find(EMPTY, chunk_start, chunk_start + needed)
11589+
if len(chunk_data) > needed:
11590+
self._buffer = buf
11591+
self._buffer_pos = chunk_start + needed
11592+
self._position -= len(self._buffer) - self._buffer_pos
11593+
return b""
11594+
"#,
11595+
)
11596+
.unwrap();
11597+
11598+
db.clear_salsa_events();
11599+
assert_file_diagnostics(&db, filename, &[]);
11600+
let events = db.take_salsa_events();
11601+
let cycles = salsa::attach(&db, || {
11602+
events
11603+
.iter()
11604+
.filter_map(|event| {
11605+
if let salsa::EventKind::WillIterateCycle {
11606+
database_key,
11607+
iteration_count,
11608+
fell_back: _,
11609+
} = event.kind
11610+
{
11611+
Some(format!("{database_key:?}, {iteration_count:?}"))
11612+
} else {
11613+
None
11614+
}
11615+
})
11616+
.collect::<Vec<_>>()
11617+
});
11618+
assert_eq!(cycles.len(), 2414);
11619+
}
11620+
1154811621
#[test]
1154911622
fn not_literal_string() -> anyhow::Result<()> {
1155011623
let mut db = setup_db();

0 commit comments

Comments
 (0)