diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java
index 92fcabc74f563da3b458c40e24e9574c08849fc6..5c85b1b9bc29d2fface37cbe6ab4e0064188253a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java
@@ -608,10 +608,11 @@ public class FrameFunctions {
                         RCaller currentCall = RArguments.getCall(f);
                         if (!currentCall.isPromise() && currentCall.getDepth() <= depth) {
                             int currentCallIdx = currentCall.getDepth() - 1;
-                            while (currentCall != null && (currentCall.isPromise())) {
-                                currentCall = currentCall.getParent();
+                            RCaller parent = currentCall.getParent();
+                            while (parent != null && (parent.isPromise())) {
+                                parent = parent.getParent();
                             }
-                            result[currentCallIdx] = currentCall == null ? 0 : currentCall.getParent().getDepth();
+                            result[currentCallIdx] = parent == null ? 0 : parent.getDepth();
                         }
                         return RArguments.getDepth(f) == 1 ? result : null;
                     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCaller.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCaller.java
index 19b7de0d077f7a4f3a845198579f669bc3883c41..5e73298d56c622ecf1d58e6f8c4edff9ca0b0f04 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCaller.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCaller.java
@@ -51,17 +51,20 @@ public final class RCaller {
      * one, the reason are promises, which may be evaluated somewhere deep down the call stack, but
      * their parent call frame from R prespective could be much higher up the actual execution call
      * stack.
+     *
+     * Note: this is depth of the frame where this {@link RCaller} is stored, not the depth of the
+     * parent.
      */
     private final int depth;
     private boolean visibility;
     private final RCaller parent;
     /**
      * The payload can be an RSyntaxNode, a {@link Supplier}, or an {@link RCaller} (which marks
-     * promise evaluation frames). Payload represents the syntax (AST) of how the function was
-     * invoked. If the function was invoked via regular call node, then the syntax can be that call
-     * node (RSyntaxNode case), if the function was invoked by other means and we do not have the
-     * actual syntax for the invocation, we only provide it lazily via Supplier, so that we do not
-     * have to always construct the AST nodes.
+     * promise evaluation frames, see {@link #isPromise()}). Payload represents the syntax (AST) of
+     * how the function was invoked. If the function was invoked via regular call node, then the
+     * syntax can be that call node (RSyntaxNode case), if the function was invoked by other means
+     * and we do not have the actual syntax for the invocation, we only provide it lazily via
+     * Supplier, so that we do not have to always construct the AST nodes.
      */
     private final Object payload;
 
@@ -102,6 +105,29 @@ public final class RCaller {
         return payload != null;
     }
 
+    /**
+     * Promise evaluation frame is artificial frame (does not exist on the R level) that is created
+     * to evaluate a promise in its context.
+     *
+     * Terminology: actual evaluation frame is a frame of the function that created the promise and
+     * the frame in whose context the promise code should be evaluated.
+     *
+     * The artificial promise evaluation frame, marked by the {@link #isPromise()} flag, wraps the
+     * actual evaluation frame in a way that locals are delegated to the actual evaluation frame,
+     * but arguments array is altered. We cannot use the actual evaluation frame as is, because when
+     * there is a function call inside the promise code, the new frame created for the invoked
+     * function will get its {@link #parent} set to {@link RCaller} and {@code depth+1} of its
+     * caller frame. By using wrapped frame for which we set different {@link #depth} than the
+     * actual evaluation frame, we can set the {@link #depth} to the correct value, which is the
+     * {@link #depth} of the code that initiated the promise evaluation.
+     *
+     * Moreover, if the promise code invokes a function, this function should be tricked into
+     * thinking that its caller is the actual evaluation frame. Since this {@link RCaller} will be
+     * used as {@link #parent} inside the frame created for the invoked function, we use
+     * {@link #isPromise()} to find out this is artificial {@link RCaller} and we should follow the
+     * {@link #getParent()} chain until we reach the actual evaluation frame and take the real
+     * parent from there.
+     */
     public boolean isPromise() {
         return payload instanceof RCaller;
     }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
index 3b787d3e951f582f2b95faf4ad856f155322c935..d638e4150b279cd06bc013971f512f79866b0351 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
@@ -75241,6 +75241,10 @@ NULL
 #{ f <- function(x=sys.parents()) x ; g <- function() f() ; h <- function() g() ; h() }
 [1] 0 1 2
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_sysparents.testSysParents#
+#{ f4 <- function() sys.parents(); f3 <- function(y) y; f2 <- function(x) x; f1 <- function() f2(f3(f4())); f1(); }
+[1] 0 1 1 1
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_sysparents.testSysParents#
 #{ sys.parents() }
 integer(0)
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_sysparents.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_sysparents.java
index 27d8ecc6134151e99cc500fa4d777b304e6094df..1d0ce81d3adbe2b139d07ce181a3e3e271998673 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_sysparents.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_sysparents.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2012-2014, Purdue University
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -26,6 +26,7 @@ public class TestBuiltin_sysparents extends TestBase {
         assertEval("{ f <- function(x=sys.parents()) x ; g <- function() f() ; h <- function() g() ; h() }");
         assertEval("{ f <- function(x) x ; g <- function(y) f(y) ; h <- function(z=sys.parents()) g(z) ; h() }");
 
+        assertEval("{ f4 <- function() sys.parents(); f3 <- function(y) y; f2 <- function(x) x; f1 <- function() f2(f3(f4())); f1(); }");
         assertEval(Ignored.ImplementationError, "{ u <- function() sys.parents() ; f <- function(x) x ; g <- function(y) f(y) ; h <- function(z=u()) g(z) ; h() }");
     }