-
Notifications
You must be signed in to change notification settings - Fork 56
Description
Amazing work on this library and thank you, its a really powerful feature and super useful in my projects. My bug report follows:
Bug: Nested Ternary with Bridged String Variable Causes TypeError: null is not a subtype of int
Library Versions:
• dart_eval: 0.8.2
• flutter_eval: 0.8.1
• Flutter/Dart Environment:
[√] Flutter (Channel stable, 3.32.0, on Microsoft Windows [Version 10.0.26100.6584], locale en-GB) [1,375ms]
• Flutter version 3.32.0 on channel stable at ...\MY_Code\flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision be698c48a6 (4 months ago), 2025-05-19 12:59:14 -0700
• Engine revision 1881800949
• Dart version 3.8.0
• DevTools version 2.45.1
Problem Description:
When evaluating an expression that contains a nested ternary operator, a TypeError is thrown if the condition involves comparing a bridged string variable (a variable passed into the runtime from the host application) with a string literal.
The stack trace indicates the == operator within the sandbox returns null instead of a boolean equivalent (0 or 1). This null value is then passed to a BoxInt operation, which fails with the TypeError: null is not a subtype of int.
A single-level ternary operator with the same bridged variable works correctly. The issue is specific to the nesting of the conditional logic.
Steps to Reproduce:
The following minimal, self-contained code snippet reproduces the error reliably. It uses the required bridging mechanism to pass a Map<String, dynamic> into the runtime.
import 'package:dart_eval/dart_eval.dart';
import 'package:dart_eval/stdlib/core.dart';
// The service class used to evaluate the expression
class DartEvalService {
final _compiler = Compiler();
dynamic evaluate(String userExpression, Map<String, dynamic> dataContext) {
final sourceCode = '''
dynamic main(Map<String, dynamic> data) {
// Unpack the map into named variables
${dataContext.keys.map((key) => "final $key = data['$key'];").join('\n')}
return $userExpression;
}
''';
try {
final program = _compiler.compile({'my_package': {'main.dart': sourceCode}});
final runtime = Runtime.ofProgram(program);
final wrappedContext = $Map.wrap({
for (var entry in dataContext.entries)
$String(entry.key): switch (entry.value) {
String v => $String(v),
int v => $int(v),
double v => $double(v),
bool v => $bool(v),
null => $null(),
_ => $null(),
}
});
var result = runtime.executeLib('package:my_package/main.dart', 'main', [wrappedContext]);
return result?.$value;
} catch (e) {
print('--- DART EVAL RUNTIME ERROR ---');
print('Expression: $userExpression');
print('Error: $e');
print('-------------------------------');
rethrow;
}
}
}
// Main function to demonstrate the bug
void main() {
final service = DartEvalService();
// The data context passed from the "host" application
final data = {
'StageStatus': 'Current',
};
// This single-level ternary works perfectly
print('Testing single ternary (EXPECTED: SUCCESS)');
final singleTernary = 'StageStatus == "Outstanding" ? 1 : 0';
service.evaluate(singleTernary, data);
print('SUCCESS\n');
// This nested ternary fails
print('Testing nested ternary (EXPECTED: FAILURE)');
final nestedTernary = 'StageStatus == "Outstanding" ? 1 : (StageStatus == "Current" ? 2 : 3)';
service.evaluate(nestedTernary, data);
}
Expected Behavior:
The code should execute without any errors. The evaluate call with the nestedTernary expression should successfully return the integer 2.
Actual Behavior:
The code throws a dart_eval runtime exception. The following error and stack trace are produced:
--- DART EVAL DEBUG ---
INCOMING EXPRESSION: "StageStatus=="Outstanding" ? 0xFFFF0000 : (StageStatus=="Current" ? 0xFFFFFF00 : 0xFF00FF00)"
FULL DATA CONTEXT: {salst_name: Tender Identified & Qualified, salst_sort: 10, StageStatus: Current, DateCompleted: 2025-09-16T05:25:38.943Z}
VALUE OF "StageStatus": "Current"
RUNTIME TYPE of "StageStatus": String
--- DART EVAL RUNTIME ERROR ---
Expression: StageStatus=="Outstanding" ? 0xFFFF0000 : (StageStatus=="Current" ? 0xFFFFFF00 : 0xFF00FF00)
Error: dart_eval runtime exception: TypeError: null: type 'Null' is not a subtype of type 'int'
http://localhost:64171/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 266:3 throw_
http://localhost:64171/dart-sdk/lib/_internal/js_dev_runtime/private/profile.dart 117:39 _asInt
package:dart_eval/src/eval/runtime/ops/primitives.dart 181:50 run
primitives.dart:181
at main()
RUNTIME STATE
Program offset: 127
Stack sample: [L3: $"salst_sort", L4:
Args sample: []
Call stack: [0, -1]
TRACE:
121: CopyValue (L12 <-- L15)
122: Pop (1)
123: Pop (2)
124: CopyValue (L12 <-- L12)
125: Pop (1)
126: Pop (2)
127: BoxInt (L9) <<< EXCEPTION
128: Return (L9)
Thanks again !
Ted