-
Notifications
You must be signed in to change notification settings - Fork 381
Use Object.create() instead of our own polyfill #10184
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
Open
niloc132
wants to merge
3
commits into
gwtproject:main
Choose a base branch
from
niloc132:Object.create
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+38
−15
Open
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need
Object.create(superPrototype || null)to be compatible with the polyfill?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It turns out the compiler tests at least assumes that we're not going to Object.create(null) for cases like this, the failing test this PR still has is for calling hasOwnProperty on a "java" object
gwt/user/test/com/google/gwt/core/interop/JsMethodTest.java
Lines 36 to 49 in 7b221c1
superTypeIdOrPrototypeis either a typeid (which can vary in type depending on how the compiler is set up) or an object prototype... or it is null. This impl guards against the null at the start instead of waiting and after failing the && check, then failing the if check, then failing the map lookup, just bails with the earliest if - but as you pointed out, the old polyfill was passing{}instead of thenull, and while my updated did guard againstundefined(sinceObject.create(undefined)is an error), there are differences that break the above code.gwt/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
Lines 2083 to 2093 in 7b221c1
The three cases again:
generateCallToDefineClassmethod will emit thedefineClass(...)call with a reference to what you claimed, but then it will be null/undefined. Existing code likewise would have normalized that to{}.I've added another test locally to confirm that this still works (a class with a missing supertype - can't instantiate it, but you can at least reference it). The more I look at this setup code, the more I don't understand why it is as complex as it is... I wonder if there were internal Google users calling some of these "public" methods, so they couldn't be inlined?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed my mind, this code is too ossified, clean up will take more time than I can put to it now. There are confusing/inaccurate comments, extra code that can't be optimized out of JSNI, incomplete renames/removals.
I'm adding another test which validates some edge case (but working) behavior, and restoring the {} as discussed above, and I'd appreciate any review to tell me to revert more or even just drop the whole thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at 3616e45#diff-9c7cf490fdcb064930a5430886b061bd25a79106b9bbf390b7b0fa4144f01d16R85 I'm not sure whether that changes anything 🤔
Object.create({})andObject.create(null)both return{}My concern was that if the lookup fails, i.e.
@Runtime::prototypesByTypeId[superTypeIdOrPrototype]isundefined, the method will now fail and before it was returning{}. However, from your commentI understand that the difference is intentional.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought so too, but it breaks tests:
Its possible someone somewhere is using that feature in their app.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Object.create(null)creates an object with a null prototype (equivalent to__proto__: null), whereasObject.create({})creates an object with{}as its prototype (so almost equivalent to just using{}ornew Object(); as they'll all haveObject.prototypein their prototype chain)portableObjCreateusedF.prototype = obj || {}, so the new code should useObject.create(obj ?? {})for backwards compatibilityThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
??isn't an option in JSNI (though||could be used as it was before) - the use case where it would matter would be a non-native jsinterop type that declared a native jsinterop type to be its superclass, but that native type had an undefined prototype. Technically possible, but its going to fail at runtime when you use the type anyway.As above, this code is more complex than it needs to be - this method is only called in one place, and the caller already knows if it was a super typeid or a super prototype, but lets this method figure it out for itself anyway. This edge case is a bit like the unit test I added - I think it would be reasonable to fail sooner than
newif the type didn't exist (since after GWT types are loaded, changes in supertypes outside the app won't be respected). The case here is technically a regression, but its a regression of code that didn't work anyway.Or am I missing a case where this backwards compatibility would break a real case that isn't already broken? I do know there are a couple of broken types in elemental2 (TypedArray, ArrayBufferView, but you won't want to declare subtypes of those anyway), so I'll give this a spin with a real app that uses some of those and make sure nothing actually breaks. In those two examples though, it isn't a question if the type exists in JS (those two don't), but if they exist and have an undefined (not null, that's safe)
prototype.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At least in the limited real-world code I have that interacts with badly defined jsinterop types, I'm not running into errors.
That said, reviewer's choice - if any of you would like the defensive
||{}back, I'll restore it.