Open niclasEX opened 2 months ago
/cc @jensjoha seems like a problem with expression evaluation
Thanks for the reproducible bug report!
Technical details:
The request sent via kernel service from the VM is this:
[...]
request[10] = file:///path/to/file.dart
request[11] = ValueEquality
request[12] = ==
request[13] = false
request[14] = 395
request[15] = file:///path/to/file.dart
[...]
i.e. it' saying that we're in the library (the file) [10], in class ValueEquality
[11], in method ==
[12] which is not static [13] at position 395
[14] in script (still the file) [15] --- so when doing the expression calculation we're told we're in ValueEquality.==
--- which compiled looks like this:
abstract class ValueEquality<T extends core::Object? = dynamic> extends core::Object /*isMixinDeclaration*/ {
[...]
operator ==(core::Object other) → core::bool {
return other is self::ValueEquality::T%;
}
[...]
}
It has a T
so we're happily compiling the expresion T
to return [0] [0] #lib1::ValueEquality::T%;
Though, as we can see from the "frame name" (in Observatory) we're actually in _A&Parent&ValueEquality.==
with the class looking like this:
abstract class _A&Parent&ValueEquality extends self::Parent implements self::ValueEquality<self::Parent> /*isAnonymousMixin,isEliminatedMixin*/ {
[...]
operator ==(core::Object other) → core::bool {
return other is self::Parent;
}
[...]
}
so no T
actually exists.
And so the VM returns the Unbound type parameter found in %s. Please report this at dartbug.com.
error.
It seems the VM made the change to send the name of the mixin class in https://dart-review.googlesource.com/c/sdk/+/279238 (response to https://github.com/dart-lang/sdk/issues/51027) --- though giving the error The getter 'T' isn't defined for the class '_A&Parent&ValueEquality'.
(the case without that change) probably wouldn't be more helpful.
@mraleph could a solution on the VM side be something like this:
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index c841c209eb5..5a0967322d7 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -3583,12 +3583,40 @@ void TypeTranslator::BuildTypeParameterType() {
// If the type is from a constant, the parameter index isn't offset by the
// enclosing context.
+ bool special_mixin_handling_for_expression_evaluation = false;
if (!in_constant_context_) {
- const intptr_t class_type_parameter_count =
- active_class_->klass->NumTypeParameters();
+ auto klass = active_class_->klass;
+ if (klass->is_transformed_mixin_application() &&
+ active_class_->member != nullptr) {
+ const String& name = String::Handle(Z, active_class_->member->name());
+ if (name.Equals(Symbols::DebugProcedureName())) {
+ // In vm/service.cc we send over the "klass->Mixin()" class to the CFE.
+ // It's therefore compiled as is we're in the mixin, but we're not. If
+ // there's type arguments in play we have to handle that special.
+ // This is the first part of what "klass->Mixin()" does,
+ // only we extract the actual type arguments.
+ const Array& interfaces = Array::Handle(klass->interfaces());
+ const Type& mixin_type =
+ Type::Handle(Type::RawCast(interfaces.At(interfaces.Length() - 1)));
+ const TypeArguments& type_args =
+ TypeArguments::Handle(Z, mixin_type.arguments());
+ const intptr_t type_args_count = type_args.Length();
+ if (type_args_count > parameter_index) {
+ result_ = type_args.TypeAt(parameter_index);
+ return;
+ }
+ // Not pointing to the type arguments of the class,
+ // but pick the class with type parameters to shift the parameter_index
+ // correctly below.
+ Class& method_cls = Class::Handle(Z, klass->Mixin());
+ klass = &method_cls;
+ special_mixin_handling_for_expression_evaluation = true;
+ }
+ }
+ const intptr_t class_type_parameter_count = klass->NumTypeParameters();
if (class_type_parameter_count > parameter_index) {
- result_ =
- active_class_->klass->TypeParameterAt(parameter_index, nullability);
+ ASSERT(!special_mixin_handling_for_expression_evaluation);
+ result_ = klass->TypeParameterAt(parameter_index, nullability);
return;
}
parameter_index -= class_type_parameter_count;
@@ -3613,8 +3641,7 @@ void TypeTranslator::BuildTypeParameterType() {
// }
//
if (class_type_parameter_count > parameter_index) {
- result_ = active_class_->klass->TypeParameterAt(parameter_index,
- nullability);
+ result_ = klass->TypeParameterAt(parameter_index, nullability);
return;
}
parameter_index -= class_type_parameter_count;
?
/cc @rmacnak-google @bkonyi
This tracker is for issues related to:
dart:async
,dart:io
, etc.) ?Dart info output:
General info
Project info
Process info
As stated in the dart info output, this is on macOS running in vscode. The dart code runs without any exceptions and returns true as expected.
I stumbled upon this in my flutter project where I tried to create a Map<Parent, dynamic> and inserting objects threw the aforementioned exception