Support returning default values on subsequent calls after recursion detection

This commit is contained in:
Andrey Breslav
2013-10-02 12:42:21 +04:00
parent e13063017a
commit 7dfe1f963d
2 changed files with 27 additions and 14 deletions
@@ -10,7 +10,8 @@ public abstract class NotNullLazyValueWithDefault<T> extends NotNullLazyValueImp
} }
@Override @Override
public Object recursionDetected() { public Object recursionDetected(boolean firstTime) {
if (firstTime) return super.recursionDetected(firstTime);
return defaultValue; return defaultValue;
} }
} }
@@ -21,29 +21,41 @@ import org.jetbrains.jet.utils.ExceptionUtils;
import org.jetbrains.jet.utils.WrappedValues; import org.jetbrains.jet.utils.WrappedValues;
public abstract class NullableLazyValueImpl<T> implements NullableLazyValue<T> { public abstract class NullableLazyValueImpl<T> implements NullableLazyValue<T> {
private static final Object NOT_COMPUTED = new Object(); private enum State {
private static final Object COMPUTING = new Object(); NOT_COMPUTED,
COMPUTING,
RECURSION_WAS_DETECTED
}
@Nullable @Nullable
private Object value = NOT_COMPUTED; private Object value = State.NOT_COMPUTED;
public boolean isComputed() { public boolean isComputed() {
return value != NOT_COMPUTED; return value != State.NOT_COMPUTED;
} }
@Override @Override
public T compute() { public T compute() {
if (value == COMPUTING) { if (!(value instanceof State)) {
Object result = recursionDetected(); // Computed already
if (result != NOT_COMPUTED) {
return WrappedValues.unescapeThrowable(result);
}
}
else if (value != NOT_COMPUTED) {
return WrappedValues.unescapeThrowable(value); return WrappedValues.unescapeThrowable(value);
} }
value = COMPUTING; if (value == State.COMPUTING) {
Object result = recursionDetected(true);
if (result != State.NOT_COMPUTED) {
value = State.RECURSION_WAS_DETECTED;
return WrappedValues.unescapeThrowable(result);
}
}
else if (value == State.RECURSION_WAS_DETECTED) {
Object result = recursionDetected(false);
if (result != State.NOT_COMPUTED) {
return WrappedValues.unescapeThrowable(result);
}
}
value = State.COMPUTING;
try { try {
T typedValue = doCompute(); T typedValue = doCompute();
value = typedValue; value = typedValue;
@@ -60,7 +72,7 @@ public abstract class NullableLazyValueImpl<T> implements NullableLazyValue<T> {
* @return {@code NOT_COMPUTED} to proceed, a value or wrapped exception otherwise, see WrappedValues * @return {@code NOT_COMPUTED} to proceed, a value or wrapped exception otherwise, see WrappedValues
* @throws DO NOT throw exceptions from implementations of this method, instead return WrappedValues.escapeThrowable(exception) * @throws DO NOT throw exceptions from implementations of this method, instead return WrappedValues.escapeThrowable(exception)
*/ */
public Object recursionDetected() { public Object recursionDetected(boolean firstTime) {
return WrappedValues.escapeThrowable(new ReenteringLazyValueComputationException()); return WrappedValues.escapeThrowable(new ReenteringLazyValueComputationException());
} }