@@ -1440,17 +1440,37 @@ export class Compiler extends DiagnosticEmitter {
1440
1440
var nativeThisType = this . options . nativeSizeType ;
1441
1441
var nativeValueType = type . toNativeType ( ) ;
1442
1442
var module = this . module ;
1443
- var valueExpr = module . local_get ( 1 , nativeValueType ) ;
1443
+ var valueExpr : ExpressionRef ;
1444
+ var varTypes : NativeType [ ] | null = null ;
1444
1445
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
+ ] )
1449
1466
) ,
1450
- valueExpr
1451
- ) ;
1467
+ module . local_get ( 1 , nativeValueType )
1468
+ ] , nativeValueType ) ;
1469
+ varTypes = [ nativeValueType ] ;
1470
+ } else {
1471
+ valueExpr = module . local_get ( 1 , nativeValueType ) ;
1452
1472
}
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 ,
1454
1474
module . store ( type . byteSize ,
1455
1475
module . local_get ( 0 , nativeThisType ) ,
1456
1476
valueExpr ,
@@ -2652,7 +2672,7 @@ export class Compiler extends DiagnosticEmitter {
2652
2672
type = resolver . resolveType ( // reports
2653
2673
declaration . type ,
2654
2674
flow . actualFunction ,
2655
- flow . contextualTypeArguments
2675
+ makeMap ( flow . contextualTypeArguments )
2656
2676
) ;
2657
2677
if ( ! type ) continue ;
2658
2678
if ( declaration . initializer ) {
@@ -3444,7 +3464,7 @@ export class Compiler extends DiagnosticEmitter {
3444
3464
let toType = this . resolver . resolveType ( // reports
3445
3465
assert ( expression . toType ) ,
3446
3466
flow . actualFunction ,
3447
- flow . contextualTypeArguments
3467
+ makeMap ( flow . contextualTypeArguments )
3448
3468
) ;
3449
3469
if ( ! toType ) return this . module . unreachable ( ) ;
3450
3470
return this . compileExpression ( expression . expression , toType , inheritedConstraints | Constraints . CONV_EXPLICIT ) ;
@@ -6702,7 +6722,14 @@ export class Compiler extends DiagnosticEmitter {
6702
6722
}
6703
6723
6704
6724
/** 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 {
6706
6733
var module = this . module ;
6707
6734
var flow = this . currentFlow ;
6708
6735
var nativeSizeType = this . options . nativeSizeType ;
@@ -7644,9 +7671,14 @@ export class Compiler extends DiagnosticEmitter {
7644
7671
// time of implementation, this seemed more useful because dynamic rhs expressions are not
7645
7672
// possible in AS anyway. also note that the code generated below must preserve side-effects of
7646
7673
// the LHS expression even when the result is a constant, i.e. return a block dropping `expr`.
7674
+ var flow = this . currentFlow ;
7647
7675
var expr = this . compileExpression ( expression . expression , this . options . usizeType ) ;
7648
7676
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
+ ) ;
7650
7682
this . currentType = Type . bool ;
7651
7683
if ( ! expectedType ) return module . unreachable ( ) ;
7652
7684
@@ -7687,7 +7719,6 @@ export class Compiler extends DiagnosticEmitter {
7687
7719
if ( expectedType . isAssignableTo ( actualType ) ) {
7688
7720
let program = this . program ;
7689
7721
if ( ! ( actualType . isUnmanaged || expectedType . isUnmanaged ) ) {
7690
- let flow = this . currentFlow ;
7691
7722
let temp = flow . getTempLocal ( actualType ) ;
7692
7723
let instanceofInstance = assert ( program . instanceofInstance ) ;
7693
7724
this . compileFunction ( instanceofInstance ) ;
@@ -7737,7 +7768,6 @@ export class Compiler extends DiagnosticEmitter {
7737
7768
// FIXME: the temp local and the if can be removed here once flows
7738
7769
// perform null checking, which would error earlier when checking
7739
7770
// uninitialized (thus zero) `var a: A` to be an instance of something.
7740
- let flow = this . currentFlow ;
7741
7771
let temp = flow . getTempLocal ( actualType ) ;
7742
7772
let instanceofInstance = assert ( program . instanceofInstance ) ;
7743
7773
this . compileFunction ( instanceofInstance ) ;
0 commit comments