Skip to content

Fix panic in comparison operators with non-comparable types#990

Open
lawrence3699 wants to merge 1 commit intolmorg:masterfrom
lawrence3699:fix/comparison-panic-noncomparable
Open

Fix panic in comparison operators with non-comparable types#990
lawrence3699 wants to merge 1 commit intolmorg:masterfrom
lawrence3699:fix/comparison-panic-noncomparable

Conversation

@lawrence3699
Copy link
Copy Markdown

Fixes #982

Failing scenario: In non-strict mode, @PWD < 2 (or any expression comparing a non-comparable type like an array with a number via <, >, <=, >=) panics:

panic: interface conversion: interface {} is float64, not string

Root cause: compareTypes() returns mismatched Go types when one operand is non-comparable — the non-comparable side gets JSON-marshaled to a string while the comparable side retains its original Go type (e.g. float64). In expGtLt, the string case branch does rv.(string) without checking the actual type, causing the panic.

Fix: Add a safe type assertion in the string comparison branch. When rv is not already a string, convert it via types.ConvertGoType(rv, types.String) before comparing.

Before: @PWD < 2 → panic
After: @PWD < 2 → returns a boolean (string comparison)

Validation:

  • go test ./lang/expressions/ — all existing tests pass
  • go vet ./lang/expressions/ — clean
  • Added regression tests for both strict and non-strict modes
  • Verified the new test panics without the fix and passes with it

When comparing a non-comparable type (e.g. array) with a number using
<, >, <=, or >= in non-strict mode, expGtLt panicked with
"interface conversion: interface {} is float64, not string" because
compareTypes() can return mismatched Go types — the non-comparable
side is JSON-marshaled to a string while the comparable side retains
its original type (e.g. float64).

Add a safe type assertion in the string comparison branch, converting
the right-hand value to a string via types.ConvertGoType when it is
not already a string.

Fixes lmorg#982
Copilot AI review requested due to automatic review settings April 13, 2026 08:23
@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a panic in expression comparison operators (<, >, <=, >=) when non-comparable types (eg arrays) are compared against comparable types in non-strict mode, addressing issue #982.

Changes:

  • Adds a safe conversion path for the RHS operand in the string-comparison branch to prevent interface conversion panics.
  • Adds regression tests for strict-mode error behavior and non-strict-mode non-panicking behavior when comparing arrays with numbers.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
lang/expressions/exp06.go Prevents panic by safely converting rv to string when the comparison is routed through the string branch.
lang/expressions/exp06_test.go Adds regression tests covering strict vs non-strict comparisons involving non-comparable types.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +36 to +40
v, convErr := types.ConvertGoType(rv, types.String)
if convErr != nil {
return raiseError(tree.expression, tree.currentSymbol(), 0, fmt.Sprintf(
"cannot %s with %s types", tree.currentSymbol().key, left.Primitive,
))
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When converting rv to a string fails, the returned error message drops the underlying convErr details and doesn’t mention the right-hand operand type/value. Consider including convErr.Error() (and ideally both operand primitives/Go types) so users can understand why the comparison cannot be performed instead of only seeing cannot < with <left> types.

Copilot uses AI. Check for mistakes.
{
Expression: `2 < %[1,2,3]`,
Expected: false,
},
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regression test for non-strict mode only covers < and > cases. Since the fix is inside expGtLt (shared by <, <=, > and >=), add non-strict assertions for <= and >= (both operand orders) to ensure those operators also won’t panic and to lock in expected behavior.

Suggested change
},
},
{
Expression: `%[1,2,3] <= 2`,
Expected: false,
},
{
Expression: `2 >= %[1,2,3]`,
Expected: true,
},
{
Expression: `%[1,2,3] >= 2`,
Expected: true,
},
{
Expression: `2 <= %[1,2,3]`,
Expected: false,
},

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

panic: interface conversion in expressions comparison

2 participants