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

Show deprecation on arithmetic word operations #2339

Merged
merged 57 commits into from
Feb 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
0e0b447
Value.Numerics: Refactoring to prepare word deprecation
nomeata Feb 9, 2021
42b046c
Forgotten
nomeata Feb 9, 2021
79a92ab
Keep mo:prim compatible
nomeata Feb 9, 2021
a0c9fd7
Update test output
nomeata Feb 9, 2021
095b32d
Fix of_string for words
nomeata Feb 9, 2021
c36a8d4
Add bit-operations to nat and int, and wrapping operations to all
nomeata Feb 9, 2021
8ff5032
Fix wrong name for Nat64Wrap primop
nomeata Feb 9, 2021
7cd401f
Update src/mo_values/operator.ml
nomeata Feb 9, 2021
68af7c7
Forgot to actually support them operators
nomeata Feb 9, 2021
b040f02
Empty line be gone
nomeata Feb 9, 2021
806ba92
Update src/codegen/compile.ml
nomeata Feb 9, 2021
9514c35
Use right PowOp for Words
nomeata Feb 9, 2021
ce49293
Do not even begin to support +>> on IntN and NatN
nomeata Feb 9, 2021
36fb907
Shorter prefix: Just w
nomeata Feb 9, 2021
2e9e8a2
Fixup shorter prefix
nomeata Feb 9, 2021
60b8293
Update src/mo_values/numerics.ml
nomeata Feb 9, 2021
178da47
Merge remote-tracking branch 'origin/joachim/value-refactor' into joa…
nomeata Feb 9, 2021
f90a256
Simplify num_conv_wrap_prim
nomeata Feb 9, 2021
37f4399
Merge branch 'joachim/value-refactor' into joachim/new-bit-ops
nomeata Feb 9, 2021
2d8e324
Typos
nomeata Feb 9, 2021
1a3e6e1
Merge branch 'joachim/value-refactor' into joachim/new-bit-ops
nomeata Feb 9, 2021
c211c5d
Update src/lowering/desugar.ml
nomeata Feb 10, 2021
3a0ab52
Update src/lowering/desugar.ml
nomeata Feb 10, 2021
3e5959a
Merge branch 'master' of github.com:dfinity/motoko into joachim/value…
nomeata Feb 10, 2021
159a47b
Merge branch 'joachim/value-refactor' into joachim/new-bit-ops
nomeata Feb 10, 2021
a35e51c
Post-squash merge of origin/master
nomeata Feb 10, 2021
4e74f44
Changelog
nomeata Feb 10, 2021
ac3c889
Cherry-pick users’s guide
nomeata Feb 10, 2021
735c0f4
Deleted too much
nomeata Feb 10, 2021
c84c04f
Unrelated typo
nomeata Feb 10, 2021
dd6ef23
Already provide charToNat32/nat32ToChar in prim
nomeata Feb 10, 2021
53254a2
Merge branch 'master' of github.com:dfinity/motoko into joachim/new-b…
nomeata Feb 10, 2021
6fd6d70
Merge branch 'master' into joachim/new-bit-ops
nomeata Feb 10, 2021
19ab1b1
Merge branch 'master' into joachim/new-bit-ops
nomeata Feb 12, 2021
99d4086
Show deprecation on arithmetic word operations
nomeata Feb 12, 2021
2aa9b73
Merge branch 'joachim/new-bit-ops' into joachim/warn-on-word-ops
nomeata Feb 12, 2021
baa7b0b
Update test output
nomeata Feb 12, 2021
2bfd78c
Use wrapping ops on Word in numeric-ops.mo
nomeata Feb 12, 2021
ad13a79
More test suite updates
nomeata Feb 12, 2021
220bbbd
User’s guide: Migration comment (and changelog)
nomeata Feb 12, 2021
bfdf241
More test suite updates
nomeata Feb 12, 2021
e347a66
Apply suggestions from code review
nomeata Feb 12, 2021
52b005a
Update Changelog.md
nomeata Feb 12, 2021
ebfca8d
Also give deprecation warning in checking mode
nomeata Feb 12, 2021
c9f4eab
Typo in error_reporting.ml
nomeata Feb 12, 2021
76c5ef7
More copy’n’pasta (and bad testing coverage…)
nomeata Feb 12, 2021
07259ae
Merge branch 'joachim/new-bit-ops' into joachim/warn-on-word-ops
nomeata Feb 12, 2021
693a117
Update doc/overview-slides.md
nomeata Feb 12, 2021
b462eb3
More test suite updates
nomeata Feb 12, 2021
73512d6
Update perf tests
nomeata Feb 12, 2021
e5c1f01
Update doc/modules/language-guide/pages/basic-concepts.adoc
nomeata Feb 12, 2021
7e1a2ef
Update Changelog.md
nomeata Feb 12, 2021
ed4ed69
Apply suggestions from code review
nomeata Feb 12, 2021
4b50977
Merge branch 'master' into joachim/new-bit-ops
mergify[bot] Feb 12, 2021
b0f83a1
Merge branch 'joachim/new-bit-ops' into joachim/warn-on-word-ops
nomeata Feb 12, 2021
7a3c39d
Remove more code fences (```)
nomeata Feb 12, 2021
1a73d0e
Post-squash merge of origin/master
nomeata Feb 12, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
The motivation for this change is to eventually deprecate and remove the
`WordN` types.

Therefore, the wrapping arithmetic operations on `WordN` are deprecated and
their use will print a warning. See the user’s guide, section “Word types”,
for a migration guide.

* For values `x` of type `Blob`, an iterator over the elements of the blob
`x.vals()` is introduced. It works like `x.bytes()`, but returns the elements
as type `Nat8`.
Expand Down
31 changes: 31 additions & 0 deletions doc/modules/language-guide/pages/language-manual.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,37 @@ other arithmetic types, and their literals need type annotation, e.g.
`(-42 : Word16)`. For negative literals the two's-complement
representation is applied.

[IMPORTANT]
====
The `WordN` types will be deprecated in favor of the `NatN` and `IntN` types. This happens in two phases:

1. First, the wrapping arithmetic operations on word types (`+`, `-`, `*` or `**`) are deprecated, and the explicitly wrapping variants should be used (`+%`, +`-%`, `*%` and `**%`).

2. In the next phase, the `Word` types themselves are removed.

Developers can choose to follow these phases, and be guided by the deprecation
warnings, or can migrate away from using the `WordN` types now. In that case:

* Choose `NatN` or `IntN` as needed (typically `NatN`).

* For each use of `+`, `-`, `*` or `**`, decide whether you want to preserve
the wrapping behaviour, in which case you use `+%`, +`-%`, `*%` or `**%`, or
if you actually want the trapping behaviour of arithmetic on `NatN`/`IntN`.

* For each use of `Word8.fromInt`, decide whether you want wrapping or
trapping behaviour. Use `fromNat`/`fromInt` or `fromIntWrap` accordingly.

* Instead of `Char.fromWord32` and `Char.toWord32`, use `Char.fromNat32` and `Char.toNat32`.

* For each use of `>>` or `+>>`, decide if the right-shift on `Nat` resp.
`Int` gives you the desired semantics. If not, convert to the other type
before shifting.

* Use `blob.vals()` instead of `blob.bytes()`, to get a `Nat8`-iterator.

====


[[type-Blob]]
=== Type `Blob`

Expand Down
1 change: 1 addition & 0 deletions src/lang_utils/error_codes.ml
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,5 @@ let error_codes : (string * string option) list =
"M0149", Some([%blob "error_codes/M0149.adoc"]); (* Expected mutable 'var' field, found immutable field *)
"M0150", Some([%blob "error_codes/M0150.adoc"]); (* Expected immutable field, found mutable 'var' field *)
"M0151", Some([%blob "error_codes/M0151.adoc"]); (* missing field in object literal *)
"M0152", Some([%blob "error_codes/M0152.adoc"]); (* Word field deprecation *)
]
4 changes: 0 additions & 4 deletions src/lang_utils/error_codes/M0151.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,11 @@ This error means that a object literal is missing some fields, maybe because of

Erroneous code examples:

```
{ first_name = "Fred" } : { firstName : Text }
{ firstName = "Fred" } : { firstName : Text; lastName : Text }
```

If you encounter this error, you need to add the missing field name to the
object literal.

```
{ firstName = "Fred" } : { firstName : Text }
{ firstName = "Fred"; lastName = "Flintstone" } : { firstName : Text; lastName : Text }
```
19 changes: 19 additions & 0 deletions src/lang_utils/error_codes/M0152.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
= M0152

You are using a possibly wrapping operator (`+`, `-`, `*` or `**`) on a word
type (e.g. `Word8`). The word type will be deprecated in the future, and
replaced with `Nat8`, `Int8` etc. The arithmetic operations have different
semantics on these types, as they trap on overflow, instead of wrapping around.
to prepare the transition, you are advised to use the wrapping operators (`+%`,
`-%`, `*%` and `**%`) now. This way, when you eventually switch to `Nat8` or `Int8`,
these operators work as expected.

See the user's guide, section on `Word` type, for more information on this transition.

Erroneous code example:

func add(w1 : Word8, w2 : Word8) : Word8 { w1 + w2 };

Typical fix:

func add(w1 : Word8, w2 : Word8) : Word8 { w1 +% w2 };
17 changes: 17 additions & 0 deletions src/mo_frontend/typing.ml
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,21 @@ let coverage_cases category env cases t at =
let coverage_pat warnOrError env pat t =
coverage' warnOrError "pattern" env Coverage.check_pat pat t pat.at

(* Deprecation *)

let check_deprecation_binop env at t op =
let open Type in
let open Operator in
let word_op_warn s =
warn env at "M0152" "the arithmetic operation %s on %s is deprecated, use %s%% instead"
s (T.string_of_typ_expand t) s
in
match t, op with
| Prim (Word8|Word16|Word32|Word64), AddOp -> word_op_warn "+"
| Prim (Word8|Word16|Word32|Word64), SubOp -> word_op_warn "-"
| Prim (Word8|Word16|Word32|Word64), MulOp -> word_op_warn "*"
| Prim (Word8|Word16|Word32|Word64), PowOp -> word_op_warn "**"
Comment on lines +190 to +193
Copy link
Contributor

Choose a reason for hiding this comment

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

You can do this and remove the open Type

Suggested change
| Prim (Word8|Word16|Word32|Word64), AddOp -> word_op_warn "+"
| Prim (Word8|Word16|Word32|Word64), SubOp -> word_op_warn "-"
| Prim (Word8|Word16|Word32|Word64), MulOp -> word_op_warn "*"
| Prim (Word8|Word16|Word32|Word64), PowOp -> word_op_warn "**"
| Prim T.(Word8|Word16|Word32|Word64), AddOp -> word_op_warn "+"
| Prim T.(Word8|Word16|Word32|Word64), SubOp -> word_op_warn "-"
| Prim T.(Word8|Word16|Word32|Word64), MulOp -> word_op_warn "*"
| Prim T.(Word8|Word16|Word32|Word64), PowOp -> word_op_warn "**"

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Nope, that would exclue Prim. And then you need extra parenthesis, which I like less than you do ;-)

Copy link
Contributor

Choose a reason for hiding this comment

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

Or put T. before those as well -- still a net win. :)

| _, _ -> ()

(* Types *)

Expand Down Expand Up @@ -815,6 +830,7 @@ and infer_exp'' env exp : T.typ =
error_bin_op env exp.at t1 t2;
ot := t
end;
check_deprecation_binop env exp.at t op;
t
| RelE (ot, exp1, op, exp2) ->
let t1 = T.normalize (infer_exp env exp1) in
Expand Down Expand Up @@ -1228,6 +1244,7 @@ and check_exp' env0 t exp : T.typ =
ot := t;
check_exp env t exp1;
check_exp env t exp2;
check_deprecation_binop env exp.at t op;
t
| TupE exps, T.Tup ts when List.length exps = List.length ts ->
List.iter2 (check_exp env) ts exps;
Expand Down
5 changes: 0 additions & 5 deletions test/perf/assetstorage/Char.mo
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,6 @@ module {
// Not exposed pending multi-char implementation.
private let toLower : (c : Char) -> Char = Prim.charToLower;

/// Returns `true` when `c` is a decimal digit between `0` and `9`, otherwise `false`.
public func isDigit(c : Char) : Bool {
Prim.charToWord32(c) - Prim.charToWord32('0') <= (9 : Word32)
};

/// Returns the Unicode _White_Space_ property of `c`.
public let isWhitespace : (c : Char) -> Bool = Prim.charIsWhitespace;

Expand Down
8 changes: 4 additions & 4 deletions test/perf/assetstorage/Hash.mo
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ module {
public func hashWord8(key : [Hash]) : Hash {
var hash = Prim.natToWord32(0);
for (wordOfKey in key.vals()) {
hash := hash + wordOfKey;
hash := hash + hash << 10;
hash := hash +% wordOfKey;
hash := hash +% hash << 10;
hash := hash ^ (hash >> 6);
};
hash := hash + hash << 3;
hash := hash +% hash << 3;
hash := hash ^ (hash >> 11);
hash := hash + hash << 15;
hash := hash +% hash << 15;
return hash;
};

Expand Down
2 changes: 1 addition & 1 deletion test/perf/qr/char.mo
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import Prim "mo:prim";
module {
public let isDigit : Char -> Bool = func(char) {
Prim.charToWord32(char) - Prim.charToWord32('0') <= (9 : Word32)
Prim.charToWord32(char) -% Prim.charToWord32('0') <= (9 : Word32)
};

}
8 changes: 4 additions & 4 deletions test/perf/qr/hash.mo
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,13 @@ module {
public let hashWord8s : [Hash] -> Hash = func(key) {
var hash = Prim.natToWord32(0);
for (wordOfKey in key.vals()) {
hash := hash + wordOfKey;
hash := hash + hash << 10;
hash := hash +% wordOfKey;
hash := hash +% hash << 10;
hash := hash ^ (hash >> 6);
};
hash := hash + hash << 3;
hash := hash +% hash << 3;
hash := hash ^ (hash >> 11);
hash := hash + hash << 15;
hash := hash +% hash << 15;
return hash;
};

Expand Down
2 changes: 1 addition & 1 deletion test/perf/qr/numeric.mo
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ module {
if (Char.isDigit(char)) {
Option.map<Nat, Nat>(func (a) {
let b = Prim.word32ToNat(
Prim.charToWord32(char) - Prim.charToWord32('0')
Prim.charToWord32(char) -% Prim.charToWord32('0')
);
10 * a + b
}, accum)
Expand Down
64 changes: 32 additions & 32 deletions test/run/numeric-ops.mo
Original file line number Diff line number Diff line change
Expand Up @@ -154,18 +154,18 @@ func testWord8(a : Word8, b : Word8) : [Word8] {
let pos2 = (+ a) : Word8;
let neg1 = - a;
let neg2 = (- a) : Word8;
let sum1 = a + b;
let sum2 = (a + b) : Word8;
let diff1 = a - b;
let diff2 = (a - b) : Word8;
let prod1 = a * b;
let prod2 = (a * b) : Word8;
let sum1 = a +% b;
let sum2 = (a +% b) : Word8;
let diff1 = a -% b;
let diff2 = (a -% b) : Word8;
let prod1 = a *% b;
let prod2 = (a *% b) : Word8;
let rat1 = a / b;
let rat2 = (a / b) : Word8;
let mod1 = a % b;
let mod2 = (a % b) : Word8;
let pow1 = a ** b;
let pow2 = (a ** b) : Word8;
let pow1 = a **% b;
let pow2 = (a **% b) : Word8;
[pos1, pos2, neg1, neg2, sum1, sum2, diff1, diff2, prod1, prod2, rat1, rat2, mod1, mod2, pow1, pow2]
};

Expand All @@ -179,18 +179,18 @@ func testWord16(a : Word16, b : Word16) : [Word16] {
let pos2 = (+ a) : Word16;
let neg1 = - a;
let neg2 = (- a) : Word16;
let sum1 = a + b;
let sum2 = (a + b) : Word16;
let diff1 = a - b;
let diff2 = (a - b) : Word16;
let prod1 = a * b;
let prod2 = (a * b) : Word16;
let sum1 = a +% b;
let sum2 = (a +% b) : Word16;
let diff1 = a -% b;
let diff2 = (a -% b) : Word16;
let prod1 = a *% b;
let prod2 = (a *% b) : Word16;
let rat1 = a / b;
let rat2 = (a / b) : Word16;
let mod1 = a % b;
let mod2 = (a % b) : Word16;
let pow1 = a ** b;
let pow2 = (a ** b) : Word16;
let pow1 = a **% b;
let pow2 = (a **% b) : Word16;
[pos1, pos2, neg1, neg2, sum1, sum2, diff1, diff2, prod1, prod2, rat1, rat2, mod1, mod2, pow1, pow2]
};

Expand All @@ -203,18 +203,18 @@ func testWord32(a : Word32, b : Word32) : [Word32] {
let pos2 = (+ a) : Word32;
let neg1 = - a;
let neg2 = (- a) : Word32;
let sum1 = a + b;
let sum2 = (a + b) : Word32;
let diff1 = a - b;
let diff2 = (a - b) : Word32;
let prod1 = a * b;
let prod2 = (a * b) : Word32;
let sum1 = a +% b;
let sum2 = (a +% b) : Word32;
let diff1 = a -% b;
let diff2 = (a -% b) : Word32;
let prod1 = a *% b;
let prod2 = (a *% b) : Word32;
let rat1 = a / b;
let rat2 = (a / b) : Word32;
let mod1 = a % b;
let mod2 = (a % b) : Word32;
let pow1 = a ** b;
let pow2 = (a ** b) : Word32;
let pow1 = a **% b;
let pow2 = (a **% b) : Word32;
[pos1, pos2, neg1, neg2, sum1, sum2, diff1, diff2, prod1, prod2, rat1, rat2, mod1, mod2, pow1, pow2]
};

Expand All @@ -227,18 +227,18 @@ func testWord64(a : Word64, b : Word64) : [Word64] {
let pos2 = (+ a) : Word64;
let neg1 = - a;
let neg2 = (- a) : Word64;
let sum1 = a + b;
let sum2 = (a + b) : Word64;
let diff1 = a - b;
let diff2 = (a - b) : Word64;
let prod1 = a * b;
let prod2 = (a * b) : Word64;
let sum1 = a +% b;
let sum2 = (a +% b) : Word64;
let diff1 = a -% b;
let diff2 = (a -% b) : Word64;
let prod1 = a *% b;
let prod2 = (a *% b) : Word64;
let rat1 = a / b;
let rat2 = (a / b) : Word64;
let mod1 = a % b;
let mod2 = (a % b) : Word64;
let pow1 = a ** b;
let pow2 = (a ** b) : Word64;
let pow1 = a **% b;
let pow2 = (a **% b) : Word64;
[pos1, pos2, neg1, neg2, sum1, sum2, diff1, diff2, prod1, prod2, rat1, rat2, mod1, mod2, pow1, pow2]
};

Expand Down
32 changes: 32 additions & 0 deletions test/run/ok/word-ops-deprecation.tc.ok
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
word-ops-deprecation.mo:2.34-2.39: warning [M0152], the arithmetic operation + on Word8 is deprecated, use +% instead
word-ops-deprecation.mo:3.34-3.39: warning [M0152], the arithmetic operation - on Word8 is deprecated, use -% instead
word-ops-deprecation.mo:4.34-4.39: warning [M0152], the arithmetic operation * on Word8 is deprecated, use *% instead
word-ops-deprecation.mo:5.34-5.40: warning [M0152], the arithmetic operation ** on Word8 is deprecated, use **% instead
word-ops-deprecation.mo:6.35-6.40: warning [M0152], the arithmetic operation + on Word16 is deprecated, use +% instead
word-ops-deprecation.mo:7.35-7.40: warning [M0152], the arithmetic operation - on Word16 is deprecated, use -% instead
word-ops-deprecation.mo:8.35-8.40: warning [M0152], the arithmetic operation * on Word16 is deprecated, use *% instead
word-ops-deprecation.mo:9.35-9.41: warning [M0152], the arithmetic operation ** on Word16 is deprecated, use **% instead
word-ops-deprecation.mo:10.35-10.40: warning [M0152], the arithmetic operation + on Word32 is deprecated, use +% instead
word-ops-deprecation.mo:11.35-11.40: warning [M0152], the arithmetic operation - on Word32 is deprecated, use -% instead
word-ops-deprecation.mo:12.35-12.40: warning [M0152], the arithmetic operation * on Word32 is deprecated, use *% instead
word-ops-deprecation.mo:13.35-13.41: warning [M0152], the arithmetic operation ** on Word32 is deprecated, use **% instead
word-ops-deprecation.mo:14.35-14.40: warning [M0152], the arithmetic operation + on Word64 is deprecated, use +% instead
word-ops-deprecation.mo:15.35-15.40: warning [M0152], the arithmetic operation - on Word64 is deprecated, use -% instead
word-ops-deprecation.mo:16.35-16.40: warning [M0152], the arithmetic operation * on Word64 is deprecated, use *% instead
word-ops-deprecation.mo:17.35-17.41: warning [M0152], the arithmetic operation ** on Word64 is deprecated, use **% instead
word-ops-deprecation.mo:20.36-20.41: warning [M0152], the arithmetic operation + on Word8 is deprecated, use +% instead
word-ops-deprecation.mo:21.36-21.41: warning [M0152], the arithmetic operation - on Word8 is deprecated, use -% instead
word-ops-deprecation.mo:22.36-22.41: warning [M0152], the arithmetic operation * on Word8 is deprecated, use *% instead
word-ops-deprecation.mo:23.36-23.42: warning [M0152], the arithmetic operation ** on Word8 is deprecated, use **% instead
word-ops-deprecation.mo:24.38-24.43: warning [M0152], the arithmetic operation + on Word16 is deprecated, use +% instead
word-ops-deprecation.mo:25.38-25.43: warning [M0152], the arithmetic operation - on Word16 is deprecated, use -% instead
word-ops-deprecation.mo:26.38-26.43: warning [M0152], the arithmetic operation * on Word16 is deprecated, use *% instead
word-ops-deprecation.mo:27.38-27.44: warning [M0152], the arithmetic operation ** on Word16 is deprecated, use **% instead
word-ops-deprecation.mo:28.38-28.43: warning [M0152], the arithmetic operation + on Word32 is deprecated, use +% instead
word-ops-deprecation.mo:29.38-29.43: warning [M0152], the arithmetic operation - on Word32 is deprecated, use -% instead
word-ops-deprecation.mo:30.38-30.43: warning [M0152], the arithmetic operation * on Word32 is deprecated, use *% instead
word-ops-deprecation.mo:31.38-31.44: warning [M0152], the arithmetic operation ** on Word32 is deprecated, use **% instead
word-ops-deprecation.mo:32.38-32.43: warning [M0152], the arithmetic operation + on Word64 is deprecated, use +% instead
word-ops-deprecation.mo:33.38-33.43: warning [M0152], the arithmetic operation - on Word64 is deprecated, use -% instead
word-ops-deprecation.mo:34.38-34.43: warning [M0152], the arithmetic operation * on Word64 is deprecated, use *% instead
word-ops-deprecation.mo:35.38-35.44: warning [M0152], the arithmetic operation ** on Word64 is deprecated, use **% instead
Loading