Merge with local implementation of toStringTag
This commit is contained in:
commit
1cbd2e8a23
12 changed files with 499 additions and 339 deletions
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -1,3 +1,11 @@
|
||||||
|
|
||||||
|
# populated by npm
|
||||||
node_modules/
|
node_modules/
|
||||||
|
|
||||||
|
# compiled TypeScript code from src/
|
||||||
/lib/
|
/lib/
|
||||||
|
|
||||||
|
# local development helpers
|
||||||
Makefile
|
Makefile
|
||||||
|
/*.bolt
|
||||||
|
/*.c
|
||||||
|
|
19
.vscode/launch.json
vendored
Normal file
19
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Launch Program",
|
||||||
|
"skipFiles": [
|
||||||
|
"<node_internals>/**"
|
||||||
|
],
|
||||||
|
"program": "${workspaceFolder}/lib/bin/bolt.js",
|
||||||
|
"args": [ "test.bolt" ],
|
||||||
|
"outputCapture": "std"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ Bolt
|
||||||
|
|
||||||
💬 Got some questions or feedback? Just open an issue and we'll be glad to respond!
|
💬 Got some questions or feedback? Just open an issue and we'll be glad to respond!
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Bolt is a new strictly-evaluated functional programming language in the making
|
Bolt is a new strictly-evaluated functional programming language in the making
|
||||||
that aims to make writing complex applications dead-simple. It ships with some
|
that aims to make writing complex applications dead-simple. It ships with some
|
||||||
|
|
229
package-lock.json
generated
229
package-lock.json
generated
|
@ -9,36 +9,36 @@
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"commander": "^9.4.0",
|
"commander": "^10.0.0",
|
||||||
"source-map-support": "^0.5.21",
|
"source-map-support": "^0.5.21",
|
||||||
"tslib": "^2.4.0",
|
"tslib": "^2.5.0",
|
||||||
"yagl": "^0.5.1"
|
"yagl": "^0.5.1"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"bolt": "lib/bin/bolt.js"
|
"bolt": "lib/bin/bolt.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/commonmark": "^0.27.5",
|
"@types/commonmark": "^0.27.6",
|
||||||
"@types/glob": "^8.0.0",
|
"@types/glob": "^8.1.0",
|
||||||
"@types/node": "^18.7.15",
|
"@types/node": "^18.15.11",
|
||||||
"@types/yargs": "^17.0.12",
|
"@types/yargs": "^17.0.24",
|
||||||
"commonmark": "^0.30.0",
|
"commonmark": "^0.30.0",
|
||||||
"glob": "^8.0.3"
|
"glob": "^10.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/commonmark": {
|
"node_modules/@types/commonmark": {
|
||||||
"version": "0.27.5",
|
"version": "0.27.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/commonmark/-/commonmark-0.27.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/commonmark/-/commonmark-0.27.6.tgz",
|
||||||
"integrity": "sha512-vIqgmHyLsc8Or3EWLz6QkhI8/v61FNeH0yxRupA7VqSbA2eFMoHHJAhZSHudplAV89wqg1CKSmShE016ziRXuw==",
|
"integrity": "sha512-t3S2hOtSSuBp1H5PTFmekGFu9U9LBzGvHy93zHwusvj4RIGUrBQ4zHvw49CkJtAl6fZvsadKhYbv8WTxJLbBmw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/glob": {
|
"node_modules/@types/glob": {
|
||||||
"version": "8.0.0",
|
"version": "8.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz",
|
||||||
"integrity": "sha512-l6NQsDDyQUVeoTynNpC9uRvCUint/gSUXQA2euwmTuWGvPY5LSDUu6tkCtJB2SvGQlJQzLaKqcGZP4//7EDveA==",
|
"integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/minimatch": "*",
|
"@types/minimatch": "^5.1.2",
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -49,15 +49,15 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "18.7.15",
|
"version": "18.15.11",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.15.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz",
|
||||||
"integrity": "sha512-XnjpaI8Bgc3eBag2Aw4t2Uj/49lLBSStHWfqKvIuXD7FIrZyMLWp8KuAFHAqxMZYTF9l08N1ctUn9YNybZJVmQ==",
|
"integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/yargs": {
|
"node_modules/@types/yargs": {
|
||||||
"version": "17.0.12",
|
"version": "17.0.24",
|
||||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.12.tgz",
|
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz",
|
||||||
"integrity": "sha512-Nz4MPhecOFArtm81gFQvQqdV7XYCrWKx5uUt6GNHredFHn1i2mtWqXTON7EPXMtNi1qjtjEM/VCHDhcHsAMLXQ==",
|
"integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/yargs-parser": "*"
|
"@types/yargs-parser": "*"
|
||||||
|
@ -90,11 +90,11 @@
|
||||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
|
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
|
||||||
},
|
},
|
||||||
"node_modules/commander": {
|
"node_modules/commander": {
|
||||||
"version": "9.4.0",
|
"version": "10.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-9.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.0.tgz",
|
||||||
"integrity": "sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw==",
|
"integrity": "sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.20.0 || >=14"
|
"node": ">=14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/commonmark": {
|
"node_modules/commonmark": {
|
||||||
|
@ -128,40 +128,32 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/glob": {
|
"node_modules/glob": {
|
||||||
"version": "8.0.3",
|
"version": "10.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-10.0.0.tgz",
|
||||||
"integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==",
|
"integrity": "sha512-zmp9ZDC6NpDNLujV2W2n+3lH+BafIVZ4/ct+Yj3BMZTH/+bgm/eVjHzeFLwxJrrIGgjjS2eiQLlpurHsNlEAtQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fs.realpath": "^1.0.0",
|
"fs.realpath": "^1.0.0",
|
||||||
"inflight": "^1.0.4",
|
"minimatch": "^9.0.0",
|
||||||
"inherits": "2",
|
"minipass": "^5.0.0",
|
||||||
"minimatch": "^5.0.1",
|
"path-scurry": "^1.6.4"
|
||||||
"once": "^1.3.0"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=16 || 14 >=14.17"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/inflight": {
|
"node_modules/lru-cache": {
|
||||||
"version": "1.0.6",
|
"version": "9.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.0.1.tgz",
|
||||||
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
|
"integrity": "sha512-C8QsKIN1UIXeOs3iWmiZ1lQY+EnKDojWd37fXy1aSbJvH4iSma1uy2OWuoB3m4SYRli5+CUjDv3Dij5DVoetmg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"engines": {
|
||||||
"once": "^1.3.0",
|
"node": "14 || >=16.14"
|
||||||
"wrappy": "1"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/inherits": {
|
|
||||||
"version": "2.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
|
||||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/mdurl": {
|
"node_modules/mdurl": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
|
||||||
|
@ -169,15 +161,18 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/minimatch": {
|
"node_modules/minimatch": {
|
||||||
"version": "5.1.0",
|
"version": "9.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz",
|
||||||
"integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==",
|
"integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"brace-expansion": "^2.0.1"
|
"brace-expansion": "^2.0.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=16 || 14 >=14.17"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/minimist": {
|
"node_modules/minimist": {
|
||||||
|
@ -186,13 +181,29 @@
|
||||||
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
|
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/once": {
|
"node_modules/minipass": {
|
||||||
"version": "1.4.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
|
||||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
"integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/path-scurry": {
|
||||||
|
"version": "1.6.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.6.4.tgz",
|
||||||
|
"integrity": "sha512-Qp/9IHkdNiXJ3/Kon++At2nVpnhRiPq/aSvQN+H3U1WZbvNRK0RIQK/o4HMqPoXjpuGJUEWpHSs6Mnjxqh3TQg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"wrappy": "1"
|
"lru-cache": "^9.0.0",
|
||||||
|
"minipass": "^5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16 || 14 >=14.17"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/source-map": {
|
"node_modules/source-map": {
|
||||||
|
@ -219,15 +230,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/tslib": {
|
"node_modules/tslib": {
|
||||||
"version": "2.4.0",
|
"version": "2.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
|
||||||
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
|
"integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
|
||||||
},
|
|
||||||
"node_modules/wrappy": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
|
||||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/yagl": {
|
"node_modules/yagl": {
|
||||||
"version": "0.5.1",
|
"version": "0.5.1",
|
||||||
|
@ -237,18 +242,18 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/commonmark": {
|
"@types/commonmark": {
|
||||||
"version": "0.27.5",
|
"version": "0.27.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/commonmark/-/commonmark-0.27.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/commonmark/-/commonmark-0.27.6.tgz",
|
||||||
"integrity": "sha512-vIqgmHyLsc8Or3EWLz6QkhI8/v61FNeH0yxRupA7VqSbA2eFMoHHJAhZSHudplAV89wqg1CKSmShE016ziRXuw==",
|
"integrity": "sha512-t3S2hOtSSuBp1H5PTFmekGFu9U9LBzGvHy93zHwusvj4RIGUrBQ4zHvw49CkJtAl6fZvsadKhYbv8WTxJLbBmw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/glob": {
|
"@types/glob": {
|
||||||
"version": "8.0.0",
|
"version": "8.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz",
|
||||||
"integrity": "sha512-l6NQsDDyQUVeoTynNpC9uRvCUint/gSUXQA2euwmTuWGvPY5LSDUu6tkCtJB2SvGQlJQzLaKqcGZP4//7EDveA==",
|
"integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/minimatch": "*",
|
"@types/minimatch": "^5.1.2",
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -259,15 +264,15 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "18.7.15",
|
"version": "18.15.11",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.15.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz",
|
||||||
"integrity": "sha512-XnjpaI8Bgc3eBag2Aw4t2Uj/49lLBSStHWfqKvIuXD7FIrZyMLWp8KuAFHAqxMZYTF9l08N1ctUn9YNybZJVmQ==",
|
"integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/yargs": {
|
"@types/yargs": {
|
||||||
"version": "17.0.12",
|
"version": "17.0.24",
|
||||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.12.tgz",
|
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz",
|
||||||
"integrity": "sha512-Nz4MPhecOFArtm81gFQvQqdV7XYCrWKx5uUt6GNHredFHn1i2mtWqXTON7EPXMtNi1qjtjEM/VCHDhcHsAMLXQ==",
|
"integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/yargs-parser": "*"
|
"@types/yargs-parser": "*"
|
||||||
|
@ -300,9 +305,9 @@
|
||||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
|
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
|
||||||
},
|
},
|
||||||
"commander": {
|
"commander": {
|
||||||
"version": "9.4.0",
|
"version": "10.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-9.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.0.tgz",
|
||||||
"integrity": "sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw=="
|
"integrity": "sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA=="
|
||||||
},
|
},
|
||||||
"commonmark": {
|
"commonmark": {
|
||||||
"version": "0.30.0",
|
"version": "0.30.0",
|
||||||
|
@ -329,32 +334,21 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"glob": {
|
"glob": {
|
||||||
"version": "8.0.3",
|
"version": "10.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-10.0.0.tgz",
|
||||||
"integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==",
|
"integrity": "sha512-zmp9ZDC6NpDNLujV2W2n+3lH+BafIVZ4/ct+Yj3BMZTH/+bgm/eVjHzeFLwxJrrIGgjjS2eiQLlpurHsNlEAtQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"fs.realpath": "^1.0.0",
|
"fs.realpath": "^1.0.0",
|
||||||
"inflight": "^1.0.4",
|
"minimatch": "^9.0.0",
|
||||||
"inherits": "2",
|
"minipass": "^5.0.0",
|
||||||
"minimatch": "^5.0.1",
|
"path-scurry": "^1.6.4"
|
||||||
"once": "^1.3.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"inflight": {
|
"lru-cache": {
|
||||||
"version": "1.0.6",
|
"version": "9.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.0.1.tgz",
|
||||||
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
|
"integrity": "sha512-C8QsKIN1UIXeOs3iWmiZ1lQY+EnKDojWd37fXy1aSbJvH4iSma1uy2OWuoB3m4SYRli5+CUjDv3Dij5DVoetmg==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"once": "^1.3.0",
|
|
||||||
"wrappy": "1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"inherits": {
|
|
||||||
"version": "2.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
|
||||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"mdurl": {
|
"mdurl": {
|
||||||
|
@ -364,9 +358,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"minimatch": {
|
"minimatch": {
|
||||||
"version": "5.1.0",
|
"version": "9.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz",
|
||||||
"integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==",
|
"integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "^2.0.1"
|
"brace-expansion": "^2.0.1"
|
||||||
|
@ -378,13 +372,20 @@
|
||||||
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
|
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"once": {
|
"minipass": {
|
||||||
"version": "1.4.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
|
||||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
"integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"path-scurry": {
|
||||||
|
"version": "1.6.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.6.4.tgz",
|
||||||
|
"integrity": "sha512-Qp/9IHkdNiXJ3/Kon++At2nVpnhRiPq/aSvQN+H3U1WZbvNRK0RIQK/o4HMqPoXjpuGJUEWpHSs6Mnjxqh3TQg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"wrappy": "1"
|
"lru-cache": "^9.0.0",
|
||||||
|
"minipass": "^5.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"source-map": {
|
"source-map": {
|
||||||
|
@ -408,15 +409,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"tslib": {
|
"tslib": {
|
||||||
"version": "2.4.0",
|
"version": "2.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
|
||||||
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
|
"integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
|
||||||
},
|
|
||||||
"wrappy": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
|
||||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"yagl": {
|
"yagl": {
|
||||||
"version": "0.5.1",
|
"version": "0.5.1",
|
||||||
|
|
14
package.json
14
package.json
|
@ -22,17 +22,17 @@
|
||||||
"author": "Sam Vervaeck",
|
"author": "Sam Vervaeck",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"commander": "^9.4.0",
|
"commander": "^10.0.0",
|
||||||
"source-map-support": "^0.5.21",
|
"source-map-support": "^0.5.21",
|
||||||
"tslib": "^2.4.0",
|
"tslib": "^2.5.0",
|
||||||
"yagl": "^0.5.1"
|
"yagl": "^0.5.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/commonmark": "^0.27.5",
|
"@types/commonmark": "^0.27.6",
|
||||||
"@types/glob": "^8.0.0",
|
"@types/glob": "^8.1.0",
|
||||||
"@types/node": "^18.7.15",
|
"@types/node": "^18.15.11",
|
||||||
"@types/yargs": "^17.0.12",
|
"@types/yargs": "^17.0.24",
|
||||||
"commonmark": "^0.30.0",
|
"commonmark": "^0.30.0",
|
||||||
"glob": "^8.0.3"
|
"glob": "^10.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
496
src/checker.ts
496
src/checker.ts
|
@ -34,9 +34,9 @@ import {
|
||||||
TypeclassNotFoundDiagnostic,
|
TypeclassNotFoundDiagnostic,
|
||||||
TypeclassDeclaredTwiceDiagnostic,
|
TypeclassDeclaredTwiceDiagnostic,
|
||||||
} from "./diagnostics";
|
} from "./diagnostics";
|
||||||
import { assert, isDebug, assertNever, first, isEmpty, last, MultiMap, customInspectSymbol, InspectFn } from "./util";
|
import { assert, assertNever, first, isEmpty, last, MultiMap, toStringTag, InspectFn } from "./util";
|
||||||
import { Analyser } from "./analysis";
|
import { Analyser } from "./analysis";
|
||||||
import { CustomInspectFunction, inspect, InspectOptions } from "util";
|
import { InspectOptions } from "util";
|
||||||
|
|
||||||
const MAX_TYPE_ERROR_COUNT = 5;
|
const MAX_TYPE_ERROR_COUNT = 5;
|
||||||
|
|
||||||
|
@ -86,9 +86,7 @@ abstract class TypeBase {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public [customInspectSymbol](depth: number, options: InspectOptions, inspect: InspectFn): string {
|
public abstract [toStringTag](depth: number, options: InspectOptions, inspect: InspectFn): string;
|
||||||
return describeType(this as any);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +117,7 @@ class TVar extends TypeBase {
|
||||||
? this : other.substitute(sub);
|
? this : other.substitute(sub);
|
||||||
}
|
}
|
||||||
|
|
||||||
public [customInspectSymbol](depth: number, options: InspectOptions, inspect: InspectFn): string {
|
public [toStringTag]() {
|
||||||
return 'a' + this.id;
|
return 'a' + this.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,8 +139,8 @@ export class TNil extends TypeBase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public [customInspectSymbol](depth: number, options: InspectOptions, inspect: InspectFn): string {
|
public [toStringTag]() {
|
||||||
return '{}'
|
return '∂Abs';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -163,7 +161,7 @@ export class TAbsent extends TypeBase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public [customInspectSymbol](depth: number, options: InspectOptions, inspect: InspectFn): string {
|
public [toStringTag]() {
|
||||||
return 'Abs';
|
return 'Abs';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,8 +190,8 @@ export class TPresent extends TypeBase {
|
||||||
return new TPresent(this.type, this.node);
|
return new TPresent(this.type, this.node);
|
||||||
}
|
}
|
||||||
|
|
||||||
public [customInspectSymbol](depth: number, options: InspectOptions, inspect: InspectFn): string {
|
public [toStringTag](_depth: number, options: InspectOptions, inspect: InspectFn) {
|
||||||
return inspect(this.type);
|
return 'Pre ' + inspect(this.type, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -244,8 +242,8 @@ export class TArrow extends TypeBase {
|
||||||
return changed ? new TArrow(newParamType, newReturnType, this.node) : this;
|
return changed ? new TArrow(newParamType, newReturnType, this.node) : this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public [customInspectSymbol](depth: number, options: InspectOptions, inspect: InspectFn): string {
|
public [toStringTag](_depth: number, options: InspectOptions, inspect: InspectFn) {
|
||||||
return inspect(this.paramType) + ' -> ' + inspect(this.returnType);
|
return inspect(this.paramType, options) + ' -> ' + inspect(this.returnType, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -291,12 +289,8 @@ export class TCon extends TypeBase {
|
||||||
return changed ? new TCon(this.id, newArgTypes, this.displayName, this.node) : this;
|
return changed ? new TCon(this.id, newArgTypes, this.displayName, this.node) : this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public [customInspectSymbol](depth: number, options: InspectOptions, inspect: InspectFn): string {
|
public [toStringTag](_depth: number, options: InspectOptions, inspect: InspectFn) {
|
||||||
let out = this.displayName;
|
return this.displayName + ' ' + this.argTypes.map(t => inspect(t, options)).join(' ');
|
||||||
for (const argType of this.argTypes) {
|
|
||||||
out += ' ' + inspect(argType);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -338,15 +332,8 @@ class TTuple extends TypeBase {
|
||||||
return changed ? new TTuple(newElementTypes, this.node) : this;
|
return changed ? new TTuple(newElementTypes, this.node) : this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public [customInspectSymbol](depth: number, options: InspectOptions, inspect: InspectFn): string {
|
public [toStringTag](_depth: number, options: InspectOptions, inspect: InspectFn) {
|
||||||
let out = '(';
|
return this.elementTypes.map(t => inspect(t, options)).join(' × ');
|
||||||
let first = true;
|
|
||||||
for (const elementType of this.elementTypes) {
|
|
||||||
if (first) first = false;
|
|
||||||
else out += ', ';
|
|
||||||
out += inspect(elementType);
|
|
||||||
}
|
|
||||||
return out + ')';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -399,15 +386,15 @@ export class TField extends TypeBase {
|
||||||
? new TField(this.name, newType, newRestType, this.node) : this;
|
? new TField(this.name, newType, newRestType, this.node) : this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public [customInspectSymbol](depth: number, options: InspectOptions, inspect: InspectFn): string {
|
public [toStringTag](_depth: number, options: InspectOptions, inspect: InspectFn) {
|
||||||
let out = '{ ' + this.name + ': ' + inspect(this.type);
|
let out = '{ ' + this.name + ': ' + inspect(this.type, options);
|
||||||
let type = this.restType;
|
let type = this.restType;
|
||||||
while (type.kind === TypeKind.Field) {
|
while (type.kind === TypeKind.Field) {
|
||||||
out += '; ' + type.name + ': ' + inspect(type.type);
|
out += '; ' + type.name + ': ' + inspect(type.type, options);
|
||||||
type = type.restType;
|
type = type.restType;
|
||||||
}
|
}
|
||||||
if (type.kind !== TypeKind.Nil) {
|
if (type.kind !== TypeKind.Nil) {
|
||||||
out += '; ' + inspect(type);
|
out += '; ' + inspect(type, options);
|
||||||
}
|
}
|
||||||
return out + ' }'
|
return out + ' }'
|
||||||
}
|
}
|
||||||
|
@ -459,8 +446,8 @@ export class TApp extends TypeBase {
|
||||||
return changed ? new TApp(newOperatorType, newArgType, this.node) : this;
|
return changed ? new TApp(newOperatorType, newArgType, this.node) : this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public [customInspectSymbol](depth: number, options: InspectOptions, inspect: InspectFn): string {
|
public [toStringTag](_depth: number, options: InspectOptions, inspect: InspectFn) {
|
||||||
return inspect(this.left) + ' ' + inspect(this.right);
|
return inspect(this.left, options) + ' ' + inspect(this.right, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -491,7 +478,7 @@ export class TNominal extends TypeBase {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public [customInspectSymbol](depth: number, options: InspectOptions, inspect: InspectFn): string {
|
public [toStringTag]() {
|
||||||
return this.decl.name.text;
|
return this.decl.name.text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -701,6 +688,17 @@ class TVSet {
|
||||||
return this.mapping.values();
|
return this.mapping.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public [toStringTag](_depth: number, options: InspectOptions, inspect: InspectFn) {
|
||||||
|
let out = '{ ';
|
||||||
|
let first = true;
|
||||||
|
for (const tv of this) {
|
||||||
|
if (first) first = false;
|
||||||
|
else out += ', ';
|
||||||
|
out += inspect(tv, options);
|
||||||
|
}
|
||||||
|
return out + ' }';
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class TVSub {
|
class TVSub {
|
||||||
|
@ -732,14 +730,11 @@ class TVSub {
|
||||||
const enum ConstraintKind {
|
const enum ConstraintKind {
|
||||||
Equal,
|
Equal,
|
||||||
Many,
|
Many,
|
||||||
Shaped,
|
Empty,
|
||||||
Class,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class ConstraintBase {
|
abstract class ConstraintBase {
|
||||||
|
|
||||||
public abstract substitute(sub: TVSub): Constraint;
|
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
public node: Syntax | null = null
|
public node: Syntax | null = null
|
||||||
) {
|
) {
|
||||||
|
@ -766,6 +761,10 @@ abstract class ConstraintBase {
|
||||||
return first(this.getNodes()[Symbol.iterator]()) ?? null;
|
return first(this.getNodes()[Symbol.iterator]()) ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract freeTypeVars(): Iterable<TVar>;
|
||||||
|
|
||||||
|
public abstract substitute(sub: TVSub, node: Syntax | null): Constraint;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class CEqual extends ConstraintBase {
|
class CEqual extends ConstraintBase {
|
||||||
|
@ -775,21 +774,26 @@ class CEqual extends ConstraintBase {
|
||||||
public constructor(
|
public constructor(
|
||||||
public left: Type,
|
public left: Type,
|
||||||
public right: Type,
|
public right: Type,
|
||||||
public node: Syntax,
|
public node: Syntax | null,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public substitute(sub: TVSub): Constraint {
|
public substitute(sub: TVSub, node: Syntax | null = null): CEqual {
|
||||||
return new CEqual(
|
return new CEqual(
|
||||||
this.left.substitute(sub),
|
this.left.substitute(sub),
|
||||||
this.right.substitute(sub),
|
this.right.substitute(sub),
|
||||||
this.node,
|
node,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public [customInspectSymbol](depth: number, options: InspectOptions, inspect: InspectFn): string {
|
public *freeTypeVars(): Iterable<TVar> {
|
||||||
return `${inspect(this.left)} ~ ${inspect(this.right)}`;
|
yield* this.left.getTypeVars();
|
||||||
|
yield* this.right.getTypeVars();
|
||||||
|
}
|
||||||
|
|
||||||
|
public [toStringTag](_currentDepth: number, options: InspectOptions, inspect: InspectFn): string {
|
||||||
|
return inspect(this.left, options) + ' ~ ' + inspect(this.right, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -804,16 +808,47 @@ class CMany extends ConstraintBase {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public substitute(sub: TVSub): Constraint {
|
public substitute(sub: TVSub, node: Syntax | null = null): CMany {
|
||||||
const newElements = [];
|
const newElements = [];
|
||||||
for (const element of this.elements) {
|
for (const element of this.elements) {
|
||||||
newElements.push(element.substitute(sub));
|
newElements.push(element.substitute(sub, node));
|
||||||
}
|
}
|
||||||
return new CMany(newElements);
|
return new CMany(newElements);
|
||||||
}
|
}
|
||||||
|
|
||||||
public [customInspectSymbol](depth: number, options: InspectOptions, inspect: InspectFn): string {
|
public *freeTypeVars(): Iterable<TVar> {
|
||||||
return this.elements.map(el => inspect(el)).join('\n');
|
for (const element of this.elements) {
|
||||||
|
yield* element.freeTypeVars();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public [toStringTag](currentDepth: number, { depth = 2, ...options }: InspectOptions, inspect: InspectFn): string {
|
||||||
|
if (this.elements.length === 0) {
|
||||||
|
return '[]';
|
||||||
|
}
|
||||||
|
let out = '[\n';
|
||||||
|
const newOptions = { ...options, depth: depth === null ? null : depth - 1 };
|
||||||
|
out += this.elements.map(constraint => ' ' + inspect(constraint, newOptions)).join('\n');
|
||||||
|
out += '\n]';
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class CEmpty extends ConstraintBase {
|
||||||
|
|
||||||
|
public readonly kind = ConstraintKind.Empty;
|
||||||
|
|
||||||
|
public substitute(_sub: TVSub, _node: Syntax | null = null): Constraint {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public *freeTypeVars(): Iterable<TVar> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public [toStringTag]() {
|
||||||
|
return 'ε';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -821,6 +856,7 @@ class CMany extends ConstraintBase {
|
||||||
type Constraint
|
type Constraint
|
||||||
= CEqual
|
= CEqual
|
||||||
| CMany
|
| CMany
|
||||||
|
| CEmpty
|
||||||
|
|
||||||
class ConstraintSet extends Array<Constraint> {
|
class ConstraintSet extends Array<Constraint> {
|
||||||
}
|
}
|
||||||
|
@ -830,32 +866,44 @@ abstract class SchemeBase {
|
||||||
|
|
||||||
class Forall extends SchemeBase {
|
class Forall extends SchemeBase {
|
||||||
|
|
||||||
public typeVars: TVSet;
|
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
typeVars: Iterable<TVar>,
|
public typeVars: TVSet,
|
||||||
public constraints: Iterable<Constraint>,
|
public constraint: Constraint,
|
||||||
public type: Type,
|
public type: Type,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.typeVars = new TVSet();
|
}
|
||||||
const allowed = new TVSet(type.getTypeVars());
|
|
||||||
for (const tv of typeVars) {
|
public *freeTypeVars(): Iterable<TVar> {
|
||||||
if (allowed.has(tv)) {
|
for (const tv of this.constraint.freeTypeVars()) {
|
||||||
this.typeVars.add(tv);
|
if (!this.typeVars.has(tv)) {
|
||||||
|
yield tv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const tv of this.type.getTypeVars()) {
|
||||||
|
if (!this.typeVars.has(tv)) {
|
||||||
|
yield tv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected [customInspectSymbol](depth: number, inspectOptions: InspectOptions, inspect: InspectFn): string {
|
protected [toStringTag](_depth: number, options: InspectOptions, inspect: InspectFn): string {
|
||||||
let out = 'forall';
|
let out = 'forall';
|
||||||
if (this.typeVars.size > 0) {
|
if (this.typeVars.size > 0) {
|
||||||
out += ' ' + [...this.typeVars].map(tv => inspect(tv)).join(' ');
|
out += ' ' + [...this.typeVars].map(tv => inspect(tv, options)).join(' ');
|
||||||
}
|
}
|
||||||
out += '. ' + inspect(this.type);
|
out += '. ' + inspect(this.type, options);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static mono(type: Type): Forall {
|
||||||
|
return new Forall(new TVSet, new CEmpty, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static fromArrays(typeVars: TVar[], constraints: Constraint[], type: Type): Forall {
|
||||||
|
return new Forall(new TVSet(typeVars), new CMany(constraints), type);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Scheme
|
export type Scheme
|
||||||
|
@ -894,9 +942,6 @@ class TypeEnv {
|
||||||
}
|
}
|
||||||
|
|
||||||
public add(name: string, scheme: Scheme, kind: Symkind): void {
|
public add(name: string, scheme: Scheme, kind: Symkind): void {
|
||||||
if (isDebug) {
|
|
||||||
validateScheme(scheme);
|
|
||||||
}
|
|
||||||
this.mapping.add(name, [kind, scheme]);
|
this.mapping.add(name, [kind, scheme]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -909,6 +954,17 @@ class TypeEnv {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public hasTypeVar(seek: TVar): boolean {
|
||||||
|
for (const [_name, [_kind, scheme]] of this.mapping) {
|
||||||
|
for (const tv of scheme.freeTypeVars()) {
|
||||||
|
if (tv.id === seek.id) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class KindEnv {
|
class KindEnv {
|
||||||
|
@ -965,7 +1021,7 @@ export interface InferContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
function isFunctionDeclarationLike(node: LetDeclaration): boolean {
|
function isFunctionDeclarationLike(node: LetDeclaration): boolean {
|
||||||
return node.pattern.kind === SyntaxKind.NamedPattern
|
return (node.pattern.kind === SyntaxKind.NamedPattern || node.pattern.kind === SyntaxKind.NestedPattern && node.pattern.pattern.kind === SyntaxKind.NamedPattern)
|
||||||
&& (node.params.length > 0 || (node.body !== null && node.body.kind === SyntaxKind.BlockBody));
|
&& (node.params.length > 0 || (node.body !== null && node.body.kind === SyntaxKind.BlockBody));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1000,18 +1056,18 @@ export class Checker {
|
||||||
const a = new TVar(this.nextTypeVarId++);
|
const a = new TVar(this.nextTypeVarId++);
|
||||||
const b = new TVar(this.nextTypeVarId++);
|
const b = new TVar(this.nextTypeVarId++);
|
||||||
|
|
||||||
this.globalTypeEnv.add('$', new Forall([ a, b ], [], new TArrow(new TArrow(new TArrow(a, b), a), b)), Symkind.Var);
|
this.globalTypeEnv.add('$', Forall.fromArrays([ a, b ], [], new TArrow(new TArrow(new TArrow(a, b), a), b)), Symkind.Var);
|
||||||
this.globalTypeEnv.add('String', new Forall([], [], this.stringType), Symkind.Type);
|
this.globalTypeEnv.add('String', Forall.fromArrays([], [], this.stringType), Symkind.Type);
|
||||||
this.globalTypeEnv.add('Int', new Forall([], [], this.intType), Symkind.Type);
|
this.globalTypeEnv.add('Int', Forall.fromArrays([], [], this.intType), Symkind.Type);
|
||||||
this.globalTypeEnv.add('Bool', new Forall([], [], this.boolType), Symkind.Type);
|
this.globalTypeEnv.add('Bool', Forall.fromArrays([], [], this.boolType), Symkind.Type);
|
||||||
this.globalTypeEnv.add('True', new Forall([], [], this.boolType), Symkind.Var);
|
this.globalTypeEnv.add('True', Forall.fromArrays([], [], this.boolType), Symkind.Var);
|
||||||
this.globalTypeEnv.add('False', new Forall([], [], this.boolType), Symkind.Var);
|
this.globalTypeEnv.add('False', Forall.fromArrays([], [], this.boolType), Symkind.Var);
|
||||||
this.globalTypeEnv.add('+', new Forall([], [], TArrow.build([ this.intType, this.intType ], this.intType)), Symkind.Var);
|
this.globalTypeEnv.add('+', Forall.fromArrays([], [], TArrow.build([ this.intType, this.intType ], this.intType)), Symkind.Var);
|
||||||
this.globalTypeEnv.add('-', new Forall([], [], TArrow.build([ this.intType, this.intType ], this.intType)), Symkind.Var);
|
this.globalTypeEnv.add('-', Forall.fromArrays([], [], TArrow.build([ this.intType, this.intType ], this.intType)), Symkind.Var);
|
||||||
this.globalTypeEnv.add('*', new Forall([], [], TArrow.build([ this.intType, this.intType ], this.intType)), Symkind.Var);
|
this.globalTypeEnv.add('*', Forall.fromArrays([], [], TArrow.build([ this.intType, this.intType ], this.intType)), Symkind.Var);
|
||||||
this.globalTypeEnv.add('/', new Forall([], [], TArrow.build([ this.intType, this.intType ], this.intType)), Symkind.Var);
|
this.globalTypeEnv.add('/', Forall.fromArrays([], [], TArrow.build([ this.intType, this.intType ], this.intType)), Symkind.Var);
|
||||||
this.globalTypeEnv.add('==', new Forall([ a ], [], TArrow.build([ a, a ], this.boolType)), Symkind.Var);
|
this.globalTypeEnv.add('==', Forall.fromArrays([ a ], [], TArrow.build([ a, a ], this.boolType)), Symkind.Var);
|
||||||
this.globalTypeEnv.add('not', new Forall([], [], new TArrow(this.boolType, this.boolType)), Symkind.Var);
|
this.globalTypeEnv.add('not', Forall.fromArrays([], [], new TArrow(this.boolType, this.boolType)), Symkind.Var);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1054,6 +1110,23 @@ export class Checker {
|
||||||
this.contexts.pop();
|
this.contexts.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private generalize(type: Type, constraints: Constraint[], env: TypeEnv): Scheme {
|
||||||
|
const tvs = new TVSet();
|
||||||
|
for (const tv of type.getTypeVars()) {
|
||||||
|
if (!env.hasTypeVar(tv)) {
|
||||||
|
tvs.add(tv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const constraint of constraints) {
|
||||||
|
for (const tv of constraint.freeTypeVars()) {
|
||||||
|
if (!env.hasTypeVar(tv)) {
|
||||||
|
tvs.add(tv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Forall(tvs, new CMany(constraints), type);
|
||||||
|
}
|
||||||
|
|
||||||
private lookupKind(env: KindEnv, node: NodeWithReference, emitDiagnostic = true): Kind | null {
|
private lookupKind(env: KindEnv, node: NodeWithReference, emitDiagnostic = true): Kind | null {
|
||||||
const [modulePath, name] = splitReferences(node);
|
const [modulePath, name] = splitReferences(node);
|
||||||
if (modulePath.length > 0) {
|
if (modulePath.length > 0) {
|
||||||
|
@ -1184,6 +1257,10 @@ export class Checker {
|
||||||
return context.returnType;
|
return context.returnType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getTypeEnv(): TypeEnv {
|
||||||
|
return this.getContext().env;
|
||||||
|
}
|
||||||
|
|
||||||
private createSubstitution(scheme: Scheme): TVSub {
|
private createSubstitution(scheme: Scheme): TVSub {
|
||||||
const sub = new TVSub();
|
const sub = new TVSub();
|
||||||
const tvs = [...scheme.typeVars]
|
const tvs = [...scheme.typeVars]
|
||||||
|
@ -1194,12 +1271,27 @@ export class Checker {
|
||||||
}
|
}
|
||||||
|
|
||||||
private instantiate(scheme: Scheme, node: Syntax | null, sub = this.createSubstitution(scheme)): Type {
|
private instantiate(scheme: Scheme, node: Syntax | null, sub = this.createSubstitution(scheme)): Type {
|
||||||
for (const constraint of scheme.constraints) {
|
const update = (constraint: CEqual) => {
|
||||||
const substituted = constraint.substitute(sub);
|
constraint.node = node;
|
||||||
substituted.node = node;
|
constraint.prevInstantiation = scheme.constraint;
|
||||||
substituted.prevInstantiation = constraint;
|
|
||||||
this.addConstraint(substituted);
|
|
||||||
}
|
}
|
||||||
|
const transform = (constraint: Constraint): Constraint => {
|
||||||
|
switch (constraint.kind) {
|
||||||
|
case ConstraintKind.Many:
|
||||||
|
const newConstraints: Constraint[] = [];
|
||||||
|
for (const element of constraint.elements) {
|
||||||
|
newConstraints.push(transform(element));
|
||||||
|
}
|
||||||
|
return new CMany(newConstraints);
|
||||||
|
case ConstraintKind.Empty:
|
||||||
|
return constraint;
|
||||||
|
case ConstraintKind.Equal:
|
||||||
|
const newConstraint = constraint.substitute(sub);
|
||||||
|
update(newConstraint);
|
||||||
|
return newConstraint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.addConstraint(transform(scheme.constraint));
|
||||||
return scheme.type.substitute(sub);
|
return scheme.type.substitute(sub);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1561,10 +1653,6 @@ export class Checker {
|
||||||
|
|
||||||
case SyntaxKind.InstanceDeclaration:
|
case SyntaxKind.InstanceDeclaration:
|
||||||
{
|
{
|
||||||
const cls = node.getScope().lookup(node.name.text, Symkind.Typeclass) as ClassDeclaration | null;
|
|
||||||
if (cls === null) {
|
|
||||||
this.diagnostics.add(new TypeclassNotFoundDiagnostic(node.name));
|
|
||||||
}
|
|
||||||
for (const element of node.elements) {
|
for (const element of node.elements) {
|
||||||
this.infer(element);
|
this.infer(element);
|
||||||
}
|
}
|
||||||
|
@ -1619,34 +1707,23 @@ export class Checker {
|
||||||
if (isFunctionDeclarationLike(node)) {
|
if (isFunctionDeclarationLike(node)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
const ctx = this.getContext();
|
||||||
|
const constraints: ConstraintSet = [];
|
||||||
|
const innerCtx: InferContext = {
|
||||||
|
...ctx,
|
||||||
|
constraints,
|
||||||
|
};
|
||||||
|
this.pushContext(innerCtx);
|
||||||
let type;
|
let type;
|
||||||
if (node.pattern.kind === SyntaxKind.WrappedOperator) {
|
|
||||||
type = this.createTypeVar();
|
|
||||||
this.addBinding(node.pattern.operator.text, new Forall([], [], type), Symkind.Var);
|
|
||||||
} else {
|
|
||||||
type = this.inferBindings(node.pattern, [], []);
|
|
||||||
}
|
|
||||||
if (node.typeAssert !== null) {
|
if (node.typeAssert !== null) {
|
||||||
this.addConstraint(
|
type = this.inferTypeExpression(node.typeAssert.typeExpression);
|
||||||
new CEqual(
|
|
||||||
this.inferTypeExpression(node.typeAssert.typeExpression),
|
|
||||||
type,
|
|
||||||
node
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (node.body !== null) {
|
if (node.body !== null) {
|
||||||
|
let bodyType;
|
||||||
switch (node.body.kind) {
|
switch (node.body.kind) {
|
||||||
case SyntaxKind.ExprBody:
|
case SyntaxKind.ExprBody:
|
||||||
{
|
{
|
||||||
const type2 = this.inferExpression(node.body.expression);
|
bodyType = this.inferExpression(node.body.expression);
|
||||||
this.addConstraint(
|
|
||||||
new CEqual(
|
|
||||||
type,
|
|
||||||
type2,
|
|
||||||
node
|
|
||||||
)
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SyntaxKind.BlockBody:
|
case SyntaxKind.BlockBody:
|
||||||
|
@ -1655,7 +1732,23 @@ export class Checker {
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (type === undefined) {
|
||||||
|
type = bodyType;
|
||||||
|
} else {
|
||||||
|
constraints.push(
|
||||||
|
new CEqual(
|
||||||
|
type,
|
||||||
|
bodyType,
|
||||||
|
node.body
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (type === undefined) {
|
||||||
|
type = this.createTypeVar();
|
||||||
|
}
|
||||||
|
this.popContext(innerCtx);
|
||||||
|
this.inferBindings(node.pattern, type, undefined, constraints, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1697,9 +1790,11 @@ export class Checker {
|
||||||
returnType: context.returnType,
|
returnType: context.returnType,
|
||||||
};
|
};
|
||||||
this.pushContext(newContext);
|
this.pushContext(newContext);
|
||||||
|
const armPatternType = this.createTypeVar();
|
||||||
|
this.inferBindings(arm.pattern, armPatternType);
|
||||||
this.addConstraint(
|
this.addConstraint(
|
||||||
new CEqual(
|
new CEqual(
|
||||||
this.inferBindings(arm.pattern, [], []),
|
armPatternType,
|
||||||
exprType,
|
exprType,
|
||||||
arm.pattern,
|
arm.pattern,
|
||||||
)
|
)
|
||||||
|
@ -1898,10 +1993,10 @@ export class Checker {
|
||||||
this.diagnostics.add(new BindingNotFoundDiagnostic([], node.name.text, node.name));
|
this.diagnostics.add(new BindingNotFoundDiagnostic([], node.name.text, node.name));
|
||||||
}
|
}
|
||||||
type = this.createTypeVar();
|
type = this.createTypeVar();
|
||||||
this.addBinding(node.name.text, new Forall([], [], type), Symkind.Type);
|
this.addBinding(node.name.text, Forall.mono(type), Symkind.Type);
|
||||||
} else {
|
} else {
|
||||||
assert(isEmpty(scheme.typeVars));
|
assert(isEmpty(scheme.typeVars));
|
||||||
assert(isEmpty(scheme.constraints));
|
assert(scheme.constraint.kind === ConstraintKind.Empty);
|
||||||
type = scheme.type;
|
type = scheme.type;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1940,94 +2035,99 @@ export class Checker {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public inferBindings(pattern: Pattern, typeVars: Iterable<TVar>, constraints: Iterable<Constraint>): Type {
|
public inferBindings(pattern: Pattern, type: Type, typeVars = new TVSet, constraints: Constraint[] = [], generalize = false): void {
|
||||||
|
|
||||||
switch (pattern.kind) {
|
switch (pattern.kind) {
|
||||||
|
|
||||||
case SyntaxKind.NamedPattern:
|
case SyntaxKind.NamedPattern:
|
||||||
{
|
{
|
||||||
const type = this.createTypeVar();
|
let scheme;
|
||||||
this.addBinding(pattern.name.text, new Forall(typeVars, constraints, type), Symkind.Var);
|
const env = this.getTypeEnv();
|
||||||
return type;
|
if (generalize) {
|
||||||
|
scheme = this.generalize(type, constraints, env);
|
||||||
|
} else {
|
||||||
|
scheme = new Forall(typeVars, new CMany(constraints), type);
|
||||||
|
}
|
||||||
|
this.addBinding(pattern.name.text, scheme, Symkind.Var);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SyntaxKind.NestedPattern:
|
case SyntaxKind.NestedPattern:
|
||||||
return this.inferBindings(pattern.pattern, typeVars, constraints);
|
this.inferBindings(pattern.pattern, type, typeVars, constraints);
|
||||||
|
break;
|
||||||
|
|
||||||
case SyntaxKind.NamedTuplePattern:
|
// case SyntaxKind.NamedTuplePattern:
|
||||||
{
|
// {
|
||||||
const scheme = this.lookup(pattern.name, Symkind.Type);
|
// const scheme = this.lookup(pattern.name, Symkind.Type);
|
||||||
if (scheme === null) {
|
// if (scheme === null) {
|
||||||
return this.createTypeVar();
|
// return this.createTypeVar();
|
||||||
}
|
// }
|
||||||
let tupleType = pattern.elements.map(p => this.inferBindings(p, typeVars, constraints));
|
// let tupleType = new TTuple(pattern.elements.map(p =>
|
||||||
// FIXME not tested
|
// this.inferBindings(p, this.createTypeVar(), typeVars, constraints));
|
||||||
return TApp.build(
|
// // FIXME not tested
|
||||||
new TNominal(scheme.type.node as StructDeclaration | EnumDeclaration, pattern),
|
// this.addConstraint(new CEqual(tupleType, type, pattern));
|
||||||
tupleType
|
// return TApp.build(
|
||||||
);
|
// new TNominal(scheme.type.node as StructDeclaration | EnumDeclaration, pattern),
|
||||||
}
|
// tupleType
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
case SyntaxKind.LiteralPattern:
|
case SyntaxKind.LiteralPattern:
|
||||||
{
|
{
|
||||||
let type;
|
let literalType;
|
||||||
switch (pattern.token.kind) {
|
switch (pattern.token.kind) {
|
||||||
case SyntaxKind.Integer:
|
case SyntaxKind.Integer:
|
||||||
type = this.getIntType();
|
literalType = this.getIntType();
|
||||||
break;
|
break;
|
||||||
case SyntaxKind.StringLiteral:
|
case SyntaxKind.StringLiteral:
|
||||||
type = this.getStringType();
|
literalType = this.getStringType();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
type = type.shallowClone();
|
literalType = literalType.shallowClone();
|
||||||
type.node = pattern;
|
literalType.node = pattern;
|
||||||
return type;
|
this.addConstraint(
|
||||||
|
new CEqual(
|
||||||
|
literalType,
|
||||||
|
type,
|
||||||
|
pattern,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SyntaxKind.DisjunctivePattern:
|
case SyntaxKind.DisjunctivePattern:
|
||||||
{
|
{
|
||||||
const type = this.createTypeVar();
|
this.inferBindings(pattern.left, type, typeVars, constraints),
|
||||||
this.addConstraint(
|
this.inferBindings(pattern.right, type, typeVars, constraints);
|
||||||
new CEqual(
|
break;
|
||||||
this.inferBindings(pattern.left, typeVars, constraints),
|
|
||||||
type,
|
|
||||||
pattern.left
|
|
||||||
)
|
|
||||||
);
|
|
||||||
this.addConstraint(
|
|
||||||
new CEqual(
|
|
||||||
this.inferBindings(pattern.right, typeVars, constraints),
|
|
||||||
type,
|
|
||||||
pattern.left
|
|
||||||
)
|
|
||||||
);
|
|
||||||
return type;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case SyntaxKind.StructPattern:
|
case SyntaxKind.StructPattern:
|
||||||
{
|
{
|
||||||
const variadicMember = getVariadicMember(pattern);
|
const variadicMember = getVariadicMember(pattern);
|
||||||
let type: Type;
|
let structType: Type;
|
||||||
if (variadicMember === null) {
|
if (variadicMember === null) {
|
||||||
type = new TNil(pattern);
|
structType = new TNil(pattern);
|
||||||
} else if (variadicMember.pattern === null) {
|
|
||||||
type = this.createTypeVar();
|
|
||||||
} else {
|
} else {
|
||||||
type = this.inferBindings(variadicMember.pattern, typeVars, constraints);
|
structType = this.createTypeVar();
|
||||||
|
if (variadicMember.pattern !== null) {
|
||||||
|
this.inferBindings(variadicMember.pattern, structType, typeVars, constraints);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (const member of pattern.members) {
|
for (const member of pattern.members) {
|
||||||
switch (member.kind) {
|
switch (member.kind) {
|
||||||
case SyntaxKind.StructPatternField:
|
case SyntaxKind.StructPatternField:
|
||||||
{
|
{
|
||||||
const fieldType = this.inferBindings(member.pattern, typeVars, constraints);
|
const fieldType = this.createTypeVar();
|
||||||
type = new TField(member.name.text, new TPresent(fieldType), type, pattern);
|
this.inferBindings(member.pattern, fieldType, typeVars, constraints);
|
||||||
|
structType = new TField(member.name.text, new TPresent(fieldType), fieldType, pattern);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SyntaxKind.PunnedStructPatternField:
|
case SyntaxKind.PunnedStructPatternField:
|
||||||
{
|
{
|
||||||
const fieldType = this.createTypeVar();
|
const fieldType = this.createTypeVar();
|
||||||
this.addBinding(member.name.text, new Forall([], [], fieldType), Symkind.Var);
|
this.addBinding(member.name.text, Forall.mono(fieldType), Symkind.Var);
|
||||||
type = new TField(member.name.text, new TPresent(fieldType), type, pattern);
|
structType = new TField(member.name.text, new TPresent(fieldType), fieldType, pattern);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SyntaxKind.VariadicStructPatternElement:
|
case SyntaxKind.VariadicStructPatternElement:
|
||||||
|
@ -2036,7 +2136,14 @@ export class Checker {
|
||||||
assertNever(member);
|
assertNever(member);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return TField.sort(type);
|
this.addConstraint(
|
||||||
|
new CEqual(
|
||||||
|
type,
|
||||||
|
TField.sort(structType),
|
||||||
|
pattern,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -2078,7 +2185,7 @@ export class Checker {
|
||||||
const env = node.typeEnv = new TypeEnv(parentEnv);
|
const env = node.typeEnv = new TypeEnv(parentEnv);
|
||||||
for (const tv of node.types) {
|
for (const tv of node.types) {
|
||||||
assert(tv.kind === SyntaxKind.VarTypeExpression);
|
assert(tv.kind === SyntaxKind.VarTypeExpression);
|
||||||
env.add(tv.name.text, new Forall([], [], this.createTypeVar(tv)), Symkind.Type);
|
env.add(tv.name.text, Forall.mono(this.createTypeVar(tv)), Symkind.Type);
|
||||||
}
|
}
|
||||||
for (const element of node.elements) {
|
for (const element of node.elements) {
|
||||||
this.initialize(element, env);
|
this.initialize(element, env);
|
||||||
|
@ -2088,6 +2195,9 @@ export class Checker {
|
||||||
|
|
||||||
case SyntaxKind.InstanceDeclaration:
|
case SyntaxKind.InstanceDeclaration:
|
||||||
{
|
{
|
||||||
|
if (!this.classDecls.has(node.name.text)) {
|
||||||
|
this.diagnostics.add(new TypeclassNotFoundDiagnostic(node.name));
|
||||||
|
}
|
||||||
const env = node.typeEnv = new TypeEnv(parentEnv);
|
const env = node.typeEnv = new TypeEnv(parentEnv);
|
||||||
for (const element of node.elements) {
|
for (const element of node.elements) {
|
||||||
this.initialize(element, env);
|
this.initialize(element, env);
|
||||||
|
@ -2126,11 +2236,11 @@ export class Checker {
|
||||||
const kindArgs = [];
|
const kindArgs = [];
|
||||||
for (const name of node.varExps) {
|
for (const name of node.varExps) {
|
||||||
const kindArg = this.createTypeVar();
|
const kindArg = this.createTypeVar();
|
||||||
env.add(name.text, new Forall([], [], kindArg), Symkind.Type);
|
env.add(name.text, Forall.mono(kindArg), Symkind.Type);
|
||||||
kindArgs.push(kindArg);
|
kindArgs.push(kindArg);
|
||||||
}
|
}
|
||||||
const type = TApp.build(new TNominal(node, node), kindArgs);
|
const type = TApp.build(new TNominal(node, node), kindArgs);
|
||||||
parentEnv.add(node.name.text, new Forall(typeVars, constraints, type), Symkind.Type);
|
parentEnv.add(node.name.text, new Forall(typeVars, new CMany(constraints), type), Symkind.Type);
|
||||||
let elementTypes: Type[] = [];
|
let elementTypes: Type[] = [];
|
||||||
if (node.members !== null) {
|
if (node.members !== null) {
|
||||||
for (const member of node.members) {
|
for (const member of node.members) {
|
||||||
|
@ -2157,7 +2267,7 @@ export class Checker {
|
||||||
throw new Error(`Unexpected ${member}`);
|
throw new Error(`Unexpected ${member}`);
|
||||||
}
|
}
|
||||||
// FIXME `typeVars` may contain too much irrelevant type variables
|
// FIXME `typeVars` may contain too much irrelevant type variables
|
||||||
parentEnv.add(member.name.text, new Forall(typeVars, constraints, ctorType), Symkind.Var);
|
parentEnv.add(member.name.text, new Forall(typeVars, new CMany(constraints), ctorType), Symkind.Var);
|
||||||
elementTypes.push(elementType);
|
elementTypes.push(elementType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2181,11 +2291,11 @@ export class Checker {
|
||||||
for (const varExpr of node.varExps) {
|
for (const varExpr of node.varExps) {
|
||||||
const typeVar = this.createTypeVar();
|
const typeVar = this.createTypeVar();
|
||||||
kindArgs.push(typeVar);
|
kindArgs.push(typeVar);
|
||||||
env.add(varExpr.text, new Forall([], [], typeVar), Symkind.Type);
|
env.add(varExpr.text, Forall.mono(typeVar), Symkind.Type);
|
||||||
}
|
}
|
||||||
const type = this.inferTypeExpression(node.typeExpression);
|
const type = this.inferTypeExpression(node.typeExpression);
|
||||||
this.popContext(context);
|
this.popContext(context);
|
||||||
const scheme = new Forall(typeVars, constraints, TApp.build(type, kindArgs));
|
const scheme = new Forall(typeVars, new CMany(constraints), TApp.build(type, kindArgs));
|
||||||
parentEnv.add(node.name.text, scheme, Symkind.Type);
|
parentEnv.add(node.name.text, scheme, Symkind.Type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2205,7 +2315,7 @@ export class Checker {
|
||||||
const kindArgs = [];
|
const kindArgs = [];
|
||||||
for (const varExpr of node.varExps) {
|
for (const varExpr of node.varExps) {
|
||||||
const kindArg = this.createTypeVar();
|
const kindArg = this.createTypeVar();
|
||||||
env.add(varExpr.text, new Forall([], [], kindArg), Symkind.Type);
|
env.add(varExpr.text, Forall.mono(kindArg), Symkind.Type);
|
||||||
kindArgs.push(kindArg);
|
kindArgs.push(kindArg);
|
||||||
}
|
}
|
||||||
let type: Type = new TNil(node);
|
let type: Type = new TNil(node);
|
||||||
|
@ -2215,7 +2325,7 @@ export class Checker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.popContext(context);
|
this.popContext(context);
|
||||||
parentEnv.add(node.name.text, new Forall(typeVars, constraints, TField.sort(type)), Symkind.Type);
|
parentEnv.add(node.name.text, new Forall(typeVars, new CMany(constraints), TField.sort(type)), Symkind.Type);
|
||||||
//parentEnv.add(node.name.text, new Forall(typeVars, constraints, new TArrow(type, TApp.build(type, kindArgs))), Symkind.Var);
|
//parentEnv.add(node.name.text, new Forall(typeVars, constraints, new TArrow(type, TApp.build(type, kindArgs))), Symkind.Var);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2270,24 +2380,27 @@ export class Checker {
|
||||||
}
|
}
|
||||||
|
|
||||||
const env = node.typeEnv!;
|
const env = node.typeEnv!;
|
||||||
const inner: InferContext = {
|
const innerCtx: InferContext = {
|
||||||
typeVars,
|
typeVars,
|
||||||
constraints,
|
constraints,
|
||||||
env,
|
env,
|
||||||
returnType: null,
|
returnType: null,
|
||||||
};
|
};
|
||||||
node.context = inner;
|
node.context = innerCtx;
|
||||||
|
|
||||||
this.contexts.push(inner);
|
this.contexts.push(innerCtx);
|
||||||
|
|
||||||
const returnType = this.createTypeVar();
|
const returnType = this.createTypeVar();
|
||||||
inner.returnType = returnType;
|
innerCtx.returnType = returnType;
|
||||||
|
|
||||||
const paramTypes = node.params.map(
|
const paramTypes = node.params.map(param => {
|
||||||
param => this.inferBindings(param.pattern, [], [])
|
const paramType = this.createTypeVar();
|
||||||
);
|
this.inferBindings(param.pattern, paramType)
|
||||||
|
return paramType;
|
||||||
|
});
|
||||||
|
|
||||||
let type = TArrow.build(paramTypes, returnType, node);
|
let type = TArrow.build(paramTypes, returnType, node);
|
||||||
|
|
||||||
if (node.typeAssert !== null) {
|
if (node.typeAssert !== null) {
|
||||||
this.addConstraint(
|
this.addConstraint(
|
||||||
new CEqual(
|
new CEqual(
|
||||||
|
@ -2316,20 +2429,13 @@ export class Checker {
|
||||||
if (node.parent!.kind !== SyntaxKind.InstanceDeclaration) {
|
if (node.parent!.kind !== SyntaxKind.InstanceDeclaration) {
|
||||||
const scopeDecl = node.parent!.getScope().node;
|
const scopeDecl = node.parent!.getScope().node;
|
||||||
const outer = {
|
const outer = {
|
||||||
typeVars: inner.typeVars,
|
typeVars: innerCtx.typeVars,
|
||||||
constraints: inner.constraints,
|
constraints: innerCtx.constraints,
|
||||||
env: scopeDecl.typeEnv!,
|
env: scopeDecl.typeEnv!,
|
||||||
returnType: null,
|
returnType: null,
|
||||||
};
|
};
|
||||||
this.contexts.push(outer)
|
this.contexts.push(outer)
|
||||||
let ty2;
|
this.inferBindings(node.pattern, type, typeVars, constraints);
|
||||||
if (node.pattern.kind === SyntaxKind.WrappedOperator) {
|
|
||||||
ty2 = this.createTypeVar();
|
|
||||||
this.addBinding(node.pattern.operator.text, new Forall([], [], ty2), Symkind.Var);
|
|
||||||
} else {
|
|
||||||
ty2 = this.inferBindings(node.pattern, typeVars, constraints);
|
|
||||||
}
|
|
||||||
this.addConstraint(new CEqual(ty2, type, node));
|
|
||||||
this.contexts.pop();
|
this.contexts.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2341,18 +2447,17 @@ export class Checker {
|
||||||
if (element.kind === SyntaxKind.LetDeclaration
|
if (element.kind === SyntaxKind.LetDeclaration
|
||||||
&& isFunctionDeclarationLike(element)) {
|
&& isFunctionDeclarationLike(element)) {
|
||||||
if (!this.analyser.isReferencedInParentScope(element)) {
|
if (!this.analyser.isReferencedInParentScope(element)) {
|
||||||
assert(element.pattern.kind === SyntaxKind.NamedPattern);
|
const scheme = this.lookup(element.name, Symkind.Var);
|
||||||
const scheme = this.lookup(element.pattern.name, Symkind.Var);
|
|
||||||
assert(scheme !== null);
|
assert(scheme !== null);
|
||||||
this.instantiate(scheme, null);
|
this.instantiate(scheme, null);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const elementHasTypeEnv = hasTypeEnv(element);
|
const shouldChangeTypeEnv = shouldChangeTypeEnvDuringVisit(element);
|
||||||
if (elementHasTypeEnv) {
|
if (shouldChangeTypeEnv) {
|
||||||
this.pushContext({ ...this.getContext(), env: element.typeEnv! });
|
this.pushContext({ ...this.getContext(), env: element.typeEnv! });
|
||||||
}
|
}
|
||||||
this.infer(element);
|
this.infer(element);
|
||||||
if(elementHasTypeEnv) {
|
if(shouldChangeTypeEnv) {
|
||||||
this.contexts.pop();
|
this.contexts.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2524,7 +2629,7 @@ export class Checker {
|
||||||
left = find(left);
|
left = find(left);
|
||||||
right = find(right);
|
right = find(right);
|
||||||
|
|
||||||
//console.log(`unify ${describeType(left)} ~ ${describeType(right)}`);
|
// console.log(`unify ${describeType(left)} @ ${left.node && left.node.constructor && left.node.constructor.name} ~ ${describeType(right)} @ ${right.node && right.node.constructor && right.node.constructor.name}`);
|
||||||
|
|
||||||
const swap = () => { [right, left] = [left, right]; }
|
const swap = () => { [right, left] = [left, right]; }
|
||||||
|
|
||||||
|
@ -2578,9 +2683,9 @@ export class Checker {
|
||||||
// into a special chain.
|
// into a special chain.
|
||||||
TypeBase.join(left, right);
|
TypeBase.join(left, right);
|
||||||
|
|
||||||
if (left.node !== undefined) {
|
// if (left.node !== null) {
|
||||||
right.node = left.node;
|
// right.node = left.node;
|
||||||
}
|
// }
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2718,7 +2823,7 @@ export class Checker {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVariadicMember(node: StructPattern) {
|
function getVariadicMember(node: StructPattern) {1713
|
||||||
for (const member of node.members) {
|
for (const member of node.members) {
|
||||||
if (member.kind === SyntaxKind.VariadicStructPatternElement) {
|
if (member.kind === SyntaxKind.VariadicStructPatternElement) {
|
||||||
return member;
|
return member;
|
||||||
|
@ -2734,10 +2839,9 @@ type HasTypeEnv
|
||||||
| ModuleDeclaration
|
| ModuleDeclaration
|
||||||
| SourceFile
|
| SourceFile
|
||||||
|
|
||||||
function hasTypeEnv(node: Syntax): node is HasTypeEnv {
|
function shouldChangeTypeEnvDuringVisit(node: Syntax): node is HasTypeEnv {
|
||||||
return node.kind === SyntaxKind.ClassDeclaration
|
return node.kind === SyntaxKind.ClassDeclaration
|
||||||
|| node.kind === SyntaxKind.InstanceDeclaration
|
|| node.kind === SyntaxKind.InstanceDeclaration
|
||||||
|| node.kind === SyntaxKind.LetDeclaration
|
|
||||||
|| node.kind === SyntaxKind.ModuleDeclaration
|
|| node.kind === SyntaxKind.ModuleDeclaration
|
||||||
|| node.kind === SyntaxKind.SourceFile
|
|| node.kind === SyntaxKind.SourceFile
|
||||||
}
|
}
|
||||||
|
|
23
src/cst.ts
23
src/cst.ts
|
@ -2,7 +2,7 @@
|
||||||
import type stream from "stream";
|
import type stream from "stream";
|
||||||
import path from "path"
|
import path from "path"
|
||||||
|
|
||||||
import { assert, implementationLimitation, IndentWriter, JSONObject, JSONValue } from "./util";
|
import { assert, implementationLimitation, IndentWriter, JSONObject, JSONValue, unreachable } from "./util";
|
||||||
import { isNodeWithScope, Scope } from "./scope"
|
import { isNodeWithScope, Scope } from "./scope"
|
||||||
import { InferContext, Kind, KindEnv, Scheme, Type, TypeEnv } from "./checker"
|
import { InferContext, Kind, KindEnv, Scheme, Type, TypeEnv } from "./checker"
|
||||||
import { Emitter } from "./emitter";
|
import { Emitter } from "./emitter";
|
||||||
|
@ -39,9 +39,8 @@ export class TextPosition {
|
||||||
} else {
|
} else {
|
||||||
this.column++;
|
this.column++;
|
||||||
}
|
}
|
||||||
this.offset += text.length;
|
|
||||||
}
|
}
|
||||||
|
this.offset += text.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -618,7 +617,7 @@ export class StringLiteral extends TokenBase {
|
||||||
} else if (code <= 127) {
|
} else if (code <= 127) {
|
||||||
out += '\\x' + code.toString(16).padStart(2, '0');
|
out += '\\x' + code.toString(16).padStart(2, '0');
|
||||||
} else {
|
} else {
|
||||||
out += '\\u' + code.toString(17).padStart(4, '0');
|
out += '\\u' + code.toString(16).padStart(4, '0');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out += '"';
|
out += '"';
|
||||||
|
@ -1387,7 +1386,7 @@ export class NamedPattern extends SyntaxBase {
|
||||||
public readonly kind = SyntaxKind.NamedPattern;
|
public readonly kind = SyntaxKind.NamedPattern;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
public name: Identifier,
|
public name: Identifier | CustomOperator,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
@ -2687,7 +2686,7 @@ export class LetDeclaration extends SyntaxBase {
|
||||||
public letKeyword: LetKeyword,
|
public letKeyword: LetKeyword,
|
||||||
public foreignKeyword: ForeignKeyword | null,
|
public foreignKeyword: ForeignKeyword | null,
|
||||||
public mutKeyword: MutKeyword | null,
|
public mutKeyword: MutKeyword | null,
|
||||||
public pattern: Pattern | WrappedOperator,
|
public pattern: Pattern,
|
||||||
public params: Param[],
|
public params: Param[],
|
||||||
public typeAssert: TypeAssert | null,
|
public typeAssert: TypeAssert | null,
|
||||||
public body: Body | null,
|
public body: Body | null,
|
||||||
|
@ -2695,6 +2694,18 @@ export class LetDeclaration extends SyntaxBase {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get name(): Identifier | CustomOperator {
|
||||||
|
switch (this.pattern.kind) {
|
||||||
|
case SyntaxKind.NamedPattern:
|
||||||
|
return this.pattern.name;
|
||||||
|
case SyntaxKind.NestedPattern:
|
||||||
|
assert(this.pattern.pattern.kind === SyntaxKind.NamedPattern);
|
||||||
|
return this.pattern.pattern.name;
|
||||||
|
default:
|
||||||
|
unreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public clone(): LetDeclaration {
|
public clone(): LetDeclaration {
|
||||||
return new LetDeclaration(
|
return new LetDeclaration(
|
||||||
this.pubKeyword !== null ? this.pubKeyword.clone() : null,
|
this.pubKeyword !== null ? this.pubKeyword.clone() : null,
|
||||||
|
|
|
@ -852,7 +852,7 @@ export class Parser {
|
||||||
this.getToken()
|
this.getToken()
|
||||||
this.getToken();
|
this.getToken();
|
||||||
this.getToken();
|
this.getToken();
|
||||||
pattern = new WrappedOperator(t1, t2, t3);
|
pattern = new NestedPattern(t1, new NamedPattern(t2), t3);
|
||||||
} else {
|
} else {
|
||||||
pattern = this.parsePattern();
|
pattern = this.parsePattern();
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ import {
|
||||||
InstanceKeyword,
|
InstanceKeyword,
|
||||||
Backslash,
|
Backslash,
|
||||||
} from "./cst"
|
} from "./cst"
|
||||||
import { Diagnostics, UnexpectedCharDiagnostic } from "./diagnostics"
|
import { Diagnostics } from "./diagnostics"
|
||||||
import { Stream, BufferedStream, assert } from "./util";
|
import { Stream, BufferedStream, assert } from "./util";
|
||||||
|
|
||||||
const EOF = '\uFFFF'
|
const EOF = '\uFFFF'
|
||||||
|
@ -182,7 +182,6 @@ export class Scanner extends BufferedStream<Token> {
|
||||||
|
|
||||||
case '"':
|
case '"':
|
||||||
{
|
{
|
||||||
const startPos = this.getCurrentPosition();
|
|
||||||
let contents = '';
|
let contents = '';
|
||||||
let escaping = false;
|
let escaping = false;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
|
@ -111,11 +111,7 @@ export class Scope {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (node.pattern.kind === SyntaxKind.WrappedOperator) {
|
this.scanPattern(node.pattern, node);
|
||||||
this.add(node.pattern.operator.text, node, Symkind.Var);
|
|
||||||
} else {
|
|
||||||
this.scanPattern(node.pattern, node);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -195,6 +195,7 @@ mod CD.
|
||||||
let alpha: A.Foo
|
let alpha: A.Foo
|
||||||
```
|
```
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
## Rest-expressions on extensible records work
|
## Rest-expressions on extensible records work
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -207,3 +208,19 @@ let foo { x, y, .. } : Point -> Int = x + y
|
||||||
|
|
||||||
foo { x = 1, y = 2 }
|
foo { x = 1, y = 2 }
|
||||||
```
|
```
|
||||||
|
=======
|
||||||
|
|
||||||
|
## A polymorphic function is properly generalized when assigned to a new variable
|
||||||
|
|
||||||
|
```
|
||||||
|
let id x = x
|
||||||
|
let id2 = id
|
||||||
|
let id3 = id
|
||||||
|
|
||||||
|
id3 1
|
||||||
|
id3 "bla"
|
||||||
|
|
||||||
|
id2 1
|
||||||
|
id2 "bla"
|
||||||
|
````
|
||||||
|
>>>>>>> 11bae0fed0d58eafebd863b4e3bf117176176cb1
|
||||||
|
|
19
src/util.ts
19
src/util.ts
|
@ -1,13 +1,20 @@
|
||||||
|
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import stream from "stream"
|
import stream from "stream"
|
||||||
import { inspect } from "util";
|
import { InspectOptions } from "util";
|
||||||
|
|
||||||
export const isDebug = process.env['NODE_ENV'] === 'development';
|
export const isDebug = process.env['NODE_ENV'] === 'development';
|
||||||
|
|
||||||
export const customInspectSymbol = Symbol.for('nodejs.util.inspect.custom')
|
export const toStringTag = Symbol.for('nodejs.util.inspect.custom');
|
||||||
|
|
||||||
export type InspectFn = typeof inspect;
|
export type InspectFn = (value: any, options: InspectOptions) => string;
|
||||||
|
|
||||||
|
export function isIterable(value: any): value is Iterable<any> {
|
||||||
|
if (value === undefined || value === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return typeof(value[Symbol.iterator]) === 'function';
|
||||||
|
}
|
||||||
|
|
||||||
export function first<T>(iter: Iterator<T>): T | undefined {
|
export function first<T>(iter: Iterator<T>): T | undefined {
|
||||||
return iter.next().value;
|
return iter.next().value;
|
||||||
|
@ -81,6 +88,10 @@ export function implementationLimitation(test: boolean): asserts test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function unreachable(): never {
|
||||||
|
throw new Error(`Code that should never be executed was reached during operation.`);
|
||||||
|
}
|
||||||
|
|
||||||
export function assertNever(value: never): never {
|
export function assertNever(value: never): never {
|
||||||
console.error(value);
|
console.error(value);
|
||||||
throw new Error(`Assertion failed. See the stack trace for more information.`);
|
throw new Error(`Assertion failed. See the stack trace for more information.`);
|
||||||
|
@ -201,7 +212,7 @@ export class MultiMap<K, V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public *[Symbol.iterator](): Iterable<[K, V]> {
|
public *[Symbol.iterator](): Iterator<[K, V]> {
|
||||||
for (const [key, elements] of this.mapping) {
|
for (const [key, elements] of this.mapping) {
|
||||||
for (const value of elements) {
|
for (const value of elements) {
|
||||||
yield [key, value];
|
yield [key, value];
|
||||||
|
|
Loading…
Reference in a new issue