All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.jet.lang.resolve.DescriptorResolver Maven / Gradle / Ivy

/*
 * Copyright 2010-2014 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.jet.lang.resolve;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import kotlin.Function0;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
import org.jetbrains.jet.lang.descriptors.impl.*;
import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory1;
import org.jetbrains.jet.lang.evaluate.ConstantExpressionEvaluator;
import org.jetbrains.jet.lang.evaluate.EvaluatePackage;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.constants.IntegerValueTypeConstant;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.JetScopeUtils;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.lexer.JetKeywordToken;
import org.jetbrains.jet.lexer.JetModifierKeywordToken;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.storage.StorageManager;

import javax.inject.Inject;
import java.util.*;

import static org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER;
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
import static org.jetbrains.jet.lang.resolve.ModifiersChecker.*;
import static org.jetbrains.jet.lexer.JetTokens.OVERRIDE_KEYWORD;
import static org.jetbrains.jet.storage.LockBasedStorageManager.NO_LOCKS;

public class DescriptorResolver {
    public static final Name COPY_METHOD_NAME = Name.identifier("copy");
    public static final String COMPONENT_FUNCTION_NAME_PREFIX = "component";

    @NotNull
    private TypeResolver typeResolver;
    @NotNull
    private AnnotationResolver annotationResolver;
    @NotNull
    private ExpressionTypingServices expressionTypingServices;
    @NotNull
    private DelegatedPropertyResolver delegatedPropertyResolver;
    @NotNull
    private StorageManager storageManager;

    @Inject
    public void setTypeResolver(@NotNull TypeResolver typeResolver) {
        this.typeResolver = typeResolver;
    }

    @Inject
    public void setAnnotationResolver(@NotNull AnnotationResolver annotationResolver) {
        this.annotationResolver = annotationResolver;
    }

    @Inject
    public void setExpressionTypingServices(@NotNull ExpressionTypingServices expressionTypingServices) {
        this.expressionTypingServices = expressionTypingServices;
    }

    @Inject
    public void setDelegatedPropertyResolver(@NotNull DelegatedPropertyResolver delegatedPropertyResolver) {
        this.delegatedPropertyResolver = delegatedPropertyResolver;
    }

    @Inject
    public void setStorageManager(@NotNull StorageManager storageManager) {
        this.storageManager = storageManager;
    }

    public void resolveMutableClassDescriptor(
            @NotNull TopDownAnalysisParameters topDownAnalysisParameters,
            @NotNull JetClass classElement,
            @NotNull MutableClassDescriptor descriptor,
            BindingTrace trace
    ) {
        // TODO : Where-clause
        List typeParameters = Lists.newArrayList();
        int index = 0;
        for (JetTypeParameter typeParameter : classElement.getTypeParameters()) {
            if (!topDownAnalysisParameters.isLazyTopDownAnalysis()) {
                // TODO: Support
                AnnotationResolver.reportUnsupportedAnnotationForTypeParameter(typeParameter, trace);
            }

            TypeParameterDescriptor typeParameterDescriptor = TypeParameterDescriptorImpl.createForFurtherModification(
                    descriptor,
                    Annotations.EMPTY,
                    typeParameter.hasModifier(JetTokens.REIFIED_KEYWORD),
                    typeParameter.getVariance(),
                    JetPsiUtil.safeName(typeParameter.getName()),
                    index
            );
            trace.record(BindingContext.TYPE_PARAMETER, typeParameter, typeParameterDescriptor);
            typeParameters.add(typeParameterDescriptor);
            index++;
        }
        descriptor.setTypeParameterDescriptors(typeParameters);
        Modality defaultModality = descriptor.getKind() == ClassKind.TRAIT ? Modality.ABSTRACT : Modality.FINAL;
        descriptor.setModality(resolveModalityFromModifiers(classElement, defaultModality));
        descriptor.setVisibility(resolveVisibilityFromModifiers(classElement, getDefaultClassVisibility(descriptor)));

        trace.record(BindingContext.CLASS, classElement, descriptor);
    }

    public void resolveSupertypesForMutableClassDescriptor(
            @NotNull JetClassOrObject jetClass,
            @NotNull MutableClassDescriptor descriptor,
            BindingTrace trace
    ) {
        for (JetType supertype : resolveSupertypes(descriptor.getScopeForClassHeaderResolution(), descriptor, jetClass, trace)) {
            descriptor.addSupertype(supertype);
        }
    }

    public List resolveSupertypes(
            @NotNull JetScope scope,
            @NotNull ClassDescriptor classDescriptor,
            @NotNull JetClassOrObject jetClass,
            BindingTrace trace
    ) {
        List supertypes = Lists.newArrayList();
        List delegationSpecifiers = jetClass.getDelegationSpecifiers();
        Collection declaredSupertypes = resolveDelegationSpecifiers(
                scope,
                delegationSpecifiers,
                typeResolver, trace, false);

        for (JetType declaredSupertype : declaredSupertypes) {
            addValidSupertype(supertypes, declaredSupertype);
        }

        if (classDescriptor.getKind() == ClassKind.ENUM_CLASS && !containsClass(supertypes)) {
            supertypes.add(0, KotlinBuiltIns.getInstance().getEnumType(classDescriptor.getDefaultType()));
        }

        if (supertypes.isEmpty()) {
            JetType defaultSupertype = getDefaultSupertype(jetClass, trace);
            addValidSupertype(supertypes, defaultSupertype);
        }

        return supertypes;
    }

    private static void addValidSupertype(List supertypes, JetType declaredSupertype) {
        if (!declaredSupertype.isError()) {
            supertypes.add(declaredSupertype);
        }
    }

    private boolean containsClass(Collection result) {
        for (JetType type : result) {
            ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
            if (descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() != ClassKind.TRAIT) {
                return true;
            }
        }
        return false;
    }

    private JetType getDefaultSupertype(JetClassOrObject jetClass, BindingTrace trace) {
        // TODO : beautify
        if (jetClass instanceof JetEnumEntry) {
            JetClassOrObject parent = PsiTreeUtil.getParentOfType(jetClass, JetClassOrObject.class);
            ClassDescriptor parentDescriptor = trace.getBindingContext().get(BindingContext.CLASS, parent);
            if (parentDescriptor.getTypeConstructor().getParameters().isEmpty()) {
                return parentDescriptor.getDefaultType();
            }
            else {
                trace.report(NO_GENERICS_IN_SUPERTYPE_SPECIFIER.on(jetClass.getNameIdentifier()));
                return ErrorUtils.createErrorType("Supertype not specified");
            }
        }
        else if (jetClass instanceof JetClass && ((JetClass) jetClass).isAnnotation()) {
            return KotlinBuiltIns.getInstance().getAnnotationType();
        }
        return KotlinBuiltIns.getInstance().getAnyType();
    }

    public Collection resolveDelegationSpecifiers(
            JetScope extensibleScope,
            List delegationSpecifiers,
            @NotNull TypeResolver resolver,
            BindingTrace trace,
            boolean checkBounds
    ) {
        if (delegationSpecifiers.isEmpty()) {
            return Collections.emptyList();
        }
        Collection result = Lists.newArrayList();
        for (JetDelegationSpecifier delegationSpecifier : delegationSpecifiers) {
            JetTypeReference typeReference = delegationSpecifier.getTypeReference();
            if (typeReference != null) {
                result.add(resolver.resolveType(extensibleScope, typeReference, trace, checkBounds));
                JetTypeElement bareSuperType = checkNullableSupertypeAndStripQuestionMarks(trace, typeReference.getTypeElement());
                checkProjectionsInImmediateArguments(trace, bareSuperType);
            }
            else {
                result.add(ErrorUtils.createErrorType("No type reference"));
            }
        }
        return result;
    }

    @Nullable
    private static JetTypeElement checkNullableSupertypeAndStripQuestionMarks(@NotNull BindingTrace trace, @Nullable JetTypeElement typeElement) {
        while (typeElement instanceof JetNullableType) {
            JetNullableType nullableType = (JetNullableType) typeElement;
            typeElement = nullableType.getInnerType();
            // report only for innermost '?', the rest gets a 'redundant' warning
            if (!(typeElement instanceof JetNullableType) && typeElement != null) {
                trace.report(NULLABLE_SUPERTYPE.on(nullableType));
            }
        }
        return typeElement;
    }

    private static void checkProjectionsInImmediateArguments(@NotNull BindingTrace trace, @Nullable JetTypeElement typeElement) {
        if (typeElement instanceof JetUserType) {
            JetUserType userType = (JetUserType) typeElement;
            List typeArguments = userType.getTypeArguments();
            for (JetTypeProjection typeArgument : typeArguments) {
                if (typeArgument.getProjectionKind() != JetProjectionKind.NONE) {
                    trace.report(PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE.on(typeArgument));
                }
            }
        }
    }

    @NotNull
    public SimpleFunctionDescriptor resolveFunctionDescriptorWithAnnotationArguments(
            @NotNull DeclarationDescriptor containingDescriptor,
            @NotNull JetScope scope,
            @NotNull JetNamedFunction function,
            @NotNull BindingTrace trace,
            @NotNull DataFlowInfo dataFlowInfo
    ) {
        return resolveFunctionDescriptor(containingDescriptor, scope, function, trace, dataFlowInfo,
                                         annotationResolver.resolveAnnotationsWithArguments(scope, function.getModifierList(), trace));
    }

    @NotNull
    public SimpleFunctionDescriptor resolveFunctionDescriptor(
            @NotNull DeclarationDescriptor containingDescriptor,
            @NotNull JetScope scope,
            @NotNull JetNamedFunction function,
            @NotNull BindingTrace trace,
            @NotNull DataFlowInfo dataFlowInfo
    ) {
       return resolveFunctionDescriptor(containingDescriptor, scope, function, trace, dataFlowInfo,
                                        annotationResolver.resolveAnnotationsWithoutArguments(scope, function.getModifierList(), trace));
    }

    @NotNull
    private SimpleFunctionDescriptor resolveFunctionDescriptor(
            @NotNull DeclarationDescriptor containingDescriptor,
            @NotNull final JetScope scope,
            @NotNull final JetNamedFunction function,
            @NotNull final BindingTrace trace,
            @NotNull final DataFlowInfo dataFlowInfo,
            @NotNull Annotations annotations
    ) {
        final SimpleFunctionDescriptorImpl functionDescriptor = SimpleFunctionDescriptorImpl.create(
                containingDescriptor,
                annotations,
                JetPsiUtil.safeName(function.getName()),
                CallableMemberDescriptor.Kind.DECLARATION
        );
        WritableScope innerScope = new WritableScopeImpl(scope, functionDescriptor, new TraceBasedRedeclarationHandler(trace),
                                                         "Function descriptor header scope");
        innerScope.addLabeledDeclaration(functionDescriptor);

        List typeParameterDescriptors =
                resolveTypeParametersForCallableDescriptor(functionDescriptor, innerScope, function.getTypeParameters(), trace);
        innerScope.changeLockLevel(WritableScope.LockLevel.BOTH);
        resolveGenericBounds(function, functionDescriptor, innerScope, typeParameterDescriptors, trace);

        JetType receiverType = null;
        JetTypeReference receiverTypeRef = function.getReceiverTypeRef();
        if (receiverTypeRef != null) {
            JetScope scopeForReceiver =
                    function.hasTypeParameterListBeforeFunctionName()
                    ? innerScope
                    : scope;
            receiverType = typeResolver.resolveType(scopeForReceiver, receiverTypeRef, trace, true);
        }

        List valueParameterDescriptors =
                resolveValueParameters(functionDescriptor, innerScope, function.getValueParameters(), trace);

        innerScope.changeLockLevel(WritableScope.LockLevel.READING);

        JetTypeReference returnTypeRef = function.getReturnTypeRef();
        JetType returnType;
        if (returnTypeRef != null) {
            returnType = typeResolver.resolveType(innerScope, returnTypeRef, trace, true);
        }
        else if (function.hasBlockBody()) {
            returnType = KotlinBuiltIns.getInstance().getUnitType();
        }
        else {
            JetExpression bodyExpression = function.getBodyExpression();
            if (bodyExpression != null) {
                returnType =
                        DeferredType.createRecursionIntolerant(
                                storageManager,
                                trace,
                                new Function0() {
                                    @Override
                                    public JetType invoke() {
                                        JetType type = expressionTypingServices
                                                .getBodyExpressionType(trace, scope, dataFlowInfo, function, functionDescriptor);
                                        return transformAnonymousTypeIfNeeded(functionDescriptor, function, type, trace);
                                    }
                                });
            }
            else {
                returnType = ErrorUtils.createErrorType("No type, no body");
            }
        }
        boolean hasBody = function.getBodyExpression() != null;
        Modality modality = resolveModalityFromModifiers(function, getDefaultModality(containingDescriptor, hasBody));
        Visibility visibility = resolveVisibilityFromModifiers(function, getDefaultVisibility(function, containingDescriptor));
        functionDescriptor.initialize(
                receiverType,
                getExpectedThisObjectIfNeeded(containingDescriptor),
                typeParameterDescriptors,
                valueParameterDescriptors,
                returnType,
                modality,
                visibility
        );

        BindingContextUtils.recordFunctionDeclarationToDescriptor(trace, function, functionDescriptor);
        return functionDescriptor;
    }

    @NotNull
    public static SimpleFunctionDescriptor createComponentFunctionDescriptor(
            int parameterIndex,
            @NotNull PropertyDescriptor property,
            @NotNull ValueParameterDescriptor parameter,
            @NotNull ClassDescriptor classDescriptor,
            @NotNull BindingTrace trace
    ) {
        String functionName = COMPONENT_FUNCTION_NAME_PREFIX + parameterIndex;
        JetType returnType = property.getType();

        SimpleFunctionDescriptorImpl functionDescriptor = SimpleFunctionDescriptorImpl.create(
                classDescriptor,
                Annotations.EMPTY,
                Name.identifier(functionName),
                CallableMemberDescriptor.Kind.SYNTHESIZED
        );

        functionDescriptor.initialize(
                null,
                classDescriptor.getThisAsReceiverParameter(),
                Collections.emptyList(),
                Collections.emptyList(),
                returnType,
                Modality.FINAL,
                property.getVisibility()
        );

        trace.record(BindingContext.DATA_CLASS_COMPONENT_FUNCTION, parameter, functionDescriptor);

        return functionDescriptor;
    }

    @NotNull
    public static SimpleFunctionDescriptor createCopyFunctionDescriptor(
            @NotNull Collection constructorParameters,
            @NotNull ClassDescriptor classDescriptor,
            @NotNull BindingTrace trace
    ) {
        JetType returnType = classDescriptor.getDefaultType();

        SimpleFunctionDescriptorImpl functionDescriptor = SimpleFunctionDescriptorImpl.create(
                classDescriptor,
                Annotations.EMPTY,
                COPY_METHOD_NAME,
                CallableMemberDescriptor.Kind.SYNTHESIZED
        );

        List parameterDescriptors = Lists.newArrayList();

        for (ValueParameterDescriptor parameter : constructorParameters) {
            PropertyDescriptor propertyDescriptor = trace.getBindingContext().get(BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter);
            // If parameter hasn't corresponding property, so it mustn't have default value as a parameter in copy function for data class
            boolean declaresDefaultValue = propertyDescriptor != null;
            ValueParameterDescriptorImpl parameterDescriptor =
                    new ValueParameterDescriptorImpl(functionDescriptor, null, parameter.getIndex(), parameter.getAnnotations(),
                                                     parameter.getName(), parameter.getType(),
                                                     declaresDefaultValue,
                                                     parameter.getVarargElementType());
            parameterDescriptors.add(parameterDescriptor);
            if (declaresDefaultValue) {
                trace.record(BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameterDescriptor, propertyDescriptor);
            }
        }

        functionDescriptor.initialize(
                null,
                classDescriptor.getThisAsReceiverParameter(),
                Collections.emptyList(),
                parameterDescriptors,
                returnType,
                Modality.FINAL,
                classDescriptor.getVisibility()
        );

        trace.record(BindingContext.DATA_CLASS_COPY_FUNCTION, classDescriptor, functionDescriptor);
        return functionDescriptor;
    }

    public static Visibility getDefaultVisibility(JetModifierListOwner modifierListOwner, DeclarationDescriptor containingDescriptor) {
        Visibility defaultVisibility;
        if (containingDescriptor instanceof ClassDescriptor) {
            JetModifierList modifierList = modifierListOwner.getModifierList();
            defaultVisibility = modifierList != null && modifierList.hasModifier(OVERRIDE_KEYWORD)
                                           ? Visibilities.INHERITED
                                           : Visibilities.INTERNAL;
        }
        else if (containingDescriptor instanceof FunctionDescriptor) {
            defaultVisibility = Visibilities.LOCAL;
        }
        else {
            defaultVisibility = Visibilities.INTERNAL;
        }
        return defaultVisibility;
    }

    public static Modality getDefaultModality(DeclarationDescriptor containingDescriptor, boolean isBodyPresent) {
        Modality defaultModality;
        if (containingDescriptor instanceof ClassDescriptor) {
            boolean isTrait = ((ClassDescriptor) containingDescriptor).getKind() == ClassKind.TRAIT;
            boolean isDefinitelyAbstract = isTrait && !isBodyPresent;
            Modality basicModality = isTrait ? Modality.OPEN : Modality.FINAL;
            defaultModality = isDefinitelyAbstract ? Modality.ABSTRACT : basicModality;
        }
        else {
            defaultModality = Modality.FINAL;
        }
        return defaultModality;
    }

    @NotNull
    private List resolveValueParameters(
            FunctionDescriptor functionDescriptor,
            WritableScope parameterScope,
            List valueParameters,
            BindingTrace trace
    ) {
        List result = new ArrayList();
        for (int i = 0; i < valueParameters.size(); i++) {
            JetParameter valueParameter = valueParameters.get(i);
            JetTypeReference typeReference = valueParameter.getTypeReference();

            JetType type;
            if (typeReference == null) {
                trace.report(VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION.on(valueParameter));
                type = ErrorUtils.createErrorType("Type annotation was missing");
            }
            else {
                type = typeResolver.resolveType(parameterScope, typeReference, trace, true);
            }

            if (!(functionDescriptor instanceof ConstructorDescriptor)) {
                checkParameterHasNoValOrVar(trace, valueParameter, VAL_OR_VAR_ON_FUN_PARAMETER);
                checkParameterHasNoModifier(trace, valueParameter);
            } else {
                checkConstructorParameterHasNoModifier(trace, valueParameter);
            }

            ValueParameterDescriptor valueParameterDescriptor =
                    resolveValueParameterDescriptor(parameterScope, functionDescriptor, valueParameter, i, type, trace);
            parameterScope.addVariableDescriptor(valueParameterDescriptor);
            result.add(valueParameterDescriptor);
        }
        return result;
    }

    @NotNull
    public ValueParameterDescriptorImpl resolveValueParameterDescriptor(
            JetScope scope, DeclarationDescriptor declarationDescriptor,
            JetParameter valueParameter, int index, JetType type, BindingTrace trace
    ) {
        return resolveValueParameterDescriptor(declarationDescriptor, valueParameter, index, type, trace,
                annotationResolver.resolveAnnotationsWithoutArguments(scope, valueParameter.getModifierList(), trace));
    }

    @NotNull
    public ValueParameterDescriptorImpl resolveValueParameterDescriptorWithAnnotationArguments(
            JetScope scope, DeclarationDescriptor declarationDescriptor,
            JetParameter valueParameter, int index, JetType type, BindingTrace trace
    ) {
        return resolveValueParameterDescriptor(declarationDescriptor, valueParameter, index, type, trace,
                annotationResolver.resolveAnnotationsWithArguments(scope, valueParameter.getModifierList(), trace));
    }

    @NotNull
    private static ValueParameterDescriptorImpl resolveValueParameterDescriptor(
            DeclarationDescriptor declarationDescriptor,
            JetParameter valueParameter, int index, JetType type, BindingTrace trace,
            Annotations annotations
    ) {
        JetType varargElementType = null;
        JetType variableType = type;
        if (valueParameter.hasModifier(JetTokens.VARARG_KEYWORD)) {
            varargElementType = type;
            variableType = DescriptorUtils.getVarargParameterType(type);
        }
        ValueParameterDescriptorImpl valueParameterDescriptor = new ValueParameterDescriptorImpl(
                declarationDescriptor,
                null,
                index,
                annotations,
                JetPsiUtil.safeName(valueParameter.getName()),
                variableType,
                valueParameter.getDefaultValue() != null,
                varargElementType
        );

        trace.record(BindingContext.VALUE_PARAMETER, valueParameter, valueParameterDescriptor);
        return valueParameterDescriptor;
    }

    public List resolveTypeParametersForCallableDescriptor(
            DeclarationDescriptor containingDescriptor,
            WritableScope extensibleScope,
            List typeParameters,
            BindingTrace trace
    ) {
        List result = new ArrayList();
        for (int i = 0, typeParametersSize = typeParameters.size(); i < typeParametersSize; i++) {
            JetTypeParameter typeParameter = typeParameters.get(i);
            result.add(resolveTypeParameterForCallableDescriptor(containingDescriptor, extensibleScope, typeParameter, i, trace));
        }
        return result;
    }

    private TypeParameterDescriptorImpl resolveTypeParameterForCallableDescriptor(
            DeclarationDescriptor containingDescriptor,
            WritableScope extensibleScope,
            JetTypeParameter typeParameter,
            int index,
            BindingTrace trace
    ) {
        if (typeParameter.getVariance() != Variance.INVARIANT) {
            assert !(containingDescriptor instanceof ClassifierDescriptor) : "This method is intended for functions/properties";
            trace.report(VARIANCE_ON_TYPE_PARAMETER_OF_FUNCTION_OR_PROPERTY.on(typeParameter));
        }

        // TODO: Support annotation for type parameters
        AnnotationResolver.reportUnsupportedAnnotationForTypeParameter(typeParameter, trace);

        TypeParameterDescriptorImpl typeParameterDescriptor = TypeParameterDescriptorImpl.createForFurtherModification(
                containingDescriptor,
                Annotations.EMPTY,
                typeParameter.hasModifier(JetTokens.REIFIED_KEYWORD),
                typeParameter.getVariance(),
                JetPsiUtil.safeName(typeParameter.getName()),
                index
        );
        trace.record(BindingContext.TYPE_PARAMETER, typeParameter, typeParameterDescriptor);
        extensibleScope.addTypeParameterDescriptor(typeParameterDescriptor);
        return typeParameterDescriptor;
    }

    @NotNull
    public static ConstructorDescriptorImpl createAndRecordPrimaryConstructorForObject(
            @Nullable PsiElement object,
            @NotNull ClassDescriptor classDescriptor,
            @NotNull BindingTrace trace
    ) {
        ConstructorDescriptorImpl constructorDescriptor = DescriptorFactory.createPrimaryConstructorForObject(classDescriptor);
        if (object != null) {
            trace.record(CONSTRUCTOR, object, constructorDescriptor);
        }
        return constructorDescriptor;
    }

    static final class UpperBoundCheckerTask {
        JetTypeReference upperBound;
        JetType upperBoundType;
        boolean isClassObjectConstraint;

        private UpperBoundCheckerTask(JetTypeReference upperBound, JetType upperBoundType, boolean classObjectConstraint) {
            this.upperBound = upperBound;
            this.upperBoundType = upperBoundType;
            isClassObjectConstraint = classObjectConstraint;
        }
    }

    public void resolveGenericBounds(
            @NotNull JetTypeParameterListOwner declaration,
            @NotNull DeclarationDescriptor descriptor,
            JetScope scope,
            List parameters,
            BindingTrace trace
    ) {
        List deferredUpperBoundCheckerTasks = Lists.newArrayList();

        List typeParameters = declaration.getTypeParameters();
        Map parameterByName = Maps.newHashMap();
        for (int i = 0; i < typeParameters.size(); i++) {
            JetTypeParameter jetTypeParameter = typeParameters.get(i);
            TypeParameterDescriptorImpl typeParameterDescriptor = parameters.get(i);

            parameterByName.put(typeParameterDescriptor.getName(), typeParameterDescriptor);

            JetTypeReference extendsBound = jetTypeParameter.getExtendsBound();
            if (extendsBound != null) {
                JetType type = typeResolver.resolveType(scope, extendsBound, trace, false);
                typeParameterDescriptor.addUpperBound(type);
                deferredUpperBoundCheckerTasks.add(new UpperBoundCheckerTask(extendsBound, type, false));
            }
        }
        for (JetTypeConstraint constraint : declaration.getTypeConstraints()) {
            reportUnsupportedClassObjectConstraint(trace, constraint);

            JetSimpleNameExpression subjectTypeParameterName = constraint.getSubjectTypeParameterName();
            if (subjectTypeParameterName == null) {
                continue;
            }
            Name referencedName = subjectTypeParameterName.getReferencedNameAsName();
            TypeParameterDescriptorImpl typeParameterDescriptor = parameterByName.get(referencedName);
            JetTypeReference boundTypeReference = constraint.getBoundTypeReference();
            JetType bound = null;
            if (boundTypeReference != null) {
                bound = typeResolver.resolveType(scope, boundTypeReference, trace, false);
                deferredUpperBoundCheckerTasks
                        .add(new UpperBoundCheckerTask(boundTypeReference, bound, constraint.isClassObjectConstraint()));
            }

            if (typeParameterDescriptor != null) {
                trace.record(BindingContext.REFERENCE_TARGET, subjectTypeParameterName, typeParameterDescriptor);
                if (bound != null) {
                    if (constraint.isClassObjectConstraint()) {
                        // Class object bounds are not supported
                        //typeParameterDescriptor.addClassObjectBound(bound);
                    }
                    else {
                        typeParameterDescriptor.addUpperBound(bound);
                    }
                }
            }
        }

        for (TypeParameterDescriptorImpl parameter : parameters) {
            parameter.addDefaultUpperBound();

            parameter.setInitialized();

            checkConflictingUpperBounds(trace, parameter, typeParameters.get(parameter.getIndex()));
        }

        if (!(declaration instanceof JetClass)) {
            for (UpperBoundCheckerTask checkerTask : deferredUpperBoundCheckerTasks) {
                checkUpperBoundType(checkerTask.upperBound, checkerTask.upperBoundType, checkerTask.isClassObjectConstraint, trace);
            }

            checkNamesInConstraints(declaration, descriptor, scope, trace);
        }
    }

    public static void checkConflictingUpperBounds(
            @NotNull BindingTrace trace,
            @NotNull TypeParameterDescriptor parameter,
            @NotNull JetTypeParameter typeParameter
    ) {
        PsiElement nameIdentifier = typeParameter.getNameIdentifier();
        if (KotlinBuiltIns.getInstance().isNothing(parameter.getUpperBoundsAsType())) {
            if (nameIdentifier != null) {
                trace.report(CONFLICTING_UPPER_BOUNDS.on(nameIdentifier, parameter));
            }
        }

        JetType classObjectType = parameter.getClassObjectType();
        if (classObjectType != null && KotlinBuiltIns.getInstance().isNothing(classObjectType)) {
            if (nameIdentifier != null) {
                trace.report(CONFLICTING_CLASS_OBJECT_UPPER_BOUNDS.on(nameIdentifier, parameter));
            }
        }
    }

    public void checkNamesInConstraints(
            @NotNull JetTypeParameterListOwner declaration,
            @NotNull DeclarationDescriptor descriptor,
            @NotNull JetScope scope,
            @NotNull BindingTrace trace
    ) {
        for (JetTypeConstraint constraint : declaration.getTypeConstraints()) {
            JetSimpleNameExpression nameExpression = constraint.getSubjectTypeParameterName();
            if (nameExpression == null) continue;

            Name name = nameExpression.getReferencedNameAsName();

            ClassifierDescriptor classifier = scope.getClassifier(name);
            if (classifier instanceof TypeParameterDescriptor && classifier.getContainingDeclaration() == descriptor) continue;

            if (classifier != null) {
                // To tell the user that we look only for locally defined type parameters
                trace.report(NAME_IN_CONSTRAINT_IS_NOT_A_TYPE_PARAMETER.on(nameExpression, constraint, declaration));
                trace.record(BindingContext.REFERENCE_TARGET, nameExpression, classifier);
            }
            else {
                trace.report(UNRESOLVED_REFERENCE.on(nameExpression, nameExpression));
            }

            JetTypeReference boundTypeReference = constraint.getBoundTypeReference();
            if (boundTypeReference != null) {
                typeResolver.resolveType(scope, boundTypeReference, trace, true);
            }
        }
    }

    public static void reportUnsupportedClassObjectConstraint(BindingTrace trace, JetTypeConstraint constraint) {
        if (constraint.isClassObjectConstraint()) {
            trace.report(UNSUPPORTED.on(constraint, "Class objects constraints are not supported yet"));
        }
    }

    public static void checkUpperBoundType(
            JetTypeReference upperBound,
            JetType upperBoundType,
            boolean isClassObjectConstraint,
            BindingTrace trace
    ) {
        if (!TypeUtils.canHaveSubtypes(JetTypeChecker.INSTANCE, upperBoundType)) {
            if (isClassObjectConstraint) {
                trace.report(FINAL_CLASS_OBJECT_UPPER_BOUND.on(upperBound, upperBoundType));
            }
            else {
                trace.report(FINAL_UPPER_BOUND.on(upperBound, upperBoundType));
            }
        }
    }

    @NotNull
    public VariableDescriptor resolveLocalVariableDescriptor(
            @NotNull JetScope scope,
            @NotNull JetParameter parameter,
            BindingTrace trace
    ) {
        JetType type = resolveParameterType(scope, parameter, trace);
        return resolveLocalVariableDescriptor(parameter, type, trace, scope);
    }

    private JetType resolveParameterType(JetScope scope, JetParameter parameter, BindingTrace trace) {
        JetTypeReference typeReference = parameter.getTypeReference();
        JetType type;
        if (typeReference != null) {
            type = typeResolver.resolveType(scope, typeReference, trace, true);
        }
        else {
            // Error is reported by the parser
            type = ErrorUtils.createErrorType("Annotation is absent");
        }
        if (parameter.hasModifier(JetTokens.VARARG_KEYWORD)) {
            return DescriptorUtils.getVarargParameterType(type);
        }
        return type;
    }

    public VariableDescriptor resolveLocalVariableDescriptor(
            @NotNull JetParameter parameter,
            @NotNull JetType type,
            BindingTrace trace,
            @NotNull JetScope scope
    ) {
        VariableDescriptor variableDescriptor = new LocalVariableDescriptor(
                scope.getContainingDeclaration(),
                annotationResolver.resolveAnnotationsWithArguments(scope, parameter.getModifierList(), trace),
                JetPsiUtil.safeName(parameter.getName()),
                type,
                false);
        trace.record(BindingContext.VALUE_PARAMETER, parameter, variableDescriptor);
        return variableDescriptor;
    }

    @NotNull
    public VariableDescriptor resolveLocalVariableDescriptor(
            JetScope scope,
            JetVariableDeclaration variable,
            DataFlowInfo dataFlowInfo,
            BindingTrace trace
    ) {
        DeclarationDescriptor containingDeclaration = scope.getContainingDeclaration();
        // SCRIPT: Create property descriptors
        if (JetPsiUtil.isScriptDeclaration(variable)) {
            PropertyDescriptorImpl propertyDescriptor = PropertyDescriptorImpl.create(
                    containingDeclaration,
                    annotationResolver.resolveAnnotationsWithArguments(scope, variable.getModifierList(), trace),
                    Modality.FINAL,
                    Visibilities.INTERNAL,
                    variable.isVar(),
                    JetPsiUtil.safeName(variable.getName()),
                    CallableMemberDescriptor.Kind.DECLARATION
            );

            JetType type =
                    getVariableType(propertyDescriptor, scope, variable, dataFlowInfo, false, trace); // For a local variable the type must not be deferred

            ReceiverParameterDescriptor receiverParameter = ((ScriptDescriptor) containingDeclaration).getThisAsReceiverParameter();
            propertyDescriptor.setType(type, Collections.emptyList(), receiverParameter, (JetType) null);
            initializeWithDefaultGetterSetter(propertyDescriptor);
            trace.record(BindingContext.VARIABLE, variable, propertyDescriptor);
            return propertyDescriptor;
        }
        else {
            VariableDescriptorImpl variableDescriptor =
                    resolveLocalVariableDescriptorWithType(scope, variable, null, trace);

            JetType type =
                    getVariableType(variableDescriptor, scope, variable, dataFlowInfo, false, trace); // For a local variable the type must not be deferred
            variableDescriptor.setOutType(type);
            return variableDescriptor;
        }
    }

    private static void initializeWithDefaultGetterSetter(PropertyDescriptorImpl propertyDescriptor) {
        PropertyGetterDescriptorImpl getter = propertyDescriptor.getGetter();
        if (getter == null && propertyDescriptor.getVisibility() != Visibilities.PRIVATE) {
            getter = DescriptorFactory.createDefaultGetter(propertyDescriptor);
            getter.initialize(propertyDescriptor.getType());
        }

        PropertySetterDescriptor setter = propertyDescriptor.getSetter();
        if (setter == null && propertyDescriptor.isVar()) {
            setter = DescriptorFactory.createDefaultSetter(propertyDescriptor);
        }
        propertyDescriptor.initialize(getter, setter);
    }

    @NotNull
    public VariableDescriptorImpl resolveLocalVariableDescriptorWithType(
            @NotNull JetScope scope,
            @NotNull JetVariableDeclaration variable,
            @Nullable JetType type,
            @NotNull BindingTrace trace
    ) {
        VariableDescriptorImpl variableDescriptor = new LocalVariableDescriptor(
                scope.getContainingDeclaration(),
                annotationResolver.resolveAnnotationsWithArguments(scope, variable.getModifierList(), trace),
                JetPsiUtil.safeName(variable.getName()),
                type,
                variable.isVar());
        trace.record(BindingContext.VARIABLE, variable, variableDescriptor);
        return variableDescriptor;
    }

    @NotNull
    public PropertyDescriptor resolvePropertyDescriptor(
            @NotNull DeclarationDescriptor containingDeclaration,
            @NotNull JetScope scope,
            @NotNull JetProperty property,
            @NotNull BindingTrace trace,
            @NotNull DataFlowInfo dataFlowInfo
    ) {
        JetModifierList modifierList = property.getModifierList();
        boolean isVar = property.isVar();

        boolean hasBody = hasBody(property);
        Modality modality = containingDeclaration instanceof ClassDescriptor
                            ? resolveModalityFromModifiers(property, getDefaultModality(containingDeclaration, hasBody))
                            : Modality.FINAL;
        Visibility visibility = resolveVisibilityFromModifiers(property, getDefaultVisibility(property, containingDeclaration));
        PropertyDescriptorImpl propertyDescriptor = PropertyDescriptorImpl.create(
                containingDeclaration,
                annotationResolver.resolveAnnotationsWithoutArguments(scope, modifierList, trace),
                modality,
                visibility,
                isVar,
                JetPsiUtil.safeName(property.getName()),
                CallableMemberDescriptor.Kind.DECLARATION
        );

        List typeParameterDescriptors;
        JetScope scopeWithTypeParameters;
        JetType receiverType = null;

        {
            List typeParameters = property.getTypeParameters();
            if (typeParameters.isEmpty()) {
                scopeWithTypeParameters = scope;
                typeParameterDescriptors = Collections.emptyList();
            }
            else {
                WritableScope writableScope = new WritableScopeImpl(
                        scope, containingDeclaration, new TraceBasedRedeclarationHandler(trace),
                        "Scope with type parameters of a property");
                typeParameterDescriptors = resolveTypeParametersForCallableDescriptor(containingDeclaration, writableScope, typeParameters,
                                                                                      trace);
                writableScope.changeLockLevel(WritableScope.LockLevel.READING);
                resolveGenericBounds(property, propertyDescriptor, writableScope, typeParameterDescriptors, trace);
                scopeWithTypeParameters = writableScope;
            }

            JetTypeReference receiverTypeRef = property.getReceiverTypeRef();
            if (receiverTypeRef != null) {
                receiverType = typeResolver.resolveType(scopeWithTypeParameters, receiverTypeRef, trace, true);
            }
        }

        ReceiverParameterDescriptor receiverDescriptor = DescriptorFactory.createReceiverParameterForCallable(propertyDescriptor,
                                                                                                              receiverType);

        JetScope propertyScope = JetScopeUtils.getPropertyDeclarationInnerScope(propertyDescriptor, scope, typeParameterDescriptors,
                                                                                NO_RECEIVER_PARAMETER, trace);

        JetType type = getVariableType(propertyDescriptor, propertyScope, property, dataFlowInfo, true, trace);

        propertyDescriptor.setType(type, typeParameterDescriptors, getExpectedThisObjectIfNeeded(containingDeclaration),
                                   receiverDescriptor);

        PropertyGetterDescriptorImpl getter = resolvePropertyGetterDescriptor(scopeWithTypeParameters, property, propertyDescriptor, trace);
        PropertySetterDescriptor setter = resolvePropertySetterDescriptor(scopeWithTypeParameters, property, propertyDescriptor, trace);

        propertyDescriptor.initialize(getter, setter);

        trace.record(BindingContext.VARIABLE, property, propertyDescriptor);
        return propertyDescriptor;
    }

    /*package*/
    static boolean hasBody(JetProperty property) {
        boolean hasBody = property.getDelegateExpressionOrInitializer() != null;
        if (!hasBody) {
            JetPropertyAccessor getter = property.getGetter();
            if (getter != null && getter.getBodyExpression() != null) {
                hasBody = true;
            }
            JetPropertyAccessor setter = property.getSetter();
            if (!hasBody && setter != null && setter.getBodyExpression() != null) {
                hasBody = true;
            }
        }
        return hasBody;
    }

    @NotNull
    private JetType getVariableType(
            @NotNull final VariableDescriptorImpl variableDescriptor,
            @NotNull final JetScope scope,
            @NotNull final JetVariableDeclaration variable,
            @NotNull final DataFlowInfo dataFlowInfo,
            boolean notLocal,
            @NotNull final BindingTrace trace
    ) {
        JetTypeReference propertyTypeRef = variable.getTypeRef();

        boolean hasDelegate = variable instanceof JetProperty && ((JetProperty) variable).getDelegateExpression() != null;
        if (propertyTypeRef == null) {
            final JetExpression initializer = variable.getInitializer();
            if (initializer == null) {
                if (hasDelegate && variableDescriptor instanceof PropertyDescriptor) {
                    final JetProperty property = (JetProperty) variable;
                    final JetExpression propertyDelegateExpression = property.getDelegateExpression();
                    if (propertyDelegateExpression != null) {
                        return DeferredType.createRecursionIntolerant(
                                storageManager,
                                trace,
                                new Function0() {
                                    @Override
                                    public JetType invoke() {
                                        return resolveDelegatedPropertyType(property, (PropertyDescriptor) variableDescriptor, scope,
                                                                            propertyDelegateExpression, dataFlowInfo, trace);
                                    }
                                });
                    }
                }
                if (!notLocal) {
                    trace.report(VARIABLE_WITH_NO_TYPE_NO_INITIALIZER.on(variable));
                }
                return ErrorUtils.createErrorType("No type, no body");
            }
            else {
                if (notLocal) {
                    return DeferredType.createRecursionIntolerant(
                            storageManager,
                            trace,
                            new Function0() {
                                @Override
                                public JetType invoke() {
                                    JetType initializerType = resolveInitializerType(scope, initializer, dataFlowInfo, trace);
                                    setConstantForVariableIfNeeded(variableDescriptor, scope, variable, dataFlowInfo, initializerType, trace);
                                    return transformAnonymousTypeIfNeeded(variableDescriptor, variable, initializerType, trace);
                                }
                            }
                    );
                }
                else {
                    JetType initializerType = resolveInitializerType(scope, initializer, dataFlowInfo, trace);
                    setConstantForVariableIfNeeded(variableDescriptor, scope, variable, dataFlowInfo, initializerType, trace);
                    return initializerType;
                }
            }
        }
        else {
            JetType type = typeResolver.resolveType(scope, propertyTypeRef, trace, true);
            setConstantForVariableIfNeeded(variableDescriptor, scope, variable, dataFlowInfo, type, trace);
            return type;
        }
    }

    private void setConstantForVariableIfNeeded(
            @NotNull VariableDescriptorImpl variableDescriptor,
            @NotNull final JetScope scope,
            @NotNull JetVariableDeclaration variable,
            @NotNull final DataFlowInfo dataFlowInfo,
            @NotNull final JetType variableType,
            @NotNull final BindingTrace trace
    ) {
        if (!shouldRecordInitializerForProperty(variableDescriptor, variableType)) return;

        final JetExpression initializer = variable.getInitializer();
        if (initializer == null) return;

        variableDescriptor.setCompileTimeInitializer(
            storageManager.createRecursionTolerantNullableLazyValue(new Function0>() {
                @Nullable
                @Override
                public CompileTimeConstant invoke() {
                    JetType initializerType = expressionTypingServices.safeGetType(scope, initializer, variableType, dataFlowInfo, trace);
                    CompileTimeConstant constant = ConstantExpressionEvaluator.object$.evaluate(initializer, trace, initializerType);
                    if (constant instanceof IntegerValueTypeConstant) {
                        return EvaluatePackage.createCompileTimeConstantWithType((IntegerValueTypeConstant) constant, initializerType);
                    }
                    return constant;
                }
            }, null)
        );
    }

    @NotNull
    private JetType resolveDelegatedPropertyType(
            @NotNull JetProperty property,
            @NotNull PropertyDescriptor propertyDescriptor,
            @NotNull JetScope scope,
            @NotNull JetExpression delegateExpression,
            @NotNull DataFlowInfo dataFlowInfo,
            @NotNull BindingTrace trace
    ) {
        JetScope accessorScope = JetScopeUtils.makeScopeForPropertyAccessor(propertyDescriptor, scope, trace);

        JetType type = delegatedPropertyResolver.resolveDelegateExpression(
                delegateExpression, property, propertyDescriptor, scope, accessorScope, trace, dataFlowInfo);

        if (type != null) {
            JetType getterReturnType = delegatedPropertyResolver
                    .getDelegatedPropertyGetMethodReturnType(propertyDescriptor, delegateExpression, type, trace, accessorScope);
            if (getterReturnType != null) {
                return getterReturnType;
            }
        }
        return ErrorUtils.createErrorType("Type from delegate");
    }

    @Nullable
    private static JetType transformAnonymousTypeIfNeeded(
            @NotNull DeclarationDescriptorWithVisibility descriptor,
            @NotNull JetNamedDeclaration declaration,
            @NotNull JetType type,
            @NotNull BindingTrace trace
    ) {
        ClassifierDescriptor classifierDescriptor = type.getConstructor().getDeclarationDescriptor();
        if (classifierDescriptor == null || !DescriptorUtils.isAnonymousObject(classifierDescriptor)) {
            return type;
        }

        boolean definedInClass = DescriptorUtils.getParentOfType(descriptor, ClassDescriptor.class) != null;
        boolean isLocal = descriptor.getContainingDeclaration() instanceof CallableDescriptor;
        Visibility visibility = descriptor.getVisibility();
        boolean transformNeeded = !isLocal && !visibility.isPublicAPI()
                                  && !(definedInClass && Visibilities.PRIVATE.equals(visibility));
        if (transformNeeded) {
            if (type.getConstructor().getSupertypes().size() == 1) {
                assert type.getArguments().isEmpty() : "Object expression couldn't have any type parameters!";
                return type.getConstructor().getSupertypes().iterator().next();
            }
            else {
                trace.report(AMBIGUOUS_ANONYMOUS_TYPE_INFERRED.on(declaration, type.getConstructor().getSupertypes()));
            }
        }
        return type;
    }

    @NotNull
    private JetType resolveInitializerType(
            @NotNull JetScope scope,
            @NotNull JetExpression initializer,
            @NotNull DataFlowInfo dataFlowInfo,
            @NotNull BindingTrace trace
    ) {
        return expressionTypingServices.safeGetType(scope, initializer, TypeUtils.NO_EXPECTED_TYPE, dataFlowInfo, trace);
    }

    @Nullable
    private PropertySetterDescriptor resolvePropertySetterDescriptor(
            @NotNull JetScope scope,
            @NotNull JetProperty property,
            @NotNull PropertyDescriptor propertyDescriptor,
            BindingTrace trace
    ) {
        JetPropertyAccessor setter = property.getSetter();
        PropertySetterDescriptorImpl setterDescriptor = null;
        if (setter != null) {
            Annotations annotations =
                    annotationResolver.resolveAnnotationsWithoutArguments(scope, setter.getModifierList(), trace);
            JetParameter parameter = setter.getParameter();

            setterDescriptor = new PropertySetterDescriptorImpl(propertyDescriptor, annotations,
                                                                resolveModalityFromModifiers(setter, propertyDescriptor.getModality()),
                                                                resolveVisibilityFromModifiers(setter, propertyDescriptor.getVisibility()),
                                                                setter.getBodyExpression() != null, false,
                                                                CallableMemberDescriptor.Kind.DECLARATION, null);
            if (parameter != null) {

                // This check is redundant: the parser does not allow a default value, but we'll keep it just in case
                JetExpression defaultValue = parameter.getDefaultValue();
                if (defaultValue != null) {
                    trace.report(SETTER_PARAMETER_WITH_DEFAULT_VALUE.on(defaultValue));
                }

                JetType type;
                JetTypeReference typeReference = parameter.getTypeReference();
                if (typeReference == null) {
                    type = propertyDescriptor.getType(); // TODO : this maybe unknown at this point
                }
                else {
                    type = typeResolver.resolveType(scope, typeReference, trace, true);
                    JetType inType = propertyDescriptor.getType();
                    if (inType != null) {
                        if (!TypeUtils.equalTypes(type, inType)) {
                            trace.report(WRONG_SETTER_PARAMETER_TYPE.on(typeReference, inType, type));
                        }
                    }
                    else {
                        // TODO : the same check may be needed later???
                    }
                }

                ValueParameterDescriptorImpl valueParameterDescriptor =
                        resolveValueParameterDescriptor(scope, setterDescriptor, parameter, 0, type, trace);
                setterDescriptor.initialize(valueParameterDescriptor);
            }
            else {
                setterDescriptor.initializeDefault();
            }

            trace.record(BindingContext.PROPERTY_ACCESSOR, setter, setterDescriptor);
        }
        else if (property.isVar()) {
            setterDescriptor = DescriptorFactory.createSetter(propertyDescriptor, property.getDelegateExpression() == null);
        }

        if (!property.isVar()) {
            if (setter != null) {
                //                trace.getErrorHandler().genericError(setter.asElement().getNode(), "A 'val'-property cannot have a setter");
                trace.report(VAL_WITH_SETTER.on(setter));
            }
        }
        return setterDescriptor;
    }

    @Nullable
    private PropertyGetterDescriptorImpl resolvePropertyGetterDescriptor(
            @NotNull JetScope scope,
            @NotNull JetProperty property,
            @NotNull PropertyDescriptor propertyDescriptor,
            BindingTrace trace
    ) {
        PropertyGetterDescriptorImpl getterDescriptor;
        JetPropertyAccessor getter = property.getGetter();
        if (getter != null) {
            Annotations annotations =
                    annotationResolver.resolveAnnotationsWithoutArguments(scope, getter.getModifierList(), trace);

            JetType outType = propertyDescriptor.getType();
            JetType returnType = outType;
            JetTypeReference returnTypeReference = getter.getReturnTypeReference();
            if (returnTypeReference != null) {
                returnType = typeResolver.resolveType(scope, returnTypeReference, trace, true);
                if (outType != null && !TypeUtils.equalTypes(returnType, outType)) {
                    trace.report(WRONG_GETTER_RETURN_TYPE.on(returnTypeReference, propertyDescriptor.getReturnType(), outType));
                }
            }

            getterDescriptor = new PropertyGetterDescriptorImpl(propertyDescriptor, annotations,
                                                                resolveModalityFromModifiers(getter, propertyDescriptor.getModality()),
                                                                resolveVisibilityFromModifiers(getter, propertyDescriptor.getVisibility()),
                                                                getter.getBodyExpression() != null, false,
                                                                CallableMemberDescriptor.Kind.DECLARATION, null);
            getterDescriptor.initialize(returnType);
            trace.record(BindingContext.PROPERTY_ACCESSOR, getter, getterDescriptor);
        }
        else {
            getterDescriptor = DescriptorFactory.createGetter(propertyDescriptor, property.getDelegateExpression() == null);
            getterDescriptor.initialize(propertyDescriptor.getType());
        }
        return getterDescriptor;
    }

    @NotNull
    private ConstructorDescriptorImpl createConstructorDescriptor(
            @NotNull JetScope scope,
            @NotNull ClassDescriptor classDescriptor,
            boolean isPrimary,
            @Nullable JetModifierList modifierList,
            @NotNull JetDeclaration declarationToTrace,
            List typeParameters, @NotNull List valueParameters, BindingTrace trace
    ) {
        ConstructorDescriptorImpl constructorDescriptor = ConstructorDescriptorImpl.create(
                classDescriptor,
                annotationResolver.resolveAnnotationsWithoutArguments(scope, modifierList, trace),
                isPrimary
        );
        trace.record(BindingContext.CONSTRUCTOR, declarationToTrace, constructorDescriptor);
        WritableScopeImpl parameterScope = new WritableScopeImpl(
                scope, constructorDescriptor, new TraceBasedRedeclarationHandler(trace), "Scope with value parameters of a constructor");
        parameterScope.changeLockLevel(WritableScope.LockLevel.BOTH);
        ConstructorDescriptorImpl constructor = constructorDescriptor.initialize(
                typeParameters,
                resolveValueParameters(
                        constructorDescriptor,
                        parameterScope,
                        valueParameters, trace),
                resolveVisibilityFromModifiers(modifierList, getDefaultConstructorVisibility(classDescriptor)),
                DescriptorUtils.isConstructorOfStaticNestedClass(constructorDescriptor));
        if (isAnnotationClass(classDescriptor)) {
            CompileTimeConstantUtils.checkConstructorParametersType(valueParameters, trace);
        }
        return constructor;
    }

    @Nullable
    public ConstructorDescriptorImpl resolvePrimaryConstructorDescriptor(
            @NotNull JetScope scope,
            @NotNull ClassDescriptor classDescriptor,
            @NotNull JetClass classElement,
            BindingTrace trace
    ) {
        if (classDescriptor.getKind() == ClassKind.ENUM_ENTRY) return null;
        return createConstructorDescriptor(
                scope,
                classDescriptor,
                true,
                classElement.getPrimaryConstructorModifierList(),
                classElement,
                classDescriptor.getTypeConstructor().getParameters(), classElement.getPrimaryConstructorParameters(), trace);
    }

    @NotNull
    public PropertyDescriptor resolvePrimaryConstructorParameterToAProperty(
            @NotNull ClassDescriptor classDescriptor,
            @NotNull ValueParameterDescriptor valueParameter,
            @NotNull JetScope scope,
            @NotNull JetParameter parameter, BindingTrace trace
    ) {
        JetType type = resolveParameterType(scope, parameter, trace);
        Name name = parameter.getNameAsSafeName();
        boolean isMutable = parameter.isMutable();
        JetModifierList modifierList = parameter.getModifierList();

        if (modifierList != null) {
            ASTNode abstractNode = modifierList.getModifierNode(JetTokens.ABSTRACT_KEYWORD);
            if (abstractNode != null) {
                trace.report(ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS.on(parameter));
            }
        }

        PropertyDescriptorImpl propertyDescriptor = PropertyDescriptorImpl.create(
                classDescriptor,
                valueParameter.getAnnotations(),
                resolveModalityFromModifiers(parameter, Modality.FINAL),
                resolveVisibilityFromModifiers(parameter, Visibilities.INTERNAL),
                isMutable,
                name,
                CallableMemberDescriptor.Kind.DECLARATION
        );
        propertyDescriptor.setType(type, Collections.emptyList(),
                                   getExpectedThisObjectIfNeeded(classDescriptor), NO_RECEIVER_PARAMETER);

        PropertyGetterDescriptorImpl getter = DescriptorFactory.createDefaultGetter(propertyDescriptor);
        PropertySetterDescriptor setter =
                propertyDescriptor.isVar() ? DescriptorFactory.createDefaultSetter(propertyDescriptor) : null;

        propertyDescriptor.initialize(getter, setter);
        getter.initialize(propertyDescriptor.getType());

        trace.record(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter, propertyDescriptor);
        trace.record(BindingContext.VALUE_PARAMETER_AS_PROPERTY, valueParameter, propertyDescriptor);
        return propertyDescriptor;
    }

    public static void checkBounds(@NotNull JetTypeReference typeReference, @NotNull JetType type, BindingTrace trace) {
        if (type.isError()) return;

        JetTypeElement typeElement = typeReference.getTypeElement();
        if (typeElement == null) return;

        List parameters = type.getConstructor().getParameters();
        List arguments = type.getArguments();
        assert parameters.size() == arguments.size();

        List jetTypeArguments = typeElement.getTypeArgumentsAsTypes();
        assert jetTypeArguments.size() == arguments.size() : typeElement.getText();

        TypeSubstitutor substitutor = TypeSubstitutor.create(type);
        for (int i = 0; i < jetTypeArguments.size(); i++) {
            JetTypeReference jetTypeArgument = jetTypeArguments.get(i);

            if (jetTypeArgument == null) continue;

            JetType typeArgument = arguments.get(i).getType();
            checkBounds(jetTypeArgument, typeArgument, trace);

            TypeParameterDescriptor typeParameterDescriptor = parameters.get(i);
            checkBounds(jetTypeArgument, typeArgument, typeParameterDescriptor, substitutor, trace);
        }
    }

    public static void checkBounds(
            @NotNull JetTypeReference jetTypeArgument,
            @NotNull JetType typeArgument,
            @NotNull TypeParameterDescriptor typeParameterDescriptor,
            @NotNull TypeSubstitutor substitutor, BindingTrace trace
    ) {
        for (JetType bound : typeParameterDescriptor.getUpperBounds()) {
            JetType substitutedBound = substitutor.safeSubstitute(bound, Variance.INVARIANT);
            if (!JetTypeChecker.INSTANCE.isSubtypeOf(typeArgument, substitutedBound)) {
                trace.report(UPPER_BOUND_VIOLATED.on(jetTypeArgument, substitutedBound, typeArgument));
            }
        }
    }

    @NotNull
    public static SimpleFunctionDescriptor createEnumClassObjectValuesMethod(
            @NotNull ClassDescriptor classObject,
            @NotNull BindingTrace trace
    ) {
        final ClassDescriptor enumClassDescriptor = (ClassDescriptor) classObject.getContainingDeclaration();
        assert DescriptorUtils.isEnumClass(enumClassDescriptor) : "values should be created in enum class: " + enumClassDescriptor;
        return DescriptorFactory
                .createEnumClassObjectValuesMethod(classObject, DeferredType.create(NO_LOCKS, trace, new Function0() {
                    @Override
                    public JetType invoke() {
                        return KotlinBuiltIns.getInstance().getArrayType(enumClassDescriptor.getDefaultType());
                    }
                }));
    }


    @NotNull
    public static SimpleFunctionDescriptor createEnumClassObjectValueOfMethod(
            @NotNull ClassDescriptor classObject,
            @NotNull BindingTrace trace
    ) {
        final ClassDescriptor enumClassDescriptor = (ClassDescriptor) classObject.getContainingDeclaration();
        assert DescriptorUtils.isEnumClass(enumClassDescriptor) : "valueOf should be created in enum class: " + enumClassDescriptor;
        return DescriptorFactory
                .createEnumClassObjectValueOfMethod(classObject, DeferredType.create(NO_LOCKS, trace, new Function0() {
                    @Override
                    public JetType invoke() {
                        return enumClassDescriptor.getDefaultType();
                    }
                }));
    }

    public static boolean checkHasOuterClassInstance(
            @NotNull JetScope scope,
            @NotNull BindingTrace trace,
            @NotNull PsiElement reportErrorsOn,
            @NotNull ClassDescriptor target
    ) {
        ClassDescriptor classDescriptor = getContainingClass(scope);

        if (!isInsideOuterClassOrItsSubclass(classDescriptor, target)) {
            return true;
        }

        while (classDescriptor != null) {
            if (isSubclass(classDescriptor, target)) {
                return true;
            }

            if (isStaticNestedClass(classDescriptor)) {
                trace.report(INACCESSIBLE_OUTER_CLASS_EXPRESSION.on(reportErrorsOn, classDescriptor));
                return false;
            }
            classDescriptor = getParentOfType(classDescriptor, ClassDescriptor.class, true);
        }
        return true;
    }

    public static void checkParameterHasNoValOrVar(
            @NotNull BindingTrace trace,
            @NotNull JetParameter parameter,
            @NotNull DiagnosticFactory1 diagnosticFactory
    ) {
        ASTNode valOrVarNode = parameter.getValOrVarNode();
        if (valOrVarNode != null) {
            trace.report(diagnosticFactory.on(valOrVarNode.getPsi(), ((JetKeywordToken) valOrVarNode.getElementType())));
        }
    }

    private static void checkConstructorParameterHasNoModifier(
            @NotNull BindingTrace trace,
            @NotNull JetParameter parameter
    ) {
        // If is not a property, then it must have no modifier
        if (parameter.getValOrVarNode() == null) {
            checkParameterHasNoModifier(trace, parameter);
        }
    }

    public static void checkParameterHasNoModifier(
            @NotNull BindingTrace trace,
            @NotNull JetParameter parameter
    ) {
        JetModifierList modifiers = parameter.getModifierList();
        if (modifiers != null) {
            ASTNode node = modifiers.getNode().getFirstChildNode();

            while (node != null) {
                IElementType elementType = node.getElementType();

                if (elementType != JetTokens.VARARG_KEYWORD && elementType instanceof JetModifierKeywordToken) {
                    trace.report(ILLEGAL_MODIFIER.on(node.getPsi(), (JetModifierKeywordToken) elementType));
                }
                node = node.getTreeNext();
            }
        }
    }

    public static void resolvePackageHeader(
            @NotNull JetPackageDirective packageDirective,
            @NotNull ModuleDescriptor module,
            @NotNull BindingTrace trace
    ) {
        for (JetSimpleNameExpression nameExpression : packageDirective.getPackageNames()) {
            FqName fqName = packageDirective.getFqName(nameExpression);

            PackageViewDescriptor packageView = module.getPackage(fqName);
            assert packageView != null : "package not found: " + fqName;
            trace.record(REFERENCE_TARGET, nameExpression, packageView);

            PackageViewDescriptor parentPackageView = packageView.getContainingDeclaration();
            assert parentPackageView != null : "package has no parent: " + packageView;
            trace.record(RESOLUTION_SCOPE, nameExpression, parentPackageView.getMemberScope());
        }
    }

    public static void registerFileInPackage(@NotNull BindingTrace trace, @NotNull JetFile file) {
        // Register files corresponding to this package
        // The trace currently does not support bi-di multimaps that would handle this task nicer
        FqName fqName = file.getPackageFqName();
        Collection files = trace.get(PACKAGE_TO_FILES, fqName);
        if (files == null) {
            files = Sets.newIdentityHashSet();
        }
        files.add(file);
        trace.record(BindingContext.PACKAGE_TO_FILES, fqName, files);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy