diff --git a/pkg/dart2wasm/lib/code_generator.dart b/pkg/dart2wasm/lib/code_generator.dart index e1be91c00686..66d7a680d0e3 100644 --- a/pkg/dart2wasm/lib/code_generator.dart +++ b/pkg/dart2wasm/lib/code_generator.dart @@ -1857,17 +1857,20 @@ class CodeGenerator extends ExpressionVisitor1 @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; @@ -1923,7 +1926,11 @@ class CodeGenerator extends ExpressionVisitor1 @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 diff --git a/pkg/dart2wasm/lib/intrinsics.dart b/pkg/dart2wasm/lib/intrinsics.dart index a4902ad01864..780f9270940b 100644 --- a/pkg/dart2wasm/lib/intrinsics.dart +++ b/pkg/dart2wasm/lib/intrinsics.dart @@ -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; diff --git a/pkg/dart2wasm/lib/translator.dart b/pkg/dart2wasm/lib/translator.dart index dc57e39b3b77..676d4bb3d9d2 100644 --- a/pkg/dart2wasm/lib/translator.dart +++ b/pkg/dart2wasm/lib/translator.dart @@ -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; @@ -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 diff --git a/sdk/lib/_internal/wasm/lib/errors_patch.dart b/sdk/lib/_internal/wasm/lib/errors_patch.dart index 88b9a2277846..991d48215720 100644 --- a/sdk/lib/_internal/wasm/lib/errors_patch.dart +++ b/sdk/lib/_internal/wasm/lib/errors_patch.dart @@ -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) { @@ -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); }