001    /*
002     * Copyright 2010-2013 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.jet.lang.types;
018    
019    import kotlin.Function0;
020    import kotlin.Function1;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
023    import org.jetbrains.jet.lang.resolve.BindingTrace;
024    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
025    import org.jetbrains.jet.storage.NotNullLazyValue;
026    import org.jetbrains.jet.storage.StorageManager;
027    import org.jetbrains.jet.util.Box;
028    import org.jetbrains.jet.util.ReenteringLazyValueComputationException;
029    
030    import java.util.List;
031    
032    import static org.jetbrains.jet.lang.resolve.BindingContext.DEFERRED_TYPE;
033    
034    public class DeferredType implements LazyType {
035    
036        private static final Function1 EMPTY_CONSUMER = new Function1<Object, Void>() {
037            @Override
038            public Void invoke(Object t) {
039                return null;
040            }
041        };
042    
043        private static final Function1<Boolean,JetType> RECURSION_PREVENTER = new Function1<Boolean, JetType>() {
044            @Override
045            public JetType invoke(Boolean firstTime) {
046                if (firstTime) throw new ReenteringLazyValueComputationException();
047                return ErrorUtils.createErrorType("Recursive dependency");
048            }
049        };
050    
051        @NotNull
052        public static DeferredType create(
053                @NotNull StorageManager storageManager,
054                @NotNull BindingTrace trace,
055                @NotNull Function0<JetType> compute
056        ) {
057            DeferredType deferredType = new DeferredType(storageManager.createLazyValue(compute));
058            trace.record(DEFERRED_TYPE, new Box<DeferredType>(deferredType));
059            return deferredType;
060        }
061        
062        @NotNull
063        public static DeferredType createRecursionIntolerant(
064                @NotNull StorageManager storageManager,
065                @NotNull BindingTrace trace,
066                @NotNull Function0<JetType> compute
067        ) {
068            //noinspection unchecked
069            DeferredType deferredType = new DeferredType(storageManager.createLazyValueWithPostCompute(
070                    compute,
071                    RECURSION_PREVENTER,
072                    EMPTY_CONSUMER
073            ));
074            trace.record(DEFERRED_TYPE, new Box<DeferredType>(deferredType));
075            return deferredType;
076        }
077    
078        private final NotNullLazyValue<JetType> lazyValue;
079    
080        private DeferredType(@NotNull NotNullLazyValue<JetType> lazyValue) {
081            this.lazyValue = lazyValue;
082        }
083    
084        public boolean isComputed() {
085            return lazyValue.isComputed();
086        }
087    
088        @NotNull
089        public JetType getActualType() {
090            return lazyValue.invoke();
091        }
092    
093        @Override
094        @NotNull
095        public JetScope getMemberScope() {
096            return getActualType().getMemberScope();
097        }
098    
099        @Override
100        public boolean isError() {
101            return getActualType().isError();
102        }
103    
104        @Override
105        @NotNull
106        public TypeConstructor getConstructor() {
107            return getActualType().getConstructor();
108        }
109    
110        @Override
111        @NotNull
112        public List<TypeProjection> getArguments() {
113            return getActualType().getArguments();
114        }
115    
116        @Override
117        public boolean isNullable() {
118            return getActualType().isNullable();
119        }
120    
121        @NotNull
122        @Override
123        public Annotations getAnnotations() {
124            return getActualType().getAnnotations();
125        }
126    
127        @Override
128        public String toString() {
129            try {
130                if (lazyValue.isComputed()) {
131                    return getActualType().toString();
132                }
133                else {
134                    return "<Not computed yet>";
135                }
136            }
137            catch (ReenteringLazyValueComputationException e) {
138                return "<Failed to compute this type>";
139            }
140        }
141    
142        @Override
143        public boolean equals(Object obj) {
144            return getActualType().equals(obj);
145        }
146    
147        @Override
148        public int hashCode() {
149            return getActualType().hashCode();
150        }
151    }