Skip to content

Invoking operator== on a mirror and passing null as an argument, how should it be handled? #42688

Closed
@sstrickl

Description

@sstrickl

In CL 153202, I'm fixing Function::DoArgumentTypesMatch to be NNBD-compliant, among other things. On the main branch, that method skips argument checks if the argument is null, but that no longer happens after my CL (instead it appropriately checks the argument type using Instance::NullIsAssignableTo). This is causing a test failure in tests/lib/mirrors/null_test.dart, where we have:

  InstanceMirror im1 = reflect(null);
  Expect.equals(cm, im1.type);
  Expect.isTrue(im1.invoke(const Symbol("=="), [null]).reflectee);

and in sdk/lib/core/object.dart, we have:

  external bool operator ==(Object other);

Thus, when Instance::NullIsAssignableTo is checked with the type Object in strong mode, it fails and causes the type error:

Unhandled exception:
type 'Null' is not a subtype of type 'Object' of 'other'
#0      _TypeError._throwNew (dart:core-patch/errors_patch.dart:98:34)
#1      _InstanceMirror._invoke (dart:mirrors-patch/mirrors_impl.dart:337:37)
#2      _InstanceMirror.invoke (dart:mirrors-patch/mirrors_impl.dart:333:25)
#3      test (file:///usr/local/google/home/sstrickl/dart/sdk/tests/lib/mirrors/null_test.dart:21:21)
#4      main (file:///usr/local/google/home/sstrickl/dart/sdk/tests/lib/mirrors/null_test.dart:12:5)
#5      _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:301:19)
#6      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168:12)

For now, I'm going to approve the failure (and add comments in the test pointing at this issue). I'm happy to fix things, but I need to know which of the approaches to take here:

  1. We can just declare this a type error and change the test to use expect.throwsTypeError() in this and similar cases throughout the file.
  2. We can change InstanceMirror.invoke in sdk/lib/_internal/vm/lib/mirrors_impl.dart to specifically check for Symbol('==') and a null argument, and return the correct value based on the reflectee value. This means any overrides of Object.== will not be taken into consideration (which may return true for == despite having a non-null receiver).
  3. We can change Instance::Invoke in the VM to check to see if the function that will be invoked is Object.== and then do the check there. However, this means that trying to invoke == on an instance where a subclass overrides Object.== will continue to fail, unless the subclass allows a nullable argument.

Of course, if another alternative is preferred, I can look at implementing that as well.

\cc @lrhn

Metadata

Metadata

Assignees

No one assigned

    Labels

    NNBDIssues related to NNBD Releasearea-testCross-cutting test issues (use area- labels for specific failures; not used for package:test).

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions