diff --git a/runtime/tests/concurrency/stress_test_list.json b/runtime/tests/concurrency/stress_test_list.json index 6a766c4943a..5b094ac098e 100644 --- a/runtime/tests/concurrency/stress_test_list.json +++ b/runtime/tests/concurrency/stress_test_list.json @@ -180,7 +180,6 @@ "../vm/dart/slow_path_shared_stub_test.dart", "../vm/dart/stack_overflow_shared_test.dart", "../vm/dart/stacktrace_mixin_application_test.dart", - "../vm/dart/strict_null_safety_checks_in_weak_mode_test.dart", "../vm/dart/string_equals_test.dart", "../vm/dart/string_intern_test.dart", "../vm/dart/switchable_call_monomorphic_regression_42517_test.dart", diff --git a/runtime/tests/vm/dart/strict_null_safety_checks_in_weak_mode_test.dart b/runtime/tests/vm/dart/strict_null_safety_checks_in_weak_mode_test.dart deleted file mode 100644 index b70a3d4e0c7..00000000000 --- a/runtime/tests/vm/dart/strict_null_safety_checks_in_weak_mode_test.dart +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// This test verifies that with --strict_null_safety_checks runtime casts and -// required parameters have strong mode semantics in weak mode. -// Derived from tests/language/nnbd/subtyping/type_casts_strong_test.dart -// and tests/language/nnbd/required_named_parameters/required_named_args_strong_test.dart. - -// VMOptions=--strict_null_safety_checks --optimization_counter_threshold=10 --deterministic -// Requirements=nnbd-weak - -import 'package:expect/expect.dart'; - -class C {} - -class W { - @pragma('vm:never-inline') - asT(arg) => arg as T; - - @pragma('vm:never-inline') - asNullableT(arg) => arg as T?; - - @pragma('vm:never-inline') - asXT(arg) => arg as X; - - @pragma('vm:never-inline') - asNullableXT(arg) => arg as X?; - - @pragma('vm:never-inline') - asXNullableT(arg) => arg as X; -} - -class X {} - -class Y {} - -class Z extends Y {} - -testCasts() { - // Testing 'arg as T', T = Y - final wy = new W(); - wy.asT(new Y()); - wy.asT(new Z()); - Expect.throwsTypeError(() { - wy.asT(null); - }); - Expect.throwsTypeError(() { - wy.asT(new C()); - }); - - // Testing 'arg as T?', T = Y - wy.asNullableT(new Y()); - wy.asNullableT(new Z()); - wy.asNullableT(null); - Expect.throwsTypeError(() { - wy.asNullableT(new C()); - }); - - // Testing 'arg as X', T = Y - wy.asXT(new X()); - wy.asXT(new X()); - Expect.throwsTypeError(() { - wy.asXT(null); - }); - Expect.throwsTypeError(() { - wy.asXT(new X()); - }); - Expect.throwsTypeError(() { - wy.asXT(new X()); - }); - - // Testing 'arg as X?', T = Y - wy.asNullableXT(new X()); - wy.asNullableXT(new X()); - wy.asNullableXT(null); - Expect.throwsTypeError(() { - wy.asNullableXT(new X()); - }); - Expect.throwsTypeError(() { - wy.asNullableXT(new X()); - }); - - // Testing 'arg as X', T = Y - wy.asXNullableT(new X()); - wy.asXNullableT(new X()); - wy.asXNullableT(new X()); - Expect.throwsTypeError(() { - wy.asXNullableT(null); - }); - Expect.throwsTypeError(() { - wy.asXNullableT(new X()); - }); - - // Testing 'arg as X', T = Y? - final wny = new W(); - wny.asXT(new X()); - wny.asXT(new X()); - wny.asXT(new X()); - Expect.throwsTypeError(() { - wny.asXT(null); - }); - Expect.throwsTypeError(() { - wny.asXT(new X()); - }); -} - -func(String q0, {bool p3 = false, required int p1, required String p2}) => ""; - -testRequiredParameters() { - dynamic f = func; - - // Invalid: Subtype may not redeclare optional parameters as required. - Expect.throwsTypeError(() { - Function( - String p0, { - required int p1, - String p2, - }) t2 = f; - }); - - // Invalid: Subtype may not declare new required named parameters. - Expect.throwsTypeError(() { - Function( - String p0, { - required int p1, - }) t3 = f; - }); - - // Invalid: Invocation with explicit null required named argument. - Expect.throwsTypeError(() { - f("", p1: null, p2: null); - }); - Expect.throwsTypeError(() { - Function.apply(f, [""], {#p1: null, #p2: null}); - }); - - // Invalid: Invocation that omits a required named argument. - Expect.throwsNoSuchMethodError(() { - f("", p1: 100); - }); - Expect.throwsNoSuchMethodError(() { - Function.apply(f, [""], {#p1: 100}); - }); -} - -main() { - for (int i = 0; i < 20; ++i) { - testCasts(); - testRequiredParameters(); - } -} diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc index 11c38f4fdd5..ef0c8c7ee3f 100644 --- a/runtime/vm/compiler/backend/flow_graph_compiler.cc +++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc @@ -2901,8 +2901,7 @@ void FlowGraphCompiler::GenerateCallerChecksForAssertAssignable( if (dst_type.IsObjectType()) { // Special case: non-nullable Object. - ASSERT(dst_type.IsNonNullable() && - isolate_group()->use_strict_null_safety_checks()); + ASSERT(dst_type.IsNonNullable()); __ CompareObject(TypeTestABI::kInstanceReg, Object::null_object()); __ BranchIf(NOT_EQUAL, done); // Fall back to type testing stub in caller to throw the exception. @@ -2924,8 +2923,7 @@ void FlowGraphCompiler::GenerateCallerChecksForAssertAssignable( // Special case: Instantiate the type parameter on the caller side, invoking // the TTS of the corresponding type parameter in the caller. const TypeParameter& type_param = TypeParameter::Cast(dst_type); - if (isolate_group()->use_strict_null_safety_checks() && - !type_param.IsNonNullable()) { + if (!type_param.IsNonNullable()) { // If the type parameter is nullable when running in strong mode, we need // to handle null before calling the TTS because the type parameter may be // instantiated with a non-nullable type, where the TTS rejects null. diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc index 381cf0b64bf..d4ca3e7e00b 100644 --- a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc +++ b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc @@ -282,22 +282,15 @@ void FlowGraphCompiler::GenerateAssertAssignable( if (dst_type.IsNull()) { __ Comment("AssertAssignable for runtime type"); // kDstTypeReg should already contain the destination type. - const bool null_safety = - IsolateGroup::Current()->use_strict_null_safety_checks(); - GenerateNonLazyDeoptableStubCall( - source, - null_safety ? StubCode::TypeIsTopTypeForSubtypingNullSafe() - : StubCode::TypeIsTopTypeForSubtyping(), - UntaggedPcDescriptors::kOther, locs); + GenerateNonLazyDeoptableStubCall(source, + StubCode::TypeIsTopTypeForSubtyping(), + UntaggedPcDescriptors::kOther, locs); // TypeTestABI::kSubtypeTestCacheReg is 0 if the type is a top type. __ BranchIfZero(TypeTestABI::kSubtypeTestCacheReg, &is_assignable, compiler::Assembler::kNearJump); - GenerateNonLazyDeoptableStubCall( - source, - null_safety ? StubCode::NullIsAssignableToTypeNullSafe() - : StubCode::NullIsAssignableToType(), - UntaggedPcDescriptors::kOther, locs); + GenerateNonLazyDeoptableStubCall(source, StubCode::NullIsAssignableToType(), + UntaggedPcDescriptors::kOther, locs); // TypeTestABI::kSubtypeTestCacheReg is 0 if the object is null and is // assignable. __ BranchIfZero(TypeTestABI::kSubtypeTestCacheReg, &is_assignable, diff --git a/runtime/vm/compiler/backend/type_propagator_test.cc b/runtime/vm/compiler/backend/type_propagator_test.cc index 42b3de66535..ebe53f37e43 100644 --- a/runtime/vm/compiler/backend/type_propagator_test.cc +++ b/runtime/vm/compiler/backend/type_propagator_test.cc @@ -634,11 +634,10 @@ ISOLATE_UNIT_TEST_CASE(TypePropagator_RedefineCanBeSentinelWithCannotBe) { { BlockBuilder builder(H.flow_graph(), b3); v7 = builder.AddDefinition(new RedefinitionInstr(new Value(v3))); - CompileType int_type = CompileType::FromAbstractType( - Type::Handle(Type::IntType()), - /*can_be_null=*/ - !IsolateGroup::Current()->use_strict_null_safety_checks(), - /*can_be_sentinel=*/false); + CompileType int_type = + CompileType::FromAbstractType(Type::Handle(Type::IntType()), + /*can_be_null=*/true, + /*can_be_sentinel=*/false); v7->AsRedefinition()->set_constrained_type(new CompileType(int_type)); builder.AddInstruction(new GotoInstr(b4, S.GetNextDeoptId())); } diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc index d25982b9ccd..78117d9adeb 100644 --- a/runtime/vm/compiler/frontend/kernel_to_il.cc +++ b/runtime/vm/compiler/frontend/kernel_to_il.cc @@ -2966,9 +2966,6 @@ Fragment FlowGraphBuilder::TestClosureFunctionNamedParameterRequired( const ClosureCallInfo& info, Fragment set, Fragment not_set) { - // Required named arguments only exist if null_safety is enabled. - if (!IG->use_strict_null_safety_checks()) return not_set; - Fragment check_required; // We calculate the index to dereference in the parameter names array. check_required += LoadLocal(info.vars->current_param_index); @@ -3140,10 +3137,6 @@ Fragment FlowGraphBuilder::BuildClosureCallNamedArgumentsCheck( // When no named arguments are provided, we just need to check for possible // required named arguments. if (info.descriptor.NamedCount() == 0) { - // No work to do if there are no possible required named parameters. - if (!IG->use_strict_null_safety_checks()) { - return Fragment(); - } // If the below changes, we can no longer assume that flag slots existing // means there are required parameters. static_assert(compiler::target::kNumParameterFlags == 1, diff --git a/runtime/vm/compiler/frontend/prologue_builder.cc b/runtime/vm/compiler/frontend/prologue_builder.cc index f4858e53bbf..49523562696 100644 --- a/runtime/vm/compiler/frontend/prologue_builder.cc +++ b/runtime/vm/compiler/frontend/prologue_builder.cc @@ -197,8 +197,6 @@ Fragment PrologueBuilder::BuildParameterHandling() { copy_args_prologue.current = next_missing; } else if (num_opt_named_params > 0) { - const bool check_required_params = - IsolateGroup::Current()->use_strict_null_safety_checks(); const intptr_t first_name_offset = compiler::target::ArgumentsDescriptor::first_named_entry_offset() - compiler::target::Array::data_offset(); @@ -265,8 +263,7 @@ Fragment PrologueBuilder::BuildParameterHandling() { good += Drop(); } - const bool required = check_required_params && - function_.IsRequiredAt(opt_param_position[i]); + const bool required = function_.IsRequiredAt(opt_param_position[i]); if (required) { copy_args_prologue += good; diff --git a/runtime/vm/compiler/stub_code_compiler.cc b/runtime/vm/compiler/stub_code_compiler.cc index 2abf5d8915a..95270122968 100644 --- a/runtime/vm/compiler/stub_code_compiler.cc +++ b/runtime/vm/compiler/stub_code_compiler.cc @@ -706,8 +706,7 @@ static void EnsureIsTypeOrFunctionTypeOrTypeParameter(Assembler* assembler, // non-zero otherwise. // // All registers other than outputs and non-preserved scratches are preserved. -static void GenerateTypeIsTopTypeForSubtyping(Assembler* assembler, - bool null_safety) { +void StubCodeCompiler::GenerateTypeIsTopTypeForSubtypingStub() { // The only case where the original value of kSubtypeTestCacheReg is needed // after the stub call is on IA32, where it's currently preserved on the stack // before calling the stub (as it's also CODE_REG on that architecture), so we @@ -755,13 +754,11 @@ static void GenerateTypeIsTopTypeForSubtyping(Assembler* assembler, __ BranchIf(EQUAL, &unwrap_future_or, compiler::Assembler::kNearJump); __ CompareImmediate(scratch2_reg, kInstanceCid); __ BranchIf(NOT_EQUAL, &done, compiler::Assembler::kNearJump); - if (null_safety) { - // Instance type isn't a top type if non-nullable in null safe mode. - __ CompareAbstractTypeNullabilityWith( - scratch1_reg, static_cast(Nullability::kNonNullable), - scratch2_reg); - __ BranchIf(EQUAL, &done, compiler::Assembler::kNearJump); - } + // Instance type isn't a top type if non-nullable. + __ CompareAbstractTypeNullabilityWith( + scratch1_reg, static_cast(Nullability::kNonNullable), + scratch2_reg); + __ BranchIf(EQUAL, &done, compiler::Assembler::kNearJump); __ Bind(&is_top_type); __ LoadImmediate(output_reg, 0); __ Bind(&done); @@ -786,14 +783,6 @@ static void GenerateTypeIsTopTypeForSubtyping(Assembler* assembler, __ Jump(&check_top_type, compiler::Assembler::kNearJump); } -void StubCodeCompiler::GenerateTypeIsTopTypeForSubtypingStub() { - GenerateTypeIsTopTypeForSubtyping(assembler, /*null_safety=*/false); -} - -void StubCodeCompiler::GenerateTypeIsTopTypeForSubtypingNullSafeStub() { - GenerateTypeIsTopTypeForSubtyping(assembler, /*null_safety=*/true); -} - // Version of Instance::NullIsAssignableTo(other, inst_tav, fun_tav) used when // the destination type was not known at compile time. Must be kept in sync. // @@ -811,8 +800,7 @@ void StubCodeCompiler::GenerateTypeIsTopTypeForSubtypingNullSafeStub() { // non-zero otherwise. // // All registers other than outputs and non-preserved scratches are preserved. -static void GenerateNullIsAssignableToType(Assembler* assembler, - bool null_safety) { +void StubCodeCompiler::GenerateNullIsAssignableToTypeStub() { // The only case where the original value of kSubtypeTestCacheReg is needed // after the stub call is on IA32, where it's currently preserved on the stack // before calling the stub (as it's also CODE_REG on that architecture), so we @@ -839,87 +827,83 @@ static void GenerateNullIsAssignableToType(Assembler* assembler, compiler::Label is_assignable, done; // Initialize the first scratch register (and thus the output register) with // the destination type. We do this before the check to ensure the output - // register has a non-zero value if !null_safety and kInstanceReg is not null. + // register has a non-zero value if kInstanceReg is not null. __ MoveRegister(kCurrentTypeReg, TypeTestABI::kDstTypeReg); __ CompareObject(TypeTestABI::kInstanceReg, Object::null_object()); - if (null_safety) { - compiler::Label check_null_assignable; - // Skip checking the type if not null. - __ BranchIf(NOT_EQUAL, &done); - __ Bind(&check_null_assignable); - // scratch1_reg: Current type to check. - EnsureIsTypeOrFunctionTypeOrTypeParameter(assembler, kCurrentTypeReg, - kScratchReg); - compiler::Label is_not_type; - __ CompareClassId(kCurrentTypeReg, kTypeCid, kScratchReg); - __ BranchIf(NOT_EQUAL, &is_not_type, compiler::Assembler::kNearJump); - __ CompareAbstractTypeNullabilityWith( - kCurrentTypeReg, static_cast(Nullability::kNonNullable), - kScratchReg); - __ BranchIf(NOT_EQUAL, &is_assignable); - // FutureOr is a special case because it may have the non-nullable bit set, - // but FutureOr functions as the union of T and Future, so it must be - // unwrapped to see if T is nullable. - __ LoadTypeClassId(kScratchReg, kCurrentTypeReg); - __ CompareImmediate(kScratchReg, kFutureOrCid); - __ BranchIf(NOT_EQUAL, &done); - __ LoadCompressedField( - kScratchReg, - compiler::FieldAddress(kCurrentTypeReg, - compiler::target::Type::arguments_offset())); - __ CompareObject(kScratchReg, Object::null_object()); - // If the arguments are null, then unwrapping gives the dynamic type, - // which can take null. - __ BranchIf(EQUAL, &is_assignable); - __ LoadCompressedField( - kCurrentTypeReg, - compiler::FieldAddress( - kScratchReg, compiler::target::TypeArguments::type_at_offset(0))); - __ Jump(&check_null_assignable, compiler::Assembler::kNearJump); - __ Bind(&is_not_type); - // Null is assignable to a type parameter only if it is nullable or if the - // instantiation is nullable. - __ CompareAbstractTypeNullabilityWith( - kCurrentTypeReg, static_cast(Nullability::kNonNullable), - kScratchReg); - __ BranchIf(NOT_EQUAL, &is_assignable); - // Don't set kScratchReg in here as on IA32, that's the function TAV reg. - auto handle_case = [&](Register tav) { - // We can reuse kCurrentTypeReg to hold the index because we no longer - // need the type parameter afterwards. - auto const kIndexReg = kCurrentTypeReg; - // If the TAV is null, resolving gives the (nullable) dynamic type. - __ CompareObject(tav, NullObject()); - __ BranchIf(EQUAL, &is_assignable, Assembler::kNearJump); - // Resolve the type parameter to its instantiated type and loop. - __ LoadFieldFromOffset(kIndexReg, kCurrentTypeReg, - target::TypeParameter::index_offset(), - kUnsignedTwoBytes); - __ LoadIndexedCompressed(kCurrentTypeReg, tav, - target::TypeArguments::types_offset(), - kIndexReg); - __ Jump(&check_null_assignable); - }; + compiler::Label check_null_assignable; + // Skip checking the type if not null. + __ BranchIf(NOT_EQUAL, &done); + __ Bind(&check_null_assignable); + // scratch1_reg: Current type to check. + EnsureIsTypeOrFunctionTypeOrTypeParameter(assembler, kCurrentTypeReg, + kScratchReg); + compiler::Label is_not_type; + __ CompareClassId(kCurrentTypeReg, kTypeCid, kScratchReg); + __ BranchIf(NOT_EQUAL, &is_not_type, compiler::Assembler::kNearJump); + __ CompareAbstractTypeNullabilityWith( + kCurrentTypeReg, static_cast(Nullability::kNonNullable), + kScratchReg); + __ BranchIf(NOT_EQUAL, &is_assignable); + // FutureOr is a special case because it may have the non-nullable bit set, + // but FutureOr functions as the union of T and Future, so it must be + // unwrapped to see if T is nullable. + __ LoadTypeClassId(kScratchReg, kCurrentTypeReg); + __ CompareImmediate(kScratchReg, kFutureOrCid); + __ BranchIf(NOT_EQUAL, &done); + __ LoadCompressedField( + kScratchReg, + compiler::FieldAddress(kCurrentTypeReg, + compiler::target::Type::arguments_offset())); + __ CompareObject(kScratchReg, Object::null_object()); + // If the arguments are null, then unwrapping gives the dynamic type, + // which can take null. + __ BranchIf(EQUAL, &is_assignable); + __ LoadCompressedField( + kCurrentTypeReg, + compiler::FieldAddress( + kScratchReg, compiler::target::TypeArguments::type_at_offset(0))); + __ Jump(&check_null_assignable, compiler::Assembler::kNearJump); + __ Bind(&is_not_type); + // Null is assignable to a type parameter only if it is nullable or if the + // instantiation is nullable. + __ CompareAbstractTypeNullabilityWith( + kCurrentTypeReg, static_cast(Nullability::kNonNullable), + kScratchReg); + __ BranchIf(NOT_EQUAL, &is_assignable); - Label function_type_param; - __ LoadFromSlot(kScratchReg, TypeTestABI::kDstTypeReg, - Slot::AbstractType_flags()); - __ BranchIfBit(kScratchReg, - target::UntaggedTypeParameter::kIsFunctionTypeParameterBit, - NOT_ZERO, &function_type_param, Assembler::kNearJump); - handle_case(TypeTestABI::kInstantiatorTypeArgumentsReg); - __ Bind(&function_type_param); + // Don't set kScratchReg in here as on IA32, that's the function TAV reg. + auto handle_case = [&](Register tav) { + // We can reuse kCurrentTypeReg to hold the index because we no longer + // need the type parameter afterwards. + auto const kIndexReg = kCurrentTypeReg; + // If the TAV is null, resolving gives the (nullable) dynamic type. + __ CompareObject(tav, NullObject()); + __ BranchIf(EQUAL, &is_assignable, Assembler::kNearJump); + // Resolve the type parameter to its instantiated type and loop. + __ LoadFieldFromOffset(kIndexReg, kCurrentTypeReg, + target::TypeParameter::index_offset(), + kUnsignedTwoBytes); + __ LoadIndexedCompressed(kCurrentTypeReg, tav, + target::TypeArguments::types_offset(), kIndexReg); + __ Jump(&check_null_assignable); + }; + + Label function_type_param; + __ LoadFromSlot(kScratchReg, TypeTestABI::kDstTypeReg, + Slot::AbstractType_flags()); + __ BranchIfBit(kScratchReg, + target::UntaggedTypeParameter::kIsFunctionTypeParameterBit, + NOT_ZERO, &function_type_param, Assembler::kNearJump); + handle_case(TypeTestABI::kInstantiatorTypeArgumentsReg); + __ Bind(&function_type_param); #if defined(TARGET_ARCH_IA32) - // Function TAV is on top of stack because we're using that register as - // kScratchReg. - __ LoadFromStack(TypeTestABI::kFunctionTypeArgumentsReg, 0); + // Function TAV is on top of stack because we're using that register as + // kScratchReg. + __ LoadFromStack(TypeTestABI::kFunctionTypeArgumentsReg, 0); #endif - handle_case(TypeTestABI::kFunctionTypeArgumentsReg); - } else { - // Null in non-null-safe mode is always assignable. - __ BranchIf(NOT_EQUAL, &done, compiler::Assembler::kNearJump); - } + handle_case(TypeTestABI::kFunctionTypeArgumentsReg); + __ Bind(&is_assignable); __ LoadImmediate(kOutputReg, 0); __ Bind(&done); @@ -930,13 +914,6 @@ static void GenerateNullIsAssignableToType(Assembler* assembler, __ Ret(); } -void StubCodeCompiler::GenerateNullIsAssignableToTypeStub() { - GenerateNullIsAssignableToType(assembler, /*null_safety=*/false); -} - -void StubCodeCompiler::GenerateNullIsAssignableToTypeNullSafeStub() { - GenerateNullIsAssignableToType(assembler, /*null_safety=*/true); -} #if !defined(TARGET_ARCH_IA32) // The TypeTestStubs are used to test whether a given value is of a given // type. All variants have the same calling convention: diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h index 1086405514c..96415734de4 100644 --- a/runtime/vm/flag_list.h +++ b/runtime/vm/flag_list.h @@ -109,9 +109,7 @@ constexpr bool FLAG_support_il_printer = false; P(enable_asserts, bool, false, "Enable assert statements.") \ P(inline_alloc, bool, true, "Whether to use inline allocation fast paths.") \ R(null_assertions, false, bool, false, "Obsolete, ignored.") \ - R(strict_null_safety_checks, false, bool, false, \ - "Enable strict type checks for non-nullable types and required " \ - "parameters.") \ + R(strict_null_safety_checks, false, bool, false, "Obsolete, ignored.") \ P(enable_mirrors, bool, true, \ "Disable to make importing dart:mirrors an error.") \ P(enable_ffi, bool, true, "Disable to make importing dart:ffi an error.") \ diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h index c320cc38d37..28825b3b721 100644 --- a/runtime/vm/isolate.h +++ b/runtime/vm/isolate.h @@ -469,10 +469,6 @@ class IsolateGroup : public IntrusiveDListEntry { NullSafetyBit::update(null_safety, isolate_group_flags_); } - bool use_strict_null_safety_checks() const { - return null_safety() || FLAG_strict_null_safety_checks; - } - bool should_load_vmservice() const { return ShouldLoadVmServiceBit::decode(isolate_group_flags_); } diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index c38fdaf0636..4125e09968f 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -9466,7 +9466,6 @@ bool Function::AreValidArguments(const ArgumentsDescriptor& args_desc, } // Verify that all argument names are valid parameter names. Thread* thread = Thread::Current(); - auto isolate_group = thread->isolate_group(); Zone* zone = thread->zone(); String& argument_name = String::Handle(zone); String& parameter_name = String::Handle(zone); @@ -9496,33 +9495,31 @@ bool Function::AreValidArguments(const ArgumentsDescriptor& args_desc, return false; } } - if (isolate_group->use_strict_null_safety_checks()) { - // Verify that all required named parameters are filled. - for (intptr_t j = num_parameters - NumOptionalNamedParameters(); - j < num_parameters; j++) { - if (IsRequiredAt(j)) { - parameter_name = ParameterNameAt(j); - ASSERT(parameter_name.IsSymbol()); - bool found = false; - for (intptr_t i = 0; i < num_named_arguments; i++) { - argument_name = args_desc.NameAt(i); - ASSERT(argument_name.IsSymbol()); - if (argument_name.Equals(parameter_name)) { - found = true; - break; - } + // Verify that all required named parameters are filled. + for (intptr_t j = num_parameters - NumOptionalNamedParameters(); + j < num_parameters; j++) { + if (IsRequiredAt(j)) { + parameter_name = ParameterNameAt(j); + ASSERT(parameter_name.IsSymbol()); + bool found = false; + for (intptr_t i = 0; i < num_named_arguments; i++) { + argument_name = args_desc.NameAt(i); + ASSERT(argument_name.IsSymbol()); + if (argument_name.Equals(parameter_name)) { + found = true; + break; } - if (!found) { - if (error_message != nullptr) { - const intptr_t kMessageBufferSize = 64; - char message_buffer[kMessageBufferSize]; - Utils::SNPrint(message_buffer, kMessageBufferSize, - "missing required named parameter '%s'", - parameter_name.ToCString()); - *error_message = String::New(message_buffer); - } - return false; + } + if (!found) { + if (error_message != nullptr) { + const intptr_t kMessageBufferSize = 64; + char message_buffer[kMessageBufferSize]; + Utils::SNPrint(message_buffer, kMessageBufferSize, + "missing required named parameter '%s'", + parameter_name.ToCString()); + *error_message = String::New(message_buffer); } + return false; } } } @@ -10243,7 +10240,6 @@ bool FunctionType::IsSubtypeOf( } Thread* thread = Thread::Current(); Zone* zone = thread->zone(); - auto isolate_group = thread->isolate_group(); FunctionTypeMapping scope(zone, &function_type_equivalence, *this, other); // Check the type parameters and bounds of generic functions. @@ -10309,32 +10305,30 @@ bool FunctionType::IsSubtypeOf( return false; } } - if (isolate_group->use_strict_null_safety_checks()) { - // Check that for each required named parameter in this function, there's a - // corresponding required named parameter in the other function. - String& param_name = other_param_name; - for (intptr_t j = num_params - num_opt_named_params; j < num_params; j++) { - if (IsRequiredAt(j)) { - param_name = ParameterNameAt(j); - ASSERT(param_name.IsSymbol()); - bool found = false; - for (intptr_t i = other_num_fixed_params; i < other_num_params; i++) { - ASSERT(String::Handle(zone, other.ParameterNameAt(i)).IsSymbol()); - if (other.ParameterNameAt(i) == param_name.ptr()) { - found = true; - if (!other.IsRequiredAt(i)) { - TRACE_TYPE_CHECKS_VERBOSE( - " - result: false (mismatch in required named " - "parameters)\n"); - return false; - } + // Check that for each required named parameter in this function, there's a + // corresponding required named parameter in the other function. + String& param_name = other_param_name; + for (intptr_t j = num_params - num_opt_named_params; j < num_params; j++) { + if (IsRequiredAt(j)) { + param_name = ParameterNameAt(j); + ASSERT(param_name.IsSymbol()); + bool found = false; + for (intptr_t i = other_num_fixed_params; i < other_num_params; i++) { + ASSERT(String::Handle(zone, other.ParameterNameAt(i)).IsSymbol()); + if (other.ParameterNameAt(i) == param_name.ptr()) { + found = true; + if (!other.IsRequiredAt(i)) { + TRACE_TYPE_CHECKS_VERBOSE( + " - result: false (mismatch in required named " + "parameters)\n"); + return false; } } - if (!found) { - TRACE_TYPE_CHECKS_VERBOSE( - " - result: false (required named parameter not found)\n"); - return false; - } + } + if (!found) { + TRACE_TYPE_CHECKS_VERBOSE( + " - result: false (required named parameter not found)\n"); + return false; } } } @@ -20729,10 +20723,6 @@ bool Instance::IsAssignableTo( const TypeArguments& other_instantiator_type_arguments, const TypeArguments& other_function_type_arguments) const { ASSERT(!other.IsDynamicType()); - // In weak mode type casts, whether in legacy or opted-in libraries, the null - // instance is detected and handled in inlined code and therefore cannot be - // encountered here as a Dart null receiver. - ASSERT(IsolateGroup::Current()->use_strict_null_safety_checks() || !IsNull()); // In strong mode, compute NNBD_SUBTYPE(runtimeType, other). // In weak mode, compute LEGACY_SUBTYPE(runtimeType, other). return RuntimeTypeIsSubtypeOf(other, other_instantiator_type_arguments, @@ -20774,13 +20764,6 @@ bool Instance::NullIsInstanceOf( // Must be kept in sync with GenerateNullIsAssignableToType in // stub_code_compiler.cc if any changes are made. bool Instance::NullIsAssignableTo(const AbstractType& other) { - Thread* thread = Thread::Current(); - auto isolate_group = thread->isolate_group(); - - // In weak mode, Null is a bottom type (according to LEGACY_SUBTYPE). - if (!isolate_group->use_strict_null_safety_checks()) { - return true; - } // "Left Null" rule: null is assignable when destination type is either // legacy or nullable. Otherwise it is not assignable or we cannot tell // without instantiating type parameter. @@ -20788,8 +20771,7 @@ bool Instance::NullIsAssignableTo(const AbstractType& other) { return true; } if (other.IsFutureOrType()) { - return NullIsAssignableTo( - AbstractType::Handle(thread->zone(), other.UnwrapFutureOr())); + return NullIsAssignableTo(AbstractType::Handle(other.UnwrapFutureOr())); } // Since the TAVs are not available, for non-nullable type parameters // this returns a conservative approximation of "not assignable" . @@ -20822,11 +20804,6 @@ bool Instance::RuntimeTypeIsSubtypeOf( return true; } Thread* thread = Thread::Current(); - auto isolate_group = thread->isolate_group(); - // In weak testing mode, Null type is a subtype of any type. - if (IsNull() && !isolate_group->use_strict_null_safety_checks()) { - return true; - } Zone* zone = thread->zone(); const Class& cls = Class::Handle(zone, clazz()); if (cls.IsClosureClass()) { @@ -20921,7 +20898,6 @@ bool Instance::RuntimeTypeIsSubtypeOf( } } if (IsNull()) { - ASSERT(isolate_group->use_strict_null_safety_checks()); if (instantiated_other.IsNullType()) { return true; } @@ -21328,8 +21304,7 @@ bool AbstractType::IsNullabilityEquivalent(Thread* thread, Nullability this_type_nullability = nullability(); Nullability other_type_nullability = other_type.nullability(); if (kind == TypeEquality::kInSubtypeTest) { - if (thread->isolate_group()->use_strict_null_safety_checks() && - this_type_nullability == Nullability::kNullable && + if (this_type_nullability == Nullability::kNullable && other_type_nullability == Nullability::kNonNullable) { return false; } @@ -21550,10 +21525,7 @@ bool AbstractType::IsTopTypeForSubtyping() const { return true; } if (cid == kInstanceCid) { // Object type. - // NNBD weak mode uses LEGACY_SUBTYPE for assignability / 'as' tests, - // and non-nullable Object is a top type according to LEGACY_SUBTYPE. - return !IsNonNullable() || - !IsolateGroup::Current()->use_strict_null_safety_checks(); + return !IsNonNullable(); } if (cid == kFutureOrCid) { // FutureOr where T is a top type behaves as a top type. @@ -21742,7 +21714,6 @@ bool AbstractType::IsSubtypeOf( return result; } Thread* thread = Thread::Current(); - auto isolate_group = thread->isolate_group(); Zone* zone = thread->zone(); // Type parameters cannot be handled by Class::IsSubtypeOf(). // When comparing two uninstantiated function types, one returning type @@ -21794,16 +21765,14 @@ bool AbstractType::IsSubtypeOf( // Any type that can be the type of a closure is a subtype of Function or // non-nullable Object. if (other.IsObjectType() || other.IsDartFunctionType()) { - const bool result = !isolate_group->use_strict_null_safety_checks() || - !IsNullable() || !other.IsNonNullable(); + const bool result = !IsNullable() || !other.IsNonNullable(); TRACE_TYPE_CHECKS_VERBOSE(" - result: %s (function vs non-function)\n", (result ? "true" : "false")); return result; } if (other.IsFunctionType()) { // Check for two function types. - if (isolate_group->use_strict_null_safety_checks() && IsNullable() && - other.IsNonNullable()) { + if (IsNullable() && other.IsNonNullable()) { TRACE_TYPE_CHECKS_VERBOSE( " - result: false (function nullability)\n"); return false; @@ -21833,16 +21802,14 @@ bool AbstractType::IsSubtypeOf( // Record types cannot be handled by Class::IsSubtypeOf(). if (IsRecordType()) { if (other.IsObjectType() || other.IsDartRecordType()) { - const bool result = !isolate_group->use_strict_null_safety_checks() || - !IsNullable() || !other.IsNonNullable(); + const bool result = !IsNullable() || !other.IsNonNullable(); TRACE_TYPE_CHECKS_VERBOSE(" - result: %s (record vs non-record)\n", (result ? "true" : "false")); return result; } if (other.IsRecordType()) { // Check for two record types. - if (isolate_group->use_strict_null_safety_checks() && IsNullable() && - other.IsNonNullable()) { + if (IsNullable() && other.IsNonNullable()) { TRACE_TYPE_CHECKS_VERBOSE(" - result: false (record nullability)\n"); return false; } diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc index 89e9d024fba..3becef67bb8 100644 --- a/runtime/vm/object_test.cc +++ b/runtime/vm/object_test.cc @@ -7464,12 +7464,7 @@ ISOLATE_UNIT_TEST_CASE(ClosureType_SubtypeOfFunctionType) { EXPECT_SUBTYPE(closure_type_legacy, function_type_nonnullable); EXPECT_SUBTYPE(closure_type_nullable, function_type_nullable); EXPECT_SUBTYPE(closure_type_nullable, function_type_legacy); - // Nullable types are not a subtype of non-nullable types in strict mode. - if (IsolateGroup::Current()->use_strict_null_safety_checks()) { - EXPECT_NOT_SUBTYPE(closure_type_nullable, function_type_nonnullable); - } else { - EXPECT_SUBTYPE(closure_type_nullable, function_type_nonnullable); - } + EXPECT_NOT_SUBTYPE(closure_type_nullable, function_type_nonnullable); const auto& async_lib = Library::Handle(Library::AsyncLibrary()); const auto& future_or_class = @@ -7502,13 +7497,8 @@ ISOLATE_UNIT_TEST_CASE(ClosureType_SubtypeOfFunctionType) { EXPECT_SUBTYPE(closure_type_legacy, future_or_function_type_nonnullable); EXPECT_SUBTYPE(closure_type_nullable, future_or_function_type_nullable); EXPECT_SUBTYPE(closure_type_nullable, future_or_function_type_legacy); - // Nullable types are not a subtype of non-nullable types in strict mode. - if (IsolateGroup::Current()->use_strict_null_safety_checks()) { - EXPECT_NOT_SUBTYPE(closure_type_nullable, - future_or_function_type_nonnullable); - } else { - EXPECT_SUBTYPE(closure_type_nullable, future_or_function_type_nonnullable); - } + EXPECT_NOT_SUBTYPE(closure_type_nullable, + future_or_function_type_nonnullable); } ISOLATE_UNIT_TEST_CASE(FunctionType_IsSubtypeOfNonNullableObject) { @@ -7526,11 +7516,7 @@ ISOLATE_UNIT_TEST_CASE(FunctionType_IsSubtypeOfNonNullableObject) { FinalizeAndCanonicalize(&type_nullable_function_int_nullary); EXPECT_SUBTYPE(type_function_int_nullary, type_object); - if (IsolateGroup::Current()->use_strict_null_safety_checks()) { - EXPECT_NOT_SUBTYPE(type_nullable_function_int_nullary, type_object); - } else { - EXPECT_SUBTYPE(type_nullable_function_int_nullary, type_object); - } + EXPECT_NOT_SUBTYPE(type_nullable_function_int_nullary, type_object); } #undef EXPECT_NOT_SUBTYPE diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc index c4729748bee..728fa7c12b5 100644 --- a/runtime/vm/runtime_entry.cc +++ b/runtime/vm/runtime_entry.cc @@ -1204,10 +1204,8 @@ DEFINE_RUNTIME_ENTRY(TypeCheck, 7) { } #endif // defined(TARGET_ARCH_IA32) - // These are guaranteed on the calling side. + // This is guaranteed on the calling side. ASSERT(!dst_type.IsDynamicType()); - ASSERT(!src_instance.IsNull() || - isolate->group()->use_strict_null_safety_checks()); const bool is_instance_of = src_instance.IsAssignableTo( dst_type, instantiator_type_arguments, function_type_arguments); diff --git a/runtime/vm/stub_code_list.h b/runtime/vm/stub_code_list.h index a873f3d50a1..f8e89ac5e7a 100644 --- a/runtime/vm/stub_code_list.h +++ b/runtime/vm/stub_code_list.h @@ -107,9 +107,7 @@ namespace dart { V(AssertSubtype) \ V(AssertAssignable) \ V(TypeIsTopTypeForSubtyping) \ - V(TypeIsTopTypeForSubtypingNullSafe) \ V(NullIsAssignableToType) \ - V(NullIsAssignableToTypeNullSafe) \ V(Subtype1TestCache) \ V(Subtype2TestCache) \ V(Subtype3TestCache) \ diff --git a/runtime/vm/type_testing_stubs.cc b/runtime/vm/type_testing_stubs.cc index f8051c8e38d..afa5166e0f4 100644 --- a/runtime/vm/type_testing_stubs.cc +++ b/runtime/vm/type_testing_stubs.cc @@ -343,8 +343,7 @@ void TypeTestingStubGenerator::BuildOptimizedTypeTestStubFastCases( ASSERT(!type.IsTopTypeForSubtyping()); if (type.IsObjectType()) { - ASSERT(type.IsNonNullable() && - hi->thread()->isolate_group()->use_strict_null_safety_checks()); + ASSERT(type.IsNonNullable()); compiler::Label is_null; __ CompareObject(TypeTestABI::kInstanceReg, Object::null_object()); __ BranchIf(EQUAL, &is_null, compiler::Assembler::kNearJump); @@ -1084,8 +1083,6 @@ void TypeTestingStubGenerator::BuildOptimizedTypeParameterArgumentValueCheck( ? TypeTestABI::kInstantiatorTypeArgumentsReg : TypeTestABI::kFunctionTypeArgumentsReg; - const bool strict_null_safety = - hi->thread()->isolate_group()->use_strict_null_safety_checks(); compiler::Label is_subtype; // TODO(dartbug.com/46920): Currently only canonical equality (identity) // and some top and bottom types are checked. @@ -1117,24 +1114,20 @@ void TypeTestingStubGenerator::BuildOptimizedTypeParameterArgumentValueCheck( __ CompareImmediate(TTSInternalRegs::kScratchReg, kVoidCid); __ BranchIf(EQUAL, &is_subtype); __ CompareImmediate(TTSInternalRegs::kScratchReg, kInstanceCid); - if (strict_null_safety) { - __ BranchIf(NOT_EQUAL, &check_subtype_type_class_ids); - // If non-nullable Object, then the subtype must be legacy or non-nullable. - __ CompareAbstractTypeNullabilityWith( - TTSInternalRegs::kSuperTypeArgumentReg, - static_cast(Nullability::kNonNullable), - TTSInternalRegs::kScratchReg); - __ BranchIf(NOT_EQUAL, &is_subtype); - __ Comment("Checking for legacy or non-nullable instance type argument"); - __ CompareAbstractTypeNullabilityWith( - TTSInternalRegs::kSubTypeArgumentReg, - static_cast(Nullability::kNullable), - TTSInternalRegs::kScratchReg); - __ BranchIf(EQUAL, check_failed); - __ Jump(&is_subtype); - } else { - __ BranchIf(EQUAL, &is_subtype, compiler::Assembler::kNearJump); - } + __ BranchIf(NOT_EQUAL, &check_subtype_type_class_ids); + // If non-nullable Object, then the subtype must be legacy or non-nullable. + __ CompareAbstractTypeNullabilityWith( + TTSInternalRegs::kSuperTypeArgumentReg, + static_cast(Nullability::kNonNullable), + TTSInternalRegs::kScratchReg); + __ BranchIf(NOT_EQUAL, &is_subtype); + __ Comment("Checking for legacy or non-nullable instance type argument"); + __ CompareAbstractTypeNullabilityWith( + TTSInternalRegs::kSubTypeArgumentReg, + static_cast(Nullability::kNullable), + TTSInternalRegs::kScratchReg); + __ BranchIf(EQUAL, check_failed); + __ Jump(&is_subtype); __ Bind(&check_subtype_type_class_ids); __ Comment("Checking instance type argument for possible bottom types"); @@ -1150,15 +1143,13 @@ void TypeTestingStubGenerator::BuildOptimizedTypeParameterArgumentValueCheck( __ CompareImmediate(TTSInternalRegs::kScratchReg, kNullCid); // Last possible check, so fall back to slow stub on failure. __ BranchIf(NOT_EQUAL, check_failed); - if (strict_null_safety) { - // Only nullable or legacy types can be a supertype of Null. - __ Comment("Checking for legacy or nullable instantiated type parameter"); - __ CompareAbstractTypeNullabilityWith( - TTSInternalRegs::kSuperTypeArgumentReg, - static_cast(Nullability::kNonNullable), - TTSInternalRegs::kScratchReg); - __ BranchIf(EQUAL, check_failed); - } + // Only nullable or legacy types can be a supertype of Null. + __ Comment("Checking for legacy or nullable instantiated type parameter"); + __ CompareAbstractTypeNullabilityWith( + TTSInternalRegs::kSuperTypeArgumentReg, + static_cast(Nullability::kNonNullable), + TTSInternalRegs::kScratchReg); + __ BranchIf(EQUAL, check_failed); __ Bind(&is_subtype); } @@ -1176,9 +1167,7 @@ void TypeTestingStubGenerator::BuildOptimizedTypeArgumentValueCheck( return; } - const bool strict_null_safety = - hi->thread()->isolate_group()->use_strict_null_safety_checks(); - ASSERT(!type.IsObjectType() || (strict_null_safety && type.IsNonNullable())); + ASSERT(!type.IsObjectType() || type.IsNonNullable()); if (assembler->EmittingComments()) { TextBuffer buffer(128); @@ -1211,7 +1200,7 @@ void TypeTestingStubGenerator::BuildOptimizedTypeArgumentValueCheck( } else { __ Comment("Checks for Object type"); } - if (strict_null_safety && type.IsNonNullable()) { + if (type.IsNonNullable()) { // Nullable types cannot be a subtype of a non-nullable type. __ CompareAbstractTypeNullabilityWith( TTSInternalRegs::kSubTypeArgumentReg, @@ -1230,7 +1219,7 @@ void TypeTestingStubGenerator::BuildOptimizedTypeArgumentValueCheck( __ Comment("Checks for Type"); __ Bind(&sub_is_type); - if (strict_null_safety && type.IsNonNullable()) { + if (type.IsNonNullable()) { // Nullable types cannot be a subtype of a non-nullable type in strict mode. __ CompareAbstractTypeNullabilityWith( TTSInternalRegs::kSubTypeArgumentReg, diff --git a/runtime/vm/type_testing_stubs_test.cc b/runtime/vm/type_testing_stubs_test.cc index 5224165408c..209eb1180de 100644 --- a/runtime/vm/type_testing_stubs_test.cc +++ b/runtime/vm/type_testing_stubs_test.cc @@ -1659,9 +1659,6 @@ ISOLATE_UNIT_TEST_CASE(TTS_Future) { THR_Print(" Testing Future\n"); THR_Print("********************************************************\n\n"); - const bool strict_null_safety = - thread->isolate_group()->use_strict_null_safety_checks(); - // And here, obj is an object of type Future. // // True positive from TTS: @@ -1705,15 +1702,6 @@ ISOLATE_UNIT_TEST_CASE(TTS_Future) { RunTTSTest(type_future_t, {obj_futurenullablefunction, tav_nullable_function_int_nullary, tav_null}); - if (!strict_null_safety) { - RunTTSTest(type_future_object, - {obj_futurenullablefunction, tav_null, tav_null}); - RunTTSTest(type_future_function, - {obj_futurenullablefunction, tav_null, tav_null}); - RunTTSTest(type_future_t, - {obj_futurenullablefunction, tav_object, tav_null}); - } - // False negative from TTS (caught by runtime or STC): // obj as Future : No specialization. // obj as Future : No specialization. @@ -1740,16 +1728,6 @@ ISOLATE_UNIT_TEST_CASE(TTS_Future) { FalseNegative({obj_futurenullablefunction, tav_legacy_function_int_nullary, tav_null})); - if (!strict_null_safety) { - RunTTSTest(type_future_function_int_nullary, - FalseNegative({obj_futurenullablefunction, tav_null, tav_null})); - RunTTSTest(type_future_t, FalseNegative({obj_futurenullablefunction, - tav_function, tav_null})); - RunTTSTest(type_future_t, - FalseNegative({obj_futurenullablefunction, - tav_function_int_nullary, tav_null})); - } - // Errors: // obj as Future<_Closure?> : Type arg is not a supertype // obj as Future<_Closure*> : Type arg is not a supertype @@ -1784,20 +1762,18 @@ ISOLATE_UNIT_TEST_CASE(TTS_Future) { RunTTSTest(type_future_t, Failure({obj_futurenullablefunction, tav_closure, tav_null})); - if (strict_null_safety) { - RunTTSTest(type_future_function_int_nullary, - Failure({obj_futurenullablefunction, tav_null, tav_null})); - RunTTSTest(type_future_object, - Failure({obj_futurenullablefunction, tav_null, tav_null})); - RunTTSTest(type_future_function, - Failure({obj_futurenullablefunction, tav_null, tav_null})); - RunTTSTest(type_future_t, - Failure({obj_futurenullablefunction, tav_object, tav_null})); - RunTTSTest(type_future_t, - Failure({obj_futurenullablefunction, tav_function, tav_null})); - RunTTSTest(type_future_t, Failure({obj_futurenullablefunction, - tav_function_int_nullary, tav_null})); - } + RunTTSTest(type_future_function_int_nullary, + Failure({obj_futurenullablefunction, tav_null, tav_null})); + RunTTSTest(type_future_object, + Failure({obj_futurenullablefunction, tav_null, tav_null})); + RunTTSTest(type_future_function, + Failure({obj_futurenullablefunction, tav_null, tav_null})); + RunTTSTest(type_future_t, + Failure({obj_futurenullablefunction, tav_object, tav_null})); + RunTTSTest(type_future_t, + Failure({obj_futurenullablefunction, tav_function, tav_null})); + RunTTSTest(type_future_t, Failure({obj_futurenullablefunction, + tav_function_int_nullary, tav_null})); } ISOLATE_UNIT_TEST_CASE(TTS_Regress40964) { @@ -1953,10 +1929,9 @@ ISOLATE_UNIT_TEST_CASE(TTS_Object) { Type::Handle(IsolateGroup::Current()->object_store()->object_type()); const auto& tav_null = Object::null_type_arguments(); - // Object* is a top type, so its TTS won't specialize at all. Object is not, + // Non-nullable Object is not a top type, // so its TTS specializes the first time it is invoked. - const bool should_specialize = - IsolateGroup::Current()->use_strict_null_safety_checks(); + const bool should_specialize = true; auto make_test_case = [&](const Instance& instance) -> TTSTestCase { return {instance, tav_null, tav_null}; }; @@ -2136,22 +2111,14 @@ ISOLATE_UNIT_TEST_CASE(TTS_Partial) { state.InvokeExistingStub({obj_b_never, tav_null, tav_d}); state.InvokeExistingStub({obj_b_null, tav_null, tav_nullable_c}); state.InvokeExistingStub({obj_b_null, tav_null, tav_legacy_c}); - if (IsolateGroup::Current()->use_strict_null_safety_checks()) { - state.InvokeExistingStub(Failure({obj_b_null, tav_null, tav_c})); - } else { - state.InvokeExistingStub({obj_b_null, tav_null, tav_c}); - } + state.InvokeExistingStub(Failure({obj_b_null, tav_null, tav_c})); state.InvokeExistingStub({obj_b_e, tav_null, tav_nullable_object}); state.InvokeExistingStub({obj_b_e_nullable, tav_null, tav_nullable_object}); state.InvokeExistingStub({obj_b_e, tav_null, tav_legacy_object}); state.InvokeExistingStub({obj_b_e_nullable, tav_null, tav_legacy_object}); state.InvokeExistingStub({obj_b_e, tav_null, tav_object}); - if (IsolateGroup::Current()->use_strict_null_safety_checks()) { - state.InvokeExistingStub(Failure({obj_b_e_nullable, tav_null, tav_object})); - } else { - state.InvokeExistingStub({obj_b_e_nullable, tav_null, tav_object}); - } + state.InvokeExistingStub(Failure({obj_b_e_nullable, tav_null, tav_object})); } ISOLATE_UNIT_TEST_CASE(TTS_Partial_Incremental) {