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 5d960d496ad..71c929d7cd9 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 @@ -49,6 +49,7 @@ 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.utils.WrappedValues; import java.util.*; @@ -395,6 +396,12 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements LazyDesc } } }, + new Computable() { + @Override + public Object compute() { + return WrappedValues.unescapeExceptionOrNull(Collections.emptyList()); + } + }, new Consumer>() { @Override public void consume(@NotNull Collection supertypes) { diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/lazy/storage/LockBasedStorageManager.java b/core/descriptors/src/org/jetbrains/jet/lang/resolve/lazy/storage/LockBasedStorageManager.java index eedd0bd4535..2377516dd15 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/lazy/storage/LockBasedStorageManager.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/lazy/storage/LockBasedStorageManager.java @@ -67,8 +67,34 @@ public class LockBasedStorageManager implements StorageManager { @NotNull @Override - public NotNullLazyValue createLazyValueWithPostCompute(@NotNull Computable computable, @NotNull final Consumer postCompute) { + public NotNullLazyValue createRecursionTolerantLazyValue( + @NotNull Computable computable, @NotNull final T onRecursiveCall + ) { return new LockBasedNotNullLazyValue(lock, computable) { + @Override + protected Object recursionDetected() { + return onRecursiveCall; + } + }; + } + + @NotNull + @Override + public NotNullLazyValue createLazyValueWithPostCompute( + @NotNull Computable computable, + final Computable onRecursiveCall, + @NotNull final Consumer postCompute + ) { + return new LockBasedNotNullLazyValue(lock, computable) { + @Nullable + @Override + protected Object recursionDetected() { + if (onRecursiveCall == null) { + return super.recursionDetected(); + } + return onRecursiveCall.compute(); + } + @Override protected void postCompute(@NotNull T value) { postCompute.consume(value); @@ -84,11 +110,11 @@ public class LockBasedStorageManager implements StorageManager { @NotNull @Override - public NullableLazyValue createRecursionTolerantNullableLazyValue(@NotNull Computable computable) { + public NullableLazyValue createRecursionTolerantNullableLazyValue(@NotNull Computable computable, final T onRecursiveCall) { return new LockBasedLazyValue(lock, computable) { @Override protected Object recursionDetected() { - return WrappedValues.escapeNull(null); + return WrappedValues.escapeNull(onRecursiveCall); } }; } diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/lazy/storage/StorageManager.java b/core/descriptors/src/org/jetbrains/jet/lang/resolve/lazy/storage/StorageManager.java index ee74708a1cd..07e56795951 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/lazy/storage/StorageManager.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/lazy/storage/StorageManager.java @@ -20,6 +20,7 @@ import com.intellij.openapi.util.Computable; import com.intellij.util.Consumer; import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public interface StorageManager { /** @@ -38,21 +39,29 @@ public interface StorageManager { @NotNull NotNullLazyValue createLazyValue(@NotNull Computable computable); + @NotNull + NotNullLazyValue createRecursionTolerantLazyValue(@NotNull Computable computable, @NotNull T onRecursiveCall); + /** - * {@code postCompute} is called after the value is computed, but before any other thread sees it (the current thread may + * @param onRecursiveCall is called if the computation calls itself recursively. + * If this parameter is null, an exception will be thrown on a recursive call. + * If this function returns null, the computation proceeds recursively, + * otherwise it should return a result of WrappedValues.escape*() 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, @NotNull Consumer postCompute); + NotNullLazyValue createLazyValueWithPostCompute( + @NotNull Computable computable, + @Nullable Computable onRecursiveCall, + @NotNull Consumer postCompute + ); @NotNull NullableLazyValue createNullableLazyValue(@NotNull Computable computable); - /** - * If recursion is detected, respective calls to compute() simply return null - */ @NotNull - NullableLazyValue createRecursionTolerantNullableLazyValue(@NotNull Computable computable); + NullableLazyValue createRecursionTolerantNullableLazyValue(@NotNull Computable computable, @Nullable T onRecursiveCall); /** * {@code postCompute} is called after the value is computed, but before any other thread sees it (the current thread may