[Detail Bug] Compiler: `if` conditions optimized to constants drop side effects and produce mis-indented Bash
- Vorherrschende Sprache
- Rust
- Sterne
- 5.2k
- Forks
- 145
- Ø Merge
- 5 T. 3 Std.
- Gemergte PRs (30 T.)
- 7
Beschreibung
# Summary
- **Context**: `IfCondition::translate` in `src/modules/condition/ifcond.rs` is responsible for translating `if` statements into Bash code, including an optimization for conditions known at compile-time.
- **Bug**: The translation process for statically known conditions (`true` or `false`) completely skips translating the condition expression itself, which causes all side effects within that expression to be lost.
- **Actual vs. expected**: Statically optimized `if` conditions lose side effects like command executions and function calls, whereas they should be preserved even if the condition's value is constant.
- **Impact**: Valid Amber code that relies on side effects within an `if` condition will produce incorrect Bash scripts where those side effects never occur.
# Code with bug
```rust
match self.expr.analyze_control_flow() {
Some(true) => self
.true_block
.as_ref()
.map(|b| b.translate(meta)) // <-- BUG 🔴 [Loses side effects of self.expr and has wrong indentation]
.unwrap_or(FragmentKind::Empty),
Some(false) => self
.false_block
.as_ref()
.map(|b| b.translate(meta)) // <-- BUG 🔴 [Loses side effects of self.expr and has wrong indentation]
.unwrap_or(FragmentKind::Empty),
```
# Evidence
### Side effect loss
When compiling the following Amber code:
```amber
fun my_func(): Bool {
echo "Side effect"
return false
}
if my_func() or true {
echo "Done"
}
```
The compiler determines that `my_func() or true` is statically `true` (since `or true` is always true). It then skips the translation of the expression, resulting in Bash code where `my_func` is defined but **never called**:
```bash
my_func__0_v0() {
echo "Side effect"
ret_my_func0_v0=0
return 0
}
# The call to my_func__0_v0 is missing here!
echo "Done"
```
The expected behavior is that `my_func` should be called before `echo "Done"`.
### Indentation bug
Additionally, the optimization returns the translated block directly, which results in incorrect indentation in the generated Bash. For example:
```amber
if true {
echo "Done"
}
```
Generates:
```bash
echo "Done"
```
Instead of:
```bash
echo "Done"
```
The leading spaces are preserved because the block was translated with `increase_indent: true`, but the `if` statement that would have justified the indentation was removed.
# Why has this bug gone undetected?
This bug primarily affects expressions that combine compile-time constants with side-effect-ful operations (like commands or functions) in a way that allows the compiler to determine the result statically. In typical scripts, `if` conditions are either fully dynamic or simple literals, making this edge case rare but critical for correctness.
# Recommended fix
The `translate` method should always call `self.expr.translate(meta)` to ensure side effects are pushed to the statement queue, even if the result is ignored. Furthermore, when unwrapping a block due to static optimization, its indentation should be adjusted.
```rust
fn translate(&self, meta: &mut TranslateMetadata) -> FragmentKind {
let _ = self.expr.translate(meta); // Preserve side effects 🟢
match self.expr.analyze_control_flow() {
Some(true) => {
if let Some(true_block) = &self.true_block {
let mut frag = true_block.translate(meta);
if let FragmentKind::Block(ref mut block) = frag {
block.increase_indent = false; // Fix indentation 🟢
}
frag
} else {
FragmentKind::Empty
}
}
// ... similar for Some(false) ...
```
# Related bugs
Similar aggressive optimizations that lose side effects are also present in `src/modules/condition/ifchain.rs` and `src/modules/expression/ternop/ternary.rs`.
# History
This bug was introduced in commit 09af993 (@Ph0enixKM, 2025-12-19, PR #940). The change added control flow analysis to optimize statically known conditions, but it incorrectly skipped calling `translate()` on the condition expression, losing its side effects, and failed to handle block indentation when unwrapping optimized branches.
Beitragsleitfaden
Für dieses Repository ist kein Beitragsleitfaden indexiert
Bewertung
Dieses Issue wurde noch nicht bewertet.