Skip to content

Commit efc13d9

Browse files
Feat/cube/compile error (#1909)
1 parent d50bac1 commit efc13d9

21 files changed

+161
-26
lines changed

Cargo.lock

+15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/burn-cube-macros/src/analyzer.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ impl VariableAnalyzer {
128128
if let syn::Expr::Block(expr_block) = &**expr {
129129
self.find_occurrences_in_stmts(&expr_block.block.stmts, depth);
130130
} else {
131-
todo!("Analysis: Only block else expr is supported")
131+
// Unsupported: handled in codegen.
132132
}
133133
}
134134
}
@@ -190,17 +190,12 @@ impl VariableAnalyzer {
190190
syn::Expr::Break(_) => {}
191191
syn::Expr::Return(expr) => {
192192
if expr.expr.is_some() {
193-
todo!("Analysis: only void return supported")
193+
// Unsupported: handled in codegen.
194194
}
195195
}
196196
syn::Expr::Paren(expr) => self.find_occurrences_in_expr(&expr.expr, depth),
197-
syn::Expr::Array(expr) => {
198-
for element in expr.elems.iter() {
199-
match element {
200-
syn::Expr::Lit(_) => {}
201-
_ => todo!("Analysis: only array of literals is supported"),
202-
}
203-
}
197+
syn::Expr::Array(_expr) => {
198+
// No analysis since only literals are supported
204199
}
205200
syn::Expr::Reference(expr) => self.find_occurrences_in_expr(&expr.expr, depth),
206201
syn::Expr::Closure(expr) => {
@@ -251,7 +246,12 @@ impl VariableAnalyzer {
251246
self.find_occurrences_in_expr(&field.expr, depth)
252247
}
253248
}
254-
_ => todo!("Analysis: unsupported expr {expr:?}"),
249+
syn::Expr::Range(_range) => {
250+
// Error is handled during codegen.
251+
}
252+
_ => {
253+
// Error is handled during codegen.
254+
}
255255
}
256256
}
257257
}

crates/burn-cube-macros/src/codegen_function/base.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,14 @@ pub(crate) fn codegen_expr_with_comptime(
125125
syn::Expr::Unary(op) => codegen_unary(op, loop_level, variable_tracker),
126126
syn::Expr::Field(field) => codegen_field(field, loop_level, variable_tracker),
127127
syn::Expr::Struct(struct_) => codegen_struct(struct_, loop_level, variable_tracker),
128-
_ => panic!("Codegen: Unsupported {:?}", expr),
128+
syn::Expr::Range(range) => syn::Error::new_spanned(
129+
range,
130+
"Range is not supported, use [range](cubecl::prelude::range) instead.",
131+
)
132+
.to_compile_error(),
133+
_ => {
134+
syn::Error::new_spanned(expr, "Expression is not supported").to_compile_error()
135+
}
129136
};
130137

131138
(tokens, false)

crates/burn-cube-macros/src/codegen_function/branch.rs

+25-9
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,24 @@ pub(crate) fn codegen_for_loop(
2424
variable_tracker.codegen_declare(id.to_string(), loop_level as u8 + 1);
2525
}
2626

27+
let invalid_for_loop = || {
28+
syn::Error::new_spanned(
29+
&for_loop.expr,
30+
"Invalid for loop: use [range](cubecl::prelude::range] instead.",
31+
)
32+
.into_compile_error()
33+
};
34+
2735
match for_loop.expr.as_ref() {
2836
syn::Expr::Call(call) => {
2937
let func_name = match call.func.as_ref() {
30-
syn::Expr::Path(path) => path
31-
.path
32-
.get_ident()
33-
.expect("Codegen: func in for loop should have ident"),
34-
_ => todo!("Codegen: Only path call supported"),
38+
syn::Expr::Path(path) => match path.path.get_ident() {
39+
Some(ident) => ident,
40+
None => return invalid_for_loop(),
41+
},
42+
_ => {
43+
return invalid_for_loop();
44+
}
3545
};
3646

3747
if &func_name.to_string() == "range" {
@@ -64,10 +74,10 @@ pub(crate) fn codegen_for_loop(
6474
}
6575
}
6676
} else {
67-
todo!("Codegen: Only range is supported")
77+
invalid_for_loop()
6878
}
6979
}
70-
_ => todo!("Codegen: Only call is supported {for_loop:?}"),
80+
_ => invalid_for_loop(),
7181
}
7282
}
7383

@@ -96,8 +106,10 @@ pub(crate) fn codegen_break() -> TokenStream {
96106
/// Codegen for return statement
97107
pub(crate) fn codegen_return(expr_return: &syn::ExprReturn) -> TokenStream {
98108
if expr_return.expr.is_some() {
99-
panic!("Codegen: Only void return is supported.")
109+
return syn::Error::new_spanned(expr_return, "Codegen: Only void return is supported.")
110+
.into_compile_error();
100111
}
112+
101113
quote::quote! {
102114
burn_cube::frontend::branch::return_expand(context);
103115
}
@@ -131,7 +143,11 @@ pub(crate) fn codegen_if(
131143
burn_cube::frontend::branch::if_else_expand(context, #comptime_bool, _cond.into(), |context| #then_block, |context| #else_block);
132144
}
133145
} else {
134-
todo!("Codegen: Only block else expr is supported")
146+
syn::Error::new_spanned(
147+
expr,
148+
"Unsupported: only `else` block is allowed after an `if` statement.",
149+
)
150+
.into_compile_error()
135151
}
136152
} else {
137153
quote::quote! {

crates/burn-cube-macros/src/codegen_function/function.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,12 @@ pub(crate) fn codegen_closure(
4141
if let syn::Pat::Ident(ident) = &*pat_type.pat {
4242
&ident.ident
4343
} else {
44-
panic!("Codegen: Unsupported {:?}", input);
44+
return syn::Error::new_spanned(pat_type, "Unsupported input")
45+
.into_compile_error();
4546
},
4647
Some(pat_type.ty.clone()),
4748
),
48-
_ => panic!("Codegen: Unsupported {:?}", input),
49+
_ => return syn::Error::new_spanned(input, "Unsupported input").into_compile_error(),
4950
};
5051

5152
if let Some(ty) = ty {
@@ -92,7 +93,12 @@ pub(crate) fn codegen_call(
9293
}
9394
path
9495
}
95-
_ => todo!("Codegen: func call {:?} not supported", call.func),
96+
_ => {
97+
return (
98+
syn::Error::new_spanned(&call.func, "Unsupported").into_compile_error(),
99+
false,
100+
)
101+
}
96102
};
97103

98104
// Path

crates/burn-cube-macros/src/codegen_function/launch.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ impl Codegen {
8383
codegen.state_inputs.push((ident.clone(), *ty));
8484
}
8585
}
86-
_ => todo!("Only Typed inputs are supported"),
86+
_ => panic!("Only Typed inputs are supported"),
8787
};
8888
}
8989

crates/burn-cube-macros/src/codegen_function/variable.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ pub(crate) fn codegen_array_lit(array: &syn::ExprArray) -> TokenStream {
2929
for element in array.elems.iter() {
3030
let token = match element {
3131
syn::Expr::Lit(lit) => codegen_lit(lit),
32-
_ => todo!("Codegen: Only arrays of literals are supported"),
32+
_ => {
33+
return syn::Error::new_spanned(array, "Only arrays of literals are supported")
34+
.into_compile_error()
35+
}
3336
};
3437
tokens.extend(quote::quote! { #token, });
3538
}

crates/burn-cube-macros/src/lib.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,12 @@ pub fn cube(attr: TokenStream, tokens: TokenStream) -> TokenStream {
4949

5050
let mut variable_tracker = VariableAnalyzer::create_tracker(&func);
5151

52-
let cube = codegen_cube(&func, &mut variable_tracker);
52+
let mut cube = codegen_cube(&func, &mut variable_tracker);
53+
54+
for err in variable_tracker.errors.drain(..) {
55+
cube.extend(err.into_compile_error());
56+
}
57+
5358
let code: TokenStream = if launch {
5459
let launch = codegen_launch(&func.sig);
5560

crates/burn-cube-macros/src/tracker.rs

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub(crate) struct VariableTracker {
2323
analysis_repeats: HashMap<VariableKey, u8>,
2424
codegen_repeats: HashMap<VariableKey, u8>,
2525
variable_uses: HashMap<VariableIdent, VariableUse>,
26+
pub errors: Vec<syn::Error>,
2627
}
2728

2829
#[derive(Debug, Default)]

crates/burn-cube/Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,6 @@ derive-new = { workspace = true }
3232
num-traits = { workspace = true }
3333

3434
log = { workspace = true }
35+
36+
[dev-dependencies]
37+
trybuild = "1"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use burn_cube::prelude::*;
2+
3+
#[cube]
4+
fn range(x: UInt, y: UInt) {
5+
let _array = [x, y];
6+
}
7+
8+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
error: Only arrays of literals are supported
2+
--> tests/error/array_variable.rs:5:18
3+
|
4+
5 | let _array = [x, y];
5+
| ^^^^^^
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use burn_cube::prelude::*;
2+
3+
#[cube]
4+
fn range() {
5+
for _ in 0..10 {}
6+
}
7+
8+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
error: Invalid for loop: use [range](cubecl::prelude::range] instead.
2+
--> tests/error/for_loop_range.rs:5:14
3+
|
4+
5 | for _ in 0..10 {}
5+
| ^^^^^
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
use burn_cube::prelude::*;
2+
3+
#[cube]
4+
fn range(x: UInt, y: UInt) {
5+
if x == y {
6+
} else if x != y {
7+
}
8+
}
9+
10+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
error: Unsupported: only `else` block is allowed after an `if` statement.
2+
--> tests/error/if_else_if.rs:6:12
3+
|
4+
6 | } else if x != y {
5+
| ____________^
6+
7 | | }
7+
| |_____^

crates/burn-cube/tests/error/range.rs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use burn_cube::prelude::*;
2+
3+
#[cube]
4+
fn range() {
5+
0..10;
6+
}
7+
8+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
error: Range is not supported, use [range](cubecl::prelude::range) instead.
2+
--> tests/error/range.rs:5:5
3+
|
4+
5 | 0..10;
5+
| ^^^^^
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use burn_cube::prelude::*;
2+
3+
#[cube]
4+
fn range(x: UInt, y: UInt) -> UInt {
5+
if x == y {
6+
return x;
7+
}
8+
9+
y
10+
}
11+
12+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
error: Codegen: Only void return is supported.
2+
--> tests/error/return_value.rs:6:9
3+
|
4+
6 | return x;
5+
| ^^^^^^^^

crates/burn-cube/tests/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1 +1,7 @@
11
mod frontend;
2+
3+
#[test]
4+
fn compile_fail_tests() {
5+
let t = trybuild::TestCases::new();
6+
t.compile_fail("tests/error/*.rs");
7+
}

0 commit comments

Comments
 (0)