Description
Background
In Dart 2 and Dart 2.1 releases due to a bug in dart:mirrors
implementation it was possible to violate strong mode type safety via dart:mirrors
.
For example the following code:
import 'dart:mirrors';
class A {
void method(int v) {
if (v != null && v is! int) {
print("This should be impossible: expected null or int got ${v}");
}
}
}
void main() {
final obj = A();
reflect(obj).invoke(#method, ['not-an-number']);
}
In Dart 2.1 release would print
This should be impossible: expected null or int got not-an-number
In Dart 2.1.1 we are addressing this issue meaning that this code would start throwing TypeError
Unhandled exception:
type 'String' is not a subtype of type 'int' of 'v'
#0 _TypeError._throwNew (dart:core/runtime/liberrors_patch.dart:89:51)
#1 _LocalInstanceMirror._invoke (dart:mirrors/runtime/libmirrors_impl.dart:327:37)
#2 _LocalInstanceMirror.invoke (dart:mirrors/runtime/libmirrors_impl.dart:323:25)
#3 main (file:///tmp/test.dart:13:16)
#4 _startIsolate.<anonymous closure> (dart:isolate/runtime/libisolate_patch.dart:289:19)
#5 _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12)
Expected impact
We expect that only programs that are incorrect with respect to strong mode would break.
However this might also reveal issues where programs relying on mirrors were not taking care of creating instances of generic classes with correct type arguments - and instead relied on Dart 1 "dynamic-is-bottom" semantics.
For example the following code would stop working:
import 'dart:mirrors';
class B<T> {
}
class A {
void method(B<int> v) {
}
}
void main() {
final obj = A();
reflect(obj).invoke(#method, [B()]);
}
This would fail with
type 'B<dynamic>' is not a subtype of type 'B<int>' of 'v'
Addressing the breakage
You would need to change your reflective code to pass arguments of correct types, which also means creating instances with correct type arguments.
Note that if you need to construct object reflectively with the given type arguments you can use reflectType
to create type mirror with the given type arguments and then cast this mirror to ClassMirror
and use ClassMirror.newInstance
:
print((reflectType(B, [int]) as ClassMirror).newInstance(const Symbol(""), []).reflectee); // Instance of B<int>
Known Affected Packages
package:rpc
see #35009
/cc @mit-mit