Skip to content

fix(compiler-cli): don't unnecessarily throw on StaticSymbols - #12158

Merged
tbosch merged 1 commit into
angular:masterfrom
steve8708:static-symbol-bug
Oct 11, 2016
Merged

tbosch merged 1 commit into
angular:masterfrom
steve8708:static-symbol-bug

Conversation

@steve8708

@steve8708 steve8708 commented Oct 7, 2016 •

Copy link
Copy Markdown
Contributor

Please check if the PR fulfills these requirements

What kind of change does this PR introduce? (check one with "x")

[x] Bugfix
[ ] Feature
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] CI related changes
[ ] Other... Please describe:

What is the current behavior? (You can also link to an open issue here)
#11276 #12097

ngc throws an error when StaticSymbol interface compatible objects are passed to StaticReflector.parameters or StaticReflector.hasLifecycleHook

What is the new behavior?

If the object properly matches the StaticSymbol interface, do not throw an error and allow the object to be processed

Does this PR introduce a breaking change? (check one with "x")

[ ] Yes
[x] No

If this PR contains a breaking change, please describe the impact and migration path for existing applications: ...

Other information:

Closes #11276 #12097

@steve8708

Copy link
Copy Markdown
Contributor Author

(fyi this is a blocker for AOT support in angular/universal)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chuckjaz chuckjaz Oct 11, 2016 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is wrong. The reason that this code checks using instanceof is because the static reflector assumes that all the static symbols it receives in its API were produced by the static reflector. This is because it uses object identity to cache information and determine type identity. The bug is not that we are checking for instanceof instead of using isStaticSymbol, rather, it is that someone is passing static symbol that wasn't produced by the static reflector. In this case the test is doing what it was intended to do, report this case.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it, thanks for the explanation @chuckjaz

I'll dig deeper and find the source of static symbols not created by the static reflector and update this PR accordingly

@steve8708 steve8708 Oct 11, 2016 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So from digging around deeper I see what is going on.

The objects were originally static symbols created by the StaticSymbol constructor, but then were cloned in the mapStringMap function (which is called by simplify in the parameters method of the static reflector) which is where the instanceof check breaks, as well as proper ability to cache by reference.

Looking deeper into why this happens to only some providers in some situations and to why the simplify functions that are being used exist in the first place and if the cloning can be circumvented or if it is a deeper issue that StaticSymbols are passed to the simplify function in the first place

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for looking into this! StaticSymbol should be a special case in the evaluator. Try adding the lines:

        if (expression instanceof StaticSymbol) {
          return expression;
        }

just after the test for Array in simplify(). This will prevent the static reflector from trying to clone a StaticSymbol, treating it like a primitive instead of a hash map.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you find how a StaticSymbol got in a value passed to simplify() I would be curious. That shouldn't happen but if it does we shouldn't damage it.

@steve8708 steve8708 Oct 11, 2016 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chuckjaz agreed, and thanks!

My solution was identical to yours but I added the check below the check for primitives, if it's important that it be below the check for Array just let me know and I'll happily move it

So far I am stumped as well how only in rare cases static symbols are passed to simplify (it's within some deep recursion in some edge case situations it seems) but I'll definitely let you know if I figure it out!

Also, just added a test for this new check as well 👍

@chuckjaz chuckjaz Oct 11, 2016 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are cross talking! No need for it being after Array really. It is slightly faster there (in that StaticSymbols are less common than Arrays) but not really noticeably so. Only move it if you feel so inclined.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chuckjaz makes perfect sense, I went a head and pushed one small update with that extra optimization 👍

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you then also export the StaticSymbol here as well and drop the declaration in static_reflector? You will probably need to add members to the one in @angular/compiler...

@tbosch tbosch added pr_state: LGTM action: cleanup The PR is in need of cleanup, either due to needing a rebase or in response to comments from reviews labels Oct 10, 2016
@steve8708
steve8708 force-pushed the static-symbol-bug branch 2 times, most recently from 6d545f3 to 14ab2f7 Compare October 11, 2016 20:37

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found the issue.

When recursively processing/simplifying annotation metadata StaticSymbols need to be kept in tact rather than treated as plain string maps and cloned

This was happening to us in universal for any private import we made from platform-browser using the format we see from the this repo must be used to properly import private exports (i.e. using the explicit typeof x type annotations) which we do in universal here.

I'm guessing this is just a byproduct of the parsing being a bit different when using that special import/export format required for private exports.

I've updated this PR accordingly to check for StaticSymbol before further processing in the simplifyInContext method which I've verified with this fix universal now builds and runs as expected with AOT

Happy to make any further updates or refactors desired as well, just let me know, and thanks for taking a look at this @tbosch and @chuckjaz!

@chuckjaz chuckjaz Oct 11, 2016 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a test to static_reflector_spec.ts that verifies that simplify() will not clone a StaticSymbol? Something like:

  it('should not clone a static symbol', () => {
    const symbol = new StaticSymbol('/tmp/src/some_file.ts', 'SomeSymbol');
    expect(simplify(symbol, symbol)).toBe(symbol);
  });

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chuckjaz just did in a separate commit 👍

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you want me to squash it with the first, just let me know

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Up to you. Tobias will probably squash and merge anyway.

@chuckjaz chuckjaz added pr_state: LGTM and removed action: cleanup The PR is in need of cleanup, either due to needing a rebase or in response to comments from reviews labels Oct 11, 2016

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this to be a separate commit. Just squash them.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chuckjaz squashed 👍

@chuckjaz chuckjaz added action: merge The PR is ready for merge by the caretaker area: core Issues related to the framework runtime labels Oct 11, 2016
@tbosch
tbosch merged commit 8c477b2 into angular:master Oct 11, 2016
@alexeagle

Copy link
Copy Markdown
Contributor

Awesome, thanks for digging so deep, @steve8708 !

@steve8708

Copy link
Copy Markdown
Contributor Author

no problem, thank you for the tips @alexeagle!

@snstarosciak

Copy link
Copy Markdown

Hey everyone, I'm a bit confused here :/ I stumbled upon this thread from this one as I was looking for a solution to fix my Ionic 2 compiler when I run ionic build ios. I don't see the file modules/@angular/compiler-cli/src/static_reflector.ts The closest thing would be modules/@angular/compiler-cli/src/static_reflector.d.ts and it's only 80 lines long. Would anyone be able to shed some light on this for me? :)

@chuckjaz

Copy link
Copy Markdown
Contributor

I am not sure what your question is but the lines https://github.com/angular/angular/blob/master/modules/%40angular/compiler-cli/src/static_reflector.ts#L369-L371 were added to resolve this issue.

@snstarosciak

Copy link
Copy Markdown

@chuckjaz Thanks for quick response. Sorry for the confusion. I don't have that file in my respective node_modules directory. I was able to solve the problem by not using the DomSanitizer as a provider and just imported it directly into my component. Problem solved :)

@angular-automatic-lock-bot

Copy link
Copy Markdown

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot Bot locked and limited conversation to collaborators Sep 10, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

action: merge The PR is ready for merge by the caretaker area: core Issues related to the framework runtime cla: yes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Importing RouterTestingModule in spec files causes AOT/ngc compiler to fail

6 participants