Skip to content

Commit fcb3336

Browse files
authored
Base support for coalescing & logical assignment (#20549)
1 parent c8ccd4b commit fcb3336

File tree

7 files changed

+41
-15
lines changed

7 files changed

+41
-15
lines changed

ChangeLog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ See docs/process.md for more on how version tagging works.
3030
- If exceptions are disabled, using `new` together with `std::nothrow` no
3131
longer aborts if the allocation fails. Instead `nullptr` is returned now.
3232
This does not change the behavior of regular usage of `new`.
33+
- Default `MIN_CHROME_VERSION` was increased from 75 to 85 and default
34+
`MIN_FIREFOX_VERSION` was increased from 68 to 79 to allow Emscripten
35+
to use some ES2021 features for smaller JavaScript code size. (#20549)
3336

3437
3.1.47 - 10/09/23
3538
-----------------

src/settings.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1768,10 +1768,10 @@ var AUTO_NATIVE_LIBRARIES = true;
17681768
// versions >= MIN_FIREFOX_VERSION
17691769
// are desired to work. Pass -sMIN_FIREFOX_VERSION=majorVersion to drop support
17701770
// for Firefox versions older than < majorVersion.
1771-
// Firefox ESR 68 was released on July 9, 2019.
1771+
// Firefox 79 was released on 2020-07-28.
17721772
// MAX_INT (0x7FFFFFFF, or -1) specifies that target is not supported.
17731773
// [link]
1774-
var MIN_FIREFOX_VERSION = 68;
1774+
var MIN_FIREFOX_VERSION = 79;
17751775

17761776
// Specifies the oldest version of desktop Safari to target. Version is encoded
17771777
// in MMmmVV, e.g. 70101 denotes Safari 7.1.1.
@@ -1810,10 +1810,10 @@ var MIN_EDGE_VERSION = 0x7FFFFFFF;
18101810

18111811
// Specifies the oldest version of Chrome. E.g. pass -sMIN_CHROME_VERSION=58 to
18121812
// drop support for Chrome 57 and older.
1813-
// Chrome 75.0.3770 was released on 2019-06-04
1813+
// Chrome 85 was released on 2020-08-25.
18141814
// MAX_INT (0x7FFFFFFF, or -1) specifies that target is not supported.
18151815
// [link]
1816-
var MIN_CHROME_VERSION = 75;
1816+
var MIN_CHROME_VERSION = 85;
18171817

18181818
// Specifies minimum node version to target for the generated code. This is
18191819
// distinct from the minimum version required run the emscripten compiler.

test/test_core.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9907,13 +9907,9 @@ def test_main_reads_args(self):
99079907
@requires_node
99089908
def test_promise(self):
99099909
# This test depends on Promise.any, which in turn requires a modern target. Check that it
9910-
# fails to even build without bumping the min versions:
9911-
err = self.expect_fail([EMCC, test_file('core/test_promise.c')])
9910+
# fails to even build on old targets.
9911+
err = self.expect_fail([EMCC, test_file('core/test_promise.c'), '-sMIN_CHROME_VERSION=75'])
99129912
self.assertContained('error: emscripten_promise_any used, but Promise.any is not supported by the current runtime configuration', err)
9913-
self.set_setting('MIN_NODE_VERSION', '150000')
9914-
self.set_setting('MIN_SAFARI_VERSION', '150000')
9915-
self.set_setting('MIN_FIREFOX_VERSION', '79')
9916-
self.set_setting('MIN_CHROME_VERSION', '85')
99179913
self.do_core_test('test_promise.c')
99189914

99199915
@with_asyncify_and_jspi

test/test_other.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12967,14 +12967,16 @@ def test_es5_transpile(self, args):
1296712967
# - arrow funcs
1296812968
# - for..of
1296912969
# - object.assign
12970+
# - nullish coalescing & chaining
12971+
# - logical assignment
1297012972
create_file('es6_library.js', '''\
1297112973
addToLibrary({
1297212974
foo: function(arg="hello") {
1297312975
// Object.assign + let
1297412976
let obj = Object.assign({}, {prop:1});
1297512977
err('prop: ' + obj.prop);
1297612978

12977-
// arror funcs + const
12979+
// arrow funcs + const
1297812980
const bar = () => 2;
1297912981
err('bar: ' + bar());
1298012982

@@ -12991,6 +12993,22 @@ def test_es5_transpile(self, args):
1299112993
};
1299212994
global['foo'] = obj3;
1299312995
err('value2: ' + obj3.myMethod());
12996+
12997+
// Nullish coalescing
12998+
var definitely = global['maybe'] ?? {};
12999+
13000+
// Optional chaining
13001+
global['maybe']
13002+
?.subObj
13003+
?.[key]
13004+
?.func
13005+
?.();
13006+
13007+
// Logical assignment
13008+
var obj4 = null;
13009+
obj4 ??= 0;
13010+
obj4 ||= 1;
13011+
obj4 &&= 2;
1299413012
}
1299513013
});
1299613014
''')
@@ -13005,13 +13023,22 @@ def check_for_es6(filename, expect):
1300513023
self.assertContained(['() => 2', '()=>2'], js)
1300613024
self.assertContained('const ', js)
1300713025
self.assertContained('let ', js)
13026+
self.assertContained('?.[', js)
13027+
self.assertContained('?.(', js)
13028+
self.assertContained('??=', js)
13029+
self.assertContained('||=', js)
13030+
self.assertContained('&&=', js)
1300813031
else:
1300913032
self.verify_es5(filename)
1301013033
self.assertNotContained('foo(arg=', js)
1301113034
self.assertNotContained('() => 2', js)
1301213035
self.assertNotContained('()=>2', js)
1301313036
self.assertNotContained('const ', js)
1301413037
self.assertNotContained('let ', js)
13038+
self.assertNotContained('??', js)
13039+
self.assertNotContained('?.', js)
13040+
self.assertNotContained('||=', js)
13041+
self.assertNotContained('&&=', js)
1301513042

1301613043
# Check that under normal circumstances none of these features get
1301713044
# removed / transpiled.

tools/acorn-optimizer.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,7 +1044,7 @@ function applyDCEGraphRemovals(ast) {
10441044

10451045
// Need a parser to pass to acorn.Node constructor.
10461046
// Create it once and reuse it.
1047-
const stubParser = new acorn.Parser({ecmaVersion: 2020});
1047+
const stubParser = new acorn.Parser({ecmaVersion: 2021});
10481048

10491049
function createNode(props) {
10501050
const node = new acorn.Node(stubParser);
@@ -2008,7 +2008,7 @@ let ast;
20082008
try {
20092009
ast = acorn.parse(input, {
20102010
// Keep in sync with --language_in that we pass to closure in building.py
2011-
ecmaVersion: 2020,
2011+
ecmaVersion: 2021,
20122012
preserveParens: closureFriendly,
20132013
onComment: closureFriendly ? sourceComments : undefined,
20142014
sourceType: exportES6 ? 'module' : 'script',

tools/building.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ def closure_compiler(filename, advanced=True, extra_closure_args=None):
567567

568568
args = ['--compilation_level', 'ADVANCED_OPTIMIZATIONS' if advanced else 'SIMPLE_OPTIMIZATIONS']
569569
# Keep in sync with ecmaVersion in tools/acorn-optimizer.js
570-
args += ['--language_in', 'ECMASCRIPT_2020']
570+
args += ['--language_in', 'ECMASCRIPT_2021']
571571
# Tell closure not to do any transpiling or inject any polyfills.
572572
# At some point we may want to look into using this as way to convert to ES5 but
573573
# babel is perhaps a better tool for that.

tools/unsafe_optimizations.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ function optPassMergeVarInitializationAssignments(ast) {
223223
}
224224

225225
function runOnJsText(js, pretty = false) {
226-
const ast = acorn.parse(js, {ecmaVersion: 2020});
226+
const ast = acorn.parse(js, {ecmaVersion: 2021});
227227

228228
optPassSimplifyModuleInitialization(ast);
229229
optPassRemoveRedundantOperatorNews(ast);

0 commit comments

Comments
 (0)