use crate::assert::Assert;
use crate::eval::bc::opcode::BcOpcode;
use crate::eval::compiler::def::FrozenDef;
use crate::tests::bc::golden::bc_golden_test;
use crate::values::ValueLike;
#[test]
fn test_def_const_inlined() {
bc_golden_test(
"def_inline_const_inlined",
r#"
def trivial():
return 10
def test():
return trivial()
"#,
)
}
#[test]
fn test_def_list_inlined() {
bc_golden_test(
"def_inline_list_inlined",
r#"
def test():
return returns_list()
# Also test function is inlined if it is defined after the caller.
def returns_list():
return [10, True]
"#,
)
}
#[test]
fn test_dict_inlined() {
bc_golden_test(
"def_inline_dict_inlined",
r#"
def returns_dict():
# This should fail at runtime.
return {[]: 10}
def test():
return returns_dict()
"#,
);
}
#[test]
fn test_do_not_inline_functions_with_return_type() {
bc_golden_test(
"def_inline_return_type_inlined",
r#"
def smth() -> str:
return "10"
def test():
# This call should not be inlined.
return smth()
"#,
);
}
#[test]
fn test_dict_inlined_call_stack() {
let mut a = Assert::new();
a.module("f.bzl", "def f(): return {[]: 10}");
let m_g = a.module("g.bzl", "load('f.bzl', 'f')\ndef g(): return f()");
let m_h = a.module("h.bzl", "load('g.bzl', 'g')\ndef h(): return g()");
for (m, f) in [(m_g, "g"), (m_h, "h")] {
let f = m.get(f).unwrap();
let f = f.value().downcast_ref::<FrozenDef>().unwrap();
assert_eq!(
BcOpcode::ListNew,
f.bc().instrs.opcodes().as_slice()[0],
"in `{}`",
f,
);
}
let error = a.fail(
r"
load('h.bzl', 'h')
h()
",
"",
);
assert_eq!(
r"
Traceback (most recent call last):
* assert.bzl:3, in <module>
h()
* h.bzl.bzl:2, in h
def h(): return g()
* g.bzl.bzl:2, in g
def g(): return f()
error: Value of type `list` is not hashable
--> f.bzl.bzl:1:18
|
1 | def f(): return {[]: 10}
| ^^
|
",
&format!("\n{:#}", error)
);
}
#[test]
fn test_do_not_inline_too_large_functions() {
let mut a = Assert::new();
a.module("a0.bzl", "def a0(): return noop()");
for i in 1..100 {
let i_1 = i - 1;
a.module(
&format!("a{i}.bzl"),
&format!(
"load('a{i_1}.bzl', 'a{i_1}')\n\
def a{i}(): return a{i_1}() or a{i_1}()"
),
);
}
}
#[test]
fn test_calls_with_const_args_inlined() {
bc_golden_test(
"def_inline_const_args_inlined",
r#"
def foo(x, y):
return noop(y, x)
def test():
# This call should be inlined.
return foo(10, True)
"#,
);
}
#[test]
fn test_calls_with_locals_inlined() {
bc_golden_test(
"def_inline_locals_inlined",
r#"
def foo(x, y):
return noop(y, x)
def test(x, y):
# This call should be inlined.
return foo(y, x)
"#,
);
}