Skip to content

[Feature Request] Compiler should auto-insert references for == and != #16620

@vineethk

Description

@vineethk

🚀 Feature Request

Summary

For any non-reference operands of == and !=, the compiler should automatically insert references. This would:

  • make generated programs more efficient
  • should be backwards-compatible at the source level
  • make it consistent with the new comparison operators being added

Details

Note that currently, we can use == (or correspondingly !=) on values or references. When used on a value, that value needs to have drop ability (enforced by the compiler and the static bytecode verifier).

If the value has copy ability, and we have x == y, the compiler could end up making copies of x and y (specifically, the compiler inserts copies if x or y are alive after). We have a lint rule to detect this case and warn: https://aptos.dev/en/build/smart-contracts/linter#avoid_copy_on_identity_comparison. By implementing this feature, we can get rid of this lint (as the compiler automatically does what this lint was suggesting we do).

I believe it should be generally backwards compatible for the compiler to automatically insert references when using == or != on non-reference values. We would accept all programs we would previously accept, but also accept some programs that we would previous reject.

Consider the program:

    struct W {
        x: u64,
    }

    fun foo(x: W, y: W): u64 {
        if (x == y) {
            1
        } else {
            2
        }
    }

We get compiler errors that W is not droppable.

By adding reference to the operands of ==:

    fun foo_ref_inserted(x: W, y: W): u64 {
        if (&x == &y) {
            1
        } else {
            2
        }
    }

This also gives compiler errors about non-droppability, but the error messages are slightly different.

On the other hand, consider this program:

    struct W has copy {
        x: u64,
    }

    fun foo(x: W, y: W): (W, W) {
        if (x == y) {
            (x, y)
        } else {
            (y, x)
        }
    }

Fails compilation because == drops the value.

But by adding references to the operands of ==, the program compiles okay.

    struct W has copy {
        x: u64,
    }

    fun foo(x: W, y: W): (W, W) {
        if (&x == &y) {
            (x, y)
        } else {
            (y, x)
        }
    }

Similarly, this is not accepted by the compiler:

    struct W has drop {
        x: u64,
    }

    fun foo(x: W, y: W): (W, W) {
        if (x == y) {
            (x, y)
        } else {
            (y, x)
        }
    }

But the following reference-inserted version is:

    struct W has drop {
        x: u64,
    }

    fun foo(x: W, y: W): (W, W) {
        if (&x == &y) {
            (x, y)
        } else {
            (y, x)
        }
    }

Metadata

Metadata

Assignees

Projects

Status

Assigned

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions