Skip to content
This repository was archived by the owner on Sep 16, 2022. It is now read-only.

Analyzer summaries missing generic types for DartObject #908

Open
matanlurey opened this issue Feb 17, 2018 · 19 comments
Open

Analyzer summaries missing generic types for DartObject #908

matanlurey opened this issue Feb 17, 2018 · 19 comments

Comments

@matanlurey
Copy link
Contributor

We have a class called MultiToken and another called ExistingProvider:

https://github.com/dart-lang/angular/blob/1abcb5c62fc8a8267f1abdb2081d07f40567c56f/angular/lib/src/core/di/opaque_token.dart#L62-L74

https://github.com/dart-lang/angular/blob/1abcb5c62fc8a8267f1abdb2081d07f40567c56f/angular/lib/src/di/providers.dart#L241-L265

This pattern was created in order to correctly "infer" what the type of a given DI provider should be, but also not require manual type annotations (use flowing type inference from OpaqueToken<T> -> ExistingProvider<T> -> Provider<T> (T):

const NG_VALUE_ACCESSOR = const MultiToken<ControlValueAccessor>(
  'NgValueAccessor',
);

const DEFAULT_VALUE_ACCESSOR = const ExistingProvider.forToken(
  NG_VALUE_ACCESSOR,
  DefaultValueAccessor,
);

When analyzing this during our compilation, T of DEFAULT_VALUE_ACCESSOR is dynamic internally (with bazel_codegen) and (correctly) ControlValueAccessor externally (with build_runner). This is causing our sync to fail on travis:

https://api.travis-ci.org/v3/job/342583283/log.txt

If I manually type (don't rely on inference), it works as intended in both places:

const DEFAULT_VALUE_ACCESSOR = const ExistingProvider<ControlValueAccessor>.forToken(
  NG_VALUE_ACCESSOR,
  DefaultValueAccessor,
);

It's also possible this is due to different analyzer versions/configuration? I know top-level inference is inconsistent without using Dart 2 semantics, but I'm very confused why this works properly externally but not internally.

/cc @natebosch @scheglov @alorenzen

@natebosch
Copy link
Contributor

Both places are using an AnalysisContext. Both places set strongMode to true and no other analysis options. (bazel, build_runner)

In bazel we use summaries for files outside the current package, in build_runner we always read Dart sources, never summaries.

@matanlurey
Copy link
Contributor Author

Interestingly enough, this worked internally a while back :-/

@natebosch
Copy link
Contributor

Could be a regression in the AnalysisContext in that case - I think we're likely getting older versions of the analyzer package externally than what is rolled internally. If you can build a test case you might want to see if you can try against older versions of analyzer internally.

@matanlurey
Copy link
Contributor Author

For folks reading this thread:

INTERNALLY = 0.31.2-alpha.0
EXTERNALLY = ^0.31.0+1

@MichaelRFairhurst
Copy link
Contributor

My understanding was that top levels don't have inference, they get implicit dynamic. It seems like for const values we do some kind of inference, though...

We did just change const values around a bit in order to support asserts in initializers?

@matanlurey
Copy link
Contributor Author

@MichaelRFairhurst:

My understanding was that top levels don't have inference, they get implicit dynamic. It seems like for const values we do some kind of inference, though...

Yeah, it works as of 0.31.0+1 for this limited case. If I'm relying on something "bad", let me know, but my assumption is that it should continue to work indefinitely.

If you need a better reproduction case, I'm happy to write one.

@MichaelRFairhurst
Copy link
Contributor

Its my understanding that this does not have any inference...const ExistingProvider.forToken(...) but rather gets implicit dynamic...I think that's the problem

@matanlurey
Copy link
Contributor Author

matanlurey commented Feb 20, 2018

@MichaelRFairhurst:

Its a little hard to see here, but the failing travis sees it:

https://api.travis-ci.org/v3/job/342583283/log.txt

     Which: is different.
            Expected: ... ;\n  List<dynamic> _ ...
              Actual: ... ;\n  List<import15.C ...
                                    ^
             Differ at offset 8427
  ./build/test/_files/directives/directive_wrapper.template_debug.golden is out of date. See ./build/test/_files/directives/directive_wrapper.template_debug.check.

i.e. externally, we read this provider as T=ControlValueAccessor, but internally it is read as T=dynamic. We obviously want the former.

EDIT: I will add that one of these uses summaries of dependencies (internally, with Bazel) and one of these does not (externally, with Build Runner). That may or may not matter?

@matanlurey
Copy link
Contributor Author

In order to avoid this blocking the sync, I'll add a work-around for now @alorenzen.

@matanlurey matanlurey self-assigned this Feb 21, 2018
alorenzen pushed a commit that referenced this issue Feb 21, 2018
Added a general-case regression test to track addressing #908 correctly.

PiperOrigin-RevId: 186484795
alorenzen pushed a commit that referenced this issue Feb 21, 2018
Added a general-case regression test to track addressing #908 correctly.

PiperOrigin-RevId: 186484795
matanlurey added a commit that referenced this issue Feb 21, 2018
Added a general-case regression test to track addressing #908 correctly.

PiperOrigin-RevId: 186484795
@matanlurey
Copy link
Contributor Author

Ping @MichaelRFairhurst @scheglov could I get some help?

I added a regression test here:
https://github.com/dart-lang/angular/blob/master/_tests/test/regression/908_analyzer_inference_test.dart

The skipped case passes externally, but fails internally.

@leafpetersen
Copy link
Contributor

This should almost certainly be inferred. We do toplevel inference, and this looks like a straightforward example of something we should catch, unless I'm missing something. There are a lot of known bugs and unimplemented bits in the analyzer (since it was intended to only be implemented in the new front end), but we certainly shouldn't be regressing here.

Unfortunately this is sometimes very sensitive to multiple files and analysis order, but if there's any way you can get a small repro that would be great. Also, file an issue in the sdk if you haven't already.

@matanlurey
Copy link
Contributor Author

@leafpetersen I tried implementing the simplest repro possible:

import 'provider.dart';
import 'token.dart';

const tokenOfString = const Token<String>();
const implicitProviderOfString = const Provider(tokenOfString);
const explicitProviderOfString = const Provider<String>(tokenOfString);
@TestOn('vm')
import 'package:analyzer/dart/constant/value.dart';
import 'package:build/build.dart';
import 'package:build_test/build_test.dart';
import 'package:test/test.dart';

void main() {
  final asset = new AssetId('top_level_analyzer', 'lib/library.dart');

  DartObject explicitProviderOfString;
  DartObject implicitProviderOfString;

  setUpAll(() async {
    final library = await resolveAsset(asset, (r) => r.libraryFor(asset));
    final fields = library.definingCompilationUnit.topLevelVariables;;
    explicitProviderOfString = fields[1].computeConstantValue();
    implicitProviderOfString = fields[2].computeConstantValue();
  });

  test('should resolve explicitProviderOfString', () async {
    expect(explicitProviderOfString.type.toString(), 'Provider<String>');
  });

  test('should resolve implicitProviderOfString', () async {
    expect(implicitProviderOfString.type.toString(), 'Provider<String>');
  });
}

... and this works externally, just fine, with both:

  • analyzer: 0.31.1
  • analyzer: 0.31.2-alpha.0

... so now I'm thinking its related to summaries (Bazel uses). I'll try and write the same test internally and see if I get different results tomorrow, I hope I can figure something out.

@matanlurey
Copy link
Contributor Author

@stereotype441 took a look at this.

I'm going to port the above test internally, where it fails, and then share with the team to see if we can make some progress. Update a little later today.

@matanlurey
Copy link
Contributor Author

From what I can tell... this works fine internally, too.

It's likely something very subtle and not directly related to the analyzer, or build, but I really appreciate everyone looking at this and trying to help diagnose the problem(s). I'll ping again if I have a fix or further questions.

@matanlurey
Copy link
Contributor Author

I'm closing this, as we are just landing a workaround instead.

@matanlurey
Copy link
Contributor Author

This test fails internally when DDC enforces type checks for List:

https://github.com/dart-lang/angular/blob/master/_tests/test/core/linker/deferred_component_ngmodel_test.dart

... it shouldn't.

@stereotype441
Copy link
Contributor

I believe the underlying cause is dart-lang/sdk#32290.

@matanlurey
Copy link
Contributor Author

Wow! Thanks @stereotype441!

I think I can add a workaround, again, until we have a fix.

@matanlurey matanlurey changed the title Discrepancies with Analyzer during compilation Analyzer summaries missing generic types for DartObject Feb 23, 2018
alorenzen pushed a commit that referenced this issue Feb 23, 2018
After further investigation, there is some regression in resolving types from
the angular_forms library from within the _goldens library, but only internally
for the golden file generator ... woo, a mouth-full.

It makes sense to just trim this specific case out, since we have coverage of
the type inference feature in other test cases, and not worry about trying to
resolve another package from within the golden files.

[After speaking to multiple members of the analyzer team, it seems like both order, types (summaries versus source files), and other very subtle things could cause this, and since we are on the deprecated AnalysisContext for builders anyway, it doesn't make sense to focus on this specific case.]

... also refactor that golden file, while we are at it!

PiperOrigin-RevId: 186656275
alorenzen pushed a commit that referenced this issue Feb 23, 2018
…ease(s).

Filed/updated a number of cleanup/refactor bugs while doing this:
* #908
* #916
* #915
* #844
* #914
* dart-lang/sdk#32284

Closes #913.

PiperOrigin-RevId: 186683475
alorenzen pushed a commit that referenced this issue Feb 23, 2018
…tokens.

After this CL, we will infer, in the view compiler:
  `Provider<dynamic>(OpaqueToken<T>)`
as
  `Provider<T>(OpaqueToken<T>)`

This isn't strictly right, but its better than emitting incorrect types
(dynamic), which can block Dart2. Once #908 is fixed, we can revert this
change.

PiperOrigin-RevId: 186788142
alorenzen pushed a commit that referenced this issue Feb 24, 2018
After further investigation, there is some regression in resolving types from
the angular_forms library from within the _goldens library, but only internally
for the golden file generator ... woo, a mouth-full.

It makes sense to just trim this specific case out, since we have coverage of
the type inference feature in other test cases, and not worry about trying to
resolve another package from within the golden files.

[After speaking to multiple members of the analyzer team, it seems like both order, types (summaries versus source files), and other very subtle things could cause this, and since we are on the deprecated AnalysisContext for builders anyway, it doesn't make sense to focus on this specific case.]

... also refactor that golden file, while we are at it!

PiperOrigin-RevId: 186656275
alorenzen pushed a commit that referenced this issue Feb 24, 2018
…ease(s).

Filed/updated a number of cleanup/refactor bugs while doing this:
* #908
* #916
* #915
* #844
* #914
* dart-lang/sdk#32284

Closes #913.

PiperOrigin-RevId: 186683475
alorenzen pushed a commit that referenced this issue Feb 24, 2018
…tokens.

After this CL, we will infer, in the view compiler:
  `Provider<dynamic>(OpaqueToken<T>)`
as
  `Provider<T>(OpaqueToken<T>)`

This isn't strictly right, but its better than emitting incorrect types
(dynamic), which can block Dart2. Once #908 is fixed, we can revert this
change.

PiperOrigin-RevId: 186788142
alorenzen pushed a commit that referenced this issue Feb 24, 2018
After further investigation, there is some regression in resolving types from
the angular_forms library from within the _goldens library, but only internally
for the golden file generator ... woo, a mouth-full.

It makes sense to just trim this specific case out, since we have coverage of
the type inference feature in other test cases, and not worry about trying to
resolve another package from within the golden files.

[After speaking to multiple members of the analyzer team, it seems like both order, types (summaries versus source files), and other very subtle things could cause this, and since we are on the deprecated AnalysisContext for builders anyway, it doesn't make sense to focus on this specific case.]

... also refactor that golden file, while we are at it!

PiperOrigin-RevId: 186656275
alorenzen pushed a commit that referenced this issue Feb 24, 2018
…ease(s).

Filed/updated a number of cleanup/refactor bugs while doing this:
* #908
* #916
* #915
* #844
* #914
* dart-lang/sdk#32284

Closes #913.

PiperOrigin-RevId: 186683475
alorenzen pushed a commit that referenced this issue Feb 24, 2018
…tokens.

After this CL, we will infer, in the view compiler:
  `Provider<dynamic>(OpaqueToken<T>)`
as
  `Provider<T>(OpaqueToken<T>)`

This isn't strictly right, but its better than emitting incorrect types
(dynamic), which can block Dart2. Once #908 is fixed, we can revert this
change.

PiperOrigin-RevId: 186788142
alorenzen pushed a commit that referenced this issue Feb 24, 2018
After further investigation, there is some regression in resolving types from
the angular_forms library from within the _goldens library, but only internally
for the golden file generator ... woo, a mouth-full.

It makes sense to just trim this specific case out, since we have coverage of
the type inference feature in other test cases, and not worry about trying to
resolve another package from within the golden files.

[After speaking to multiple members of the analyzer team, it seems like both order, types (summaries versus source files), and other very subtle things could cause this, and since we are on the deprecated AnalysisContext for builders anyway, it doesn't make sense to focus on this specific case.]

... also refactor that golden file, while we are at it!

PiperOrigin-RevId: 186656275
alorenzen pushed a commit that referenced this issue Feb 24, 2018
…ease(s).

Filed/updated a number of cleanup/refactor bugs while doing this:
* #908
* #916
* #915
* #844
* #914
* dart-lang/sdk#32284

Closes #913.

PiperOrigin-RevId: 186683475
alorenzen pushed a commit that referenced this issue Feb 24, 2018
…tokens.

After this CL, we will infer, in the view compiler:
  `Provider<dynamic>(OpaqueToken<T>)`
as
  `Provider<T>(OpaqueToken<T>)`

This isn't strictly right, but its better than emitting incorrect types
(dynamic), which can block Dart2. Once #908 is fixed, we can revert this
change.

PiperOrigin-RevId: 186788142
matanlurey added a commit that referenced this issue Feb 25, 2018
After further investigation, there is some regression in resolving types from
the angular_forms library from within the _goldens library, but only internally
for the golden file generator ... woo, a mouth-full.

It makes sense to just trim this specific case out, since we have coverage of
the type inference feature in other test cases, and not worry about trying to
resolve another package from within the golden files.

[After speaking to multiple members of the analyzer team, it seems like both order, types (summaries versus source files), and other very subtle things could cause this, and since we are on the deprecated AnalysisContext for builders anyway, it doesn't make sense to focus on this specific case.]

... also refactor that golden file, while we are at it!

PiperOrigin-RevId: 186656275
matanlurey added a commit that referenced this issue Feb 25, 2018
…ease(s).

Filed/updated a number of cleanup/refactor bugs while doing this:
* #908
* #916
* #915
* #844
* #914
* dart-lang/sdk#32284

Closes #913.

PiperOrigin-RevId: 186683475
matanlurey added a commit that referenced this issue Feb 25, 2018
…tokens.

After this CL, we will infer, in the view compiler:
  `Provider<dynamic>(OpaqueToken<T>)`
as
  `Provider<T>(OpaqueToken<T>)`

This isn't strictly right, but its better than emitting incorrect types
(dynamic), which can block Dart2. Once #908 is fixed, we can revert this
change.

PiperOrigin-RevId: 186788142
@matanlurey matanlurey removed their assignment Feb 28, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants