Skip to content

Commit 71650bd

Browse files
committed
comptime, check files, blog post
1 parent 138cb0f commit 71650bd

File tree

180 files changed

+3052
-261
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

180 files changed

+3052
-261
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
contract ComptimeBasics {
2+
pub fn basic_arithmetic() -> u256 {
3+
const a: u256 = 10;
4+
const b: u256 = 20;
5+
const c: u256 = a * b + 5;
6+
return c;
7+
}
8+
9+
pub fn refined_constants() {
10+
const x: MinValue<u256, 100> = 200;
11+
const y: MinValue<u256, 50> = 100;
12+
const prod = x * y; // comptime: 20000
13+
14+
const r: InRange<u256, 20, 200> = 55;
15+
const sum = r + 5; // comptime: 60
16+
}
17+
18+
pub fn comptime_block_example() -> u256 {
19+
const res: u256 = comptime {
20+
return 42;
21+
};
22+
return res;
23+
}
24+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
struct Pair {
2+
a: u256;
3+
b: u256;
4+
}
5+
6+
enum Status {
7+
A,
8+
B,
9+
C,
10+
}
11+
12+
contract ComptimeFolds {
13+
pub fn compare_bool() -> bool {
14+
const a: u256 = 10;
15+
const b: u256 = 20;
16+
const ok: bool = a < b;
17+
return ok;
18+
}
19+
20+
pub fn bitwise_and_shift() -> u256 {
21+
const x: u256 = 6; // 110
22+
const y: u256 = 3; // 011
23+
const z: u256 = (x & y) | (x ^ y) << 1;
24+
return z;
25+
}
26+
27+
pub fn shift_ops() -> u256 {
28+
const a: u256 = 1 << 8;
29+
const b: u256 = 256 >> 3;
30+
return a + b;
31+
}
32+
33+
pub fn switch_expr() -> u256 {
34+
const x: u256 = 7;
35+
const y: u256 = switch (x) {
36+
0...5 => 10,
37+
6...10 => 20,
38+
else => 30,
39+
};
40+
return y;
41+
}
42+
43+
pub fn array_literal_sum() -> u256 {
44+
const arr: [u256; 3] = [1, 2, 3];
45+
const sum: u256 = arr[0] + arr[1] + arr[2];
46+
return sum;
47+
}
48+
49+
pub fn struct_field_access() -> u256 {
50+
const v: u256 = (Pair { a: 10, b: 32 }).a + (Pair { a: 10, b: 32 }).b;
51+
return v;
52+
}
53+
54+
pub fn enum_compare() -> bool {
55+
const ok: bool = Status.B == Status.B;
56+
return ok;
57+
}
58+
59+
pub fn enum_switch() -> u256 {
60+
const v: u256 = switch (Status.B) {
61+
Status.A => 1,
62+
Status.B => 2,
63+
Status.C => 3,
64+
};
65+
return v;
66+
}
67+
68+
pub fn unary_ops() -> u256 {
69+
const a: u256 = 1;
70+
const b: u256 = ~a;
71+
const c: bool = !(a == 2);
72+
return b + (if (c) 1 else 0);
73+
}
74+
75+
pub fn cast_ops() -> u256 {
76+
const a: u256 = (5 as u256);
77+
const b: u256 = (10 as! u256);
78+
return a + b;
79+
}
80+
81+
// builtin divs removed for now
82+
}

ora-example/refinements/arithmetic_test.ora

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ contract ArithmeticRefinements {
5858
let diff4 = e - f; // Type: MaxValue<u256, 500> (1000 - 500)
5959

6060
// InRange - InRange = InRange
61-
let g: InRange<u256, 10, 100> = 50;
62-
let h: InRange<u256, 20, 200> = 100;
63-
let diff5 = g - h; // Type: InRange<u256, 0, 80> (min: 10-200, max: 100-20)
61+
let g: InRange<u256, 100, 100> = 100;
62+
let h: InRange<u256, 20, 50> = 50;
63+
let diff5 = g - h; // Type: InRange<u256, 50, 80> (min: 100-50, max: 100-20)
6464
}
6565

6666
// ============================================================================
@@ -147,4 +147,3 @@ contract ArithmeticRefinements {
147147
let result2 = result1 - b; // Type: MinValue<u256, 500> (conservative: 1000 - 500)
148148
}
149149
}
150-
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#!/usr/bin/env python3
2+
import re
3+
import subprocess
4+
from pathlib import Path
5+
6+
REPO = Path(__file__).resolve().parents[1]
7+
ORA_BIN = REPO / "zig-out" / "bin" / "ora"
8+
CHECKS_DIR = REPO / "tests" / "mlir"
9+
10+
SKIP_MARKERS = ["/invalid/", "/negative_tests/"]
11+
12+
13+
def should_skip(path: Path) -> bool:
14+
s = str(path)
15+
if any(m in s for m in SKIP_MARKERS):
16+
return True
17+
name = path.name
18+
if name.startswith("fail_") or "/fail_" in s or "fail_region_err" in s:
19+
return True
20+
if "/logs/log_fail_" in s:
21+
return True
22+
return False
23+
24+
25+
def main() -> int:
26+
if not ORA_BIN.exists():
27+
print(f"error: ora binary not found at {ORA_BIN}. Run 'zig build' first.")
28+
return 1
29+
30+
CHECKS_DIR.mkdir(parents=True, exist_ok=True)
31+
32+
# collect already covered inputs
33+
covered = set()
34+
for check in CHECKS_DIR.glob("*.check"):
35+
try:
36+
text = check.read_text()
37+
except Exception:
38+
continue
39+
m = re.search(r"^// INPUT:\s*(.+)$", text, re.M)
40+
if m:
41+
covered.add(m.group(1).strip())
42+
43+
ora_files = sorted((REPO / "ora-example").rglob("*.ora"))
44+
45+
created = 0
46+
failed = []
47+
48+
for path in ora_files:
49+
rel = path.relative_to(REPO).as_posix()
50+
if should_skip(path):
51+
continue
52+
if rel in covered:
53+
continue
54+
55+
try:
56+
proc = subprocess.run(
57+
[str(ORA_BIN), "--emit-mlir", str(path)],
58+
cwd=REPO,
59+
stdout=subprocess.PIPE,
60+
stderr=subprocess.PIPE,
61+
text=True,
62+
timeout=30,
63+
)
64+
except Exception as e:
65+
failed.append((rel, f"exception {e}"))
66+
continue
67+
if proc.returncode != 0:
68+
failed.append((rel, f"exit {proc.returncode}"))
69+
continue
70+
71+
out = proc.stdout
72+
marker = "Ora MLIR (before conversion)"
73+
if marker not in out:
74+
failed.append((rel, "missing Ora MLIR marker"))
75+
continue
76+
77+
ora = out.split(marker, 1)[1]
78+
func_names = re.findall(r"func\.func\s+@([A-Za-z0-9_]+)", ora)
79+
80+
check_name = "auto__" + rel.replace("/", "__").replace(".ora", ".check")
81+
check_path = CHECKS_DIR / check_name
82+
83+
lines = []
84+
lines.append("// AUTO-GENERATED. Do not edit by hand.")
85+
lines.append(f"// INPUT: {rel}")
86+
lines.append("// CHECK-NOT: builtin.unrealized_conversion_cast")
87+
if func_names:
88+
for name in func_names:
89+
lines.append(f"// CHECK-LABEL: func.func @{name}")
90+
else:
91+
lines.append("// CHECK: module")
92+
93+
check_path.write_text("\n".join(lines) + "\n")
94+
created += 1
95+
96+
print(f"created {created} checks")
97+
if failed:
98+
print("failed:")
99+
for rel, reason in failed:
100+
print(f" {rel}: {reason}")
101+
return 0
102+
103+
104+
if __name__ == "__main__":
105+
raise SystemExit(main())

