@@ -10145,6 +10145,7 @@ export class Compiler extends DiagnosticEmitter {
10145
10145
10146
10146
/** Makes a string conversion of the given expression. */
10147
10147
makeToString ( expr : ExpressionRef , type : Type , reportNode : Node ) : ExpressionRef {
10148
+ let module = this . module ;
10148
10149
let stringType = this . program . stringInstance . type ;
10149
10150
if ( type == stringType ) {
10150
10151
return expr ;
@@ -10161,15 +10162,30 @@ export class Compiler extends DiagnosticEmitter {
10161
10162
reportNode
10162
10163
) ) {
10163
10164
this . currentType = stringType ;
10164
- return this . module . unreachable ( ) ;
10165
+ return module . unreachable ( ) ;
10165
10166
}
10166
10167
if ( ! type . isStrictlyAssignableTo ( assert ( toStringSignature . thisType ) ) ) {
10167
- this . errorRelated (
10168
- DiagnosticCode . The_this_types_of_each_signature_are_incompatible ,
10169
- reportNode . range , toStringInstance . identifierAndSignatureRange
10168
+ if ( ! type . is ( TypeFlags . Nullable ) ) {
10169
+ this . errorRelated (
10170
+ DiagnosticCode . The_this_types_of_each_signature_are_incompatible ,
10171
+ reportNode . range , toStringInstance . identifierAndSignatureRange
10172
+ ) ;
10173
+ this . currentType = stringType ;
10174
+ return module . unreachable ( ) ;
10175
+ }
10176
+
10177
+ // Attempt to retry on the non-nullable form of the type, wrapped in a ternary:
10178
+ // `expr ? expr.toString() : "null"`
10179
+ const tempLocal = this . currentFlow . getTempLocal ( type ) ;
10180
+ return module . if (
10181
+ module . local_tee ( tempLocal . index , expr , type . isManaged ) ,
10182
+ this . makeToString (
10183
+ module . local_get ( tempLocal . index , type . toRef ( ) ) ,
10184
+ type . nonNullableType ,
10185
+ reportNode
10186
+ ) ,
10187
+ this . ensureStaticString ( "null" )
10170
10188
) ;
10171
- this . currentType = stringType ;
10172
- return this . module . unreachable ( ) ;
10173
10189
}
10174
10190
let toStringReturnType = toStringSignature . returnType ;
10175
10191
if ( ! toStringReturnType . isStrictlyAssignableTo ( stringType ) ) {
@@ -10178,7 +10194,7 @@ export class Compiler extends DiagnosticEmitter {
10178
10194
reportNode . range , toStringInstance . identifierAndSignatureRange , toStringReturnType . toString ( ) , stringType . toString ( )
10179
10195
) ;
10180
10196
this . currentType = stringType ;
10181
- return this . module . unreachable ( ) ;
10197
+ return module . unreachable ( ) ;
10182
10198
}
10183
10199
return this . makeCallDirect ( toStringInstance , [ expr ] , reportNode ) ;
10184
10200
}
@@ -10188,7 +10204,7 @@ export class Compiler extends DiagnosticEmitter {
10188
10204
reportNode . range , type . toString ( ) , stringType . toString ( )
10189
10205
) ;
10190
10206
this . currentType = stringType ;
10191
- return this . module . unreachable ( ) ;
10207
+ return module . unreachable ( ) ;
10192
10208
}
10193
10209
10194
10210
/** Makes an allocation suitable to hold the data of an instance of the given class. */
0 commit comments