Only count a tail-call if it actually is one

in e.g.

case x of
    0 -> 0
    _ -> f ( x - 1)

The old code would look at the first branch. it is not a tail call, so
it concluded that the whole expression isn't. But the second branch is.
This commit is contained in:
Folkert 2019-11-28 13:04:15 +01:00
parent 5063c3ac7f
commit d171506fc7

View file

@ -841,9 +841,14 @@ fn canonicalize_case_branch<'a>(
// If all branches are tail calling the same symbol, then so is the conditional as a whole. // If all branches are tail calling the same symbol, then so is the conditional as a whole.
if !*recorded_tail_call { if !*recorded_tail_call {
// If we haven't recorded output.tail_call yet, record it. match branch_output.tail_call {
output.tail_call = branch_output.tail_call; Some(call) => {
*recorded_tail_call = true; // If we haven't recorded output.tail_call yet, record it.
output.tail_call = Some(call);
*recorded_tail_call = true;
}
None => output.tail_call = None,
};
} else if branch_output.tail_call != output.tail_call { } else if branch_output.tail_call != output.tail_call {
// If we recorded output.tail_call, but what we recorded differs from what we just saw, // If we recorded output.tail_call, but what we recorded differs from what we just saw,
// then game over. This can't possibly be a self tail call! // then game over. This can't possibly be a self tail call!
@ -1506,7 +1511,7 @@ fn can_defs<'a>(
ret_constraint: can_output.constraint.clone(), ret_constraint: can_output.constraint.clone(),
}))); })));
// see below: a closure needs a fresh References! // see below: a closure needs a fresh References!
let mut is_closure = false; let mut is_closure = false;
match ( match (
@ -1532,7 +1537,11 @@ fn can_defs<'a>(
let references = env.closures.remove(&symbol).unwrap_or_else(|| let references = env.closures.remove(&symbol).unwrap_or_else(||
panic!("Tried to remove symbol {:?} from procedures, but it was not found: {:?}", symbol, env.closures)); panic!("Tried to remove symbol {:?} from procedures, but it was not found: {:?}", symbol, env.closures));
dbg!(loc_can_expr.clone(), can_output.tail_call.clone(), defined_symbol.clone()); dbg!(
loc_can_expr.clone(),
can_output.tail_call.clone(),
defined_symbol.clone()
);
// The closure is self tail recursive iff it tail calls itself (by defined name). // The closure is self tail recursive iff it tail calls itself (by defined name).
let is_recursive = if let Some(ref symbol) = can_output.tail_call { let is_recursive = if let Some(ref symbol) = can_output.tail_call {
if symbol == defined_symbol { if symbol == defined_symbol {
@ -1578,7 +1587,6 @@ fn can_defs<'a>(
// Functions' references don't count in defs. // Functions' references don't count in defs.
// See 3d5a2560057d7f25813112dfa5309956c0f9e6a9 and its // See 3d5a2560057d7f25813112dfa5309956c0f9e6a9 and its
// parent commit for the bug this fixed! // parent commit for the bug this fixed!
if is_closure { if is_closure {
References::new() References::new()
} else { } else {