Skip to content

Crash when calling a virtual method that is not implemented in the mixin #47148

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
axxop opened this issue Sep 8, 2021 · 2 comments
Closed
Labels
closed-as-intended Closed as the reported issue is expected behavior

Comments

@axxop
Copy link

axxop commented Sep 8, 2021

main.dart

import 'lib.dart';

mixin D {
  _test();
}

main() {
  P()._test();
}

lib.dart

import 'main.dart';

class P with D {}

The analyzer show no errors, but it crashed in running:

Unhandled exception:
NoSuchMethodError: Class 'P' has no instance method '_test'.
Receiver: Instance of 'P'
Tried calling: _test()
#0      Object.noSuchMethod (dart:core-patch/object_patch.dart:63:5)
...
@eernstg
Copy link
Member

eernstg commented Sep 8, 2021

This is actually working as specified.

It is not possible for a class in a library L to declare an implementation of a method whose member signature is introduced by a declaration D in a different library L2 when D has a private name.

In that situation, a 'noSuchMethod' forwarder is generated. This means that the method exists (for instance, we can tear it off), but it will not do anything other than calling noSuchMethod with various data describing the invocation.

However, you basically won't be able to interpret that data because, in particular, the memberName will be a symbol that you can't create outside L2, so you can't actually write your own noSuchMethod where you recognize that symbol by an equality test and run some code that you wish to execute when that private method is invoked.

All in all, this means that soundness is preserved (the object will have the required method), but it is kept private (in the sense that you can't just go ahead and implement it).

We discussed various options for making this scenario "more statically typed" (technically it is sound, but it looks a lot like a dynamic type error). Obviously, we could just make it a compile-time error to implement or extend a class (or mix in a mixin) in such a way that this mechanism kicks in. However, that would be a breaking change, which makes it a lot harder to do (for everyone!).

@lrhn
Copy link
Member

lrhn commented Sep 8, 2021

This is working as intended.

The P class declaration cannot see the _test declaration because it's private to a different library.
The rule in that case is that since P is not abstract, so it must implement its interface, but it cannot possibly implement _test (or know that it should), you get a free "no such method" forwarding stub added to implement _test.

Basically, you get a _test() => noSuchMethod(Invocation.method(#test, null)); method added automatically. That's what you're calling.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-as-intended Closed as the reported issue is expected behavior
Projects
None yet
Development

No branches or pull requests

3 participants