Exemple #1
0
  public static void genClassOrObject(
      @NotNull CodegenContext parentContext,
      @NotNull JetClassOrObject aClass,
      @NotNull GenerationState state,
      @Nullable MemberCodegen<?> parentCodegen) {
    ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);

    if (descriptor == null || ErrorUtils.isError(descriptor)) {
      badDescriptor(descriptor, state.getClassBuilderMode());
      return;
    }

    if (descriptor.getName().equals(SpecialNames.NO_NAME_PROVIDED)) {
      badDescriptor(descriptor, state.getClassBuilderMode());
    }

    ClassBuilder classBuilder =
        state.getFactory().forClassImplementation(descriptor, aClass.getContainingFile());
    ClassContext classContext =
        parentContext.intoClass(descriptor, OwnerKind.IMPLEMENTATION, state);
    new ImplementationBodyCodegen(aClass, classContext, classBuilder, state, parentCodegen)
        .generate();

    if (aClass instanceof JetClass && ((JetClass) aClass).isTrait()) {
      ClassBuilder traitImplBuilder =
          state.getFactory().forTraitImplementation(descriptor, state, aClass.getContainingFile());
      ClassContext traitImplContext =
          parentContext.intoClass(descriptor, OwnerKind.TRAIT_IMPL, state);
      new TraitImplBodyCodegen(aClass, traitImplContext, traitImplBuilder, state, parentCodegen)
          .generate();
    }
  }
 @Override
 public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
   JetType type = QuickFixUtil.getDeclarationReturnType(element);
   return super.isAvailable(project, editor, file)
       && type != null
       && !ErrorUtils.isErrorType(type);
 }
  @NotNull
  private JetType modifyTypeAccordingToSuperMethods(
      @NotNull JetType autoType,
      @NotNull List<TypeAndVariance> typesFromSuper,
      @NotNull TypeUsage howThisTypeIsUsed) {
    if (ErrorUtils.isErrorType(autoType)) {
      return autoType;
    }

    boolean resultNullable = typeMustBeNullable(autoType, typesFromSuper, howThisTypeIsUsed);
    ClassifierDescriptor resultClassifier = modifyTypeClassifier(autoType, typesFromSuper);
    List<TypeProjection> resultArguments =
        getTypeArgsOfType(autoType, resultClassifier, typesFromSuper);
    JetScope resultScope;
    if (resultClassifier instanceof ClassDescriptor) {
      resultScope = ((ClassDescriptor) resultClassifier).getMemberScope(resultArguments);
    } else {
      resultScope = autoType.getMemberScope();
    }

    JetTypeImpl type =
        new JetTypeImpl(
            autoType.getAnnotations(),
            resultClassifier.getTypeConstructor(),
            resultNullable,
            resultArguments,
            resultScope);

    PropagationHeuristics.checkArrayInReturnType(this, type, typesFromSuper);
    return type;
  }
  @NotNull
  public TypeInfoForCall getQualifiedExpressionExtendedTypeInfo(
      @NotNull JetQualifiedExpression expression,
      @NotNull ResolutionContext context,
      @NotNull ResolveMode resolveMode) {
    // TODO : functions as values
    JetExpression selectorExpression = expression.getSelectorExpression();
    JetExpression receiverExpression = expression.getReceiverExpression();
    JetTypeInfo receiverTypeInfo =
        expressionTypingServices.getTypeInfoWithNamespaces(
            receiverExpression,
            context.scope,
            NO_EXPECTED_TYPE,
            context.dataFlowInfo,
            context.trace);
    JetType receiverType = receiverTypeInfo.getType();
    if (selectorExpression == null) return TypeInfoForCall.create(null, context.dataFlowInfo);
    if (receiverType == null)
      receiverType = ErrorUtils.createErrorType("Type for " + expression.getText());

    context = context.replaceDataFlowInfo(receiverTypeInfo.getDataFlowInfo());

    if (selectorExpression instanceof JetSimpleNameExpression) {
      ConstantUtils.propagateConstantValues(
          expression, context.trace, (JetSimpleNameExpression) selectorExpression);
    }

    TypeInfoForCall selectorReturnTypeInfo =
        getSelectorReturnTypeInfo(
            new ExpressionReceiver(receiverExpression, receiverType),
            expression.getOperationTokenNode(),
            selectorExpression,
            context,
            resolveMode);
    JetType selectorReturnType = selectorReturnTypeInfo.getType();

    // TODO move further
    if (!(receiverType instanceof NamespaceType)
        && expression.getOperationSign() == JetTokens.SAFE_ACCESS) {
      if (selectorReturnType != null
          && !selectorReturnType.isNullable()
          && !KotlinBuiltIns.getInstance().isUnit(selectorReturnType)) {
        if (receiverType.isNullable()) {
          selectorReturnType = TypeUtils.makeNullable(selectorReturnType);
        }
      }
    }

    // TODO : this is suspicious: remove this code?
    if (selectorReturnType != null) {
      context.trace.record(BindingContext.EXPRESSION_TYPE, selectorExpression, selectorReturnType);
    }
    JetTypeInfo typeInfo =
        JetTypeInfo.create(selectorReturnType, selectorReturnTypeInfo.getDataFlowInfo());
    if (resolveMode == ResolveMode.TOP_LEVEL_CALL) {
      DataFlowUtils.checkType(typeInfo.getType(), expression, context, typeInfo.getDataFlowInfo());
    }
    return TypeInfoForCall.create(typeInfo, selectorReturnTypeInfo);
  }
 public ErrorSimpleFunctionDescriptorImpl(ErrorUtils.ErrorScope ownerScope) {
   super(
       ErrorUtils.getErrorClass(),
       Annotations.EMPTY,
       Name.special("<ERROR FUNCTION>"),
       Kind.DECLARATION);
   this.ownerScope = ownerScope;
 }
 private void reportIncompleteHierarchyForErrorTypes(
     ClassDescriptor classDescriptor, List<JetType> result) {
   for (JetType supertype : result) {
     if (ErrorUtils.isErrorType(supertype)) {
       trace.record(BindingContext.INCOMPLETE_HIERARCHY, classDescriptor);
     }
   }
 }
  private List<ValueParameterDescriptor> createValueParameterDescriptors(
      ExpressionTypingContext context,
      JetFunctionLiteral functionLiteral,
      FunctionDescriptorImpl functionDescriptor,
      boolean functionTypeExpected) {
    List<ValueParameterDescriptor> valueParameterDescriptors = Lists.newArrayList();
    List<JetParameter> declaredValueParameters = functionLiteral.getValueParameters();

    List<ValueParameterDescriptor> expectedValueParameters =
        (functionTypeExpected)
            ? JetStandardClasses.getValueParameters(functionDescriptor, context.expectedType)
            : null;

    boolean hasDeclaredValueParameters = functionLiteral.getValueParameterList() != null;
    if (functionTypeExpected
        && !hasDeclaredValueParameters
        && expectedValueParameters.size() == 1) {
      ValueParameterDescriptor valueParameterDescriptor = expectedValueParameters.get(0);
      ValueParameterDescriptor it =
          new ValueParameterDescriptorImpl(
              functionDescriptor,
              0,
              Collections.<AnnotationDescriptor>emptyList(),
              "it",
              false,
              valueParameterDescriptor.getOutType(),
              valueParameterDescriptor.hasDefaultValue(),
              valueParameterDescriptor.getVarargElementType());
      valueParameterDescriptors.add(it);
      context.trace.record(AUTO_CREATED_IT, it);
    } else {
      for (int i = 0; i < declaredValueParameters.size(); i++) {
        JetParameter declaredParameter = declaredValueParameters.get(i);
        JetTypeReference typeReference = declaredParameter.getTypeReference();

        JetType type;
        if (typeReference != null) {
          type = context.getTypeResolver().resolveType(context.scope, typeReference);
        } else {
          if (expectedValueParameters != null && i < expectedValueParameters.size()) {
            type = expectedValueParameters.get(i).getOutType();
          } else {
            context.trace.report(CANNOT_INFER_PARAMETER_TYPE.on(declaredParameter));
            type = ErrorUtils.createErrorType("Cannot be inferred");
          }
        }
        ValueParameterDescriptor valueParameterDescriptor =
            context
                .getDescriptorResolver()
                .resolveValueParameterDescriptor(functionDescriptor, declaredParameter, i, type);
        valueParameterDescriptors.add(valueParameterDescriptor);
      }
    }
    return valueParameterDescriptors;
  }
 private String renderType(JetType type, boolean shortNamesOnly) {
   if (type == null) {
     return escape("[NULL]");
   } else if (ErrorUtils.isErrorType(type)) {
     return escape(type.toString());
   } else if (JetStandardClasses.isUnit(type)) {
     return escape(JetStandardClasses.UNIT_ALIAS + (type.isNullable() ? "?" : ""));
   } else if (JetStandardClasses.isTupleType(type)) {
     return escape(renderTupleType(type, shortNamesOnly));
   } else if (JetStandardClasses.isFunctionType(type)) {
     return escape(renderFunctionType(type, shortNamesOnly));
   } else {
     return escape(renderDefaultType(type, shortNamesOnly));
   }
 }
 private boolean furtherNameLookup(
     @NotNull JetSimpleNameExpression expression,
     @NotNull JetType[] result,
     @NotNull ResolutionContext context) {
   NamespaceType namespaceType = lookupNamespaceType(expression, context);
   if (namespaceType == null) {
     return false;
   }
   if (context.expressionPosition == ExpressionPosition.LHS_OF_DOT) {
     result[0] = namespaceType;
     return true;
   }
   context.trace.report(EXPRESSION_EXPECTED_NAMESPACE_FOUND.on(expression));
   result[0] = ErrorUtils.createErrorType("Type for " + expression.getReferencedNameAsName());
   return false;
 }
Exemple #10
0
 /**
  * Add import directive corresponding to a type to file when it is needed.
  *
  * @param type type to import
  * @param file file where import directive should be added
  */
 public static void addImportDirectivesIfNeeded(@NotNull JetType type, @NotNull JetFile file) {
   if (JetPluginUtil.checkTypeIsStandard(type, file.getProject())
       || ErrorUtils.isErrorType(type)) {
     return;
   }
   BindingContext bindingContext = getContextForSingleFile(file);
   PsiElement element =
       BindingContextUtils.descriptorToDeclaration(
           bindingContext, type.getMemberScope().getContainingDeclaration());
   if (element != null
       && element.getContainingFile()
           == file) { // declaration is in the same file, so no import is needed
     return;
   }
   for (ClassDescriptor clazz : TypeUtils.getAllClassDescriptors(type)) {
     addImportDirective(DescriptorUtils.getFQName(getTopLevelClass(clazz)).toSafe(), file);
   }
 }
  @Override
  public void visitClassType(String name, boolean nullable, boolean forceReal) {
    FqName ourName =
        new FqName(
            name.replace('/', '.').replace('$', '.') // TODO: not sure
            );

    this.classDescriptor = null;
    if (!forceReal) {
      classDescriptor =
          javaSemanticServices
              .getTypeTransformer()
              .getKotlinAnalog(ourName, JavaTypeTransformer.TypeUsage.MEMBER_SIGNATURE_INVARIANT);
    }

    if (classDescriptor == null) {
      // TODO: this is the worst code in Kotlin project
      Matcher matcher = Pattern.compile("jet\\.Function(\\d+)").matcher(ourName.getFqName());
      if (matcher.matches()) {
        classDescriptor = JetStandardClasses.getFunction(Integer.parseInt(matcher.group(1)));
      }
    }

    if (classDescriptor == null) {
      Matcher matcher = Pattern.compile("jet\\.Tuple(\\d+)").matcher(ourName.getFqName());
      if (matcher.matches()) {
        classDescriptor = JetStandardClasses.getTuple(Integer.parseInt(matcher.group(1)));
      }
    }

    if (this.classDescriptor == null) {
      this.classDescriptor =
          javaDescriptorResolver.resolveClass(ourName, DescriptorSearchRule.INCLUDE_KOTLIN);
    }

    if (this.classDescriptor == null) {
      // TODO: report in to trace
      this.errorType = ErrorUtils.createErrorType("class not found by name: " + ourName);
    }
    this.nullable = nullable;
    this.typeArguments = new ArrayList<TypeProjection>();
  }
  @NotNull
  private String renderClassName(@NotNull ClassDescriptor klass) {
    if (ErrorUtils.isError(klass)) {
      return klass.getTypeConstructor().toString();
    }
    if (shortNames) {
      List<Name> qualifiedNameElements = Lists.newArrayList();

      // for nested classes qualified name should be used
      DeclarationDescriptor current = klass;
      do {
        if (((ClassDescriptor) current).getKind() != ClassKind.CLASS_OBJECT) {
          qualifiedNameElements.add(current.getName());
        }
        current = current.getContainingDeclaration();
      } while (current instanceof ClassDescriptor);

      Collections.reverse(qualifiedNameElements);
      return renderFqName(qualifiedNameElements);
    }
    return renderFqName(DescriptorUtils.getFQName(klass));
  }
  private void transformSupertypeList(
      List<JetType> result,
      PsiClassType[] extendsListTypes,
      TypeVariableResolver typeVariableResolver) {
    for (PsiClassType type : extendsListTypes) {
      PsiClass resolved = type.resolve();
      if (resolved != null) {
        String qualifiedName = resolved.getQualifiedName();
        assert qualifiedName != null;
        if (JvmStdlibNames.JET_OBJECT.getFqName().equalsTo(qualifiedName)) {
          continue;
        }
      }

      JetType transform =
          typeTransformer.transformToType(type, TypeUsage.SUPERTYPE, typeVariableResolver);
      if (ErrorUtils.isErrorType(transform)) {
        continue;
      }

      result.add(TypeUtils.makeNotNullable(transform));
    }
  }
 @Override
 public boolean apply(JetType type) {
   return !ErrorUtils.isErrorType(type) && (TypeUtils.getClassDescriptor(type) != null);
 }
  @NotNull
  public TypeInfoForCall getCallExpressionTypeInfoForCallWithoutFinalTypeCheck(
      @NotNull JetCallExpression callExpression,
      @NotNull ReceiverValue receiver,
      @Nullable ASTNode callOperationNode,
      @NotNull ResolutionContext context,
      @NotNull ResolveMode resolveMode) {
    boolean[] result = new boolean[1];
    Call call = CallMaker.makeCall(receiver, callOperationNode, callExpression);

    TemporaryBindingTrace traceForFunction =
        TemporaryBindingTrace.create(
            context.trace, "trace to resolve as function call", callExpression);
    ResolvedCall<FunctionDescriptor> resolvedCall =
        getResolvedCallForFunction(
            call,
            callExpression,
            receiver,
            context.replaceBindingTrace(traceForFunction),
            resolveMode,
            result);
    if (result[0]) {
      FunctionDescriptor functionDescriptor =
          resolvedCall != null ? resolvedCall.getResultingDescriptor() : null;
      traceForFunction.commit();
      if (callExpression.getValueArgumentList() == null
          && callExpression.getFunctionLiteralArguments().isEmpty()) {
        // there are only type arguments
        boolean hasValueParameters =
            functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
        context.trace.report(
            FUNCTION_CALL_EXPECTED.on(callExpression, callExpression, hasValueParameters));
      }
      if (functionDescriptor == null) {
        return TypeInfoForCall.create(null, context.dataFlowInfo);
      }
      JetType type = functionDescriptor.getReturnType();

      return TypeInfoForCall.create(
          type, resolvedCall.getDataFlowInfo(), resolvedCall, call, context, resolveMode);
    }

    JetExpression calleeExpression = callExpression.getCalleeExpression();
    if (calleeExpression instanceof JetSimpleNameExpression
        && callExpression.getTypeArgumentList() == null) {
      TemporaryBindingTrace traceForVariable =
          TemporaryBindingTrace.create(
              context.trace, "trace to resolve as variable with 'invoke' call", callExpression);
      JetType type =
          getVariableType(
              (JetSimpleNameExpression) calleeExpression,
              receiver,
              callOperationNode,
              context.replaceBindingTrace(traceForVariable),
              result);
      if (result[0]) {
        traceForVariable.commit();
        context.trace.report(
            FUNCTION_EXPECTED.on(
                (JetReferenceExpression) calleeExpression,
                calleeExpression,
                type != null ? type : ErrorUtils.createErrorType("")));
        return TypeInfoForCall.create(null, context.dataFlowInfo);
      }
    }
    traceForFunction.commit();
    return TypeInfoForCall.create(null, context.dataFlowInfo);
  }
  @Override
  public JetType visitFunctionLiteralExpression(
      JetFunctionLiteralExpression expression, ExpressionTypingContext context) {
    JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
    JetBlockExpression bodyExpression = functionLiteral.getBodyExpression();
    if (bodyExpression == null) return null;

    JetType expectedType = context.expectedType;
    boolean functionTypeExpected =
        expectedType != TypeUtils.NO_EXPECTED_TYPE
            && JetStandardClasses.isFunctionType(expectedType);

    NamedFunctionDescriptorImpl functionDescriptor =
        createFunctionDescriptor(expression, context, functionTypeExpected);

    List<JetType> parameterTypes = Lists.newArrayList();
    List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters();
    for (ValueParameterDescriptor valueParameter : valueParameters) {
      parameterTypes.add(valueParameter.getOutType());
    }
    ReceiverDescriptor receiverParameter = functionDescriptor.getReceiverParameter();
    JetType receiver = receiverParameter != NO_RECEIVER ? receiverParameter.getType() : null;

    JetType returnType = TypeUtils.NO_EXPECTED_TYPE;
    JetScope functionInnerScope =
        FunctionDescriptorUtil.getFunctionInnerScope(
            context.scope, functionDescriptor, context.trace);
    JetTypeReference returnTypeRef = functionLiteral.getReturnTypeRef();
    if (returnTypeRef != null) {
      returnType = context.getTypeResolver().resolveType(context.scope, returnTypeRef);
      context
          .getServices()
          .checkFunctionReturnType(
              expression,
              context
                  .replaceScope(functionInnerScope)
                  .replaceExpectedType(returnType)
                  .replaceExpectedReturnType(returnType)
                  .replaceDataFlowInfo(context.dataFlowInfo));
    } else {
      if (functionTypeExpected) {
        returnType = JetStandardClasses.getReturnTypeFromFunctionType(expectedType);
      }
      returnType =
          context
              .getServices()
              .getBlockReturnedType(
                  functionInnerScope,
                  bodyExpression,
                  CoercionStrategy.COERCION_TO_UNIT,
                  context.replaceExpectedType(returnType).replaceExpectedReturnType(returnType));
    }
    JetType safeReturnType =
        returnType == null ? ErrorUtils.createErrorType("<return type>") : returnType;
    functionDescriptor.setReturnType(safeReturnType);

    boolean hasDeclaredValueParameters = functionLiteral.getValueParameterList() != null;
    if (!hasDeclaredValueParameters && functionTypeExpected) {
      JetType expectedReturnType = JetStandardClasses.getReturnTypeFromFunctionType(expectedType);
      if (JetStandardClasses.isUnit(expectedReturnType)) {
        functionDescriptor.setReturnType(JetStandardClasses.getUnitType());
        return DataFlowUtils.checkType(
            JetStandardClasses.getFunctionType(
                Collections.<AnnotationDescriptor>emptyList(),
                receiver,
                parameterTypes,
                JetStandardClasses.getUnitType()),
            expression,
            context);
      }
    }
    return DataFlowUtils.checkType(
        JetStandardClasses.getFunctionType(
            Collections.<AnnotationDescriptor>emptyList(),
            receiver,
            parameterTypes,
            safeReturnType),
        expression,
        context);
  }
