04d4be0982
Within some AST context (at library granularity, for convenience), we collect all the assignments to local vars: - Declaration with no initializer amounts to `null` assignment - Assignment ops are expanded naively: `x++` yield an assigned value of `x + 1`, etc We detect "trivially nullable" variables (e.g. `var x;`, `x = breaking.out;`) by spotting assigned values that are nullable under the optimistic assumption that all known variables are non-nullable. Then we build a nullability dependency graph in linear time: whenever we see `x = y;`, we know that "y is nullable" implies "x is nullable". Finally, we propagate "trivial nullabilities" through that graph: any variable that wasn't reached is deemed not-nullable. (this is similar to mark and sweep garbage collection, where the roots are the "trivially nullable" variables; credits to leafpetersen@ for linear solution)