org.jetbrains.kotlin.resolve.BodyResolver Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlin-compiler-embeddable Show documentation
Show all versions of kotlin-compiler-embeddable Show documentation
the Kotlin compiler embeddable
/*
* Copyright 2010-2017 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.resolve;
import com.google.common.collect.Maps;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import kotlin.Unit;
import kotlin.collections.CollectionsKt;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.FunctionTypesKt;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.config.LanguageFeature;
import org.jetbrains.kotlin.config.LanguageVersionSettings;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.name.SpecialNames;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
import org.jetbrains.kotlin.resolve.calls.CallResolver;
import org.jetbrains.kotlin.resolve.calls.components.InferenceSession;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil;
import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolverKt;
import org.jetbrains.kotlin.resolve.scopes.*;
import org.jetbrains.kotlin.resolve.source.KotlinSourceElementKt;
import org.jetbrains.kotlin.types.*;
import org.jetbrains.kotlin.types.error.ErrorUtils;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices;
import org.jetbrains.kotlin.types.expressions.PreliminaryDeclarationVisitor;
import org.jetbrains.kotlin.types.expressions.ValueParameterResolver;
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
import org.jetbrains.kotlin.util.Box;
import org.jetbrains.kotlin.util.ReenteringLazyValueComputationException;
import java.util.*;
import static org.jetbrains.kotlin.config.LanguageFeature.AllowSealedInheritorsInDifferentFilesOfSamePackage;
import static org.jetbrains.kotlin.config.LanguageFeature.TopLevelSealedInheritance;
import static org.jetbrains.kotlin.diagnostics.Errors.*;
import static org.jetbrains.kotlin.resolve.BindingContext.*;
import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt.isEffectivelyExternal;
import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
public class BodyResolver {
@NotNull private final Project project;
@NotNull private final AnnotationChecker annotationChecker;
@NotNull private final ExpressionTypingServices expressionTypingServices;
@NotNull private final CallResolver callResolver;
@NotNull private final ObservableBindingTrace trace;
@NotNull private final ControlFlowAnalyzer controlFlowAnalyzer;
@NotNull private final DeclarationsChecker declarationsChecker;
@NotNull private final AnnotationResolver annotationResolver;
@NotNull private final DelegatedPropertyResolver delegatedPropertyResolver;
@NotNull private final AnalyzerExtensions analyzerExtensions;
@NotNull private final ValueParameterResolver valueParameterResolver;
@NotNull private final BodyResolveCache bodyResolveCache;
@NotNull private final KotlinBuiltIns builtIns;
@NotNull private final OverloadChecker overloadChecker;
@NotNull private final LanguageVersionSettings languageVersionSettings;
public BodyResolver(
@NotNull Project project,
@NotNull AnnotationResolver annotationResolver,
@NotNull BodyResolveCache bodyResolveCache,
@NotNull CallResolver callResolver,
@NotNull ControlFlowAnalyzer controlFlowAnalyzer,
@NotNull DeclarationsChecker declarationsChecker,
@NotNull DelegatedPropertyResolver delegatedPropertyResolver,
@NotNull ExpressionTypingServices expressionTypingServices,
@NotNull AnalyzerExtensions analyzerExtensions,
@NotNull BindingTrace trace,
@NotNull ValueParameterResolver valueParameterResolver,
@NotNull AnnotationChecker annotationChecker,
@NotNull KotlinBuiltIns builtIns,
@NotNull OverloadChecker overloadChecker,
@NotNull LanguageVersionSettings languageVersionSettings
) {
this.project = project;
this.annotationResolver = annotationResolver;
this.bodyResolveCache = bodyResolveCache;
this.callResolver = callResolver;
this.controlFlowAnalyzer = controlFlowAnalyzer;
this.declarationsChecker = declarationsChecker;
this.delegatedPropertyResolver = delegatedPropertyResolver;
this.expressionTypingServices = expressionTypingServices;
this.analyzerExtensions = analyzerExtensions;
this.annotationChecker = annotationChecker;
this.overloadChecker = overloadChecker;
this.trace = new ObservableBindingTrace(trace);
this.valueParameterResolver = valueParameterResolver;
this.builtIns = builtIns;
this.languageVersionSettings = languageVersionSettings;
}
private void resolveBehaviorDeclarationBodies(@NotNull BodiesResolveContext c) {
resolveSuperTypeEntryLists(c);
resolvePropertyDeclarationBodies(c);
resolveAnonymousInitializers(c);
resolvePrimaryConstructorParameters(c);
resolveSecondaryConstructors(c);
resolveFunctionBodies(c);
if (!c.getTopDownAnalysisMode().isLocalDeclarations()) {
computeDeferredTypes();
}
}
private void resolveSecondaryConstructors(@NotNull BodiesResolveContext c) {
for (Map.Entry entry : c.getSecondaryConstructors().entrySet()) {
LexicalScope declaringScope = c.getDeclaringScope(entry.getKey());
assert declaringScope != null : "Declaring scope should be registered before body resolve";
resolveSecondaryConstructorBody(c.getOuterDataFlowInfo(), trace, entry.getKey(), entry.getValue(), declaringScope, c.getLocalContext());
}
if (c.getSecondaryConstructors().isEmpty()) return;
Set visitedConstructors = new HashSet<>();
for (Map.Entry entry : c.getSecondaryConstructors().entrySet()) {
checkCyclicConstructorDelegationCall(entry.getValue(), visitedConstructors);
}
}
public void resolveSecondaryConstructorBody(
@NotNull DataFlowInfo outerDataFlowInfo,
@NotNull BindingTrace trace,
@NotNull KtSecondaryConstructor constructor,
@NotNull ClassConstructorDescriptor descriptor,
@NotNull LexicalScope declaringScope,
@Nullable ExpressionTypingContext localContext
) {
ForceResolveUtil.forceResolveAllContents(descriptor.getAnnotations());
resolveFunctionBody(
outerDataFlowInfo, trace, constructor, descriptor, declaringScope,
headerInnerScope -> resolveSecondaryConstructorDelegationCall(
outerDataFlowInfo, trace, headerInnerScope, constructor,
descriptor, localContext != null ? localContext.inferenceSession : null
),
scope -> new LexicalScopeImpl(
scope, descriptor, scope.isOwnerDescriptorAccessibleByLabel(), scope.getImplicitReceiver(), scope.getContextReceiversGroup(),
LexicalScopeKind.CONSTRUCTOR_HEADER
),
localContext
);
}
@Nullable
private DataFlowInfo resolveSecondaryConstructorDelegationCall(
@NotNull DataFlowInfo outerDataFlowInfo,
@NotNull BindingTrace trace,
@NotNull LexicalScope scope,
@NotNull KtSecondaryConstructor constructor,
@NotNull ClassConstructorDescriptor descriptor,
@Nullable InferenceSession inferenceSession
) {
if (descriptor.isExpect() || isEffectivelyExternal(descriptor)) {
// For expected and external classes, we do not resolve constructor delegation calls because they are prohibited
return DataFlowInfo.Companion.getEMPTY();
}
OverloadResolutionResults> results = callResolver.resolveConstructorDelegationCall(
trace, scope, outerDataFlowInfo,
descriptor, constructor.getDelegationCall(), inferenceSession);
if (results != null && results.isSingleResult()) {
ResolvedCall extends CallableDescriptor> resolvedCall = results.getResultingCall();
recordConstructorDelegationCall(trace, descriptor, resolvedCall);
return resolvedCall.getDataFlowInfoForArguments().getResultInfo();
}
return null;
}
private void checkCyclicConstructorDelegationCall(
@NotNull ConstructorDescriptor constructorDescriptor,
@NotNull Set visitedConstructors
) {
if (visitedConstructors.contains(constructorDescriptor)) return;
// if visit constructor that is already in current chain
// such constructor is on cycle
Set visitedInCurrentChain = new HashSet<>();
ConstructorDescriptor currentConstructorDescriptor = constructorDescriptor;
while (true) {
ProgressManager.checkCanceled();
visitedInCurrentChain.add(currentConstructorDescriptor);
ConstructorDescriptor delegatedConstructorDescriptor = getDelegatedConstructor(currentConstructorDescriptor);
if (delegatedConstructorDescriptor == null) break;
// if next delegation call is super or primary constructor or already visited
if (!constructorDescriptor.getContainingDeclaration().equals(delegatedConstructorDescriptor.getContainingDeclaration()) ||
delegatedConstructorDescriptor.isPrimary() ||
visitedConstructors.contains(delegatedConstructorDescriptor)) {
break;
}
if (visitedInCurrentChain.contains(delegatedConstructorDescriptor)) {
reportEachConstructorOnCycle(delegatedConstructorDescriptor);
break;
}
currentConstructorDescriptor = delegatedConstructorDescriptor;
}
visitedConstructors.addAll(visitedInCurrentChain);
}
private void reportEachConstructorOnCycle(@NotNull ConstructorDescriptor startConstructor) {
ConstructorDescriptor currentConstructor = startConstructor;
do {
PsiElement constructorToReport = DescriptorToSourceUtils.descriptorToDeclaration(currentConstructor);
if (constructorToReport != null) {
KtConstructorDelegationCall call = ((KtSecondaryConstructor) constructorToReport).getDelegationCall();
assert call.getCalleeExpression() != null
: "Callee expression of delegation call should not be null on cycle as there should be explicit 'this' calls";
trace.report(CYCLIC_CONSTRUCTOR_DELEGATION_CALL.on(call.getCalleeExpression()));
}
currentConstructor = getDelegatedConstructor(currentConstructor);
assert currentConstructor != null : "Delegated constructor should not be null in cycle";
}
while (startConstructor != currentConstructor);
}
@Nullable
private ConstructorDescriptor getDelegatedConstructor(@NotNull ConstructorDescriptor constructor) {
ResolvedCall call = trace.get(CONSTRUCTOR_RESOLVED_DELEGATION_CALL, constructor);
return call == null || !call.getStatus().isSuccess() ? null : call.getResultingDescriptor().getOriginal();
}
public void resolveBodies(@NotNull BodiesResolveContext c) {
resolveBehaviorDeclarationBodies(c);
controlFlowAnalyzer.process(c);
declarationsChecker.process(c);
analyzerExtensions.process(c);
}
private void resolveSuperTypeEntryLists(@NotNull BodiesResolveContext c) {
// TODO : Make sure the same thing is not initialized twice
for (Map.Entry entry : c.getDeclaredClasses().entrySet()) {
KtClassOrObject classOrObject = entry.getKey();
ClassDescriptorWithResolutionScopes descriptor = entry.getValue();
ExpressionTypingContext localContext = c.getLocalContext();
resolveSuperTypeEntryList(c.getOuterDataFlowInfo(), classOrObject, descriptor,
descriptor.getUnsubstitutedPrimaryConstructor(),
descriptor.getScopeForConstructorHeaderResolution(),
descriptor.getScopeForMemberDeclarationResolution(),
localContext != null ? localContext.inferenceSession : null);
}
}
public void resolveSuperTypeEntryList(
@NotNull DataFlowInfo outerDataFlowInfo,
@NotNull KtClassOrObject ktClass,
@NotNull ClassDescriptor descriptor,
@Nullable ConstructorDescriptor primaryConstructor,
@NotNull LexicalScope scopeForConstructorResolution,
@NotNull LexicalScope scopeForMemberResolution,
@Nullable InferenceSession inferenceSession
) {
ProgressManager.checkCanceled();
LexicalScope scopeForConstructor =
primaryConstructor == null
? null
: FunctionDescriptorUtil.getFunctionInnerScope(scopeForConstructorResolution, primaryConstructor, trace, overloadChecker);
if (primaryConstructor == null) {
checkRedeclarationsInClassHeaderWithoutPrimaryConstructor(descriptor, scopeForConstructorResolution);
}
ExpressionTypingServices typeInferrer = expressionTypingServices; // TODO : flow
Map supertypes = Maps.newLinkedHashMap();
ResolvedCall>[] primaryConstructorDelegationCall = new ResolvedCall[1];
KtVisitorVoid visitor = new KtVisitorVoid() {
private void recordSupertype(KtTypeReference typeReference, KotlinType supertype) {
if (supertype == null) return;
supertypes.put(typeReference, supertype);
}
@Override
public void visitDelegatedSuperTypeEntry(@NotNull KtDelegatedSuperTypeEntry specifier) {
if (descriptor.getKind() == ClassKind.INTERFACE) {
trace.report(DELEGATION_IN_INTERFACE.on(specifier));
}
KotlinType supertype = trace.getBindingContext().get(BindingContext.TYPE, specifier.getTypeReference());
recordSupertype(specifier.getTypeReference(), supertype);
if (supertype != null) {
DeclarationDescriptor declarationDescriptor = supertype.getConstructor().getDeclarationDescriptor();
if (declarationDescriptor instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
if (classDescriptor.getKind() != ClassKind.INTERFACE) {
trace.report(DELEGATION_NOT_TO_INTERFACE.on(specifier.getTypeReference()));
}
}
}
KtExpression delegateExpression = specifier.getDelegateExpression();
if (delegateExpression != null) {
LexicalScope scope = scopeForConstructor == null ? scopeForMemberResolution : scopeForConstructor;
KotlinType expectedType = supertype != null ? supertype : NO_EXPECTED_TYPE;
typeInferrer.getType(
scope, delegateExpression, expectedType, outerDataFlowInfo,
inferenceSession != null ? inferenceSession : InferenceSession.Companion.getDefault(), trace
);
}
if (descriptor.isExpect()) {
trace.report(IMPLEMENTATION_BY_DELEGATION_IN_EXPECT_CLASS.on(specifier));
}
else if (primaryConstructor == null) {
trace.report(UNSUPPORTED.on(specifier, "Delegation without primary constructor is not supported"));
}
}
@Override
public void visitSuperTypeCallEntry(@NotNull KtSuperTypeCallEntry call) {
KtValueArgumentList valueArgumentList = call.getValueArgumentList();
PsiElement elementToMark = valueArgumentList == null ? call : valueArgumentList;
if (descriptor.getKind() == ClassKind.INTERFACE) {
trace.report(SUPERTYPE_INITIALIZED_IN_INTERFACE.on(elementToMark));
}
if (descriptor.isExpect()) {
trace.report(SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS.on(elementToMark));
}
KtTypeReference typeReference = call.getTypeReference();
if (typeReference == null) return;
if (primaryConstructor == null) {
if (descriptor.getKind() != ClassKind.INTERFACE) {
trace.report(SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR.on(call));
}
recordSupertype(typeReference, trace.getBindingContext().get(BindingContext.TYPE, typeReference));
return;
}
OverloadResolutionResults results = callResolver.resolveFunctionCall(
trace, scopeForConstructor, CallMaker.makeConstructorCallWithoutTypeArguments(call),
NO_EXPECTED_TYPE, outerDataFlowInfo, false, inferenceSession
);
if (results.isSingleResult()) {
KotlinType supertype = results.getResultingDescriptor().getReturnType();
recordSupertype(typeReference, supertype);
ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype);
if (classDescriptor != null) {
// allow only one delegating constructor
if (primaryConstructorDelegationCall[0] == null) {
primaryConstructorDelegationCall[0] = results.getResultingCall();
}
else {
primaryConstructorDelegationCall[0] = null;
}
}
// Recording type info for callee to use later in JetObjectLiteralExpression
trace.record(PROCESSED, call.getCalleeExpression(), true);
trace.record(EXPRESSION_TYPE_INFO, call.getCalleeExpression(),
TypeInfoFactoryKt.noTypeInfo(results.getResultingCall().getDataFlowInfoForArguments().getResultInfo()));
}
else {
recordSupertype(typeReference, trace.getBindingContext().get(BindingContext.TYPE, typeReference));
}
}
@Override
public void visitSuperTypeEntry(@NotNull KtSuperTypeEntry specifier) {
KtTypeReference typeReference = specifier.getTypeReference();
KotlinType supertype = trace.getBindingContext().get(BindingContext.TYPE, typeReference);
recordSupertype(typeReference, supertype);
if (supertype == null) return;
ClassDescriptor superClass = TypeUtils.getClassDescriptor(supertype);
if (superClass == null) return;
if (superClass.getKind().isSingleton()) {
// A "singleton in supertype" diagnostic will be reported later
return;
}
if (descriptor.getKind() != ClassKind.INTERFACE &&
descriptor.getUnsubstitutedPrimaryConstructor() != null &&
superClass.getKind() != ClassKind.INTERFACE &&
!descriptor.isExpect() && !isEffectivelyExternal(descriptor) &&
!ErrorUtils.isError(superClass)
) {
trace.report(SUPERTYPE_NOT_INITIALIZED.on(specifier));
}
}
@Override
public void visitKtElement(@NotNull KtElement element) {
throw new UnsupportedOperationException(element.getText() + " : " + element);
}
};
if (ktClass instanceof KtEnumEntry && DescriptorUtils.isEnumEntry(descriptor) && ktClass.getSuperTypeListEntries().isEmpty()) {
assert scopeForConstructor != null : "Scope for enum class constructor should be non-null: " + descriptor;
resolveConstructorCallForEnumEntryWithoutInitializer(
(KtEnumEntry) ktClass, descriptor, scopeForConstructor,
outerDataFlowInfo, primaryConstructorDelegationCall, inferenceSession
);
}
for (KtSuperTypeListEntry delegationSpecifier : ktClass.getSuperTypeListEntries()) {
ProgressManager.checkCanceled();
delegationSpecifier.accept(visitor);
}
if (DescriptorUtils.isAnnotationClass(descriptor) && ktClass.getSuperTypeList() != null) {
trace.report(SUPERTYPES_FOR_ANNOTATION_CLASS.on(ktClass.getSuperTypeList()));
}
if (primaryConstructorDelegationCall[0] != null && primaryConstructor != null) {
recordConstructorDelegationCall(trace, primaryConstructor, primaryConstructorDelegationCall[0]);
}
checkSupertypeList(descriptor, supertypes, ktClass);
}
private void checkRedeclarationsInClassHeaderWithoutPrimaryConstructor(
@NotNull final ClassDescriptor descriptor, @NotNull LexicalScope scopeForConstructorResolution
) {
// Initializing a scope will report errors if any.
new LexicalScopeImpl(
scopeForConstructorResolution, descriptor, true, null, Collections.emptyList(), LexicalScopeKind.CLASS_HEADER,
new TraceBasedLocalRedeclarationChecker(trace, overloadChecker),
new Function1() {
@Override
public Unit invoke(LexicalScopeImpl.InitializeHandler handler) {
// If a class has no primary constructor, it still can have type parameters declared in header.
for (TypeParameterDescriptor typeParameter : descriptor.getDeclaredTypeParameters()) {
handler.addClassifierDescriptor(typeParameter);
}
return Unit.INSTANCE;
}
});
}
private void resolveConstructorCallForEnumEntryWithoutInitializer(
@NotNull KtEnumEntry ktEnumEntry,
@NotNull ClassDescriptor enumEntryDescriptor,
@NotNull LexicalScope scopeForConstructor,
@NotNull DataFlowInfo outerDataFlowInfo,
@NotNull ResolvedCall>[] primaryConstructorDelegationCall,
@Nullable InferenceSession inferenceSession
) {
assert enumEntryDescriptor.getKind() == ClassKind.ENUM_ENTRY : "Enum entry expected: " + enumEntryDescriptor;
ClassDescriptor enumClassDescriptor = (ClassDescriptor) enumEntryDescriptor.getContainingDeclaration();
if (enumClassDescriptor.getKind() != ClassKind.ENUM_CLASS) return;
if (enumClassDescriptor.isExpect()) return;
List applicableConstructors = getConstructorForEmptyArgumentsList(enumClassDescriptor);
if (applicableConstructors.size() != 1) {
trace.report(ENUM_ENTRY_SHOULD_BE_INITIALIZED.on(ktEnumEntry));
return;
}
KtInitializerList ktInitializerList = new KtPsiFactory(project, false).createEnumEntryInitializerList();
KtSuperTypeCallEntry ktCallEntry = (KtSuperTypeCallEntry) ktInitializerList.getInitializers().get(0);
Call call = CallMaker.makeConstructorCallWithoutTypeArguments(ktCallEntry);
trace.record(BindingContext.TYPE, ktCallEntry.getTypeReference(), enumClassDescriptor.getDefaultType());
trace.record(BindingContext.CALL, ktEnumEntry, call);
OverloadResolutionResults results = callResolver.resolveFunctionCall(
trace,
scopeForConstructor,
call,
NO_EXPECTED_TYPE,
outerDataFlowInfo,
false,
inferenceSession
);
if (primaryConstructorDelegationCall[0] == null) {
primaryConstructorDelegationCall[0] = results.getResultingCall();
}
}
@NotNull
private static List getConstructorForEmptyArgumentsList(@NotNull ClassDescriptor descriptor) {
return CollectionsKt.filter(
descriptor.getConstructors(),
(constructor) -> CollectionsKt.all(
constructor.getValueParameters(),
(parameter) -> parameter.declaresDefaultValue() || parameter.getVarargElementType() != null
)
);
}
// Returns a set of enum or sealed types of which supertypeOwner is an entry or a member
@NotNull
private Set getAllowedFinalSupertypes(
@NotNull ClassDescriptor descriptor,
@NotNull Map supertypes,
@NotNull KtClassOrObject ktClassOrObject
) {
Set parentEnumOrSealed = Collections.emptySet();
if (ktClassOrObject instanceof KtEnumEntry) {
parentEnumOrSealed = Collections.singleton(((ClassDescriptor) descriptor.getContainingDeclaration()).getTypeConstructor());
}
else if (languageVersionSettings.supportsFeature(TopLevelSealedInheritance) && DescriptorUtils.isTopLevelDeclaration(descriptor)) {
// TODO: improve diagnostic when top level sealed inheritance is disabled
for (KotlinType supertype : supertypes.values()) {
ClassifierDescriptor classifierDescriptor = supertype.getConstructor().getDeclarationDescriptor();
if (DescriptorUtils.isSealedClass(classifierDescriptor) && DescriptorUtils.isTopLevelDeclaration(classifierDescriptor)) {
parentEnumOrSealed = Collections.singleton(classifierDescriptor.getTypeConstructor());
}
}
}
else {
ClassDescriptor currentDescriptor = descriptor;
while (currentDescriptor.getContainingDeclaration() instanceof ClassDescriptor) {
currentDescriptor = (ClassDescriptor) currentDescriptor.getContainingDeclaration();
if (DescriptorUtils.isSealedClass(currentDescriptor)) {
if (parentEnumOrSealed.isEmpty()) {
parentEnumOrSealed = new HashSet<>();
}
parentEnumOrSealed.add(currentDescriptor.getTypeConstructor());
if (currentDescriptor.isExpect()) {
List actualDescriptors = ExpectedActualResolverKt.findCompatibleActualsForExpected(
currentDescriptor, DescriptorUtilsKt.getModule( currentDescriptor)
);
for (MemberDescriptor actualDescriptor: actualDescriptors) {
if (actualDescriptor instanceof TypeAliasDescriptor) {
parentEnumOrSealed.add(((TypeAliasDescriptor) actualDescriptor).getExpandedType().getConstructor());
}
}
}
}
}
}
return parentEnumOrSealed;
}
@SuppressWarnings("unchecked")
private static void recordConstructorDelegationCall(
@NotNull BindingTrace trace,
@NotNull ConstructorDescriptor constructor,
@NotNull ResolvedCall> call
) {
trace.record(CONSTRUCTOR_RESOLVED_DELEGATION_CALL, constructor, (ResolvedCall) call);
}
private void checkSupertypeList(
@NotNull ClassDescriptor supertypeOwner,
@NotNull Map supertypes,
@NotNull KtClassOrObject ktClassOrObject
) {
Set allowedFinalSupertypes = getAllowedFinalSupertypes(supertypeOwner, supertypes, ktClassOrObject);
Set typeConstructors = new HashSet<>();
boolean classAppeared = false;
for (Map.Entry entry : supertypes.entrySet()) {
KtTypeReference typeReference = entry.getKey();
KotlinType supertype = entry.getValue();
KtTypeElement typeElement = typeReference.getTypeElement();
if (typeElement instanceof KtFunctionType) {
for (KtParameter parameter : ((KtFunctionType) typeElement).getParameters()) {
PsiElement nameIdentifier = parameter.getNameIdentifier();
if (nameIdentifier != null) {
trace.report(Errors.UNSUPPORTED.on(nameIdentifier, "named parameter in function type in supertype position"));
}
}
}
boolean addSupertype = true;
ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype);
if (classDescriptor != null) {
if (ErrorUtils.isError(classDescriptor)) continue;
if (FunctionTypesKt.isExtensionFunctionType(supertype) &&
!languageVersionSettings.supportsFeature(LanguageFeature.FunctionalTypeWithExtensionAsSupertype)
) {
trace.report(SUPERTYPE_IS_EXTENSION_FUNCTION_TYPE.on(typeReference));
}
else if (FunctionTypesKt.isSuspendExtensionFunctionType(supertype) &&
!languageVersionSettings.supportsFeature(LanguageFeature.FunctionalTypeWithExtensionAsSupertype) &&
languageVersionSettings.supportsFeature(LanguageFeature.SuspendFunctionAsSupertype)) {
trace.report(SUPERTYPE_IS_SUSPEND_EXTENSION_FUNCTION_TYPE.on(typeReference));
}
else if (FunctionTypesKt.isSuspendFunctionType(supertype) &&
!languageVersionSettings.supportsFeature(LanguageFeature.SuspendFunctionAsSupertype)
) {
trace.report(SUPERTYPE_IS_SUSPEND_FUNCTION_TYPE.on(typeReference));
}
else if (FunctionTypesKt.isKSuspendFunctionType(supertype) &&
!languageVersionSettings.supportsFeature(LanguageFeature.SuspendFunctionAsSupertype)) {
trace.report(SUPERTYPE_IS_KSUSPEND_FUNCTION_TYPE.on(typeReference));
}
if (classDescriptor.getKind() != ClassKind.INTERFACE) {
if (supertypeOwner.getKind() == ClassKind.ENUM_CLASS) {
trace.report(CLASS_IN_SUPERTYPE_FOR_ENUM.on(typeReference));
addSupertype = false;
}
else if (supertypeOwner.getKind() == ClassKind.INTERFACE &&
!classAppeared && !DynamicTypesKt.isDynamic(supertype) /* avoid duplicate diagnostics */) {
trace.report(INTERFACE_WITH_SUPERCLASS.on(typeReference));
addSupertype = false;
}
else if (ktClassOrObject.hasModifier(KtTokens.DATA_KEYWORD) &&
!languageVersionSettings.supportsFeature(LanguageFeature.DataClassInheritance)) {
trace.report(DATA_CLASS_CANNOT_HAVE_CLASS_SUPERTYPES.on(typeReference));
addSupertype = false;
}
else if (DescriptorUtils.isSubclass(classDescriptor, builtIns.getThrowable())) {
if (!supertypeOwner.getDeclaredTypeParameters().isEmpty()) {
trace.report(GENERIC_THROWABLE_SUBCLASS.on(ktClassOrObject.getTypeParameterList()));
addSupertype = false;
}
else if (!supertypeOwner.getTypeConstructor().getParameters().isEmpty()) {
if (languageVersionSettings
.supportsFeature(LanguageFeature.ProhibitInnerClassesOfGenericClassExtendingThrowable)) {
trace.report(INNER_CLASS_OF_GENERIC_THROWABLE_SUBCLASS.on(ktClassOrObject));
addSupertype = false;
}
else {
trace.report(INNER_CLASS_OF_GENERIC_THROWABLE_SUBCLASS_WARNING.on(ktClassOrObject));
}
}
}
if (classAppeared) {
trace.report(MANY_CLASSES_IN_SUPERTYPE_LIST.on(typeReference));
}
else {
classAppeared = true;
}
}
}
else {
trace.report(SUPERTYPE_NOT_A_CLASS_OR_INTERFACE.on(typeReference));
}
TypeConstructor constructor = supertype.getConstructor();
if (addSupertype && !typeConstructors.add(constructor)) {
trace.report(SUPERTYPE_APPEARS_TWICE.on(typeReference));
}
if (classDescriptor == null) return;
if (classDescriptor.getKind().isSingleton()) {
if (!DescriptorUtils.isEnumEntry(classDescriptor)) {
trace.report(SINGLETON_IN_SUPERTYPE.on(typeReference));
}
}
else if (!allowedFinalSupertypes.contains(constructor)) {
if (DescriptorUtils.isSealedClass(classDescriptor)) {
DeclarationDescriptor containingDescriptor = supertypeOwner.getContainingDeclaration();
while (containingDescriptor != null && containingDescriptor != classDescriptor) {
containingDescriptor = containingDescriptor.getContainingDeclaration();
}
if (containingDescriptor == null) {
if (
!languageVersionSettings.supportsFeature(AllowSealedInheritorsInDifferentFilesOfSamePackage) ||
DescriptorUtils.isLocal(supertypeOwner)
) {
trace.report(SEALED_SUPERTYPE.on(typeReference));
}
}
else {
String declarationName;
if (supertypeOwner.getName() == SpecialNames.NO_NAME_PROVIDED) {
declarationName = "Anonymous object";
} else {
declarationName = "Local class";
}
trace.report(SEALED_SUPERTYPE_IN_LOCAL_CLASS.on(typeReference, declarationName, classDescriptor.getKind()));
}
}
else if (ModalityUtilsKt.isFinalOrEnum(classDescriptor)) {
trace.report(FINAL_SUPERTYPE.on(typeReference));
}
else if (KotlinBuiltIns.isEnum(classDescriptor)) {
trace.report(CLASS_CANNOT_BE_EXTENDED_DIRECTLY.on(typeReference, classDescriptor));
}
}
}
}
private void resolveAnonymousInitializers(@NotNull BodiesResolveContext c) {
for (Map.Entry entry : c.getAnonymousInitializers().entrySet()) {
KtAnonymousInitializer initializer = entry.getKey();
ClassDescriptorWithResolutionScopes descriptor = entry.getValue();
ExpressionTypingContext context = c.getLocalContext();
resolveAnonymousInitializer(c.getOuterDataFlowInfo(), initializer, descriptor, context != null ? context.inferenceSession : null);
}
}
public void resolveAnonymousInitializer(
@NotNull DataFlowInfo outerDataFlowInfo,
@NotNull KtAnonymousInitializer anonymousInitializer,
@NotNull ClassDescriptorWithResolutionScopes classDescriptor,
@Nullable InferenceSession inferenceSession
) {
ProgressManager.checkCanceled();
LexicalScope scopeForInitializers = classDescriptor.getScopeForInitializerResolution();
KtExpression body = anonymousInitializer.getBody();
if (body != null) {
PreliminaryDeclarationVisitor.Companion.createForDeclaration(
(KtDeclaration) anonymousInitializer.getParent().getParent(), trace, languageVersionSettings);
expressionTypingServices.getTypeInfo(
scopeForInitializers, body, NO_EXPECTED_TYPE, outerDataFlowInfo,
inferenceSession != null ? inferenceSession : InferenceSession.Companion.getDefault(), trace, /*isStatement = */true
);
}
processModifiersOnInitializer(anonymousInitializer, scopeForInitializers);
if (classDescriptor.getConstructors().isEmpty()) {
trace.report(ANONYMOUS_INITIALIZER_IN_INTERFACE.on(anonymousInitializer));
}
if (classDescriptor.isExpect()) {
trace.report(EXPECTED_DECLARATION_WITH_BODY.on(anonymousInitializer));
}
}
private void processModifiersOnInitializer(@NotNull KtModifierListOwner owner, @NotNull LexicalScope scope) {
annotationChecker.check(owner, trace, null);
ModifierCheckerCore.INSTANCE.check(owner, trace, null, languageVersionSettings);
KtModifierList modifierList = owner.getModifierList();
if (modifierList == null) return;
annotationResolver.resolveAnnotationsWithArguments(scope, modifierList, trace);
}
private void resolvePrimaryConstructorParameters(@NotNull BodiesResolveContext c) {
for (Map.Entry entry : c.getDeclaredClasses().entrySet()) {
KtClassOrObject klass = entry.getKey();
ClassDescriptorWithResolutionScopes classDescriptor = entry.getValue();
ConstructorDescriptor unsubstitutedPrimaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
if (unsubstitutedPrimaryConstructor != null) {
ForceResolveUtil.forceResolveAllContents(unsubstitutedPrimaryConstructor.getAnnotations());
ExpressionTypingContext localContext = c.getLocalContext();
LexicalScope parameterScope = getPrimaryConstructorParametersScope(classDescriptor.getScopeForConstructorHeaderResolution(),
unsubstitutedPrimaryConstructor);
valueParameterResolver.resolveValueParameters(
klass.getPrimaryConstructorParameters(), unsubstitutedPrimaryConstructor.getValueParameters(),
parameterScope, c.getOuterDataFlowInfo(), trace, localContext != null ? localContext.inferenceSession : null
);
// Annotations on value parameter and constructor parameter could be splitted
resolveConstructorPropertyDescriptors(klass);
}
}
}
private void resolveConstructorPropertyDescriptors(KtClassOrObject ktClassOrObject) {
for (KtParameter parameter : ktClassOrObject.getPrimaryConstructorParameters()) {
PropertyDescriptor descriptor = trace.getBindingContext().get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter);
if (descriptor != null) {
ForceResolveUtil.forceResolveAllContents(descriptor.getAnnotations());
if (languageVersionSettings.supportsFeature(LanguageFeature.ProhibitErroneousExpressionsInAnnotationsWithUseSiteTargets)) {
PropertyGetterDescriptor getterDescriptor = descriptor.getGetter();
if (getterDescriptor != null) {
ForceResolveUtil.forceResolveAllContents(getterDescriptor.getAnnotations());
}
PropertySetterDescriptor setterDescriptor = descriptor.getSetter();
if (setterDescriptor != null) {
ForceResolveUtil.forceResolveAllContents(setterDescriptor.getAnnotations());
}
}
}
}
}
private static LexicalScope getPrimaryConstructorParametersScope(
LexicalScope originalScope,
ConstructorDescriptor unsubstitutedPrimaryConstructor
) {
return new LexicalScopeImpl(originalScope, unsubstitutedPrimaryConstructor, false, null,
Collections.emptyList(), LexicalScopeKind.DEFAULT_VALUE, LocalRedeclarationChecker.DO_NOTHING.INSTANCE,
handler -> {
for (ValueParameterDescriptor valueParameter : unsubstitutedPrimaryConstructor.getValueParameters()) {
handler.addVariableDescriptor(valueParameter);
}
return Unit.INSTANCE;
});
}
public void resolveProperty(
@NotNull BodiesResolveContext c,
@NotNull KtProperty property,
@NotNull PropertyDescriptor propertyDescriptor
) {
computeDeferredType(propertyDescriptor.getReturnType());
PreliminaryDeclarationVisitor.Companion.createForDeclaration(property, trace, languageVersionSettings);
KtExpression initializer = property.getInitializer();
LexicalScope propertyHeaderScope = ScopeUtils.makeScopeForPropertyHeader(getScopeForProperty(c, property), propertyDescriptor);
ExpressionTypingContext context = c.getLocalContext();
if (initializer != null) {
resolvePropertyInitializer(
c.getOuterDataFlowInfo(), property, propertyDescriptor,
initializer, propertyHeaderScope, context != null ? context.inferenceSession : null
);
}
KtExpression delegateExpression = property.getDelegateExpression();
if (delegateExpression != null) {
assert initializer == null : "Initializer should be null for delegated property : " + property.getText();
resolvePropertyDelegate(
c.getOuterDataFlowInfo(), property, propertyDescriptor,
delegateExpression, propertyHeaderScope, context != null ? context.inferenceSession : null
);
}
resolvePropertyAccessors(c, property, propertyDescriptor);
ForceResolveUtil.forceResolveAllContents(propertyDescriptor.getAnnotations());
FieldDescriptor backingField = propertyDescriptor.getBackingField();
if (backingField != null) {
ForceResolveUtil.forceResolveAllContents(backingField.getAnnotations());
}
}
private void resolvePropertyDeclarationBodies(@NotNull BodiesResolveContext c) {
// Member properties
Set processed = new HashSet<>();
for (Map.Entry entry : c.getDeclaredClasses().entrySet()) {
if (!(entry.getKey() instanceof KtClass)) continue;
KtClass ktClass = (KtClass) entry.getKey();
ClassDescriptorWithResolutionScopes classDescriptor = entry.getValue();
for (KtProperty property : ktClass.getProperties()) {
PropertyDescriptor propertyDescriptor = c.getProperties().get(property);
assert propertyDescriptor != null;
resolveProperty(c, property, propertyDescriptor);
processed.add(property);
}
}
// Top-level properties & properties of objects
for (Map.Entry entry : c.getProperties().entrySet()) {
KtProperty property = entry.getKey();
if (processed.contains(property)) continue;
PropertyDescriptor propertyDescriptor = entry.getValue();
resolveProperty(c, property, propertyDescriptor);
}
}
private static LexicalScope makeScopeForPropertyAccessor(
@NotNull BodiesResolveContext c, @NotNull KtPropertyAccessor accessor, @NotNull PropertyDescriptor descriptor
) {
LexicalScope accessorDeclaringScope = c.getDeclaringScope(accessor);
assert accessorDeclaringScope != null : "Scope for accessor " + accessor.getText() + " should exists";
LexicalScope headerScope = ScopeUtils.makeScopeForPropertyHeader(accessorDeclaringScope, descriptor);
return new LexicalScopeImpl(headerScope, descriptor, true, descriptor.getExtensionReceiverParameter(), descriptor.getContextReceiverParameters(),
LexicalScopeKind.PROPERTY_ACCESSOR_BODY);
}
private void resolvePropertyAccessors(
@NotNull BodiesResolveContext c,
@NotNull KtProperty property,
@NotNull PropertyDescriptor propertyDescriptor
) {
ObservableBindingTrace fieldAccessTrackingTrace = createFieldTrackingTrace(propertyDescriptor);
KtPropertyAccessor getter = property.getGetter();
PropertyGetterDescriptor getterDescriptor = propertyDescriptor.getGetter();
boolean forceResolveAnnotations =
languageVersionSettings.supportsFeature(LanguageFeature.ProhibitErroneousExpressionsInAnnotationsWithUseSiteTargets);
if (getterDescriptor != null) {
if (getter != null) {
LexicalScope accessorScope = makeScopeForPropertyAccessor(c, getter, propertyDescriptor);
resolveFunctionBody(c.getOuterDataFlowInfo(), fieldAccessTrackingTrace, getter, getterDescriptor, accessorScope, c.getLocalContext());
}
if (getter != null || forceResolveAnnotations) {
ForceResolveUtil.forceResolveAllContents(getterDescriptor.getAnnotations());
}
}
KtPropertyAccessor setter = property.getSetter();
PropertySetterDescriptor setterDescriptor = propertyDescriptor.getSetter();
if (setterDescriptor != null) {
if (setter != null) {
LexicalScope accessorScope = makeScopeForPropertyAccessor(c, setter, propertyDescriptor);
resolveFunctionBody(c.getOuterDataFlowInfo(), fieldAccessTrackingTrace, setter, setterDescriptor, accessorScope, c.getLocalContext());
}
if (setter != null || forceResolveAnnotations) {
ForceResolveUtil.forceResolveAllContents(setterDescriptor.getAnnotations());
}
}
}
private ObservableBindingTrace createFieldTrackingTrace(PropertyDescriptor propertyDescriptor) {
return new ObservableBindingTrace(trace).addHandler(
BindingContext.REFERENCE_TARGET,
(slice, expression, descriptor) -> {
if (expression instanceof KtSimpleNameExpression &&
descriptor instanceof SyntheticFieldDescriptor) {
trace.record(BindingContext.BACKING_FIELD_REQUIRED,
propertyDescriptor);
}
}
);
}
private void resolvePropertyDelegate(
@NotNull DataFlowInfo outerDataFlowInfo,
@NotNull KtProperty property,
@NotNull PropertyDescriptor propertyDescriptor,
@NotNull KtExpression delegateExpression,
@NotNull LexicalScope propertyHeaderScope,
@Nullable InferenceSession inferenceSession
) {
delegatedPropertyResolver.resolvePropertyDelegate(outerDataFlowInfo,
property,
propertyDescriptor,
delegateExpression,
propertyHeaderScope,
inferenceSession != null ? inferenceSession : InferenceSession.Companion.getDefault(),
trace);
}
private void resolvePropertyInitializer(
@NotNull DataFlowInfo outerDataFlowInfo,
@NotNull KtProperty property,
@NotNull PropertyDescriptor propertyDescriptor,
@NotNull KtExpression initializer,
@NotNull LexicalScope propertyHeader,
@Nullable InferenceSession inferenceSession
) {
LexicalScope propertyDeclarationInnerScope = ScopeUtils.makeScopeForPropertyInitializer(propertyHeader, propertyDescriptor);
KotlinType expectedTypeForInitializer = property.getTypeReference() != null ? propertyDescriptor.getType() : NO_EXPECTED_TYPE;
if (propertyDescriptor.getCompileTimeInitializer() == null) {
expressionTypingServices.getType(
propertyDeclarationInnerScope, initializer, expectedTypeForInitializer,
outerDataFlowInfo, inferenceSession != null ? inferenceSession : InferenceSession.Companion.getDefault(), trace
);
}
}
@NotNull
private static LexicalScope getScopeForProperty(@NotNull BodiesResolveContext c, @NotNull KtProperty property) {
LexicalScope scope = c.getDeclaringScope(property);
assert scope != null : "Scope for property " + property.getText() + " should exists";
return scope;
}
private void resolveFunctionBodies(@NotNull BodiesResolveContext c) {
for (Map.Entry entry : c.getFunctions().entrySet()) {
KtNamedFunction declaration = entry.getKey();
LexicalScope scope = c.getDeclaringScope(declaration);
assert scope != null : "Scope is null: " + PsiUtilsKt.getElementTextWithContext(declaration);
if (!c.getTopDownAnalysisMode().isLocalDeclarations() && !(bodyResolveCache instanceof BodyResolveCache.ThrowException) &&
expressionTypingServices.getStatementFilter() != StatementFilter.NONE) {
bodyResolveCache.resolveFunctionBody(declaration).addOwnDataTo(trace, true);
}
else {
resolveFunctionBody(c.getOuterDataFlowInfo(), trace, declaration, entry.getValue(), scope, c.getLocalContext());
}
}
}
public void resolveFunctionBody(
@NotNull DataFlowInfo outerDataFlowInfo,
@NotNull BindingTrace trace,
@NotNull KtDeclarationWithBody function,
@NotNull FunctionDescriptor functionDescriptor,
@NotNull LexicalScope declaringScope,
@Nullable ExpressionTypingContext localContext
) {
computeDeferredType(functionDescriptor.getReturnType());
resolveFunctionBody(outerDataFlowInfo, trace, function, functionDescriptor, declaringScope, null, null, localContext);
assert functionDescriptor.getReturnType() != null;
}
private void resolveFunctionBody(
@NotNull DataFlowInfo outerDataFlowInfo,
@NotNull BindingTrace trace,
@NotNull KtDeclarationWithBody function,
@NotNull FunctionDescriptor functionDescriptor,
@NotNull LexicalScope scope,
@Nullable Function1 beforeBlockBody,
// Creates wrapper scope for header resolution if necessary (see resolveSecondaryConstructorBody)
@Nullable Function1 headerScopeFactory,
@Nullable ExpressionTypingContext localContext
) {
ProgressManager.checkCanceled();
PreliminaryDeclarationVisitor.Companion.createForDeclaration(function, trace, languageVersionSettings);
LexicalScope innerScope = FunctionDescriptorUtil.getFunctionInnerScope(scope, functionDescriptor, trace, overloadChecker);
List valueParameters = function.getValueParameters();
List valueParameterDescriptors = functionDescriptor.getValueParameters();
LexicalScope headerScope = headerScopeFactory != null ? headerScopeFactory.invoke(innerScope) : innerScope;
valueParameterResolver.resolveValueParameters(
valueParameters, valueParameterDescriptors, headerScope, outerDataFlowInfo, trace,
localContext != null ? localContext.inferenceSession : null
);
// Synthetic "field" creation
if (functionDescriptor instanceof PropertyAccessorDescriptor && functionDescriptor.getExtensionReceiverParameter() == null
&& functionDescriptor.getContextReceiverParameters().isEmpty()) {
PropertyAccessorDescriptor accessorDescriptor = (PropertyAccessorDescriptor) functionDescriptor;
KtProperty property = (KtProperty) function.getParent();
SourceElement propertySourceElement = KotlinSourceElementKt.toSourceElement(property);
SyntheticFieldDescriptor fieldDescriptor = new SyntheticFieldDescriptor(accessorDescriptor, propertySourceElement);
innerScope = new LexicalScopeImpl(innerScope, functionDescriptor, true, null, Collections.emptyList(),
LexicalScopeKind.PROPERTY_ACCESSOR_BODY,
LocalRedeclarationChecker.DO_NOTHING.INSTANCE, handler -> {
handler.addVariableDescriptor(fieldDescriptor);
return Unit.INSTANCE;
});
// Check parameter name shadowing
for (KtParameter parameter : function.getValueParameters()) {
if (SyntheticFieldDescriptor.NAME.equals(parameter.getNameAsName())) {
trace.report(Errors.ACCESSOR_PARAMETER_NAME_SHADOWING.on(parameter));
}
}
}
DataFlowInfo dataFlowInfo = null;
if (beforeBlockBody != null) {
dataFlowInfo = beforeBlockBody.invoke(headerScope);
}
if (function.hasBody()) {
expressionTypingServices.checkFunctionReturnType(
innerScope, function, functionDescriptor, dataFlowInfo != null ? dataFlowInfo : outerDataFlowInfo, null, trace, localContext
);
}
assert functionDescriptor.getReturnType() != null;
}
public void resolveConstructorParameterDefaultValues(
@NotNull DataFlowInfo outerDataFlowInfo,
@NotNull BindingTrace trace,
@NotNull KtPrimaryConstructor constructor,
@NotNull ConstructorDescriptor constructorDescriptor,
@NotNull LexicalScope declaringScope,
@Nullable InferenceSession inferenceSession
) {
List valueParameters = constructor.getValueParameters();
List valueParameterDescriptors = constructorDescriptor.getValueParameters();
LexicalScope scope = getPrimaryConstructorParametersScope(declaringScope, constructorDescriptor);
valueParameterResolver.resolveValueParameters(valueParameters, valueParameterDescriptors, scope, outerDataFlowInfo, trace, inferenceSession);
}
public static void computeDeferredType(KotlinType type) {
// handle type inference loop: function or property body contains a reference to itself
// fun f() = { f() }
// val x = x
// type resolution must be started before body resolution
if (type instanceof DeferredType) {
DeferredType deferredType = (DeferredType) type;
if (!deferredType.isComputed()) {
deferredType.getDelegate();
}
}
}
private void computeDeferredTypes() {
Collection> deferredTypes = trace.getKeys(DEFERRED_TYPE);
if (deferredTypes.isEmpty()) {
return;
}
Deque queue = new ArrayDeque<>(deferredTypes.size() + 1);
trace.addHandler(DEFERRED_TYPE, (deferredTypeKeyDeferredTypeWritableSlice, key, value) -> queue.offerLast(key.getData()));
for (Box deferredType : deferredTypes) {
queue.offerLast(deferredType.getData());
}
while (!queue.isEmpty()) {
DeferredType deferredType = queue.pollFirst();
if (!deferredType.isComputed()) {
try {
deferredType.getDelegate(); // to compute
}
catch (ReenteringLazyValueComputationException e) {
// A problem should be reported while computing the type
}
}
}
}
}