@@ -9859,3 +9859,150 @@ func TestCheckOptionalBindingElseBranch(t *testing.T) {
98599859	errs  :=  RequireCheckerErrors (t , err , 1 )
98609860	assert .IsType (t , & sema.ResourceUseAfterInvalidationError {}, errs [0 ])
98619861}
9862+ 
9863+ func  TestCheckResourceSecondValueTransfer (t  * testing.T ) {
9864+ 
9865+ 	t .Parallel ()
9866+ 
9867+ 	t .Run ("basic array invalid" , func (t  * testing.T ) {
9868+ 		t .Parallel ()
9869+ 
9870+ 		_ , err  :=  ParseAndCheck (t , ` 
9871+             resource R {} 
9872+ 
9873+             access(all) fun main() { 
9874+                 let vaults: @[AnyResource] <- [<-[]] 
9875+                 let old <- vaults[0] <- vaults 
9876+                 destroy old 
9877+             } 
9878+         ` )
9879+ 
9880+ 		errs  :=  RequireCheckerErrors (t , err , 1 )
9881+ 		assert .IsType (t , & sema.ResourceUseAfterInvalidationError {}, errs [0 ])
9882+ 	})
9883+ 
9884+ 	t .Run ("basic array" , func (t  * testing.T ) {
9885+ 		t .Parallel ()
9886+ 
9887+ 		_ , err  :=  ParseAndCheck (t , ` 
9888+             resource R {} 
9889+ 
9890+             access(all) fun main() { 
9891+                 let vaults: @[AnyResource] <- [<-[]] 
9892+                 let bar <- create R() 
9893+                 let old <- vaults[0] <- bar 
9894+                 destroy old 
9895+                 destroy vaults 
9896+             } 
9897+         ` )
9898+ 
9899+ 		require .NoError (t , err )
9900+ 	})
9901+ 
9902+ 	t .Run ("basic function call invalid" , func (t  * testing.T ) {
9903+ 		t .Parallel ()
9904+ 
9905+ 		_ , err  :=  ParseAndCheck (t , ` 
9906+             resource R {} 
9907+ 
9908+             access(all) fun foo(_ r: @R): @R { 
9909+                 return <-r  
9910+             } 
9911+ 
9912+             access(all) fun main() { 
9913+                 var r <- create R() 
9914+                 let r2 <- r <- foo(<-r) 
9915+                 destroy r2 
9916+                 // note that r is still "valid" after the two value transfer so we must destroy it 
9917+                 destroy r 
9918+             } 
9919+         ` )
9920+ 
9921+ 		errs  :=  RequireCheckerErrors (t , err , 1 )
9922+ 		assert .IsType (t , & sema.ResourceUseAfterInvalidationError {}, errs [0 ])
9923+ 	})
9924+ 
9925+ 	t .Run ("basic function call valid" , func (t  * testing.T ) {
9926+ 		t .Parallel ()
9927+ 
9928+ 		_ , err  :=  ParseAndCheck (t , ` 
9929+             resource R {} 
9930+ 
9931+             access(all) fun foo(_ r: @R): @R { 
9932+                 return <-r  
9933+             } 
9934+ 
9935+             access(all) fun main() { 
9936+                 var r <- create R() 
9937+                 var bar <- create R() 
9938+                 let r2 <- r <- foo(<-bar) 
9939+                 destroy r2 
9940+                 destroy r 
9941+             } 
9942+         ` )
9943+ 
9944+ 		require .NoError (t , err )
9945+ 	})
9946+ 
9947+ 	t .Run ("invalid" , func (t  * testing.T ) {
9948+ 		t .Parallel ()
9949+ 
9950+ 		_ , err  :=  ParseAndCheck (t , ` 
9951+             access(all) resource R{} 
9952+ 
9953+             access(all) fun collect(copy2: @R?, _ arrRef: auth(Mutate) &[R]): @R { 
9954+                 arrRef.append(<- copy2!) 
9955+                 return <- create R() 
9956+             } 
9957+              
9958+             access(all) fun main() { 
9959+                 var victim: @R? <- create R() 
9960+                 var arr: @[R] <- [] 
9961+              
9962+                 // In the optional binding below, the 'victim' must be invalidated 
9963+                 // before evaluation of the collect() call 
9964+                 let copy1 <- victim <- collect(copy2: <- victim, &arr as auth(Mutate) &[R]) 
9965+              
9966+                 // Panics when trying to destroy 
9967+                 destroy copy1 
9968+                 destroy arr     
9969+                 destroy victim 
9970+             } 
9971+         ` )
9972+ 
9973+ 		errs  :=  RequireCheckerErrors (t , err , 1 )
9974+ 		assert .IsType (t , & sema.ResourceUseAfterInvalidationError {}, errs [0 ])
9975+ 	})
9976+ 
9977+ 	t .Run ("regression" , func (t  * testing.T ) {
9978+ 		t .Parallel ()
9979+ 
9980+ 		_ , err  :=  ParseAndCheck (t , ` 
9981+             access(all) resource R{} 
9982+ 
9983+             access(all) fun collect(copy2: @R?, _ arrRef: auth(Mutate) &[R]): @R { 
9984+                 arrRef.append(<- copy2!) 
9985+                 return <- create R() 
9986+             } 
9987+              
9988+             access(all) fun main() { 
9989+                 var victim: @R? <- create R() 
9990+                 var arr: @[R] <- [] 
9991+              
9992+                 if let copy1 <- victim <- collect(copy2: <- victim, &arr as auth(Mutate) &[R]) { 
9993+                     var ignore = &victim as &R? 
9994+                     arr.append(<- copy1) 
9995+                     destroy victim 
9996+                 } else { 
9997+                     destroy victim // Never executed 
9998+                 } 
9999+                  
10000+                 destroy arr 
10001+             } 
10002+         ` )
10003+ 
10004+ 		errs  :=  RequireCheckerErrors (t , err , 1 )
10005+ 		// we'd like to only report one error here (i.e. in `copy2: <- victim`, not `&victim as &R?`) 
10006+ 		assert .IsType (t , & sema.ResourceUseAfterInvalidationError {}, errs [0 ])
10007+ 	})
10008+ }
0 commit comments