@@ -1440,17 +1440,37 @@ export class Compiler extends DiagnosticEmitter {
14401440 var nativeThisType = this . options . nativeSizeType ;
14411441 var nativeValueType = type . toNativeType ( ) ;
14421442 var module = this . module ;
1443- var valueExpr = module . local_get ( 1 , nativeValueType ) ;
1443+ var valueExpr : ExpressionRef ;
1444+ var varTypes : NativeType [ ] | null = null ;
14441445 if ( type . isManaged ) {
1445- valueExpr = this . makeReplace (
1446- module . load ( type . byteSize , false ,
1447- module . local_get ( 0 , nativeThisType ) ,
1448- nativeValueType , instance . memoryOffset
1446+ // Can't use makeReplace here since there's no corresponding flow, so
1447+ // 0: this, 1: value, 2: oldValue (temp)
1448+ valueExpr = module . block ( null , [
1449+ module . if (
1450+ module . binary ( nativeValueType == NativeType . I64 ? BinaryOp . NeI64 : BinaryOp . NeI32 ,
1451+ // value != (oldValue = this.field)
1452+ module . local_get ( 1 , nativeValueType ) ,
1453+ module . local_tee ( 2 ,
1454+ module . load ( type . byteSize , false ,
1455+ module . local_get ( 0 , nativeThisType ) ,
1456+ nativeValueType , instance . memoryOffset
1457+ )
1458+ )
1459+ ) ,
1460+ module . block ( null , [
1461+ module . drop (
1462+ this . makeRetain ( module . local_get ( 1 , nativeValueType ) )
1463+ ) ,
1464+ this . makeRelease ( module . local_get ( 2 , nativeValueType ) )
1465+ ] )
14491466 ) ,
1450- valueExpr
1451- ) ;
1467+ module . local_get ( 1 , nativeValueType )
1468+ ] , nativeValueType ) ;
1469+ varTypes = [ nativeValueType ] ;
1470+ } else {
1471+ valueExpr = module . local_get ( 1 , nativeValueType ) ;
14521472 }
1453- instance . setterRef = module . addFunction ( instance . internalSetterName , createType ( [ nativeThisType , nativeValueType ] ) , NativeType . None , null ,
1473+ instance . setterRef = module . addFunction ( instance . internalSetterName , createType ( [ nativeThisType , nativeValueType ] ) , NativeType . None , varTypes ,
14541474 module . store ( type . byteSize ,
14551475 module . local_get ( 0 , nativeThisType ) ,
14561476 valueExpr ,
@@ -2652,7 +2672,7 @@ export class Compiler extends DiagnosticEmitter {
26522672 type = resolver . resolveType ( // reports
26532673 declaration . type ,
26542674 flow . actualFunction ,
2655- flow . contextualTypeArguments
2675+ makeMap ( flow . contextualTypeArguments )
26562676 ) ;
26572677 if ( ! type ) continue ;
26582678 if ( declaration . initializer ) {
@@ -3444,7 +3464,7 @@ export class Compiler extends DiagnosticEmitter {
34443464 let toType = this . resolver . resolveType ( // reports
34453465 assert ( expression . toType ) ,
34463466 flow . actualFunction ,
3447- flow . contextualTypeArguments
3467+ makeMap ( flow . contextualTypeArguments )
34483468 ) ;
34493469 if ( ! toType ) return this . module . unreachable ( ) ;
34503470 return this . compileExpression ( expression . expression , toType , inheritedConstraints | Constraints . CONV_EXPLICIT ) ;
@@ -6702,7 +6722,14 @@ export class Compiler extends DiagnosticEmitter {
67026722 }
67036723
67046724 /** Makes a replace, retaining the new expression's value and releasing the old expression's value, in this order. */
6705- makeReplace ( oldExpr : ExpressionRef , newExpr : ExpressionRef , alreadyRetained : bool = false ) : ExpressionRef {
6725+ makeReplace (
6726+ /** Old value being replaced. */
6727+ oldExpr : ExpressionRef ,
6728+ /** New value being assigned. */
6729+ newExpr : ExpressionRef ,
6730+ /** Whether the new value is already retained. */
6731+ alreadyRetained : bool = false ,
6732+ ) : ExpressionRef {
67066733 var module = this . module ;
67076734 var flow = this . currentFlow ;
67086735 var nativeSizeType = this . options . nativeSizeType ;
@@ -7644,9 +7671,14 @@ export class Compiler extends DiagnosticEmitter {
76447671 // time of implementation, this seemed more useful because dynamic rhs expressions are not
76457672 // possible in AS anyway. also note that the code generated below must preserve side-effects of
76467673 // the LHS expression even when the result is a constant, i.e. return a block dropping `expr`.
7674+ var flow = this . currentFlow ;
76477675 var expr = this . compileExpression ( expression . expression , this . options . usizeType ) ;
76487676 var actualType = this . currentType ;
7649- var expectedType = this . resolver . resolveType ( expression . isType , this . currentFlow . actualFunction ) ;
7677+ var expectedType = this . resolver . resolveType (
7678+ expression . isType ,
7679+ flow . actualFunction ,
7680+ makeMap ( flow . contextualTypeArguments )
7681+ ) ;
76507682 this . currentType = Type . bool ;
76517683 if ( ! expectedType ) return module . unreachable ( ) ;
76527684
@@ -7687,7 +7719,6 @@ export class Compiler extends DiagnosticEmitter {
76877719 if ( expectedType . isAssignableTo ( actualType ) ) {
76887720 let program = this . program ;
76897721 if ( ! ( actualType . isUnmanaged || expectedType . isUnmanaged ) ) {
7690- let flow = this . currentFlow ;
76917722 let temp = flow . getTempLocal ( actualType ) ;
76927723 let instanceofInstance = assert ( program . instanceofInstance ) ;
76937724 this . compileFunction ( instanceofInstance ) ;
@@ -7737,7 +7768,6 @@ export class Compiler extends DiagnosticEmitter {
77377768 // FIXME: the temp local and the if can be removed here once flows
77387769 // perform null checking, which would error earlier when checking
77397770 // uninitialized (thus zero) `var a: A` to be an instance of something.
7740- let flow = this . currentFlow ;
77417771 let temp = flow . getTempLocal ( actualType ) ;
77427772 let instanceofInstance = assert ( program . instanceofInstance ) ;
77437773 this . compileFunction ( instanceofInstance ) ;
0 commit comments