private void buildRescueBodyInternal(IRScope s, Node node, Variable rv, Label endLabel) {
final RescueBodyNode rescueBodyNode = (RescueBodyNode) node;
final Node exceptionList = rescueBodyNode.getExceptionNodes();
// Load exception & exception comparison type
Variable exc = s.getNewTemporaryVariable();
s.addInstr(new ReceiveExceptionInstr(exc));
// Compare and branch as necessary!
Label uncaughtLabel = s.getNewLabel();
Label caughtLabel = s.getNewLabel();
if (exceptionList != null) {
if (exceptionList instanceof ListNode) {
for (Node excType : ((ListNode) exceptionList).childNodes()) {
outputExceptionCheck(s, build(excType, s), exc, caughtLabel);
}
} else { // splatnode, catch
outputExceptionCheck(s, build(((SplatNode)exceptionList).getValue(), s), exc, caughtLabel);
}
} else {
// FIXME:
// rescue => e AND rescue implicitly EQQ the exception object with StandardError
// We generate explicit IR for this test here. But, this can lead to inconsistent
// behavior (when compared to MRI) in certain scenarios. See example:
//
// self.class.const_set(:StandardError, 1)
// begin; raise TypeError.new; rescue; puts "AHA"; end
//
// MRI rescues the error, but we will raise an exception because of reassignment
// of StandardError. I am ignoring this for now and treating this as undefined behavior.
//
// SSS FIXME: Create a 'StandardError' operand type to eliminate this.
Variable v = s.getNewTemporaryVariable();
s.addInstr(new InheritanceSearchConstInstr(v, s.getCurrentModuleVariable(), "StandardError", false));
outputExceptionCheck(s, v, exc, caughtLabel);
}
// Uncaught exception -- build other rescue nodes or rethrow!