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 isComputing() {
081            return lazyValue.isComputing();
082        }
083    
084        public boolean isComputed() {
085            return lazyValue.isComputed();
086        }
087    
088        @Override
089        public KotlinType getDelegate() {
090            return lazyValue.invoke();
091        }
092    
093        @Override
094        public String toString() {
095            try {
096                if (lazyValue.isComputed()) {
097                    return getDelegate().toString();
098                }
099                else {
100                    return "<Not computed yet>";
101                }
102            }
103            catch (ReenteringLazyValueComputationException e) {
104                return "<Failed to compute this type>";
105            }
106        }
107    }