Repository: aptos-labs/aptos-core (language: python)

Issue:
[compiler] Error message when wrongly using string constants is not useful
Supposed you start with Move and try to create a string constant

```
 string::utf8("<empty>")
```

There is a `b"..."` missing in front of the string, but the error you get is:

```
error: invalid character
   ┌─ /Users/wrwg/play/tn/sources/hello.move:21:35
   │
21 │             Empty => string::utf8("<empty>"),
   │                                   ^ Invalid character: '"'
```

To figure the solution is hard for Move beginners.


Discussion / hints:

Fix patch:
diff --git a/third_party/move/move-compiler/src/parser/lexer.rs b/third_party/move/move-compiler/src/parser/lexer.rs
index 71bfd10c28daa..b2a3439ff182e 100644
--- a/third_party/move/move-compiler/src/parser/lexer.rs
+++ b/third_party/move/move-compiler/src/parser/lexer.rs
@@ -478,6 +478,25 @@ fn find_token(
                 (get_name_token(&text[..len]), len)
             }
         },
+        '"' => {
+            let line = &text.lines().next().unwrap()[1..];
+            match get_string_len(line) {
+                Some(_last_quote) => {
+                    let loc = make_loc(file_hash, start_offset, start_offset);
+                    return Err(Box::new(diag!(
+                        Syntax::InvalidByteString,
+                        (loc, "String literal must begin with b\" (for a byte string) or x\" (for a hex string)")
+                    )));
+                },
+                None => {
+                    let loc = make_loc(file_hash, start_offset, start_offset);
+                    return Err(Box::new(diag!(
+                        Syntax::InvalidCharacter,
+                        (loc, format!("Invalid character: '{}'; string literal must begin with `b\"` and closing quote `\"` must appear on same line", c))
+                    )));
+                },
+            }
+        },
         '&' => {
             if text.starts_with("&mut ") {
                 (Tok::AmpMut, 5)


Test patch:
diff --git a/third_party/move/move-compiler-v2/tests/folding/constants_hexstring.exp b/third_party/move/move-compiler-v2/tests/folding/constants_hexstring.exp
new file mode 100644
index 0000000000000..3cd2419cbd2dc
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/folding/constants_hexstring.exp
@@ -0,0 +1,13 @@
+
+Diagnostics:
+error: invalid hex string
+  ┌─ tests/folding/constants_hexstring.move:6:29
+  │
+6 │     const C12: vector<u8> = x"hello";
+  │                             ^^^^^^^^ Odd number of characters in hex string. Expected 2 hexadecimal digits for each byte
+
+error: invalid hex string
+  ┌─ tests/folding/constants_hexstring.move:7:31
+  │
+7 │     const C13: vector<u8> = x"hello!";
+  │                               ^ Invalid hexadecimal character: 'h'
diff --git a/third_party/move/move-compiler-v2/tests/folding/constants_hexstring.move b/third_party/move/move-compiler-v2/tests/folding/constants_hexstring.move
new file mode 100644
index 0000000000000..db5e628e6bac1
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/folding/constants_hexstring.move
@@ -0,0 +1,9 @@
+address 0x42 {
+module M {
+    fun u(): u64 { 0 }
+
+    const C11: vector<u8> = x"deadbeef";
+    const C12: vector<u8> = x"hello";
+    const C13: vector<u8> = x"hello!";
+}
+}
diff --git a/third_party/move/move-compiler-v2/tests/folding/constants_quoted_string.exp b/third_party/move/move-compiler-v2/tests/folding/constants_quoted_string.exp
new file mode 100644
index 0000000000000..6cffcc2f11976
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/folding/constants_quoted_string.exp
@@ -0,0 +1,7 @@
+
+Diagnostics:
+error: invalid byte string
+  ┌─ tests/folding/constants_quoted_string.move:5:29
+  │
+5 │     const C12: vector<u8> = "<empty>";
+  │                             ^ String literal must begin with b" (for a byte string) or x" (for a hex string)
diff --git a/third_party/move/move-compiler-v2/tests/folding/constants_quoted_string.move b/third_party/move/move-compiler-v2/tests/folding/constants_quoted_string.move
new file mode 100644
index 0000000000000..a51de933b4e29
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/folding/constants_quoted_string.move
@@ -0,0 +1,8 @@
+address 0x42 {
+module M {
+    fun u(): u64 { 0 }
+
+    const C12: vector<u8> = "<empty>";
+    const C13: vector<u8> = "foo;
+}
+}
diff --git a/third_party/move/move-compiler-v2/tests/folding/constants_simple.move b/third_party/move/move-compiler-v2/tests/folding/constants_simple.move
index dc5e980cf6a65..36ea3929b3d70 100644
--- a/third_party/move/move-compiler-v2/tests/folding/constants_simple.move
+++ b/third_party/move/move-compiler-v2/tests/folding/constants_simple.move
@@ -11,6 +11,9 @@ module M {
     const C7: u256 = 4 / 3 + 4 - 1 << 143;
     const C8: u16 = 123;
     const C9: u32 = (453 as u32);
-
+    const C10: vector<u8> = b"<empty>";
+    const C11: vector<u8> = x"deadbeef";
+    const C12: vector<u8> = b"\"foo\"";
+    const C13: vector<u8> = b"\"\x48";
 }
 }
diff --git a/third_party/move/move-compiler-v2/tests/folding/constants_single_quote.exp b/third_party/move/move-compiler-v2/tests/folding/constants_single_quote.exp
new file mode 100644
index 0000000000000..7719a8e9f4933
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/folding/constants_single_quote.exp
@@ -0,0 +1,7 @@
+
+Diagnostics:
+error: invalid character
+  ┌─ tests/folding/constants_single_quote.move:4:29
+  │
+4 │     const C13: vector<u8> = "foo
+  │                             ^ Invalid character: '"'; string literal must begin with `b"` and closing quote `"` must appear on same line
diff --git a/third_party/move/move-compiler-v2/tests/folding/constants_single_quote.move b/third_party/move/move-compiler-v2/tests/folding/constants_single_quote.move
new file mode 100644
index 0000000000000..5ac99045bd143
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/folding/constants_single_quote.move
@@ -0,0 +1,10 @@
+address 0x42 {
+module M {
+    fun u(): u64 { 0 }
+    const C13: vector<u8> = "foo
+    ";
+    const C14: vector<u8> = "bar";
+    const C15: vector<u8> = b"baz";
+    const C16: vector<u8> = x"quux";
+}
+}
diff --git a/third_party/move/move-compiler-v2/tests/folding/constants_string_non_utf8.exp b/third_party/move/move-compiler-v2/tests/folding/constants_string_non_utf8.exp
new file mode 100644
index 0000000000000..1f4aa39687e2a
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/folding/constants_string_non_utf8.exp
@@ -0,0 +1,7 @@
+
+Diagnostics:
+error: invalid character
+  ┌─ tests/folding/constants_string_non_utf8.move:5:31
+  │
+5 │     const C12: vector<u8> = b"ÿ";
+  │                               ^ Invalid character 'ÿ' found when reading file. Only ASCII printable characters, tabs (\t), lf (\n) and crlf (\r\n) are permitted.
diff --git a/third_party/move/move-compiler-v2/tests/folding/constants_string_non_utf8.move b/third_party/move/move-compiler-v2/tests/folding/constants_string_non_utf8.move
new file mode 100644
index 0000000000000..b1ff20f608048
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/folding/constants_string_non_utf8.move
@@ -0,0 +1,7 @@
+address 0x42 {
+module M {
+    fun u(): u64 { 0 }
+
+    const C12: vector<u8> = b"ÿ";
+}
+}
diff --git a/third_party/move/move-compiler/tests/move_check/parser/constants_hexstring.exp b/third_party/move/move-compiler/tests/move_check/parser/constants_hexstring.exp
new file mode 100644
index 0000000000000..0fa9678e51c46
--- /dev/null
+++ b/third_party/move/move-compiler/tests/move_check/parser/constants_hexstring.exp
@@ -0,0 +1,24 @@
+error[E01008]: invalid hex string
+  ┌─ tests/move_check/parser/constants_hexstring.move:6:29
+  │
+6 │     const C12: vector<u8> = x"hello";
+  │                             ^^^^^^^^ Odd number of characters in hex string. Expected 2 hexadecimal digits for each byte
+
+error[E08001]: cannot compute constant value
+  ┌─ tests/move_check/parser/constants_hexstring.move:6:29
+  │
+6 │     const C12: vector<u8> = x"hello";
+  │                             ^^^^^^^^ Invalid expression in 'const'. This expression could not be evaluated to a value
+
+error[E08001]: cannot compute constant value
+  ┌─ tests/move_check/parser/constants_hexstring.move:7:29
+  │
+7 │     const C13: vector<u8> = x"hello!";
+  │                             ^^^^^^^^^ Invalid expression in 'const'. This expression could not be evaluated to a value
+
+error[E01008]: invalid hex string
+  ┌─ tests/move_check/parser/constants_hexstring.move:7:31
+  │
+7 │     const C13: vector<u8> = x"hello!";
+  │                               ^ Invalid hexadecimal character: 'h'
+
diff --git a/third_party/move/move-compiler/tests/move_check/parser/constants_hexstring.move b/third_party/move/move-compiler/tests/move_check/parser/constants_hexstring.move
new file mode 100644
index 0000000000000..db5e628e6bac1
--- /dev/null
+++ b/third_party/move/move-compiler/tests/move_check/parser/constants_hexstring.move
@@ -0,0 +1,9 @@
+address 0x42 {
+module M {
+    fun u(): u64 { 0 }
+
+    const C11: vector<u8> = x"deadbeef";
+    const C12: vector<u8> = x"hello";
+    const C13: vector<u8> = x"hello!";
+}
+}
diff --git a/third_party/move/move-compiler/tests/move_check/parser/constants_quoted_string.exp b/third_party/move/move-compiler/tests/move_check/parser/constants_quoted_string.exp
new file mode 100644
index 0000000000000..4aefbcb208d9b
--- /dev/null
+++ b/third_party/move/move-compiler/tests/move_check/parser/constants_quoted_string.exp
@@ -0,0 +1,6 @@
+error[E01007]: invalid byte string
+  ┌─ tests/move_check/parser/constants_quoted_string.move:5:29
+  │
+5 │     const C12: vector<u8> = "<empty>";
+  │                             ^ String literal must begin with b" (for a byte string) or x" (for a hex string)
+
diff --git a/third_party/move/move-compiler/tests/move_check/parser/constants_quoted_string.move b/third_party/move/move-compiler/tests/move_check/parser/constants_quoted_string.move
new file mode 100644
index 0000000000000..a51de933b4e29
--- /dev/null
+++ b/third_party/move/move-compiler/tests/move_check/parser/constants_quoted_string.move
@@ -0,0 +1,8 @@
+address 0x42 {
+module M {
+    fun u(): u64 { 0 }
+
+    const C12: vector<u8> = "<empty>";
+    const C13: vector<u8> = "foo;
+}
+}
diff --git a/third_party/move/move-compiler/tests/move_check/parser/constants_simple.move b/third_party/move/move-compiler/tests/move_check/parser/constants_simple.move
index dc5e980cf6a65..36ea3929b3d70 100644
--- a/third_party/move/move-compiler/tests/move_check/parser/constants_simple.move
+++ b/third_party/move/move-compiler/tests/move_check/parser/constants_simple.move
@@ -11,6 +11,9 @@ module M {
     const C7: u256 = 4 / 3 + 4 - 1 << 143;
     const C8: u16 = 123;
     const C9: u32 = (453 as u32);
-
+    const C10: vector<u8> = b"<empty>";
+    const C11: vector<u8> = x"deadbeef";
+    const C12: vector<u8> = b"\"foo\"";
+    const C13: vector<u8> = b"\"\x48";
 }
 }
