@@ -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