diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/descriptors/LazyClassDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/descriptors/LazyClassDescriptor.java index f71aa1eaea7..56080d28afe 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/descriptors/LazyClassDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/descriptors/LazyClassDescriptor.java @@ -23,6 +23,7 @@ import com.google.common.collect.Lists; import com.intellij.openapi.util.Computable; import com.intellij.psi.PsiElement; import com.intellij.util.Consumer; +import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; 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.JetClassLikeInfo; 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.scopes.*; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeConstructor; 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 java.util.*; @@ -397,9 +397,9 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements LazyDesc } } }, - new Computable() { + new Function() { @Override - public Object compute() { + public Object fun(Boolean firstTime) { return WrappedValues.unescapeExceptionOrNull(Collections.emptyList()); } }, diff --git a/core/util.runtime/src/org/jetbrains/jet/storage/LockBasedStorageManager.java b/core/util.runtime/src/org/jetbrains/jet/storage/LockBasedStorageManager.java index d2fa481b416..132908ff15f 100644 --- a/core/util.runtime/src/org/jetbrains/jet/storage/LockBasedStorageManager.java +++ b/core/util.runtime/src/org/jetbrains/jet/storage/LockBasedStorageManager.java @@ -84,7 +84,7 @@ public class LockBasedStorageManager implements StorageManager { ) { return new LockBasedNotNullLazyValue(lock, computable) { @Override - protected Object recursionDetected() { + protected Object recursionDetected(boolean firstTime) { return onRecursiveCall; } }; @@ -94,17 +94,17 @@ public class LockBasedStorageManager implements StorageManager { @Override public NotNullLazyValue createLazyValueWithPostCompute( @NotNull Computable computable, - final Computable onRecursiveCall, + final Function onRecursiveCall, @NotNull final Consumer postCompute ) { return new LockBasedNotNullLazyValue(lock, computable) { @Nullable @Override - protected Object recursionDetected() { + protected Object recursionDetected(boolean firstTime) { if (onRecursiveCall == null) { - return super.recursionDetected(); + return super.recursionDetected(firstTime); } - return onRecursiveCall.compute(); + return onRecursiveCall.fun(firstTime); } @Override @@ -125,7 +125,7 @@ public class LockBasedStorageManager implements StorageManager { public NullableLazyValue createRecursionTolerantNullableLazyValue(@NotNull Computable computable, final T onRecursiveCall) { return new LockBasedLazyValue(lock, computable) { @Override - protected Object recursionDetected() { + protected Object recursionDetected(boolean firstTime) { return onRecursiveCall; } }; @@ -159,7 +159,8 @@ public class LockBasedStorageManager implements StorageManager { private enum NotValue { NOT_COMPUTED, - COMPUTING + COMPUTING, + RECURSION_WAS_DETECTED } private final Lock lock; @@ -188,7 +189,14 @@ public class LockBasedStorageManager implements StorageManager { _value = 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; 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 * @throws DO NOT throw exceptions from implementations of this method, instead return WrappedValues.escapeThrowable(exception) */ @Nullable - protected Object recursionDetected() { + protected Object recursionDetected(boolean firstTime) { return WrappedValues.escapeThrowable(new IllegalStateException("Recursive call in a lazy value")); } diff --git a/core/util.runtime/src/org/jetbrains/jet/storage/StorageManager.java b/core/util.runtime/src/org/jetbrains/jet/storage/StorageManager.java index 1453a61b356..6f92c366abf 100644 --- a/core/util.runtime/src/org/jetbrains/jet/storage/StorageManager.java +++ b/core/util.runtime/src/org/jetbrains/jet/storage/StorageManager.java @@ -44,15 +44,15 @@ public interface StorageManager { /** * @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 * @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 NotNullLazyValue createLazyValueWithPostCompute( @NotNull Computable computable, - @Nullable Computable onRecursiveCall, + @Nullable Function onRecursiveCall, @NotNull Consumer postCompute );