From 20e98d9fee4dca2c9bccfd64ec2bbdc948780e8c Mon Sep 17 00:00:00 2001 From: Supun Setunga Date: Fri, 7 Jun 2024 13:13:56 -0700 Subject: [PATCH] Simplify nil-coalescing checking --- runtime/sema/check_binary_expression.go | 27 +------------------- runtime/tests/checker/nil_coalescing_test.go | 27 +++++++++++++++----- runtime/tests/checker/resources_test.go | 18 +++++++++++++ 3 files changed, 40 insertions(+), 32 deletions(-) diff --git a/runtime/sema/check_binary_expression.go b/runtime/sema/check_binary_expression.go index b4f77fbc2d..0d52b3512e 100644 --- a/runtime/sema/check_binary_expression.go +++ b/runtime/sema/check_binary_expression.go @@ -441,13 +441,6 @@ func (checker *Checker) checkBinaryExpressionNilCoalescing( return InvalidType } - leftInner := leftOptional.Type - - if leftInner == NeverType { - return rightType - } - canNarrow := false - if !rightIsInvalid { if rightType.IsResourceType() { @@ -458,25 +451,7 @@ func (checker *Checker) checkBinaryExpressionNilCoalescing( }, ) } - - if !IsSubType(rightType, leftOptional) { - - checker.report( - &InvalidBinaryOperandError{ - Operation: operation, - Side: common.OperandSideRight, - ExpectedType: leftOptional, - ActualType: rightType, - Range: ast.NewRangeFromPositioned(checker.memoryGauge, expression.Right), - }, - ) - } else { - canNarrow = IsSubType(rightType, leftInner) - } } - if !canNarrow { - return leftOptional - } - return leftInner + return LeastCommonSuperType(leftOptional.Type, rightType) } diff --git a/runtime/tests/checker/nil_coalescing_test.go b/runtime/tests/checker/nil_coalescing_test.go index 729569cc9f..aea40272d1 100644 --- a/runtime/tests/checker/nil_coalescing_test.go +++ b/runtime/tests/checker/nil_coalescing_test.go @@ -159,14 +159,29 @@ func TestCheckInvalidNilCoalescingNonMatchingTypes(t *testing.T) { t.Parallel() - _, err := ParseAndCheck(t, ` - let x: Int? = 1 - let y = x ?? false - `) + t.Run("with super type", func(t *testing.T) { + t.Parallel() - errs := RequireCheckerErrors(t, err, 1) + _, err := ParseAndCheck(t, ` + let x: Int? = 1 + let y = x ?? false + `) + + require.NoError(t, err) + }) + + t.Run("no super type", func(t *testing.T) { + + t.Parallel() + + _, err := ParseAndCheck(t, ` + let x: Int? = 1 + let y: Int = x ?? false + `) - assert.IsType(t, &sema.InvalidBinaryOperandError{}, errs[0]) + errs := RequireCheckerErrors(t, err, 1) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + }) } func TestCheckNilCoalescingAny(t *testing.T) { diff --git a/runtime/tests/checker/resources_test.go b/runtime/tests/checker/resources_test.go index dee04e29c3..cffe9ba4ac 100644 --- a/runtime/tests/checker/resources_test.go +++ b/runtime/tests/checker/resources_test.go @@ -9936,3 +9936,21 @@ func TestCheckInvalidNestedResourceCapture(t *testing.T) { require.NoError(t, err) }) } + +func TestCheckInvalidOptionalResourceCoalescingRightSideNilLeftSide(t *testing.T) { + t.Parallel() + + _, err := ParseAndCheck(t, ` + resource R {} + fun test() { + let rs: @[R?] <- [nil, nil] + rs[0] <-! create R() + rs[1] <-! nil ?? rs[0] + destroy rs + } + `) + + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.InvalidNilCoalescingRightResourceOperandError{}, errs[0]) +}