From eae248cc4195ea306c74569b8fecc49b839f5f8f Mon Sep 17 00:00:00 2001 From: Regis Crelier Date: Fri, 8 May 2020 18:08:26 +0000 Subject: [PATCH] [VM/compiler] Emit a throw NoSuchMethodError for bad arity rather than aborting compilation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bad arity maybe detected after an isolate reload or when using strong mode with a mix of opted in and opted out libraries. The thrown NoSuchMethodError contains enough information to be useful, but does not mirror the complete invocation (e.g. arguments). This CL does not fix https://github.com/dart-lang/sdk/issues/37517 where the target is missing after a reload (not just bad arity). The VM implementation of NoSuchMethodError is cleaned up, but the deprecated constructor 'NoSuchMethodError(...)' is not yet removed, since it is still documented. Change-Id: I0306971c59cb510d21cb1b1acc3545c8817dfea7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/146986 Reviewed-by: Alexander Markov Reviewed-by: Ryan Macnak Commit-Queue: Régis Crelier --- runtime/lib/mirrors.cc | 10 +- .../frontend/kernel_binary_flowgraph.cc | 34 +-- .../frontend/kernel_binary_flowgraph.h | 2 +- runtime/vm/compiler/frontend/kernel_to_il.cc | 44 ++-- runtime/vm/compiler/frontend/kernel_to_il.h | 2 +- runtime/vm/isolate_reload_test.cc | 4 +- runtime/vm/object.cc | 10 +- runtime/vm/runtime_entry.cc | 9 +- sdk/lib/_internal/vm/lib/errors_patch.dart | 215 ++-------------- .../vm/lib/invocation_mirror_patch.dart | 19 +- .../lib/_internal/vm/lib/errors_patch.dart | 235 +++--------------- 11 files changed, 129 insertions(+), 455 deletions(-) diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc index b8a123eb9a7..9f2dfe5433c 100644 --- a/runtime/lib/mirrors.cc +++ b/runtime/lib/mirrors.cc @@ -54,14 +54,14 @@ static void ThrowNoSuchMethod(const Instance& receiver, const Smi& invocation_type = Smi::Handle(Smi::New(InvocationMirror::EncodeType(level, kind))); - const Array& args = Array::Handle(Array::New(6)); + const Array& args = Array::Handle(Array::New(7)); args.SetAt(0, receiver); args.SetAt(1, function_name); args.SetAt(2, invocation_type); - // TODO(regis): Support invocation of generic functions with type arguments. - args.SetAt(3, Object::null_type_arguments()); - args.SetAt(4, arguments); - args.SetAt(5, argument_names); + args.SetAt(3, Object::smi_zero()); // Type arguments length. + args.SetAt(4, Object::null_type_arguments()); + args.SetAt(5, arguments); + args.SetAt(6, argument_names); const Library& libcore = Library::Handle(Library::CoreLibrary()); const Class& NoSuchMethodError = diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc index 0ea4e895c80..121aff8107e 100644 --- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc +++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc @@ -1685,8 +1685,9 @@ Fragment StreamingFlowGraphBuilder::RethrowException(TokenPosition position, return flow_graph_builder_->RethrowException(position, catch_try_index); } -Fragment StreamingFlowGraphBuilder::ThrowNoSuchMethodError() { - return flow_graph_builder_->ThrowNoSuchMethodError(); +Fragment StreamingFlowGraphBuilder::ThrowNoSuchMethodError( + const Function& target) { + return flow_graph_builder_->ThrowNoSuchMethodError(target); } Fragment StreamingFlowGraphBuilder::Constant(const Object& value) { @@ -1715,32 +1716,12 @@ Fragment StreamingFlowGraphBuilder::CheckNull( clear_the_temp); } -static void BadArity(const Script& script, - TokenPosition position, - const String& error_message) { -#ifndef PRODUCT - // TODO(https://github.com/dart-lang/sdk/issues/37517): Should emit code to - // throw a NoSuchMethodError. - // Correct arity is checked at compile time by CFE. However, an isolate reload - // after an arity change may lead here. - // Using strong mode with a mix of opted in and opted out libraries may - // also result in this error undetected by CFE. - Isolate* isolate = Isolate::Current(); - ASSERT(isolate->HasAttemptedReload() || isolate->null_safety()); - Report::MessageF(Report::kError, script, position, Report::AtLocation, - "Static call with invalid arguments: %s", - error_message.ToCString()); -#endif - UNREACHABLE(); -} - Fragment StreamingFlowGraphBuilder::StaticCall(TokenPosition position, const Function& target, intptr_t argument_count, ICData::RebindRule rebind_rule) { - String& error_message = String::Handle(); - if (!target.AreValidArgumentCounts(0, argument_count, 0, &error_message)) { - BadArity(script_, position, error_message); + if (!target.AreValidArgumentCounts(0, argument_count, 0, nullptr)) { + return flow_graph_builder_->ThrowNoSuchMethodError(target); } return flow_graph_builder_->StaticCall(position, target, argument_count, rebind_rule); @@ -1755,10 +1736,9 @@ Fragment StreamingFlowGraphBuilder::StaticCall( const InferredTypeMetadata* result_type, intptr_t type_args_count, bool use_unchecked_entry) { - String& error_message = String::Handle(); if (!target.AreValidArguments(type_args_count, argument_count, argument_names, - &error_message)) { - BadArity(script_, position, error_message); + nullptr)) { + return flow_graph_builder_->ThrowNoSuchMethodError(target); } return flow_graph_builder_->StaticCall( position, target, argument_count, argument_names, rebind_rule, diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h index fbba4d67c6d..d694a83f5f0 100644 --- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h +++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h @@ -166,7 +166,7 @@ class StreamingFlowGraphBuilder : public KernelReaderHelper { intptr_t yield_index = PcDescriptorsLayout::kInvalidYieldIndex); Fragment EvaluateAssertion(); Fragment RethrowException(TokenPosition position, int catch_try_index); - Fragment ThrowNoSuchMethodError(); + Fragment ThrowNoSuchMethodError(const Function& target); Fragment Constant(const Object& value); Fragment IntConstant(int64_t value); Fragment LoadStaticField(const Field& field); diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc index 62ce5a75552..35e2fadb48f 100644 --- a/runtime/vm/compiler/frontend/kernel_to_il.cc +++ b/runtime/vm/compiler/frontend/kernel_to_il.cc @@ -392,7 +392,7 @@ Fragment FlowGraphBuilder::ThrowException(TokenPosition position) { instructions += Fragment(new (Z) ThrowInstr(position, GetNextDeoptId(), exception)) .closed(); - // Use it's side effect of leaving a constant on the stack (does not change + // Use its side effect of leaving a constant on the stack (does not change // the graph). NullConstant(); @@ -408,7 +408,7 @@ Fragment FlowGraphBuilder::RethrowException(TokenPosition position, Fragment(new (Z) ReThrowInstr(position, catch_try_index, GetNextDeoptId(), exception, stacktrace)) .closed(); - // Use it's side effect of leaving a constant on the stack (does not change + // Use its side effect of leaving a constant on the stack (does not change // the graph). NullConstant(); @@ -678,7 +678,7 @@ Fragment FlowGraphBuilder::ThrowTypeError() { return instructions; } -Fragment FlowGraphBuilder::ThrowNoSuchMethodError() { +Fragment FlowGraphBuilder::ThrowNoSuchMethodError(const Function& target) { const Class& klass = Class::ZoneHandle( Z, Library::LookupCoreClass(Symbols::NoSuchMethodError())); ASSERT(!klass.IsNull()); @@ -688,20 +688,36 @@ Fragment FlowGraphBuilder::ThrowNoSuchMethodError() { Fragment instructions; - // Call NoSuchMethodError._throwNew static function. - instructions += NullConstant(); // receiver + const Class& owner = Class::Handle(Z, target.Owner()); + AbstractType& receiver = AbstractType::ZoneHandle(); + InvocationMirror::Kind kind = InvocationMirror::Kind::kMethod; + InvocationMirror::Level level; + if (owner.IsTopLevel()) { + level = InvocationMirror::Level::kTopLevel; + } else { + receiver = owner.RareType(); + if (target.kind() == FunctionLayout::kConstructor) { + level = InvocationMirror::Level::kConstructor; + } else { + level = InvocationMirror::Level::kStatic; + } + } - instructions += - Constant(H.DartString("", Heap::kOld)); // memberName - instructions += IntConstant(-1); // invocation_type - instructions += NullConstant(); // type arguments - instructions += NullConstant(); // arguments - instructions += NullConstant(); // argumentNames + // Call NoSuchMethodError._throwNew static function. + instructions += Constant(receiver); // receiver + instructions += Constant(String::ZoneHandle(Z, target.name())); // memberName + 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 = */ 6, ICData::kStatic); - // Leave "result" on the stack since callers expect it to be there (even - // though the function will result in an exception). + /* argument_count = */ 7, ICData::kStatic); + + // Properly close graph with a ThrowInstr, although it is not executed. + instructions += ThrowException(TokenPosition::kNoSource); + instructions += Drop(); return instructions; } diff --git a/runtime/vm/compiler/frontend/kernel_to_il.h b/runtime/vm/compiler/frontend/kernel_to_il.h index f6f08e5d1e2..fbee8532bdb 100644 --- a/runtime/vm/compiler/frontend/kernel_to_il.h +++ b/runtime/vm/compiler/frontend/kernel_to_il.h @@ -164,7 +164,7 @@ class FlowGraphBuilder : public BaseFlowGraphBuilder { bool use_unchecked_entry = false); Fragment StringInterpolateSingle(TokenPosition position); Fragment ThrowTypeError(); - Fragment ThrowNoSuchMethodError(); + Fragment ThrowNoSuchMethodError(const Function& target); Fragment ThrowLateInitializationError(TokenPosition position, const String& name); Fragment BuildImplicitClosureCreation(const Function& target); diff --git a/runtime/vm/isolate_reload_test.cc b/runtime/vm/isolate_reload_test.cc index 5f16ca6b66b..72411fb00c4 100644 --- a/runtime/vm/isolate_reload_test.cc +++ b/runtime/vm/isolate_reload_test.cc @@ -4516,7 +4516,9 @@ TEST_CASE(IsolateReload_StaticTargetArityChange) { lib = TestCase::ReloadTestScript(kReloadScript); EXPECT_VALID(lib); EXPECT_ERROR(SimpleInvokeError(lib, "main"), - "Static call with invalid arguments"); + "Unhandled exception:\n" + "NoSuchMethodError: No constructor 'A.' " + "with matching arguments declared in class 'A'."); } #endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME) diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index 84112b10f39..c6515e16285 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -3907,14 +3907,14 @@ static ObjectPtr ThrowNoSuchMethod(const Instance& receiver, const Smi& invocation_type = Smi::Handle(Smi::New(InvocationMirror::EncodeType(level, kind))); - const Array& args = Array::Handle(Array::New(6)); + const Array& args = Array::Handle(Array::New(7)); args.SetAt(0, receiver); args.SetAt(1, function_name); args.SetAt(2, invocation_type); - // TODO(regis): Support invocation of generic functions with type arguments. - args.SetAt(3, Object::null_type_arguments()); - args.SetAt(4, arguments); - args.SetAt(5, argument_names); + args.SetAt(3, Object::smi_zero()); // Type arguments length. + args.SetAt(4, Object::null_type_arguments()); + args.SetAt(5, arguments); + args.SetAt(6, argument_names); const Library& libcore = Library::Handle(Library::CoreLibrary()); const Class& NoSuchMethodError = diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc index ecd35ca5008..36ec9f8455b 100644 --- a/runtime/vm/runtime_entry.cc +++ b/runtime/vm/runtime_entry.cc @@ -179,13 +179,14 @@ static void NullErrorHelper(Zone* zone, const String& selector) { zone, Smi::New(InvocationMirror::EncodeType(InvocationMirror::kDynamic, kind))); - const Array& args = Array::Handle(zone, Array::New(6)); + const Array& args = Array::Handle(zone, Array::New(7)); args.SetAt(0, /* instance */ Object::null_object()); args.SetAt(1, selector); args.SetAt(2, invocation_type); - args.SetAt(3, /* func_type_args */ Object::null_object()); - args.SetAt(4, /* func_args */ Object::null_object()); - args.SetAt(5, /* func_arg_names */ Object::null_object()); + args.SetAt(3, /* func_type_args_length */ Object::smi_zero()); + args.SetAt(4, /* func_type_args */ Object::null_object()); + args.SetAt(5, /* func_args */ Object::null_object()); + args.SetAt(6, /* func_arg_names */ Object::null_object()); Exceptions::ThrowByType(Exceptions::kNoSuchMethod, args); } diff --git a/sdk/lib/_internal/vm/lib/errors_patch.dart b/sdk/lib/_internal/vm/lib/errors_patch.dart index 1ffcfa13720..add6b295db9 100644 --- a/sdk/lib/_internal/vm/lib/errors_patch.dart +++ b/sdk/lib/_internal/vm/lib/errors_patch.dart @@ -180,12 +180,6 @@ class AbstractClassInstantiationError { @patch class NoSuchMethodError { - // Deprecated members to be removed. - Symbol _memberName; - List _arguments; - Map _namedArguments; - List _existingArgumentNames; - final Object _receiver; final Invocation _invocation; @@ -202,44 +196,29 @@ class NoSuchMethodError { // method at compile time. The receiver is actually the literal class of the // unresolved method. @pragma("vm:entry-point", "call") - static void _throwNew(Object receiver, String memberName, int invocation_type, - Object typeArguments, List arguments, List argumentNames) { - throw new NoSuchMethodError._withType(receiver, memberName, invocation_type, - typeArguments, arguments, argumentNames); - } - - static void _throwNewIfNotLoaded( - _LibraryPrefix prefix, + static void _throwNew( Object receiver, String memberName, - int invocation_type, + int invocationType, + int typeArgumentsLength, Object typeArguments, List arguments, List argumentNames) { - if (!prefix.isLoaded()) { - _throwNew(receiver, memberName, invocation_type, typeArguments, arguments, - argumentNames); - } + throw new NoSuchMethodError._withType(receiver, memberName, invocationType, + typeArgumentsLength, typeArguments, arguments, argumentNames); } - // TODO(regis): Deprecated member still used by dart2js to be removed. - // Remember the type from the invocation mirror or static compilation - // analysis when thrown directly with _throwNew. A negative value means - // that no information is available. - int _invocation_type; - - // TODO(regis): Deprecated constructor still used by dart2js to be removed. + // Deprecated constructor. @patch - NoSuchMethodError(Object receiver, Symbol memberName, - List positionalArguments, Map namedArguments, - [List existingArgumentNames = null]) - : _receiver = receiver, - _invocation = null, - _memberName = memberName, - _arguments = positionalArguments, - _namedArguments = namedArguments, - _existingArgumentNames = existingArgumentNames, - _invocation_type = -1; + NoSuchMethodError(this._receiver, Symbol memberName, List positionalArguments, + Map namedArguments, + [List existingArgumentNames = null]) // existingArgumentNames ignored. + : this._invocation = new _InvocationMirror._withType( + memberName, + _InvocationMirror._UNINITIALIZED, + null, // Type arguments not supported in deprecated constructor. + positionalArguments, + namedArguments); // Helper to build a map of named arguments. static Map _NamedArgumentsMap( @@ -247,8 +226,8 @@ class NoSuchMethodError { Map namedArguments = new Map(); int numPositionalArguments = arguments.length - argumentNames.length; for (int i = 0; i < argumentNames.length; i++) { - var arg_value = arguments[numPositionalArguments + i]; - namedArguments[new Symbol(argumentNames[i])] = arg_value; + final argValue = arguments[numPositionalArguments + i]; + namedArguments[new Symbol(argumentNames[i])] = argValue; } return namedArguments; } @@ -261,17 +240,16 @@ class NoSuchMethodError { NoSuchMethodError._withType( this._receiver, String memberName, - int invocation_type, + int invocationType, + int typeArgumentsLength, // Needed with all-dynamic (null) typeArguments. Object typeArguments, List arguments, List argumentNames) : this._invocation = new _InvocationMirror._withType( new Symbol(memberName), - invocation_type, - typeArguments != null - // TODO(33073): Use actual count of type arguments in place of 0. - ? _InvocationMirror._unpackTypeArguments(typeArguments, 0) - : null, + invocationType, + _InvocationMirror._unpackTypeArguments( + typeArguments, typeArgumentsLength), argumentNames != null ? arguments.sublist(0, arguments.length - argumentNames.length) : arguments, @@ -284,12 +262,7 @@ class NoSuchMethodError { @patch String toString() { - // TODO(regis): Remove this null check once dart2js is updated. var invocation = _invocation; - if (invocation == null) { - // Use deprecated version of toString. - return _toStringDeprecated(); - } if (invocation is _InvocationMirror) { String memberName = internal.Symbol.computeUnmangledName(invocation.memberName); @@ -341,7 +314,7 @@ class NoSuchMethodError { _existingMethodSignature(_receiver, memberName, invocation._type); String argsMsg = existingSig != null ? " with matching arguments" : ""; - String kindBuf; + String kindBuf = "function"; if (kind >= 0 && kind < 5) { kindBuf = (const [ "method", @@ -452,7 +425,8 @@ class NoSuchMethodError { var name = _symbolToString(invocation.memberName); var receiverType = "${receiver.runtimeType}"; if (invocation.isAccessor) { - return "NoSuchMethodError: $receiverType has no $name ${invocation.isGetter ? "getter" : "setter"}"; + return "NoSuchMethodError: $receiverType has no $name " + "${invocation.isGetter ? "getter" : "setter"}"; } var buffer = StringBuffer("NoSuchMethodError")..write(": "); buffer.write("$receiverType has no $name method accepting arguments "); @@ -490,145 +464,6 @@ class NoSuchMethodError { } return "$symbol"; } - - // TODO(regis): Remove this function once dart2js is updated. - String _toStringDeprecated() { - var level = (_invocation_type >> _InvocationMirror._LEVEL_SHIFT) & - _InvocationMirror._LEVEL_MASK; - var type = _invocation_type & _InvocationMirror._KIND_MASK; - String memberName = (_memberName == null) - ? "" - : internal.Symbol.computeUnmangledName(_memberName); - - if (type == _InvocationMirror._LOCAL_VAR) { - return "NoSuchMethodError: Cannot assign to final variable '$memberName'"; - } - - StringBuffer arguments = new StringBuffer(); - int argumentCount = 0; - if (_arguments != null) { - for (; argumentCount < _arguments.length; argumentCount++) { - if (argumentCount > 0) { - arguments.write(", "); - } - arguments.write(Error.safeToString(_arguments[argumentCount])); - } - } - if (_namedArguments != null) { - _namedArguments.forEach((Symbol key, var value) { - if (argumentCount > 0) { - arguments.write(", "); - } - arguments.write(internal.Symbol.computeUnmangledName(key)); - arguments.write(": "); - arguments.write(Error.safeToString(value)); - argumentCount++; - }); - } - bool argsMismatch = _existingArgumentNames != null; - String argsMessage = argsMismatch ? " with matching arguments" : ""; - - String type_str; - if (type >= 0 && type < 5) { - type_str = (const [ - "method", - "getter", - "setter", - "getter or setter", - "variable" - ])[type]; - } - - StringBuffer msg_buf = new StringBuffer("NoSuchMethodError: "); - bool is_type_call = false; - switch (level) { - case _InvocationMirror._DYNAMIC: - { - if (_receiver == null) { - if (argsMismatch) { - msg_buf.writeln("The null object does not have a $type_str " - "'$memberName'$argsMessage."); - } else { - msg_buf - .writeln("The $type_str '$memberName' was called on null."); - } - } else { - if (_receiver is _Closure) { - msg_buf.writeln("Closure call with mismatched arguments: " - "function '$memberName'"); - } else if (_receiver is _Type && memberName == "call") { - is_type_call = true; - String name = _receiver.toString(); - msg_buf.writeln("Attempted to use type '$name' as a function. " - "Since types do not define a method 'call', this is not " - "possible. Did you intend to call the $name constructor and " - "forget the 'new' operator?"); - } else { - msg_buf - .writeln("Class '${_receiver.runtimeType}' has no instance " - "$type_str '$memberName'$argsMessage."); - } - } - break; - } - case _InvocationMirror._SUPER: - { - msg_buf.writeln("Super class of class '${_receiver.runtimeType}' has " - "no instance $type_str '$memberName'$argsMessage."); - memberName = "super.$memberName"; - break; - } - case _InvocationMirror._STATIC: - { - msg_buf.writeln("No static $type_str '$memberName'$argsMessage " - "declared in class '$_receiver'."); - break; - } - case _InvocationMirror._CONSTRUCTOR: - { - msg_buf.writeln("No constructor '$memberName'$argsMessage declared " - "in class '$_receiver'."); - memberName = "new $memberName"; - break; - } - case _InvocationMirror._TOP_LEVEL: - { - msg_buf.writeln("No top-level $type_str '$memberName'$argsMessage " - "declared."); - break; - } - } - - if (level == _InvocationMirror._TOP_LEVEL) { - msg_buf.writeln("Receiver: top-level"); - } else { - msg_buf.writeln("Receiver: ${Error.safeToString(_receiver)}"); - } - - if (type == _InvocationMirror._METHOD) { - String m = is_type_call ? "$_receiver" : "$memberName"; - msg_buf.write("Tried calling: $m($arguments)"); - } else if (argumentCount == 0) { - msg_buf.write("Tried calling: $memberName"); - } else if (type == _InvocationMirror._SETTER) { - msg_buf.write("Tried calling: $memberName$arguments"); - } else { - msg_buf.write("Tried calling: $memberName = $arguments"); - } - - if (argsMismatch) { - StringBuffer formalParameters = new StringBuffer(); - for (int i = 0; i < _existingArgumentNames.length; i++) { - if (i > 0) { - formalParameters.write(", "); - } - formalParameters.write(_existingArgumentNames[i]); - } - msg_buf.write("\nFound: $memberName($formalParameters)"); - } - - return msg_buf.toString(); - } } @pragma("vm:entry-point") diff --git a/sdk/lib/_internal/vm/lib/invocation_mirror_patch.dart b/sdk/lib/_internal/vm/lib/invocation_mirror_patch.dart index cfa7a6d6b22..1f43d545969 100644 --- a/sdk/lib/_internal/vm/lib/invocation_mirror_patch.dart +++ b/sdk/lib/_internal/vm/lib/invocation_mirror_patch.dart @@ -12,6 +12,7 @@ class _InvocationMirror implements Invocation { // Constants describing the invocation kind. // _FIELD cannot be generated by regular invocation mirrors. + static const int _UNINITIALIZED = -1; static const int _METHOD = 0; static const int _GETTER = 1; static const int _SETTER = 2; @@ -48,7 +49,7 @@ class _InvocationMirror implements Invocation { // External representation of the invocation mirror; populated on demand. Symbol _memberName; - int _type; + int _type = _UNINITIALIZED; List _typeArguments; List _positionalArguments; Map _namedArguments; @@ -61,7 +62,9 @@ class _InvocationMirror implements Invocation { } void _setMemberNameAndType() { - _type ??= 0; + if (_type == _UNINITIALIZED) { + _type = 0; + } if (_functionName.startsWith("get:")) { _type |= _GETTER; _memberName = new internal.Symbol.unvalidated(_functionName.substring(4)); @@ -144,28 +147,28 @@ class _InvocationMirror implements Invocation { } bool get isMethod { - if (_type == null) { + if (_type == _UNINITIALIZED) { _setMemberNameAndType(); } return (_type & _KIND_MASK) == _METHOD; } bool get isAccessor { - if (_type == null) { + if (_type == _UNINITIALIZED) { _setMemberNameAndType(); } return (_type & _KIND_MASK) != _METHOD; } bool get isGetter { - if (_type == null) { + if (_type == _UNINITIALIZED) { _setMemberNameAndType(); } return (_type & _KIND_MASK) == _GETTER; } bool get isSetter { - if (_type == null) { + if (_type == _UNINITIALIZED) { _setMemberNameAndType(); } return (_type & _KIND_MASK) == _SETTER; @@ -182,7 +185,7 @@ class _InvocationMirror implements Invocation { @pragma("vm:entry-point", "call") static _allocateInvocationMirror(String functionName, List argumentsDescriptor, List arguments, bool isSuperInvocation, - [int type = null]) { + [int type = _UNINITIALIZED]) { return new _InvocationMirror( functionName, argumentsDescriptor, arguments, isSuperInvocation, type); } @@ -200,6 +203,6 @@ class _InvocationMirror implements Invocation { int type, int delayedTypeArgumentsLen) { return new _InvocationMirror(functionName, argumentsDescriptor, arguments, - false, type, delayedTypeArgumentsLen); + false, type ?? _UNINITIALIZED, delayedTypeArgumentsLen); } } diff --git a/sdk_nnbd/lib/_internal/vm/lib/errors_patch.dart b/sdk_nnbd/lib/_internal/vm/lib/errors_patch.dart index 05983d7a616..c4b91f205e3 100644 --- a/sdk_nnbd/lib/_internal/vm/lib/errors_patch.dart +++ b/sdk_nnbd/lib/_internal/vm/lib/errors_patch.dart @@ -177,22 +177,15 @@ class AbstractClassInstantiationError { @patch class NoSuchMethodError { - // Deprecated members to be removed. - Symbol? _memberName; - List? _arguments; - Map? _namedArguments; - List? _existingArgumentNames; + final Object? _receiver; + final Invocation _invocation; - final Object _receiver; - final Invocation? _invocation; - - // Issue(dartbug.com/127160): Remove the cast to [_InvocationMirror]. @patch - NoSuchMethodError.withInvocation(Object receiver, Invocation invocation) + NoSuchMethodError.withInvocation(Object? receiver, Invocation invocation) : _receiver = receiver, _invocation = invocation; - static void _throwNewInvocation(Object receiver, Invocation invocation) { + static void _throwNewInvocation(Object? receiver, Invocation invocation) { throw new NoSuchMethodError.withInvocation(receiver, invocation); } @@ -200,44 +193,29 @@ class NoSuchMethodError { // method at compile time. The receiver is actually the literal class of the // unresolved method. @pragma("vm:entry-point", "call") - static void _throwNew(Object receiver, String memberName, int invocationType, - Object? typeArguments, List? arguments, List? argumentNames) { - throw new NoSuchMethodError._withType(receiver, memberName, invocationType, - typeArguments, arguments, argumentNames); - } - - static void _throwNewIfNotLoaded( - _LibraryPrefix prefix, + static void _throwNew( Object receiver, String memberName, int invocationType, - Object typeArguments, - List arguments, - List argumentNames) { - if (!prefix.isLoaded()) { - _throwNew(receiver, memberName, invocationType, typeArguments, arguments, - argumentNames); - } + int typeArgumentsLength, + Object? typeArguments, + List? arguments, + List? argumentNames) { + throw new NoSuchMethodError._withType(receiver, memberName, invocationType, + typeArgumentsLength, typeArguments, arguments, argumentNames); } - // TODO(regis): Deprecated member still used by dart2js to be removed. - // Remember the type from the invocation mirror or static compilation - // analysis when thrown directly with _throwNew. A negative value means - // that no information is available. - int _invocationType = -1; - - // TODO(regis): Deprecated constructor still used by dart2js to be removed. + // Deprecated constructor. @patch - NoSuchMethodError(Object receiver, Symbol memberName, - List positionalArguments, Map namedArguments, - [List? existingArgumentNames = null]) - : _receiver = receiver, - _invocation = null, - _memberName = memberName, - _arguments = positionalArguments, - _namedArguments = namedArguments, - _existingArgumentNames = existingArgumentNames, - _invocationType = -1; + NoSuchMethodError(this._receiver, Symbol memberName, + List? positionalArguments, Map? namedArguments, + [List? existingArgumentNames = null]) // existingArgumentNames ignored. + : this._invocation = new _InvocationMirror._withType( + memberName, + _InvocationMirror._UNINITIALIZED, + null, // Type arguments not supported in deprecated constructor. + positionalArguments, + namedArguments); // Helper to build a map of named arguments. static Map _NamedArgumentsMap( @@ -260,16 +238,15 @@ class NoSuchMethodError { this._receiver, String memberName, int invocationType, + int typeArgumentsLength, // Needed with all-dynamic (null) typeArguments. Object? typeArguments, List? arguments, List? argumentNames) : this._invocation = new _InvocationMirror._withType( new Symbol(memberName), invocationType, - typeArguments != null - // TODO(33073): Use actual count of type arguments in place of 0. - ? _InvocationMirror._unpackTypeArguments(typeArguments, 0) - : null, + _InvocationMirror._unpackTypeArguments( + typeArguments, typeArgumentsLength), argumentNames != null ? arguments!.sublist(0, arguments.length - argumentNames.length) : arguments, @@ -277,17 +254,12 @@ class NoSuchMethodError { ? _NamedArgumentsMap(arguments!, argumentNames) : null); - static String? _existingMethodSignature(Object receiver, String methodName, + static String? _existingMethodSignature(Object? receiver, String methodName, int invocationType) native "NoSuchMethodError_existingMethodSignature"; @patch String toString() { - // TODO(regis): Remove this null check once dart2js is updated. final localInvocation = _invocation; - if (localInvocation == null) { - // Use deprecated version of toString. - return _toStringDeprecated(); - } if (localInvocation is _InvocationMirror) { var internalName = localInvocation.memberName as internal.Symbol; String memberName = internal.Symbol.computeUnmangledName(internalName); @@ -343,14 +315,16 @@ class NoSuchMethodError { _receiver, memberName, localInvocation._type); String argsMsg = existingSig != null ? " with matching arguments" : ""; - assert(kind >= 0 && kind < 5); - final String kindBuf = (const [ - "method", - "getter", - "setter", - "getter or setter", - "variable" - ])[kind]; + String kindBuf = "function"; + if (kind >= 0 && kind < 5) { + kindBuf = (const [ + "method", + "getter", + "setter", + "getter or setter", + "variable" + ])[kind]; + } StringBuffer msgBuf = new StringBuffer("NoSuchMethodError: "); bool isTypeCall = false; @@ -448,7 +422,7 @@ class NoSuchMethodError { /// Used for situations where there is no extra information available /// about the failed invocation than the [Invocation] object and receiver, /// which includes errors created using [NoSuchMethodError.withInvocation]. - static String _toStringPlain(Object receiver, Invocation invocation) { + static String _toStringPlain(Object? receiver, Invocation invocation) { var name = _symbolToString(invocation.memberName); var receiverType = "${receiver.runtimeType}"; if (invocation.isAccessor) { @@ -491,143 +465,6 @@ class NoSuchMethodError { } return "$symbol"; } - - // TODO(regis): Remove this function once dart2js is updated. - String _toStringDeprecated() { - var level = (_invocationType >> _InvocationMirror._LEVEL_SHIFT) & - _InvocationMirror._LEVEL_MASK; - var type = _invocationType & _InvocationMirror._KIND_MASK; - String memberName = (_memberName == null) - ? "" - : internal.Symbol.computeUnmangledName(_memberName as internal.Symbol); - - if (type == _InvocationMirror._LOCAL_VAR) { - return "NoSuchMethodError: Cannot assign to final variable '$memberName'"; - } - - StringBuffer arguments = new StringBuffer(); - int argumentCount = 0; - final args = _arguments; - if (args != null) { - for (; argumentCount < args.length; argumentCount++) { - if (argumentCount > 0) { - arguments.write(", "); - } - arguments.write(Error.safeToString(args[argumentCount])); - } - } - _namedArguments?.forEach((Symbol key, var value) { - if (argumentCount > 0) { - arguments.write(", "); - } - var internalName = key as internal.Symbol; - arguments.write(internal.Symbol.computeUnmangledName(internalName)); - arguments.write(": "); - arguments.write(Error.safeToString(value)); - argumentCount++; - }); - bool argsMismatch = _existingArgumentNames != null; - String argsMessage = argsMismatch ? " with matching arguments" : ""; - - final String typeStr = (type >= 0 && type < 5) - ? (const [ - "method", - "getter", - "setter", - "getter or setter", - "variable" - ])[type] - : ""; - - StringBuffer msgBuf = new StringBuffer("NoSuchMethodError: "); - bool isTypeCall = false; - switch (level) { - case _InvocationMirror._DYNAMIC: - { - if (_receiver == null) { - if (argsMismatch) { - msgBuf.writeln("The null object does not have a $typeStr " - "'$memberName'$argsMessage."); - } else { - msgBuf.writeln("The $typeStr '$memberName' was called on null."); - } - } else { - if (_receiver is _Closure) { - msgBuf.writeln("Closure call with mismatched arguments: " - "function '$memberName'"); - } else if (_receiver is _Type && memberName == "call") { - isTypeCall = true; - String name = _receiver.toString(); - msgBuf.writeln("Attempted to use type '$name' as a function. " - "Since types do not define a method 'call', this is not " - "possible. Did you intend to call the $name constructor and " - "forget the 'new' operator?"); - } else { - msgBuf.writeln("Class '${_receiver.runtimeType}' has no instance " - "$typeStr '$memberName'$argsMessage."); - } - } - break; - } - case _InvocationMirror._SUPER: - { - msgBuf.writeln("Super class of class '${_receiver.runtimeType}' has " - "no instance $typeStr '$memberName'$argsMessage."); - memberName = "super.$memberName"; - break; - } - case _InvocationMirror._STATIC: - { - msgBuf.writeln("No static $typeStr '$memberName'$argsMessage " - "declared in class '$_receiver'."); - break; - } - case _InvocationMirror._CONSTRUCTOR: - { - msgBuf.writeln("No constructor '$memberName'$argsMessage declared " - "in class '$_receiver'."); - memberName = "new $memberName"; - break; - } - case _InvocationMirror._TOP_LEVEL: - { - msgBuf.writeln("No top-level $typeStr '$memberName'$argsMessage " - "declared."); - break; - } - } - - if (level == _InvocationMirror._TOP_LEVEL) { - msgBuf.writeln("Receiver: top-level"); - } else { - msgBuf.writeln("Receiver: ${Error.safeToString(_receiver)}"); - } - - if (type == _InvocationMirror._METHOD) { - String m = isTypeCall ? "$_receiver" : "$memberName"; - msgBuf.write("Tried calling: $m($arguments)"); - } else if (argumentCount == 0) { - msgBuf.write("Tried calling: $memberName"); - } else if (type == _InvocationMirror._SETTER) { - msgBuf.write("Tried calling: $memberName$arguments"); - } else { - msgBuf.write("Tried calling: $memberName = $arguments"); - } - - if (argsMismatch) { - StringBuffer formalParameters = new StringBuffer(); - final argumentNames = _existingArgumentNames!; - for (int i = 0; i < argumentNames.length; i++) { - if (i > 0) { - formalParameters.write(", "); - } - formalParameters.write(argumentNames[i]); - } - msgBuf.write("\nFound: $memberName($formalParameters)"); - } - - return msgBuf.toString(); - } } @pragma("vm:entry-point")