Skip to content

Flow analysis fails to record types of interest when an is expression is not used in a conditional context #60479

Open
@stereotype441

Description

@stereotype441

Consider the following code (from dart-lang/co19#3126 (comment)):

class S {}

class T extends S {
  void foo() {}
}

void main() {
  var s = S();
  s is T;
  s = T();
  s.foo(); // Error, so `T` was not a type of interest, but it should be.
}

According to the flow analysis spec:

  • true(s is T) should add the type T to the tested list in the VariableModel for s.
  • Since there is no specific rule defining after(N) for is expressions, the general rule after(N) = join(true(N), false(N)) should be used (see the Expressions subsection).
  • join is based on joinV, and the definition of joinV (see the Models subsection) says that joinV takes the union of the tested lists from the two branches.
  • So after(s is T) should include T as one of the tested types for s. (In other words, T should be a type of interest for s after this is check).

What's happening instead is that instead of using the general rule after(N) = join(true(N), false(N)) for is expressions, flow analysis is failing to update its description of the _current flow state, so in effect what the implementation is doing is this (I've highlighted the difference from the spec in bold):

  • instance check: If N is an expression of the form E1 is S where the static type of E1 is T then:
    • Let before(E1) = before(N)
    • If T is a bottom type, then:
      • Let true(N) = unreachable(after(E1)).
      • Let false(N) = after(E1).
    • Otherwise:
      • Let true(N) = promote(E1, S, after(E1))
      • Let false(N) = promote(E1, factor(T, S), after(E1))
      • Let after(N) = after(E1)

In practice this is pretty benign because most of the time people perform is tests, they do so in a conditional context, so the flow models that get propagated forward come from true(N) and false(N) (which are behaving correctly). The incorrect behavior only happens if the is test isn't used in a condition, so the flow model that gets propagated forward come from the buggy after(N).

Since the bug only manifests if an is test is used in an unusual way, and only causes problems with types of interest, I'm classifying this as a P3. I will still try to get to fixing it though.

Metadata

Metadata

Assignees

Labels

P3A lower priority bug or feature requestarea-dart-modelFor issues related to conformance to the language spec in the parser, compilers or the CLI analyzer.model-flowImplementation of flow analysis in analyzer/cfetype-bugIncorrect behavior (everything from a crash to more subtle misbehavior)

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions