/* * Copyright 2010-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jetbrains.kotlin.types; import kotlin.jvm.functions.Function0; import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.storage.NotNullLazyValue; import org.jetbrains.kotlin.storage.StorageManager; import org.jetbrains.kotlin.util.Box; import org.jetbrains.kotlin.util.ReenteringLazyValueComputationException; import static org.jetbrains.kotlin.resolve.BindingContext.DEFERRED_TYPE; public class DeferredType extends WrappedType { private static final Function1<Boolean, KotlinType> RECURSION_PREVENTER = firstTime -> { if (firstTime) throw new ReenteringLazyValueComputationException(); return ErrorUtils.createErrorType("Recursive dependency"); }; @NotNull /*package private*/ static DeferredType create( @NotNull StorageManager storageManager, @NotNull BindingTrace trace, @NotNull Function0<KotlinType> compute ) { DeferredType deferredType = new DeferredType(storageManager.createLazyValue(compute)); trace.record(DEFERRED_TYPE, new Box<>(deferredType)); return deferredType; } @NotNull /*package private*/ static DeferredType createRecursionIntolerant( @NotNull StorageManager storageManager, @NotNull BindingTrace trace, @NotNull Function0<KotlinType> compute ) { //noinspection unchecked DeferredType deferredType = new DeferredType(storageManager.createLazyValueWithPostCompute(compute, RECURSION_PREVENTER, t -> null)); trace.record(DEFERRED_TYPE, new Box<>(deferredType)); return deferredType; } private final NotNullLazyValue<KotlinType> lazyValue; private DeferredType(@NotNull NotNullLazyValue<KotlinType> lazyValue) { this.lazyValue = lazyValue; } public boolean isComputing() { return lazyValue.isComputing(); } @Override public boolean isComputed() { return lazyValue.isComputed(); } @NotNull @Override public KotlinType getDelegate() { return lazyValue.invoke(); } @NotNull @Override public String toString() { try { if (lazyValue.isComputed()) { return getDelegate().toString(); } else { return "<Not computed yet>"; } } catch (ReenteringLazyValueComputationException e) { return "<Failed to compute this type>"; } } }