mirror of
https://github.com/dart-lang/sdk
synced 2024-09-06 00:59:09 +00:00
[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:
parent
836e56b774
commit
25548a912f
|
@ -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});
|
||||
}
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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_;
|
||||
|
|
Loading…
Reference in a new issue