[VM/nnbd] Simplify NNBDMode enum class.

NNBDMode does not reflect the semantics (legacy or nnbd) of type tests anymore.
Instead, the semantics are derived from the value of the strong mode flag.
This required one function to be specialized, namely the implementation of
'null is Type' in weak mode in an opted-in library, which still requires
nnbd semantics although run in weak mode.
Relevant changes are in object.h and object.cc:
- methods NNBD_NullIsInstanceOf and NNBD_IsTopType are new.
- methods IsNullType, IsTopType, and IsNeverType are modified.

Change-Id: I36cd43d93d2cfabd110cbcc6b26487a583bb089d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/130444
Commit-Queue: Régis Crelier <regis@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Régis Crelier 2020-01-08 19:35:00 +00:00 committed by commit-bot@chromium.org
parent c0dfdb27e7
commit e2e290b4cf
32 changed files with 259 additions and 267 deletions

View file

@ -277,8 +277,8 @@ DEFINE_NATIVE_ENTRY(Ffi_storePointer, 0, 3) {
auto& new_value_type =
AbstractType::Handle(zone, new_value.GetType(Heap::kNew));
if (!new_value_type.IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest,
pointer_type_arg, Heap::kNew)) {
if (!new_value_type.IsSubtypeOf(NNBDMode::kLegacyLib, pointer_type_arg,
Heap::kNew)) {
const String& error = String::Handle(String::NewFormatted(
"New value (%s) is not a subtype of '%s'.",
String::Handle(new_value_type.UserVisibleName()).ToCString(),

View file

@ -707,7 +707,7 @@ static RawAbstractType* InstantiateType(const AbstractType& type,
instantiator_type_args = instantiator.arguments();
}
AbstractType& result = AbstractType::Handle(type.InstantiateFrom(
NNBDMode::kLegacyLib_LegacyTest, instantiator_type_args,
NNBDMode::kLegacyLib, instantiator_type_args,
Object::null_type_arguments(), kAllFree, NULL, Heap::kOld));
ASSERT(result.IsFinalized());
return result.Canonicalize();
@ -1477,8 +1477,8 @@ DEFINE_NATIVE_ENTRY(ClassMirror_invokeConstructor, 0, 5) {
// type arguments of the type reflected by the class mirror.
ASSERT(redirect_type.IsInstantiated(kFunctions));
redirect_type ^= redirect_type.InstantiateFrom(
NNBDMode::kLegacyLib_LegacyTest, type_arguments,
Object::null_type_arguments(), kNoneFree, NULL, Heap::kOld);
NNBDMode::kLegacyLib, type_arguments, Object::null_type_arguments(),
kNoneFree, NULL, Heap::kOld);
redirect_type ^= redirect_type.Canonicalize();
}
@ -1507,7 +1507,7 @@ DEFINE_NATIVE_ENTRY(ClassMirror_invokeConstructor, 0, 5) {
ArgumentsDescriptor::New(kTypeArgsLen, args.Length(), arg_names));
ArgumentsDescriptor args_descriptor(args_descriptor_array);
if (!redirected_constructor.AreValidArguments(NNBDMode::kLegacyLib_LegacyTest,
if (!redirected_constructor.AreValidArguments(NNBDMode::kLegacyLib,
args_descriptor, NULL)) {
external_constructor_name = redirected_constructor.name();
ThrowNoSuchMethod(AbstractType::Handle(klass.RareType()),
@ -1518,8 +1518,7 @@ DEFINE_NATIVE_ENTRY(ClassMirror_invokeConstructor, 0, 5) {
}
const Object& type_error =
Object::Handle(redirected_constructor.DoArgumentTypesMatch(
NNBDMode::kLegacyLib_LegacyTest, args, args_descriptor,
type_arguments));
NNBDMode::kLegacyLib, args, args_descriptor, type_arguments));
if (!type_error.IsNull()) {
Exceptions::PropagateError(Error::Cast(type_error));
UNREACHABLE();
@ -1757,9 +1756,7 @@ DEFINE_NATIVE_ENTRY(VariableMirror_type, 0, 2) {
DEFINE_NATIVE_ENTRY(TypeMirror_subtypeTest, 0, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, a, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, b, arguments->NativeArgAt(1));
return Bool::Get(
a.IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest, b, Heap::kNew))
.raw();
return Bool::Get(a.IsSubtypeOf(NNBDMode::kLegacyLib, b, Heap::kNew)).raw();
}
#endif // !DART_PRECOMPILED_RUNTIME

View file

@ -403,8 +403,8 @@ DEFINE_NATIVE_ENTRY(Internal_boundsCheckForPartialInstantiation, 0, 2) {
// The supertype may not be instantiated.
// TODO(regis): What is the correct nnbd mode to use here?
if (!AbstractType::InstantiateAndTestSubtype(
NNBDMode::kLegacyLib_LegacyTest, &subtype, &supertype,
instantiator_type_args, function_type_args)) {
NNBDMode::kLegacyLib, &subtype, &supertype, instantiator_type_args,
function_type_args)) {
// Throw a dynamic type error.
TokenPosition location;
{

View file

@ -384,16 +384,16 @@ void ClassFinalizer::CheckRecursiveType(const Class& cls,
!pending_arguments.IsSubvectorInstantiated(first_type_param,
num_type_params)) {
const TypeArguments& instantiated_arguments = TypeArguments::Handle(
zone, arguments.InstantiateFrom(NNBDMode::kLegacyLib_LegacyTest,
zone, arguments.InstantiateFrom(NNBDMode::kLegacyLib,
Object::null_type_arguments(),
Object::null_type_arguments(),
kNoneFree, NULL, Heap::kNew));
const TypeArguments& instantiated_pending_arguments =
TypeArguments::Handle(zone, pending_arguments.InstantiateFrom(
NNBDMode::kLegacyLib_LegacyTest,
Object::null_type_arguments(),
Object::null_type_arguments(),
kNoneFree, NULL, Heap::kNew));
TypeArguments::Handle(
zone, pending_arguments.InstantiateFrom(
NNBDMode::kLegacyLib, Object::null_type_arguments(),
Object::null_type_arguments(), kNoneFree, NULL,
Heap::kNew));
if (!instantiated_pending_arguments.IsSubvectorEquivalent(
instantiated_arguments, first_type_param, num_type_params,
/* syntactically = */ true)) {

View file

@ -814,7 +814,7 @@ void ConstantPropagator::VisitInstanceOf(InstanceOfInstr* instr) {
const Object& value = def->constant_value();
const AbstractType& checked_type = instr->type();
// TODO(regis): Revisit the evaluation of the type test.
if (checked_type.IsTopType(NNBDMode::kLegacyTest)) {
if (checked_type.IsTopType()) {
SetValue(instr, Bool::True());
} else if (IsNonConstant(value)) {
intptr_t value_cid = instr->value()->definition()->Type()->ToCid();

View file

@ -2259,8 +2259,7 @@ void FlowGraphCompiler::GenerateAssertAssignableViaTypeTestingStub(
// caller side!
const Type& int_type = Type::Handle(zone(), Type::IntType());
bool is_non_smi = false;
if (int_type.IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest, dst_type,
Heap::kOld)) {
if (int_type.IsSubtypeOf(NNBDMode::kLegacyLib, dst_type, Heap::kOld)) {
__ BranchIfSmi(instance_reg, done);
is_non_smi = true;
}

View file

@ -279,7 +279,7 @@ FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
const Register kInstanceReg = R0;
const Type& smi_type = Type::Handle(zone(), Type::SmiType());
const bool smi_is_ok =
smi_type.IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest, type, Heap::kOld);
smi_type.IsSubtypeOf(NNBDMode::kLegacyLib, type, Heap::kOld);
__ tst(kInstanceReg, compiler::Operand(kSmiTagMask));
if (smi_is_ok) {
// Fast case for type = FutureOr<int/num/top-type>.
@ -315,7 +315,7 @@ FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
ASSERT(tp_argument.HasTypeClass());
// Check if type argument is dynamic, Object, or void.
const Type& object_type = Type::Handle(zone(), Type::ObjectType());
if (object_type.IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest, tp_argument,
if (object_type.IsSubtypeOf(NNBDMode::kLegacyLib, tp_argument,
Heap::kOld)) {
// Instance class test only necessary.
return GenerateSubtype1TestCacheLookup(
@ -366,7 +366,7 @@ bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
__ tst(kInstanceReg, compiler::Operand(kSmiTagMask));
// If instance is Smi, check directly.
const Class& smi_class = Class::Handle(zone(), Smi::Class());
if (Class::IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest, smi_class,
if (Class::IsSubtypeOf(NNBDMode::kLegacyLib, smi_class,
Object::null_type_arguments(), type_class,
Object::null_type_arguments(), Heap::kOld)) {
// Fast case for type = int/num/top-type.

View file

@ -270,7 +270,7 @@ FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
const Register kInstanceReg = R0;
const Type& smi_type = Type::Handle(zone(), Type::SmiType());
const bool smi_is_ok =
smi_type.IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest, type, Heap::kOld);
smi_type.IsSubtypeOf(NNBDMode::kLegacyLib, type, Heap::kOld);
// Fast case for type = FutureOr<int/num/top-type>.
__ BranchIfSmi(kInstanceReg,
smi_is_ok ? is_instance_lbl : is_not_instance_lbl);
@ -302,7 +302,7 @@ FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
if (tp_argument.IsType()) {
// Check if type argument is dynamic, Object, or void.
const Type& object_type = Type::Handle(zone(), Type::ObjectType());
if (object_type.IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest, tp_argument,
if (object_type.IsSubtypeOf(NNBDMode::kLegacyLib, tp_argument,
Heap::kOld)) {
// Instance class test only necessary.
return GenerateSubtype1TestCacheLookup(
@ -351,7 +351,7 @@ bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
const Register kInstanceReg = R0;
// If instance is Smi, check directly.
const Class& smi_class = Class::Handle(zone(), Smi::Class());
if (Class::IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest, smi_class,
if (Class::IsSubtypeOf(NNBDMode::kLegacyLib, smi_class,
Object::null_type_arguments(), type_class,
Object::null_type_arguments(), Heap::kOld)) {
// Fast case for type = int/num/top-type.

View file

@ -259,7 +259,7 @@ FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
const Register kInstanceReg = EAX;
const Type& smi_type = Type::Handle(zone(), Type::SmiType());
const bool smi_is_ok =
smi_type.IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest, type, Heap::kOld);
smi_type.IsSubtypeOf(NNBDMode::kLegacyLib, type, Heap::kOld);
__ testl(kInstanceReg, compiler::Immediate(kSmiTagMask));
if (smi_is_ok) {
// Fast case for type = FutureOr<int/num/top-type>.
@ -294,7 +294,7 @@ FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
if (tp_argument.IsType()) {
// Check if type argument is dynamic, Object, or void.
const Type& object_type = Type::Handle(zone(), Type::ObjectType());
if (object_type.IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest, tp_argument,
if (object_type.IsSubtypeOf(NNBDMode::kLegacyLib, tp_argument,
Heap::kOld)) {
// Instance class test only necessary.
return GenerateSubtype1TestCacheLookup(
@ -343,7 +343,7 @@ bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
__ testl(kInstanceReg, compiler::Immediate(kSmiTagMask));
// If instance is Smi, check directly.
const Class& smi_class = Class::Handle(zone(), Smi::Class());
if (Class::IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest, smi_class,
if (Class::IsSubtypeOf(NNBDMode::kLegacyLib, smi_class,
Object::null_type_arguments(), type_class,
Object::null_type_arguments(), Heap::kOld)) {
// Fast case for type = int/num/top-type.

View file

@ -275,7 +275,7 @@ FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
const Register kInstanceReg = RAX;
const Type& smi_type = Type::Handle(zone(), Type::SmiType());
const bool smi_is_ok =
smi_type.IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest, type, Heap::kOld);
smi_type.IsSubtypeOf(NNBDMode::kLegacyLib, type, Heap::kOld);
__ testq(kInstanceReg, compiler::Immediate(kSmiTagMask));
if (smi_is_ok) {
// Fast case for type = FutureOr<int/num/top-type>.
@ -312,7 +312,7 @@ FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
ASSERT(tp_argument.HasTypeClass());
// Check if type argument is dynamic, Object, or void.
const Type& object_type = Type::Handle(zone(), Type::ObjectType());
if (object_type.IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest, tp_argument,
if (object_type.IsSubtypeOf(NNBDMode::kLegacyLib, tp_argument,
Heap::kOld)) {
// Instance class test only necessary.
return GenerateSubtype1TestCacheLookup(
@ -366,7 +366,7 @@ bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
__ testq(kInstanceReg, compiler::Immediate(kSmiTagMask));
// If instance is Smi, check directly.
const Class& smi_class = Class::Handle(zone(), Smi::Class());
if (Class::IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest, smi_class,
if (Class::IsSubtypeOf(NNBDMode::kLegacyLib, smi_class,
Object::null_type_arguments(), type_class,
Object::null_type_arguments(), Heap::kOld)) {
// Fast case for type = int/num/top-type.

View file

@ -219,8 +219,8 @@ void HierarchyInfo::BuildRangesFor(ClassTable* table,
test_succeeded = false;
} else if (use_subtype_test) {
cls_type = cls.RareType();
test_succeeded = cls_type.IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest,
dst_type, Heap::kNew);
test_succeeded =
cls_type.IsSubtypeOf(NNBDMode::kLegacyLib, dst_type, Heap::kNew);
} else {
while (!cls.IsObjectClass()) {
if (cls.raw() == klass.raw()) {
@ -3254,7 +3254,7 @@ static bool MayBeNumber(CompileType* type) {
}
// Note that type 'Number' is a subtype of itself.
return compile_type.IsTopType() || compile_type.IsTypeParameter() ||
compile_type.IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest,
compile_type.IsSubtypeOf(NNBDMode::kLegacyLib,
Type::Handle(Type::Number()), Heap::kOld);
}

View file

@ -1383,11 +1383,10 @@ void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const Register object = locs()->in(0).reg();
const Register result = locs()->out(0).reg();
const AbstractType& value_type = *this->object()->Type()->ToAbstractType();
// Using NNBDMode::kLegacyLib_LegacyTest is safe, because it throws a wider
// Using NNBDMode::kLegacyLib is safe, because it throws a wider
// net over the types accepting a Smi value, especially during the nnbd
// migration that does not guarantee soundness.
if (CompileType::Smi().IsAssignableTo(NNBDMode::kLegacyLib_LegacyTest,
value_type) ||
if (CompileType::Smi().IsAssignableTo(NNBDMode::kLegacyLib, value_type) ||
value_type.IsTypeParameter()) {
__ LoadTaggedClassIdMayBeSmi(result, object);
} else {

View file

@ -1262,11 +1262,10 @@ void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const Register object = locs()->in(0).reg();
const Register result = locs()->out(0).reg();
const AbstractType& value_type = *this->object()->Type()->ToAbstractType();
// Using NNBDMode::kLegacyLib_LegacyTest is safe, because it throws a wider
// Using NNBDMode::kLegacyLib is safe, because it throws a wider
// net over the types accepting a Smi value, especially during the nnbd
// migration that does not guarantee soundness.
if (CompileType::Smi().IsAssignableTo(NNBDMode::kLegacyLib_LegacyTest,
value_type) ||
if (CompileType::Smi().IsAssignableTo(NNBDMode::kLegacyLib, value_type) ||
value_type.IsTypeParameter()) {
__ LoadTaggedClassIdMayBeSmi(result, object);
} else {

View file

@ -916,7 +916,7 @@ AssertAssignableInstr* FlowGraphDeserializer::DeserializeAssertAssignable(
if (!ParseDartValue(dst_name_sexp, &dst_name)) return nullptr;
// TODO(regis): Serialize/deserialize nnbd_mode.
auto nnbd_mode = NNBDMode::kLegacyLib_LegacyTest;
auto nnbd_mode = NNBDMode::kLegacyLib;
auto kind = AssertAssignableInstr::Kind::kUnknown;
if (auto const kind_sexp = CheckSymbol(sexp->ExtraLookupValue("kind"))) {

View file

@ -1238,11 +1238,10 @@ void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const Register object = locs()->in(0).reg();
const Register result = locs()->out(0).reg();
const AbstractType& value_type = *this->object()->Type()->ToAbstractType();
// Using NNBDMode::kLegacyLib_LegacyTest is safe, because it throws a wider
// Using NNBDMode::kLegacyLib is safe, because it throws a wider
// net over the types accepting a Smi value, especially during the nnbd
// migration that does not guarantee soundness.
if (CompileType::Smi().IsAssignableTo(NNBDMode::kLegacyLib_LegacyTest,
value_type) ||
if (CompileType::Smi().IsAssignableTo(NNBDMode::kLegacyLib, value_type) ||
value_type.IsTypeParameter()) {
// We don't use Assembler::LoadTaggedClassIdMayBeSmi() here---which uses
// a conditional move instead, and requires an additional register---because

View file

@ -1289,11 +1289,10 @@ void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const Register object = locs()->in(0).reg();
const Register result = locs()->out(0).reg();
const AbstractType& value_type = *this->object()->Type()->ToAbstractType();
// Using NNBDMode::kLegacyLib_LegacyTest is safe, because it throws a wider
// Using NNBDMode::kLegacyLib is safe, because it throws a wider
// net over the types accepting a Smi value, especially during the nnbd
// migration that does not guarantee soundness.
if (CompileType::Smi().IsAssignableTo(NNBDMode::kLegacyLib_LegacyTest,
value_type) ||
if (CompileType::Smi().IsAssignableTo(NNBDMode::kLegacyLib, value_type) ||
value_type.IsTypeParameter()) {
// We don't use Assembler::LoadTaggedClassIdMayBeSmi() here---which uses
// a conditional move instead---because it is slower, probably due to

View file

@ -369,7 +369,7 @@ static Definition* MakeAssertAssignable(CompilerState* S,
new Value(flow_graph->constant_null()),
AbstractType::ZoneHandle(Type::ObjectType()),
Symbols::Empty(), S->GetNextDeoptId(),
NNBDMode::kLegacyLib_LegacyTest);
NNBDMode::kLegacyLib);
}
ISOLATE_UNIT_TEST_CASE(LoadOptimizer_RedefinitionAliasing_CheckNull_NoEscape) {

View file

@ -554,11 +554,11 @@ void CompileType::Union(CompileType* other) {
}
const AbstractType* other_abstract_type = other->ToAbstractType();
if (abstract_type->IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest,
*other_abstract_type, Heap::kOld)) {
if (abstract_type->IsSubtypeOf(NNBDMode::kLegacyLib, *other_abstract_type,
Heap::kOld)) {
type_ = other_abstract_type;
return;
} else if (other_abstract_type->IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest,
} else if (other_abstract_type->IsSubtypeOf(NNBDMode::kLegacyLib,
*abstract_type, Heap::kOld)) {
return; // Nothing to do.
}
@ -569,8 +569,8 @@ void CompileType::Union(CompileType* other) {
Class& cls = Class::Handle(abstract_type->type_class());
for (; !cls.IsNull() && !cls.IsGeneric(); cls = cls.SuperClass()) {
type_ = &AbstractType::ZoneHandle(cls.RareType());
if (other_abstract_type->IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest,
*type_, Heap::kOld)) {
if (other_abstract_type->IsSubtypeOf(NNBDMode::kLegacyLib, *type_,
Heap::kOld)) {
// Found suitable supertype: keep type_ only.
cid_ = kDynamicCid;
return;
@ -610,8 +610,8 @@ CompileType* CompileType::ComputeRefinedType(CompileType* old_type,
const AbstractType* new_abstract_type = new_type->ToAbstractType();
CompileType* preferred_type;
if (old_abstract_type->IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest,
*new_abstract_type, Heap::kOld)) {
if (old_abstract_type->IsSubtypeOf(NNBDMode::kLegacyLib, *new_abstract_type,
Heap::kOld)) {
// Prefer old type, as it is clearly more specific.
preferred_type = old_type;
} else {
@ -945,7 +945,7 @@ CompileType RedefinitionInstr::ComputeType() const {
return CompileType::CreateNullable(is_nullable,
constrained_type_->ToNullableCid());
}
if (value()->Type()->IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest,
if (value()->Type()->IsSubtypeOf(NNBDMode::kLegacyLib,
*constrained_type_->ToAbstractType())) {
return is_nullable ? *value()->Type()
: value()->Type()->CopyNonNullable();

View file

@ -1141,7 +1141,7 @@ bool CallSpecializer::TypeCheckAsClassEquality(NNBDMode mode,
return false;
}
if (mode != NNBDMode::kLegacyLib_LegacyTest) {
if (mode != NNBDMode::kLegacyLib) {
return false; // TODO(regis): Implement.
}
@ -1193,7 +1193,7 @@ bool CallSpecializer::TryOptimizeInstanceOfUsingStaticTypes(
ASSERT(I->can_use_strong_mode_types());
ASSERT(Token::IsTypeTestOperator(call->token_kind()));
if (mode != NNBDMode::kLegacyLib_LegacyTest) {
if (mode != NNBDMode::kLegacyLib) {
return false; // TODO(regis): Implement.
}
@ -1579,8 +1579,7 @@ void TypedDataSpecializer::TryInlineCall(TemplateDartCall<0>* call) {
auto& type_class = Class::Handle(zone_);
#define TRY_INLINE(iface, member_name, type, cid) \
if (!member_name.IsNull()) { \
if (receiver_type->IsAssignableTo(NNBDMode::kLegacyLib_LegacyTest, \
member_name)) { \
if (receiver_type->IsAssignableTo(NNBDMode::kLegacyLib, member_name)) { \
if (is_length_getter) { \
type_class = member_name.type_class(); \
ReplaceWithLengthGetter(call); \
@ -1590,9 +1589,7 @@ void TypedDataSpecializer::TryInlineCall(TemplateDartCall<0>* call) {
ReplaceWithIndexGet(call, cid); \
} else { \
if (!index_type->IsNullableInt()) return; \
if (!value_type->IsAssignableTo(NNBDMode::kLegacyLib_LegacyTest, \
type)) \
return; \
if (!value_type->IsAssignableTo(NNBDMode::kLegacyLib, type)) return; \
type_class = member_name.type_class(); \
ReplaceWithIndexSet(call, cid); \
} \

View file

@ -1588,9 +1588,8 @@ Function& StreamingFlowGraphBuilder::FindMatchingFunction(
while (!iterate_klass.IsNull()) {
function = iterate_klass.LookupDynamicFunctionAllowPrivate(name);
if (!function.IsNull()) {
if (function.AreValidArguments(NNBDMode::kLegacyLib_LegacyTest,
type_args_len, argument_count,
argument_names,
if (function.AreValidArguments(NNBDMode::kLegacyLib, type_args_len,
argument_count, argument_names,
/* error_message = */ NULL)) {
return function;
}
@ -3333,9 +3332,8 @@ Fragment StreamingFlowGraphBuilder::BuildStaticInvocation(TokenPosition* p) {
instructions += BuildArguments(&argument_names, NULL /* arg count */,
NULL /* positional arg count */,
special_case); // read arguments.
ASSERT(target.AreValidArguments(NNBDMode::kLegacyLib_LegacyTest,
type_args_len, argument_count, argument_names,
NULL));
ASSERT(target.AreValidArguments(NNBDMode::kLegacyLib, type_args_len,
argument_count, argument_names, NULL));
// Special case identical(x, y) call.
// Note: similar optimization is performed in bytecode flow graph builder -
@ -3630,7 +3628,7 @@ Fragment StreamingFlowGraphBuilder::BuildIsExpression(TokenPosition* p) {
// The VM does not like an instanceOf call with a dynamic type. We need to
// special case this situation by detecting a top type (using non-nullable
// semantics which is safe in all cases).
if (type.IsTopType(NNBDMode::kNonNullableTest)) {
if (type.NNBD_IsTopType()) {
// Evaluate the expression on the left but ignore its result.
instructions += Drop();

View file

@ -2889,7 +2889,7 @@ static void InvokeTypeCheckFromTypeTestStub(Assembler* assembler,
__ PushImmediate(target::ToRawSmi(mode));
// TODO(regis): Pass nnbd mode in a register from call site.
__ PushImmediate(
target::ToRawSmi(static_cast<intptr_t>(NNBDMode::kLegacyLib_LegacyTest)));
target::ToRawSmi(static_cast<intptr_t>(NNBDMode::kLegacyLib)));
__ CallRuntime(kTypeCheckRuntimeEntry, 8);
__ Drop(2); // mode and nnbd mode
__ Pop(kSubtypeTestCacheReg);

View file

@ -2982,7 +2982,7 @@ static void InvokeTypeCheckFromTypeTestStub(Assembler* assembler,
__ PushImmediate(target::ToRawSmi(mode));
// TODO(regis): Pass nnbd mode in a register from call site.
__ PushImmediate(
target::ToRawSmi(static_cast<intptr_t>(NNBDMode::kLegacyLib_LegacyTest)));
target::ToRawSmi(static_cast<intptr_t>(NNBDMode::kLegacyLib)));
__ CallRuntime(kTypeCheckRuntimeEntry, 8);
__ Drop(2); // mode and nnbd mode
__ Pop(kSubtypeTestCacheReg);

View file

@ -2973,8 +2973,8 @@ static void InvokeTypeCheckFromTypeTestStub(Assembler* assembler,
__ pushq(kSubtypeTestCacheReg);
__ PushImmediate(Immediate(target::ToRawSmi(mode)));
// TODO(regis): Pass nnbd mode in a register from call site.
__ PushImmediate(Immediate(target::ToRawSmi(
static_cast<intptr_t>(NNBDMode::kLegacyLib_LegacyTest))));
__ PushImmediate(
Immediate(target::ToRawSmi(static_cast<intptr_t>(NNBDMode::kLegacyLib))));
__ CallRuntime(kTypeCheckRuntimeEntry, 8);
__ Drop(2); // mode and nnbd_mode
__ popq(kSubtypeTestCacheReg);

View file

@ -152,7 +152,7 @@ static RawInstance* GetListInstance(Zone* zone, const Object& obj) {
ASSERT(!list_class.IsNull());
const Instance& instance = Instance::Cast(obj);
const Class& obj_class = Class::Handle(zone, obj.clazz());
if (Class::IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest, obj_class,
if (Class::IsSubtypeOf(NNBDMode::kLegacyLib, obj_class,
Object::null_type_arguments(), list_class,
Object::null_type_arguments(), Heap::kNew)) {
return instance.raw();
@ -169,7 +169,7 @@ static RawInstance* GetMapInstance(Zone* zone, const Object& obj) {
ASSERT(!map_class.IsNull());
const Instance& instance = Instance::Cast(obj);
const Class& obj_class = Class::Handle(zone, obj.clazz());
if (Class::IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest, obj_class,
if (Class::IsSubtypeOf(NNBDMode::kLegacyLib, obj_class,
Object::null_type_arguments(), map_class,
Object::null_type_arguments(), Heap::kNew)) {
return instance.raw();
@ -2044,7 +2044,7 @@ DART_EXPORT Dart_Handle Dart_ObjectIsType(Dart_Handle object,
RETURN_TYPE_ERROR(Z, object, Instance);
}
CHECK_CALLBACK_STATE(T);
*value = instance.IsInstanceOf(NNBDMode::kLegacyLib_LegacyTest, type_obj,
*value = instance.IsInstanceOf(NNBDMode::kLegacyLib, type_obj,
Object::null_type_arguments(),
Object::null_type_arguments());
return Api::Success();
@ -2206,10 +2206,9 @@ DART_EXPORT bool Dart_IsFuture(Dart_Handle handle) {
Class::Handle(I->object_store()->future_class());
ASSERT(!future_class.IsNull());
const Class& obj_class = Class::Handle(Z, obj.clazz());
bool is_future =
Class::IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest, obj_class,
Object::null_type_arguments(), future_class,
Object::null_type_arguments(), Heap::kNew);
bool is_future = Class::IsSubtypeOf(
NNBDMode::kLegacyLib, obj_class, Object::null_type_arguments(),
future_class, Object::null_type_arguments(), Heap::kNew);
return is_future;
}
return false;
@ -4046,8 +4045,8 @@ DART_EXPORT Dart_Handle Dart_New(Dart_Handle type,
// We do not support generic constructors.
ASSERT(redirect_type.IsInstantiated(kFunctions));
redirect_type ^= redirect_type.InstantiateFrom(
NNBDMode::kLegacyLib_LegacyTest, type_arguments,
Object::null_type_arguments(), kNoneFree, NULL, Heap::kNew);
NNBDMode::kLegacyLib, type_arguments, Object::null_type_arguments(),
kNoneFree, NULL, Heap::kNew);
redirect_type ^= redirect_type.Canonicalize();
}

View file

@ -1310,7 +1310,7 @@ bool Interpreter::AssertAssignableField(Thread* thread,
SP[3] = InterpreterHelpers::GetTypeArguments(thread, instance);
SP[4] = null_value; // Implicit setters cannot be generic.
SP[5] = is_getter ? Symbols::FunctionResult().raw() : field->ptr()->name_;
SP[6] = Smi::New(static_cast<intptr_t>(NNBDMode::kLegacyLib_LegacyTest));
SP[6] = Smi::New(static_cast<intptr_t>(NNBDMode::kLegacyLib));
return AssertAssignable(thread, pc, FP, /* call_top */ SP + 6,
/* args */ SP + 1, cache);
}
@ -3571,8 +3571,7 @@ SwitchDispatch:
Instance::RawCast(FrameArguments(FP, argc)[receiver_idx]);
SP[5] = InterpreterHelpers::GetTypeArguments(thread, receiver);
// TODO(regis): Provide correct nnbd mode.
RawSmi* nnbd_mode =
Smi::New(static_cast<intptr_t>(NNBDMode::kLegacyLib_LegacyTest));
RawSmi* nnbd_mode = Smi::New(static_cast<intptr_t>(NNBDMode::kLegacyLib));
if (type_args_len > 0) {
SP[6] = FrameArguments(FP, argc)[0];

View file

@ -3673,7 +3673,7 @@ RawObject* Class::InvokeSetter(const String& setter_name,
InvocationMirror::kSetter);
}
parameter_type = setter.ParameterTypeAt(0);
if (nnbd_mode() != NNBDMode::kLegacyLib_LegacyTest) {
if (nnbd_mode() != NNBDMode::kLegacyLib) {
// TODO(regis): Make type check nullability aware.
UNIMPLEMENTED();
}
@ -3701,7 +3701,7 @@ RawObject* Class::InvokeSetter(const String& setter_name,
}
parameter_type = field.type();
if (nnbd_mode() != NNBDMode::kLegacyLib_LegacyTest) {
if (nnbd_mode() != NNBDMode::kLegacyLib) {
// TODO(regis): Make type check nullability aware.
UNIMPLEMENTED();
}
@ -3767,15 +3767,15 @@ RawObject* Class::Invoke(const String& function_name,
ArgumentsDescriptor args_descriptor(args_descriptor_array);
const TypeArguments& type_args = Object::null_type_arguments();
if (function.IsNull() ||
!function.AreValidArguments(NNBDMode::kLegacyLib_LegacyTest,
args_descriptor, NULL) ||
!function.AreValidArguments(NNBDMode::kLegacyLib, args_descriptor,
NULL) ||
(respect_reflectable && !function.is_reflectable())) {
return ThrowNoSuchMethod(
AbstractType::Handle(zone, RareType()), function_name, args, arg_names,
InvocationMirror::kStatic, InvocationMirror::kMethod);
}
RawObject* type_error = function.DoArgumentTypesMatch(
NNBDMode::kLegacyLib_LegacyTest, args, args_descriptor, type_args);
NNBDMode::kLegacyLib, args, args_descriptor, type_args);
if (type_error != Error::null()) {
return type_error;
}
@ -4442,9 +4442,9 @@ void Class::set_declaration_type(const Type& value) const {
// Since declaration type is used as the runtime type of instances of a
// non-generic class, the nullability is set to kNonNullable instead of
// kLegacy when the non-nullable experiment is enabled.
ASSERT(!value.IsNullType() || value.IsNullable());
ASSERT(value.type_class_id() != kNullCid || value.IsNullable());
ASSERT(
value.IsNullType() ||
value.type_class_id() == kNullCid ||
(Dart::non_nullable_flag() ? value.IsNonNullable() : value.IsLegacy()));
StorePointer(&raw_ptr()->declaration_type_, value.raw());
}
@ -4547,7 +4547,7 @@ bool Class::IsSubtypeOf(NNBDMode mode,
}
const AbstractType& other_type_arg =
AbstractType::Handle(zone, other_type_arguments.TypeAt(0));
if (other_type_arg.IsTopType(mode)) {
if (other_type_arg.IsTopType()) {
return true;
}
if (!type_arguments.IsNull() && this_class.IsFutureClass()) {
@ -4558,10 +4558,10 @@ bool Class::IsSubtypeOf(NNBDMode mode,
}
}
if (other_type_arg.HasTypeClass() &&
Class::IsSubtypeOf(mode, this_class, type_arguments,
Class::Handle(zone, other_type_arg.type_class()),
TypeArguments::Handle(other_type_arg.arguments()),
space)) {
Class::IsSubtypeOf(
mode, this_class, type_arguments,
Class::Handle(zone, other_type_arg.type_class()),
TypeArguments::Handle(zone, other_type_arg.arguments()), space)) {
return true;
}
}
@ -5366,7 +5366,7 @@ bool TypeArguments::IsTopTypes(NNBDMode mode,
AbstractType& type = AbstractType::Handle();
for (intptr_t i = 0; i < len; i++) {
type = TypeAt(from_index + i);
if (type.IsNull() || !type.IsTopType(mode)) {
if (type.IsNull() || !type.IsTopType()) {
return false;
}
}
@ -7029,7 +7029,7 @@ bool Function::AreValidArguments(NNBDMode mode,
num_named_arguments, error_message)) {
return false;
}
if (mode != NNBDMode::kLegacyLib_LegacyTest) {
if (mode != NNBDMode::kLegacyLib) {
// TODO(regis): Check required named arguments.
}
// Verify that all argument names are valid parameter names.
@ -7379,7 +7379,7 @@ bool Function::IsContravariantParameter(NNBDMode mode,
Heap::Space space) const {
const AbstractType& param_type =
AbstractType::Handle(ParameterTypeAt(parameter_position));
if (param_type.IsTopType(mode)) {
if (param_type.IsTopType()) {
return true;
}
const AbstractType& other_param_type =
@ -7424,7 +7424,7 @@ bool Function::HasSameTypeParametersAndBounds(const Function& other) const {
bool Function::IsSubtypeOf(NNBDMode mode,
const Function& other,
Heap::Space space) const {
if (mode != NNBDMode::kLegacyLib_LegacyTest) {
if (mode != NNBDMode::kLegacyLib) {
// TODO(regis): Check required named parameters.
}
const intptr_t num_fixed_params = num_fixed_parameters();
@ -7457,7 +7457,7 @@ bool Function::IsSubtypeOf(NNBDMode mode,
const AbstractType& other_res_type =
AbstractType::Handle(zone, other.result_type());
// 'void Function()' is a subtype of 'Object Function()'.
if (!other_res_type.IsTopType(mode)) {
if (!other_res_type.IsTopType()) {
const AbstractType& res_type = AbstractType::Handle(zone, result_type());
if (!res_type.IsSubtypeOf(mode, other_res_type, space)) {
return false;
@ -9471,7 +9471,7 @@ StaticTypeExactnessState StaticTypeExactnessState::Compute(
for (intptr_t i = path.length() - 2; (i >= 0) && !type.IsInstantiated();
i--) {
args = path[i]->arguments();
type = type.InstantiateFrom(NNBDMode::kLegacyLib_LegacyTest, args,
type = type.InstantiateFrom(NNBDMode::kLegacyLib, args,
TypeArguments::null_type_arguments(), kAllFree,
/*instantiation_trail=*/nullptr, Heap::kNew);
}
@ -11411,15 +11411,14 @@ static RawObject* InvokeInstanceFunction(
// first element.
ArgumentsDescriptor args_descriptor(args_descriptor_array);
if (function.IsNull() ||
!function.AreValidArguments(NNBDMode::kLegacyLib_LegacyTest,
args_descriptor, NULL) ||
!function.AreValidArguments(NNBDMode::kLegacyLib, args_descriptor,
NULL) ||
(respect_reflectable && !function.is_reflectable())) {
return DartEntry::InvokeNoSuchMethod(receiver, target_name, args,
args_descriptor_array);
}
RawObject* type_error =
function.DoArgumentTypesMatch(NNBDMode::kLegacyLib_LegacyTest, args,
args_descriptor, instantiator_type_args);
RawObject* type_error = function.DoArgumentTypesMatch(
NNBDMode::kLegacyLib, args, args_descriptor, instantiator_type_args);
if (type_error != Error::null()) {
return type_error;
}
@ -11608,8 +11607,8 @@ RawObject* Library::Invoke(const String& function_name,
ArgumentsDescriptor args_descriptor(args_descriptor_array);
const TypeArguments& type_args = Object::null_type_arguments();
if (function.IsNull() ||
!function.AreValidArguments(NNBDMode::kLegacyLib_LegacyTest,
args_descriptor, NULL) ||
!function.AreValidArguments(NNBDMode::kLegacyLib, args_descriptor,
NULL) ||
(respect_reflectable && !function.is_reflectable())) {
return ThrowNoSuchMethod(
AbstractType::Handle(Class::Handle(toplevel_class()).RareType()),
@ -11617,7 +11616,7 @@ RawObject* Library::Invoke(const String& function_name,
InvocationMirror::kMethod);
}
RawObject* type_error = function.DoArgumentTypesMatch(
NNBDMode::kLegacyLib_LegacyTest, args, args_descriptor, type_args);
NNBDMode::kLegacyLib, args, args_descriptor, type_args);
if (type_error != Error::null()) {
return type_error;
}
@ -16887,41 +16886,38 @@ bool Instance::IsInstanceOf(
ASSERT(!other.IsTypeRef()); // Must be dereferenced at compile time.
// Note that Object::sentinel() has Null class, but !IsNull().
ASSERT(raw() != Object::sentinel().raw());
// The NNBDMode::kNonNullableTest mode cannot be set yet.
ASSERT((mode & NNBDMode::kTestMask) != NNBDMode::kNonNullableTest);
if (FLAG_strong_non_nullable_type_checks) {
if (IsNull()) {
// In a legacy library, compute
// NNBD_SUBTYPE(other, Null) || NNBD_SUBTYPE(Object, other)
// In an opted-in library, compute
// NNBD_SUBTYPE(Null, other).
return Instance::NullIsInstanceOf(
mode | NNBDMode::kNonNullableTest, other,
other_instantiator_type_arguments, other_function_type_arguments);
return Instance::NullIsInstanceOf(mode, other,
other_instantiator_type_arguments,
other_function_type_arguments);
}
// Compute NNBD_SUBTYPE(runtimeType, other).
return RuntimeTypeIsSubtypeOf(mode | NNBDMode::kNonNullableTest, other,
return RuntimeTypeIsSubtypeOf(mode, other,
other_instantiator_type_arguments,
other_function_type_arguments);
}
if (IsNull()) {
if (mode == NNBDMode::kOptedInLib) {
// Compute NNBD_SUBTYPE(Null, other).
return Instance::NullIsInstanceOf(
NNBDMode::kOptedInLib_NonNullableTest, other,
other_instantiator_type_arguments, other_function_type_arguments);
return Instance::NNBD_NullIsInstanceOf(other,
other_instantiator_type_arguments,
other_function_type_arguments);
}
ASSERT(mode == NNBDMode::kLegacyLib);
// Compute the same subtyping result as pre-nnbd Dart:
// LEGACY_SUBTYPE(other, Null) || LEGACY_SUBTYPE(Object, other).
return Instance::NullIsInstanceOf(NNBDMode::kLegacyLib_LegacyTest, other,
return Instance::NullIsInstanceOf(NNBDMode::kLegacyLib, other,
other_instantiator_type_arguments,
other_function_type_arguments);
}
// Compute the same subtyping result as pre-nnbd Dart:
// LEGACY_SUBTYPE(runtimeType, other).
return RuntimeTypeIsSubtypeOf(mode | NNBDMode::kLegacyTest, other,
other_instantiator_type_arguments,
return RuntimeTypeIsSubtypeOf(mode, other, other_instantiator_type_arguments,
other_function_type_arguments);
}
@ -16935,39 +16931,30 @@ bool Instance::IsAssignableTo(
ASSERT(!other.IsTypeRef()); // Must be dereferenced at compile time.
// Note that Object::sentinel() has Null class, but !IsNull().
ASSERT(raw() != Object::sentinel().raw());
// The NNBDMode::kNonNullableTest mode cannot be set yet.
ASSERT((mode & NNBDMode::kTestMask) != NNBDMode::kNonNullableTest);
// 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(FLAG_strong_non_nullable_type_checks || !IsNull());
// In strong mode, compute NNBD_SUBTYPE(runtimeType, other).
// In weak mode, compute LEGACY_SUBTYPE(runtimeType, other).
return RuntimeTypeIsSubtypeOf(
mode | (FLAG_strong_non_nullable_type_checks ? NNBDMode::kNonNullableTest
: NNBDMode::kLegacyTest),
other, other_instantiator_type_arguments, other_function_type_arguments);
return RuntimeTypeIsSubtypeOf(mode, other, other_instantiator_type_arguments,
other_function_type_arguments);
}
// For kLegacyLib_NonNullableTest mode:
// In strong mode, for kLegacyLib mode:
// return NNBD_SUBTYPE(other, Null) || NNBD_SUBTYPE(Object, other).
// For kOptedInLib_NonNullableTest mode:
// In strong mode, for kOptedInLib mode:
// return NNBD_SUBTYPE(Null, other).
// For kLegacyLib_LegacyTest mode:
// In weak mode, for kLegacyLib mode:
// return LEGACY_SUBTYPE(other, Null) || LEGACY_SUBTYPE(Object, other).
// The NNBDMode::kOptedInLib_LegacyTest mode is never passed.
// The NNBDMode::kOptedInLib mode is never passed in weak mode.
bool Instance::NullIsInstanceOf(
NNBDMode mode,
const AbstractType& other,
const TypeArguments& other_instantiator_type_arguments,
const TypeArguments& other_function_type_arguments) {
ASSERT(mode != NNBDMode::kOptedInLib_LegacyTest);
// Strong mode must be reflected by mode.
ASSERT(!FLAG_strong_non_nullable_type_checks ||
(mode & NNBDMode::kTestMask) == NNBDMode::kNonNullableTest);
if (other.IsNullType(mode) || other.IsTopType(mode)) {
ASSERT(FLAG_strong_non_nullable_type_checks || mode != NNBDMode::kOptedInLib);
if (other.IsNullType() || other.IsTopType()) {
return true;
}
AbstractType& instantiated_other = AbstractType::Handle(other.raw());
@ -16978,19 +16965,17 @@ bool Instance::NullIsInstanceOf(
if (instantiated_other.IsTypeRef()) {
instantiated_other = TypeRef::Cast(instantiated_other).type();
}
if (instantiated_other.IsNullType(mode) ||
instantiated_other.IsTopType(mode)) {
if (instantiated_other.IsNullType() || instantiated_other.IsTopType()) {
return true;
}
}
// instantiated_other is not modified if not FutureOr<T>.
if (instantiated_other.IsFutureOr(&instantiated_other)) {
if (instantiated_other.IsNullType(mode) ||
instantiated_other.IsTopType(mode)) {
return true;
}
while (instantiated_other.IsFutureOr(&instantiated_other)) {
}
if (mode == NNBDMode::kOptedInLib_NonNullableTest) {
if (instantiated_other.IsNullType() || instantiated_other.IsTopType()) {
return true;
}
if (FLAG_strong_non_nullable_type_checks) {
const Nullability other_nullability = instantiated_other.nullability();
return other_nullability == Nullability::kNullable ||
other_nullability == Nullability::kLegacy;
@ -16998,6 +16983,38 @@ bool Instance::NullIsInstanceOf(
return false;
}
// Return NNBD_SUBTYPE(Null, other) independently of strong flag value.
bool Instance::NNBD_NullIsInstanceOf(
const AbstractType& other,
const TypeArguments& other_instantiator_type_arguments,
const TypeArguments& other_function_type_arguments) {
Nullability other_nullability = other.nullability();
if (other_nullability == Nullability::kNullable ||
other_nullability == Nullability::kLegacy) {
// This includes Null type and top types when using nnbd testing.
// Also, an uninstantiated type that is either nullable or legacy will
// be either nullable or legacy after instantiation and cannot throw a
// type error during instantiation.
return true;
}
AbstractType& instantiated_other = AbstractType::Handle(other.raw());
if (!other.IsInstantiated()) {
instantiated_other = other.InstantiateFrom(
NNBDMode::kOptedInLib, other_instantiator_type_arguments,
other_function_type_arguments, kAllFree, NULL, Heap::kOld);
if (instantiated_other.IsTypeRef()) {
instantiated_other = TypeRef::Cast(instantiated_other).type();
}
}
// instantiated_other is not modified if not FutureOr<T>.
while (instantiated_other.IsFutureOr(&instantiated_other)) {
}
// Test nullability again after instantiation.
other_nullability = instantiated_other.nullability();
return other_nullability == Nullability::kNullable ||
other_nullability == Nullability::kLegacy;
}
bool Instance::RuntimeTypeIsSubtypeOf(
NNBDMode mode,
const AbstractType& other,
@ -17006,17 +17023,12 @@ bool Instance::RuntimeTypeIsSubtypeOf(
ASSERT(other.IsFinalized());
ASSERT(!other.IsDynamicType());
ASSERT(!other.IsTypeRef()); // Must be dereferenced at compile time.
// Strong mode must be reflected by mode.
ASSERT(!FLAG_strong_non_nullable_type_checks ||
(mode & NNBDMode::kTestMask) == NNBDMode::kNonNullableTest);
// Instance may not have runtimeType dynamic, void, or Never.
if (other.IsTopType(mode)) {
if (other.IsTopType()) {
return true;
}
// In legacy testing mode, Null type is a subtype of any type.
if (IsNull() && ((mode & NNBDMode::kTestMask) == NNBDMode::kLegacyTest)) {
// In weak testing mode, Null type is a subtype of any type.
if (IsNull() && !FLAG_strong_non_nullable_type_checks) {
return true;
}
Thread* thread = Thread::Current();
@ -17034,7 +17046,7 @@ bool Instance::RuntimeTypeIsSubtypeOf(
if (instantiated_other.IsTypeRef()) {
instantiated_other = TypeRef::Cast(instantiated_other).type();
}
if (instantiated_other.IsTopType(mode) ||
if (instantiated_other.IsTopType() ||
instantiated_other.IsDartFunctionType()) {
return true;
}
@ -17074,7 +17086,7 @@ bool Instance::RuntimeTypeIsSubtypeOf(
if (instantiated_other.IsTypeRef()) {
instantiated_other = TypeRef::Cast(instantiated_other).type();
}
if (instantiated_other.IsTopType(mode)) {
if (instantiated_other.IsTopType()) {
return true;
}
}
@ -17082,8 +17094,8 @@ bool Instance::RuntimeTypeIsSubtypeOf(
return false;
}
if (IsNull()) {
ASSERT((mode & NNBDMode::kTestMask) == NNBDMode::kNonNullableTest);
if (instantiated_other.IsNullType(mode)) {
ASSERT(FLAG_strong_non_nullable_type_checks);
if (instantiated_other.IsNullType()) {
return true;
}
if (IsFutureOrInstanceOf(zone, mode, instantiated_other)) {
@ -17111,7 +17123,7 @@ bool Instance::IsFutureOrInstanceOf(Zone* zone,
TypeArguments::Handle(zone, other.arguments());
const AbstractType& other_type_arg =
AbstractType::Handle(zone, other_type_arguments.TypeAt(0));
if (other_type_arg.IsTopType(mode)) {
if (other_type_arg.IsTopType()) {
return true;
}
if (Class::Handle(zone, clazz()).IsFutureClass()) {
@ -17356,7 +17368,7 @@ RawAbstractType* AbstractType::CheckInstantiatedNullability(
Heap::Space space) const {
Nullability result_nullability;
const Nullability arg_nullability = nullability();
if ((mode & NNBDMode::kLibMask) == NNBDMode::kOptedInLib) {
if (mode == NNBDMode::kOptedInLib) {
const Nullability var_nullability = type_param.nullability();
// Adjust nullability of result 'arg' instantiated from 'var' (x throws).
// arg/var ! ? * %
@ -17700,21 +17712,19 @@ bool AbstractType::IsNullTypeRef() const {
return IsTypeRef() && (TypeRef::Cast(*this).type() == AbstractType::null());
}
bool AbstractType::IsNullType(NNBDMode mode) const {
bool AbstractType::IsNullType() const {
const classid_t cid = type_class_id();
return cid == kNullCid ||
(cid == kNeverCid &&
((mode & NNBDMode::kTestMask) == NNBDMode::kLegacyTest ||
IsNullable()));
(!FLAG_strong_non_nullable_type_checks || IsNullable()));
}
bool AbstractType::IsNeverType(NNBDMode mode) const {
return type_class_id() == kNeverCid &&
(mode & NNBDMode::kTestMask) == NNBDMode::kNonNullableTest &&
bool AbstractType::IsNeverType() const {
return FLAG_strong_non_nullable_type_checks && type_class_id() == kNeverCid &&
!IsNullable();
}
bool AbstractType::IsTopType(NNBDMode mode) const {
bool AbstractType::IsTopType() const {
const classid_t cid = type_class_id();
if (cid == kIllegalCid) { // Includes TypeParameter.
return false;
@ -17723,7 +17733,7 @@ bool AbstractType::IsTopType(NNBDMode mode) const {
return true;
}
if (cid == kInstanceCid) { // Object type.
return (mode & NNBDMode::kTestMask) == NNBDMode::kLegacyTest ||
return !FLAG_strong_non_nullable_type_checks ||
!IsNonNullable(); // kLegacy or kNullable.
}
// FutureOr<T> where T is a top type behaves as a top type.
@ -17737,7 +17747,37 @@ bool AbstractType::IsTopType(NNBDMode mode) const {
TypeArguments::Handle(zone, arguments());
const AbstractType& type_arg =
AbstractType::Handle(zone, type_arguments.TypeAt(0));
if (type_arg.IsTopType(mode)) {
if (type_arg.IsTopType()) {
return true;
}
}
return false;
}
bool AbstractType::NNBD_IsTopType() const {
const classid_t cid = type_class_id();
if (cid == kIllegalCid) { // Includes TypeParameter.
return false;
}
if (cid == kDynamicCid || cid == kVoidCid) {
return true;
}
if (cid == kInstanceCid) { // Object type.
return !IsNonNullable(); // kLegacy or kNullable.
}
// FutureOr<T> where T is a top type behaves as a top type.
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
if (Class::Handle(zone, type_class()).IsFutureOrClass()) {
if (arguments() == TypeArguments::null()) {
return true;
}
const TypeArguments& type_arguments =
TypeArguments::Handle(zone, arguments());
const AbstractType& type_arg =
AbstractType::Handle(zone, type_arguments.TypeAt(0));
if (type_arg.NNBD_IsTopType()) {
return true;
}
}
@ -17818,32 +17858,25 @@ bool AbstractType::IsSubtypeOf(NNBDMode mode,
Heap::Space space) const {
ASSERT(IsFinalized());
ASSERT(other.IsFinalized());
// Strong mode must be reflected by mode.
ASSERT(!FLAG_strong_non_nullable_type_checks ||
(mode & NNBDMode::kTestMask) == NNBDMode::kNonNullableTest);
if (other.IsTopType(mode) || IsNeverType(mode)) {
if (other.IsTopType() || IsNeverType()) {
return true;
}
if (IsDynamicType() || IsVoidType()) {
return false;
}
if (IsNullType(mode)) {
// In legacy testing mode, Null type is a subtype of any type.
if ((mode & NNBDMode::kTestMask) == NNBDMode::kLegacyTest) {
if (IsNullType()) {
// In weak testing mode, Null type is a subtype of any type.
if (!FLAG_strong_non_nullable_type_checks) {
return true;
}
if (other.IsNullType(mode)) {
return true;
if (other.IsTypeParameter()) {
return false;
}
AbstractType& other_type_arg = AbstractType::Handle(other.raw());
// other_type_arg is not modified if not FutureOr<T>.
if (other.IsFutureOr(&other_type_arg)) {
if (other_type_arg.IsNullType(mode) || other_type_arg.IsTopType(mode)) {
return true;
}
while (other_type_arg.IsFutureOr(&other_type_arg)) {
}
return !other.IsTypeParameter() && !other_type_arg.IsNonNullable();
return !other_type_arg.IsTypeParameter() && !other_type_arg.IsNonNullable();
}
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
@ -17936,10 +17969,9 @@ bool AbstractType::IsSubtypeOf(NNBDMode mode,
}
return false;
}
if ((mode & NNBDMode::kTestMask) == NNBDMode::kNonNullableTest) {
if (IsNullable() && other.IsNonNullable()) {
return false;
}
if (FLAG_strong_non_nullable_type_checks && IsNullable() &&
other.IsNonNullable()) {
return false;
}
return Class::IsSubtypeOf(
mode, type_cls, TypeArguments::Handle(zone, arguments()), other_type_cls,
@ -17963,7 +17995,7 @@ bool AbstractType::IsSubtypeOfFutureOr(Zone* zone,
TypeArguments::Handle(zone, other.arguments());
const AbstractType& other_type_arg =
AbstractType::Handle(zone, other_type_arguments.TypeAt(0));
if (other_type_arg.IsTopType(mode)) {
if (other_type_arg.IsTopType()) {
return true;
}
// Retry the IsSubtypeOf check after unwrapping type arg of FutureOr.
@ -18452,7 +18484,7 @@ bool Type::IsRecursive() const {
bool Type::IsDeclarationTypeOf(const Class& cls) const {
ASSERT(type_class() == cls.raw());
if (IsNullType()) {
if (cls.IsNullClass()) {
return true;
}
if (cls.IsGeneric() || cls.IsClosureClass() || cls.IsTypedefClass()) {
@ -18490,7 +18522,7 @@ RawAbstractType* Type::Canonicalize(TrailPtr trail) const {
// Fast canonical lookup/registry for simple types.
if (IsDeclarationTypeOf(cls)) {
ASSERT(!IsFunctionType());
ASSERT(!IsNullType() || IsNullable());
ASSERT(!cls.IsNullClass() || IsNullable());
Type& type = Type::Handle(zone, cls.declaration_type());
if (type.IsNull()) {
ASSERT(!cls.raw()->InVMIsolateHeap() || (isolate == Dart::vm_isolate()));

View file

@ -860,48 +860,16 @@ enum class Nullability : int8_t {
};
// The NNBDMode is passed to routines performing type reification and/or subtype
// tests. The mode consists of two bits, one reflecting the opted-in status of
// the library performing type reification and/or subtype tests, the other bit
// specifying whether the type test should be performed according the pre-nnbd
// semantics (noted LEGACY_SUBTYPE(S, T) in the specification), or according to
// the nnbd semantics (noted NNBD_SUBTYPE(S, T) in the specification).
// The first bit is usually passed explicitly from Dart code to the runtime
// entry, because the runtime cannot efficiently tell if the call originated in
// an opted-in or legacy library. Then, the bit defining the semantics of the
// test is computed depending on the actual value of the instance being checked
// (null or non-null), on the value of the global strong mode flag, and on the
// nature of the test (instance test or type cast).
// For more details, see the language specification.
// tests. The mode reflects the opted-in status of the library performing type
// reification and/or subtype tests.
// Note that the weak or strong testing mode is not reflected in NNBDMode, but
// imposed globally by the value of FLAG_strong_non_nullable_type_checks.
enum class NNBDMode {
// Status of the library:
kLibMask = 1,
kLegacyLib = 0, // Library is legacy.
kOptedInLib = 1, // Library is opted-in.
// Semantics of the type test:
kTestMask = 2,
kLegacyTest = 0, // Legacy type test, i.e. LEGACY_SUBTYPE(S, T).
kNonNullableTest = 2, // Non-nullable type test, i.e. NNBD_SUBTYPE(S, T).
// All possible values:
kLegacyLib_LegacyTest = 0,
kOptedInLib_LegacyTest = 1,
kLegacyLib_NonNullableTest = 2,
kOptedInLib_NonNullableTest = 3,
};
NNBDMode inline operator|(NNBDMode lhs, NNBDMode rhs) {
return static_cast<NNBDMode>(
static_cast<std::underlying_type<NNBDMode>::type>(lhs) |
static_cast<std::underlying_type<NNBDMode>::type>(rhs));
}
NNBDMode inline operator&(NNBDMode lhs, NNBDMode rhs) {
return static_cast<NNBDMode>(
static_cast<std::underlying_type<NNBDMode>::type>(lhs) &
static_cast<std::underlying_type<NNBDMode>::type>(rhs));
}
class Class : public Object {
public:
enum InvocationDispatcherEntry {
@ -6678,6 +6646,13 @@ class Instance : public Object {
const TypeArguments& other_instantiator_type_arguments,
const TypeArguments& other_function_type_arguments);
// Return true if the null instance is an instance of other type according to
// NNBD semantics (independently of the current value of the strong flag).
static bool NNBD_NullIsInstanceOf(
const AbstractType& other,
const TypeArguments& other_instantiator_type_arguments,
const TypeArguments& other_function_type_arguments);
RawObject** FieldAddrAtOffset(intptr_t offset) const {
ASSERT(IsValidFieldOffset(offset));
return reinterpret_cast<RawObject**>(raw_value() - kHeapObjectTag + offset);
@ -7139,16 +7114,20 @@ class AbstractType : public Instance {
bool IsVoidType() const { return type_class_id() == kVoidCid; }
// Check if this type represents the 'Null' type.
bool IsNullType(NNBDMode mode = NNBDMode::kNonNullableTest) const;
bool IsNullType() const;
// Check if this type represents the 'Never' type.
bool IsNeverType(NNBDMode mode = NNBDMode::kNonNullableTest) const;
bool IsNeverType() const;
// Check if this type represents the 'Object' type.
bool IsObjectType() const { return type_class_id() == kInstanceCid; }
// Check if this type represents a top type.
bool IsTopType(NNBDMode mode = NNBDMode::kLegacyTest) const;
bool IsTopType() const;
// Check if this type represents a top type according to NNBD
// semantics (independently of the current value of the strong flag).
bool NNBD_IsTopType() const;
// Check if this type represents the 'bool' type.
bool IsBoolType() const { return type_class_id() == kBoolCid; }

View file

@ -895,8 +895,7 @@ void CallSiteResetter::Reset(const ICData& ic) {
args_desc_array_ = ic.arguments_descriptor();
ArgumentsDescriptor args_desc(args_desc_array_);
if (new_target_.IsNull() ||
!new_target_.AreValidArguments(NNBDMode::kLegacyLib_LegacyTest,
args_desc, NULL)) {
!new_target_.AreValidArguments(NNBDMode::kLegacyLib, args_desc, NULL)) {
// TODO(rmacnak): Patch to a NSME stub.
VTIR_Print("Cannot rebind static call to %s from %s\n",
old_target_.ToCString(),

View file

@ -216,11 +216,10 @@ void TypeArguments::PrintJSONImpl(JSONStream* stream, bool ref) const {
nnbd_mode_as_smi ^= prior_instantiations.At(
i + TypeArguments::Instantiation::kNnbdModeIndex);
instantiation.AddProperty(
"nnbd_mode",
nnbd_mode_as_smi.Value() ==
static_cast<intptr_t>(NNBDMode::kLegacyLib_LegacyTest)
? "legacy"
: "opted-in");
"nnbd_mode", nnbd_mode_as_smi.Value() ==
static_cast<intptr_t>(NNBDMode::kLegacyLib)
? "legacy"
: "opted-in");
type_args ^= prior_instantiations.At(
i + TypeArguments::Instantiation::kInstantiatedTypeArgsIndex);
instantiation.AddProperty("instantiated", type_args, true);

View file

@ -43,8 +43,7 @@ RawFunction* Resolver::ResolveDynamicForReceiverClass(
ResolveDynamicAnyArgs(zone, receiver_class, function_name, allow_add));
if (function.IsNull() ||
!function.AreValidArguments(NNBDMode::kLegacyLib_LegacyTest, args_desc,
NULL)) {
!function.AreValidArguments(NNBDMode::kLegacyLib, args_desc, NULL)) {
// Return a null function to signal to the upper levels to dispatch to
// "noSuchMethod" function.
if (FLAG_trace_resolving) {
@ -52,7 +51,7 @@ RawFunction* Resolver::ResolveDynamicForReceiverClass(
String::Handle(zone, Symbols::New(thread, "function not found"));
if (!function.IsNull()) {
// Obtain more detailed error message.
function.AreValidArguments(NNBDMode::kLegacyLib_LegacyTest, args_desc,
function.AreValidArguments(NNBDMode::kLegacyLib, args_desc,
&error_message);
}
THR_Print("ResolveDynamic error '%s': %s.\n", function_name.ToCString(),
@ -152,15 +151,14 @@ RawFunction* Resolver::ResolveStatic(const Library& library,
const Object& object = Object::Handle(library.ResolveName(function_name));
if (!object.IsNull() && object.IsFunction()) {
function ^= object.raw();
if (!function.AreValidArguments(NNBDMode::kLegacyLib_LegacyTest,
type_args_len, num_arguments,
argument_names, NULL)) {
if (!function.AreValidArguments(NNBDMode::kLegacyLib, type_args_len,
num_arguments, argument_names, NULL)) {
if (FLAG_trace_resolving) {
String& error_message = String::Handle();
// Obtain more detailed error message.
function.AreValidArguments(NNBDMode::kLegacyLib_LegacyTest,
type_args_len, num_arguments,
argument_names, &error_message);
function.AreValidArguments(NNBDMode::kLegacyLib, type_args_len,
num_arguments, argument_names,
&error_message);
THR_Print("ResolveStatic error '%s': %s.\n",
function_name.ToCString(), error_message.ToCString());
}
@ -200,17 +198,17 @@ RawFunction* Resolver::ResolveStatic(const Class& cls,
}
const Function& function =
Function::Handle(cls.LookupStaticFunction(function_name));
if (function.IsNull() || !function.AreValidArguments(
NNBDMode::kLegacyLib_LegacyTest, type_args_len,
num_arguments, argument_names, NULL)) {
if (function.IsNull() ||
!function.AreValidArguments(NNBDMode::kLegacyLib, type_args_len,
num_arguments, argument_names, NULL)) {
// Return a null function to signal to the upper levels to throw a
// resolution error or maybe throw the error right here.
if (FLAG_trace_resolving) {
String& error_message = String::Handle(String::New("function not found"));
if (!function.IsNull()) {
// Obtain more detailed error message.
function.AreValidArguments(NNBDMode::kLegacyLib_LegacyTest,
type_args_len, num_arguments, argument_names,
function.AreValidArguments(NNBDMode::kLegacyLib, type_args_len,
num_arguments, argument_names,
&error_message);
}
THR_Print("ResolveStatic error '%s': %s.\n", function_name.ToCString(),
@ -232,17 +230,17 @@ RawFunction* Resolver::ResolveStaticAllowPrivate(const Class& cls,
}
const Function& function =
Function::Handle(cls.LookupStaticFunctionAllowPrivate(function_name));
if (function.IsNull() || !function.AreValidArguments(
NNBDMode::kLegacyLib_LegacyTest, type_args_len,
num_arguments, argument_names, NULL)) {
if (function.IsNull() ||
!function.AreValidArguments(NNBDMode::kLegacyLib, type_args_len,
num_arguments, argument_names, NULL)) {
// Return a null function to signal to the upper levels to throw a
// resolution error or maybe throw the error right here.
if (FLAG_trace_resolving) {
String& error_message = String::Handle(String::New("function not found"));
if (!function.IsNull()) {
// Obtain more detailed error message.
function.AreValidArguments(NNBDMode::kLegacyLib_LegacyTest,
type_args_len, num_arguments, argument_names,
function.AreValidArguments(NNBDMode::kLegacyLib, type_args_len,
num_arguments, argument_names,
&error_message);
}
THR_Print("ResolveStaticAllowPrivate error '%s': %s.\n",

View file

@ -547,8 +547,8 @@ DEFINE_RUNTIME_ENTRY(ResolveCallFunction, 2) {
do {
call_function = cls.LookupDynamicFunction(Symbols::Call());
if (!call_function.IsNull()) {
if (!call_function.AreValidArguments(NNBDMode::kLegacyLib_LegacyTest,
args_desc, NULL)) {
if (!call_function.AreValidArguments(NNBDMode::kLegacyLib, args_desc,
NULL)) {
call_function = Function::null();
}
break;
@ -2111,8 +2111,8 @@ DEFINE_RUNTIME_ENTRY(NoSuchMethodFromCallStub, 4) {
while (!cls.IsNull()) {
function = cls.LookupDynamicFunction(target_name);
if (!function.IsNull()) {
ASSERT(!function.AreValidArguments(NNBDMode::kLegacyLib_LegacyTest,
args_desc, NULL));
ASSERT(
!function.AreValidArguments(NNBDMode::kLegacyLib, args_desc, NULL));
break; // mismatch, invoke noSuchMethod
}
function = cls.LookupDynamicFunction(getter_name);

View file

@ -270,7 +270,7 @@ void TypeTestingStubGenerator::BuildOptimizedTypeTestStubFastCases(
const Type& int_type = Type::Handle(Type::IntType());
const bool smi_is_ok =
int_type.IsSubtypeOf(NNBDMode::kLegacyLib_LegacyTest, type, Heap::kNew);
int_type.IsSubtypeOf(NNBDMode::kLegacyLib, type, Heap::kNew);
BuildOptimizedSubtypeRangeCheck(assembler, ranges, class_id_reg,
instance_reg, smi_is_ok);