Distinguishing first and subsequent recursive calls to lazy values
This commit is contained in:
+6
-6
@@ -23,6 +23,7 @@ import com.google.common.collect.Lists;
|
|||||||
import com.intellij.openapi.util.Computable;
|
import com.intellij.openapi.util.Computable;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import com.intellij.util.Consumer;
|
import com.intellij.util.Consumer;
|
||||||
|
import com.intellij.util.Function;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
@@ -41,15 +42,14 @@ import org.jetbrains.jet.lang.resolve.lazy.data.FilteringClassLikeInfo;
|
|||||||
import org.jetbrains.jet.lang.resolve.lazy.data.JetClassInfoUtil;
|
import org.jetbrains.jet.lang.resolve.lazy.data.JetClassInfoUtil;
|
||||||
import org.jetbrains.jet.lang.resolve.lazy.data.JetClassLikeInfo;
|
import org.jetbrains.jet.lang.resolve.lazy.data.JetClassLikeInfo;
|
||||||
import org.jetbrains.jet.lang.resolve.lazy.declarations.ClassMemberDeclarationProvider;
|
import org.jetbrains.jet.lang.resolve.lazy.declarations.ClassMemberDeclarationProvider;
|
||||||
import org.jetbrains.jet.storage.NotNullLazyValue;
|
|
||||||
import org.jetbrains.jet.storage.NullableLazyValue;
|
|
||||||
import org.jetbrains.jet.storage.StorageManager;
|
|
||||||
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
|
|
||||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.*;
|
import org.jetbrains.jet.lang.resolve.scopes.*;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
import org.jetbrains.jet.lang.types.TypeConstructor;
|
import org.jetbrains.jet.lang.types.TypeConstructor;
|
||||||
import org.jetbrains.jet.lang.types.TypeUtils;
|
import org.jetbrains.jet.lang.types.TypeUtils;
|
||||||
|
import org.jetbrains.jet.storage.NotNullLazyValue;
|
||||||
|
import org.jetbrains.jet.storage.NullableLazyValue;
|
||||||
|
import org.jetbrains.jet.storage.StorageManager;
|
||||||
import org.jetbrains.jet.utils.WrappedValues;
|
import org.jetbrains.jet.utils.WrappedValues;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -397,9 +397,9 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements LazyDesc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Computable<Object>() {
|
new Function<Boolean, Object>() {
|
||||||
@Override
|
@Override
|
||||||
public Object compute() {
|
public Object fun(Boolean firstTime) {
|
||||||
return WrappedValues.unescapeExceptionOrNull(Collections.emptyList());
|
return WrappedValues.unescapeExceptionOrNull(Collections.emptyList());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ public class LockBasedStorageManager implements StorageManager {
|
|||||||
) {
|
) {
|
||||||
return new LockBasedNotNullLazyValue<T>(lock, computable) {
|
return new LockBasedNotNullLazyValue<T>(lock, computable) {
|
||||||
@Override
|
@Override
|
||||||
protected Object recursionDetected() {
|
protected Object recursionDetected(boolean firstTime) {
|
||||||
return onRecursiveCall;
|
return onRecursiveCall;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -94,17 +94,17 @@ public class LockBasedStorageManager implements StorageManager {
|
|||||||
@Override
|
@Override
|
||||||
public <T> NotNullLazyValue<T> createLazyValueWithPostCompute(
|
public <T> NotNullLazyValue<T> createLazyValueWithPostCompute(
|
||||||
@NotNull Computable<T> computable,
|
@NotNull Computable<T> computable,
|
||||||
final Computable<Object> onRecursiveCall,
|
final Function<Boolean, Object> onRecursiveCall,
|
||||||
@NotNull final Consumer<T> postCompute
|
@NotNull final Consumer<T> postCompute
|
||||||
) {
|
) {
|
||||||
return new LockBasedNotNullLazyValue<T>(lock, computable) {
|
return new LockBasedNotNullLazyValue<T>(lock, computable) {
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
protected Object recursionDetected() {
|
protected Object recursionDetected(boolean firstTime) {
|
||||||
if (onRecursiveCall == null) {
|
if (onRecursiveCall == null) {
|
||||||
return super.recursionDetected();
|
return super.recursionDetected(firstTime);
|
||||||
}
|
}
|
||||||
return onRecursiveCall.compute();
|
return onRecursiveCall.fun(firstTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -125,7 +125,7 @@ public class LockBasedStorageManager implements StorageManager {
|
|||||||
public <T> NullableLazyValue<T> createRecursionTolerantNullableLazyValue(@NotNull Computable<T> computable, final T onRecursiveCall) {
|
public <T> NullableLazyValue<T> createRecursionTolerantNullableLazyValue(@NotNull Computable<T> computable, final T onRecursiveCall) {
|
||||||
return new LockBasedLazyValue<T>(lock, computable) {
|
return new LockBasedLazyValue<T>(lock, computable) {
|
||||||
@Override
|
@Override
|
||||||
protected Object recursionDetected() {
|
protected Object recursionDetected(boolean firstTime) {
|
||||||
return onRecursiveCall;
|
return onRecursiveCall;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -159,7 +159,8 @@ public class LockBasedStorageManager implements StorageManager {
|
|||||||
|
|
||||||
private enum NotValue {
|
private enum NotValue {
|
||||||
NOT_COMPUTED,
|
NOT_COMPUTED,
|
||||||
COMPUTING
|
COMPUTING,
|
||||||
|
RECURSION_WAS_DETECTED
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Lock lock;
|
private final Lock lock;
|
||||||
@@ -188,7 +189,14 @@ public class LockBasedStorageManager implements StorageManager {
|
|||||||
_value = value;
|
_value = value;
|
||||||
if (!(_value instanceof NotValue)) return WrappedValues.unescapeThrowable(_value);
|
if (!(_value instanceof NotValue)) return WrappedValues.unescapeThrowable(_value);
|
||||||
|
|
||||||
if (_value == NotValue.COMPUTING) return WrappedValues.unescapeThrowable(recursionDetected());
|
if (_value == NotValue.COMPUTING) {
|
||||||
|
value = NotValue.RECURSION_WAS_DETECTED;
|
||||||
|
return WrappedValues.unescapeThrowable(recursionDetected(/*firstTime = */ true));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_value == NotValue.RECURSION_WAS_DETECTED) {
|
||||||
|
return WrappedValues.unescapeThrowable(recursionDetected(/*firstTime = */ false));
|
||||||
|
}
|
||||||
|
|
||||||
value = NotValue.COMPUTING;
|
value = NotValue.COMPUTING;
|
||||||
try {
|
try {
|
||||||
@@ -208,11 +216,12 @@ public class LockBasedStorageManager implements StorageManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param firstTime {@code true} when recursion has been just detected, {@code false} otherwise
|
||||||
* @return a value or wrapped exception, see WrappedValues
|
* @return a value or wrapped exception, 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)
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
protected Object recursionDetected() {
|
protected Object recursionDetected(boolean firstTime) {
|
||||||
return WrappedValues.escapeThrowable(new IllegalStateException("Recursive call in a lazy value"));
|
return WrappedValues.escapeThrowable(new IllegalStateException("Recursive call in a lazy value"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,15 +44,15 @@ public interface StorageManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param onRecursiveCall is called if the computation calls itself recursively.
|
* @param onRecursiveCall is called if the computation calls itself recursively.
|
||||||
* If this parameter is null, an exception will be thrown on a recursive call,
|
* The parameter to it is {@code true} for the first call, {@code false} otherwise.
|
||||||
|
* If {@code onRecursiveCall} is {@code null}, an exception will be thrown on a recursive call,
|
||||||
* otherwise it should return a result of WrappedValues.escapeThrowable() method
|
* otherwise it should return a result of WrappedValues.escapeThrowable() method
|
||||||
* @param postCompute is called after the value is computed, but before any other thread sees it
|
* @param postCompute is called after the value is computed, but before any other thread sees it
|
||||||
* (the current thread may see it in between)
|
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
<T> NotNullLazyValue<T> createLazyValueWithPostCompute(
|
<T> NotNullLazyValue<T> createLazyValueWithPostCompute(
|
||||||
@NotNull Computable<T> computable,
|
@NotNull Computable<T> computable,
|
||||||
@Nullable Computable<Object> onRecursiveCall,
|
@Nullable Function<Boolean, Object> onRecursiveCall,
|
||||||
@NotNull Consumer<T> postCompute
|
@NotNull Consumer<T> postCompute
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user