[vm, reload] NoSuchMethodError after a static target goes missing or changes signature.

- Mostly restores the pre-kernel behavior, except that actual arguments are not passed to the NoSuchMethodError.
 - Instead of a vague error message, the call site whose target is missing is now part of the stack trace and the name/kind of the missing target is part of the exception message.
 - If the missing target is on a branch not taken, things properly succeed.

TEST=ci
Bug: https://github.com/dart-lang/sdk/issues/37517
Bug: https://github.com/flutter/flutter/issues/122626
Change-Id: Ic3d5a386caa8d1627d8452a5601bc728ad519987
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/291055
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Ryan Macnak 2023-03-30 19:27:17 +00:00 committed by Commit Queue
parent 836e56b774
commit 25548a912f
12 changed files with 1228 additions and 151 deletions

View file

@ -7,5 +7,5 @@ part of models;
abstract class IsolateRepository {
Iterable<Service> get reloadSourcesServices;
Future<Isolate> get(IsolateRef isolate);
Future reloadSources(IsolateRef isolate, {Service service});
Future reloadSources(IsolateRef isolate, {Service? service});
}

View file

@ -370,13 +370,6 @@ void Expect::Null(const T p) {
dart::Expect(__FILE__, __LINE__).Fail(format, ##__VA_ARGS__);
#endif
// Leaving old non-varargs versions to avoid having to rewrite all uses.
#define FAIL1(format, p1) dart::Expect(__FILE__, __LINE__).Fail(format, (p1))
#define FAIL2(format, p1, p2) \
dart::Expect(__FILE__, __LINE__).Fail(format, (p1), (p2))
#endif // defined(TESTING)
#endif // RUNTIME_PLATFORM_ASSERT_H_

View file

@ -48,9 +48,9 @@ VM_UNIT_TEST_CASE(Fail0) {
}
VM_UNIT_TEST_CASE(Fail1) {
FAIL1("This test fails with one argument: %d", 4);
FAIL("This test fails with one argument: %d", 4);
}
VM_UNIT_TEST_CASE(Fail2) {
FAIL2("This test fails with two arguments: %d, %d", -100, 42);
FAIL("This test fails with two arguments: %d, %d", -100, 42);
}

View file

@ -679,8 +679,9 @@ Fragment StreamingFlowGraphBuilder::BuildFunctionBody(
if (dart_function.is_native()) {
body += B->NativeFunctionBody(dart_function, first_parameter);
} else if (dart_function.is_external()) {
body +=
ThrowNoSuchMethodError(dart_function, /*incompatible_arguments=*/false);
body += ThrowNoSuchMethodError(TokenPosition::kNoSource, dart_function,
/*incompatible_arguments=*/false);
body += ThrowException(TokenPosition::kNoSource); // Close graph.
} else if (has_body) {
body += BuildStatement();
}
@ -1503,9 +1504,10 @@ Fragment StreamingFlowGraphBuilder::RethrowException(TokenPosition position,
}
Fragment StreamingFlowGraphBuilder::ThrowNoSuchMethodError(
TokenPosition position,
const Function& target,
bool incompatible_arguments) {
return flow_graph_builder_->ThrowNoSuchMethodError(target,
return flow_graph_builder_->ThrowNoSuchMethodError(position, target,
incompatible_arguments);
}
@ -1538,9 +1540,11 @@ Fragment StreamingFlowGraphBuilder::StaticCall(TokenPosition position,
intptr_t argument_count,
ICData::RebindRule rebind_rule) {
if (!target.AreValidArgumentCounts(0, argument_count, 0, nullptr)) {
return flow_graph_builder_->ThrowNoSuchMethodError(
target,
/*incompatible_arguments=*/true);
Fragment instructions;
instructions += DropArguments(argument_count, /*type_args_count=*/0);
instructions += ThrowNoSuchMethodError(position, target,
/*incompatible_arguments=*/true);
return instructions;
}
return flow_graph_builder_->StaticCall(position, target, argument_count,
rebind_rule);
@ -1557,15 +1561,30 @@ Fragment StreamingFlowGraphBuilder::StaticCall(
bool use_unchecked_entry) {
if (!target.AreValidArguments(type_args_count, argument_count, argument_names,
nullptr)) {
return flow_graph_builder_->ThrowNoSuchMethodError(
target,
/*incompatible_arguments=*/true);
Fragment instructions;
instructions += DropArguments(argument_count, type_args_count);
instructions += ThrowNoSuchMethodError(position, target,
/*incompatible_arguments=*/true);
return instructions;
}
return flow_graph_builder_->StaticCall(
position, target, argument_count, argument_names, rebind_rule,
result_type, type_args_count, use_unchecked_entry);
}
Fragment StreamingFlowGraphBuilder::StaticCallMissing(
TokenPosition position,
const String& selector,
intptr_t argument_count,
InvocationMirror::Level level,
InvocationMirror::Kind kind) {
Fragment instructions;
instructions += DropArguments(argument_count, /*type_args_count=*/0);
instructions += flow_graph_builder_->ThrowNoSuchMethodError(
position, selector, level, kind);
return instructions;
}
Fragment StreamingFlowGraphBuilder::InstanceCall(
TokenPosition position,
const String& name,
@ -1795,6 +1814,18 @@ Fragment StreamingFlowGraphBuilder::Drop() {
return flow_graph_builder_->Drop();
}
Fragment StreamingFlowGraphBuilder::DropArguments(intptr_t argument_count,
intptr_t type_args_count) {
Fragment instructions;
for (intptr_t i = 0; i < argument_count; i++) {
instructions += Drop();
}
if (type_args_count != 0) {
instructions += Drop();
}
return instructions;
}
Fragment StreamingFlowGraphBuilder::DropTempsPreserveTop(
intptr_t num_temps_to_drop) {
return flow_graph_builder_->DropTempsPreserveTop(num_temps_to_drop);
@ -2721,10 +2752,11 @@ Fragment StreamingFlowGraphBuilder::BuildStaticGet(TokenPosition* p) {
return LoadStaticField(field, /*calls_initializer=*/false);
}
}
} else {
const Function& function =
Function::ZoneHandle(Z, H.LookupStaticMethodByKernelProcedure(target));
}
const Function& function = Function::ZoneHandle(
Z, H.LookupStaticMethodByKernelProcedure(target, /*required=*/false));
if (!function.IsNull()) {
if (H.IsGetter(target)) {
return StaticCall(position, function, 0, Array::null_array(),
ICData::kStatic, &result_type);
@ -2739,7 +2771,12 @@ Fragment StreamingFlowGraphBuilder::BuildStaticGet(TokenPosition* p) {
}
}
return Fragment();
return StaticCallMissing(
position, H.DartSymbolPlain(H.CanonicalNameString(target)),
/* argument_count */ 0,
H.IsLibrary(H.EnclosingName(target)) ? InvocationMirror::Level::kTopLevel
: InvocationMirror::Level::kStatic,
InvocationMirror::Kind::kGetter);
}
Fragment StreamingFlowGraphBuilder::BuildStaticSet(TokenPosition* p) {
@ -2769,9 +2806,11 @@ Fragment StreamingFlowGraphBuilder::BuildStaticSet(TokenPosition* p) {
// Drop the unused result & leave the stored value on the stack.
return instructions + Drop();
} else {
const Field& field =
Field::ZoneHandle(Z, H.LookupFieldByKernelGetterOrSetter(target));
}
const Field& field = Field::ZoneHandle(
Z, H.LookupFieldByKernelGetterOrSetter(target, /*required=*/false));
if (!field.IsNull()) {
if (NeedsDebugStepCheck(stack(), position)) {
instructions = DebugStepCheck(position) + instructions;
}
@ -2780,6 +2819,14 @@ Fragment StreamingFlowGraphBuilder::BuildStaticSet(TokenPosition* p) {
instructions += StoreStaticField(position, field);
return instructions;
}
instructions += StaticCallMissing(
position, H.DartSymbolPlain(H.CanonicalNameString(target)),
/* argument_count */ 1,
H.IsLibrary(H.EnclosingName(target)) ? InvocationMirror::Level::kTopLevel
: InvocationMirror::Level::kStatic,
InvocationMirror::Kind::kSetter);
return instructions;
}
Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p,
@ -3284,8 +3331,26 @@ Fragment StreamingFlowGraphBuilder::BuildStaticInvocation(TokenPosition* p) {
NameIndex procedure_reference =
ReadCanonicalNameReference(); // read procedure reference.
intptr_t argument_count = PeekArgumentsCount();
const Function& target = Function::ZoneHandle(
Z, H.LookupStaticMethodByKernelProcedure(procedure_reference));
const Function& target =
Function::ZoneHandle(Z, H.LookupStaticMethodByKernelProcedure(
procedure_reference, /*required=*/false));
if (target.IsNull()) {
Fragment instructions;
Array& argument_names = Array::ZoneHandle(Z);
instructions +=
BuildArguments(&argument_names, nullptr /* arg count */,
nullptr /* positional arg count */); // read arguments.
instructions += StaticCallMissing(
position, H.DartSymbolPlain(H.CanonicalNameString(procedure_reference)),
argument_count,
H.IsLibrary(H.EnclosingName(procedure_reference))
? InvocationMirror::Level::kTopLevel
: InvocationMirror::Level::kStatic,
InvocationMirror::Kind::kMethod);
return instructions;
}
const Class& klass = Class::ZoneHandle(Z, target.Owner());
if (target.IsGenerativeConstructor() || target.IsFactory()) {
// The VM requires a TypeArguments object as first parameter for
@ -3411,12 +3476,24 @@ Fragment StreamingFlowGraphBuilder::BuildConstructorInvocation(
ReadCanonicalNameReference(); // read target_reference.
Class& klass = Class::ZoneHandle(
Z, H.LookupClassByKernelClass(H.EnclosingName(kernel_name)));
Z, H.LookupClassByKernelClass(H.EnclosingName(kernel_name),
/*required=*/false));
Fragment instructions;
if (klass.IsNull()) {
Array& argument_names = Array::ZoneHandle(Z);
intptr_t argument_count;
instructions += BuildArguments(
&argument_names, &argument_count,
/* positional_argument_count = */ nullptr); // read arguments.
instructions += StaticCallMissing(
position, H.DartSymbolPlain(H.CanonicalNameString(kernel_name)),
argument_count, InvocationMirror::Level::kConstructor,
InvocationMirror::Kind::kMethod);
return instructions;
}
const auto& error = klass.EnsureIsFinalized(H.thread());
ASSERT(error == Error::null());
Fragment instructions;
if (klass.NumTypeArguments() > 0) {
if (!klass.IsGeneric()) {
Type& type = Type::ZoneHandle(Z, T.ReceiverType(klass).ptr());
@ -3448,11 +3525,20 @@ Fragment StreamingFlowGraphBuilder::BuildConstructorInvocation(
&argument_names, &argument_count,
/* positional_argument_count = */ nullptr); // read arguments.
const Function& target = Function::ZoneHandle(
Z, H.LookupConstructorByKernelConstructor(klass, kernel_name));
const Function& target =
Function::ZoneHandle(Z, H.LookupConstructorByKernelConstructor(
klass, kernel_name, /*required=*/false));
++argument_count;
instructions += StaticCall(position, target, argument_count, argument_names,
ICData::kStatic, /* result_type = */ nullptr);
if (target.IsNull()) {
instructions += StaticCallMissing(
position, H.DartSymbolPlain(H.CanonicalNameString(kernel_name)),
argument_count, InvocationMirror::Level::kConstructor,
InvocationMirror::Kind::kMethod);
} else {
instructions += StaticCall(position, target, argument_count, argument_names,
ICData::kStatic, /* result_type = */ nullptr);
}
return instructions + Drop();
}

View file

@ -155,7 +155,8 @@ class StreamingFlowGraphBuilder : public KernelReaderHelper {
Fragment Return(TokenPosition position);
Fragment EvaluateAssertion();
Fragment RethrowException(TokenPosition position, int catch_try_index);
Fragment ThrowNoSuchMethodError(const Function& target,
Fragment ThrowNoSuchMethodError(TokenPosition position,
const Function& target,
bool incompatible_arguments);
Fragment Constant(const Object& value);
Fragment IntConstant(int64_t value);
@ -176,6 +177,11 @@ class StreamingFlowGraphBuilder : public KernelReaderHelper {
const InferredTypeMetadata* result_type = nullptr,
intptr_t type_args_len = 0,
bool use_unchecked_entry = false);
Fragment StaticCallMissing(TokenPosition position,
const String& selector,
intptr_t argument_count,
InvocationMirror::Level level,
InvocationMirror::Kind kind);
Fragment InstanceCall(TokenPosition position,
const String& name,
Token::Kind kind,
@ -238,6 +244,7 @@ class StreamingFlowGraphBuilder : public KernelReaderHelper {
bool is_synthesized);
Fragment TryCatch(int try_handler_index);
Fragment Drop();
Fragment DropArguments(intptr_t argument_count, intptr_t type_args_count);
// Drop given number of temps from the stack but preserve top of the stack.
Fragment DropTempsPreserveTop(intptr_t num_temps_to_drop);

View file

@ -714,19 +714,10 @@ Fragment FlowGraphBuilder::ThrowTypeError() {
return instructions;
}
Fragment FlowGraphBuilder::ThrowNoSuchMethodError(const Function& target,
bool incompatible_arguments) {
const Class& klass = Class::ZoneHandle(
Z, Library::LookupCoreClass(Symbols::NoSuchMethodError()));
ASSERT(!klass.IsNull());
const auto& error = klass.EnsureIsFinalized(H.thread());
ASSERT(error == Error::null());
const Function& throw_function = Function::ZoneHandle(
Z, klass.LookupStaticFunctionAllowPrivate(Symbols::ThrowNew()));
ASSERT(!throw_function.IsNull());
Fragment instructions;
Fragment FlowGraphBuilder::ThrowNoSuchMethodError(TokenPosition position,
const Function& target,
bool incompatible_arguments,
bool receiver_pushed) {
const Class& owner = Class::Handle(Z, target.Owner());
auto& receiver = Instance::ZoneHandle();
InvocationMirror::Kind kind = InvocationMirror::Kind::kMethod;
@ -753,24 +744,42 @@ Fragment FlowGraphBuilder::ThrowNoSuchMethodError(const Function& target,
}
}
// Call NoSuchMethodError._throwNew static function.
if (!target.IsRecordFieldGetter()) {
Fragment instructions;
if (!receiver_pushed) {
instructions += Constant(receiver); // receiver
}
instructions += Constant(String::ZoneHandle(Z, target.name())); // memberName
instructions +=
ThrowNoSuchMethodError(position, String::ZoneHandle(Z, target.name()),
level, kind, /*receiver_pushed*/ true);
return instructions;
}
Fragment FlowGraphBuilder::ThrowNoSuchMethodError(TokenPosition position,
const String& selector,
InvocationMirror::Level level,
InvocationMirror::Kind kind,
bool receiver_pushed) {
const Class& klass = Class::ZoneHandle(
Z, Library::LookupCoreClass(Symbols::NoSuchMethodError()));
ASSERT(!klass.IsNull());
const auto& error = klass.EnsureIsFinalized(H.thread());
ASSERT(error == Error::null());
const Function& throw_function = Function::ZoneHandle(
Z, klass.LookupStaticFunctionAllowPrivate(Symbols::ThrowNew()));
ASSERT(!throw_function.IsNull());
Fragment instructions;
if (!receiver_pushed) {
instructions += NullConstant(); // receiver
}
instructions += Constant(selector);
instructions += IntConstant(InvocationMirror::EncodeType(level, kind));
instructions += IntConstant(0); // type arguments length
instructions += NullConstant(); // type arguments
instructions += NullConstant(); // arguments
instructions += NullConstant(); // argumentNames
instructions += StaticCall(TokenPosition::kNoSource, throw_function,
/* argument_count = */ 7, ICData::kStatic);
// Properly close graph with a ThrowInstr, although it is not executed.
instructions += ThrowException(TokenPosition::kNoSource);
instructions += Drop();
instructions += StaticCall(position, throw_function, /* argument_count = */ 7,
ICData::kNoRebind);
return instructions;
}
@ -2373,8 +2382,10 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfRecordFieldGetter(
Fragment throw_nsm(nsm);
throw_nsm += LoadLocal(parsed_function_->receiver_var());
throw_nsm +=
ThrowNoSuchMethodError(function, /*incompatible_arguments=*/false);
throw_nsm += ThrowNoSuchMethodError(TokenPosition::kNoSource, function,
/*incompatible_arguments=*/false,
/*receiver_pushed=*/true);
throw_nsm += ThrowException(TokenPosition::kNoSource); // Close graph.
// There is no prologue code for a record field getter.
PrologueInfo prologue_info(-1, -1);

View file

@ -223,8 +223,15 @@ class FlowGraphBuilder : public BaseFlowGraphBuilder {
// [incompatible_arguments] should be true if the NSM is due to a mismatch
// between the provided arguments and the function signature.
Fragment ThrowNoSuchMethodError(const Function& target,
bool incompatible_arguments);
Fragment ThrowNoSuchMethodError(TokenPosition position,
const Function& target,
bool incompatible_arguments,
bool receiver_pushed = false);
Fragment ThrowNoSuchMethodError(TokenPosition position,
const String& selector,
InvocationMirror::Level level,
InvocationMirror::Kind kind,
bool receiver_pushed = false);
Fragment ThrowLateInitializationError(TokenPosition position,
const char* throw_method_name,
const String& name);

View file

@ -496,22 +496,27 @@ const String& TranslationHelper::DartFactoryName(NameIndex factory) {
return String::ZoneHandle(Z, Symbols::FromConcatAll(thread_, pieces));
}
// TODO(https://github.com/dart-lang/sdk/issues/37517): Should emit code to
// throw a NoSuchMethodError.
static void CheckStaticLookup(const Object& target) {
if (target.IsNull()) {
#ifndef PRODUCT
ASSERT(IsolateGroup::Current()->HasAttemptedReload());
Report::LongJump(LanguageError::Handle(LanguageError::New(String::Handle(
String::New("Unimplemented handling of missing static target")))));
#else
UNREACHABLE();
#endif
void TranslationHelper::LookupFailed(NameIndex name) {
String& message = String::Handle(String::New("Lookup failed: "));
message = String::Concat(message, DartString(CanonicalNameString(name)));
name = CanonicalNameParent(name);
while (!IsRoot(name)) {
message = String::Concat(message, String::Handle(String::New(" in ")));
message = String::Concat(message, DartString(CanonicalNameString(name)));
name = CanonicalNameParent(name);
}
Report::LongJump(LanguageError::Handle(LanguageError::New(message)));
}
void TranslationHelper::LookupFailed(StringIndex name) {
const String& message = String::Handle(String::Concat(
String::Handle(String::New("Lookup failed: ")), DartString(name)));
Report::LongJump(LanguageError::Handle(LanguageError::New(message)));
}
LibraryPtr TranslationHelper::LookupLibraryByKernelLibrary(
NameIndex kernel_library) {
NameIndex kernel_library,
bool required) {
// We only use the string and don't rely on having any particular parent.
// This ASSERT is just a sanity check.
ASSERT(IsLibrary(kernel_library) ||
@ -530,12 +535,18 @@ LibraryPtr TranslationHelper::LookupLibraryByKernelLibrary(
ASSERT(!library_name.IsNull());
const Library& library =
Library::Handle(Z, Library::LookupLibrary(thread_, library_name));
CheckStaticLookup(library);
if (library.IsNull()) {
if (required) {
LookupFailed(kernel_library);
}
return Library::null();
}
name_index_handle_ = Smi::New(kernel_library);
return info_.InsertLibrary(thread_, name_index_handle_, library);
}
ClassPtr TranslationHelper::LookupClassByKernelClass(NameIndex kernel_class) {
ClassPtr TranslationHelper::LookupClassByKernelClass(NameIndex kernel_class,
bool required) {
ASSERT(IsClass(kernel_class));
{
name_index_handle_ = Smi::New(kernel_class);
@ -548,35 +559,58 @@ ClassPtr TranslationHelper::LookupClassByKernelClass(NameIndex kernel_class) {
const String& class_name = DartClassName(kernel_class);
NameIndex kernel_library = CanonicalNameParent(kernel_class);
Library& library =
Library::Handle(Z, LookupLibraryByKernelLibrary(kernel_library));
ASSERT(!library.IsNull());
Library& library = Library::Handle(
Z, LookupLibraryByKernelLibrary(kernel_library, /*required=*/false));
if (library.IsNull()) {
if (required) {
LookupFailed(kernel_class);
}
return Class::null();
}
const Class& klass =
Class::Handle(Z, library.LookupClassAllowPrivate(class_name));
CheckStaticLookup(klass);
ASSERT(!klass.IsNull());
if (klass.IsNull()) {
if (required) {
LookupFailed(kernel_class);
}
return Class::null();
}
name_index_handle_ = Smi::New(kernel_class);
return info_.InsertClass(thread_, name_index_handle_, klass);
}
FieldPtr TranslationHelper::LookupFieldByKernelField(NameIndex kernel_field) {
FieldPtr TranslationHelper::LookupFieldByKernelField(NameIndex kernel_field,
bool required) {
ASSERT(IsField(kernel_field));
NameIndex enclosing = EnclosingName(kernel_field);
Class& klass = Class::Handle(Z);
if (IsLibrary(enclosing)) {
Library& library =
Library::Handle(Z, LookupLibraryByKernelLibrary(enclosing));
Library& library = Library::Handle(
Z, LookupLibraryByKernelLibrary(enclosing, /*required=*/false));
if (library.IsNull()) {
if (required) {
LookupFailed(kernel_field);
}
return Field::null();
}
klass = library.toplevel_class();
CheckStaticLookup(klass);
} else {
ASSERT(IsClass(enclosing));
klass = LookupClassByKernelClass(enclosing);
klass = LookupClassByKernelClass(enclosing, /*required=*/false);
if (klass.IsNull()) {
if (required) {
LookupFailed(kernel_field);
}
return Field::null();
}
}
Field& field = Field::Handle(
Z, klass.LookupFieldAllowPrivate(
DartSymbolObfuscate(CanonicalNameString(kernel_field))));
CheckStaticLookup(field);
if (field.IsNull() && required) {
LookupFailed(kernel_field);
}
return field.ptr();
}
@ -588,19 +622,30 @@ FieldPtr TranslationHelper::LookupFieldByKernelGetterOrSetter(
Class& klass = Class::Handle(Z);
if (IsLibrary(enclosing)) {
Library& library =
Library::Handle(Z, LookupLibraryByKernelLibrary(enclosing));
Library& library = Library::Handle(
Z, LookupLibraryByKernelLibrary(enclosing, /*required=*/false));
if (library.IsNull()) {
if (required) {
LookupFailed(kernel_field);
}
return Field::null();
}
klass = library.toplevel_class();
CheckStaticLookup(klass);
} else {
ASSERT(IsClass(enclosing));
klass = LookupClassByKernelClass(enclosing);
klass = LookupClassByKernelClass(enclosing, /*required=*/false);
if (klass.IsNull()) {
if (required) {
LookupFailed(kernel_field);
}
return Field::null();
}
}
Field& field = Field::Handle(
Z, klass.LookupFieldAllowPrivate(
DartSymbolObfuscate(CanonicalNameString(kernel_field))));
if (required) {
CheckStaticLookup(field);
if (field.IsNull() && required) {
LookupFailed(kernel_field);
}
return field.ptr();
}
@ -613,53 +658,66 @@ FunctionPtr TranslationHelper::LookupStaticMethodByKernelProcedure(
// The parent is either a library or a class (in which case the procedure is a
// static method).
NameIndex enclosing = EnclosingName(procedure);
Function& function = Function::Handle(Z);
if (IsLibrary(enclosing)) {
Library& library =
Library::Handle(Z, LookupLibraryByKernelLibrary(enclosing));
Function& function =
Function::Handle(Z, library.LookupFunctionAllowPrivate(procedure_name));
if (required) {
CheckStaticLookup(function);
Library& library = Library::Handle(
Z, LookupLibraryByKernelLibrary(enclosing, /*required=*/false));
if (!library.IsNull()) {
function = library.LookupFunctionAllowPrivate(procedure_name);
}
return function.ptr();
} else {
ASSERT(IsClass(enclosing));
Class& klass = Class::Handle(Z, LookupClassByKernelClass(enclosing));
const auto& error = klass.EnsureIsFinalized(thread_);
ASSERT(error == Error::null());
Function& function = Function::ZoneHandle(
Z, klass.LookupFunctionAllowPrivate(procedure_name));
if (required) {
CheckStaticLookup(function);
Class& klass = Class::Handle(
Z, LookupClassByKernelClass(enclosing, /*required=*/false));
if (!klass.IsNull()) {
const auto& error = klass.EnsureIsFinalized(thread_);
ASSERT(error == Error::null());
function = klass.LookupFunctionAllowPrivate(procedure_name);
}
return function.ptr();
}
if (function.IsNull() && required) {
LookupFailed(procedure);
}
return function.ptr();
}
FunctionPtr TranslationHelper::LookupConstructorByKernelConstructor(
NameIndex constructor) {
NameIndex constructor,
bool required) {
ASSERT(IsConstructor(constructor));
Class& klass =
Class::Handle(Z, LookupClassByKernelClass(EnclosingName(constructor)));
CheckStaticLookup(klass);
return LookupConstructorByKernelConstructor(klass, constructor);
}
FunctionPtr TranslationHelper::LookupConstructorByKernelConstructor(
const Class& owner,
NameIndex constructor) {
ASSERT(IsConstructor(constructor));
const auto& error = owner.EnsureIsFinalized(thread_);
ASSERT(error == Error::null());
Function& function = Function::Handle(
Z, owner.LookupConstructorAllowPrivate(DartConstructorName(constructor)));
CheckStaticLookup(function);
Class& klass = Class::Handle(
Z,
LookupClassByKernelClass(EnclosingName(constructor), /*required=*/false));
Function& function = Function::Handle(Z);
if (!klass.IsNull()) {
function = LookupConstructorByKernelConstructor(klass, constructor,
/*required=*/false);
}
if (function.IsNull() && required) {
LookupFailed(constructor);
}
return function.ptr();
}
FunctionPtr TranslationHelper::LookupConstructorByKernelConstructor(
const Class& owner,
StringIndex constructor_name) {
NameIndex constructor,
bool required) {
ASSERT(IsConstructor(constructor));
const auto& error = owner.EnsureIsFinalized(thread_);
ASSERT(error == Error::null());
Function& function = Function::Handle(
Z, owner.LookupConstructorAllowPrivate(DartConstructorName(constructor)));
if (function.IsNull() && required) {
LookupFailed(constructor);
}
return function.ptr();
}
FunctionPtr TranslationHelper::LookupConstructorByKernelConstructor(
const Class& owner,
StringIndex constructor_name,
bool required) {
GrowableHandlePtrArray<const String> pieces(Z, 3);
pieces.Add(String::Handle(Z, owner.Name()));
pieces.Add(Symbols::Dot());
@ -671,26 +729,25 @@ FunctionPtr TranslationHelper::LookupConstructorByKernelConstructor(
const auto& error = owner.EnsureIsFinalized(thread_);
ASSERT(error == Error::null());
FunctionPtr function = owner.LookupConstructorAllowPrivate(new_name);
ASSERT(function != Object::null());
if (function == Object::null() && required) {
LookupFailed(constructor_name);
}
return function;
}
FunctionPtr TranslationHelper::LookupMethodByMember(NameIndex target,
const String& method_name) {
const String& method_name,
bool required) {
NameIndex kernel_class = EnclosingName(target);
Class& klass = Class::Handle(Z, LookupClassByKernelClass(kernel_class));
Class& klass = Class::Handle(
Z, LookupClassByKernelClass(kernel_class, /*required=*/false));
Function& function = Function::Handle(Z);
if (klass.EnsureIsFinalized(thread_) == Error::null()) {
if (!klass.IsNull() && klass.EnsureIsFinalized(thread_) == Error::null()) {
function = klass.LookupFunctionAllowPrivate(method_name);
}
#ifdef DEBUG
if (function.IsNull()) {
THR_Print("Unable to find \'%s\' in %s\n", method_name.ToCString(),
klass.ToCString());
if (function.IsNull() && required) {
LookupFailed(target);
}
#endif
CheckStaticLookup(function);
ASSERT(!function.IsNull());
return function.ptr();
}

View file

@ -153,24 +153,33 @@ class TranslationHelper {
const String& DartFactoryName(NameIndex factory);
DART_NORETURN void LookupFailed(NameIndex name);
DART_NORETURN void LookupFailed(StringIndex name);
// A subclass overrides these when reading in the Kernel program in order to
// support recursive type expressions (e.g. for "implements X" ...
// annotations).
virtual LibraryPtr LookupLibraryByKernelLibrary(NameIndex library);
virtual ClassPtr LookupClassByKernelClass(NameIndex klass);
virtual LibraryPtr LookupLibraryByKernelLibrary(NameIndex library,
bool required = true);
virtual ClassPtr LookupClassByKernelClass(NameIndex klass,
bool required = true);
FieldPtr LookupFieldByKernelField(NameIndex field);
FieldPtr LookupFieldByKernelField(NameIndex field, bool required = true);
FieldPtr LookupFieldByKernelGetterOrSetter(NameIndex field,
bool required = true);
FunctionPtr LookupStaticMethodByKernelProcedure(NameIndex procedure,
bool required = true);
FunctionPtr LookupConstructorByKernelConstructor(NameIndex constructor);
FunctionPtr LookupConstructorByKernelConstructor(NameIndex constructor,
bool required = true);
FunctionPtr LookupConstructorByKernelConstructor(const Class& owner,
NameIndex constructor);
FunctionPtr LookupConstructorByKernelConstructor(
const Class& owner,
StringIndex constructor_name);
FunctionPtr LookupMethodByMember(NameIndex target, const String& method_name);
NameIndex constructor,
bool required = true);
FunctionPtr LookupConstructorByKernelConstructor(const Class& owner,
StringIndex constructor_name,
bool required = true);
FunctionPtr LookupMethodByMember(NameIndex target,
const String& method_name,
bool required = true);
FunctionPtr LookupDynamicFunction(const Class& klass, const String& name);
Type& GetDeclarationType(const Class& klass);

View file

@ -2437,6 +2437,909 @@ TEST_CASE(IsolateReload_ConstantIdentical) {
EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_CallDeleted_TopLevelFunction) {
const char* kScript =
"deleted() { return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" retained = () => deleted();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_TopLevelFunctionArityChange) {
const char* kScript =
"deleted() { return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" retained = () => deleted();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"deleted(newParameter) { return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_TopLevelAddTypeArguments) {
const char* kScript =
"deleted() { return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" retained = () => deleted();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"deleted<A, B, C>() { return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_CallDeleted_TopLevelRemoveTypeArguments) {
const char* kScript =
"deleted<A, B, C>() { return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" retained = () => deleted<int, int, int>();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"deleted() { return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_TopLevelMissingPassingTypeArguments) {
const char* kScript =
"deleted<A, B, C>() { return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" retained = () => deleted<int, int, int>();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_TopLevelFunctionEvaluationOrder) {
const char* kScript =
"first(flag) { if (flag) throw 'first!'; }\n"
"deleted(_) { return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" retained = (bool flag) => deleted(first(flag));\n"
" return retained(false);\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"first(flag) { if (flag) throw 'first!'; }\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained(true);\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_STREQ("first!", result); // Not NoSuchMethodError
}
TEST_CASE(IsolateReload_CallDeleted_TopLevelFunctionLibraryDeleted) {
// clang-format off
Dart_SourceFile sourcefiles[] = {
{
"file:///test-app.dart",
"import 'test-lib.dart';\n"
"var retained;\n"
"main() {\n"
" retained = () => deleted();\n"
" return retained();\n"
"}\n",
},
{
"file:///test-lib.dart",
"deleted() { return 'hello'; }\n",
},
};
// clang-format on
Dart_Handle lib = TestCase::LoadTestScriptWithDFE(
sizeof(sourcefiles) / sizeof(Dart_SourceFile), sourcefiles,
NULL /* resolver */, true /* finalize */, true /* incrementally */);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
// clang-format off
Dart_SourceFile updated_sourcefiles[] = {
{
"file:///test-app.dart",
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n",
},
};
// clang-format on
const uint8_t* kernel_buffer = NULL;
intptr_t kernel_buffer_size = 0;
char* error = TestCase::CompileTestScriptWithDFE(
"file:///test-app.dart",
sizeof(updated_sourcefiles) / sizeof(Dart_SourceFile),
updated_sourcefiles, &kernel_buffer, &kernel_buffer_size,
true /* incrementally */);
EXPECT(error == NULL);
EXPECT_NOTNULL(kernel_buffer);
lib = TestCase::ReloadTestKernel(kernel_buffer, kernel_buffer_size);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
// What actually happens because we don't re-search imported libraries.
EXPECT_STREQ(result, "hello");
// What should happen and what did happen with the old VM frontend:
// EXPECT_SUBSTRING("NoSuchMethodError", result);
// EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_TopLevelGetter) {
const char* kScript =
"get deleted { return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" retained = () => deleted;\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_TopLevelSetter) {
const char* kScript =
"set deleted(x) {}\n"
"var retained;\n"
"main() {\n"
" retained = () => deleted = 'hello';\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_TopLevelSetterEvaluationOrder) {
const char* kScript =
"first(flag) { if (flag) throw 'first!'; return 'hello'; }\n"
"set deleted(x) {}\n"
"var retained;\n"
"main() {\n"
" retained = (bool flag) => deleted = first(flag);\n"
" return retained(false);\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"first(flag) { if (flag) throw 'first!'; return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained(true);\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_STREQ("first!", result); // Not NoSuchMethodError
}
TEST_CASE(IsolateReload_CallDeleted_ClassFunction) {
const char* kScript =
"class C { static deleted() { return 'hello'; } }\n"
"var retained;\n"
"main() {\n"
" retained = () => C.deleted();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_ClassFunctionArityChange) {
const char* kScript =
"class C { static deleted() { return 'hello'; } }\n"
"var retained;\n"
"main() {\n"
" retained = () => C.deleted();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class C { static deleted(newParameter) { return 'hello'; } }\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_ClassFunctionEvaluationOrder) {
const char* kScript =
"first(flag) { if (flag) throw 'first!'; }\n"
"class C { static deleted(_) { return 'hello'; } }\n"
"var retained;\n"
"main() {\n"
" retained = (bool flag) => C.deleted(first(flag));\n"
" return retained(false);\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"first(flag) { if (flag) throw 'first!'; }\n"
"class C { }\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained(true);\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_STREQ("first!", result); // Not NoSuchMethodError
}
TEST_CASE(IsolateReload_CallDeleted_ClassGetter) {
const char* kScript =
"class C { static get deleted { return 'hello'; } }\n"
"var retained;\n"
"main() {\n"
" retained = () => C.deleted;\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_ClassSetter) {
const char* kScript =
"class C { static set deleted(x) {}}\n"
"var retained;\n"
"main() {\n"
" retained = () => C.deleted = 'hello';\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_ClassSetterEvaluationOrder) {
const char* kScript =
"first(flag) { if (flag) throw 'first!'; return 'hello'; }\n"
"class C { static set deleted(x) {}}\n"
"var retained;\n"
"main() {\n"
" retained = (bool flag) => C.deleted = first(flag);\n"
" return retained(false);\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"first(flag) { if (flag) throw 'first!'; return 'hello'; }\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained(true);\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_STREQ("first!", result);
}
TEST_CASE(IsolateReload_CallDeleted_ClassGenerativeConstructor) {
const char* kScript =
"class C { C.deleted(); }\n"
"var retained;\n"
"main() {\n"
" retained = () => C.deleted().toString();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("Instance of \'C\'", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class C {}\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_ClassGenerativeConstructorArityChange) {
const char* kScript =
"class C { C.deleted(); }\n"
"var retained;\n"
"main() {\n"
" retained = () => C.deleted().toString();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("Instance of \'C\'", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class C { C.deleted(newParameter); }\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_ClassGenerativeConstructorClassDeleted) {
const char* kScript =
"class C { C.deleted(); }\n"
"var retained;\n"
"main() {\n"
" retained = () => C.deleted().toString();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("Instance of \'C\'", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_ClassFactoryConstructor) {
const char* kScript =
"class C { factory C.deleted() => new C(); C(); }\n"
"var retained;\n"
"main() {\n"
" retained = () => C.deleted().toString();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("Instance of \'C\'", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class C {}\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_ClassFactoryConstructorArityChange) {
const char* kScript =
"class C { factory C.deleted() => new C(); C(); }\n"
"var retained;\n"
"main() {\n"
" retained = () => C.deleted().toString();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("Instance of \'C\'", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class C { factory C.deleted(newParameter) => new C(); C(); }\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_ClassFactoryConstructorClassDeleted) {
const char* kScript =
"class C { factory C.deleted() => new C(); C(); }\n"
"var retained;\n"
"main() {\n"
" retained = () => C.deleted().toString();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("Instance of \'C\'", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_SuperFunction) {
const char* kScript =
"class C { deleted() { return 'hello'; } }\n"
"class D extends C { curry() => () => super.deleted(); }\n"
"var retained;\n"
"main() {\n"
" retained = new D().curry();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class C {}\n"
"class D extends C {}\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_SuperFunctionArityChange) {
const char* kScript =
"class C { deleted() { return 'hello'; } }\n"
"class D extends C { curry() => () => super.deleted(); }\n"
"var retained;\n"
"main() {\n"
" retained = new D().curry();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class C { deleted(newParameter) { return 'hello'; } }\n"
"class D extends C {}\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_SuperGetter) {
const char* kScript =
"class C { get deleted { return 'hello'; } }\n"
"class D extends C { curry() => () => super.deleted; }\n"
"var retained;\n"
"main() {\n"
" retained = new D().curry();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class C {}\n"
"class D extends C {}\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_SuperSetter) {
const char* kScript =
"class C { set deleted(x) {} }\n"
"class D extends C { curry() => () => super.deleted = 'hello'; }\n"
"var retained;\n"
"main() {\n"
" retained = new D().curry();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class C {}\n"
"class D extends C {}\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_SuperFieldGetter) {
const char* kScript =
"class C { var deleted = 'hello'; }\n"
"class D extends C { curry() => () => super.deleted; }\n"
"var retained;\n"
"main() {\n"
" retained = new D().curry();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class C {}\n"
"class D extends C {}\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_CallDeleted_SuperFieldSetter) {
const char* kScript =
"class C { var deleted; }\n"
"class D extends C { curry() => () => super.deleted = 'hello'; }\n"
"var retained;\n"
"main() {\n"
" retained = new D().curry();\n"
" return retained();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class C {}\n"
"class D extends C {}\n"
"var retained;\n"
"main() {\n"
" try {\n"
" return retained();\n"
" } catch (e) {\n"
" return e.toString();\n"
" }\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
const char* result = SimpleInvokeStr(lib, "main");
EXPECT_SUBSTRING("NoSuchMethodError", result);
EXPECT_SUBSTRING("deleted", result);
}
TEST_CASE(IsolateReload_EnumValuesToString) {
const char* kScript =
"enum Fruit {\n"

View file

@ -135,11 +135,13 @@ ArrayPtr KernelLoader::MakeFunctionsArray() {
}
LibraryPtr BuildingTranslationHelper::LookupLibraryByKernelLibrary(
NameIndex library) {
NameIndex library,
bool required) {
return loader_->LookupLibrary(library);
}
ClassPtr BuildingTranslationHelper::LookupClassByKernelClass(NameIndex klass) {
ClassPtr BuildingTranslationHelper::LookupClassByKernelClass(NameIndex klass,
bool required) {
#if defined(DEBUG)
LibraryLookupHandleScope library_lookup_handle_scope(library_lookup_handle_);
#endif // defined(DEBUG)

View file

@ -30,8 +30,10 @@ class BuildingTranslationHelper : public TranslationHelper {
library_lookup_handle_(Library::Handle(thread->zone())) {}
virtual ~BuildingTranslationHelper() {}
virtual LibraryPtr LookupLibraryByKernelLibrary(NameIndex library);
virtual ClassPtr LookupClassByKernelClass(NameIndex klass);
virtual LibraryPtr LookupLibraryByKernelLibrary(NameIndex library,
bool required = true);
virtual ClassPtr LookupClassByKernelClass(NameIndex klass,
bool required = true);
private:
KernelLoader* loader_;