Skip to content

Commit

Permalink
deps: V8: cherry-pick a0fd3209dda8
Browse files Browse the repository at this point in the history
Original commit message:

    [import-attributes] Implement import attributes, with `assert` fallback

    In the past six months, the old import assertions proposal has been
    renamed to "import attributes" with the follwing major changes:
    1. the keyword is now `with` instead of `assert`
    2. unknown assertions cause an error rather than being ignored

    To preserve backward compatibility with existing applications that use
    `assert`, implementations _can_ keep it around as a fallback for both
    the static and dynamic forms.

    Additionally, the proposal has some minor changes that came up during
    the stage 3 reviews:
    3. dynamic import first reads all the attributes, and then verifies
       that they are all strings
    4. there is no need for a `[no LineTerminator here]` restriction before
       the `with` keyword
    5. static import syntax allows any `LiteralPropertyName` as attribute
       keys, to align with every other syntax using key-value pairs

    The new syntax is enabled by a new `--harmony-import-attributes` flag,
    disabled by default. However, the new behavioral changes also apply to
    the old syntax that is under the `--harmony-import-assertions` flag.

    This patch does implements (1), (3), (4) and (5). Handling of unknown
    import assertions was not implemented directly in V8, but delegated
    to embedders. As such, it will be implemented separately in d8 and
    Chromium.

    To simplify the review, this patch doesn't migrate usage of the term
    "assertions" to "attributes". There are many variables and internal
    functions that could be easily renamed as soon as this patch landes.
    There is one usage in the public API
    (`ModuleRequest::GetImportAssertions`) that will probably need to be
    aliased and then removed following the same process as for other API
    breaking changes.

    Bug: v8:13856
    Change-Id: I78b167348d898887332c5ca7468bc5d58cd9b1ca
    Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4632799
    Commit-Queue: Shu-yu Guo <syg@chromium.org>
    Reviewed-by: Adam Klein <adamk@chromium.org>
    Cr-Commit-Position: refs/heads/main@{#89110}

Refs: v8/v8@159c82c
Refs: v8/v8@a0fd320
PR-URL: #50183
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
  • Loading branch information
aduh95 authored and targos committed Nov 11, 2023
1 parent 27e957c commit 16fd730
Show file tree
Hide file tree
Showing 29 changed files with 698 additions and 107 deletions.
2 changes: 1 addition & 1 deletion common.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@

# Reset this number to 0 on major V8 upgrades.
# Increment by one for each non-official patch applied to deps/v8.
'v8_embedder_string': '-node.17',
'v8_embedder_string': '-node.18',

##### V8 defaults for Node.js #####

Expand Down
7 changes: 3 additions & 4 deletions deps/v8/include/v8-script.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,9 @@ class V8_EXPORT ModuleRequest : public Data {
*
* All assertions present in the module request will be supplied in this
* list, regardless of whether they are supported by the host. Per
* https://tc39.es/proposal-import-assertions/#sec-hostgetsupportedimportassertions,
* hosts are expected to ignore assertions that they do not support (as
* opposed to, for example, triggering an error if an unsupported assertion is
* present).
* https://tc39.es/proposal-import-attributes/#sec-hostgetsupportedimportattributes,
* hosts are expected to throw for assertions that they do not support (as
* opposed to, for example, ignoring them).
*/
Local<FixedArray> GetImportAssertions() const;

Expand Down
48 changes: 36 additions & 12 deletions deps/v8/src/execution/isolate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5156,7 +5156,8 @@ MaybeHandle<FixedArray> Isolate::GetImportAssertionsFromArgument(

// The parser shouldn't have allowed the second argument to import() if
// the flag wasn't enabled.
DCHECK(v8_flags.harmony_import_assertions);
DCHECK(v8_flags.harmony_import_assertions ||
v8_flags.harmony_import_attributes);

if (!import_assertions_argument->IsJSReceiver()) {
this->Throw(
Expand All @@ -5166,18 +5167,35 @@ MaybeHandle<FixedArray> Isolate::GetImportAssertionsFromArgument(

Handle<JSReceiver> import_assertions_argument_receiver =
Handle<JSReceiver>::cast(import_assertions_argument);
Handle<Name> key = factory()->assert_string();

Handle<Object> import_assertions_object;
if (!JSReceiver::GetProperty(this, import_assertions_argument_receiver, key)
.ToHandle(&import_assertions_object)) {
// This can happen if the property has a getter function that throws
// an error.
return MaybeHandle<FixedArray>();

if (v8_flags.harmony_import_attributes) {
Handle<Name> with_key = factory()->with_string();
if (!JSReceiver::GetProperty(this, import_assertions_argument_receiver,
with_key)
.ToHandle(&import_assertions_object)) {
// This can happen if the property has a getter function that throws
// an error.
return MaybeHandle<FixedArray>();
}
}

// If there is no 'assert' option in the options bag, it's not an error. Just
// do the import() as if no assertions were provided.
if (v8_flags.harmony_import_assertions &&
(!v8_flags.harmony_import_attributes ||
import_assertions_object->IsUndefined())) {
Handle<Name> assert_key = factory()->assert_string();
if (!JSReceiver::GetProperty(this, import_assertions_argument_receiver,
assert_key)
.ToHandle(&import_assertions_object)) {
// This can happen if the property has a getter function that throws
// an error.
return MaybeHandle<FixedArray>();
}
}

// If there is no 'with' or 'assert' option in the options bag, it's not an
// error. Just do the import() as if no assertions were provided.
if (import_assertions_object->IsUndefined()) return import_assertions_array;

if (!import_assertions_object->IsJSReceiver()) {
Expand All @@ -5199,6 +5217,8 @@ MaybeHandle<FixedArray> Isolate::GetImportAssertionsFromArgument(
return MaybeHandle<FixedArray>();
}

bool has_non_string_attribute = false;

// The assertions will be passed to the host in the form: [key1,
// value1, key2, value2, ...].
constexpr size_t kAssertionEntrySizeForDynamicImport = 2;
Expand All @@ -5216,9 +5236,7 @@ MaybeHandle<FixedArray> Isolate::GetImportAssertionsFromArgument(
}

if (!assertion_value->IsString()) {
this->Throw(*factory()->NewTypeError(
MessageTemplate::kNonStringImportAssertionValue));
return MaybeHandle<FixedArray>();
has_non_string_attribute = true;
}

import_assertions_array->set((i * kAssertionEntrySizeForDynamicImport),
Expand All @@ -5227,6 +5245,12 @@ MaybeHandle<FixedArray> Isolate::GetImportAssertionsFromArgument(
*assertion_value);
}

if (has_non_string_attribute) {
this->Throw(*factory()->NewTypeError(
MessageTemplate::kNonStringImportAssertionValue));
return MaybeHandle<FixedArray>();
}

return import_assertions_array;
}

Expand Down
1 change: 1 addition & 0 deletions deps/v8/src/flags/flag-definitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ DEFINE_BOOL(harmony_shipping, true, "enable all shipped harmony features")

// Features that are still work in progress (behind individual flags).
#define HARMONY_INPROGRESS_BASE(V) \
V(harmony_import_attributes, "harmony import attributes") \
V(harmony_weak_refs_with_cleanup_some, \
"harmony weak references with FinalizationRegistry.prototype.cleanupSome") \
V(harmony_temporal, "Temporal") \
Expand Down
1 change: 1 addition & 0 deletions deps/v8/src/init/bootstrapper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4523,6 +4523,7 @@ void Genesis::InitializeConsole(Handle<JSObject> extras_binding) {
void Genesis::InitializeGlobal_##id() {}

EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_import_assertions)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_import_attributes)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_symbol_as_weakmap_key)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_rab_gsab_transfer)

Expand Down
1 change: 1 addition & 0 deletions deps/v8/src/init/heap-symbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,7 @@
V(_, week_string, "week") \
V(_, weeks_string, "weeks") \
V(_, weekOfYear_string, "weekOfYear") \
V(_, with_string, "with") \
V(_, word_string, "word") \
V(_, yearMonthFromFields_string, "yearMonthFromFields") \
V(_, year_string, "year") \
Expand Down
4 changes: 3 additions & 1 deletion deps/v8/src/parsing/parser-base.h
Original file line number Diff line number Diff line change
Expand Up @@ -3774,7 +3774,9 @@ ParserBase<Impl>::ParseImportExpressions() {
AcceptINScope scope(this, true);
ExpressionT specifier = ParseAssignmentExpressionCoverGrammar();

if (v8_flags.harmony_import_assertions && Check(Token::COMMA)) {
if ((v8_flags.harmony_import_assertions ||
v8_flags.harmony_import_attributes) &&
Check(Token::COMMA)) {
if (Check(Token::RPAREN)) {
// A trailing comma allowed after the specifier.
return factory()->NewImportCallExpression(specifier, pos);
Expand Down
39 changes: 22 additions & 17 deletions deps/v8/src/parsing/parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1344,36 +1344,41 @@ ZonePtrList<const Parser::NamedImport>* Parser::ParseNamedImports(int pos) {
}

ImportAssertions* Parser::ParseImportAssertClause() {
// AssertClause :
// assert '{' '}'
// assert '{' AssertEntries '}'
// WithClause :
// with '{' '}'
// with '{' WithEntries ','? '}'

// AssertEntries :
// IdentifierName: AssertionKey
// IdentifierName: AssertionKey , AssertEntries
// WithEntries :
// LiteralPropertyName
// LiteralPropertyName ':' StringLiteral , WithEntries

// AssertionKey :
// IdentifierName
// StringLiteral
// (DEPRECATED)
// AssertClause :
// assert '{' '}'
// assert '{' WithEntries ','? '}'

auto import_assertions = zone()->New<ImportAssertions>(zone());

if (!v8_flags.harmony_import_assertions) {
return import_assertions;
}

// Assert clause is optional, and cannot be preceded by a LineTerminator.
if (scanner()->HasLineTerminatorBeforeNext() ||
!CheckContextualKeyword(ast_value_factory()->assert_string())) {
if (v8_flags.harmony_import_attributes && Check(Token::WITH)) {
// 'with' keyword consumed
} else if (v8_flags.harmony_import_assertions &&
!scanner()->HasLineTerminatorBeforeNext() &&
CheckContextualKeyword(ast_value_factory()->assert_string())) {
// 'assert' keyword consumed
} else {
return import_assertions;
}

Expect(Token::LBRACE);

while (peek() != Token::RBRACE) {
const AstRawString* attribute_key = nullptr;
if (Check(Token::STRING)) {
if (Check(Token::STRING) || Check(Token::SMI)) {
attribute_key = GetSymbol();
} else if (Check(Token::NUMBER)) {
attribute_key = GetNumberAsSymbol();
} else if (Check(Token::BIGINT)) {
attribute_key = GetBigIntAsSymbol();
} else {
attribute_key = ParsePropertyName();
}
Expand Down
146 changes: 74 additions & 72 deletions deps/v8/src/roots/static-roots.h
Original file line number Diff line number Diff line change
Expand Up @@ -693,82 +693,83 @@ struct StaticReadOnlyRoot {
static constexpr Tagged_t kweek_string = 0x5a55;
static constexpr Tagged_t kweeks_string = 0x5a65;
static constexpr Tagged_t kweekOfYear_string = 0x5a79;
static constexpr Tagged_t kword_string = 0x5a91;
static constexpr Tagged_t kyearMonthFromFields_string = 0x5aa1;
static constexpr Tagged_t kyear_string = 0x5ac1;
static constexpr Tagged_t kyears_string = 0x5ad1;
static constexpr Tagged_t kUninitializedValue = 0x5af5;
static constexpr Tagged_t kArgumentsMarker = 0x5b2d;
static constexpr Tagged_t kTerminationException = 0x5b65;
static constexpr Tagged_t kException = 0x5ba5;
static constexpr Tagged_t kOptimizedOut = 0x5bc1;
static constexpr Tagged_t kStaleRegister = 0x5bf9;
static constexpr Tagged_t kSelfReferenceMarker = 0x5c31;
static constexpr Tagged_t kBasicBlockCountersMarker = 0x5c71;
static constexpr Tagged_t karray_buffer_wasm_memory_symbol = 0x5cb5;
static constexpr Tagged_t kcall_site_info_symbol = 0x5cc5;
static constexpr Tagged_t kconsole_context_id_symbol = 0x5cd5;
static constexpr Tagged_t kconsole_context_name_symbol = 0x5ce5;
static constexpr Tagged_t kclass_fields_symbol = 0x5cf5;
static constexpr Tagged_t kclass_positions_symbol = 0x5d05;
static constexpr Tagged_t kerror_end_pos_symbol = 0x5d15;
static constexpr Tagged_t kerror_script_symbol = 0x5d25;
static constexpr Tagged_t kerror_stack_symbol = 0x5d35;
static constexpr Tagged_t kerror_start_pos_symbol = 0x5d45;
static constexpr Tagged_t kfrozen_symbol = 0x5d55;
static constexpr Tagged_t kinterpreter_trampoline_symbol = 0x5d65;
static constexpr Tagged_t knative_context_index_symbol = 0x5d75;
static constexpr Tagged_t knonextensible_symbol = 0x5d85;
static constexpr Tagged_t kpromise_debug_marker_symbol = 0x5d95;
static constexpr Tagged_t kpromise_debug_message_symbol = 0x5da5;
static constexpr Tagged_t kpromise_forwarding_handler_symbol = 0x5db5;
static constexpr Tagged_t kpromise_handled_by_symbol = 0x5dc5;
static constexpr Tagged_t kpromise_awaited_by_symbol = 0x5dd5;
static constexpr Tagged_t kregexp_result_names_symbol = 0x5de5;
static constexpr Tagged_t kregexp_result_regexp_input_symbol = 0x5df5;
static constexpr Tagged_t kregexp_result_regexp_last_index_symbol = 0x5e05;
static constexpr Tagged_t ksealed_symbol = 0x5e15;
static constexpr Tagged_t kstrict_function_transition_symbol = 0x5e25;
static constexpr Tagged_t kwith_string = 0x5a91;
static constexpr Tagged_t kword_string = 0x5aa1;
static constexpr Tagged_t kyearMonthFromFields_string = 0x5ab1;
static constexpr Tagged_t kyear_string = 0x5ad1;
static constexpr Tagged_t kyears_string = 0x5ae1;
static constexpr Tagged_t kUninitializedValue = 0x5b05;
static constexpr Tagged_t kArgumentsMarker = 0x5b3d;
static constexpr Tagged_t kTerminationException = 0x5b75;
static constexpr Tagged_t kException = 0x5bb5;
static constexpr Tagged_t kOptimizedOut = 0x5bd1;
static constexpr Tagged_t kStaleRegister = 0x5c09;
static constexpr Tagged_t kSelfReferenceMarker = 0x5c41;
static constexpr Tagged_t kBasicBlockCountersMarker = 0x5c81;
static constexpr Tagged_t karray_buffer_wasm_memory_symbol = 0x5cc5;
static constexpr Tagged_t kcall_site_info_symbol = 0x5cd5;
static constexpr Tagged_t kconsole_context_id_symbol = 0x5ce5;
static constexpr Tagged_t kconsole_context_name_symbol = 0x5cf5;
static constexpr Tagged_t kclass_fields_symbol = 0x5d05;
static constexpr Tagged_t kclass_positions_symbol = 0x5d15;
static constexpr Tagged_t kerror_end_pos_symbol = 0x5d25;
static constexpr Tagged_t kerror_script_symbol = 0x5d35;
static constexpr Tagged_t kerror_stack_symbol = 0x5d45;
static constexpr Tagged_t kerror_start_pos_symbol = 0x5d55;
static constexpr Tagged_t kfrozen_symbol = 0x5d65;
static constexpr Tagged_t kinterpreter_trampoline_symbol = 0x5d75;
static constexpr Tagged_t knative_context_index_symbol = 0x5d85;
static constexpr Tagged_t knonextensible_symbol = 0x5d95;
static constexpr Tagged_t kpromise_debug_marker_symbol = 0x5da5;
static constexpr Tagged_t kpromise_debug_message_symbol = 0x5db5;
static constexpr Tagged_t kpromise_forwarding_handler_symbol = 0x5dc5;
static constexpr Tagged_t kpromise_handled_by_symbol = 0x5dd5;
static constexpr Tagged_t kpromise_awaited_by_symbol = 0x5de5;
static constexpr Tagged_t kregexp_result_names_symbol = 0x5df5;
static constexpr Tagged_t kregexp_result_regexp_input_symbol = 0x5e05;
static constexpr Tagged_t kregexp_result_regexp_last_index_symbol = 0x5e15;
static constexpr Tagged_t ksealed_symbol = 0x5e25;
static constexpr Tagged_t kstrict_function_transition_symbol = 0x5e35;
static constexpr Tagged_t ktemplate_literal_function_literal_id_symbol =
0x5e35;
static constexpr Tagged_t ktemplate_literal_slot_id_symbol = 0x5e45;
static constexpr Tagged_t kwasm_exception_tag_symbol = 0x5e55;
static constexpr Tagged_t kwasm_exception_values_symbol = 0x5e65;
static constexpr Tagged_t kwasm_uncatchable_symbol = 0x5e75;
static constexpr Tagged_t kwasm_wrapped_object_symbol = 0x5e85;
static constexpr Tagged_t kwasm_debug_proxy_cache_symbol = 0x5e95;
static constexpr Tagged_t kwasm_debug_proxy_names_symbol = 0x5ea5;
static constexpr Tagged_t kasync_iterator_symbol = 0x5eb5;
static constexpr Tagged_t kintl_fallback_symbol = 0x5ee5;
static constexpr Tagged_t kmatch_all_symbol = 0x5f1d;
static constexpr Tagged_t kmatch_symbol = 0x5f49;
static constexpr Tagged_t ksearch_symbol = 0x5f71;
static constexpr Tagged_t ksplit_symbol = 0x5f9d;
static constexpr Tagged_t kto_primitive_symbol = 0x5fc5;
static constexpr Tagged_t kunscopables_symbol = 0x5ff5;
static constexpr Tagged_t khas_instance_symbol = 0x6025;
static constexpr Tagged_t kto_string_tag_symbol = 0x6055;
static constexpr Tagged_t kconstructor_string = 0x60ad;
static constexpr Tagged_t knext_string = 0x60c5;
static constexpr Tagged_t kresolve_string = 0x60d5;
static constexpr Tagged_t kthen_string = 0x60e9;
static constexpr Tagged_t kiterator_symbol = 0x60f9;
static constexpr Tagged_t kreplace_symbol = 0x6109;
static constexpr Tagged_t kspecies_symbol = 0x6119;
static constexpr Tagged_t kis_concat_spreadable_symbol = 0x6129;
static constexpr Tagged_t kEmptySlowElementDictionary = 0x6139;
static constexpr Tagged_t kEmptySymbolTable = 0x615d;
static constexpr Tagged_t kEmptyOrderedHashMap = 0x6179;
static constexpr Tagged_t kEmptyOrderedHashSet = 0x618d;
static constexpr Tagged_t kEmptyFeedbackMetadata = 0x61a1;
static constexpr Tagged_t kGlobalThisBindingScopeInfo = 0x61ad;
static constexpr Tagged_t kEmptyFunctionScopeInfo = 0x61cd;
static constexpr Tagged_t kNativeScopeInfo = 0x61f1;
static constexpr Tagged_t kShadowRealmScopeInfo = 0x6209;
0x5e45;
static constexpr Tagged_t ktemplate_literal_slot_id_symbol = 0x5e55;
static constexpr Tagged_t kwasm_exception_tag_symbol = 0x5e65;
static constexpr Tagged_t kwasm_exception_values_symbol = 0x5e75;
static constexpr Tagged_t kwasm_uncatchable_symbol = 0x5e85;
static constexpr Tagged_t kwasm_wrapped_object_symbol = 0x5e95;
static constexpr Tagged_t kwasm_debug_proxy_cache_symbol = 0x5ea5;
static constexpr Tagged_t kwasm_debug_proxy_names_symbol = 0x5eb5;
static constexpr Tagged_t kasync_iterator_symbol = 0x5ec5;
static constexpr Tagged_t kintl_fallback_symbol = 0x5ef5;
static constexpr Tagged_t kmatch_all_symbol = 0x5f2d;
static constexpr Tagged_t kmatch_symbol = 0x5f59;
static constexpr Tagged_t ksearch_symbol = 0x5f81;
static constexpr Tagged_t ksplit_symbol = 0x5fad;
static constexpr Tagged_t kto_primitive_symbol = 0x5fd5;
static constexpr Tagged_t kunscopables_symbol = 0x6005;
static constexpr Tagged_t khas_instance_symbol = 0x6035;
static constexpr Tagged_t kto_string_tag_symbol = 0x6065;
static constexpr Tagged_t kconstructor_string = 0x60bd;
static constexpr Tagged_t knext_string = 0x60d5;
static constexpr Tagged_t kresolve_string = 0x60e5;
static constexpr Tagged_t kthen_string = 0x60f9;
static constexpr Tagged_t kiterator_symbol = 0x6109;
static constexpr Tagged_t kreplace_symbol = 0x6119;
static constexpr Tagged_t kspecies_symbol = 0x6129;
static constexpr Tagged_t kis_concat_spreadable_symbol = 0x6139;
static constexpr Tagged_t kEmptySlowElementDictionary = 0x6149;
static constexpr Tagged_t kEmptySymbolTable = 0x616d;
static constexpr Tagged_t kEmptyOrderedHashMap = 0x6189;
static constexpr Tagged_t kEmptyOrderedHashSet = 0x619d;
static constexpr Tagged_t kEmptyFeedbackMetadata = 0x61b1;
static constexpr Tagged_t kGlobalThisBindingScopeInfo = 0x61bd;
static constexpr Tagged_t kEmptyFunctionScopeInfo = 0x61dd;
static constexpr Tagged_t kNativeScopeInfo = 0x6201;
static constexpr Tagged_t kShadowRealmScopeInfo = 0x6219;
static constexpr Tagged_t kWasmNull = 0xfffd;
};

static constexpr std::array<Tagged_t, 738> StaticReadOnlyRootsPointerTable = {
static constexpr std::array<Tagged_t, 739> StaticReadOnlyRootsPointerTable = {
StaticReadOnlyRoot::kFreeSpaceMap,
StaticReadOnlyRoot::kOnePointerFillerMap,
StaticReadOnlyRoot::kTwoPointerFillerMap,
Expand Down Expand Up @@ -1365,6 +1366,7 @@ static constexpr std::array<Tagged_t, 738> StaticReadOnlyRootsPointerTable = {
StaticReadOnlyRoot::kweek_string,
StaticReadOnlyRoot::kweeks_string,
StaticReadOnlyRoot::kweekOfYear_string,
StaticReadOnlyRoot::kwith_string,
StaticReadOnlyRoot::kword_string,
StaticReadOnlyRoot::kyearMonthFromFields_string,
StaticReadOnlyRoot::kyear_string,
Expand Down
9 changes: 9 additions & 0 deletions deps/v8/test/mjsunit/harmony/modules-import-attributes-1.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Flags: --harmony-import-attributes

import { life } from 'modules-skip-1.mjs' with { };

assertEquals(42, life());
9 changes: 9 additions & 0 deletions deps/v8/test/mjsunit/harmony/modules-import-attributes-2.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Flags: --harmony-import-attributes

import json from 'modules-skip-1.json' with { type: 'json' };

assertEquals(42, json.life);
9 changes: 9 additions & 0 deletions deps/v8/test/mjsunit/harmony/modules-import-attributes-3.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Flags: --harmony-import-attributes

import {life} from 'modules-skip-imports-json-1.mjs';

assertEquals(42, life());
Loading

0 comments on commit 16fd730

Please sign in to comment.