@@ -7027,7 +7027,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
70277027 }
70287028
70297029 fn narrow_expr_with_applicable_constraints < ' r > (
7030- & self ,
7030+ & mut self ,
70317031 target : impl Into < ast:: ExprRef < ' r > > ,
70327032 target_ty : Type < ' db > ,
70337033 constraint_keys : & [ ( FileScopeId , ConstraintKey ) ] ,
@@ -7061,7 +7061,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
70617061
70627062 let mut assigned_type = None ;
70637063 if let Some ( place_expr) = PlaceExpr :: try_from_expr ( attribute) {
7064- let ( resolved, keys) = self . record_place_load (
7064+ let ( resolved, keys) = self . infer_place_load (
70657065 PlaceExprRef :: from ( & place_expr) ,
70667066 ast:: ExprRef :: Attribute ( attribute) ,
70677067 ) ;
@@ -7071,10 +7071,16 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
70717071 }
70727072 }
70737073
7074- let resolved_type = value_type
7075- . member ( db, & attr. id )
7076- . map_type ( |ty| self . narrow_expr_with_applicable_constraints ( attribute, ty, & constraint_keys) )
7077- . unwrap_with_diagnostic ( |lookup_error| match lookup_error {
7074+ let fallback_place = value_type. member ( db, & attr. id ) ;
7075+ if !fallback_place. place . is_definitely_bound ( ) {
7076+ self . all_definitely_bound = false ;
7077+ eprintln ! ( "attribute: {:?} was not bound" , attribute) ;
7078+ }
7079+
7080+ let resolved_type =
7081+ fallback_place. map_type ( |ty| {
7082+ self . narrow_expr_with_applicable_constraints ( attribute, ty, & constraint_keys)
7083+ } ) . unwrap_with_diagnostic ( |lookup_error| match lookup_error {
70787084 LookupError :: Unbound ( _) => {
70797085 let report_unresolved_attribute = self . is_reachable ( attribute) ;
70807086
@@ -11361,8 +11367,8 @@ mod tests {
1136111367
1136211368 class Toggle:
1136311369 def __init__(self: "Toggle"):
11364- if self.x:
11365- self.x: Literal[False ] = False
11370+ if not self.x:
11371+ self.x: Literal[True ] = True
1136611372 "# ,
1136711373 )
1136811374 . unwrap ( ) ;
@@ -11390,6 +11396,73 @@ mod tests {
1139011396 assert_eq ! ( cycles. len( ) , 1 ) ;
1139111397 }
1139211398
11399+ #[ test]
11400+ fn analyze_cycles_gridout ( ) {
11401+ let mut db = setup_db ( ) ;
11402+ let filename = "src/gridout.py" ;
11403+ db. write_dedented (
11404+ filename,
11405+ r#"
11406+ EMPTY = b""
11407+ class GridOut:
11408+ def __init__(self: "GridOut") -> None:
11409+ self._buffer_pos = 0
11410+ self._buffer = b""
11411+ def readchunk(self: "GridOut") -> bytes:
11412+ if not len(self._buffer) - self._buffer_pos:
11413+ raise Exception("truncated chunk")
11414+ self._buffer_pos = 0
11415+ return EMPTY
11416+ def _read_size_or_line(self: "GridOut", size: int = -1) -> bytes:
11417+ if size > self._position:
11418+ size = self._position
11419+ if size == 0:
11420+ return bytes()
11421+ received = 0
11422+ needed = size - received
11423+ while received < size:
11424+ if self._buffer:
11425+ buf = self._buffer
11426+ chunk_start = self._buffer_pos
11427+ chunk_data = buf[self._buffer_pos :]
11428+ self._buffer = EMPTY
11429+ else:
11430+ buf = self.readchunk()
11431+ chunk_start = 0
11432+ chunk_data = buf
11433+ needed = buf.find(EMPTY, chunk_start, chunk_start + needed)
11434+ if len(chunk_data) > needed:
11435+ self._buffer = buf
11436+ self._buffer_pos = chunk_start + needed
11437+ self._position -= len(self._buffer) - self._buffer_pos
11438+ return b""
11439+ "# ,
11440+ )
11441+ . unwrap ( ) ;
11442+
11443+ db. clear_salsa_events ( ) ;
11444+ assert_file_diagnostics ( & db, filename, & [ ] ) ;
11445+ let events = db. take_salsa_events ( ) ;
11446+ let cycles = salsa:: attach ( & db, || {
11447+ events
11448+ . iter ( )
11449+ . filter_map ( |event| {
11450+ if let salsa:: EventKind :: WillIterateCycle {
11451+ database_key,
11452+ iteration_count,
11453+ fell_back : _,
11454+ } = event. kind
11455+ {
11456+ Some ( format ! ( "{database_key:?}, {iteration_count:?}" ) )
11457+ } else {
11458+ None
11459+ }
11460+ } )
11461+ . collect :: < Vec < _ > > ( )
11462+ } ) ;
11463+ assert_eq ! ( cycles. len( ) , 2414 ) ;
11464+ }
11465+
1139311466 #[ test]
1139411467 fn not_literal_string ( ) -> anyhow:: Result < ( ) > {
1139511468 let mut db = setup_db ( ) ;
0 commit comments