001 /*
002 * Copyright 2010-2015 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.kotlin.types;
018
019 import kotlin.jvm.functions.Function0;
020 import kotlin.jvm.functions.Function1;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.kotlin.resolve.BindingTrace;
023 import org.jetbrains.kotlin.storage.NotNullLazyValue;
024 import org.jetbrains.kotlin.storage.StorageManager;
025 import org.jetbrains.kotlin.util.Box;
026 import org.jetbrains.kotlin.util.ReenteringLazyValueComputationException;
027
028 import static org.jetbrains.kotlin.resolve.BindingContext.DEFERRED_TYPE;
029
030 public class DeferredType extends DelegatingType implements LazyType {
031
032 private static final Function1 EMPTY_CONSUMER = new Function1<Object, Void>() {
033 @Override
034 public Void invoke(Object t) {
035 return null;
036 }
037 };
038
039 private static final Function1<Boolean,KotlinType> RECURSION_PREVENTER = new Function1<Boolean, KotlinType>() {
040 @Override
041 public KotlinType invoke(Boolean firstTime) {
042 if (firstTime) throw new ReenteringLazyValueComputationException();
043 return ErrorUtils.createErrorType("Recursive dependency");
044 }
045 };
046
047 @NotNull
048 public static DeferredType create(
049 @NotNull StorageManager storageManager,
050 @NotNull BindingTrace trace,
051 @NotNull Function0<KotlinType> compute
052 ) {
053 DeferredType deferredType = new DeferredType(storageManager.createLazyValue(compute));
054 trace.record(DEFERRED_TYPE, new Box<DeferredType>(deferredType));
055 return deferredType;
056 }
057
058 @NotNull
059 public static DeferredType createRecursionIntolerant(
060 @NotNull StorageManager storageManager,
061 @NotNull BindingTrace trace,
062 @NotNull Function0<KotlinType> compute
063 ) {
064 //noinspection unchecked
065 DeferredType deferredType = new DeferredType(storageManager.createLazyValueWithPostCompute(
066 compute,
067 RECURSION_PREVENTER,
068 EMPTY_CONSUMER
069 ));
070 trace.record(DEFERRED_TYPE, new Box<DeferredType>(deferredType));
071 return deferredType;
072 }
073
074 private final NotNullLazyValue<KotlinType> lazyValue;
075
076 private DeferredType(@NotNull NotNullLazyValue<KotlinType> lazyValue) {
077 this.lazyValue = lazyValue;
078 }
079
080 public boolean isComputed() {
081 return lazyValue.isComputed();
082 }
083
084 @Override
085 public KotlinType getDelegate() {
086 return lazyValue.invoke();
087 }
088
089 @Override
090 public String toString() {
091 try {
092 if (lazyValue.isComputed()) {
093 return getDelegate().toString();
094 }
095 else {
096 return "<Not computed yet>";
097 }
098 }
099 catch (ReenteringLazyValueComputationException e) {
100 return "<Failed to compute this type>";
101 }
102 }
103 }