@markw65/monkeyc-optimizer 1.1.4 → 1.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/build/api.cjs +226 -73
- package/build/optimizer.cjs +216 -66
- package/build/src/optimizer-types.d.ts +1 -0
- package/build/src/type-flow/interp-call.d.ts +2 -2
- package/build/src/type-flow.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -636,3 +636,16 @@ Bug Fixes
|
|
|
636
636
|
- Code cleanup
|
|
637
637
|
- refactor some of the type code for better type safety
|
|
638
638
|
- turn on the eslint rule eqeqeq and fix all the issues
|
|
639
|
+
|
|
640
|
+
### 1.1.5
|
|
641
|
+
|
|
642
|
+
- Bug fixes
|
|
643
|
+
- Always evaluate a constant's initializer to determine its type
|
|
644
|
+
- Fix a bug refining the object type based on the properties it accesses that could lose the type of the object.
|
|
645
|
+
|
|
646
|
+
### 1.1.6
|
|
647
|
+
|
|
648
|
+
- Bug fixes
|
|
649
|
+
- Fix an issue in restrictByEquality when restricting a union including an Enum, to a specific value of the enum.
|
|
650
|
+
- Fix the display of Method types to match the syntax used in MonkeyC.
|
|
651
|
+
- Infer the type of method(:symbol) by looking up symbol.
|
package/build/api.cjs
CHANGED
|
@@ -3022,45 +3022,115 @@ function printBlockState(block, state, indent = "") {
|
|
|
3022
3022
|
console.log(`${indent} - ${typeStateEntry(value, key)}${value.equivSet ? " " + tsEquivs(state, key) : ""}`);
|
|
3023
3023
|
});
|
|
3024
3024
|
}
|
|
3025
|
-
|
|
3025
|
+
/*
|
|
3026
|
+
* We have an object, and a MemberExpression object.<name>
|
|
3027
|
+
* - decls are the StateNodes associated with the known type
|
|
3028
|
+
* of object.
|
|
3029
|
+
* - possible are all the StateNodes that declare <name>
|
|
3030
|
+
*
|
|
3031
|
+
* We want to find all the elements of possible which are
|
|
3032
|
+
* "compatible" with decls, which tells us the set of things
|
|
3033
|
+
* that object.<name> could correspond to, and also what that
|
|
3034
|
+
* tells us about object.
|
|
3035
|
+
*
|
|
3036
|
+
* The return value is two arrays of StateNode. The first
|
|
3037
|
+
* gives the refined type of object, and the second is the
|
|
3038
|
+
* array of StateNodes that could declare <name>
|
|
3039
|
+
*/
|
|
3040
|
+
function filterDecls(decls, possible, name) {
|
|
3026
3041
|
if (!possible)
|
|
3027
|
-
return null;
|
|
3028
|
-
|
|
3042
|
+
return [null, null];
|
|
3043
|
+
const result = decls.reduce((cur, decl) => {
|
|
3029
3044
|
const found = possible.reduce((flag, poss) => {
|
|
3030
3045
|
if (decl === poss ||
|
|
3031
|
-
(poss.type === "ClassDeclaration" &&
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
cur
|
|
3046
|
+
(poss.type === "ClassDeclaration" && (0,_api__WEBPACK_IMPORTED_MODULE_0__.getSuperClasses)(poss)?.has(decl))) {
|
|
3047
|
+
// poss extends decl, so decl must actually be a poss
|
|
3048
|
+
// eg we know obj is an Object, and we call obj.toNumber
|
|
3049
|
+
// so possible includes all the classes that declare toNumber
|
|
3050
|
+
// so we can refine obj's type to the union of those types
|
|
3051
|
+
if (!cur[0]) {
|
|
3052
|
+
cur = [new Set(), new Set()];
|
|
3053
|
+
}
|
|
3054
|
+
cur[0].add(poss);
|
|
3055
|
+
cur[1].add(poss);
|
|
3056
|
+
return true;
|
|
3057
|
+
}
|
|
3058
|
+
else if (decl.type === "ClassDeclaration" &&
|
|
3059
|
+
(0,_api__WEBPACK_IMPORTED_MODULE_0__.getSuperClasses)(decl)?.has(poss)) {
|
|
3060
|
+
// decl extends poss, so decl remains unchanged
|
|
3061
|
+
// eg we know obj is Menu2, we call obj.toString
|
|
3062
|
+
// Menu2 doesn't define toString, but Object does
|
|
3063
|
+
// so poss is Object. But we still know that
|
|
3064
|
+
// obj is Menu2
|
|
3065
|
+
if (!cur[0]) {
|
|
3066
|
+
cur = [new Set(), new Set()];
|
|
3067
|
+
}
|
|
3068
|
+
cur[0].add(decl);
|
|
3069
|
+
cur[1].add(poss);
|
|
3038
3070
|
return true;
|
|
3039
3071
|
}
|
|
3040
3072
|
return flag;
|
|
3041
3073
|
}, false);
|
|
3042
3074
|
if (!found) {
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3075
|
+
// If we didn't find the property in any of the
|
|
3076
|
+
// standard places, the runtime might still find
|
|
3077
|
+
// it by searching up the Module stack (and up
|
|
3078
|
+
// the module stack from any super classes)
|
|
3079
|
+
//
|
|
3080
|
+
// eg
|
|
3081
|
+
//
|
|
3082
|
+
// obj = Application.getApp();
|
|
3083
|
+
// obj.Properties.whatever
|
|
3084
|
+
//
|
|
3085
|
+
// Properties doesn't exist on AppBase, but AppBase
|
|
3086
|
+
// is declared in Application, and Application
|
|
3087
|
+
// does declare Properties. So Application.Properties
|
|
3088
|
+
// is (one of) the declarations we should find; but we
|
|
3089
|
+
// must not refine obj's type to include Application.
|
|
3090
|
+
let d = [decl];
|
|
3091
|
+
do {
|
|
3092
|
+
d.forEach((d) => {
|
|
3093
|
+
const stack = d.stack;
|
|
3094
|
+
possible.forEach((poss) => {
|
|
3095
|
+
for (let i = stack.length; i--;) {
|
|
3096
|
+
const sn = stack[i];
|
|
3097
|
+
if (sn.decls === poss.decls) {
|
|
3098
|
+
if (!cur[0]) {
|
|
3099
|
+
cur = [new Set(), new Set()];
|
|
3100
|
+
}
|
|
3101
|
+
cur[0].add(decl);
|
|
3102
|
+
cur[1].add(poss);
|
|
3103
|
+
break;
|
|
3104
|
+
}
|
|
3105
|
+
if ((0,_api__WEBPACK_IMPORTED_MODULE_0__.hasProperty)(sn.decls, name)) {
|
|
3106
|
+
break;
|
|
3107
|
+
}
|
|
3108
|
+
}
|
|
3109
|
+
});
|
|
3110
|
+
});
|
|
3111
|
+
d = d.flatMap((d) => {
|
|
3112
|
+
if (d.type !== "ClassDeclaration" ||
|
|
3113
|
+
!d.superClass ||
|
|
3114
|
+
d.superClass === true) {
|
|
3115
|
+
return [];
|
|
3116
|
+
}
|
|
3117
|
+
return d.superClass;
|
|
3118
|
+
});
|
|
3119
|
+
} while (d.length);
|
|
3053
3120
|
}
|
|
3054
3121
|
return cur;
|
|
3055
|
-
}, null);
|
|
3122
|
+
}, [null, null]);
|
|
3123
|
+
if (!result[0])
|
|
3124
|
+
return [null, null];
|
|
3125
|
+
return [Array.from(result[0]), Array.from(result[1])];
|
|
3056
3126
|
}
|
|
3057
3127
|
function findObjectDeclsByProperty(state, object, next) {
|
|
3058
3128
|
const decls = (0,_type_flow_types__WEBPACK_IMPORTED_MODULE_11__/* .getStateNodeDeclsFromType */ .iX)(state, object);
|
|
3059
3129
|
if (!decls)
|
|
3060
|
-
return null;
|
|
3130
|
+
return [null, null];
|
|
3061
3131
|
const possibleDecls = (0,_api__WEBPACK_IMPORTED_MODULE_0__.hasProperty)(state.allDeclarations, next.property.name) &&
|
|
3062
3132
|
state.allDeclarations[next.property.name];
|
|
3063
|
-
return filterDecls(decls, possibleDecls);
|
|
3133
|
+
return filterDecls(decls, possibleDecls, next.property.name);
|
|
3064
3134
|
}
|
|
3065
3135
|
function refineObjectTypeByDecls(istate, object, trueDecls) {
|
|
3066
3136
|
const refinedType = typeFromTypeStateNodes(istate.state, trueDecls);
|
|
@@ -3076,13 +3146,13 @@ function findNextObjectType(istate, trueDecls, next) {
|
|
|
3076
3146
|
}, { type: 0 /* TypeTag.Never */ });
|
|
3077
3147
|
}
|
|
3078
3148
|
function resolveDottedMember(istate, object, next) {
|
|
3079
|
-
const
|
|
3080
|
-
if (!
|
|
3149
|
+
const [objDecls, trueDecls] = findObjectDeclsByProperty(istate.state, object, next);
|
|
3150
|
+
if (!objDecls)
|
|
3081
3151
|
return null;
|
|
3082
|
-
const property = findNextObjectType(istate,
|
|
3152
|
+
const property = findNextObjectType(istate, trueDecls, next);
|
|
3083
3153
|
if (!property)
|
|
3084
3154
|
return null;
|
|
3085
|
-
const type = refineObjectTypeByDecls(istate, object,
|
|
3155
|
+
const type = refineObjectTypeByDecls(istate, object, objDecls);
|
|
3086
3156
|
const mayThrow = !subtypeOf(object, type);
|
|
3087
3157
|
return { mayThrow, object: type, property };
|
|
3088
3158
|
}
|
|
@@ -3119,11 +3189,11 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
|
|
|
3119
3189
|
next = value.obj[me.property.name];
|
|
3120
3190
|
}
|
|
3121
3191
|
else {
|
|
3122
|
-
const trueDecls = findObjectDeclsByProperty(istate.state, cur, me);
|
|
3123
|
-
if (!
|
|
3192
|
+
const [objDecls, trueDecls] = findObjectDeclsByProperty(istate.state, cur, me);
|
|
3193
|
+
if (!objDecls) {
|
|
3124
3194
|
return null;
|
|
3125
3195
|
}
|
|
3126
|
-
cur = refineObjectTypeByDecls(istate, cur,
|
|
3196
|
+
cur = refineObjectTypeByDecls(istate, cur, objDecls);
|
|
3127
3197
|
next = findNextObjectType(istate, trueDecls, me);
|
|
3128
3198
|
}
|
|
3129
3199
|
}
|
|
@@ -3310,7 +3380,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
|
|
|
3310
3380
|
const info = sysCallInfo(callee);
|
|
3311
3381
|
if (!info)
|
|
3312
3382
|
return false;
|
|
3313
|
-
const result = info(callee, calleeObj, () => node.arguments.map((arg) => evaluateExpr(state, arg, typeMap).value));
|
|
3383
|
+
const result = info(istate.state, callee, calleeObj, () => node.arguments.map((arg) => evaluateExpr(state, arg, typeMap).value));
|
|
3314
3384
|
if (result.calleeObj) {
|
|
3315
3385
|
setStateEvent(curState, calleeObjDecl, result.calleeObj, false);
|
|
3316
3386
|
}
|
|
@@ -4632,14 +4702,18 @@ function evaluateLogicalTypes(op, left, right) {
|
|
|
4632
4702
|
|
|
4633
4703
|
"use strict";
|
|
4634
4704
|
/* unused harmony exports evaluateCall, checkCallArgs, sysCallInfo */
|
|
4635
|
-
/* harmony import */ var
|
|
4636
|
-
/* harmony import */ var
|
|
4637
|
-
/* harmony import */ var
|
|
4638
|
-
/* harmony import */ var
|
|
4639
|
-
/* harmony import */ var
|
|
4640
|
-
/* harmony import */ var
|
|
4641
|
-
/* harmony import */ var
|
|
4642
|
-
/* harmony import */ var
|
|
4705
|
+
/* harmony import */ var _optimizer_types__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(9697);
|
|
4706
|
+
/* harmony import */ var _type_flow__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4859);
|
|
4707
|
+
/* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6817);
|
|
4708
|
+
/* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_api__WEBPACK_IMPORTED_MODULE_2__);
|
|
4709
|
+
/* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6906);
|
|
4710
|
+
/* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_util__WEBPACK_IMPORTED_MODULE_3__);
|
|
4711
|
+
/* harmony import */ var _interp__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(7161);
|
|
4712
|
+
/* harmony import */ var _sub_type__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(9234);
|
|
4713
|
+
/* harmony import */ var _types__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(7255);
|
|
4714
|
+
/* harmony import */ var _union_type__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(757);
|
|
4715
|
+
|
|
4716
|
+
|
|
4643
4717
|
|
|
4644
4718
|
|
|
4645
4719
|
|
|
@@ -4668,6 +4742,20 @@ function evaluateCall(istate, node, callee, args) {
|
|
|
4668
4742
|
}
|
|
4669
4743
|
return checkCallArgs(istate, node, callee.value, args);
|
|
4670
4744
|
}
|
|
4745
|
+
function calleeObjectType(istate, callee) {
|
|
4746
|
+
if (callee.type === "MemberExpression") {
|
|
4747
|
+
return (istate.typeMap?.get(callee.object) || {
|
|
4748
|
+
type: 524287 /* TypeTag.Any */,
|
|
4749
|
+
});
|
|
4750
|
+
}
|
|
4751
|
+
if (callee.type === "Identifier" && istate.func) {
|
|
4752
|
+
const func = istate.func;
|
|
4753
|
+
const [self] = func.stack.slice(-1);
|
|
4754
|
+
return typeFromTypeStateNode(istate.state, self, (func.attributes & StateNodeAttributes.STATIC) !== 0 ||
|
|
4755
|
+
self.type !== "ClassDeclaration");
|
|
4756
|
+
}
|
|
4757
|
+
return null;
|
|
4758
|
+
}
|
|
4671
4759
|
function checkCallArgs(istate, node, callees, args) {
|
|
4672
4760
|
const allDiags = [];
|
|
4673
4761
|
const resultType = reduce(callees, (result, cur) => {
|
|
@@ -4677,13 +4765,11 @@ function checkCallArgs(istate, node, callees, args) {
|
|
|
4677
4765
|
let returnType = null;
|
|
4678
4766
|
let effects = true;
|
|
4679
4767
|
let argEffects = true;
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
type: 524287 /* TypeTag.Any */,
|
|
4683
|
-
};
|
|
4768
|
+
const object = calleeObjectType(istate, node.callee);
|
|
4769
|
+
if (object) {
|
|
4684
4770
|
const info = sysCallInfo(cur);
|
|
4685
4771
|
if (info) {
|
|
4686
|
-
const result = info(cur, object, () => args);
|
|
4772
|
+
const result = info(istate.state, cur, object, () => args);
|
|
4687
4773
|
if (result.argTypes)
|
|
4688
4774
|
argTypes = result.argTypes;
|
|
4689
4775
|
if (result.returnType)
|
|
@@ -4822,7 +4908,7 @@ function sysCallInfo(func) {
|
|
|
4822
4908
|
function getSystemCallTable() {
|
|
4823
4909
|
if (systemCallInfo)
|
|
4824
4910
|
return systemCallInfo;
|
|
4825
|
-
const arrayAdd = (callee, calleeObj, getArgs) => {
|
|
4911
|
+
const arrayAdd = (state, callee, calleeObj, getArgs) => {
|
|
4826
4912
|
const ret = {};
|
|
4827
4913
|
if (calleeObj.type & 512 /* TypeTag.Array */) {
|
|
4828
4914
|
const adata = getUnionComponent(calleeObj, 512 /* TypeTag.Array */);
|
|
@@ -4854,7 +4940,7 @@ function getSystemCallTable() {
|
|
|
4854
4940
|
}
|
|
4855
4941
|
return ret;
|
|
4856
4942
|
};
|
|
4857
|
-
const arrayRet = (callee, calleeObj, _getArgs) => {
|
|
4943
|
+
const arrayRet = (state, callee, calleeObj, _getArgs) => {
|
|
4858
4944
|
const ret = { effectFree: true };
|
|
4859
4945
|
if (calleeObj.type & 512 /* TypeTag.Array */) {
|
|
4860
4946
|
const adata = getUnionComponent(calleeObj, 512 /* TypeTag.Array */);
|
|
@@ -4864,7 +4950,7 @@ function getSystemCallTable() {
|
|
|
4864
4950
|
}
|
|
4865
4951
|
return ret;
|
|
4866
4952
|
};
|
|
4867
|
-
const dictionaryGet = (callee, calleeObj, getArgs) => {
|
|
4953
|
+
const dictionaryGet = (state, callee, calleeObj, getArgs) => {
|
|
4868
4954
|
const ret = { effectFree: true };
|
|
4869
4955
|
if (calleeObj.type & 1024 /* TypeTag.Dictionary */) {
|
|
4870
4956
|
const ddata = getUnionComponent(calleeObj, 1024 /* TypeTag.Dictionary */);
|
|
@@ -4878,7 +4964,7 @@ function getSystemCallTable() {
|
|
|
4878
4964
|
}
|
|
4879
4965
|
return ret;
|
|
4880
4966
|
};
|
|
4881
|
-
const dictionaryValues = (callee, calleeObj) => {
|
|
4967
|
+
const dictionaryValues = (state, callee, calleeObj) => {
|
|
4882
4968
|
const ret = { effectFree: true };
|
|
4883
4969
|
if (calleeObj.type & 1024 /* TypeTag.Dictionary */) {
|
|
4884
4970
|
const ddata = getUnionComponent(calleeObj, 1024 /* TypeTag.Dictionary */);
|
|
@@ -4888,7 +4974,7 @@ function getSystemCallTable() {
|
|
|
4888
4974
|
}
|
|
4889
4975
|
return ret;
|
|
4890
4976
|
};
|
|
4891
|
-
const dictionaryKeys = (callee, calleeObj) => {
|
|
4977
|
+
const dictionaryKeys = (state, callee, calleeObj) => {
|
|
4892
4978
|
const ret = { effectFree: true };
|
|
4893
4979
|
if (calleeObj.type & 1024 /* TypeTag.Dictionary */) {
|
|
4894
4980
|
const ddata = getUnionComponent(calleeObj, 1024 /* TypeTag.Dictionary */);
|
|
@@ -4898,7 +4984,7 @@ function getSystemCallTable() {
|
|
|
4898
4984
|
}
|
|
4899
4985
|
return ret;
|
|
4900
4986
|
};
|
|
4901
|
-
const dictionaryPut = (callee, calleeObj, getArgs) => {
|
|
4987
|
+
const dictionaryPut = (state, callee, calleeObj, getArgs) => {
|
|
4902
4988
|
const ret = {};
|
|
4903
4989
|
if (calleeObj.type & 1024 /* TypeTag.Dictionary */) {
|
|
4904
4990
|
const ddata = getUnionComponent(calleeObj, 1024 /* TypeTag.Dictionary */);
|
|
@@ -4929,7 +5015,7 @@ function getSystemCallTable() {
|
|
|
4929
5015
|
}
|
|
4930
5016
|
return ret;
|
|
4931
5017
|
};
|
|
4932
|
-
const methodInvoke = (callee, calleeObj, getArgs) => {
|
|
5018
|
+
const methodInvoke = (state, callee, calleeObj, getArgs) => {
|
|
4933
5019
|
const ret = { argEffects: true };
|
|
4934
5020
|
if (calleeObj.type & 2048 /* TypeTag.Method */) {
|
|
4935
5021
|
const data = getUnionComponent(calleeObj, 2048 /* TypeTag.Method */);
|
|
@@ -4942,9 +5028,49 @@ function getSystemCallTable() {
|
|
|
4942
5028
|
ret.argTypes = getArgs();
|
|
4943
5029
|
return ret;
|
|
4944
5030
|
};
|
|
5031
|
+
const method = (state, callee, calleeObj, getArgs) => {
|
|
5032
|
+
const ret = {};
|
|
5033
|
+
const args = getArgs();
|
|
5034
|
+
if (args.length === 1 &&
|
|
5035
|
+
hasValue(args[0]) &&
|
|
5036
|
+
args[0].type === 131072 /* TypeTag.Symbol */) {
|
|
5037
|
+
const symbol = {
|
|
5038
|
+
type: "Identifier",
|
|
5039
|
+
name: args[0].value,
|
|
5040
|
+
};
|
|
5041
|
+
const next = {
|
|
5042
|
+
type: "MemberExpression",
|
|
5043
|
+
object: symbol,
|
|
5044
|
+
property: symbol,
|
|
5045
|
+
computed: false,
|
|
5046
|
+
};
|
|
5047
|
+
const [, trueDecls] = findObjectDeclsByProperty(state, calleeObj, next);
|
|
5048
|
+
if (!trueDecls)
|
|
5049
|
+
return ret;
|
|
5050
|
+
const callees = trueDecls
|
|
5051
|
+
.flatMap((decl) => decl.decls?.[symbol.name])
|
|
5052
|
+
.filter((decl) => decl?.type === "FunctionDeclaration");
|
|
5053
|
+
if (!callees.length)
|
|
5054
|
+
return ret;
|
|
5055
|
+
ret.returnType = callees.reduce((type, callee) => {
|
|
5056
|
+
const result = callee.node.returnType
|
|
5057
|
+
? typeFromTypespec(state, callee.node.returnType.argument, callee.stack)
|
|
5058
|
+
: { type: 524287 /* TypeTag.Any */ };
|
|
5059
|
+
const args = callee.node.params.map((param) => param.type === "BinaryExpression"
|
|
5060
|
+
? typeFromTypespec(state, param.right, callee.stack)
|
|
5061
|
+
: { type: 524287 /* TypeTag.Any */ });
|
|
5062
|
+
unionInto(type, {
|
|
5063
|
+
type: 2048 /* TypeTag.Method */,
|
|
5064
|
+
value: { result, args },
|
|
5065
|
+
});
|
|
5066
|
+
return type;
|
|
5067
|
+
}, { type: 0 /* TypeTag.Never */ });
|
|
5068
|
+
}
|
|
5069
|
+
return ret;
|
|
5070
|
+
};
|
|
4945
5071
|
const nop = () => ({ effectFree: true });
|
|
4946
5072
|
const mod = () => ({});
|
|
4947
|
-
const rounder = (callee, calleeObj, getArgs) => {
|
|
5073
|
+
const rounder = (state, callee, calleeObj, getArgs) => {
|
|
4948
5074
|
const results = {};
|
|
4949
5075
|
const fn = Math[callee.name];
|
|
4950
5076
|
results.effectFree = true;
|
|
@@ -4962,7 +5088,7 @@ function getSystemCallTable() {
|
|
|
4962
5088
|
: { type: 120 /* TypeTag.Numeric */ };
|
|
4963
5089
|
return results;
|
|
4964
5090
|
};
|
|
4965
|
-
const mathHelper = (callee, calleeObj, getArgs, helper) => {
|
|
5091
|
+
const mathHelper = (state, callee, calleeObj, getArgs, helper) => {
|
|
4966
5092
|
const results = {};
|
|
4967
5093
|
const fn = helper && typeof helper === "function"
|
|
4968
5094
|
? helper
|
|
@@ -5021,6 +5147,7 @@ function getSystemCallTable() {
|
|
|
5021
5147
|
"$.Toybox.Lang.Dictionary.toString": nop,
|
|
5022
5148
|
"$.Toybox.Lang.Dictionary.values": dictionaryValues,
|
|
5023
5149
|
"$.Toybox.Lang.Method.invoke": methodInvoke,
|
|
5150
|
+
"$.Toybox.Lang.Object.method": method,
|
|
5024
5151
|
"$.Toybox.Math.acos": mathHelper,
|
|
5025
5152
|
"$.Toybox.Math.asin": mathHelper,
|
|
5026
5153
|
"$.Toybox.Math.atan": mathHelper,
|
|
@@ -5028,15 +5155,15 @@ function getSystemCallTable() {
|
|
|
5028
5155
|
"$.Toybox.Math.ceil": rounder,
|
|
5029
5156
|
"$.Toybox.Math.cos": mathHelper,
|
|
5030
5157
|
"$.Toybox.Math.floor": rounder,
|
|
5031
|
-
"$.Toybox.Math.ln": (callee, calleeObj, getArgs) => mathHelper(callee, calleeObj, getArgs, "log"),
|
|
5032
|
-
"$.Toybox.Math.log": (callee, calleeObj, getArgs) => mathHelper(callee, calleeObj, getArgs, (x, base) => Math.log(x) / Math.log(base)),
|
|
5158
|
+
"$.Toybox.Math.ln": (state, callee, calleeObj, getArgs) => mathHelper(state, callee, calleeObj, getArgs, "log"),
|
|
5159
|
+
"$.Toybox.Math.log": (state, callee, calleeObj, getArgs) => mathHelper(state, callee, calleeObj, getArgs, (x, base) => Math.log(x) / Math.log(base)),
|
|
5033
5160
|
"$.Toybox.Math.pow": mathHelper,
|
|
5034
5161
|
"$.Toybox.Math.round": rounder,
|
|
5035
5162
|
"$.Toybox.Math.sin": mathHelper,
|
|
5036
5163
|
"$.Toybox.Math.sqrt": mathHelper,
|
|
5037
5164
|
"$.Toybox.Math.tan": mathHelper,
|
|
5038
|
-
"$.Toybox.Math.toDegrees": (callee, calleeObj, getArgs) => mathHelper(callee, calleeObj, getArgs, (arg) => (arg * 180) / Math.PI),
|
|
5039
|
-
"$.Toybox.Math.toRadians": (callee, calleeObj, getArgs) => mathHelper(callee, calleeObj, getArgs, (arg) => (arg * Math.PI) / 180),
|
|
5165
|
+
"$.Toybox.Math.toDegrees": (state, callee, calleeObj, getArgs) => mathHelper(state, callee, calleeObj, getArgs, (arg) => (arg * 180) / Math.PI),
|
|
5166
|
+
"$.Toybox.Math.toRadians": (state, callee, calleeObj, getArgs) => mathHelper(state, callee, calleeObj, getArgs, (arg) => (arg * Math.PI) / 180),
|
|
5040
5167
|
"$.Toybox.Math.mean": nop,
|
|
5041
5168
|
"$.Toybox.Math.mode": nop,
|
|
5042
5169
|
"$.Toybox.Math.stdev": nop,
|
|
@@ -5288,9 +5415,9 @@ function getLhsConstraint(istate, node) {
|
|
|
5288
5415
|
}
|
|
5289
5416
|
const object = istate.typeMap.get(node.object);
|
|
5290
5417
|
if (object && !node.computed) {
|
|
5291
|
-
const
|
|
5292
|
-
if (
|
|
5293
|
-
lookupDefs = lookupNext(istate.state, [{ parent: null, results:
|
|
5418
|
+
const [, trueDecls] = findObjectDeclsByProperty(istate.state, object, node);
|
|
5419
|
+
if (trueDecls) {
|
|
5420
|
+
lookupDefs = lookupNext(istate.state, [{ parent: null, results: trueDecls }], "decls", node.property);
|
|
5294
5421
|
}
|
|
5295
5422
|
}
|
|
5296
5423
|
}
|
|
@@ -6643,6 +6770,8 @@ function printBlockTrailer(block) {
|
|
|
6643
6770
|
/* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_util__WEBPACK_IMPORTED_MODULE_4__);
|
|
6644
6771
|
/* harmony import */ var _interp__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(7161);
|
|
6645
6772
|
/* harmony import */ var _union_type__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(757);
|
|
6773
|
+
/* harmony import */ var _intersection_type__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(6973);
|
|
6774
|
+
|
|
6646
6775
|
|
|
6647
6776
|
|
|
6648
6777
|
|
|
@@ -6866,24 +6995,47 @@ function typeFromTypeStateNode(state, sn, classVsObj) {
|
|
|
6866
6995
|
sn.resolvedType = result;
|
|
6867
6996
|
return result;
|
|
6868
6997
|
}
|
|
6869
|
-
case "VariableDeclarator":
|
|
6998
|
+
case "VariableDeclarator": {
|
|
6999
|
+
if (sn.resolvedType)
|
|
7000
|
+
return sn.resolvedType;
|
|
7001
|
+
let declared = null;
|
|
7002
|
+
if (sn.node.id.type === "BinaryExpression") {
|
|
7003
|
+
declared = typeFromTypespec(state, sn.node.id.right, sn.stack);
|
|
7004
|
+
}
|
|
6870
7005
|
if (sn.node.kind === "const" && sn.node.init) {
|
|
6871
|
-
|
|
6872
|
-
|
|
6873
|
-
return
|
|
7006
|
+
if (hasProperty(sn, "resolvedType")) {
|
|
7007
|
+
// The constant is defined recursively
|
|
7008
|
+
return declared ?? { type: 524287 /* TypeTag.Any */ };
|
|
7009
|
+
}
|
|
7010
|
+
// set the marker in case the constant appears in its
|
|
7011
|
+
// own initializer.
|
|
7012
|
+
sn.resolvedType = undefined;
|
|
7013
|
+
const stack = state.stack;
|
|
7014
|
+
let resolved;
|
|
7015
|
+
try {
|
|
7016
|
+
state.stack = sn.stack;
|
|
7017
|
+
resolved = evaluateExpr(state, sn.node.init).value;
|
|
7018
|
+
}
|
|
7019
|
+
finally {
|
|
7020
|
+
state.stack = stack;
|
|
6874
7021
|
}
|
|
6875
|
-
|
|
6876
|
-
|
|
7022
|
+
if (resolved.type === 0 /* TypeTag.Never */) {
|
|
7023
|
+
resolved = declared ?? { type: 524287 /* TypeTag.Any */ };
|
|
6877
7024
|
}
|
|
6878
|
-
if (
|
|
6879
|
-
|
|
6880
|
-
|
|
7025
|
+
else if (declared) {
|
|
7026
|
+
resolved = intersection(resolved, declared);
|
|
7027
|
+
if (resolved.type === 0 /* TypeTag.Never */) {
|
|
7028
|
+
resolved = declared;
|
|
7029
|
+
}
|
|
6881
7030
|
}
|
|
7031
|
+
sn.resolvedType = resolved;
|
|
7032
|
+
return resolved;
|
|
6882
7033
|
}
|
|
6883
7034
|
if (sn.node.id.type === "BinaryExpression") {
|
|
6884
7035
|
return typeFromTypespec(state, sn.node.id.right, sn.stack);
|
|
6885
7036
|
}
|
|
6886
7037
|
return { type: 524287 /* TypeTag.Any */ };
|
|
7038
|
+
}
|
|
6887
7039
|
}
|
|
6888
7040
|
throw new Error(`Internal error: Unexpected StateNodeDecl.type: ${sn.type}`);
|
|
6889
7041
|
}
|
|
@@ -7217,8 +7369,8 @@ function display(type) {
|
|
|
7217
7369
|
case 1024 /* TypeTag.Dictionary */:
|
|
7218
7370
|
return `${display(tv.value.key)}, ${display(tv.value.value)}`;
|
|
7219
7371
|
case 2048 /* TypeTag.Method */:
|
|
7220
|
-
return `(${tv.value.args
|
|
7221
|
-
.map((arg) => display(arg))
|
|
7372
|
+
return `Method(${tv.value.args
|
|
7373
|
+
.map((arg, i) => `a${i + 1} as ${display(arg)}`)
|
|
7222
7374
|
.join(", ")}) as ${display(tv.value.result)}`;
|
|
7223
7375
|
case 4096 /* TypeTag.Module */:
|
|
7224
7376
|
case 8192 /* TypeTag.Function */:
|
|
@@ -7278,6 +7430,7 @@ function display(type) {
|
|
|
7278
7430
|
65536 /* TypeTag.Enum */ |
|
|
7279
7431
|
262144 /* TypeTag.Typedef */ |
|
|
7280
7432
|
131072 /* TypeTag.Symbol */ |
|
|
7433
|
+
2048 /* TypeTag.Method */ |
|
|
7281
7434
|
256 /* TypeTag.String */)) {
|
|
7282
7435
|
parts.push(valueStr);
|
|
7283
7436
|
}
|
|
@@ -7305,7 +7458,7 @@ function forEachUnionComponent(v, bits, fn) {
|
|
|
7305
7458
|
bits &= ~SingleTonTypeTagsConst;
|
|
7306
7459
|
if (!bits)
|
|
7307
7460
|
return;
|
|
7308
|
-
if (v.type & UnionDataTypeTagsConst) {
|
|
7461
|
+
if ((v.type | bits) & UnionDataTypeTagsConst) {
|
|
7309
7462
|
// Don't iterate the value type bits if any union bit is set
|
|
7310
7463
|
bits &= ~ValueTypeTagsConst;
|
|
7311
7464
|
}
|
|
@@ -8602,7 +8755,7 @@ function visitReferences(state, ast, name, defn, callback, includeDefs = false,
|
|
|
8602
8755
|
const objectType = typeMap.get(node.object);
|
|
8603
8756
|
if (!objectType)
|
|
8604
8757
|
return results;
|
|
8605
|
-
const decls = (0,type_flow/* findObjectDeclsByProperty */.nK)(state, objectType, node);
|
|
8758
|
+
const [, decls] = (0,type_flow/* findObjectDeclsByProperty */.nK)(state, objectType, node);
|
|
8606
8759
|
if (decls) {
|
|
8607
8760
|
const next = (0,external_api_cjs_.lookupNext)(state, [{ parent: null, results: decls }], "decls", node.property);
|
|
8608
8761
|
if (next) {
|
package/build/optimizer.cjs
CHANGED
|
@@ -9257,6 +9257,7 @@ function widenType(t) {
|
|
|
9257
9257
|
|
|
9258
9258
|
|
|
9259
9259
|
|
|
9260
|
+
|
|
9260
9261
|
function typeTagName(tag) {
|
|
9261
9262
|
switch (tag) {
|
|
9262
9263
|
case 0 /* TypeTag.Never */:
|
|
@@ -9473,24 +9474,47 @@ function typeFromTypeStateNode(state, sn, classVsObj) {
|
|
|
9473
9474
|
sn.resolvedType = result;
|
|
9474
9475
|
return result;
|
|
9475
9476
|
}
|
|
9476
|
-
case "VariableDeclarator":
|
|
9477
|
+
case "VariableDeclarator": {
|
|
9478
|
+
if (sn.resolvedType)
|
|
9479
|
+
return sn.resolvedType;
|
|
9480
|
+
let declared = null;
|
|
9481
|
+
if (sn.node.id.type === "BinaryExpression") {
|
|
9482
|
+
declared = typeFromTypespec(state, sn.node.id.right, sn.stack);
|
|
9483
|
+
}
|
|
9477
9484
|
if (sn.node.kind === "const" && sn.node.init) {
|
|
9478
|
-
|
|
9479
|
-
|
|
9480
|
-
return
|
|
9485
|
+
if (hasProperty(sn, "resolvedType")) {
|
|
9486
|
+
// The constant is defined recursively
|
|
9487
|
+
return declared ?? { type: 524287 /* TypeTag.Any */ };
|
|
9488
|
+
}
|
|
9489
|
+
// set the marker in case the constant appears in its
|
|
9490
|
+
// own initializer.
|
|
9491
|
+
sn.resolvedType = undefined;
|
|
9492
|
+
const stack = state.stack;
|
|
9493
|
+
let resolved;
|
|
9494
|
+
try {
|
|
9495
|
+
state.stack = sn.stack;
|
|
9496
|
+
resolved = evaluateExpr(state, sn.node.init).value;
|
|
9481
9497
|
}
|
|
9482
|
-
|
|
9483
|
-
|
|
9498
|
+
finally {
|
|
9499
|
+
state.stack = stack;
|
|
9484
9500
|
}
|
|
9485
|
-
if (
|
|
9486
|
-
|
|
9487
|
-
|
|
9501
|
+
if (resolved.type === 0 /* TypeTag.Never */) {
|
|
9502
|
+
resolved = declared ?? { type: 524287 /* TypeTag.Any */ };
|
|
9503
|
+
}
|
|
9504
|
+
else if (declared) {
|
|
9505
|
+
resolved = intersection(resolved, declared);
|
|
9506
|
+
if (resolved.type === 0 /* TypeTag.Never */) {
|
|
9507
|
+
resolved = declared;
|
|
9508
|
+
}
|
|
9488
9509
|
}
|
|
9510
|
+
sn.resolvedType = resolved;
|
|
9511
|
+
return resolved;
|
|
9489
9512
|
}
|
|
9490
9513
|
if (sn.node.id.type === "BinaryExpression") {
|
|
9491
9514
|
return typeFromTypespec(state, sn.node.id.right, sn.stack);
|
|
9492
9515
|
}
|
|
9493
9516
|
return { type: 524287 /* TypeTag.Any */ };
|
|
9517
|
+
}
|
|
9494
9518
|
}
|
|
9495
9519
|
throw new Error(`Internal error: Unexpected StateNodeDecl.type: ${sn.type}`);
|
|
9496
9520
|
}
|
|
@@ -9824,8 +9848,8 @@ function display(type) {
|
|
|
9824
9848
|
case 1024 /* TypeTag.Dictionary */:
|
|
9825
9849
|
return `${display(tv.value.key)}, ${display(tv.value.value)}`;
|
|
9826
9850
|
case 2048 /* TypeTag.Method */:
|
|
9827
|
-
return `(${tv.value.args
|
|
9828
|
-
.map((arg) => display(arg))
|
|
9851
|
+
return `Method(${tv.value.args
|
|
9852
|
+
.map((arg, i) => `a${i + 1} as ${display(arg)}`)
|
|
9829
9853
|
.join(", ")}) as ${display(tv.value.result)}`;
|
|
9830
9854
|
case 4096 /* TypeTag.Module */:
|
|
9831
9855
|
case 8192 /* TypeTag.Function */:
|
|
@@ -9885,6 +9909,7 @@ function display(type) {
|
|
|
9885
9909
|
65536 /* TypeTag.Enum */ |
|
|
9886
9910
|
262144 /* TypeTag.Typedef */ |
|
|
9887
9911
|
131072 /* TypeTag.Symbol */ |
|
|
9912
|
+
2048 /* TypeTag.Method */ |
|
|
9888
9913
|
256 /* TypeTag.String */)) {
|
|
9889
9914
|
parts.push(valueStr);
|
|
9890
9915
|
}
|
|
@@ -9912,7 +9937,7 @@ function forEachUnionComponent(v, bits, fn) {
|
|
|
9912
9937
|
bits &= ~SingleTonTypeTagsConst;
|
|
9913
9938
|
if (!bits)
|
|
9914
9939
|
return;
|
|
9915
|
-
if (v.type & UnionDataTypeTagsConst) {
|
|
9940
|
+
if ((v.type | bits) & UnionDataTypeTagsConst) {
|
|
9916
9941
|
// Don't iterate the value type bits if any union bit is set
|
|
9917
9942
|
bits &= ~ValueTypeTagsConst;
|
|
9918
9943
|
}
|
|
@@ -10580,6 +10605,8 @@ function evaluateLogicalTypes(op, left, right) {
|
|
|
10580
10605
|
|
|
10581
10606
|
|
|
10582
10607
|
|
|
10608
|
+
|
|
10609
|
+
|
|
10583
10610
|
function evaluateCall(istate, node, callee, args) {
|
|
10584
10611
|
while (!hasValue(callee) || callee.type !== 8192 /* TypeTag.Function */) {
|
|
10585
10612
|
const name = node.callee.type === "Identifier"
|
|
@@ -10602,6 +10629,20 @@ function evaluateCall(istate, node, callee, args) {
|
|
|
10602
10629
|
}
|
|
10603
10630
|
return checkCallArgs(istate, node, callee.value, args);
|
|
10604
10631
|
}
|
|
10632
|
+
function calleeObjectType(istate, callee) {
|
|
10633
|
+
if (callee.type === "MemberExpression") {
|
|
10634
|
+
return (istate.typeMap?.get(callee.object) || {
|
|
10635
|
+
type: 524287 /* TypeTag.Any */,
|
|
10636
|
+
});
|
|
10637
|
+
}
|
|
10638
|
+
if (callee.type === "Identifier" && istate.func) {
|
|
10639
|
+
const func = istate.func;
|
|
10640
|
+
const [self] = func.stack.slice(-1);
|
|
10641
|
+
return typeFromTypeStateNode(istate.state, self, (func.attributes & StateNodeAttributes.STATIC) !== 0 ||
|
|
10642
|
+
self.type !== "ClassDeclaration");
|
|
10643
|
+
}
|
|
10644
|
+
return null;
|
|
10645
|
+
}
|
|
10605
10646
|
function checkCallArgs(istate, node, callees, args) {
|
|
10606
10647
|
const allDiags = [];
|
|
10607
10648
|
const resultType = (0,external_util_cjs_namespaceObject.reduce)(callees, (result, cur) => {
|
|
@@ -10611,13 +10652,11 @@ function checkCallArgs(istate, node, callees, args) {
|
|
|
10611
10652
|
let returnType = null;
|
|
10612
10653
|
let effects = true;
|
|
10613
10654
|
let argEffects = true;
|
|
10614
|
-
|
|
10615
|
-
|
|
10616
|
-
type: 524287 /* TypeTag.Any */,
|
|
10617
|
-
};
|
|
10655
|
+
const object = calleeObjectType(istate, node.callee);
|
|
10656
|
+
if (object) {
|
|
10618
10657
|
const info = sysCallInfo(cur);
|
|
10619
10658
|
if (info) {
|
|
10620
|
-
const result = info(cur, object, () => args);
|
|
10659
|
+
const result = info(istate.state, cur, object, () => args);
|
|
10621
10660
|
if (result.argTypes)
|
|
10622
10661
|
argTypes = result.argTypes;
|
|
10623
10662
|
if (result.returnType)
|
|
@@ -10756,7 +10795,7 @@ function sysCallInfo(func) {
|
|
|
10756
10795
|
function getSystemCallTable() {
|
|
10757
10796
|
if (systemCallInfo)
|
|
10758
10797
|
return systemCallInfo;
|
|
10759
|
-
const arrayAdd = (callee, calleeObj, getArgs) => {
|
|
10798
|
+
const arrayAdd = (state, callee, calleeObj, getArgs) => {
|
|
10760
10799
|
const ret = {};
|
|
10761
10800
|
if (calleeObj.type & 512 /* TypeTag.Array */) {
|
|
10762
10801
|
const adata = getUnionComponent(calleeObj, 512 /* TypeTag.Array */);
|
|
@@ -10788,7 +10827,7 @@ function getSystemCallTable() {
|
|
|
10788
10827
|
}
|
|
10789
10828
|
return ret;
|
|
10790
10829
|
};
|
|
10791
|
-
const arrayRet = (callee, calleeObj, _getArgs) => {
|
|
10830
|
+
const arrayRet = (state, callee, calleeObj, _getArgs) => {
|
|
10792
10831
|
const ret = { effectFree: true };
|
|
10793
10832
|
if (calleeObj.type & 512 /* TypeTag.Array */) {
|
|
10794
10833
|
const adata = getUnionComponent(calleeObj, 512 /* TypeTag.Array */);
|
|
@@ -10798,7 +10837,7 @@ function getSystemCallTable() {
|
|
|
10798
10837
|
}
|
|
10799
10838
|
return ret;
|
|
10800
10839
|
};
|
|
10801
|
-
const dictionaryGet = (callee, calleeObj, getArgs) => {
|
|
10840
|
+
const dictionaryGet = (state, callee, calleeObj, getArgs) => {
|
|
10802
10841
|
const ret = { effectFree: true };
|
|
10803
10842
|
if (calleeObj.type & 1024 /* TypeTag.Dictionary */) {
|
|
10804
10843
|
const ddata = getUnionComponent(calleeObj, 1024 /* TypeTag.Dictionary */);
|
|
@@ -10812,7 +10851,7 @@ function getSystemCallTable() {
|
|
|
10812
10851
|
}
|
|
10813
10852
|
return ret;
|
|
10814
10853
|
};
|
|
10815
|
-
const dictionaryValues = (callee, calleeObj) => {
|
|
10854
|
+
const dictionaryValues = (state, callee, calleeObj) => {
|
|
10816
10855
|
const ret = { effectFree: true };
|
|
10817
10856
|
if (calleeObj.type & 1024 /* TypeTag.Dictionary */) {
|
|
10818
10857
|
const ddata = getUnionComponent(calleeObj, 1024 /* TypeTag.Dictionary */);
|
|
@@ -10822,7 +10861,7 @@ function getSystemCallTable() {
|
|
|
10822
10861
|
}
|
|
10823
10862
|
return ret;
|
|
10824
10863
|
};
|
|
10825
|
-
const dictionaryKeys = (callee, calleeObj) => {
|
|
10864
|
+
const dictionaryKeys = (state, callee, calleeObj) => {
|
|
10826
10865
|
const ret = { effectFree: true };
|
|
10827
10866
|
if (calleeObj.type & 1024 /* TypeTag.Dictionary */) {
|
|
10828
10867
|
const ddata = getUnionComponent(calleeObj, 1024 /* TypeTag.Dictionary */);
|
|
@@ -10832,7 +10871,7 @@ function getSystemCallTable() {
|
|
|
10832
10871
|
}
|
|
10833
10872
|
return ret;
|
|
10834
10873
|
};
|
|
10835
|
-
const dictionaryPut = (callee, calleeObj, getArgs) => {
|
|
10874
|
+
const dictionaryPut = (state, callee, calleeObj, getArgs) => {
|
|
10836
10875
|
const ret = {};
|
|
10837
10876
|
if (calleeObj.type & 1024 /* TypeTag.Dictionary */) {
|
|
10838
10877
|
const ddata = getUnionComponent(calleeObj, 1024 /* TypeTag.Dictionary */);
|
|
@@ -10863,7 +10902,7 @@ function getSystemCallTable() {
|
|
|
10863
10902
|
}
|
|
10864
10903
|
return ret;
|
|
10865
10904
|
};
|
|
10866
|
-
const methodInvoke = (callee, calleeObj, getArgs) => {
|
|
10905
|
+
const methodInvoke = (state, callee, calleeObj, getArgs) => {
|
|
10867
10906
|
const ret = { argEffects: true };
|
|
10868
10907
|
if (calleeObj.type & 2048 /* TypeTag.Method */) {
|
|
10869
10908
|
const data = getUnionComponent(calleeObj, 2048 /* TypeTag.Method */);
|
|
@@ -10876,9 +10915,49 @@ function getSystemCallTable() {
|
|
|
10876
10915
|
ret.argTypes = getArgs();
|
|
10877
10916
|
return ret;
|
|
10878
10917
|
};
|
|
10918
|
+
const method = (state, callee, calleeObj, getArgs) => {
|
|
10919
|
+
const ret = {};
|
|
10920
|
+
const args = getArgs();
|
|
10921
|
+
if (args.length === 1 &&
|
|
10922
|
+
hasValue(args[0]) &&
|
|
10923
|
+
args[0].type === 131072 /* TypeTag.Symbol */) {
|
|
10924
|
+
const symbol = {
|
|
10925
|
+
type: "Identifier",
|
|
10926
|
+
name: args[0].value,
|
|
10927
|
+
};
|
|
10928
|
+
const next = {
|
|
10929
|
+
type: "MemberExpression",
|
|
10930
|
+
object: symbol,
|
|
10931
|
+
property: symbol,
|
|
10932
|
+
computed: false,
|
|
10933
|
+
};
|
|
10934
|
+
const [, trueDecls] = findObjectDeclsByProperty(state, calleeObj, next);
|
|
10935
|
+
if (!trueDecls)
|
|
10936
|
+
return ret;
|
|
10937
|
+
const callees = trueDecls
|
|
10938
|
+
.flatMap((decl) => decl.decls?.[symbol.name])
|
|
10939
|
+
.filter((decl) => decl?.type === "FunctionDeclaration");
|
|
10940
|
+
if (!callees.length)
|
|
10941
|
+
return ret;
|
|
10942
|
+
ret.returnType = callees.reduce((type, callee) => {
|
|
10943
|
+
const result = callee.node.returnType
|
|
10944
|
+
? typeFromTypespec(state, callee.node.returnType.argument, callee.stack)
|
|
10945
|
+
: { type: 524287 /* TypeTag.Any */ };
|
|
10946
|
+
const args = callee.node.params.map((param) => param.type === "BinaryExpression"
|
|
10947
|
+
? typeFromTypespec(state, param.right, callee.stack)
|
|
10948
|
+
: { type: 524287 /* TypeTag.Any */ });
|
|
10949
|
+
unionInto(type, {
|
|
10950
|
+
type: 2048 /* TypeTag.Method */,
|
|
10951
|
+
value: { result, args },
|
|
10952
|
+
});
|
|
10953
|
+
return type;
|
|
10954
|
+
}, { type: 0 /* TypeTag.Never */ });
|
|
10955
|
+
}
|
|
10956
|
+
return ret;
|
|
10957
|
+
};
|
|
10879
10958
|
const nop = () => ({ effectFree: true });
|
|
10880
10959
|
const mod = () => ({});
|
|
10881
|
-
const rounder = (callee, calleeObj, getArgs) => {
|
|
10960
|
+
const rounder = (state, callee, calleeObj, getArgs) => {
|
|
10882
10961
|
const results = {};
|
|
10883
10962
|
const fn = Math[callee.name];
|
|
10884
10963
|
results.effectFree = true;
|
|
@@ -10896,7 +10975,7 @@ function getSystemCallTable() {
|
|
|
10896
10975
|
: { type: 120 /* TypeTag.Numeric */ };
|
|
10897
10976
|
return results;
|
|
10898
10977
|
};
|
|
10899
|
-
const mathHelper = (callee, calleeObj, getArgs, helper) => {
|
|
10978
|
+
const mathHelper = (state, callee, calleeObj, getArgs, helper) => {
|
|
10900
10979
|
const results = {};
|
|
10901
10980
|
const fn = helper && typeof helper === "function"
|
|
10902
10981
|
? helper
|
|
@@ -10955,6 +11034,7 @@ function getSystemCallTable() {
|
|
|
10955
11034
|
"$.Toybox.Lang.Dictionary.toString": nop,
|
|
10956
11035
|
"$.Toybox.Lang.Dictionary.values": dictionaryValues,
|
|
10957
11036
|
"$.Toybox.Lang.Method.invoke": methodInvoke,
|
|
11037
|
+
"$.Toybox.Lang.Object.method": method,
|
|
10958
11038
|
"$.Toybox.Math.acos": mathHelper,
|
|
10959
11039
|
"$.Toybox.Math.asin": mathHelper,
|
|
10960
11040
|
"$.Toybox.Math.atan": mathHelper,
|
|
@@ -10962,15 +11042,15 @@ function getSystemCallTable() {
|
|
|
10962
11042
|
"$.Toybox.Math.ceil": rounder,
|
|
10963
11043
|
"$.Toybox.Math.cos": mathHelper,
|
|
10964
11044
|
"$.Toybox.Math.floor": rounder,
|
|
10965
|
-
"$.Toybox.Math.ln": (callee, calleeObj, getArgs) => mathHelper(callee, calleeObj, getArgs, "log"),
|
|
10966
|
-
"$.Toybox.Math.log": (callee, calleeObj, getArgs) => mathHelper(callee, calleeObj, getArgs, (x, base) => Math.log(x) / Math.log(base)),
|
|
11045
|
+
"$.Toybox.Math.ln": (state, callee, calleeObj, getArgs) => mathHelper(state, callee, calleeObj, getArgs, "log"),
|
|
11046
|
+
"$.Toybox.Math.log": (state, callee, calleeObj, getArgs) => mathHelper(state, callee, calleeObj, getArgs, (x, base) => Math.log(x) / Math.log(base)),
|
|
10967
11047
|
"$.Toybox.Math.pow": mathHelper,
|
|
10968
11048
|
"$.Toybox.Math.round": rounder,
|
|
10969
11049
|
"$.Toybox.Math.sin": mathHelper,
|
|
10970
11050
|
"$.Toybox.Math.sqrt": mathHelper,
|
|
10971
11051
|
"$.Toybox.Math.tan": mathHelper,
|
|
10972
|
-
"$.Toybox.Math.toDegrees": (callee, calleeObj, getArgs) => mathHelper(callee, calleeObj, getArgs, (arg) => (arg * 180) / Math.PI),
|
|
10973
|
-
"$.Toybox.Math.toRadians": (callee, calleeObj, getArgs) => mathHelper(callee, calleeObj, getArgs, (arg) => (arg * Math.PI) / 180),
|
|
11052
|
+
"$.Toybox.Math.toDegrees": (state, callee, calleeObj, getArgs) => mathHelper(state, callee, calleeObj, getArgs, (arg) => (arg * 180) / Math.PI),
|
|
11053
|
+
"$.Toybox.Math.toRadians": (state, callee, calleeObj, getArgs) => mathHelper(state, callee, calleeObj, getArgs, (arg) => (arg * Math.PI) / 180),
|
|
10974
11054
|
"$.Toybox.Math.mean": nop,
|
|
10975
11055
|
"$.Toybox.Math.mode": nop,
|
|
10976
11056
|
"$.Toybox.Math.stdev": nop,
|
|
@@ -11203,9 +11283,9 @@ function getLhsConstraint(istate, node) {
|
|
|
11203
11283
|
}
|
|
11204
11284
|
const object = istate.typeMap.get(node.object);
|
|
11205
11285
|
if (object && !node.computed) {
|
|
11206
|
-
const
|
|
11207
|
-
if (
|
|
11208
|
-
lookupDefs = (0,external_api_cjs_namespaceObject.lookupNext)(istate.state, [{ parent: null, results:
|
|
11286
|
+
const [, trueDecls] = findObjectDeclsByProperty(istate.state, object, node);
|
|
11287
|
+
if (trueDecls) {
|
|
11288
|
+
lookupDefs = (0,external_api_cjs_namespaceObject.lookupNext)(istate.state, [{ parent: null, results: trueDecls }], "decls", node.property);
|
|
11209
11289
|
}
|
|
11210
11290
|
}
|
|
11211
11291
|
}
|
|
@@ -12009,45 +12089,115 @@ function printBlockState(block, state, indent = "") {
|
|
|
12009
12089
|
console.log(`${indent} - ${typeStateEntry(value, key)}${value.equivSet ? " " + tsEquivs(state, key) : ""}`);
|
|
12010
12090
|
});
|
|
12011
12091
|
}
|
|
12012
|
-
|
|
12092
|
+
/*
|
|
12093
|
+
* We have an object, and a MemberExpression object.<name>
|
|
12094
|
+
* - decls are the StateNodes associated with the known type
|
|
12095
|
+
* of object.
|
|
12096
|
+
* - possible are all the StateNodes that declare <name>
|
|
12097
|
+
*
|
|
12098
|
+
* We want to find all the elements of possible which are
|
|
12099
|
+
* "compatible" with decls, which tells us the set of things
|
|
12100
|
+
* that object.<name> could correspond to, and also what that
|
|
12101
|
+
* tells us about object.
|
|
12102
|
+
*
|
|
12103
|
+
* The return value is two arrays of StateNode. The first
|
|
12104
|
+
* gives the refined type of object, and the second is the
|
|
12105
|
+
* array of StateNodes that could declare <name>
|
|
12106
|
+
*/
|
|
12107
|
+
function filterDecls(decls, possible, name) {
|
|
12013
12108
|
if (!possible)
|
|
12014
|
-
return null;
|
|
12015
|
-
|
|
12109
|
+
return [null, null];
|
|
12110
|
+
const result = decls.reduce((cur, decl) => {
|
|
12016
12111
|
const found = possible.reduce((flag, poss) => {
|
|
12017
12112
|
if (decl === poss ||
|
|
12018
|
-
(poss.type === "ClassDeclaration" &&
|
|
12019
|
-
|
|
12020
|
-
|
|
12021
|
-
|
|
12022
|
-
|
|
12023
|
-
|
|
12024
|
-
cur
|
|
12113
|
+
(poss.type === "ClassDeclaration" && (0,external_api_cjs_namespaceObject.getSuperClasses)(poss)?.has(decl))) {
|
|
12114
|
+
// poss extends decl, so decl must actually be a poss
|
|
12115
|
+
// eg we know obj is an Object, and we call obj.toNumber
|
|
12116
|
+
// so possible includes all the classes that declare toNumber
|
|
12117
|
+
// so we can refine obj's type to the union of those types
|
|
12118
|
+
if (!cur[0]) {
|
|
12119
|
+
cur = [new Set(), new Set()];
|
|
12120
|
+
}
|
|
12121
|
+
cur[0].add(poss);
|
|
12122
|
+
cur[1].add(poss);
|
|
12123
|
+
return true;
|
|
12124
|
+
}
|
|
12125
|
+
else if (decl.type === "ClassDeclaration" &&
|
|
12126
|
+
(0,external_api_cjs_namespaceObject.getSuperClasses)(decl)?.has(poss)) {
|
|
12127
|
+
// decl extends poss, so decl remains unchanged
|
|
12128
|
+
// eg we know obj is Menu2, we call obj.toString
|
|
12129
|
+
// Menu2 doesn't define toString, but Object does
|
|
12130
|
+
// so poss is Object. But we still know that
|
|
12131
|
+
// obj is Menu2
|
|
12132
|
+
if (!cur[0]) {
|
|
12133
|
+
cur = [new Set(), new Set()];
|
|
12134
|
+
}
|
|
12135
|
+
cur[0].add(decl);
|
|
12136
|
+
cur[1].add(poss);
|
|
12025
12137
|
return true;
|
|
12026
12138
|
}
|
|
12027
12139
|
return flag;
|
|
12028
12140
|
}, false);
|
|
12029
12141
|
if (!found) {
|
|
12030
|
-
|
|
12031
|
-
|
|
12032
|
-
|
|
12033
|
-
|
|
12034
|
-
|
|
12035
|
-
|
|
12036
|
-
|
|
12037
|
-
|
|
12038
|
-
|
|
12039
|
-
|
|
12142
|
+
// If we didn't find the property in any of the
|
|
12143
|
+
// standard places, the runtime might still find
|
|
12144
|
+
// it by searching up the Module stack (and up
|
|
12145
|
+
// the module stack from any super classes)
|
|
12146
|
+
//
|
|
12147
|
+
// eg
|
|
12148
|
+
//
|
|
12149
|
+
// obj = Application.getApp();
|
|
12150
|
+
// obj.Properties.whatever
|
|
12151
|
+
//
|
|
12152
|
+
// Properties doesn't exist on AppBase, but AppBase
|
|
12153
|
+
// is declared in Application, and Application
|
|
12154
|
+
// does declare Properties. So Application.Properties
|
|
12155
|
+
// is (one of) the declarations we should find; but we
|
|
12156
|
+
// must not refine obj's type to include Application.
|
|
12157
|
+
let d = [decl];
|
|
12158
|
+
do {
|
|
12159
|
+
d.forEach((d) => {
|
|
12160
|
+
const stack = d.stack;
|
|
12161
|
+
possible.forEach((poss) => {
|
|
12162
|
+
for (let i = stack.length; i--;) {
|
|
12163
|
+
const sn = stack[i];
|
|
12164
|
+
if (sn.decls === poss.decls) {
|
|
12165
|
+
if (!cur[0]) {
|
|
12166
|
+
cur = [new Set(), new Set()];
|
|
12167
|
+
}
|
|
12168
|
+
cur[0].add(decl);
|
|
12169
|
+
cur[1].add(poss);
|
|
12170
|
+
break;
|
|
12171
|
+
}
|
|
12172
|
+
if ((0,external_api_cjs_namespaceObject.hasProperty)(sn.decls, name)) {
|
|
12173
|
+
break;
|
|
12174
|
+
}
|
|
12175
|
+
}
|
|
12176
|
+
});
|
|
12177
|
+
});
|
|
12178
|
+
d = d.flatMap((d) => {
|
|
12179
|
+
if (d.type !== "ClassDeclaration" ||
|
|
12180
|
+
!d.superClass ||
|
|
12181
|
+
d.superClass === true) {
|
|
12182
|
+
return [];
|
|
12183
|
+
}
|
|
12184
|
+
return d.superClass;
|
|
12185
|
+
});
|
|
12186
|
+
} while (d.length);
|
|
12040
12187
|
}
|
|
12041
12188
|
return cur;
|
|
12042
|
-
}, null);
|
|
12189
|
+
}, [null, null]);
|
|
12190
|
+
if (!result[0])
|
|
12191
|
+
return [null, null];
|
|
12192
|
+
return [Array.from(result[0]), Array.from(result[1])];
|
|
12043
12193
|
}
|
|
12044
12194
|
function findObjectDeclsByProperty(state, object, next) {
|
|
12045
12195
|
const decls = getStateNodeDeclsFromType(state, object);
|
|
12046
12196
|
if (!decls)
|
|
12047
|
-
return null;
|
|
12197
|
+
return [null, null];
|
|
12048
12198
|
const possibleDecls = (0,external_api_cjs_namespaceObject.hasProperty)(state.allDeclarations, next.property.name) &&
|
|
12049
12199
|
state.allDeclarations[next.property.name];
|
|
12050
|
-
return filterDecls(decls, possibleDecls);
|
|
12200
|
+
return filterDecls(decls, possibleDecls, next.property.name);
|
|
12051
12201
|
}
|
|
12052
12202
|
function refineObjectTypeByDecls(istate, object, trueDecls) {
|
|
12053
12203
|
const refinedType = typeFromTypeStateNodes(istate.state, trueDecls);
|
|
@@ -12063,13 +12213,13 @@ function findNextObjectType(istate, trueDecls, next) {
|
|
|
12063
12213
|
}, { type: 0 /* TypeTag.Never */ });
|
|
12064
12214
|
}
|
|
12065
12215
|
function resolveDottedMember(istate, object, next) {
|
|
12066
|
-
const
|
|
12067
|
-
if (!
|
|
12216
|
+
const [objDecls, trueDecls] = findObjectDeclsByProperty(istate.state, object, next);
|
|
12217
|
+
if (!objDecls)
|
|
12068
12218
|
return null;
|
|
12069
|
-
const property = findNextObjectType(istate,
|
|
12219
|
+
const property = findNextObjectType(istate, trueDecls, next);
|
|
12070
12220
|
if (!property)
|
|
12071
12221
|
return null;
|
|
12072
|
-
const type = refineObjectTypeByDecls(istate, object,
|
|
12222
|
+
const type = refineObjectTypeByDecls(istate, object, objDecls);
|
|
12073
12223
|
const mayThrow = !subtypeOf(object, type);
|
|
12074
12224
|
return { mayThrow, object: type, property };
|
|
12075
12225
|
}
|
|
@@ -12106,11 +12256,11 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
|
|
|
12106
12256
|
next = value.obj[me.property.name];
|
|
12107
12257
|
}
|
|
12108
12258
|
else {
|
|
12109
|
-
const trueDecls = findObjectDeclsByProperty(istate.state, cur, me);
|
|
12110
|
-
if (!
|
|
12259
|
+
const [objDecls, trueDecls] = findObjectDeclsByProperty(istate.state, cur, me);
|
|
12260
|
+
if (!objDecls) {
|
|
12111
12261
|
return null;
|
|
12112
12262
|
}
|
|
12113
|
-
cur = refineObjectTypeByDecls(istate, cur,
|
|
12263
|
+
cur = refineObjectTypeByDecls(istate, cur, objDecls);
|
|
12114
12264
|
next = findNextObjectType(istate, trueDecls, me);
|
|
12115
12265
|
}
|
|
12116
12266
|
}
|
|
@@ -12297,7 +12447,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
|
|
|
12297
12447
|
const info = sysCallInfo(callee);
|
|
12298
12448
|
if (!info)
|
|
12299
12449
|
return false;
|
|
12300
|
-
const result = info(callee, calleeObj, () => node.arguments.map((arg) => evaluateExpr(state, arg, typeMap).value));
|
|
12450
|
+
const result = info(istate.state, callee, calleeObj, () => node.arguments.map((arg) => evaluateExpr(state, arg, typeMap).value));
|
|
12301
12451
|
if (result.calleeObj) {
|
|
12302
12452
|
setStateEvent(curState, calleeObjDecl, result.calleeObj, false);
|
|
12303
12453
|
}
|
|
@@ -15231,7 +15381,7 @@ async function generateOneConfig(buildConfig, manifestXML, dependencyFiles, conf
|
|
|
15231
15381
|
// the oldest optimized file, we don't need to regenerate
|
|
15232
15382
|
const source_time = await (0,external_util_cjs_namespaceObject.last_modified)(Object.keys(fnMap).concat(dependencyFiles));
|
|
15233
15383
|
const opt_time = await (0,external_util_cjs_namespaceObject.first_modified)(Object.values(fnMap).map((v) => v.output));
|
|
15234
|
-
if (source_time < opt_time &&
|
|
15384
|
+
if (source_time < opt_time && 1674707539512 < opt_time) {
|
|
15235
15385
|
return { hasTests, diagnostics: prevDiagnostics };
|
|
15236
15386
|
}
|
|
15237
15387
|
}
|
|
@@ -15258,7 +15408,7 @@ async function generateOneConfig(buildConfig, manifestXML, dependencyFiles, conf
|
|
|
15258
15408
|
return promises_namespaceObject.writeFile(external_path_.join(output, "build-info.json"), JSON.stringify({
|
|
15259
15409
|
hasTests,
|
|
15260
15410
|
diagnostics,
|
|
15261
|
-
optimizerVersion: "1.1.
|
|
15411
|
+
optimizerVersion: "1.1.6",
|
|
15262
15412
|
...Object.fromEntries(configOptionsToCheck.map((option) => [option, config[option]])),
|
|
15263
15413
|
}))
|
|
15264
15414
|
.then(() => ({ hasTests, diagnostics }));
|
|
@@ -129,6 +129,7 @@ export interface VariableStateNode extends BaseStateNode {
|
|
|
129
129
|
fullName: string;
|
|
130
130
|
stack: ProgramStateStack;
|
|
131
131
|
used?: true;
|
|
132
|
+
resolvedType?: ExactOrUnion | undefined;
|
|
132
133
|
}
|
|
133
134
|
export interface EnumStateNode extends BaseStateNode {
|
|
134
135
|
type: "EnumDeclaration";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { mctree } from "@markw65/prettier-plugin-monkeyc";
|
|
2
|
-
import { FunctionStateNode } from "
|
|
2
|
+
import { FunctionStateNode, ProgramStateAnalysis } from "../optimizer-types";
|
|
3
3
|
import { InterpStackElem, InterpState } from "./interp";
|
|
4
4
|
import { ExactOrUnion } from "./types";
|
|
5
5
|
export declare function evaluateCall(istate: InterpState, node: mctree.CallExpression, callee: ExactOrUnion, args: ExactOrUnion[]): InterpStackElem;
|
|
@@ -11,6 +11,6 @@ declare type SysCallHelperResult = {
|
|
|
11
11
|
effectFree?: true;
|
|
12
12
|
argEffects?: true;
|
|
13
13
|
};
|
|
14
|
-
declare type SysCallHelper = (func: FunctionStateNode, calleeObj: ExactOrUnion, getArgs: () => Array<ExactOrUnion>) => SysCallHelperResult;
|
|
14
|
+
declare type SysCallHelper = (state: ProgramStateAnalysis, func: FunctionStateNode, calleeObj: ExactOrUnion, getArgs: () => Array<ExactOrUnion>) => SysCallHelperResult;
|
|
15
15
|
export declare function sysCallInfo(func: FunctionStateNode): SysCallHelper | null;
|
|
16
16
|
export {};
|
package/build/src/type-flow.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { InterpState } from "./type-flow/interp";
|
|
|
4
4
|
import { ExactOrUnion } from "./type-flow/types";
|
|
5
5
|
export declare const missingNullWorkaround = true;
|
|
6
6
|
export declare function buildTypeInfo(state: ProgramStateAnalysis, func: FunctionStateNode, optimizeEquivalencies: boolean): InterpState | undefined;
|
|
7
|
-
export declare function findObjectDeclsByProperty(state: ProgramStateAnalysis, object: ExactOrUnion, next: mctree.DottedMemberExpression): StateNode[] | null;
|
|
7
|
+
export declare function findObjectDeclsByProperty(state: ProgramStateAnalysis, object: ExactOrUnion, next: mctree.DottedMemberExpression): [StateNode[], StateNode[]] | readonly [null, null];
|
|
8
8
|
export declare function resolveDottedMember(istate: InterpState, object: ExactOrUnion, next: mctree.DottedMemberExpression): {
|
|
9
9
|
mayThrow: boolean;
|
|
10
10
|
object: ExactOrUnion;
|
package/package.json
CHANGED