Skip to content

Commit

Permalink
Merge pull request #3368 from onflow/sainati/casting-move-precedence
Browse files Browse the repository at this point in the history
Decrease move operator precedence relative to cast operators
  • Loading branch information
dsainati1 authored May 31, 2024
2 parents 30a0604 + bd88a14 commit 499c877
Show file tree
Hide file tree
Showing 3 changed files with 195 additions and 1 deletion.
3 changes: 2 additions & 1 deletion runtime/parser/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const (
exprLeftBindingPowerBitwiseShift
exprLeftBindingPowerAddition
exprLeftBindingPowerMultiplication
exprLeftBindingPowerMove
exprLeftBindingPowerCasting
exprLeftBindingPowerUnaryPrefix
exprLeftBindingPowerUnaryPostfix
Expand Down Expand Up @@ -484,7 +485,7 @@ func init() {

defineExpr(unaryExpr{
tokenType: lexer.TokenLeftArrow,
bindingPower: exprLeftBindingPowerUnaryPrefix,
bindingPower: exprLeftBindingPowerMove,
operation: ast.OperationMove,
})

Expand Down
105 changes: 105 additions & 0 deletions runtime/parser/expression_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,111 @@ func TestParseAdvancedExpression(t *testing.T) {
)
})

t.Run("move operator, force casted", func(t *testing.T) {

t.Parallel()

result, errs := testParseExpression("<-x as! @T")
require.Empty(t, errs)

utils.AssertEqualWithDiff(t,
&ast.UnaryExpression{
Operation: ast.OperationMove,
Expression: &ast.CastingExpression{
Expression: &ast.IdentifierExpression{
Identifier: ast.Identifier{
Identifier: "x",
Pos: ast.Position{Line: 1, Column: 2, Offset: 2},
},
},
TypeAnnotation: &ast.TypeAnnotation{
Type: &ast.NominalType{
Identifier: ast.Identifier{
Identifier: "T",
Pos: ast.Position{Line: 1, Column: 9, Offset: 9},
},
},
StartPos: ast.Position{Line: 1, Column: 8, Offset: 8},
IsResource: true,
},
Operation: ast.OperationForceCast,
},
StartPos: ast.Position{Line: 1, Column: 0, Offset: 0},
},
result,
)
})

t.Run("move operator, failable casted", func(t *testing.T) {

t.Parallel()

result, errs := testParseExpression("<-x as? @T")
require.Empty(t, errs)

utils.AssertEqualWithDiff(t,
&ast.UnaryExpression{
Operation: ast.OperationMove,
Expression: &ast.CastingExpression{
Expression: &ast.IdentifierExpression{
Identifier: ast.Identifier{
Identifier: "x",
Pos: ast.Position{Line: 1, Column: 2, Offset: 2},
},
},
TypeAnnotation: &ast.TypeAnnotation{
Type: &ast.NominalType{
Identifier: ast.Identifier{
Identifier: "T",
Pos: ast.Position{Line: 1, Column: 9, Offset: 9},
},
},
StartPos: ast.Position{Line: 1, Column: 8, Offset: 8},
IsResource: true,
},
Operation: ast.OperationFailableCast,
},
StartPos: ast.Position{Line: 1, Column: 0, Offset: 0},
},
result,
)
})

t.Run("move operator, casted", func(t *testing.T) {

t.Parallel()

result, errs := testParseExpression("<-x as @T")
require.Empty(t, errs)

utils.AssertEqualWithDiff(t,
&ast.UnaryExpression{
Operation: ast.OperationMove,
Expression: &ast.CastingExpression{
Expression: &ast.IdentifierExpression{
Identifier: ast.Identifier{
Identifier: "x",
Pos: ast.Position{Line: 1, Column: 2, Offset: 2},
},
},
TypeAnnotation: &ast.TypeAnnotation{
Type: &ast.NominalType{
Identifier: ast.Identifier{
Identifier: "T",
Pos: ast.Position{Line: 1, Column: 8, Offset: 8},
},
},
StartPos: ast.Position{Line: 1, Column: 7, Offset: 7},
IsResource: true,
},
Operation: ast.OperationCast,
},
StartPos: ast.Position{Line: 1, Column: 0, Offset: 0},
},
result,
)
})

}

func TestParseArrayExpression(t *testing.T) {
Expand Down
88 changes: 88 additions & 0 deletions runtime/tests/checker/move_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,91 @@ func TestCheckInvalidMoves(t *testing.T) {
require.ErrorAs(t, errors[1], &invalidMoveError)
})
}

func TestCheckCastedMove(t *testing.T) {

t.Parallel()

t.Run("force", func(t *testing.T) {
t.Parallel()

_, err := ParseAndCheck(t, `
resource R {}
fun foo(): @R {
let r: @AnyResource <- create R()
return <-r as! @R
}
`)

require.NoError(t, err)
})

t.Run("static", func(t *testing.T) {
t.Parallel()

_, err := ParseAndCheck(t, `
resource R {}
fun foo(): @AnyResource {
let r <- create R()
return <-r as @AnyResource
}
`)

require.NoError(t, err)
})

t.Run("parenthesized", func(t *testing.T) {
t.Parallel()

_, err := ParseAndCheck(t, `
resource R {}
fun foo(): @R {
let r: @AnyResource <- create R()
return <-(r as! @R)
}
`)

require.NoError(t, err)
})

t.Run("function call", func(t *testing.T) {
t.Parallel()

_, err := ParseAndCheck(t, `
resource R {}
fun bar(_ r: @R) {
destroy r
}
fun foo() {
let r: @AnyResource <- create R()
bar(<-r as! @R)
}
`)

require.NoError(t, err)
})

t.Run("function call, parenthesized", func(t *testing.T) {
t.Parallel()

_, err := ParseAndCheck(t, `
resource R {}
fun bar(_ r: @R) {
destroy r
}
fun foo() {
let r: @AnyResource <- create R()
bar(<-(r as! @R))
}
`)

require.NoError(t, err)
})
}

0 comments on commit 499c877

Please sign in to comment.