Fix lookupStr
not to lookup when str
is Bottom
#154
Merged
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.
This PR fix
lookupStr
not to lookup when base object'sstr
is Bottom. This leads to fix 3 existing type mismatch and affect some cases accessinglength
property invalidly.Resolve 3 Type mismatches
3 mismatches below are resolved after fix.
Side-effect: Imprecise return type analysis
This PR affects conditions using "length" properties. There are 23 common changes in both ES2022/ES2023, along with 1 unique change in each version(ES2022/ES2023), amounting to a total of 25 changes. These changes can be classified with 3 IR-patterns like below:
Undefined
)Let's see quick example with
INTRINSICS.Map.prototype.clear
below.In the first step, accessing a property from
ESValue
type with concrete String key(corresponds toMapData
in example) resultsAbsent
. This behavior is not influenced by the change in this PR. However, the subsequent step is indeed affected. Here, accessing "length" property fromUndefined
now resultsBot
, where as previously resulted inMathT
.Consequently, the result of numericCompare (
< %1 %2.length
) becomesBot
, leading to an incomplete analysis.Bot
), before:k = (new [])
When the base object type is
Bot
, similar to Case A where it'sUndefined
, accessing the "length" property also previously resulted inMathT
. I think this scenario can be resolved by correctly handling(new [])
.In this case, I don't know how abstract closure analysis works now exactly, but precise analysis for captured variable types can resolve problems in this case.
Here are the total counts for each criterion:
A: 16
B: 5
`INTRINSICS.TypedArray.prototype.filter` diff is only in ES2023.C: 4
`INTRINSICS.RegExp.prototype[@@replace]` diff is only in ES2022.Misc
total diff (`/logs/analyze/types` with ES2022)
Total 24, INTRINSICS.RegExp.prototype[@@replace] is only in ES2022total diff (`/logs/analyze/types` with ES2023)
Total 24, INTRINSICS.TypedArray.prototype.filter is only in ES2023 ``` def :CreateListIteratorRecord:clo0(): Unknown --> def :CreateListIteratorRecord:clo0(): Normal[Undefined] | Abrupt (before) +-> def :CreateListIteratorRecord:clo0(): Unknown (after fix) -------------------------------------------------------------------------------- def :CreateMapIterator:clo0(): Unknown --> def :CreateMapIterator:clo0(): Undefined +-> def :CreateMapIterator:clo0(): Unknown -------------------------------------------------------------------------------- def :CreateSetIterator:clo0(): Unknown --> def :CreateSetIterator:clo0(): Undefined +-> def :CreateSetIterator:clo0(): Unknown -------------------------------------------------------------------------------- def :INTRINSICS.FinalizationRegistry.prototype.unregister(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Unknown --> def :INTRINSICS.FinalizationRegistry.prototype.unregister(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Normal[False] | Abrupt[throw] +-> def :INTRINSICS.FinalizationRegistry.prototype.unregister(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Abrupt[throw] -------------------------------------------------------------------------------- def :INTRINSICS.Map.prototype.clear(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Unknown --> def :INTRINSICS.Map.prototype.clear(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Normal[Undefined] | Abrupt[throw] +-> def :INTRINSICS.Map.prototype.clear(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Abrupt[throw] -------------------------------------------------------------------------------- def :INTRINSICS.Map.prototype.delete(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Unknown --> def :INTRINSICS.Map.prototype.delete(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Normal[False] | Abrupt[throw] +-> def :INTRINSICS.Map.prototype.delete(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Abrupt[throw] -------------------------------------------------------------------------------- def :INTRINSICS.Map.prototype.forEach(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Unknown --> def :INTRINSICS.Map.prototype.forEach(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Normal[Undefined] | Abrupt[throw] +-> def :INTRINSICS.Map.prototype.forEach(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Abrupt[throw] -------------------------------------------------------------------------------- def :INTRINSICS.Map.prototype.get(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Unknown --> def :INTRINSICS.Map.prototype.get(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Normal[Undefined] | Abrupt[throw] +-> def :INTRINSICS.Map.prototype.get(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Abrupt[throw] -------------------------------------------------------------------------------- def :INTRINSICS.Map.prototype.has(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Unknown --> def :INTRINSICS.Map.prototype.has(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Normal[False] | Abrupt[throw] +-> def :INTRINSICS.Map.prototype.has(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Abrupt[throw] -------------------------------------------------------------------------------- def :INTRINSICS.Map.prototype.set(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Unknown --> def :INTRINSICS.Map.prototype.set(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Normal[ESValue] | Abrupt[throw] +-> def :INTRINSICS.Map.prototype.set(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Abrupt[throw] -------------------------------------------------------------------------------- def :INTRINSICS.Math.hypot(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Unknown --> def :INTRINSICS.Math.hypot(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Normal[Number[0.0]] | Abrupt[throw] +-> def :INTRINSICS.Math.hypot(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Abrupt[throw] -------------------------------------------------------------------------------- def :INTRINSICS.Math.max(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Unknown --> def :INTRINSICS.Math.max(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Normal[Number[-INF]] | Abrupt[throw] +-> def :INTRINSICS.Math.max(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Abrupt[throw] -------------------------------------------------------------------------------- def :INTRINSICS.Math.min(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Unknown --> def :INTRINSICS.Math.min(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Normal[Number[+INF]] | Abrupt[throw] +-> def :INTRINSICS.Math.min(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Abrupt[throw] -------------------------------------------------------------------------------- def :INTRINSICS.Set.prototype.add(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Unknown --> def :INTRINSICS.Set.prototype.add(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Normal[ESValue] | Abrupt[throw] +-> def :INTRINSICS.Set.prototype.add(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Abrupt[throw] -------------------------------------------------------------------------------- def :INTRINSICS.Set.prototype.clear(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Unknown --> def :INTRINSICS.Set.prototype.clear(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Normal[Undefined] | Abrupt[throw] +-> def :INTRINSICS.Set.prototype.clear(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Abrupt[throw] -------------------------------------------------------------------------------- def :INTRINSICS.Set.prototype.delete(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Unknown --> def :INTRINSICS.Set.prototype.delete(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Normal[False] | Abrupt[throw] +-> def :INTRINSICS.Set.prototype.delete(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Abrupt[throw] -------------------------------------------------------------------------------- def :INTRINSICS.Set.prototype.forEach(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Unknown --> def :INTRINSICS.Set.prototype.forEach(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Normal[Undefined] | Abrupt[throw] +-> def :INTRINSICS.Set.prototype.forEach(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Abrupt[throw] -------------------------------------------------------------------------------- def :INTRINSICS.Set.prototype.has(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Unknown --> def :INTRINSICS.Set.prototype.has(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Normal[False] | Abrupt[throw] +-> def :INTRINSICS.Set.prototype.has(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Abrupt[throw] -------------------------------------------------------------------------------- def :INTRINSICS.String.prototype[@@iterator]:clo0(): Unknown --> def :INTRINSICS.String.prototype[@@iterator]:clo0(): Undefined +-> def :INTRINSICS.String.prototype[@@iterator]:clo0(): Unknown -------------------------------------------------------------------------------- def :INTRINSICS.TypedArray.prototype.filter(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Unknown --> def :INTRINSICS.TypedArray.prototype.filter(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Normal[Object] | Abrupt[throw] +-> def :INTRINSICS.TypedArray.prototype.filter(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Abrupt[throw] -------------------------------------------------------------------------------- def :INTRINSICS.WeakMap.prototype.set(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Unknown --> def :INTRINSICS.WeakMap.prototype.set(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Normal[ESValue] | Abrupt[throw] +-> def :INTRINSICS.WeakMap.prototype.set(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Abrupt[throw] -------------------------------------------------------------------------------- def :INTRINSICS.WeakSet.prototype.add(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Unknown --> def :INTRINSICS.WeakSet.prototype.add(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Normal[ESValue] | Abrupt[throw] +-> def :INTRINSICS.WeakSet.prototype.add(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Abrupt[throw] -------------------------------------------------------------------------------- def :INTRINSICS.get Map.prototype.size(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Unknown --> def :INTRINSICS.get Map.prototype.size(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Normal[Number] | Abrupt[throw] +-> def :INTRINSICS.get Map.prototype.size(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Abrupt[throw] -------------------------------------------------------------------------------- def :INTRINSICS.get Set.prototype.size(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Unknown --> def :INTRINSICS.get Set.prototype.size(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Normal[Number] | Abrupt[throw] +-> def :INTRINSICS.get Set.prototype.size(this: ESValue, ArgumentsList: List[ESValue], NewTarget: Object | Undefined): Abrupt[throw] -------------------------------------------------------------------------------- ```