Open kmillikin opened 6 years ago
My guess about what's going on: it's generating a typed call against a dynamically typed target:
exp::Expect::isTrue(e.toString().{core::String::contains}("Oops"));
I'm guessing the receiver e.toString()
has type dynamic
?
If so: DDK does not expect that combination. If the receiver type is only known to be dynamic
, how can you call a method on String
soundly? So it kinda doesn't make sense from a typing perspective. The fix in CFE would be to have e.toString()
getStaticType return core::String
. We could try to workaround this in DDK. But it would be better if the static types were consistent in the IR.
Confirmed the receiver type is dynamic
:
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -3756,6 +3756,7 @@ class ProgramCompiler extends Object
var jsReceiver = _visitExpression(receiver);
var args = _emitArgumentList(arguments);
var receiverType = receiver.getStaticType(types);
+ print('!!! receiver: `$receiver`, receiverType: $receiverType, target: $target');
bool isCallingDynamicField = target is Member &&
target.hasGetter &&
prints
!!! receiver: `e`, receiverType: dynamic, target: null
!!! receiver: `e.toString()`, receiverType: dynamic, target: dart.core::String::contains
I believe this is a CFE bug, because the spec says the static type of e.toString()
should be String
.
Also I realized dev compiler can't work around this in general. There are a bunch of places it uses getStaticType
, and a target is not always available to carry the type info. For example: e.toString() as String
... we are unable to eliminate the cast because we think e.toString()
has type dynamic
.
Reassigning this to CFE, let me know if that seems right to you. I may be able to work around it in the meantime for some kinds of expressions. Interestingly type inference seems to understand the real type:
main() {
Type f<T>(T t) => T;
dynamic e = 'hi';
print(f(e.toString())); // prints String
}
so at some point CFE is aware that e.toString()
has type core::String
... perhaps it is just not getting updated on the kernel node?
here's a CL that works around most of the issues: https://dart-review.googlesource.com/c/sdk/+/57710
BTW, it would be helpful if Kernel output included the target for the e.toString()
call:
on dynamic catch(final dynamic e) {
exp::Expect::isTrue(e.{core::Object::toString}().{core::String::contains}("Oops"));
}
Since the target (core::Object::toString
) was found and used for type inference, it would be nice if the target was recorded.
Thanks for taking a look.
The front end bug, which is the missing interface target, will be fixed by https://dart-review.googlesource.com/c/sdk/+/57820.
I'll fix the Kernel type system bug, which gives the wrong static type, separately.
The front-end bug was fixed in 6ac6baae8e5d65f8c619faa91b7e6cc4184750ff.
Kernel's type checker hasn't been fixed.
I need some help figuring out what's going on here. I've tried to fix #32414 in the Dart front end. If we look at this from tests/language_2/assert_with_message_test.dart:
We had in Kernel before:
and now will have
DDK generated before:
and now will generate:
However, the new code fails with
Why?