Exemple #17
0
 @Override
 public JetType invoke(Boolean firstTime) {
   if (firstTime) throw new ReenteringLazyValueComputationException();
   return ErrorUtils.createErrorType("Recursive dependency");
 }
Exemple #18
0
 private static void addNamesForType(
     ArrayList<String> result, JetType jetType, JetNameValidator validator) {
   JetStandardLibrary standardLibrary = JetStandardLibrary.getInstance();
   JetTypeChecker typeChecker = JetTypeChecker.INSTANCE;
   if (ErrorUtils.containsErrorType(jetType)) return;
   if (typeChecker.equalTypes(standardLibrary.getBooleanType(), jetType)) {
     addName(result, "b", validator);
   } else if (typeChecker.equalTypes(standardLibrary.getIntType(), jetType)) {
     addName(result, "i", validator);
   } else if (typeChecker.equalTypes(standardLibrary.getByteType(), jetType)) {
     addName(result, "byte", validator);
   } else if (typeChecker.equalTypes(standardLibrary.getLongType(), jetType)) {
     addName(result, "l", validator);
   } else if (typeChecker.equalTypes(standardLibrary.getFloatType(), jetType)) {
     addName(result, "fl", validator);
   } else if (typeChecker.equalTypes(standardLibrary.getDoubleType(), jetType)) {
     addName(result, "d", validator);
   } else if (typeChecker.equalTypes(standardLibrary.getShortType(), jetType)) {
     addName(result, "sh", validator);
   } else if (typeChecker.equalTypes(standardLibrary.getCharType(), jetType)) {
     addName(result, "c", validator);
   } else if (typeChecker.equalTypes(standardLibrary.getStringType(), jetType)) {
     addName(result, "s", validator);
   } else {
     if (jetType.getArguments().size() == 1) {
       JetType argument = jetType.getArguments().get(0).getType();
       if (typeChecker.equalTypes(standardLibrary.getArrayType(argument), jetType)) {
         if (typeChecker.equalTypes(standardLibrary.getBooleanType(), argument)) {
           addName(result, "booleans", validator);
         } else if (typeChecker.equalTypes(standardLibrary.getIntType(), argument)) {
           addName(result, "ints", validator);
         } else if (typeChecker.equalTypes(standardLibrary.getByteType(), argument)) {
           addName(result, "bytes", validator);
         } else if (typeChecker.equalTypes(standardLibrary.getLongType(), argument)) {
           addName(result, "longs", validator);
         } else if (typeChecker.equalTypes(standardLibrary.getFloatType(), argument)) {
           addName(result, "floats", validator);
         } else if (typeChecker.equalTypes(standardLibrary.getDoubleType(), argument)) {
           addName(result, "doubles", validator);
         } else if (typeChecker.equalTypes(standardLibrary.getShortType(), argument)) {
           addName(result, "shorts", validator);
         } else if (typeChecker.equalTypes(standardLibrary.getCharType(), argument)) {
           addName(result, "chars", validator);
         } else if (typeChecker.equalTypes(standardLibrary.getStringType(), argument)) {
           addName(result, "strings", validator);
         } else {
           ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(argument);
           if (classDescriptor != null) {
             Name className = classDescriptor.getName();
             addName(
                 result, "arrayOf" + StringUtil.capitalize(className.getName()) + "s", validator);
           }
         }
       } else {
         addForClassType(result, jetType, validator);
       }
     } else {
       addForClassType(result, jetType, validator);
     }
   }
 }
  private void addConstraint(
      @NotNull ConstraintKind constraintKind,
      @NotNull JetType subjectType,
      @Nullable JetType constrainingType,
      @NotNull ConstraintPosition constraintPosition) {

    if (constrainingType == TypeUtils.NO_EXPECTED_TYPE
        || constrainingType == DONT_CARE
        || constrainingType == CANT_INFER) {
      return;
    }

    if (constrainingType == null
        || (ErrorUtils.isErrorType(constrainingType)
            && constrainingType != PLACEHOLDER_FUNCTION_TYPE)) {
      hasErrorInConstrainingTypes = true;
      return;
    }

    assert subjectType != TypeUtils.NO_EXPECTED_TYPE
        : "Subject type shouldn't be NO_EXPECTED_TYPE (in position " + constraintPosition + " )";
    if (ErrorUtils.isErrorType(subjectType)) return;

    DeclarationDescriptor subjectTypeDescriptor =
        subjectType.getConstructor().getDeclarationDescriptor();

    KotlinBuiltIns kotlinBuiltIns = KotlinBuiltIns.getInstance();
    if (constrainingType == PLACEHOLDER_FUNCTION_TYPE) {
      if (!kotlinBuiltIns.isFunctionOrExtensionFunctionType(subjectType)) {
        if (subjectTypeDescriptor instanceof TypeParameterDescriptor
            && typeParameterConstraints.get(subjectTypeDescriptor) != null) {
          // a constraint binds type parameter and any function type, so there is no new info and no
          // error
          return;
        }
        errorConstraintPositions.add(constraintPosition);
      }
      return;
    }

    // todo temporary hack
    // function literal without declaring receiver type { x -> ... }
    // can be considered as extension function if one is expected
    // (special type constructor for function/ extension function should be introduced like
    // PLACEHOLDER_FUNCTION_TYPE)
    if (constraintKind == SUB_TYPE
        && kotlinBuiltIns.isFunctionType(constrainingType)
        && kotlinBuiltIns.isExtensionFunctionType(subjectType)) {
      constrainingType = createCorrespondingExtensionFunctionType(constrainingType, DONT_CARE);
    }

    DeclarationDescriptor constrainingTypeDescriptor =
        constrainingType.getConstructor().getDeclarationDescriptor();

    if (subjectTypeDescriptor instanceof TypeParameterDescriptor) {
      TypeParameterDescriptor typeParameter = (TypeParameterDescriptor) subjectTypeDescriptor;
      TypeConstraintsImpl typeConstraints = typeParameterConstraints.get(typeParameter);
      if (typeConstraints != null) {
        if (TypeUtils.dependsOnTypeParameterConstructors(
            constrainingType, Collections.singleton(DONT_CARE.getConstructor()))) {
          return;
        }
        if (subjectType.isNullable() && constrainingType.isNullable()) {
          constrainingType = TypeUtils.makeNotNullable(constrainingType);
        }
        typeConstraints.addBound(constraintKind, constrainingType);
        return;
      }
    }
    if (constrainingTypeDescriptor instanceof TypeParameterDescriptor) {
      assert typeParameterConstraints.get(constrainingTypeDescriptor) == null
          : "Constraining type contains type variable " + constrainingTypeDescriptor.getName();
    }
    if (constraintKind == SUB_TYPE && kotlinBuiltIns.isNothingOrNullableNothing(constrainingType)) {
      // following constraints are always true:
      // 'Nothing' is a subtype of any type
      if (!constrainingType.isNullable()) return;
      // 'Nothing?' is a subtype of nullable type
      if (subjectType.isNullable()) return;
    }
    if (!(constrainingTypeDescriptor instanceof ClassDescriptor)
        || !(subjectTypeDescriptor instanceof ClassDescriptor)) {
      errorConstraintPositions.add(constraintPosition);
      return;
    }
    switch (constraintKind) {
      case SUB_TYPE:
        {
          if (kotlinBuiltIns.isNothingOrNullableNothing(constrainingType)) break;
          JetType correspondingSupertype =
              TypeCheckingProcedure.findCorrespondingSupertype(constrainingType, subjectType);
          if (correspondingSupertype != null) {
            constrainingType = correspondingSupertype;
          }
          break;
        }
      case SUPER_TYPE:
        {
          if (kotlinBuiltIns.isNothingOrNullableNothing(subjectType)) break;
          JetType correspondingSupertype =
              TypeCheckingProcedure.findCorrespondingSupertype(subjectType, constrainingType);
          if (correspondingSupertype != null) {
            subjectType = correspondingSupertype;
          }
        }
      case EQUAL: // nothing
    }
    if (constrainingType.getConstructor() != subjectType.getConstructor()) {
      errorConstraintPositions.add(constraintPosition);
      return;
    }
    TypeConstructor typeConstructor = subjectType.getConstructor();
    List<TypeProjection> subjectArguments = subjectType.getArguments();
    List<TypeProjection> constrainingArguments = constrainingType.getArguments();
    List<TypeParameterDescriptor> parameters = typeConstructor.getParameters();
    for (int i = 0; i < subjectArguments.size(); i++) {
      Variance typeParameterVariance = parameters.get(i).getVariance();
      TypeProjection subjectArgument = subjectArguments.get(i);
      TypeProjection constrainingArgument = constrainingArguments.get(i);

      ConstraintKind typeParameterConstraintKind =
          getTypeParameterConstraintKind(
              typeParameterVariance, subjectArgument, constrainingArgument, constraintKind);

      addConstraint(
          typeParameterConstraintKind,
          subjectArgument.getType(),
          constrainingArgument.getType(),
          constraintPosition);
    }
  }