scripts/run-mlir-checks.sh

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
FILECHECK_BIN=${FILECHECK:-./vendor/llvm-project/build-mlir/bin/FileCheck}
5+
ORA_BIN=${ORA_BIN:-./zig-out/bin/ora}
6+
7+
if ! command -v "$FILECHECK_BIN" >/dev/null 2>&1; then
8+
echo "error: FileCheck not found. Set FILECHECK=/path/to/FileCheck" >&2
9+
exit 1
10+
fi
11+
12+
if [ ! -x "$ORA_BIN" ]; then
13+
echo "error: ora binary not found at $ORA_BIN" >&2
14+
exit 1
15+
fi
16+
17+
fail=0
18+
while IFS= read -r -d '' check; do
19+
input=$(rg -m1 "^// INPUT:" "$check" | sed -E 's#^// INPUT: ##')
20+
if [ -z "$input" ]; then
21+
echo "error: missing // INPUT: in $check" >&2
22+
fail=1
23+
continue
24+
fi
25+
if [[ "$input" == path/to/* ]]; then
26+
continue
27+
fi
28+
29+
if [ ! -f "$input" ]; then
30+
echo "error: input file not found: $input (from $check)" >&2
31+
fail=1
32+
continue
33+
fi
34+
35+
echo "[mlir-check] $check -> $input"
36+
"$ORA_BIN" --emit-mlir "$input" 2>/dev/null | \
37+
awk '
38+
/Ora MLIR \(before conversion\)/ {f=1; print; next}
39+
/^module / {if (!f) f=1}
40+
f {print}
41+
' | \
42+
"$FILECHECK_BIN" "$check" || fail=1
43+
44+
done < <(find tests/mlir -name "*.check" -print0 | sort -z)
45+
46+
exit $fail

src/ast/expressions.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,7 @@ pub const CastExpr = struct {
431431
pub const ComptimeExpr = struct {
432432
block: BlockNode,
433433
span: SourceSpan,
434+
type_info: TypeInfo = TypeInfo.unknown(),
434435
};
435436

436437
/// old() expressions for postconditions

0 commit comments

Comments
 (0)