001    /*
002     * Copyright 2010-2016 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 WrappedType {
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        @Override
085        public boolean isComputed() {
086            return lazyValue.isComputed();
087        }
088    
089        @NotNull
090        @Override
091        public KotlinType getDelegate() {
092            return lazyValue.invoke();
093        }
094    
095        @NotNull
096        @Override
097        public String toString() {
098            try {
099                if (lazyValue.isComputed()) {
100                    return getDelegate().toString();
101                }
102                else {
103                    return "<Not computed yet>";
104                }
105            }
106            catch (ReenteringLazyValueComputationException e) {
107                return "<Failed to compute this type>";
108            }
109        }
110    }