Skip to content

Unexpected analyze argument_type_not_assignable error #48395

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
cyliale opened this issue Feb 14, 2022 · 7 comments
Closed

Unexpected analyze argument_type_not_assignable error #48395

cyliale opened this issue Feb 14, 2022 · 7 comments
Labels
legacy-area-analyzer Use area-devexp instead.

Comments

@cyliale
Copy link

cyliale commented Feb 14, 2022

Hello i have the some analyze errors on use of fnString() and fnInt() when i use this sample test code. Comments in code.

Type seems not promoted in lambda function arguments.

Source code is

bool fnString(final String s) => s == 'text';
bool fnInt(final int i) => i == 1;
void main() {
  test('DART bug : analyze error in expect lambda function', () {
    Object? o = 'text';
    if (o is! String) {
      fail('o should be a String');
    }
    // Ok: unrelated_type_equality_checks lint error for "o == 1" as expected
    expect(o == 1, false);
    // Ok: o is seen as a String
    expect(o == 'text', true);
    // Ok: o is seen as a String
    expect(() => o == 'text', true);
    // Bug: argument_type_not_assignable analyze error
    // o is seen as an Object? instead of a String !!!
    expect(() => fnString(o), true);

    o = 1;
    if (o is! int) {
      fail('o should be an int');
    }
    // Ok: unrelated_type_equality_checks lint error for "o == 'text'" as expected
    expect(o == 'text', false);
    // Ok: o is seen as a int
    expect(o == 1, true);
    // Ok: o is seen as a int
    expect(() => o == 1, true);
    // Bug: argument_type_not_assignable analyze error
    // o is seen as an Object? instead of an int !!!
    expect(() => fnInt(o), true);
  });
}

Dart SDK version: 2.16.1 (stable) (Unknown timestamp) on "linux_x64"

@cyliale
Copy link
Author

cyliale commented Feb 14, 2022

If i write "final s = o;" just before then "expect(() => fnString(s), true);" has no analyze error.
If i write "final i = o;" just before then "expect(() => fnInt(i), true);" has no analyze error.

But it would be nice to not be obliged to write these additional lines.

@cyliale
Copy link
Author

cyliale commented Feb 14, 2022

If you need my yaml config.

environment:
  sdk: '>=2.15.0 <3.0.0'

dependencies:
  collection: ^1.15.0
  pub_semver: ^2.0.0
  yaml: ^3.1.0

dev_dependencies:
  lint: ^1.8.1
  matcher: '>=0.12.3 <0.14.0'
  test: ^1.16.0

and my analysis options.

include: all_lint_rules.yaml
analyzer:
  exclude:
  #- '**.freezed.dart'

  strong-mode:
    implicit-casts: false
    implicit-dynamic: false

  errors:
    included_file_warning: ignore
    missing_required_param: error
    missing_return: error
    parameter_assignments: warning
    todo: ignore

linter:
  rules:
    always_specify_types: false
    always_use_package_imports: false
    avoid_annotating_with_dynamic: false
    avoid_final_parameters: false
    prefer_double_quotes: false
    require_trailing_commas: false
    sort_constructors_first: false
    unnecessary_final: false

@cyliale
Copy link
Author

cyliale commented Feb 14, 2022

Beware, if you separate tests into two separate tests and make the variable "o" "final", the analyze bug disappears.

@bwilkerson
Copy link
Member

@stereotype441

@stereotype441
Copy link
Member

The first issue (o is seen as an Object? instead of a String in expect(() => fnString(o), true);) is expected behavior. Flow analysis only operates on local information; it doesn't make any assumptions about the behaviors of functions other than the one being analyzed. In particular, it doesn't make any assumptions about when the expect function executes the closure that's passed to it. As far as it knows, expect might save the closure somewhere, and it might get executed at a later time, after o = 1 has been executed. So it can't safely promote the type of o to String inside the closure () => fnString(o).

The second issue (o is seen as an Object? instead of an int in expect(() => fnInt(o), true);) is more unfortunate, and it's something I'm looking into fixing. In this case, flow analysis isn't smart enough to see that at the time of expect(() => fnInt(o), true);, all of the assignments to o are already in the past, and therefore, in effect, o is final now (and therefore safe to promote). This issue is tracked in dart-lang/language#1536.

@lrhn lrhn added the legacy-area-analyzer Use area-devexp instead. label Feb 14, 2022
@cyliale
Copy link
Author

cyliale commented Feb 15, 2022

Thanks a lot for your explanations and your work.

@srawlins
Copy link
Member

I'll close this in favor of dart-lang/language#1536.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
legacy-area-analyzer Use area-devexp instead.
Projects
None yet
Development

No branches or pull requests

5 participants