Skip to content

Commit

Permalink
[dart2wasm] Fix handling of null values in some non-nullable contexts
Browse files Browse the repository at this point in the history
Change-Id: Id25f4899d0898686ee30bf05f7e57a9ef84fb818
Cq-Include-Trybots: luci.dart.try:dart2wasm-linux-x64-d8-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/252740
Reviewed-by: Joshua Litt <joshualitt@google.com>
  • Loading branch information
askeksa authored and Commit Bot committed Jul 27, 2022
1 parent 1015134 commit e75be08
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 10 deletions.
17 changes: 12 additions & 5 deletions pkg/dart2wasm/lib/code_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1857,17 +1857,20 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>

@override
w.ValueType visitNullCheck(NullCheck node, w.ValueType expectedType) {
w.ValueType operandType =
translator.translateType(dartTypeOf(node.operand));
return _nullCheck(node.operand, translator.throwNullCheckError);
}

w.ValueType _nullCheck(Expression operand, Procedure errorProcedure) {
w.ValueType operandType = translator.translateType(dartTypeOf(operand));
w.ValueType nonNullOperandType = operandType.withNullability(false);
w.Label nullCheckBlock = b.block(const [], [nonNullOperandType]);
wrap(node.operand, operandType);
wrap(operand, operandType);

// We lower a null check to a br_on_non_null, throwing a [TypeError] in the
// null case.
b.br_on_non_null(nullCheckBlock);
call(translator.stackTraceCurrent.reference);
call(translator.throwNullCheckError.reference);
call(errorProcedure.reference);
b.unreachable();
b.end();
return nonNullOperandType;
Expand Down Expand Up @@ -1923,7 +1926,11 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>

@override
w.ValueType visitThrow(Throw node, w.ValueType expectedType) {
wrap(node.expression, translator.topInfo.nonNullableType);
if (dartTypeOf(node.expression).isPotentiallyNullable) {
_nullCheck(node.expression, translator.throwThrowNullError);
} else {
wrap(node.expression, translator.topInfo.nonNullableType);
}
call(translator.stackTraceCurrent.reference);

// At this point, we have the exception and the current stack trace on the
Expand Down
6 changes: 3 additions & 3 deletions pkg/dart2wasm/lib/intrinsics.dart
Original file line number Diff line number Diff line change
Expand Up @@ -714,10 +714,10 @@ class Intrinsifier {
switch (name) {
case "unsafeCast":
case "unsafeCastOpaque":
w.ValueType targetType =
translator.translateType(node.arguments.types.single);
Expression operand = node.arguments.positional.single;
return codeGen.wrap(operand, targetType);
// Just evaluate the operand and let the context convert it to the
// expected type.
return codeGen.wrap(operand, typeOfExp(operand));
case "_nativeEffect":
// Ignore argument
return translator.voidMarker;
Expand Down
3 changes: 3 additions & 0 deletions pkg/dart2wasm/lib/translator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ class Translator {
late final Procedure stringEquals;
late final Procedure stringInterpolate;
late final Procedure throwNullCheckError;
late final Procedure throwThrowNullError;
late final Procedure throwAsCheckError;
late final Procedure throwWasmRefError;
late final Procedure mapFactory;
Expand Down Expand Up @@ -250,6 +251,8 @@ class Translator {
.firstWhere((p) => p.name.text == "_interpolate");
throwNullCheckError = typeErrorClass.procedures
.firstWhere((p) => p.name.text == "_throwNullCheckError");
throwThrowNullError = typeErrorClass.procedures
.firstWhere((p) => p.name.text == "_throwThrowNullError");
throwAsCheckError = typeErrorClass.procedures
.firstWhere((p) => p.name.text == "_throwAsCheckError");
throwWasmRefError = typeErrorClass.procedures
Expand Down
12 changes: 10 additions & 2 deletions sdk/lib/_internal/wasm/lib/errors_patch.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class _Error extends Error {
}

class _TypeError extends _Error implements TypeError {
_TypeError(String message) : super('TypeError: $message');
_TypeError(String message) : super(message);

factory _TypeError.fromMessageAndStackTrace(
String message, StackTrace stackTrace) {
Expand All @@ -57,11 +57,19 @@ class _TypeError extends _Error implements TypeError {
return _throwObjectWithStackTrace(typeError, stackTrace);
}

@pragma("wasm:entry-point")
static Never _throwThrowNullError(StackTrace stackTrace) {
final typeError =
_TypeError.fromMessageAndStackTrace("Throw of null", stackTrace);
return _throwObjectWithStackTrace(typeError, stackTrace);
}

@pragma("wasm:entry-point")
static Never _throwAsCheckError(
Object? operand, Type? type, StackTrace stackTrace) {
final typeError = _TypeError.fromMessageAndStackTrace(
"Type '${operand.runtimeType}' is not a subtype of type '$type' in type cast",
"Type '${operand.runtimeType}' is not a subtype of type '$type'"
" in type cast",
stackTrace);
return _throwObjectWithStackTrace(typeError, stackTrace);
}
Expand Down

0 comments on commit e75be08

Please sign in to comment.