@@ -10145,6 +10145,7 @@ export class Compiler extends DiagnosticEmitter {
1014510145
1014610146 /** Makes a string conversion of the given expression. */
1014710147 makeToString ( expr : ExpressionRef , type : Type , reportNode : Node ) : ExpressionRef {
10148+ let module = this . module ;
1014810149 let stringType = this . program . stringInstance . type ;
1014910150 if ( type == stringType ) {
1015010151 return expr ;
@@ -10161,15 +10162,30 @@ export class Compiler extends DiagnosticEmitter {
1016110162 reportNode
1016210163 ) ) {
1016310164 this . currentType = stringType ;
10164- return this . module . unreachable ( ) ;
10165+ return module . unreachable ( ) ;
1016510166 }
1016610167 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" )
1017010188 ) ;
10171- this . currentType = stringType ;
10172- return this . module . unreachable ( ) ;
1017310189 }
1017410190 let toStringReturnType = toStringSignature . returnType ;
1017510191 if ( ! toStringReturnType . isStrictlyAssignableTo ( stringType ) ) {
@@ -10178,7 +10194,7 @@ export class Compiler extends DiagnosticEmitter {
1017810194 reportNode . range , toStringInstance . identifierAndSignatureRange , toStringReturnType . toString ( ) , stringType . toString ( )
1017910195 ) ;
1018010196 this . currentType = stringType ;
10181- return this . module . unreachable ( ) ;
10197+ return module . unreachable ( ) ;
1018210198 }
1018310199 return this . makeCallDirect ( toStringInstance , [ expr ] , reportNode ) ;
1018410200 }
@@ -10188,7 +10204,7 @@ export class Compiler extends DiagnosticEmitter {
1018810204 reportNode . range , type . toString ( ) , stringType . toString ( )
1018910205 ) ;
1019010206 this . currentType = stringType ;
10191- return this . module . unreachable ( ) ;
10207+ return module . unreachable ( ) ;
1019210208 }
1019310209
1019410210 /** Makes an allocation suitable to hold the data of an instance of the given class. */
0 commit comments