This repository has been archived by the owner on Feb 12, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 424
Re-land typed descriptors and printer #2511
Closed
sebmarkbage
wants to merge
8
commits into
facebookarchive:master
from
sebmarkbage:fixtypeddescriptor
Closed
Changes from 3 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
1b06bce
Reland typed descriptors and printer
sebmarkbage 922d40c
Fix TextPrinter by exposing assumed path conditions
sebmarkbage 2b4546d
Use undefined instead of missing to represent absent field in descrip…
sebmarkbage f046958
Fix conflict with master
trueadm 2e140d9
Fix more conflicts
trueadm 3a4d866
fix conflict
trueadm b5c8a1d
Fixed error with identical checks now that properties exist, for in w…
trueadm 5d8caf2
Fixed flow issues
trueadm 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 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 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 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
/** | ||
* Copyright (c) 2017-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. An additional grant | ||
* of patent rights can be found in the PATENTS file in the same directory. | ||
*/ | ||
|
||
/* @flow */ | ||
|
||
import invariant from "./invariant.js"; | ||
import type { AbstractValue, UndefinedValue, Value } from "./values/index.js"; | ||
import { CompilerDiagnostic, FatalError } from "./errors.js"; | ||
import type { CallableObjectValue } from "./types.js"; | ||
import type { Realm } from "./realm.js"; | ||
|
||
export class Descriptor { | ||
constructor() { | ||
invariant(this.constructor !== Descriptor, "Descriptor is an abstract base class"); | ||
} | ||
throwIfNotConcrete(realm: Realm): PropertyDescriptor { | ||
let error = new CompilerDiagnostic( | ||
"only known descriptors supported", | ||
realm.currentLocation, | ||
"PP0042", | ||
"FatalError" | ||
); | ||
realm.handleError(error); | ||
throw new FatalError(); | ||
} | ||
mightHaveBeenDeleted(): boolean { | ||
invariant(false, "should have been overridden by subclass"); | ||
} | ||
} | ||
|
||
export type DescriptorInitializer = {| | ||
writable?: boolean, | ||
enumerable?: boolean, | ||
configurable?: boolean, | ||
|
||
value?: Value, | ||
|
||
get?: UndefinedValue | CallableObjectValue | AbstractValue, | ||
set?: UndefinedValue | CallableObjectValue | AbstractValue, | ||
|}; | ||
|
||
// Normal descriptors are returned just like spec descriptors | ||
export class PropertyDescriptor extends Descriptor { | ||
writable: void | boolean; | ||
enumerable: void | boolean; | ||
configurable: void | boolean; | ||
|
||
// If value instanceof EmptyValue, then this descriptor indicates that the | ||
// corresponding property has been deleted. | ||
value: void | Value; | ||
|
||
get: void | UndefinedValue | CallableObjectValue | AbstractValue; | ||
set: void | UndefinedValue | CallableObjectValue | AbstractValue; | ||
|
||
constructor(desc: DescriptorInitializer | PropertyDescriptor) { | ||
super(); | ||
this.writable = desc.writable; | ||
this.enumerable = desc.enumerable; | ||
this.configurable = desc.configurable; | ||
this.value = desc.value; | ||
this.get = desc.get; | ||
this.set = desc.set; | ||
} | ||
|
||
throwIfNotConcrete(realm: Realm): PropertyDescriptor { | ||
return this; | ||
} | ||
mightHaveBeenDeleted(): boolean { | ||
if (this.value === undefined) return false; | ||
return this.value.mightHaveBeenDeleted(); | ||
} | ||
} | ||
|
||
// Only internal properties (those starting with $ / where internalSlot of owning property binding is true) will ever have array values. | ||
export class InternalSlotDescriptor extends Descriptor { | ||
value: void | Value | Array<any>; | ||
|
||
constructor(value?: void | Value | Array<any>) { | ||
super(); | ||
this.value = Array.isArray(value) ? value.slice(0) : value; | ||
} | ||
|
||
mightHaveBeenDeleted(): boolean { | ||
return false; | ||
} | ||
} | ||
|
||
// Only used if the result of a join of two descriptors is not a data descriptor with identical attribute values. | ||
// When present, any update to the property must produce effects that are the join of updating both descriptors, | ||
// using joinCondition as the condition of the join. | ||
export class AbstractJoinedDescriptor extends Descriptor { | ||
joinCondition: AbstractValue; | ||
// An undefined descriptor means it might be empty in this branch. | ||
descriptor1: void | Descriptor; | ||
descriptor2: void | Descriptor; | ||
|
||
constructor(joinCondition: AbstractValue, descriptor1?: Descriptor, descriptor2?: Descriptor) { | ||
super(); | ||
this.joinCondition = joinCondition; | ||
this.descriptor1 = descriptor1; | ||
this.descriptor2 = descriptor2; | ||
} | ||
mightHaveBeenDeleted(): boolean { | ||
if (!this.descriptor1 || this.descriptor1.mightHaveBeenDeleted()) { | ||
return true; | ||
} | ||
if (!this.descriptor2 || this.descriptor2.mightHaveBeenDeleted()) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
} | ||
|
||
export function cloneDescriptor(d: void | PropertyDescriptor): void | PropertyDescriptor { | ||
if (d === undefined) return undefined; | ||
return new PropertyDescriptor(d); | ||
} | ||
|
||
// does not check if the contents of value properties are the same | ||
export function equalDescriptors(d1: PropertyDescriptor, d2: PropertyDescriptor): boolean { | ||
if (d1.writable !== d2.writable) return false; | ||
if (d1.enumerable !== d2.enumerable) return false; | ||
if (d1.configurable !== d2.configurable) return false; | ||
if (d1.value !== undefined) { | ||
if (d2.value === undefined) return false; | ||
} | ||
if (d1.get !== d2.get) return false; | ||
if (d1.set !== d2.set) return false; | ||
return true; | ||
} |
This file contains 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 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 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.
There is some asymmetry here, causing equalDescriptors not to be commutative when one
value
isundefined
and the other one isn't. That issue already existed in the original code. I doubt that it's intentional? Maybe it gets rescued by the other invariant that the existance ofvalue
andget
/set
are mutually exclusive. (We could use more such invariants in places.)Anyway, for clarity, I'd suggest rewriting this case to
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.
There are three types of descriptors at the spec level. Generic, Data and Accessors. Lack of value and get/set means it's generic. So if one has a value but the other doesn't, it means that they're not even in the same category of descriptors.
Undefined value doesn't mean
empty
btw. That's an empty value.This helper function, for reasons that preceded me, doesn't compare whether the values themselves are equivalent.
Basically, this function is only meant to determine if this needs to use joined Descriptor or if it's enough to use a joined Value.
In theory, accessors doesn't need to use a joined Descriptor neither. We can just use a joined value of the getter and a joined value of the setter.