From 115baa7e32ba30cc409d52546a78ee97a9cd4f76 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Sat, 7 Jan 2023 12:24:05 -0500 Subject: [PATCH] LibJS+Everywhere: Make PrimitiveString and Utf16String fallible This makes construction of Utf16String fallible in OOM conditions. The immediate impact is that PrimitiveString must then be fallible as well, as it may either transcode UTF-8 to UTF-16, or create a UTF-16 string from ropes. There are a couple of places where it is very non-trivial to propagate the error further. A FIXME has been added to those locations. --- Tests/LibJS/test-js.cpp | 6 +- .../Spreadsheet/JSIntegration.cpp | 16 +-- Userland/Libraries/LibJS/AST.cpp | 2 +- Userland/Libraries/LibJS/Console.cpp | 2 +- .../LibJS/Contrib/Test262/IsHTMLDDA.cpp | 2 +- Userland/Libraries/LibJS/Print.cpp | 6 +- .../LibJS/Runtime/AbstractOperations.cpp | 2 +- .../LibJS/Runtime/DateConstructor.cpp | 2 +- .../Libraries/LibJS/Runtime/DatePrototype.cpp | 2 +- .../Libraries/LibJS/Runtime/GlobalObject.cpp | 2 +- .../LibJS/Runtime/Intl/AbstractOperations.cpp | 6 +- .../LibJS/Runtime/Intl/AbstractOperations.h | 2 +- .../Runtime/Intl/CollatorConstructor.cpp | 12 +-- .../LibJS/Runtime/Intl/DateTimeFormat.cpp | 2 +- .../Intl/DateTimeFormatConstructor.cpp | 20 ++-- .../Runtime/Intl/DisplayNamesConstructor.cpp | 10 +- .../Runtime/Intl/DisplayNamesPrototype.cpp | 24 ++--- .../LibJS/Runtime/Intl/DurationFormat.cpp | 4 +- .../Intl/DurationFormatConstructor.cpp | 10 +- .../LibJS/Runtime/Intl/ListFormat.cpp | 2 +- .../Runtime/Intl/ListFormatConstructor.cpp | 6 +- .../LibJS/Runtime/Intl/LocaleConstructor.cpp | 4 +- .../LibJS/Runtime/Intl/NumberFormat.cpp | 2 +- .../Runtime/Intl/NumberFormatConstructor.cpp | 38 +++---- .../Runtime/Intl/PluralRulesConstructor.cpp | 4 +- .../Intl/RelativeTimeFormatConstructor.cpp | 10 +- .../Runtime/Intl/SegmentIteratorPrototype.cpp | 2 +- .../LibJS/Runtime/Intl/Segmenter.cpp | 6 +- .../Libraries/LibJS/Runtime/Intl/Segmenter.h | 2 +- .../Runtime/Intl/SegmenterConstructor.cpp | 4 +- .../LibJS/Runtime/Intl/SegmentsPrototype.cpp | 2 +- .../Libraries/LibJS/Runtime/JSONObject.cpp | 10 +- Userland/Libraries/LibJS/Runtime/Object.cpp | 2 +- .../LibJS/Runtime/ObjectPrototype.cpp | 2 +- .../LibJS/Runtime/PrimitiveString.cpp | 100 +++++++++--------- .../Libraries/LibJS/Runtime/PrimitiveString.h | 25 +++-- .../Libraries/LibJS/Runtime/Reference.cpp | 2 +- .../Runtime/RegExpLegacyStaticProperties.cpp | 42 ++++---- .../Runtime/RegExpLegacyStaticProperties.h | 2 +- .../LibJS/Runtime/RegExpPrototype.cpp | 12 +-- .../Libraries/LibJS/Runtime/ShadowRealm.cpp | 4 +- .../LibJS/Runtime/ShadowRealmPrototype.cpp | 4 +- .../LibJS/Runtime/StringConstructor.cpp | 4 +- .../Libraries/LibJS/Runtime/StringObject.cpp | 20 ++-- .../LibJS/Runtime/StringPrototype.cpp | 16 +-- .../Runtime/Temporal/AbstractOperations.cpp | 20 ++-- .../LibJS/Runtime/Temporal/Calendar.cpp | 8 +- .../Runtime/Temporal/CalendarPrototype.cpp | 8 +- .../Temporal/ZonedDateTimePrototype.cpp | 2 +- .../Libraries/LibJS/Runtime/Utf16String.cpp | 45 ++++---- .../Libraries/LibJS/Runtime/Utf16String.h | 18 ++-- Userland/Libraries/LibJS/Runtime/Value.cpp | 25 ++--- .../Libraries/LibJS/Runtime/ValueTraits.h | 6 +- Userland/Libraries/LibWeb/Fetch/Body.cpp | 2 +- Userland/Libraries/LibWeb/Infra/JSON.cpp | 2 +- .../WebAssemblyTableConstructor.cpp | 2 +- .../LibWeb/WebDriver/ExecuteScript.cpp | 4 +- 57 files changed, 306 insertions(+), 295 deletions(-) diff --git a/Tests/LibJS/test-js.cpp b/Tests/LibJS/test-js.cpp index 719217318c..d88214b2e4 100644 --- a/Tests/LibJS/test-js.cpp +++ b/Tests/LibJS/test-js.cpp @@ -62,14 +62,14 @@ TESTJS_GLOBAL_FUNCTION(mark_as_garbage, markAsGarbage) return execution_context->lexical_environment != nullptr; }); if (!outer_environment.has_value()) - return vm.throw_completion(JS::ErrorType::UnknownIdentifier, variable_name.deprecated_string()); + return vm.throw_completion(JS::ErrorType::UnknownIdentifier, TRY(variable_name.deprecated_string())); - auto reference = TRY(vm.resolve_binding(variable_name.deprecated_string(), outer_environment.value()->lexical_environment)); + auto reference = TRY(vm.resolve_binding(TRY(variable_name.deprecated_string()), outer_environment.value()->lexical_environment)); auto value = TRY(reference.get_value(vm)); if (!can_be_held_weakly(value)) - return vm.throw_completion(JS::ErrorType::CannotBeHeldWeakly, DeprecatedString::formatted("Variable with name {}", variable_name.deprecated_string())); + return vm.throw_completion(JS::ErrorType::CannotBeHeldWeakly, DeprecatedString::formatted("Variable with name {}", TRY(variable_name.deprecated_string()))); vm.heap().uproot_cell(&value.as_cell()); TRY(reference.delete_(vm)); diff --git a/Userland/Applications/Spreadsheet/JSIntegration.cpp b/Userland/Applications/Spreadsheet/JSIntegration.cpp index 57dbb2b712..c52b9f9de2 100644 --- a/Userland/Applications/Spreadsheet/JSIntegration.cpp +++ b/Userland/Applications/Spreadsheet/JSIntegration.cpp @@ -196,7 +196,7 @@ JS_DEFINE_NATIVE_FUNCTION(SheetGlobalObject::get_real_cell_contents) auto name_value = vm.argument(0); if (!name_value.is_string()) return vm.throw_completion("Expected a String argument to get_real_cell_contents()"); - auto position = sheet_object->m_sheet.parse_cell_name(name_value.as_string().deprecated_string()); + auto position = sheet_object->m_sheet.parse_cell_name(TRY(name_value.as_string().deprecated_string())); if (!position.has_value()) return vm.throw_completion("Invalid cell name"); @@ -225,7 +225,7 @@ JS_DEFINE_NATIVE_FUNCTION(SheetGlobalObject::set_real_cell_contents) auto name_value = vm.argument(0); if (!name_value.is_string()) return vm.throw_completion("Expected the first argument of set_real_cell_contents() to be a String"); - auto position = sheet_object->m_sheet.parse_cell_name(name_value.as_string().deprecated_string()); + auto position = sheet_object->m_sheet.parse_cell_name(TRY(name_value.as_string().deprecated_string())); if (!position.has_value()) return vm.throw_completion("Invalid cell name"); @@ -234,7 +234,7 @@ JS_DEFINE_NATIVE_FUNCTION(SheetGlobalObject::set_real_cell_contents) return vm.throw_completion("Expected the second argument of set_real_cell_contents() to be a String"); auto& cell = sheet_object->m_sheet.ensure(position.value()); - auto& new_contents = new_contents_value.as_string().deprecated_string(); + auto const& new_contents = TRY(new_contents_value.as_string().deprecated_string()); cell.set_data(new_contents); return JS::js_null(); } @@ -255,7 +255,7 @@ JS_DEFINE_NATIVE_FUNCTION(SheetGlobalObject::parse_cell_name) auto name_value = vm.argument(0); if (!name_value.is_string()) return vm.throw_completion("Expected a String argument to parse_cell_name()"); - auto position = sheet_object->m_sheet.parse_cell_name(name_value.as_string().deprecated_string()); + auto position = sheet_object->m_sheet.parse_cell_name(TRY(name_value.as_string().deprecated_string())); if (!position.has_value()) return JS::js_undefined(); @@ -301,7 +301,7 @@ JS_DEFINE_NATIVE_FUNCTION(SheetGlobalObject::column_index) if (!column_name.is_string()) return vm.throw_completion(JS::ErrorType::NotAnObjectOfType, "String"); - auto& column_name_str = column_name.as_string().deprecated_string(); + auto const& column_name_str = TRY(column_name.as_string().deprecated_string()); auto* this_object = TRY(vm.this_value().to_object(vm)); @@ -326,7 +326,7 @@ JS_DEFINE_NATIVE_FUNCTION(SheetGlobalObject::column_arithmetic) if (!column_name.is_string()) return vm.throw_completion(JS::ErrorType::NotAnObjectOfType, "String"); - auto& column_name_str = column_name.as_string().deprecated_string(); + auto const& column_name_str = TRY(column_name.as_string().deprecated_string()); auto offset = TRY(vm.argument(1).to_number(vm)); auto offset_number = static_cast(offset.as_double()); @@ -354,7 +354,7 @@ JS_DEFINE_NATIVE_FUNCTION(SheetGlobalObject::get_column_bound) if (!column_name.is_string()) return vm.throw_completion(JS::ErrorType::NotAnObjectOfType, "String"); - auto& column_name_str = column_name.as_string().deprecated_string(); + auto const& column_name_str = TRY(column_name.as_string().deprecated_string()); auto* this_object = TRY(vm.this_value().to_object(vm)); if (!is(this_object)) @@ -405,7 +405,7 @@ JS_DEFINE_NATIVE_FUNCTION(WorkbookObject::sheet) auto& workbook = static_cast(this_object)->m_workbook; if (name_value.is_string()) { - auto& name = name_value.as_string().deprecated_string(); + auto const& name = TRY(name_value.as_string().deprecated_string()); for (auto& sheet : workbook.sheets()) { if (sheet.name() == name) return JS::Value(&sheet.global_object()); diff --git a/Userland/Libraries/LibJS/AST.cpp b/Userland/Libraries/LibJS/AST.cpp index 22d554b5c2..551c2e7a9b 100644 --- a/Userland/Libraries/LibJS/AST.cpp +++ b/Userland/Libraries/LibJS/AST.cpp @@ -3446,7 +3446,7 @@ Completion ImportCall::execute(Interpreter& interpreter) const // 4. If supportedAssertions contains key, then if (supported_assertions.contains_slow(property_key.to_string())) { // a. Append { [[Key]]: key, [[Value]]: value } to assertions. - assertions.empend(property_key.to_string(), value.as_string().deprecated_string()); + assertions.empend(property_key.to_string(), TRY(value.as_string().deprecated_string())); } } } diff --git a/Userland/Libraries/LibJS/Console.cpp b/Userland/Libraries/LibJS/Console.cpp index 14bb58acc8..69837cf1e8 100644 --- a/Userland/Libraries/LibJS/Console.cpp +++ b/Userland/Libraries/LibJS/Console.cpp @@ -212,7 +212,7 @@ ThrowCompletionOr Console::assert_() // 3. Otherwise: else { // 1. Let concat be the concatenation of message, U+003A (:), U+0020 SPACE, and first. - auto concat = PrimitiveString::create(vm, DeprecatedString::formatted("{}: {}", message->deprecated_string(), first.to_string(vm).value())); + auto concat = PrimitiveString::create(vm, DeprecatedString::formatted("{}: {}", TRY(message->deprecated_string()), first.to_string(vm).value())); // 2. Set data[0] to concat. data[0] = concat; } diff --git a/Userland/Libraries/LibJS/Contrib/Test262/IsHTMLDDA.cpp b/Userland/Libraries/LibJS/Contrib/Test262/IsHTMLDDA.cpp index 115972fbed..8162ddac34 100644 --- a/Userland/Libraries/LibJS/Contrib/Test262/IsHTMLDDA.cpp +++ b/Userland/Libraries/LibJS/Contrib/Test262/IsHTMLDDA.cpp @@ -20,7 +20,7 @@ ThrowCompletionOr IsHTMLDDA::call() auto& vm = this->vm(); if (vm.argument_count() == 0) return js_null(); - if (vm.argument(0).is_string() && vm.argument(0).as_string().deprecated_string().is_empty()) + if (vm.argument(0).is_string() && TRY(vm.argument(0).as_string().deprecated_string()).is_empty()) return js_null(); // Not sure if this really matters, INTERPRETING.md simply says: // * IsHTMLDDA - (present only in implementations that can provide it) an object that: diff --git a/Userland/Libraries/LibJS/Print.cpp b/Userland/Libraries/LibJS/Print.cpp index 6524ff9b98..0452a201e2 100644 --- a/Userland/Libraries/LibJS/Print.cpp +++ b/Userland/Libraries/LibJS/Print.cpp @@ -777,9 +777,13 @@ ErrorOr print_intl_segmenter(JS::PrintContext& print_context, JS::Intl::Se ErrorOr print_intl_segments(JS::PrintContext& print_context, JS::Intl::Segments const& segments, HashTable& seen_objects) { + auto segments_string = JS::Utf16String::create(segments.vm(), segments.segments_string()); + if (segments_string.is_error()) + return Error::from_errno(ENOMEM); + TRY(print_type(print_context, "Segments")); out("\n string: "); - TRY(print_value(print_context, JS::PrimitiveString::create(segments.vm(), segments.segments_string()), seen_objects)); + TRY(print_value(print_context, JS::PrimitiveString::create(segments.vm(), segments_string.release_value()), seen_objects)); out("\n segmenter: "); TRY(print_value(print_context, &segments.segments_segmenter(), seen_objects)); return {}; diff --git a/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp b/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp index cef3472432..7e49ef6f51 100644 --- a/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp +++ b/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp @@ -594,7 +594,7 @@ ThrowCompletionOr perform_eval(VM& vm, Value x, CallerMode strict_caller, .in_class_field_initializer = in_class_field_initializer, }; - Parser parser { Lexer { code_string.deprecated_string() }, Program::Type::Script, move(initial_state) }; + Parser parser { Lexer { TRY(code_string.deprecated_string()) }, Program::Type::Script, move(initial_state) }; auto program = parser.parse_program(strict_caller == CallerMode::Strict); // b. If script is a List of errors, throw a SyntaxError exception. diff --git a/Userland/Libraries/LibJS/Runtime/DateConstructor.cpp b/Userland/Libraries/LibJS/Runtime/DateConstructor.cpp index 607b0eb8b8..fd1b843739 100644 --- a/Userland/Libraries/LibJS/Runtime/DateConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/DateConstructor.cpp @@ -241,7 +241,7 @@ ThrowCompletionOr> DateConstructor::construct(FunctionObjec if (primitive.is_string()) { // 1. Assert: The next step never returns an abrupt completion because Type(v) is String. // 2. Let tv be the result of parsing v as a date, in exactly the same manner as for the parse method (21.4.3.2). - time_value = parse_date_string(primitive.as_string().deprecated_string()); + time_value = parse_date_string(TRY(primitive.as_string().deprecated_string())); } // iii. Else, else { diff --git a/Userland/Libraries/LibJS/Runtime/DatePrototype.cpp b/Userland/Libraries/LibJS/Runtime/DatePrototype.cpp index faadc9a06f..fe854aea78 100644 --- a/Userland/Libraries/LibJS/Runtime/DatePrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/DatePrototype.cpp @@ -1257,7 +1257,7 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::symbol_to_primitive) auto hint_value = vm.argument(0); if (!hint_value.is_string()) return vm.throw_completion(ErrorType::InvalidHint, hint_value.to_string_without_side_effects()); - auto& hint = hint_value.as_string().deprecated_string(); + auto const& hint = TRY(hint_value.as_string().deprecated_string()); Value::PreferredType try_first; if (hint == "string" || hint == "default") try_first = Value::PreferredType::String; diff --git a/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp b/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp index 10629f97dd..7115826205 100644 --- a/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp @@ -343,7 +343,7 @@ JS_DEFINE_NATIVE_FUNCTION(GlobalObject::eval) // 19.2.6.1.1 Encode ( string, unescapedSet ), https://tc39.es/ecma262/#sec-encode static ThrowCompletionOr encode(VM& vm, DeprecatedString const& string, StringView unescaped_set) { - auto utf16_string = Utf16String(string); + auto utf16_string = TRY(Utf16String::create(vm, string)); // 1. Let strLen be the length of string. auto string_length = utf16_string.length_in_code_units(); diff --git a/Userland/Libraries/LibJS/Runtime/Intl/AbstractOperations.cpp b/Userland/Libraries/LibJS/Runtime/Intl/AbstractOperations.cpp index 94d212e8d7..030490a8b4 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/AbstractOperations.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/AbstractOperations.cpp @@ -376,14 +376,14 @@ static auto& find_key_in_value(T& value, StringView key) } // 9.2.7 ResolveLocale ( availableLocales, requestedLocales, options, relevantExtensionKeys, localeData ), https://tc39.es/ecma402/#sec-resolvelocale -LocaleResult resolve_locale(Vector const& requested_locales, LocaleOptions const& options, Span relevant_extension_keys) +ThrowCompletionOr resolve_locale(Vector const& requested_locales, LocaleOptions const& options, Span relevant_extension_keys) { // 1. Let matcher be options.[[localeMatcher]]. auto const& matcher = options.locale_matcher; MatcherResult matcher_result; // 2. If matcher is "lookup", then - if (matcher.is_string() && (matcher.as_string().deprecated_string() == "lookup"sv)) { + if (matcher.is_string() && (TRY(matcher.as_string().deprecated_string()) == "lookup"sv)) { // a. Let r be ! LookupMatcher(availableLocales, requestedLocales). matcher_result = lookup_matcher(requested_locales); } @@ -578,7 +578,7 @@ ThrowCompletionOr supported_locales(VM& vm, Vector con Vector supported_locales; // 3. If matcher is "best fit", then - if (matcher.as_string().deprecated_string() == "best fit"sv) { + if (TRY(matcher.as_string().deprecated_string()) == "best fit"sv) { // a. Let supportedLocales be BestFitSupportedLocales(availableLocales, requestedLocales). supported_locales = best_fit_supported_locales(requested_locales); } diff --git a/Userland/Libraries/LibJS/Runtime/Intl/AbstractOperations.h b/Userland/Libraries/LibJS/Runtime/Intl/AbstractOperations.h index 03ee60e235..4850dee849 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/AbstractOperations.h +++ b/Userland/Libraries/LibJS/Runtime/Intl/AbstractOperations.h @@ -86,7 +86,7 @@ bool is_well_formed_unit_identifier(StringView unit_identifier); ThrowCompletionOr> canonicalize_locale_list(VM&, Value locales); Optional best_available_locale(StringView locale); DeprecatedString insert_unicode_extension_and_canonicalize(::Locale::LocaleID locale_id, ::Locale::LocaleExtension extension); -LocaleResult resolve_locale(Vector const& requested_locales, LocaleOptions const& options, Span relevant_extension_keys); +ThrowCompletionOr resolve_locale(Vector const& requested_locales, LocaleOptions const& options, Span relevant_extension_keys); Vector lookup_supported_locales(Vector const& requested_locales); Vector best_fit_supported_locales(Vector const& requested_locales); ThrowCompletionOr supported_locales(VM&, Vector const& requested_locales, Value options); diff --git a/Userland/Libraries/LibJS/Runtime/Intl/CollatorConstructor.cpp b/Userland/Libraries/LibJS/Runtime/Intl/CollatorConstructor.cpp index 46897f21f2..d538e1aced 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/CollatorConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/CollatorConstructor.cpp @@ -27,7 +27,7 @@ static ThrowCompletionOr initialize_collator(VM& vm, Collator& collat auto usage = TRY(get_option(vm, *options, vm.names.usage, OptionType::String, { "sort"sv, "search"sv }, "sort"sv)); // 4. Set collator.[[Usage]] to usage. - collator.set_usage(usage.as_string().deprecated_string()); + collator.set_usage(TRY(usage.as_string().deprecated_string())); // 5. If usage is "sort", then // a. Let localeData be %Collator%.[[SortLocaleData]]. @@ -49,11 +49,11 @@ static ThrowCompletionOr initialize_collator(VM& vm, Collator& collat // 11. If collation is not undefined, then if (!collation.is_undefined()) { // a. If collation does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception. - if (!::Locale::is_type_identifier(collation.as_string().deprecated_string())) + if (!::Locale::is_type_identifier(TRY(collation.as_string().deprecated_string()))) return vm.throw_completion(ErrorType::OptionIsNotValidValue, collation, "collation"sv); // 12. Set opt.[[co]] to collation. - opt.co = collation.as_string().deprecated_string(); + opt.co = TRY(collation.as_string().deprecated_string()); } // 13. Let numeric be ? GetOption(options, "numeric", "boolean", undefined, undefined). @@ -69,13 +69,13 @@ static ThrowCompletionOr initialize_collator(VM& vm, Collator& collat // 17. Set opt.[[kf]] to caseFirst. auto case_first = TRY(get_option(vm, *options, vm.names.caseFirst, OptionType::String, { "upper"sv, "lower"sv, "false"sv }, Empty {})); if (!case_first.is_undefined()) - opt.kf = case_first.as_string().deprecated_string(); + opt.kf = TRY(case_first.as_string().deprecated_string()); // 18. Let relevantExtensionKeys be %Collator%.[[RelevantExtensionKeys]]. auto relevant_extension_keys = Collator::relevant_extension_keys(); // 19. Let r be ResolveLocale(%Collator%.[[AvailableLocales]], requestedLocales, opt, relevantExtensionKeys, localeData). - auto result = resolve_locale(requested_locales, opt, relevant_extension_keys); + auto result = TRY(resolve_locale(requested_locales, opt, relevant_extension_keys)); // 20. Set collator.[[Locale]] to r.[[locale]]. collator.set_locale(move(result.locale)); @@ -117,7 +117,7 @@ static ThrowCompletionOr initialize_collator(VM& vm, Collator& collat } // 28. Set collator.[[Sensitivity]] to sensitivity. - collator.set_sensitivity(sensitivity.as_string().deprecated_string()); + collator.set_sensitivity(TRY(sensitivity.as_string().deprecated_string())); // 29. Let ignorePunctuation be ? GetOption(options, "ignorePunctuation", "boolean", undefined, false). auto ignore_punctuation = TRY(get_option(vm, *options, vm.names.ignorePunctuation, OptionType::Boolean, {}, false)); diff --git a/Userland/Libraries/LibJS/Runtime/Intl/DateTimeFormat.cpp b/Userland/Libraries/LibJS/Runtime/Intl/DateTimeFormat.cpp index 8f1f527b77..39dfbc2a42 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/DateTimeFormat.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/DateTimeFormat.cpp @@ -716,7 +716,7 @@ ThrowCompletionOr> format_date_time_pattern(VM& vm, Dat // 2. If the "length" property of fv is greater than 2, let fv be the substring of fv containing the last two characters. // NOTE: The first length check here isn't enough, but lets us avoid UTF-16 transcoding when the formatted value is ASCII. if (formatted_value.length() > 2) { - Utf16String utf16_formatted_value { formatted_value }; + auto utf16_formatted_value = TRY(Utf16String::create(vm, formatted_value)); if (utf16_formatted_value.length_in_code_units() > 2) formatted_value = TRY_OR_THROW_OOM(vm, utf16_formatted_value.substring_view(utf16_formatted_value.length_in_code_units() - 2).to_utf8()); } diff --git a/Userland/Libraries/LibJS/Runtime/Intl/DateTimeFormatConstructor.cpp b/Userland/Libraries/LibJS/Runtime/Intl/DateTimeFormatConstructor.cpp index 2dab5e6d9f..db56421082 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/DateTimeFormatConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/DateTimeFormatConstructor.cpp @@ -106,11 +106,11 @@ ThrowCompletionOr initialize_date_time_format(VM& vm, DateTimeF // 7. If calendar is not undefined, then if (!calendar.is_undefined()) { // a. If calendar does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception. - if (!::Locale::is_type_identifier(calendar.as_string().deprecated_string())) + if (!::Locale::is_type_identifier(TRY(calendar.as_string().deprecated_string()))) return vm.throw_completion(ErrorType::OptionIsNotValidValue, calendar, "calendar"sv); // 8. Set opt.[[ca]] to calendar. - opt.ca = calendar.as_string().deprecated_string(); + opt.ca = TRY(calendar.as_string().deprecated_string()); } // 9. Let numberingSystem be ? GetOption(options, "numberingSystem", "string", undefined, undefined). @@ -119,11 +119,11 @@ ThrowCompletionOr initialize_date_time_format(VM& vm, DateTimeF // 10. If numberingSystem is not undefined, then if (!numbering_system.is_undefined()) { // a. If numberingSystem does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception. - if (!::Locale::is_type_identifier(numbering_system.as_string().deprecated_string())) + if (!::Locale::is_type_identifier(TRY(numbering_system.as_string().deprecated_string()))) return vm.throw_completion(ErrorType::OptionIsNotValidValue, numbering_system, "numberingSystem"sv); // 11. Set opt.[[nu]] to numberingSystem. - opt.nu = numbering_system.as_string().deprecated_string(); + opt.nu = TRY(numbering_system.as_string().deprecated_string()); } // 12. Let hour12 be ? GetOption(options, "hour12", "boolean", undefined, undefined). @@ -140,11 +140,11 @@ ThrowCompletionOr initialize_date_time_format(VM& vm, DateTimeF // 15. Set opt.[[hc]] to hourCycle. if (!hour_cycle.is_nullish()) - opt.hc = hour_cycle.as_string().deprecated_string(); + opt.hc = TRY(hour_cycle.as_string().deprecated_string()); // 16. Let localeData be %DateTimeFormat%.[[LocaleData]]. // 17. Let r be ResolveLocale(%DateTimeFormat%.[[AvailableLocales]], requestedLocales, opt, %DateTimeFormat%.[[RelevantExtensionKeys]], localeData). - auto result = resolve_locale(requested_locales, opt, DateTimeFormat::relevant_extension_keys()); + auto result = TRY(resolve_locale(requested_locales, opt, DateTimeFormat::relevant_extension_keys())); // 18. Set dateTimeFormat.[[Locale]] to r.[[locale]]. date_time_format.set_locale(move(result.locale)); @@ -277,7 +277,7 @@ ThrowCompletionOr initialize_date_time_format(VM& vm, DateTimeF // d. Set formatOptions.[[]] to value. if (!value.is_undefined()) { - option = ::Locale::calendar_pattern_style_from_string(value.as_string().deprecated_string()); + option = ::Locale::calendar_pattern_style_from_string(TRY(value.as_string().deprecated_string())); // e. If value is not undefined, then // i. Set hasExplicitFormatComponents to true. @@ -296,14 +296,14 @@ ThrowCompletionOr initialize_date_time_format(VM& vm, DateTimeF // 39. Set dateTimeFormat.[[DateStyle]] to dateStyle. if (!date_style.is_undefined()) - date_time_format.set_date_style(date_style.as_string().deprecated_string()); + date_time_format.set_date_style(TRY(date_style.as_string().deprecated_string())); // 40. Let timeStyle be ? GetOption(options, "timeStyle", "string", « "full", "long", "medium", "short" », undefined). auto time_style = TRY(get_option(vm, *options, vm.names.timeStyle, OptionType::String, AK::Array { "full"sv, "long"sv, "medium"sv, "short"sv }, Empty {})); // 41. Set dateTimeFormat.[[TimeStyle]] to timeStyle. if (!time_style.is_undefined()) - date_time_format.set_time_style(time_style.as_string().deprecated_string()); + date_time_format.set_time_style(TRY(time_style.as_string().deprecated_string())); Optional<::Locale::CalendarPattern> best_format {}; @@ -325,7 +325,7 @@ ThrowCompletionOr initialize_date_time_format(VM& vm, DateTimeF auto formats = ::Locale::get_calendar_available_formats(data_locale, date_time_format.calendar()); // b. If matcher is "basic", then - if (matcher.as_string().deprecated_string() == "basic"sv) { + if (TRY(matcher.as_string().deprecated_string()) == "basic"sv) { // i. Let bestFormat be BasicFormatMatcher(formatOptions, formats). best_format = basic_format_matcher(format_options, move(formats)); } diff --git a/Userland/Libraries/LibJS/Runtime/Intl/DisplayNamesConstructor.cpp b/Userland/Libraries/LibJS/Runtime/Intl/DisplayNamesConstructor.cpp index 81a897fdc7..d44a0a0be4 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/DisplayNamesConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/DisplayNamesConstructor.cpp @@ -76,13 +76,13 @@ ThrowCompletionOr> DisplayNamesConstructor::construct(Funct opt.locale_matcher = matcher; // 10. Let r be ResolveLocale(%DisplayNames%.[[AvailableLocales]], requestedLocales, opt, %DisplayNames%.[[RelevantExtensionKeys]]). - auto result = resolve_locale(requested_locales, opt, {}); + auto result = TRY(resolve_locale(requested_locales, opt, {})); // 11. Let style be ? GetOption(options, "style", "string", « "narrow", "short", "long" », "long"). auto style = TRY(get_option(vm, *options, vm.names.style, OptionType::String, { "narrow"sv, "short"sv, "long"sv }, "long"sv)); // 12. Set displayNames.[[Style]] to style. - display_names->set_style(style.as_string().deprecated_string()); + display_names->set_style(TRY(style.as_string().deprecated_string())); // 13. Let type be ? GetOption(options, "type", "string", « "language", "region", "script", "currency", "calendar", "dateTimeField" », undefined). auto type = TRY(get_option(vm, *options, vm.names.type, OptionType::String, { "language"sv, "region"sv, "script"sv, "currency"sv, "calendar"sv, "dateTimeField"sv }, Empty {})); @@ -92,13 +92,13 @@ ThrowCompletionOr> DisplayNamesConstructor::construct(Funct return vm.throw_completion(ErrorType::IsUndefined, "options.type"sv); // 15. Set displayNames.[[Type]] to type. - display_names->set_type(type.as_string().deprecated_string()); + display_names->set_type(TRY(type.as_string().deprecated_string())); // 16. Let fallback be ? GetOption(options, "fallback", "string", « "code", "none" », "code"). auto fallback = TRY(get_option(vm, *options, vm.names.fallback, OptionType::String, { "code"sv, "none"sv }, "code"sv)); // 17. Set displayNames.[[Fallback]] to fallback. - display_names->set_fallback(fallback.as_string().deprecated_string()); + display_names->set_fallback(TRY(fallback.as_string().deprecated_string())); // 18. Set displayNames.[[Locale]] to r.[[locale]]. display_names->set_locale(move(result.locale)); @@ -119,7 +119,7 @@ ThrowCompletionOr> DisplayNamesConstructor::construct(Funct // 26. If type is "language", then if (display_names->type() == DisplayNames::Type::Language) { // a. Set displayNames.[[LanguageDisplay]] to languageDisplay. - display_names->set_language_display(language_display.as_string().deprecated_string()); + display_names->set_language_display(TRY(language_display.as_string().deprecated_string())); // b. Let typeFields be typeFields.[[]]. // c. Assert: typeFields is a Record (see 12.4.3). diff --git a/Userland/Libraries/LibJS/Runtime/Intl/DisplayNamesPrototype.cpp b/Userland/Libraries/LibJS/Runtime/Intl/DisplayNamesPrototype.cpp index 79450b62a3..2ad69c9abf 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/DisplayNamesPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/DisplayNamesPrototype.cpp @@ -47,7 +47,7 @@ JS_DEFINE_NATIVE_FUNCTION(DisplayNamesPrototype::of) code = PrimitiveString::create(vm, move(code_string)); // 4. Let code be ? CanonicalCodeForDisplayNames(displayNames.[[Type]], code). - code = TRY(canonical_code_for_display_names(vm, display_names->type(), code.as_string().deprecated_string())); + code = TRY(canonical_code_for_display_names(vm, display_names->type(), TRY(code.as_string().deprecated_string()))); // 5. Let fields be displayNames.[[Fields]]. // 6. If fields has a field [[]], return fields.[[]]. @@ -57,48 +57,48 @@ JS_DEFINE_NATIVE_FUNCTION(DisplayNamesPrototype::of) switch (display_names->type()) { case DisplayNames::Type::Language: if (display_names->language_display() == DisplayNames::LanguageDisplay::Dialect) { - result = ::Locale::get_locale_language_mapping(display_names->locale(), code.as_string().deprecated_string()); + result = ::Locale::get_locale_language_mapping(display_names->locale(), TRY(code.as_string().deprecated_string())); if (result.has_value()) break; } - if (auto locale = is_structurally_valid_language_tag(code.as_string().deprecated_string()); locale.has_value()) + if (auto locale = is_structurally_valid_language_tag(TRY(code.as_string().deprecated_string())); locale.has_value()) formatted_result = ::Locale::format_locale_for_display(display_names->locale(), locale.release_value()); break; case DisplayNames::Type::Region: - result = ::Locale::get_locale_territory_mapping(display_names->locale(), code.as_string().deprecated_string()); + result = ::Locale::get_locale_territory_mapping(display_names->locale(), TRY(code.as_string().deprecated_string())); break; case DisplayNames::Type::Script: - result = ::Locale::get_locale_script_mapping(display_names->locale(), code.as_string().deprecated_string()); + result = ::Locale::get_locale_script_mapping(display_names->locale(), TRY(code.as_string().deprecated_string())); break; case DisplayNames::Type::Currency: switch (display_names->style()) { case ::Locale::Style::Long: - result = ::Locale::get_locale_long_currency_mapping(display_names->locale(), code.as_string().deprecated_string()); + result = ::Locale::get_locale_long_currency_mapping(display_names->locale(), TRY(code.as_string().deprecated_string())); break; case ::Locale::Style::Short: - result = ::Locale::get_locale_short_currency_mapping(display_names->locale(), code.as_string().deprecated_string()); + result = ::Locale::get_locale_short_currency_mapping(display_names->locale(), TRY(code.as_string().deprecated_string())); break; case ::Locale::Style::Narrow: - result = ::Locale::get_locale_narrow_currency_mapping(display_names->locale(), code.as_string().deprecated_string()); + result = ::Locale::get_locale_narrow_currency_mapping(display_names->locale(), TRY(code.as_string().deprecated_string())); break; default: VERIFY_NOT_REACHED(); } break; case DisplayNames::Type::Calendar: - result = ::Locale::get_locale_calendar_mapping(display_names->locale(), code.as_string().deprecated_string()); + result = ::Locale::get_locale_calendar_mapping(display_names->locale(), TRY(code.as_string().deprecated_string())); break; case DisplayNames::Type::DateTimeField: switch (display_names->style()) { case ::Locale::Style::Long: - result = ::Locale::get_locale_long_date_field_mapping(display_names->locale(), code.as_string().deprecated_string()); + result = ::Locale::get_locale_long_date_field_mapping(display_names->locale(), TRY(code.as_string().deprecated_string())); break; case ::Locale::Style::Short: - result = ::Locale::get_locale_short_date_field_mapping(display_names->locale(), code.as_string().deprecated_string()); + result = ::Locale::get_locale_short_date_field_mapping(display_names->locale(), TRY(code.as_string().deprecated_string())); break; case ::Locale::Style::Narrow: - result = ::Locale::get_locale_narrow_date_field_mapping(display_names->locale(), code.as_string().deprecated_string()); + result = ::Locale::get_locale_narrow_date_field_mapping(display_names->locale(), TRY(code.as_string().deprecated_string())); break; default: VERIFY_NOT_REACHED(); diff --git a/Userland/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp b/Userland/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp index 59dd10be74..51d8d87f82 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp @@ -308,7 +308,7 @@ ThrowCompletionOr get_duration_unit_options(VM& vm, Depreca } } } else { - style = style_value.as_string().deprecated_string(); + style = TRY(style_value.as_string().deprecated_string()); } // 4. Let displayField be the string-concatenation of unit and "Display". @@ -332,7 +332,7 @@ ThrowCompletionOr get_duration_unit_options(VM& vm, Depreca } // 7. Return the Record { [[Style]]: style, [[Display]]: display }. - return DurationUnitOptions { .style = move(style), .display = display.as_string().deprecated_string() }; + return DurationUnitOptions { .style = move(style), .display = TRY(display.as_string().deprecated_string()) }; } // 1.1.7 PartitionDurationFormatPattern ( durationFormat, duration ), https://tc39.es/proposal-intl-duration-format/#sec-partitiondurationformatpattern diff --git a/Userland/Libraries/LibJS/Runtime/Intl/DurationFormatConstructor.cpp b/Userland/Libraries/LibJS/Runtime/Intl/DurationFormatConstructor.cpp index 4abb840f8c..ec4d8b5f60 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/DurationFormatConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/DurationFormatConstructor.cpp @@ -67,17 +67,17 @@ ThrowCompletionOr> DurationFormatConstructor::construct(Fun // 7. If numberingSystem is not undefined, then if (!numbering_system.is_undefined()) { // a. If numberingSystem does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception. - if (!::Locale::is_type_identifier(numbering_system.as_string().deprecated_string())) + if (!::Locale::is_type_identifier(TRY(numbering_system.as_string().deprecated_string()))) return vm.throw_completion(ErrorType::OptionIsNotValidValue, numbering_system, "numberingSystem"sv); } // 8. Let opt be the Record { [[localeMatcher]]: matcher, [[nu]]: numberingSystem }. LocaleOptions opt {}; opt.locale_matcher = matcher; - opt.nu = numbering_system.is_undefined() ? Optional() : numbering_system.as_string().deprecated_string(); + opt.nu = numbering_system.is_undefined() ? Optional() : TRY(numbering_system.as_string().deprecated_string()); // 9. Let r be ResolveLocale(%DurationFormat%.[[AvailableLocales]], requestedLocales, opt, %DurationFormat%.[[RelevantExtensionKeys]], %DurationFormat%.[[LocaleData]]). - auto result = resolve_locale(requested_locales, opt, DurationFormat::relevant_extension_keys()); + auto result = TRY(resolve_locale(requested_locales, opt, DurationFormat::relevant_extension_keys())); // 10. Let locale be r.[[locale]]. auto locale = move(result.locale); @@ -93,7 +93,7 @@ ThrowCompletionOr> DurationFormatConstructor::construct(Fun auto style = TRY(get_option(vm, *options, vm.names.style, OptionType::String, { "long"sv, "short"sv, "narrow"sv, "digital"sv }, "short"sv)); // 14. Set durationFormat.[[Style]] to style. - duration_format->set_style(style.as_string().deprecated_string()); + duration_format->set_style(TRY(style.as_string().deprecated_string())); // 15. Set durationFormat.[[DataLocale]] to r.[[dataLocale]]. duration_format->set_data_locale(move(result.data_locale)); @@ -119,7 +119,7 @@ ThrowCompletionOr> DurationFormatConstructor::construct(Fun auto digital_base = duration_instances_component.digital_default; // f. Let unitOptions be ? GetDurationUnitOptions(unit, options, style, valueList, digitalBase, prevStyle). - auto unit_options = TRY(get_duration_unit_options(vm, unit, *options, style.as_string().deprecated_string(), value_list, digital_base, previous_style)); + auto unit_options = TRY(get_duration_unit_options(vm, unit, *options, TRY(style.as_string().deprecated_string()), value_list, digital_base, previous_style)); // g. Set the value of the styleSlot slot of durationFormat to unitOptions.[[Style]]. (duration_format->*style_slot)(unit_options.style); diff --git a/Userland/Libraries/LibJS/Runtime/Intl/ListFormat.cpp b/Userland/Libraries/LibJS/Runtime/Intl/ListFormat.cpp index 8958b44112..ee0781f307 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/ListFormat.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/ListFormat.cpp @@ -274,7 +274,7 @@ ThrowCompletionOr> string_list_from_iterable(VM& vm, Va } // iii. Append nextValue to the end of the List list. - list.append(next_value.as_string().deprecated_string()); + list.append(TRY(next_value.as_string().deprecated_string())); } } while (next != nullptr); diff --git a/Userland/Libraries/LibJS/Runtime/Intl/ListFormatConstructor.cpp b/Userland/Libraries/LibJS/Runtime/Intl/ListFormatConstructor.cpp index e272feceed..5b5da0b83a 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/ListFormatConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/ListFormatConstructor.cpp @@ -71,7 +71,7 @@ ThrowCompletionOr> ListFormatConstructor::construct(Functio // 8. Let localeData be %ListFormat%.[[LocaleData]]. // 9. Let r be ResolveLocale(%ListFormat%.[[AvailableLocales]], requestedLocales, opt, %ListFormat%.[[RelevantExtensionKeys]], localeData). - auto result = resolve_locale(requested_locales, opt, {}); + auto result = TRY(resolve_locale(requested_locales, opt, {})); // 10. Set listFormat.[[Locale]] to r.[[locale]]. list_format->set_locale(move(result.locale)); @@ -80,13 +80,13 @@ ThrowCompletionOr> ListFormatConstructor::construct(Functio auto type = TRY(get_option(vm, *options, vm.names.type, OptionType::String, { "conjunction"sv, "disjunction"sv, "unit"sv }, "conjunction"sv)); // 12. Set listFormat.[[Type]] to type. - list_format->set_type(type.as_string().deprecated_string()); + list_format->set_type(TRY(type.as_string().deprecated_string())); // 13. Let style be ? GetOption(options, "style", "string", « "long", "short", "narrow" », "long"). auto style = TRY(get_option(vm, *options, vm.names.style, OptionType::String, { "long"sv, "short"sv, "narrow"sv }, "long"sv)); // 14. Set listFormat.[[Style]] to style. - list_format->set_style(style.as_string().deprecated_string()); + list_format->set_style(TRY(style.as_string().deprecated_string())); // Note: The remaining steps are skipped in favor of deferring to LibUnicode. diff --git a/Userland/Libraries/LibJS/Runtime/Intl/LocaleConstructor.cpp b/Userland/Libraries/LibJS/Runtime/Intl/LocaleConstructor.cpp index 957a35a4da..b764000fa1 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/LocaleConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/LocaleConstructor.cpp @@ -33,10 +33,10 @@ static ThrowCompletionOr> get_string_option(VM& vm, O if (option.is_undefined()) return Optional {}; - if (validator && !validator(option.as_string().deprecated_string())) + if (validator && !validator(TRY(option.as_string().deprecated_string()))) return vm.throw_completion(ErrorType::OptionIsNotValidValue, option, property); - return option.as_string().deprecated_string(); + return TRY(option.as_string().deprecated_string()); } // 14.1.2 ApplyOptionsToTag ( tag, options ), https://tc39.es/ecma402/#sec-apply-options-to-tag diff --git a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp index fe3ec38b00..2ef7f05645 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp @@ -1604,7 +1604,7 @@ ThrowCompletionOr to_intl_mathematical_value(VM& vm, Value va // 3. If Type(primValue) is String, // a. Let str be primValue. - auto const& string = primitive_value.as_string().deprecated_string(); + auto const& string = TRY(primitive_value.as_string().deprecated_string()); // Step 4 handled separately by the FIXME above. diff --git a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormatConstructor.cpp b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormatConstructor.cpp index 6a9dc66e13..dc4481cd9b 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormatConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormatConstructor.cpp @@ -103,16 +103,16 @@ ThrowCompletionOr initialize_number_format(VM& vm, NumberFormat& // 7. If numberingSystem is not undefined, then if (!numbering_system.is_undefined()) { // a. If numberingSystem does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception. - if (!::Locale::is_type_identifier(numbering_system.as_string().deprecated_string())) + if (!::Locale::is_type_identifier(TRY(numbering_system.as_string().deprecated_string()))) return vm.throw_completion(ErrorType::OptionIsNotValidValue, numbering_system, "numberingSystem"sv); // 8. Set opt.[[nu]] to numberingSystem. - opt.nu = numbering_system.as_string().deprecated_string(); + opt.nu = TRY(numbering_system.as_string().deprecated_string()); } // 9. Let localeData be %NumberFormat%.[[LocaleData]]. // 10. Let r be ResolveLocale(%NumberFormat%.[[AvailableLocales]], requestedLocales, opt, %NumberFormat%.[[RelevantExtensionKeys]], localeData). - auto result = resolve_locale(requested_locales, opt, NumberFormat::relevant_extension_keys()); + auto result = TRY(resolve_locale(requested_locales, opt, NumberFormat::relevant_extension_keys())); // 11. Set numberFormat.[[Locale]] to r.[[locale]]. number_format.set_locale(move(result.locale)); @@ -176,7 +176,7 @@ ThrowCompletionOr initialize_number_format(VM& vm, NumberFormat& auto notation = TRY(get_option(vm, *options, vm.names.notation, OptionType::String, { "standard"sv, "scientific"sv, "engineering"sv, "compact"sv }, "standard"sv)); // 22. Set numberFormat.[[Notation]] to notation. - number_format.set_notation(notation.as_string().deprecated_string()); + number_format.set_notation(TRY(notation.as_string().deprecated_string())); // 23. Perform ? SetNumberFormatDigitOptions(numberFormat, options, mnfdDefault, mxfdDefault, notation). TRY(set_number_format_digit_options(vm, number_format, *options, default_min_fraction_digits, default_max_fraction_digits, number_format.notation())); @@ -199,7 +199,7 @@ ThrowCompletionOr initialize_number_format(VM& vm, NumberFormat& auto trailing_zero_display = TRY(get_option(vm, *options, vm.names.trailingZeroDisplay, OptionType::String, { "auto"sv, "stripIfInteger"sv }, "auto"sv)); // 27. Set numberFormat.[[TrailingZeroDisplay]] to trailingZeroDisplay. - number_format.set_trailing_zero_display(trailing_zero_display.as_string().deprecated_string()); + number_format.set_trailing_zero_display(TRY(trailing_zero_display.as_string().deprecated_string())); // 28. Let compactDisplay be ? GetOption(options, "compactDisplay", "string", « "short", "long" », "short"). auto compact_display = TRY(get_option(vm, *options, vm.names.compactDisplay, OptionType::String, { "short"sv, "long"sv }, "short"sv)); @@ -210,7 +210,7 @@ ThrowCompletionOr initialize_number_format(VM& vm, NumberFormat& // 30. If notation is "compact", then if (number_format.notation() == NumberFormat::Notation::Compact) { // a. Set numberFormat.[[CompactDisplay]] to compactDisplay. - number_format.set_compact_display(compact_display.as_string().deprecated_string()); + number_format.set_compact_display(TRY(compact_display.as_string().deprecated_string())); // b. Set defaultUseGrouping to "min2". default_use_grouping = "min2"sv; @@ -226,13 +226,13 @@ ThrowCompletionOr initialize_number_format(VM& vm, NumberFormat& auto sign_display = TRY(get_option(vm, *options, vm.names.signDisplay, OptionType::String, { "auto"sv, "never"sv, "always"sv, "exceptZero"sv, "negative"sv }, "auto"sv)); // 34. Set numberFormat.[[SignDisplay]] to signDisplay. - number_format.set_sign_display(sign_display.as_string().deprecated_string()); + number_format.set_sign_display(TRY(sign_display.as_string().deprecated_string())); // 35. Let roundingMode be ? GetOption(options, "roundingMode", "string", « "ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor", "halfExpand", "halfTrunc", "halfEven" », "halfExpand"). auto rounding_mode = TRY(get_option(vm, *options, vm.names.roundingMode, OptionType::String, { "ceil"sv, "floor"sv, "expand"sv, "trunc"sv, "halfCeil"sv, "halfFloor"sv, "halfExpand"sv, "halfTrunc"sv, "halfEven"sv }, "halfExpand"sv)); // 36. Set numberFormat.[[RoundingMode]] to roundingMode. - number_format.set_rounding_mode(rounding_mode.as_string().deprecated_string()); + number_format.set_rounding_mode(TRY(rounding_mode.as_string().deprecated_string())); // 37. Return numberFormat. return &number_format; @@ -282,7 +282,7 @@ ThrowCompletionOr set_number_format_digit_options(VM& vm, NumberFormatBase bool need_fraction_digits = true; // 14. If roundingPriority is "auto", then - if (rounding_priority.as_string().deprecated_string() == "auto"sv) { + if (TRY(rounding_priority.as_string().deprecated_string()) == "auto"sv) { // a. Set needSd to hasSd. need_significant_digits = has_significant_digits; @@ -358,12 +358,12 @@ ThrowCompletionOr set_number_format_digit_options(VM& vm, NumberFormatBase // 17. If needSd is true or needFd is true, then if (need_significant_digits || need_fraction_digits) { // a. If roundingPriority is "morePrecision", then - if (rounding_priority.as_string().deprecated_string() == "morePrecision"sv) { + if (TRY(rounding_priority.as_string().deprecated_string()) == "morePrecision"sv) { // i. Set intlObj.[[RoundingType]] to morePrecision. intl_object.set_rounding_type(NumberFormatBase::RoundingType::MorePrecision); } // b. Else if roundingPriority is "lessPrecision", then - else if (rounding_priority.as_string().deprecated_string() == "lessPrecision"sv) { + else if (TRY(rounding_priority.as_string().deprecated_string()) == "lessPrecision"sv) { // i. Set intlObj.[[RoundingType]] to lessPrecision. intl_object.set_rounding_type(NumberFormatBase::RoundingType::LessPrecision); } @@ -410,7 +410,7 @@ ThrowCompletionOr set_number_format_unit_options(VM& vm, NumberFormat& int auto style = TRY(get_option(vm, options, vm.names.style, OptionType::String, { "decimal"sv, "percent"sv, "currency"sv, "unit"sv }, "decimal"sv)); // 4. Set intlObj.[[Style]] to style. - intl_object.set_style(style.as_string().deprecated_string()); + intl_object.set_style(TRY(style.as_string().deprecated_string())); // 5. Let currency be ? GetOption(options, "currency", "string", undefined, undefined). auto currency = TRY(get_option(vm, options, vm.names.currency, OptionType::String, {}, Empty {})); @@ -423,7 +423,7 @@ ThrowCompletionOr set_number_format_unit_options(VM& vm, NumberFormat& int } // 7. Else, // a. If ! IsWellFormedCurrencyCode(currency) is false, throw a RangeError exception. - else if (!is_well_formed_currency_code(currency.as_string().deprecated_string())) + else if (!is_well_formed_currency_code(TRY(currency.as_string().deprecated_string()))) return vm.throw_completion(ErrorType::OptionIsNotValidValue, currency, "currency"sv); // 8. Let currencyDisplay be ? GetOption(options, "currencyDisplay", "string", « "code", "symbol", "narrowSymbol", "name" », "symbol"). @@ -443,7 +443,7 @@ ThrowCompletionOr set_number_format_unit_options(VM& vm, NumberFormat& int } // 12. Else, // a. If ! IsWellFormedUnitIdentifier(unit) is false, throw a RangeError exception. - else if (!is_well_formed_unit_identifier(unit.as_string().deprecated_string())) + else if (!is_well_formed_unit_identifier(TRY(unit.as_string().deprecated_string()))) return vm.throw_completion(ErrorType::OptionIsNotValidValue, unit, "unit"sv); // 13. Let unitDisplay be ? GetOption(options, "unitDisplay", "string", « "short", "narrow", "long" », "short"). @@ -452,22 +452,22 @@ ThrowCompletionOr set_number_format_unit_options(VM& vm, NumberFormat& int // 14. If style is "currency", then if (intl_object.style() == NumberFormat::Style::Currency) { // a. Set intlObj.[[Currency]] to the ASCII-uppercase of currency. - intl_object.set_currency(currency.as_string().deprecated_string().to_uppercase()); + intl_object.set_currency(TRY(currency.as_string().deprecated_string()).to_uppercase()); // c. Set intlObj.[[CurrencyDisplay]] to currencyDisplay. - intl_object.set_currency_display(currency_display.as_string().deprecated_string()); + intl_object.set_currency_display(TRY(currency_display.as_string().deprecated_string())); // d. Set intlObj.[[CurrencySign]] to currencySign. - intl_object.set_currency_sign(currency_sign.as_string().deprecated_string()); + intl_object.set_currency_sign(TRY(currency_sign.as_string().deprecated_string())); } // 15. If style is "unit", then if (intl_object.style() == NumberFormat::Style::Unit) { // a. Set intlObj.[[Unit]] to unit. - intl_object.set_unit(unit.as_string().deprecated_string()); + intl_object.set_unit(TRY(unit.as_string().deprecated_string())); // b. Set intlObj.[[UnitDisplay]] to unitDisplay. - intl_object.set_unit_display(unit_display.as_string().deprecated_string()); + intl_object.set_unit_display(TRY(unit_display.as_string().deprecated_string())); } return {}; diff --git a/Userland/Libraries/LibJS/Runtime/Intl/PluralRulesConstructor.cpp b/Userland/Libraries/LibJS/Runtime/Intl/PluralRulesConstructor.cpp index 3748e0918e..0ae99801e8 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/PluralRulesConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/PluralRulesConstructor.cpp @@ -94,14 +94,14 @@ ThrowCompletionOr initialize_plural_rules(VM& vm, PluralRules& plu auto type = TRY(get_option(vm, *options, vm.names.type, OptionType::String, AK::Array { "cardinal"sv, "ordinal"sv }, "cardinal"sv)); // 7. Set pluralRules.[[Type]] to t. - plural_rules.set_type(type.as_string().deprecated_string()); + plural_rules.set_type(TRY(type.as_string().deprecated_string())); // 8. Perform ? SetNumberFormatDigitOptions(pluralRules, options, +0𝔽, 3𝔽, "standard"). TRY(set_number_format_digit_options(vm, plural_rules, *options, 0, 3, NumberFormat::Notation::Standard)); // 9. Let localeData be %PluralRules%.[[LocaleData]]. // 10. Let r be ResolveLocale(%PluralRules%.[[AvailableLocales]], requestedLocales, opt, %PluralRules%.[[RelevantExtensionKeys]], localeData). - auto result = resolve_locale(requested_locales, opt, {}); + auto result = TRY(resolve_locale(requested_locales, opt, {})); // 11. Set pluralRules.[[Locale]] to r.[[locale]]. plural_rules.set_locale(move(result.locale)); diff --git a/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatConstructor.cpp b/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatConstructor.cpp index 790e13b46c..bfd0b4faff 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatConstructor.cpp @@ -101,16 +101,16 @@ ThrowCompletionOr initialize_relative_time_format(VM& vm, R // 7. If numberingSystem is not undefined, then if (!numbering_system.is_undefined()) { // a. If numberingSystem does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception. - if (!::Locale::is_type_identifier(numbering_system.as_string().deprecated_string())) + if (!::Locale::is_type_identifier(TRY(numbering_system.as_string().deprecated_string()))) return vm.throw_completion(ErrorType::OptionIsNotValidValue, numbering_system, "numberingSystem"sv); // 8. Set opt.[[nu]] to numberingSystem. - opt.nu = numbering_system.as_string().deprecated_string(); + opt.nu = TRY(numbering_system.as_string().deprecated_string()); } // 9. Let localeData be %RelativeTimeFormat%.[[LocaleData]]. // 10. Let r be ResolveLocale(%RelativeTimeFormat%.[[AvailableLocales]], requestedLocales, opt, %RelativeTimeFormat%.[[RelevantExtensionKeys]], localeData). - auto result = resolve_locale(requested_locales, opt, RelativeTimeFormat::relevant_extension_keys()); + auto result = TRY(resolve_locale(requested_locales, opt, RelativeTimeFormat::relevant_extension_keys())); // 11. Let locale be r.[[locale]]. auto locale = move(result.locale); @@ -129,13 +129,13 @@ ThrowCompletionOr initialize_relative_time_format(VM& vm, R auto style = TRY(get_option(vm, *options, vm.names.style, OptionType::String, { "long"sv, "short"sv, "narrow"sv }, "long"sv)); // 16. Set relativeTimeFormat.[[Style]] to style. - relative_time_format.set_style(style.as_string().deprecated_string()); + relative_time_format.set_style(TRY(style.as_string().deprecated_string())); // 17. Let numeric be ? GetOption(options, "numeric", "string", « "always", "auto" », "always"). auto numeric = TRY(get_option(vm, *options, vm.names.numeric, OptionType::String, { "always"sv, "auto"sv }, "always"sv)); // 18. Set relativeTimeFormat.[[Numeric]] to numeric. - relative_time_format.set_numeric(numeric.as_string().deprecated_string()); + relative_time_format.set_numeric(TRY(numeric.as_string().deprecated_string())); // 19. Let relativeTimeFormat.[[NumberFormat]] be ! Construct(%NumberFormat%, « locale »). auto number_format = MUST(construct(vm, *realm.intrinsics().intl_number_format_constructor(), PrimitiveString::create(vm, locale))); diff --git a/Userland/Libraries/LibJS/Runtime/Intl/SegmentIteratorPrototype.cpp b/Userland/Libraries/LibJS/Runtime/Intl/SegmentIteratorPrototype.cpp index 09c0a1586f..bd4a598832 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/SegmentIteratorPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/SegmentIteratorPrototype.cpp @@ -60,7 +60,7 @@ JS_DEFINE_NATIVE_FUNCTION(SegmentIteratorPrototype::next) iterator->set_iterated_string_next_segment_code_unit_index(end_index); // 9. Let segmentData be ! CreateSegmentDataObject(segmenter, string, startIndex, endIndex). - auto* segment_data = create_segment_data_object(vm, segmenter, string, start_index, end_index); + auto segment_data = TRY(create_segment_data_object(vm, segmenter, string, start_index, end_index)); // 10. Return CreateIterResultObject(segmentData, false). return create_iterator_result_object(vm, segment_data, false); diff --git a/Userland/Libraries/LibJS/Runtime/Intl/Segmenter.cpp b/Userland/Libraries/LibJS/Runtime/Intl/Segmenter.cpp index d79be00a23..dc51db79c3 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/Segmenter.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/Segmenter.cpp @@ -45,7 +45,7 @@ StringView Segmenter::segmenter_granularity_string() const } // 18.7.1 CreateSegmentDataObject ( segmenter, string, startIndex, endIndex ), https://tc39.es/ecma402/#sec-createsegmentdataobject -Object* create_segment_data_object(VM& vm, Segmenter const& segmenter, Utf16View const& string, double start_index, double end_index) +ThrowCompletionOr> create_segment_data_object(VM& vm, Segmenter const& segmenter, Utf16View const& string, double start_index, double end_index) { auto& realm = *vm.current_realm(); @@ -68,13 +68,13 @@ Object* create_segment_data_object(VM& vm, Segmenter const& segmenter, Utf16View auto segment = string.substring_view(start_index, end_index - start_index); // 7. Perform ! CreateDataPropertyOrThrow(result, "segment", segment). - MUST(result->create_data_property_or_throw(vm.names.segment, PrimitiveString::create(vm, segment))); + MUST(result->create_data_property_or_throw(vm.names.segment, PrimitiveString::create(vm, TRY(Utf16String::create(vm, segment))))); // 8. Perform ! CreateDataPropertyOrThrow(result, "index", 𝔽(startIndex)). MUST(result->create_data_property_or_throw(vm.names.index, Value(start_index))); // 9. Perform ! CreateDataPropertyOrThrow(result, "input", string). - MUST(result->create_data_property_or_throw(vm.names.input, PrimitiveString::create(vm, string))); + MUST(result->create_data_property_or_throw(vm.names.input, PrimitiveString::create(vm, TRY(Utf16String::create(vm, string))))); // 10. Let granularity be segmenter.[[SegmenterGranularity]]. auto granularity = segmenter.segmenter_granularity(); diff --git a/Userland/Libraries/LibJS/Runtime/Intl/Segmenter.h b/Userland/Libraries/LibJS/Runtime/Intl/Segmenter.h index 56eb1aa1df..4034b1b077 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/Segmenter.h +++ b/Userland/Libraries/LibJS/Runtime/Intl/Segmenter.h @@ -37,7 +37,7 @@ private: SegmenterGranularity m_segmenter_granularity { SegmenterGranularity::Grapheme }; // [[SegmenterGranularity]] }; -Object* create_segment_data_object(VM&, Segmenter const&, Utf16View const&, double start_index, double end_index); +ThrowCompletionOr> create_segment_data_object(VM&, Segmenter const&, Utf16View const&, double start_index, double end_index); enum class Direction { Before, After, diff --git a/Userland/Libraries/LibJS/Runtime/Intl/SegmenterConstructor.cpp b/Userland/Libraries/LibJS/Runtime/Intl/SegmenterConstructor.cpp index 827e9f6b79..3b840327ab 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/SegmenterConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/SegmenterConstructor.cpp @@ -71,7 +71,7 @@ ThrowCompletionOr> SegmenterConstructor::construct(Function // 9. Let localeData be %Segmenter%.[[LocaleData]]. // 10. Let r be ResolveLocale(%Segmenter%.[[AvailableLocales]], requestedLocales, opt, %Segmenter%.[[RelevantExtensionKeys]], localeData). - auto result = resolve_locale(requested_locales, opt, {}); + auto result = TRY(resolve_locale(requested_locales, opt, {})); // 11. Set segmenter.[[Locale]] to r.[[locale]]. segmenter->set_locale(move(result.locale)); @@ -80,7 +80,7 @@ ThrowCompletionOr> SegmenterConstructor::construct(Function auto granularity = TRY(get_option(vm, *options, vm.names.granularity, OptionType::String, { "grapheme"sv, "word"sv, "sentence"sv }, "grapheme"sv)); // 13. Set segmenter.[[SegmenterGranularity]] to granularity. - segmenter->set_segmenter_granularity(granularity.as_string().deprecated_string()); + segmenter->set_segmenter_granularity(TRY(granularity.as_string().deprecated_string())); // 14. Return segmenter. return segmenter; diff --git a/Userland/Libraries/LibJS/Runtime/Intl/SegmentsPrototype.cpp b/Userland/Libraries/LibJS/Runtime/Intl/SegmentsPrototype.cpp index aba326ecfb..2edf03efd0 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/SegmentsPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/SegmentsPrototype.cpp @@ -58,7 +58,7 @@ JS_DEFINE_NATIVE_FUNCTION(SegmentsPrototype::containing) auto end_index = find_boundary(segmenter, string, n, Direction::After, segments->boundaries_cache()); // 10. Return ! CreateSegmentDataObject(segmenter, string, startIndex, endIndex). - return create_segment_data_object(vm, segmenter, string, start_index, end_index); + return TRY(create_segment_data_object(vm, segmenter, string, start_index, end_index)); } // 18.5.2.2 %SegmentsPrototype% [ @@iterator ] ( ), https://tc39.es/ecma402/#sec-%segmentsprototype%-@@iterator diff --git a/Userland/Libraries/LibJS/Runtime/JSONObject.cpp b/Userland/Libraries/LibJS/Runtime/JSONObject.cpp index 5698a819f1..530b1dac2b 100644 --- a/Userland/Libraries/LibJS/Runtime/JSONObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/JSONObject.cpp @@ -63,7 +63,7 @@ ThrowCompletionOr JSONObject::stringify_impl(VM& vm, Value val auto replacer_value = TRY(replacer_object.get(i)); DeprecatedString item; if (replacer_value.is_string()) { - item = replacer_value.as_string().deprecated_string(); + item = TRY(replacer_value.as_string().deprecated_string()); } else if (replacer_value.is_number()) { item = MUST(replacer_value.to_string(vm)); } else if (replacer_value.is_object()) { @@ -93,7 +93,7 @@ ThrowCompletionOr JSONObject::stringify_impl(VM& vm, Value val space_mv = min(10, space_mv); state.gap = space_mv < 1 ? DeprecatedString::empty() : DeprecatedString::repeated(' ', space_mv); } else if (space.is_string()) { - auto string = space.as_string().deprecated_string(); + auto string = TRY(space.as_string().deprecated_string()); if (string.length() <= 10) state.gap = string; else @@ -185,7 +185,7 @@ ThrowCompletionOr JSONObject::serialize_json_property(VM& vm, // 8. If Type(value) is String, return QuoteJSONString(value). if (value.is_string()) - return quote_json_string(value.as_string().deprecated_string()); + return quote_json_string(TRY(value.as_string().deprecated_string())); // 9. If Type(value) is Number, then if (value.is_number()) { @@ -250,7 +250,7 @@ ThrowCompletionOr JSONObject::serialize_json_object(VM& vm, St } else { auto property_list = TRY(object.enumerable_own_property_names(PropertyKind::Key)); for (auto& property : property_list) - TRY(process_property(property.as_string().deprecated_string())); + TRY(process_property(TRY(property.as_string().deprecated_string()))); } StringBuilder builder; if (property_strings.is_empty()) { @@ -473,7 +473,7 @@ ThrowCompletionOr JSONObject::internalize_json_property(VM& vm, Object* h } else { auto property_list = TRY(value_object.enumerable_own_property_names(Object::PropertyKind::Key)); for (auto& property_key : property_list) - TRY(process_property(property_key.as_string().deprecated_string())); + TRY(process_property(TRY(property_key.as_string().deprecated_string()))); } } diff --git a/Userland/Libraries/LibJS/Runtime/Object.cpp b/Userland/Libraries/LibJS/Runtime/Object.cpp index 4869c69318..3ae26f3090 100644 --- a/Userland/Libraries/LibJS/Runtime/Object.cpp +++ b/Userland/Libraries/LibJS/Runtime/Object.cpp @@ -1267,7 +1267,7 @@ Optional Object::enumerate_object_properties(Functioninternal_get_own_property(property_key)); diff --git a/Userland/Libraries/LibJS/Runtime/ObjectPrototype.cpp b/Userland/Libraries/LibJS/Runtime/ObjectPrototype.cpp index 5a53ffcdad..4ebcda17fd 100644 --- a/Userland/Libraries/LibJS/Runtime/ObjectPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/ObjectPrototype.cpp @@ -125,7 +125,7 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::to_string) if (!to_string_tag.is_string()) tag = move(builtin_tag); else - tag = to_string_tag.as_string().deprecated_string(); + tag = TRY(to_string_tag.as_string().deprecated_string()); // 17. Return the string-concatenation of "[object ", tag, and "]". return PrimitiveString::create(vm, DeprecatedString::formatted("[object {}]", tag)); diff --git a/Userland/Libraries/LibJS/Runtime/PrimitiveString.cpp b/Userland/Libraries/LibJS/Runtime/PrimitiveString.cpp index 3d4f87de34..74d535c848 100644 --- a/Userland/Libraries/LibJS/Runtime/PrimitiveString.cpp +++ b/Userland/Libraries/LibJS/Runtime/PrimitiveString.cpp @@ -25,20 +25,19 @@ PrimitiveString::PrimitiveString(PrimitiveString& lhs, PrimitiveString& rhs) } PrimitiveString::PrimitiveString(DeprecatedString string) - : m_has_utf8_string(true) - , m_utf8_string(move(string)) + : m_utf8_string(move(string)) { } PrimitiveString::PrimitiveString(Utf16String string) - : m_has_utf16_string(true) - , m_utf16_string(move(string)) + : m_utf16_string(move(string)) { } PrimitiveString::~PrimitiveString() { - vm().string_cache().remove(m_utf8_string); + if (has_utf8_string()) + vm().string_cache().remove(*m_utf8_string); } void PrimitiveString::visit_edges(Cell::Visitor& visitor) @@ -57,62 +56,60 @@ bool PrimitiveString::is_empty() const return false; } - if (m_has_utf16_string) - return m_utf16_string.is_empty(); - if (m_has_utf8_string) - return m_utf8_string.is_empty(); + if (has_utf16_string()) + return m_utf16_string->is_empty(); + if (has_utf8_string()) + return m_utf8_string->is_empty(); VERIFY_NOT_REACHED(); } -DeprecatedString const& PrimitiveString::deprecated_string() const +ThrowCompletionOr PrimitiveString::deprecated_string() const { - resolve_rope_if_needed(); - if (!m_has_utf8_string) { - // FIXME: Propagate this error. - m_utf8_string = MUST(m_utf16_string.to_utf8(vm())); - m_has_utf8_string = true; + TRY(resolve_rope_if_needed()); + + if (!has_utf8_string()) { + VERIFY(has_utf16_string()); + m_utf8_string = TRY(m_utf16_string->to_utf8(vm())); } - return m_utf8_string; + + return *m_utf8_string; } -Utf16String const& PrimitiveString::utf16_string() const +ThrowCompletionOr PrimitiveString::utf16_string() const { - resolve_rope_if_needed(); - if (!m_has_utf16_string) { - m_utf16_string = Utf16String(m_utf8_string); - m_has_utf16_string = true; + TRY(resolve_rope_if_needed()); + + if (!has_utf16_string()) { + VERIFY(has_utf8_string()); + m_utf16_string = TRY(Utf16String::create(vm(), *m_utf8_string)); } - return m_utf16_string; + + return *m_utf16_string; } -Utf16View PrimitiveString::utf16_string_view() const +ThrowCompletionOr PrimitiveString::utf16_string_view() const { - return utf16_string().view(); + return TRY(utf16_string()).view(); } -Optional PrimitiveString::get(VM& vm, PropertyKey const& property_key) const +ThrowCompletionOr> PrimitiveString::get(VM& vm, PropertyKey const& property_key) const { if (property_key.is_symbol()) - return {}; + return Optional {}; if (property_key.is_string()) { if (property_key.as_string() == vm.names.length.as_string()) { - auto length = utf16_string().length_in_code_units(); + auto length = TRY(utf16_string()).length_in_code_units(); return Value(static_cast(length)); } } auto index = canonical_numeric_index_string(property_key, CanonicalIndexMode::IgnoreNumericRoundtrip); if (!index.is_index()) - return {}; - auto str = utf16_string_view(); + return Optional {}; + auto str = TRY(utf16_string_view()); auto length = str.length_in_code_units(); if (length <= index.as_index()) - return {}; - return create(vm, str.substring_view(index.as_index(), 1)); -} - -NonnullGCPtr PrimitiveString::create(VM& vm, Utf16View const& view) -{ - return create(vm, Utf16String(view)); + return Optional {}; + return create(vm, TRY(Utf16String::create(vm, str.substring_view(index.as_index(), 1)))); } NonnullGCPtr PrimitiveString::create(VM& vm, Utf16String string) @@ -170,28 +167,29 @@ NonnullGCPtr PrimitiveString::create(VM& vm, PrimitiveString& l return vm.heap().allocate_without_realm(lhs, rhs); } -void PrimitiveString::resolve_rope_if_needed() const +ThrowCompletionOr PrimitiveString::resolve_rope_if_needed() const { if (!m_is_rope) - return; + return {}; + + auto& vm = this->vm(); // NOTE: Special case for two concatenated UTF-16 strings. // This is here as an optimization, although I'm unsure how valuable it is. if (m_lhs->has_utf16_string() && m_rhs->has_utf16_string()) { - auto const& lhs_string = m_lhs->utf16_string(); - auto const& rhs_string = m_rhs->utf16_string(); + auto const& lhs_string = TRY(m_lhs->utf16_string()); + auto const& rhs_string = TRY(m_rhs->utf16_string()); Utf16Data combined; combined.ensure_capacity(lhs_string.length_in_code_units() + rhs_string.length_in_code_units()); combined.extend(lhs_string.string()); combined.extend(rhs_string.string()); - m_utf16_string = Utf16String(move(combined)); - m_has_utf16_string = true; + m_utf16_string = TRY(Utf16String::create(vm, move(combined))); m_is_rope = false; m_lhs = nullptr; m_rhs = nullptr; - return; + return {}; } // This vector will hold all the pieces of the rope that need to be assembled @@ -221,21 +219,21 @@ void PrimitiveString::resolve_rope_if_needed() const for (auto const* current : pieces) { if (!previous) { // This is the very first piece, just append it and continue. - builder.append(current->deprecated_string()); + builder.append(TRY(current->deprecated_string())); previous = current; continue; } // Get the UTF-8 representations for both strings. - auto const& previous_string_as_utf8 = previous->deprecated_string(); - auto const& current_string_as_utf8 = current->deprecated_string(); + auto const& previous_string_as_utf8 = TRY(previous->deprecated_string()); + auto const& current_string_as_utf8 = TRY(current->deprecated_string()); // NOTE: Now we need to look at the end of the previous string and the start // of the current string, to see if they should be combined into a surrogate. // Surrogates encoded as UTF-8 are 3 bytes. if ((previous_string_as_utf8.length() < 3) || (current_string_as_utf8.length() < 3)) { - builder.append(current->deprecated_string()); + builder.append(TRY(current->deprecated_string())); previous = current; continue; } @@ -243,7 +241,7 @@ void PrimitiveString::resolve_rope_if_needed() const // Might the previous string end with a UTF-8 encoded surrogate? if ((static_cast(previous_string_as_utf8[previous_string_as_utf8.length() - 3]) & 0xf0) != 0xe0) { // If not, just append the current string and continue. - builder.append(current->deprecated_string()); + builder.append(TRY(current->deprecated_string())); previous = current; continue; } @@ -251,7 +249,7 @@ void PrimitiveString::resolve_rope_if_needed() const // Might the current string begin with a UTF-8 encoded surrogate? if ((static_cast(current_string_as_utf8[0]) & 0xf0) != 0xe0) { // If not, just append the current string and continue. - builder.append(current->deprecated_string()); + builder.append(TRY(current->deprecated_string())); previous = current; continue; } @@ -260,7 +258,7 @@ void PrimitiveString::resolve_rope_if_needed() const auto low_surrogate = *Utf8View(current_string_as_utf8).begin(); if (!Utf16View::is_high_surrogate(high_surrogate) || !Utf16View::is_low_surrogate(low_surrogate)) { - builder.append(current->deprecated_string()); + builder.append(TRY(current->deprecated_string())); previous = current; continue; } @@ -275,10 +273,10 @@ void PrimitiveString::resolve_rope_if_needed() const } m_utf8_string = builder.to_deprecated_string(); - m_has_utf8_string = true; m_is_rope = false; m_lhs = nullptr; m_rhs = nullptr; + return {}; } } diff --git a/Userland/Libraries/LibJS/Runtime/PrimitiveString.h b/Userland/Libraries/LibJS/Runtime/PrimitiveString.h index 210e066cd6..ea004323fa 100644 --- a/Userland/Libraries/LibJS/Runtime/PrimitiveString.h +++ b/Userland/Libraries/LibJS/Runtime/PrimitiveString.h @@ -8,9 +8,11 @@ #pragma once #include +#include #include #include #include +#include #include #include @@ -20,7 +22,6 @@ class PrimitiveString final : public Cell { JS_CELL(PrimitiveString, Cell); public: - [[nodiscard]] static NonnullGCPtr create(VM&, Utf16View const&); [[nodiscard]] static NonnullGCPtr create(VM&, Utf16String); [[nodiscard]] static NonnullGCPtr create(VM&, DeprecatedString); [[nodiscard]] static NonnullGCPtr create(VM&, PrimitiveString&, PrimitiveString&); @@ -31,15 +32,16 @@ public: PrimitiveString& operator=(PrimitiveString const&) = delete; bool is_empty() const; + u32 hash() const; - DeprecatedString const& deprecated_string() const; - bool has_utf8_string() const { return m_has_utf8_string; } + ThrowCompletionOr deprecated_string() const; + bool has_utf8_string() const { return m_utf8_string.has_value(); } - Utf16String const& utf16_string() const; - Utf16View utf16_string_view() const; - bool has_utf16_string() const { return m_has_utf16_string; } + ThrowCompletionOr utf16_string() const; + ThrowCompletionOr utf16_string_view() const; + bool has_utf16_string() const { return m_utf16_string.has_value(); } - Optional get(VM&, PropertyKey const&) const; + ThrowCompletionOr> get(VM&, PropertyKey const&) const; private: explicit PrimitiveString(PrimitiveString&, PrimitiveString&); @@ -48,18 +50,15 @@ private: virtual void visit_edges(Cell::Visitor&) override; - void resolve_rope_if_needed() const; + ThrowCompletionOr resolve_rope_if_needed() const; mutable bool m_is_rope { false }; - mutable bool m_has_utf8_string { false }; - mutable bool m_has_utf16_string { false }; mutable PrimitiveString* m_lhs { nullptr }; mutable PrimitiveString* m_rhs { nullptr }; - mutable DeprecatedString m_utf8_string; - - mutable Utf16String m_utf16_string; + mutable Optional m_utf8_string; + mutable Optional m_utf16_string; }; } diff --git a/Userland/Libraries/LibJS/Runtime/Reference.cpp b/Userland/Libraries/LibJS/Runtime/Reference.cpp index 908150a019..21af7d06b4 100644 --- a/Userland/Libraries/LibJS/Runtime/Reference.cpp +++ b/Userland/Libraries/LibJS/Runtime/Reference.cpp @@ -114,7 +114,7 @@ ThrowCompletionOr Reference::get_value(VM& vm) const // OPTIMIZATION: For various primitives we can avoid actually creating a new object for them. Object* base_obj = nullptr; if (m_base_value.is_string()) { - auto string_value = m_base_value.as_string().get(vm, m_name); + auto string_value = TRY(m_base_value.as_string().get(vm, m_name)); if (string_value.has_value()) return *string_value; base_obj = realm.intrinsics().string_prototype(); diff --git a/Userland/Libraries/LibJS/Runtime/RegExpLegacyStaticProperties.cpp b/Userland/Libraries/LibJS/Runtime/RegExpLegacyStaticProperties.cpp index 5044548037..3cb342e474 100644 --- a/Userland/Libraries/LibJS/Runtime/RegExpLegacyStaticProperties.cpp +++ b/Userland/Libraries/LibJS/Runtime/RegExpLegacyStaticProperties.cpp @@ -68,7 +68,7 @@ ThrowCompletionOr set_legacy_regexp_static_property(VM& vm, RegExpConstruc } // UpdateLegacyRegExpStaticProperties ( C, S, startIndex, endIndex, capturedValues ), https://github.com/tc39/proposal-regexp-legacy-features#updatelegacyregexpstaticproperties--c-s-startindex-endindex-capturedvalues- -void update_legacy_regexp_static_properties(RegExpConstructor& constructor, Utf16String const& string, size_t start_index, size_t end_index, Vector const& captured_values) +ThrowCompletionOr update_legacy_regexp_static_properties(VM& vm, RegExpConstructor& constructor, Utf16String const& string, size_t start_index, size_t end_index, Vector const& captured_values) { auto& legacy_static_properties = constructor.legacy_static_properties(); @@ -92,7 +92,7 @@ void update_legacy_regexp_static_properties(RegExpConstructor& constructor, Utf1 // 8. Set the value of C’s [[RegExpLastMatch]] internal slot to a String whose length is endIndex - startIndex and containing the code units from S with indices startIndex through endIndex - 1, in ascending order. auto last_match = string.view().substring_view(start_index, end_index - start_index); - legacy_static_properties.set_last_match(Utf16String(last_match)); + legacy_static_properties.set_last_match(TRY(Utf16String::create(vm, last_match))); // 9. If n > 0, set the value of C’s [[RegExpLastParen]] internal slot to the last element of capturedValues. if (group_count > 0) { @@ -101,49 +101,45 @@ void update_legacy_regexp_static_properties(RegExpConstructor& constructor, Utf1 } // 10. Else, set the value of C’s [[RegExpLastParen]] internal slot to the empty String. else { - legacy_static_properties.set_last_paren(Utf16String(""sv)); + legacy_static_properties.set_last_paren(TRY(Utf16String::create(vm))); } // 11. Set the value of C’s [[RegExpLeftContext]] internal slot to a String whose length is startIndex and containing the code units from S with indices 0 through startIndex - 1, in ascending order. auto left_context = string.view().substring_view(0, start_index); - legacy_static_properties.set_left_context(Utf16String(left_context)); + legacy_static_properties.set_left_context(TRY(Utf16String::create(vm, left_context))); // 12. Set the value of C’s [[RegExpRightContext]] internal slot to a String whose length is len - endIndex and containing the code units from S with indices endIndex through len - 1, in ascending order. auto right_context = string.view().substring_view(end_index, len - end_index); - legacy_static_properties.set_right_context(Utf16String(right_context)); + legacy_static_properties.set_right_context(TRY(Utf16String::create(vm, right_context))); // 13. For each integer i such that 1 ≤ i ≤ 9 for (size_t i = 1; i <= 9; i++) { - auto value = Utf16String(""sv); - // If i ≤ n, set the value of C’s [[RegExpPareni]] internal slot to the ith element of capturedValues. - if (i <= group_count) { - value = captured_values[i - 1]; - } - // Else, set the value of C’s [[RegExpPareni]] internal slot to the empty String. - else { - // It's already an empty string - } + // i. If i ≤ n, set the value of C’s [[RegExpPareni]] internal slot to the ith element of capturedValues. + // ii. Else, set the value of C’s [[RegExpPareni]] internal slot to the empty String. + auto value = (i <= group_count) ? captured_values[i - 1] : TRY(Utf16String::create(vm)); if (i == 1) { - legacy_static_properties.set_$1(Utf16String(value)); + legacy_static_properties.set_$1(move(value)); } else if (i == 2) { - legacy_static_properties.set_$2(Utf16String(value)); + legacy_static_properties.set_$2(move(value)); } else if (i == 3) { - legacy_static_properties.set_$3(Utf16String(value)); + legacy_static_properties.set_$3(move(value)); } else if (i == 4) { - legacy_static_properties.set_$4(Utf16String(value)); + legacy_static_properties.set_$4(move(value)); } else if (i == 5) { - legacy_static_properties.set_$5(Utf16String(value)); + legacy_static_properties.set_$5(move(value)); } else if (i == 6) { - legacy_static_properties.set_$6(Utf16String(value)); + legacy_static_properties.set_$6(move(value)); } else if (i == 7) { - legacy_static_properties.set_$7(Utf16String(value)); + legacy_static_properties.set_$7(move(value)); } else if (i == 8) { - legacy_static_properties.set_$8(Utf16String(value)); + legacy_static_properties.set_$8(move(value)); } else if (i == 9) { - legacy_static_properties.set_$9(Utf16String(value)); + legacy_static_properties.set_$9(move(value)); } } + + return {}; } // InvalidateLegacyRegExpStaticProperties ( C ), https://github.com/tc39/proposal-regexp-legacy-features#invalidatelegacyregexpstaticproperties--c diff --git a/Userland/Libraries/LibJS/Runtime/RegExpLegacyStaticProperties.h b/Userland/Libraries/LibJS/Runtime/RegExpLegacyStaticProperties.h index 878975ab54..5ee4d37d54 100644 --- a/Userland/Libraries/LibJS/Runtime/RegExpLegacyStaticProperties.h +++ b/Userland/Libraries/LibJS/Runtime/RegExpLegacyStaticProperties.h @@ -73,7 +73,7 @@ private: ThrowCompletionOr set_legacy_regexp_static_property(VM& vm, RegExpConstructor& constructor, Value this_value, void (RegExpLegacyStaticProperties::*property_setter)(Utf16String), Value value); ThrowCompletionOr get_legacy_regexp_static_property(VM& vm, RegExpConstructor& constructor, Value this_value, Optional const& (RegExpLegacyStaticProperties::*property_getter)() const); -void update_legacy_regexp_static_properties(RegExpConstructor& constructor, Utf16String const& string, size_t start_index, size_t end_index, Vector const& captured_values); +ThrowCompletionOr update_legacy_regexp_static_properties(VM& vm, RegExpConstructor& constructor, Utf16String const& string, size_t start_index, size_t end_index, Vector const& captured_values); void invalidate_legacy_regexp_static_properties(RegExpConstructor& constructor); } diff --git a/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp b/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp index 37b4be5cbf..0b056697d3 100644 --- a/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp @@ -275,7 +275,7 @@ static ThrowCompletionOr regexp_builtin_exec(VM& vm, RegExpObject& regexp // 27. Let matchedValue be ! GetMatchString(S, match). // 28. Perform ! CreateDataPropertyOrThrow(A, "0", matchedValue). - MUST(array->create_data_property_or_throw(0, PrimitiveString::create(vm, match.view.u16_view()))); + MUST(array->create_data_property_or_throw(0, PrimitiveString::create(vm, TRY(Utf16String::create(vm, match.view.u16_view()))))); // 29. If R contains any GroupName, then // a. Let groups be OrdinaryObjectCreate(null). @@ -300,7 +300,7 @@ static ThrowCompletionOr regexp_builtin_exec(VM& vm, RegExpObject& regexp // ii. Append undefined to indices. indices.append({}); // iii. Append capture to indices. - captured_values.append(Utf16String(""sv)); + captured_values.append(TRY(Utf16String::create(vm))); } // c. Else, else { @@ -311,7 +311,7 @@ static ThrowCompletionOr regexp_builtin_exec(VM& vm, RegExpObject& regexp // 2. Set captureEnd to ! GetStringIndex(S, Input, captureEnd). // iv. Let capture be the Match { [[StartIndex]]: captureStart, [[EndIndex]: captureEnd }. // v. Let capturedValue be ! GetMatchString(S, capture). - auto capture_as_utf16_string = Utf16String(capture.view.u16_view()); + auto capture_as_utf16_string = TRY(Utf16String::create(vm, capture.view.u16_view())); captured_value = PrimitiveString::create(vm, capture_as_utf16_string); // vi. Append capture to indices. indices.append(Match::create(capture)); @@ -351,7 +351,7 @@ static ThrowCompletionOr regexp_builtin_exec(VM& vm, RegExpObject& regexp if (regexp_object.legacy_features_enabled()) { // a. Perform UpdateLegacyRegExpStaticProperties(%RegExp%, S, lastIndex, e, capturedValues). auto* regexp_constructor = realm.intrinsics().regexp_constructor(); - update_legacy_regexp_static_properties(*regexp_constructor, string, match_indices.start_index, match_indices.end_index, captured_values); + TRY(update_legacy_regexp_static_properties(vm, *regexp_constructor, string, match_indices.start_index, match_indices.end_index, captured_values)); } // ii. Else, else { @@ -998,7 +998,7 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_split) auto substring = string.substring_view(last_match_end, next_search_from - last_match_end); // 2. Perform ! CreateDataPropertyOrThrow(A, ! ToString(𝔽(lengthA)), T). - MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, substring))); + MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, TRY(Utf16String::create(vm, substring))))); // 3. Set lengthA to lengthA + 1. ++array_length; @@ -1045,7 +1045,7 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_split) auto substring = string.substring_view(last_match_end); // 21. Perform ! CreateDataPropertyOrThrow(A, ! ToString(𝔽(lengthA)), T). - MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, substring))); + MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, TRY(Utf16String::create(vm, substring))))); // 22. Return A. return array; diff --git a/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp b/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp index 55599256d4..0fe13a9c21 100644 --- a/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp +++ b/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp @@ -86,7 +86,7 @@ ThrowCompletionOr copy_name_and_length(VM& vm, FunctionObject& function, F target_name = PrimitiveString::create(vm, DeprecatedString::empty()); // 8. Perform SetFunctionName(F, targetName, prefix). - function.set_function_name({ target_name.as_string().deprecated_string() }, move(prefix)); + function.set_function_name({ TRY(target_name.as_string().deprecated_string()) }, move(prefix)); return {}; } @@ -272,7 +272,7 @@ ThrowCompletionOr shadow_realm_import_value(VM& vm, DeprecatedString spec // NOTE: Even though the spec tells us to use %ThrowTypeError%, it's not observable if we actually do. // Throw a nicer TypeError forwarding the import error message instead (we know the argument is an Error object). auto throw_type_error = NativeFunction::create(realm, {}, [](auto& vm) -> ThrowCompletionOr { - return vm.template throw_completion(vm.argument(0).as_object().get_without_side_effects(vm.names.message).as_string().deprecated_string()); + return vm.template throw_completion(TRY(vm.argument(0).as_object().get_without_side_effects(vm.names.message).as_string().deprecated_string())); }); // 13. Return PerformPromiseThen(innerCapability.[[Promise]], onFulfilled, callerRealm.[[Intrinsics]].[[%ThrowTypeError%]], promiseCapability). diff --git a/Userland/Libraries/LibJS/Runtime/ShadowRealmPrototype.cpp b/Userland/Libraries/LibJS/Runtime/ShadowRealmPrototype.cpp index a1b17512e9..30fe1b21d3 100644 --- a/Userland/Libraries/LibJS/Runtime/ShadowRealmPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/ShadowRealmPrototype.cpp @@ -49,7 +49,7 @@ JS_DEFINE_NATIVE_FUNCTION(ShadowRealmPrototype::evaluate) auto& eval_realm = object->shadow_realm(); // 6. Return ? PerformShadowRealmEval(sourceText, callerRealm, evalRealm). - return perform_shadow_realm_eval(vm, source_text.as_string().deprecated_string(), *caller_realm, eval_realm); + return perform_shadow_realm_eval(vm, TRY(source_text.as_string().deprecated_string()), *caller_realm, eval_realm); } // 3.4.2 ShadowRealm.prototype.importValue ( specifier, exportName ), https://tc39.es/proposal-shadowrealm/#sec-shadowrealm.prototype.importvalue @@ -79,7 +79,7 @@ JS_DEFINE_NATIVE_FUNCTION(ShadowRealmPrototype::import_value) auto& eval_context = object->execution_context(); // 8. Return ? ShadowRealmImportValue(specifierString, exportNameString, callerRealm, evalRealm, evalContext). - return shadow_realm_import_value(vm, move(specifier_string), export_name.as_string().deprecated_string(), *caller_realm, eval_realm, eval_context); + return shadow_realm_import_value(vm, move(specifier_string), TRY(export_name.as_string().deprecated_string()), *caller_realm, eval_realm, eval_context); } } diff --git a/Userland/Libraries/LibJS/Runtime/StringConstructor.cpp b/Userland/Libraries/LibJS/Runtime/StringConstructor.cpp index aa45fd348f..6964cb28dc 100644 --- a/Userland/Libraries/LibJS/Runtime/StringConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/StringConstructor.cpp @@ -106,7 +106,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringConstructor::from_char_code) for (size_t i = 0; i < vm.argument_count(); ++i) string.append(TRY(vm.argument(i).to_u16(vm))); - return PrimitiveString::create(vm, Utf16String(move(string))); + return PrimitiveString::create(vm, TRY(Utf16String::create(vm, move(string)))); } // 22.1.2.2 String.fromCodePoint ( ...codePoints ), https://tc39.es/ecma262/#sec-string.fromcodepoint @@ -126,7 +126,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringConstructor::from_code_point) TRY_OR_THROW_OOM(vm, code_point_to_utf16(string, static_cast(code_point))); } - return PrimitiveString::create(vm, Utf16String(move(string))); + return PrimitiveString::create(vm, TRY(Utf16String::create(vm, move(string)))); } } diff --git a/Userland/Libraries/LibJS/Runtime/StringObject.cpp b/Userland/Libraries/LibJS/Runtime/StringObject.cpp index 51da264983..170449ef8b 100644 --- a/Userland/Libraries/LibJS/Runtime/StringObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/StringObject.cpp @@ -30,7 +30,9 @@ void StringObject::initialize(Realm& realm) { auto& vm = this->vm(); Object::initialize(realm); - define_direct_property(vm.names.length, Value(m_string.utf16_string_view().length_in_code_units()), 0); + + // FIXME: Propagate this error. + define_direct_property(vm.names.length, Value(MUST(m_string.utf16_string_view()).length_in_code_units()), 0); } void StringObject::visit_edges(Cell::Visitor& visitor) @@ -40,7 +42,7 @@ void StringObject::visit_edges(Cell::Visitor& visitor) } // 10.4.3.5 StringGetOwnProperty ( S, P ), https://tc39.es/ecma262/#sec-stringgetownproperty -static Optional string_get_own_property(StringObject const& string, PropertyKey const& property_key) +static ThrowCompletionOr> string_get_own_property(StringObject const& string, PropertyKey const& property_key) { VERIFY(property_key.is_valid()); @@ -48,7 +50,7 @@ static Optional string_get_own_property(StringObject const& // NOTE: The spec only uses string and symbol keys, and later coerces to numbers - // this is not the case for PropertyKey, so '!property_key.is_string()' would be wrong. if (property_key.is_symbol()) - return {}; + return Optional {}; // 2. Let index be CanonicalNumericIndexString(P). auto index = canonical_numeric_index_string(property_key, CanonicalIndexMode::IgnoreNumericRoundtrip); @@ -57,21 +59,21 @@ static Optional string_get_own_property(StringObject const& // 4. If IsIntegralNumber(index) is false, return undefined. // 5. If index is -0𝔽, return undefined. if (!index.is_index()) - return {}; + return Optional {}; // 6. Let str be S.[[StringData]]. // 7. Assert: Type(str) is String. - auto str = string.primitive_string().utf16_string_view(); + auto str = TRY(string.primitive_string().utf16_string_view()); // 8. Let len be the length of str. auto length = str.length_in_code_units(); // 9. If ℝ(index) < 0 or len ≤ ℝ(index), return undefined. if (length <= index.as_index()) - return {}; + return Optional {}; // 10. Let resultStr be the String value of length 1, containing one code unit from str, specifically the code unit at index ℝ(index). - auto result_str = PrimitiveString::create(string.vm(), str.substring_view(index.as_index(), 1)); + auto result_str = PrimitiveString::create(string.vm(), TRY(Utf16String::create(string.vm(), str.substring_view(index.as_index(), 1)))); // 11. Return the PropertyDescriptor { [[Value]]: resultStr, [[Writable]]: false, [[Enumerable]]: true, [[Configurable]]: false }. return PropertyDescriptor { @@ -104,7 +106,7 @@ ThrowCompletionOr StringObject::internal_define_own_property(PropertyKey c VERIFY(property_key.is_valid()); // 1. Let stringDesc be StringGetOwnProperty(S, P). - auto string_descriptor = string_get_own_property(*this, property_key); + auto string_descriptor = TRY(string_get_own_property(*this, property_key)); // 2. If stringDesc is not undefined, then if (string_descriptor.has_value()) { @@ -128,7 +130,7 @@ ThrowCompletionOr> StringObject::internal_own_property_keys( auto keys = MarkedVector { heap() }; // 2. Let str be O.[[StringData]]. - auto str = m_string.utf16_string_view(); + auto str = TRY(m_string.utf16_string_view()); // 3. Assert: Type(str) is String. diff --git a/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp b/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp index c43706bbb7..be8d5b8f6d 100644 --- a/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp @@ -237,7 +237,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::at) return js_undefined(); // 7. Return ? Get(O, ! ToString(𝔽(k))). - return PrimitiveString::create(vm, string.substring_view(index.value(), 1)); + return PrimitiveString::create(vm, TRY(Utf16String::create(vm, string.substring_view(index.value(), 1)))); } // 22.1.3.2 String.prototype.charAt ( pos ), https://tc39.es/ecma262/#sec-string.prototype.charat @@ -248,7 +248,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::char_at) if (position < 0 || position >= string.length_in_code_units()) return PrimitiveString::create(vm, DeprecatedString::empty()); - return PrimitiveString::create(vm, string.substring_view(position, 1)); + return PrimitiveString::create(vm, TRY(Utf16String::create(vm, string.substring_view(position, 1)))); } // 22.1.3.3 String.prototype.charCodeAt ( pos ), https://tc39.es/ecma262/#sec-string.prototype.charcodeat @@ -518,7 +518,7 @@ static ThrowCompletionOr pad_string(VM& vm, Utf16String string, PadPlacem if (max_length <= string_length) return PrimitiveString::create(vm, move(string)); - Utf16String fill_string(Utf16Data { 0x20 }); + auto fill_string = TRY(Utf16String::create(vm, Utf16Data { 0x20 })); if (!vm.argument(1).is_undefined()) { fill_string = TRY(vm.argument(1).to_utf16_string(vm)); if (fill_string.is_empty()) @@ -736,7 +736,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::slice) if (int_start >= int_end) return PrimitiveString::create(vm, DeprecatedString::empty()); - return PrimitiveString::create(vm, string.substring_view(int_start, int_end - int_start)); + return PrimitiveString::create(vm, TRY(Utf16String::create(vm, string.substring_view(int_start, int_end - int_start)))); } // 22.1.3.22 String.prototype.split ( separator, limit ), https://tc39.es/ecma262/#sec-string.prototype.split @@ -793,7 +793,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::split) } auto segment = string.substring_view(start, position - start); - MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, segment))); + MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, TRY(Utf16String::create(vm, segment))))); ++array_length; if (array_length == limit) return array; @@ -802,7 +802,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::split) } auto rest = string.substring_view(start); - MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, rest))); + MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, TRY(Utf16String::create(vm, rest))))); return array; } @@ -867,7 +867,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::substring) size_t to = max(final_start, final_end); // 10. Return the substring of S from from to to. - return PrimitiveString::create(vm, string.substring_view(from, to - from)); + return PrimitiveString::create(vm, TRY(Utf16String::create(vm, string.substring_view(from, to - from)))); } enum class TargetCase { @@ -1111,7 +1111,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::substr) return PrimitiveString::create(vm, DeprecatedString::empty()); // 11. Return the substring of S from intStart to intEnd. - return PrimitiveString::create(vm, string.substring_view(int_start, int_end - int_start)); + return PrimitiveString::create(vm, TRY(Utf16String::create(vm, string.substring_view(int_start, int_end - int_start)))); } // B.2.2.2.1 CreateHTML ( string, tag, attribute, value ), https://tc39.es/ecma262/#sec-createhtml diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp index df93af001d..5a0506e021 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp @@ -146,8 +146,8 @@ ThrowCompletionOr get_option(VM& vm, Object const& options, PropertyKey c if (!values.is_empty()) { // NOTE: Every location in the spec that invokes GetOption with type=boolean also has values=undefined. VERIFY(value.is_string()); - if (!values.contains_slow(value.as_string().deprecated_string())) - return vm.throw_completion(ErrorType::OptionIsNotValidValue, value.as_string().deprecated_string(), property.as_string()); + if (auto const& value_string = TRY(value.as_string().deprecated_string()); !values.contains_slow(value_string)) + return vm.throw_completion(ErrorType::OptionIsNotValidValue, value_string, property.as_string()); } // 9. Return value. @@ -165,7 +165,7 @@ ThrowCompletionOr to_temporal_overflow(VM& vm, Object const* o auto option = TRY(get_option(vm, *options, vm.names.overflow, OptionType::String, { "constrain"sv, "reject"sv }, "constrain"sv)); VERIFY(option.is_string()); - return option.as_string().deprecated_string(); + return TRY(option.as_string().deprecated_string()); } // 13.5 ToTemporalDisambiguation ( options ), https://tc39.es/proposal-temporal/#sec-temporal-totemporaldisambiguation @@ -179,7 +179,7 @@ ThrowCompletionOr to_temporal_disambiguation(VM& vm, Object co auto option = TRY(get_option(vm, *options, vm.names.disambiguation, OptionType::String, { "compatible"sv, "earlier"sv, "later"sv, "reject"sv }, "compatible"sv)); VERIFY(option.is_string()); - return option.as_string().deprecated_string(); + return TRY(option.as_string().deprecated_string()); } // 13.6 ToTemporalRoundingMode ( normalizedOptions, fallback ), https://tc39.es/proposal-temporal/#sec-temporal-totemporalroundingmode @@ -202,7 +202,7 @@ ThrowCompletionOr to_temporal_rounding_mode(VM& vm, Object con fallback.view())); VERIFY(option.is_string()); - return option.as_string().deprecated_string(); + return TRY(option.as_string().deprecated_string()); } // 13.7 NegateTemporalRoundingMode ( roundingMode ), https://tc39.es/proposal-temporal/#sec-temporal-negatetemporalroundingmode @@ -239,7 +239,7 @@ ThrowCompletionOr to_temporal_offset(VM& vm, Object const* opt auto option = TRY(get_option(vm, *options, vm.names.offset, OptionType::String, { "prefer"sv, "use"sv, "ignore"sv, "reject"sv }, fallback.view())); VERIFY(option.is_string()); - return option.as_string().deprecated_string(); + return TRY(option.as_string().deprecated_string()); } // 13.9 ToCalendarNameOption ( normalizedOptions ), https://tc39.es/proposal-temporal/#sec-temporal-tocalendarnameoption @@ -249,7 +249,7 @@ ThrowCompletionOr to_calendar_name_option(VM& vm, Object const auto option = TRY(get_option(vm, normalized_options, vm.names.calendarName, OptionType::String, { "auto"sv, "always"sv, "never"sv, "critical"sv }, "auto"sv)); VERIFY(option.is_string()); - return option.as_string().deprecated_string(); + return TRY(option.as_string().deprecated_string()); } // 13.10 ToTimeZoneNameOption ( normalizedOptions ), https://tc39.es/proposal-temporal/#sec-temporal-totimezonenameoption @@ -259,7 +259,7 @@ ThrowCompletionOr to_time_zone_name_option(VM& vm, Object cons auto option = TRY(get_option(vm, normalized_options, vm.names.timeZoneName, OptionType::String, { "auto"sv, "never"sv, "critical"sv }, "auto"sv)); VERIFY(option.is_string()); - return option.as_string().deprecated_string(); + return TRY(option.as_string().deprecated_string()); } // 13.11 ToShowOffsetOption ( normalizedOptions ), https://tc39.es/proposal-temporal/#sec-temporal-toshowoffsetoption @@ -269,7 +269,7 @@ ThrowCompletionOr to_show_offset_option(VM& vm, Object const& auto option = TRY(get_option(vm, normalized_options, vm.names.offset, OptionType::String, { "auto"sv, "never"sv }, "auto"sv)); VERIFY(option.is_string()); - return option.as_string().deprecated_string(); + return TRY(option.as_string().deprecated_string()); } // 13.12 ToTemporalRoundingIncrement ( normalizedOptions, dividend, inclusive ), https://tc39.es/proposal-temporal/#sec-temporal-totemporalroundingincrement @@ -530,7 +530,7 @@ ThrowCompletionOr> get_temporal_unit(VM& vm, Object c Optional value = option_value.is_undefined() ? Optional {} - : option_value.as_string().deprecated_string(); + : TRY(option_value.as_string().deprecated_string()); // 11. If value is listed in the Plural column of Table 13, then for (auto const& row : temporal_units) { diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp index 3929a4e04d..685bb7726a 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp @@ -126,7 +126,7 @@ ThrowCompletionOr> calendar_fields(VM& vm, Object& cale Vector result; for (auto& value : list) - result.append(value.as_string().deprecated_string()); + result.append(TRY(value.as_string().deprecated_string())); return result; } @@ -781,7 +781,7 @@ ThrowCompletionOr resolve_iso_month(VM& vm, Object const& fields) // 6. Assert: Type(monthCode) is String. VERIFY(month_code.is_string()); - auto& month_code_string = month_code.as_string().deprecated_string(); + auto const& month_code_string = TRY(month_code.as_string().deprecated_string()); // 7. If the length of monthCode is not 3, throw a RangeError exception. auto month_length = month_code_string.length(); @@ -943,7 +943,7 @@ ThrowCompletionOr default_merge_calendar_fields(VM& vm, Object const& f // 3. For each element key of fieldsKeys, do for (auto& key : fields_keys) { // a. If key is not "month" or "monthCode", then - if (key.as_string().deprecated_string() != vm.names.month.as_string() && key.as_string().deprecated_string() != vm.names.monthCode.as_string()) { + if (!TRY(key.as_string().deprecated_string()).is_one_of(vm.names.month.as_string(), vm.names.monthCode.as_string())) { auto property_key = MUST(PropertyKey::from_value(vm, key)); // i. Let propValue be ? Get(fields, key). @@ -977,7 +977,7 @@ ThrowCompletionOr default_merge_calendar_fields(VM& vm, Object const& f } // See comment above. - additional_fields_keys_contains_month_or_month_code_property |= key.as_string().deprecated_string() == vm.names.month.as_string() || key.as_string().deprecated_string() == vm.names.monthCode.as_string(); + additional_fields_keys_contains_month_or_month_code_property |= TRY(key.as_string().deprecated_string()) == vm.names.month.as_string() || TRY(key.as_string().deprecated_string()) == vm.names.monthCode.as_string(); } // 6. If additionalFieldsKeys does not contain either "month" or "monthCode", then diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/CalendarPrototype.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/CalendarPrototype.cpp index d7611d5431..beaf9b76a3 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/CalendarPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/CalendarPrototype.cpp @@ -559,19 +559,21 @@ JS_DEFINE_NATIVE_FUNCTION(CalendarPrototype::fields) return TRY(iterator_close(vm, iterator_record, move(completion))); } + auto const& next_value_string = TRY(next_value.as_string().deprecated_string()); + // iii. If fieldNames contains nextValue, then if (field_names.contains_slow(next_value)) { // 1. Let completion be ThrowCompletion(a newly created RangeError object). - auto completion = vm.throw_completion(ErrorType::TemporalDuplicateCalendarField, next_value.as_string().deprecated_string()); + auto completion = vm.throw_completion(ErrorType::TemporalDuplicateCalendarField, next_value_string); // 2. Return ? IteratorClose(iteratorRecord, completion). return TRY(iterator_close(vm, iterator_record, move(completion))); } // iv. If nextValue is not one of "year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", then - if (!next_value.as_string().deprecated_string().is_one_of("year"sv, "month"sv, "monthCode"sv, "day"sv, "hour"sv, "minute"sv, "second"sv, "millisecond"sv, "microsecond"sv, "nanosecond"sv)) { + if (!next_value_string.is_one_of("year"sv, "month"sv, "monthCode"sv, "day"sv, "hour"sv, "minute"sv, "second"sv, "millisecond"sv, "microsecond"sv, "nanosecond"sv)) { // 1. Let completion be ThrowCompletion(a newly created RangeError object). - auto completion = vm.throw_completion(ErrorType::TemporalInvalidCalendarFieldName, next_value.as_string().deprecated_string()); + auto completion = vm.throw_completion(ErrorType::TemporalInvalidCalendarFieldName, next_value_string); // 2. Return ? IteratorClose(iteratorRecord, completion). return TRY(iterator_close(vm, iterator_record, move(completion))); diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTimePrototype.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTimePrototype.cpp index 3ac193b92f..8ecb6526ba 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTimePrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTimePrototype.cpp @@ -801,7 +801,7 @@ JS_DEFINE_NATIVE_FUNCTION(ZonedDateTimePrototype::with) // 18. Assert: Type(offsetString) is String. VERIFY(offset_string_value.is_string()); - auto const& offset_string = offset_string_value.as_string().deprecated_string(); + auto const& offset_string = TRY(offset_string_value.as_string().deprecated_string()); // 19. Let dateTimeResult be ? InterpretTemporalDateTimeFields(calendar, fields, options). auto date_time_result = TRY(interpret_temporal_date_time_fields(vm, calendar, *fields, *options)); diff --git a/Userland/Libraries/LibJS/Runtime/Utf16String.cpp b/Userland/Libraries/LibJS/Runtime/Utf16String.cpp index 098d761e67..3114e4b661 100644 --- a/Userland/Libraries/LibJS/Runtime/Utf16String.cpp +++ b/Userland/Libraries/LibJS/Runtime/Utf16String.cpp @@ -11,9 +11,9 @@ namespace JS { namespace Detail { -static NonnullRefPtr the_empty_utf16_string() +static ThrowCompletionOr> the_empty_utf16_string(VM& vm) { - static NonnullRefPtr empty_string = Utf16StringImpl::create(); + static NonnullRefPtr empty_string = TRY(Utf16StringImpl::create(vm)); return empty_string; } @@ -22,27 +22,27 @@ Utf16StringImpl::Utf16StringImpl(Utf16Data string) { } -NonnullRefPtr Utf16StringImpl::create() +ThrowCompletionOr> Utf16StringImpl::create(VM& vm) { - return adopt_ref(*new Utf16StringImpl()); + return TRY_OR_THROW_OOM(vm, adopt_nonnull_ref_or_enomem(new (nothrow) Utf16StringImpl())); } -NonnullRefPtr Utf16StringImpl::create(Utf16Data string) +ThrowCompletionOr> Utf16StringImpl::create(VM& vm, Utf16Data string) { - return adopt_ref(*new Utf16StringImpl(move(string))); + return TRY_OR_THROW_OOM(vm, adopt_nonnull_ref_or_enomem(new (nothrow) Utf16StringImpl(move(string)))); } -NonnullRefPtr Utf16StringImpl::create(StringView string) +ThrowCompletionOr> Utf16StringImpl::create(VM& vm, StringView string) { - return create(AK::utf8_to_utf16(string).release_value_but_fixme_should_propagate_errors()); + return create(vm, TRY_OR_THROW_OOM(vm, utf8_to_utf16(string))); } -NonnullRefPtr Utf16StringImpl::create(Utf16View const& view) +ThrowCompletionOr> Utf16StringImpl::create(VM& vm, Utf16View const& view) { Utf16Data string; - string.ensure_capacity(view.length_in_code_units()); - string.append(view.data(), view.length_in_code_units()); - return create(move(string)); + TRY_OR_THROW_OOM(vm, string.try_ensure_capacity(view.length_in_code_units())); + string.unchecked_append(view.data(), view.length_in_code_units()); + return create(vm, move(string)); } Utf16Data const& Utf16StringImpl::string() const @@ -57,23 +57,28 @@ Utf16View Utf16StringImpl::view() const } -Utf16String::Utf16String() - : m_string(Detail::the_empty_utf16_string()) +ThrowCompletionOr Utf16String::create(VM& vm) { + return Utf16String { TRY(Detail::the_empty_utf16_string(vm)) }; } -Utf16String::Utf16String(Utf16Data string) - : m_string(Detail::Utf16StringImpl::create(move(string))) +ThrowCompletionOr Utf16String::create(VM& vm, Utf16Data string) { + return Utf16String { TRY(Detail::Utf16StringImpl::create(vm, move(string))) }; } -Utf16String::Utf16String(StringView string) - : m_string(Detail::Utf16StringImpl::create(move(string))) +ThrowCompletionOr Utf16String::create(VM& vm, StringView string) { + return Utf16String { TRY(Detail::Utf16StringImpl::create(vm, string)) }; } -Utf16String::Utf16String(Utf16View const& string) - : m_string(Detail::Utf16StringImpl::create(move(string))) +ThrowCompletionOr Utf16String::create(VM& vm, Utf16View const& string) +{ + return Utf16String { TRY(Detail::Utf16StringImpl::create(vm, string)) }; +} + +Utf16String::Utf16String(NonnullRefPtr string) + : m_string(move(string)) { } diff --git a/Userland/Libraries/LibJS/Runtime/Utf16String.h b/Userland/Libraries/LibJS/Runtime/Utf16String.h index 4b101a8261..6b6b7d9db1 100644 --- a/Userland/Libraries/LibJS/Runtime/Utf16String.h +++ b/Userland/Libraries/LibJS/Runtime/Utf16String.h @@ -21,10 +21,10 @@ class Utf16StringImpl : public RefCounted { public: ~Utf16StringImpl() = default; - static NonnullRefPtr create(); - static NonnullRefPtr create(Utf16Data); - static NonnullRefPtr create(StringView); - static NonnullRefPtr create(Utf16View const&); + static ThrowCompletionOr> create(VM&); + static ThrowCompletionOr> create(VM&, Utf16Data); + static ThrowCompletionOr> create(VM&, StringView); + static ThrowCompletionOr> create(VM&, Utf16View const&); Utf16Data const& string() const; Utf16View view() const; @@ -40,10 +40,10 @@ private: class Utf16String { public: - Utf16String(); - explicit Utf16String(Utf16Data); - explicit Utf16String(StringView); - explicit Utf16String(Utf16View const&); + static ThrowCompletionOr create(VM&); + static ThrowCompletionOr create(VM&, Utf16Data); + static ThrowCompletionOr create(VM&, StringView); + static ThrowCompletionOr create(VM&, Utf16View const&); Utf16Data const& string() const; Utf16View view() const; @@ -57,6 +57,8 @@ public: bool is_empty() const; private: + explicit Utf16String(NonnullRefPtr); + NonnullRefPtr m_string; }; diff --git a/Userland/Libraries/LibJS/Runtime/Value.cpp b/Userland/Libraries/LibJS/Runtime/Value.cpp index ed93bb6c4e..4c840429cb 100644 --- a/Userland/Libraries/LibJS/Runtime/Value.cpp +++ b/Userland/Libraries/LibJS/Runtime/Value.cpp @@ -351,7 +351,7 @@ DeprecatedString Value::to_string_without_side_effects() const case INT32_TAG: return DeprecatedString::number(as_i32()); case STRING_TAG: - return as_string().deprecated_string(); + return MUST(as_string().deprecated_string()); case SYMBOL_TAG: return as_symbol().to_deprecated_string(); case BIGINT_TAG: @@ -382,7 +382,7 @@ ThrowCompletionOr Value::to_string(VM& vm) const switch (m_value.tag) { // 1. If argument is a String, return argument. case STRING_TAG: - return as_string().deprecated_string(); + return TRY(as_string().deprecated_string()); // 2. If argument is a Symbol, throw a TypeError exception. case SYMBOL_TAG: return vm.throw_completion(ErrorType::Convert, "symbol", "string"); @@ -421,10 +421,10 @@ ThrowCompletionOr Value::to_string(VM& vm) const ThrowCompletionOr Value::to_utf16_string(VM& vm) const { if (is_string()) - return as_string().utf16_string(); + return TRY(as_string().utf16_string()); auto utf8_string = TRY(to_string(vm)); - return Utf16String(utf8_string); + return Utf16String::create(vm, utf8_string); } // 7.1.2 ToBoolean ( argument ), https://tc39.es/ecma262/#sec-toboolean @@ -684,7 +684,7 @@ ThrowCompletionOr Value::to_number(VM& vm) const return Value(as_bool() ? 1 : 0); // 6. If argument is a String, return StringToNumber(argument). case STRING_TAG: - return string_to_number(as_string().deprecated_string().view()); + return string_to_number(TRY(as_string().deprecated_string())); // 7. Assert: argument is an Object. case OBJECT_TAG: { // 8. Let primValue be ? ToPrimitive(argument, number). @@ -738,7 +738,7 @@ ThrowCompletionOr Value::to_bigint(VM& vm) const return &primitive.as_bigint(); case STRING_TAG: { // 1. Let n be ! StringToBigInt(prim). - auto bigint = string_to_bigint(vm, primitive.as_string().deprecated_string()); + auto bigint = string_to_bigint(vm, TRY(primitive.as_string().deprecated_string())); // 2. If n is undefined, throw a SyntaxError exception. if (!bigint.has_value()) @@ -2150,7 +2150,8 @@ bool same_value_non_number(Value lhs, Value rhs) // 5. If x is a String, then if (lhs.is_string()) { // a. If x and y are exactly the same sequence of code units (same length and same code units at corresponding indices), return true; otherwise, return false. - return lhs.as_string().deprecated_string() == rhs.as_string().deprecated_string(); + // FIXME: Propagate this error. + return MUST(lhs.as_string().deprecated_string()) == MUST(rhs.as_string().deprecated_string()); } // 3. If x is undefined, return true. @@ -2231,7 +2232,7 @@ ThrowCompletionOr is_loosely_equal(VM& vm, Value lhs, Value rhs) // 7. If Type(x) is BigInt and Type(y) is String, then if (lhs.is_bigint() && rhs.is_string()) { // a. Let n be StringToBigInt(y). - auto bigint = string_to_bigint(vm, rhs.as_string().deprecated_string()); + auto bigint = string_to_bigint(vm, TRY(rhs.as_string().deprecated_string())); // b. If n is undefined, return false. if (!bigint.has_value()) @@ -2312,8 +2313,8 @@ ThrowCompletionOr is_less_than(VM& vm, Value lhs, Value rhs, bool left // 3. If px is a String and py is a String, then if (x_primitive.is_string() && y_primitive.is_string()) { - auto x_string = x_primitive.as_string().deprecated_string(); - auto y_string = y_primitive.as_string().deprecated_string(); + auto x_string = TRY(x_primitive.as_string().deprecated_string()); + auto y_string = TRY(y_primitive.as_string().deprecated_string()); Utf8View x_code_points { x_string }; Utf8View y_code_points { y_string }; @@ -2348,7 +2349,7 @@ ThrowCompletionOr is_less_than(VM& vm, Value lhs, Value rhs, bool left // a. If px is a BigInt and py is a String, then if (x_primitive.is_bigint() && y_primitive.is_string()) { // i. Let ny be StringToBigInt(py). - auto y_bigint = string_to_bigint(vm, y_primitive.as_string().deprecated_string()); + auto y_bigint = string_to_bigint(vm, TRY(y_primitive.as_string().deprecated_string())); // ii. If ny is undefined, return undefined. if (!y_bigint.has_value()) @@ -2363,7 +2364,7 @@ ThrowCompletionOr is_less_than(VM& vm, Value lhs, Value rhs, bool left // b. If px is a String and py is a BigInt, then if (x_primitive.is_string() && y_primitive.is_bigint()) { // i. Let nx be StringToBigInt(px). - auto x_bigint = string_to_bigint(vm, x_primitive.as_string().deprecated_string()); + auto x_bigint = string_to_bigint(vm, TRY(x_primitive.as_string().deprecated_string())); // ii. If nx is undefined, return undefined. if (!x_bigint.has_value()) diff --git a/Userland/Libraries/LibJS/Runtime/ValueTraits.h b/Userland/Libraries/LibJS/Runtime/ValueTraits.h index 2bae2c9cde..c88fddc709 100644 --- a/Userland/Libraries/LibJS/Runtime/ValueTraits.h +++ b/Userland/Libraries/LibJS/Runtime/ValueTraits.h @@ -16,8 +16,10 @@ struct ValueTraits : public Traits { static unsigned hash(Value value) { VERIFY(!value.is_empty()); - if (value.is_string()) - return value.as_string().deprecated_string().hash(); + if (value.is_string()) { + // FIXME: Propagate this error. + return value.as_string().deprecated_string().release_value().hash(); + } if (value.is_bigint()) return value.as_bigint().big_integer().hash(); diff --git a/Userland/Libraries/LibWeb/Fetch/Body.cpp b/Userland/Libraries/LibWeb/Fetch/Body.cpp index 5835e8d89d..6acc57173d 100644 --- a/Userland/Libraries/LibWeb/Fetch/Body.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Body.cpp @@ -163,7 +163,7 @@ JS::NonnullGCPtr consume_body(JS::Realm& realm, BodyMixin const& ob // 4. Let steps be to return the result of package data with the first argument given, type, and object’s MIME type. auto steps = [&vm, &realm, &object, type](JS::Value value) -> WebIDL::ExceptionOr { VERIFY(value.is_string()); - auto bytes = TRY_OR_THROW_OOM(vm, ByteBuffer::copy(value.as_string().deprecated_string().bytes())); + auto bytes = TRY_OR_THROW_OOM(vm, ByteBuffer::copy(TRY(value.as_string().deprecated_string()).bytes())); return package_data(realm, move(bytes), type, object.mime_type_impl()); }; diff --git a/Userland/Libraries/LibWeb/Infra/JSON.cpp b/Userland/Libraries/LibWeb/Infra/JSON.cpp index 8e2e2a1568..91977659e2 100644 --- a/Userland/Libraries/LibWeb/Infra/JSON.cpp +++ b/Userland/Libraries/LibWeb/Infra/JSON.cpp @@ -49,7 +49,7 @@ WebIDL::ExceptionOr serialize_javascript_value_to_json_string( VERIFY(result.is_string()); // 4. Return result. - return result.as_string().deprecated_string(); + return TRY(result.as_string().deprecated_string()); } // https://infra.spec.whatwg.org/#serialize-a-javascript-value-to-json-bytes diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyTableConstructor.cpp b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyTableConstructor.cpp index c63a16a877..337d32b52e 100644 --- a/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyTableConstructor.cpp +++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssemblyTableConstructor.cpp @@ -35,7 +35,7 @@ JS::ThrowCompletionOr> WebAssemblyTableConstructor: auto element_value = TRY(descriptor->get("element")); if (!element_value.is_string()) return vm.throw_completion(JS::ErrorType::InvalidHint, element_value.to_string_without_side_effects()); - auto& element = element_value.as_string().deprecated_string(); + auto const& element = TRY(element_value.as_string().deprecated_string()); Optional reference_type; if (element == "anyfunc"sv) diff --git a/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.cpp b/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.cpp index 1f4744f35d..1fa2b62263 100644 --- a/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.cpp +++ b/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.cpp @@ -95,7 +95,7 @@ static ErrorOr internal_json_clone_algorithm if (value.is_number()) return JsonValue { value.as_double() }; if (value.is_string()) - return JsonValue { value.as_string().deprecated_string() }; + return JsonValue { TRY_OR_JS_ERROR(value.as_string().deprecated_string()) }; // NOTE: BigInt and Symbol not mentioned anywhere in the WebDriver spec, as it references ES5. // It assumes that all primitives are handled above, and the value is an object for the remaining steps. @@ -114,7 +114,7 @@ static ErrorOr internal_json_clone_algorithm auto to_json_result = TRY_OR_JS_ERROR(to_json.as_function().internal_call(value, JS::MarkedVector { vm.heap() })); if (!to_json_result.is_string()) return ExecuteScriptResultType::JavaScriptError; - return to_json_result.as_string().deprecated_string(); + return TRY_OR_JS_ERROR(to_json_result.as_string().deprecated_string()); } // -> Otherwise