diff --git a/third_party/move/move-compiler/tests/move_check/parser/constants_single_quote.exp b/third_party/move/move-compiler/tests/move_check/parser/constants_single_quote.exp
new file mode 100644
index 0000000000000..4cd777b63242f
--- /dev/null
+++ b/third_party/move/move-compiler/tests/move_check/parser/constants_single_quote.exp
@@ -0,0 +1,6 @@
+error[E01001]: invalid character
+  ┌─ tests/move_check/parser/constants_single_quote.move:4:29
+  │
+4 │     const C13: vector<u8> = "foo
+  │                             ^ Invalid character: '"'; string literal must begin with `b"` and closing quote `"` must appear on same line
+
diff --git a/third_party/move/move-compiler/tests/move_check/parser/constants_single_quote.move b/third_party/move/move-compiler/tests/move_check/parser/constants_single_quote.move
new file mode 100644
index 0000000000000..5ac99045bd143
--- /dev/null
+++ b/third_party/move/move-compiler/tests/move_check/parser/constants_single_quote.move
@@ -0,0 +1,10 @@
+address 0x42 {
+module M {
+    fun u(): u64 { 0 }
+    const C13: vector<u8> = "foo
+    ";
+    const C14: vector<u8> = "bar";
+    const C15: vector<u8> = b"baz";
+    const C16: vector<u8> = x"quux";
+}
+}
diff --git a/third_party/move/move-compiler/tests/move_check/parser/constants_string_non_utf8.exp b/third_party/move/move-compiler/tests/move_check/parser/constants_string_non_utf8.exp
new file mode 100644
index 0000000000000..05b90d2d3704e
--- /dev/null
+++ b/third_party/move/move-compiler/tests/move_check/parser/constants_string_non_utf8.exp
@@ -0,0 +1,6 @@
+error[E01001]: invalid character
+  ┌─ tests/move_check/parser/constants_string_non_utf8.move:5:31
+  │
+5 │     const C12: vector<u8> = b"ÿ";
+  │                               ^ Invalid character 'ÿ' found when reading file. Only ASCII printable characters, tabs (\t), lf (\n) and crlf (\r\n) are permitted.
+
diff --git a/third_party/move/move-compiler/tests/move_check/parser/constants_string_non_utf8.move b/third_party/move/move-compiler/tests/move_check/parser/constants_string_non_utf8.move
new file mode 100644
index 0000000000000..b1ff20f608048
--- /dev/null
+++ b/third_party/move/move-compiler/tests/move_check/parser/constants_string_non_utf8.move
@@ -0,0 +1,7 @@
+address 0x42 {
+module M {
+    fun u(): u64 { 0 }
+
+    const C12: vector<u8> = b"ÿ";
+}
+}