Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug][compiler-v2] Move v2 compiler enum destruction via pattern matching is broken #14813

Closed
alnoki opened this issue Sep 30, 2024 · 1 comment · Fixed by #14987
Closed

[Bug][compiler-v2] Move v2 compiler enum destruction via pattern matching is broken #14813

alnoki opened this issue Sep 30, 2024 · 1 comment · Fixed by #14987
Assignees
Labels

Comments

@alnoki
Copy link
Contributor

alnoki commented Sep 30, 2024

Background

@brmataptos @fEst1ck @georgemitenkov @rahxephon89 @runtian-zhou @vineethk @wrwg

I'm trying to do enum destuction via pattern matching but it is
throwing a compiler bug:

bug: bytecode verification failed with unexpected status code `CONSTRAINT_NOT_SATISFIED`. This is a compiler bug, consider reporting it.
    ┌─ /Users/me/the/code
    │
  1 │ ╭ module hello_wolfgang::red_black_map {
  2 │ │
  3 │ │     use std::vector;
  4 │ │
    · │
135 │ │     }
136 │ │ }
    │ ╰─^

Specifically, the problematic code is the simple function contains (see
code listing at bottom), because the module compiles just fine without this
function.

        match (self.search(key)) {
            Found { .. } => true,
            NotFound { .. } => false
        }

I am unable to use the fully-qualified syntax:

    public fun contains<V>(self: &Map<V>, key: u256): bool {
        match (self.search(key)) {
            Found { node: _, side_as_child: _ } => true,
            NotFound { prospective_parent: _, prospective_side_as_child: _ } => false
        }
    }

Nor can I use the is keyword:

    public fun contains<V>(self: &Map<V>, key: u256): bool {
        if (self.search(key) is SearchResult::Found) {
            true
        } else {
            false
        }
    }
  1. Could it be a result of using nested enums?
  2. I think I've exhausted all of the syntactical methods for doing this simple
    match compare, so is there something else I can do in the interim while this
    gets patched?

Code listing

module hello_wolfgang::red_black_map {

    use std::vector;

    enum Color has copy, drop {
        Red,
        Black
    }

    enum Pointer has copy, drop {
        Index(u64),
        Null
    }

    enum Side has copy, drop {
        Left,
        Right,
        Null
    }

    enum SearchResult has copy, drop {
        Found {
            node: Pointer,
            side_as_child: Side
        },
        NotFound {
            prospective_parent: Pointer,
            prospective_side_as_child: Side
        }
    }

    struct Node<V> has drop {
        key: u256,
        value: V,
        color: Color,
        parent: Pointer,
        left: Pointer,
        right: Pointer
    }

    struct Map<V> has drop {
        root: Pointer,
        nodes: vector<Node<V>>
    }

    public fun new<V>(): Map<V> {
        Map { root: Pointer::Null, nodes: vector::empty() }
    }

    public fun contains<V>(self: &Map<V>, key: u256): bool {
        match (self.search(key)) {
            Found { .. } => true,
            NotFound { .. } => false
        }
    }

    public fun insert<V: drop>(self: &mut Map<V>, key: u256, value: V) {
        match(self.root) {
            Null => {
                self.nodes.push_back(
                    Node {
                        key: key,
                        value: value,
                        color: Color::Black,
                        parent: Pointer::Null,
                        left: Pointer::Null,
                        right: Pointer::Null
                    }
                );
                self.root = Pointer::Index(0);
            }
            _ => {}
        }
    }

    fun search<V: drop>(self: &Map<V>, key: u256): SearchResult {
        let side_as_child = Side::Null;
        match(self.root) {
            Null => {
                return SearchResult::NotFound {
                    prospective_parent: Pointer::Null,
                    prospective_side_as_child: side_as_child
                }
            }
            Index(index) => {
                loop {
                    let node = &self.nodes[index];
                    if (key < node.key) {
                        match(node.left) {
                            Index(next_index) => {
                                index = next_index;
                                side_as_child = Side::Left;
                            }
                            Null => {
                                return SearchResult::NotFound {
                                    prospective_parent: Pointer::Index(index),
                                    prospective_side_as_child: Side::Left
                                };
                            }
                        }
                    } else if (key > node.key) {
                        match(node.right) {
                            Index(next_index) => {
                                index = next_index;
                                side_as_child = Side::Right;
                            }
                            Null => {
                                return SearchResult::NotFound {
                                    prospective_parent: Pointer::Index(index),
                                    prospective_side_as_child: Side::Right
                                };
                            }
                        }
                    } else {
                        return SearchResult::Found {
                            node: Pointer::Index(index),
                            side_as_child: side_as_child
                        };
                    }
                }
            }
        }
    }

    public fun length<V>(self: &Map<V>): u64 {
        self.nodes.length()
    }

    #[test]
    fun test_insert_length() {
        let map = new();
        assert!(map.length() == 0);
        map.insert(1, 1);
        assert!(map.length() == 1);
    }
}
@alnoki alnoki added the bug Something isn't working label Sep 30, 2024
@alnoki alnoki changed the title [Bug] Move v2 compiler enum destruction via pattern matching is broken [Bug][compiler-v2] Move v2 compiler enum destruction via pattern matching is broken Oct 1, 2024
@wrwg wrwg self-assigned this Oct 3, 2024
@wrwg
Copy link
Contributor

wrwg commented Oct 16, 2024

This is actually a bug in the v2 compiler ability checker (which is then caught by the bytecode verifier which is run at end of compilation. The minimal repro is:

module 0x815::red_black_map {

    struct Map<phantom V> has drop {
    }

    public fun contains<V>(self: &Map<V>, key: u256): bool {
        self.search(key)
    }

    fun search<V: drop>(self: &Map<V>, key: u256): bool {
        true
    }
}

search can't be called since the contains V does not have the drop ability. The compiler should have complained but it did not.

So no need to stop using enums.

Thanks for reporting, we send out fix soon.

wrwg added a commit that referenced this issue Oct 16, 2024
… displaying message in compiler pipeline.

This also demonstrates the problem with bug #14813
wrwg added a commit that referenced this issue Oct 16, 2024
…ameters

Closes #14813

The first commit here demonstrates the error and improves on how we display bytecode verification errors, the 2nd fixes the issue in the compiler.
wrwg added a commit that referenced this issue Oct 18, 2024
… displaying message in compiler pipeline.

This also demonstrates the problem with bug #14813
wrwg added a commit that referenced this issue Oct 18, 2024
…ameters

Closes #14813

The first commit here demonstrates the error and improves on how we display bytecode verification errors, the 2nd fixes the issue in the compiler.
@wrwg wrwg closed this as completed in 1645c96 Oct 18, 2024
@github-project-automation github-project-automation bot moved this from 🆕 New to ✅ Done in Move Language and Runtime Oct 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

3 participants