Beispiel #1
0
  /**
   * Two types are related, roughly, when one is a subtype or supertype of the other.
   *
   * <p>Note that some types have platform-specific counterparts, i.e. jet.String is mapped to
   * java.lang.String, such types (and all their sub- and supertypes) are related too.
   *
   * <p>Due to limitations in PlatformToKotlinClassMap, we only consider mapping of platform classes
   * to Kotlin classed (i.e. java.lang.String -> jet.String) and ignore mappings that go the other
   * way.
   */
  private static boolean isRelated(
      @NotNull JetType a,
      @NotNull JetType b,
      @NotNull PlatformToKotlinClassMap platformToKotlinClassMap) {
    List<JetType> aTypes = mapToPlatformIndependentTypes(a, platformToKotlinClassMap);
    List<JetType> bTypes = mapToPlatformIndependentTypes(b, platformToKotlinClassMap);

    for (JetType aType : aTypes) {
      for (JetType bType : bTypes) {
        if (JetTypeChecker.INSTANCE.isSubtypeOf(aType, bType)) return true;
        if (JetTypeChecker.INSTANCE.isSubtypeOf(bType, aType)) return true;
      }
    }

    return false;
  }
Beispiel #2
0
 private void assertSubtypingRelation(String subtype, String supertype, boolean expected) {
   JetType typeNode1 = makeType(subtype);
   JetType typeNode2 = makeType(supertype);
   boolean result = JetTypeChecker.INSTANCE.isSubtypeOf(typeNode1, typeNode2);
   String modifier = expected ? "not " : "";
   assertTrue(typeNode1 + " is " + modifier + "a subtype of " + typeNode2, result == expected);
 }
  @Nullable
  private static JetType computeUnsafeReturnType(
      @NotNull JetFunctionLiteralExpression expression,
      @NotNull ExpressionTypingContext context,
      @NotNull SimpleFunctionDescriptorImpl functionDescriptor,
      @Nullable JetType expectedReturnType) {
    JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
    JetBlockExpression bodyExpression = functionLiteral.getBodyExpression();
    assert bodyExpression != null;

    JetScope functionInnerScope =
        FunctionDescriptorUtil.getFunctionInnerScope(
            context.scope, functionDescriptor, context.trace);
    JetTypeReference returnTypeRef = functionLiteral.getReturnTypeRef();
    JetType declaredReturnType = null;
    if (returnTypeRef != null) {
      declaredReturnType =
          context
              .expressionTypingServices
              .getTypeResolver()
              .resolveType(context.scope, returnTypeRef, context.trace, true);
      // This is needed for ControlStructureTypingVisitor#visitReturnExpression() to properly
      // type-check returned expressions
      functionDescriptor.setReturnType(declaredReturnType);
      if (expectedReturnType != null) {
        if (!JetTypeChecker.INSTANCE.isSubtypeOf(declaredReturnType, expectedReturnType)) {
          context.trace.report(EXPECTED_RETURN_TYPE_MISMATCH.on(returnTypeRef, expectedReturnType));
        }
      }
    }

    // Type-check the body
    ExpressionTypingContext newContext =
        context
            .replaceScope(functionInnerScope)
            .replaceExpectedType(
                declaredReturnType != null
                    ? declaredReturnType
                    : (expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE));

    JetType typeOfBodyExpression =
        context
            .expressionTypingServices
            .getBlockReturnedType(bodyExpression, COERCION_TO_UNIT, newContext)
            .getType();

    List<JetType> returnedExpressionTypes =
        Lists.newArrayList(
            getTypesOfLocallyReturnedExpressions(
                functionLiteral, context.trace, collectReturns(bodyExpression)));
    ContainerUtil.addIfNotNull(returnedExpressionTypes, typeOfBodyExpression);

    if (declaredReturnType != null) return declaredReturnType;
    if (returnedExpressionTypes.isEmpty()) return null;
    return CommonSupertypes.commonSupertype(returnedExpressionTypes);
  }
  private void checkParameterAndReturnTypesForOverridingMethods(
      @NotNull List<ValueParameterDescriptor> valueParameters,
      @NotNull List<TypeParameterDescriptor> methodTypeParameters,
      @Nullable JetType returnType) {
    TypeSubstitutor substitutor =
        DescriptorResolverUtils.createSubstitutorForTypeParameters(originalToAltTypeParameters);

    for (ValueParameterDescriptor parameter : valueParameters) {
      int index = parameter.getIndex();
      ValueParameterDescriptor altParameter = altValueParameters.get(index);

      JetType substituted = substitutor.substitute(parameter.getType(), Variance.INVARIANT);
      assert substituted != null;

      if (!TypeUtils.equalTypes(substituted, altParameter.getType())) {
        throw new AlternativeSignatureMismatchException(
            "Parameter type changed for method which overrides another: "
                + altParameter.getType()
                + ", was: "
                + parameter.getType());
      }
    }

    // don't check receiver

    for (TypeParameterDescriptor parameter : methodTypeParameters) {
      int index = parameter.getIndex();

      JetType substituted =
          substitutor.substitute(parameter.getUpperBoundsAsType(), Variance.INVARIANT);
      assert substituted != null;

      if (!TypeUtils.equalTypes(substituted, altTypeParameters.get(index).getUpperBoundsAsType())) {
        throw new AlternativeSignatureMismatchException(
            "Type parameter's upper bound changed for method which overrides another: "
                + altTypeParameters.get(index).getUpperBoundsAsType()
                + ", was: "
                + parameter.getUpperBoundsAsType());
      }
    }

    if (returnType != null) {
      JetType substitutedReturnType = substitutor.substitute(returnType, Variance.INVARIANT);
      assert substitutedReturnType != null;

      if (!JetTypeChecker.INSTANCE.isSubtypeOf(altReturnType, substitutedReturnType)) {
        throw new AlternativeSignatureMismatchException(
            "Return type is changed to not subtype for method which overrides another: "
                + altReturnType
                + ", was: "
                + returnType);
      }
    }
  }
  private static boolean isArgumentTypeValid(
      BindingContext bindingContext, JetValueArgument argument, ValueParameterDescriptor param) {
    if (argument.getArgumentExpression() != null) {
      JetType paramType = getActualParameterType(param);
      JetType exprType =
          bindingContext.get(BindingContext.EXPRESSION_TYPE, argument.getArgumentExpression());
      return exprType == null || JetTypeChecker.INSTANCE.isSubtypeOf(exprType, paramType);
    }

    return false;
  }
Beispiel #6
0
 private static <D extends CallableDescriptor> boolean setImpliedThis(
     @NotNull JetScope scope, ResolutionCandidate<D> candidate) {
   ReceiverDescriptor expectedThisObject = candidate.getDescriptor().getExpectedThisObject();
   if (!expectedThisObject.exists()) return true;
   List<ReceiverDescriptor> receivers = Lists.newArrayList();
   scope.getImplicitReceiversHierarchy(receivers);
   for (ReceiverDescriptor receiver : receivers) {
     if (JetTypeChecker.INSTANCE.isSubtypeOf(receiver.getType(), expectedThisObject.getType())) {
       // TODO : Autocasts & nullability
       candidate.setThisObject(expectedThisObject);
       return true;
     }
   }
   return false;
 }
  @NotNull
  private static ValueParameterDescriptor createValueParameterDescriptor(
      @NotNull ExpressionTypingContext context,
      @NotNull FunctionDescriptorImpl functionDescriptor,
      @NotNull List<JetParameter> declaredValueParameters,
      @Nullable List<ValueParameterDescriptor> expectedValueParameters,
      int index) {
    JetParameter declaredParameter = declaredValueParameters.get(index);
    JetTypeReference typeReference = declaredParameter.getTypeReference();

    JetType expectedType;
    if (expectedValueParameters != null && index < expectedValueParameters.size()) {
      expectedType = expectedValueParameters.get(index).getType();
    } else {
      expectedType = null;
    }
    JetType type;
    if (typeReference != null) {
      type =
          context
              .expressionTypingServices
              .getTypeResolver()
              .resolveType(context.scope, typeReference, context.trace, true);
      if (expectedType != null) {
        if (!JetTypeChecker.INSTANCE.isSubtypeOf(expectedType, type)) {
          context.trace.report(
              EXPECTED_PARAMETER_TYPE_MISMATCH.on(declaredParameter, expectedType));
        }
      }
    } else {
      if (expectedType == null
          || expectedType == DONT_CARE
          || expectedType == CANT_INFER_TYPE_PARAMETER) {
        context.trace.report(CANNOT_INFER_PARAMETER_TYPE.on(declaredParameter));
      }
      if (expectedType != null) {
        type = expectedType;
      } else {
        type = CANT_INFER_LAMBDA_PARAM_TYPE;
      }
    }
    return context
        .expressionTypingServices
        .getDescriptorResolver()
        .resolveValueParameterDescriptorWithAnnotationArguments(
            context.scope, functionDescriptor, declaredParameter, index, type, context.trace);
  }
  @Override
  public void updateUI(Object descriptor, ParameterInfoUIContext context) {
    // todo: when we will have ability to pass Array as vararg, implement such feature here too?
    if (context == null
        || context.getParameterOwner() == null
        || !context.getParameterOwner().isValid()) {
      return;
    }
    PsiElement parameterOwner = context.getParameterOwner();
    if (parameterOwner instanceof JetValueArgumentList) {
      JetValueArgumentList argumentList = (JetValueArgumentList) parameterOwner;
      if (descriptor instanceof FunctionDescriptor) {
        JetFile file = (JetFile) argumentList.getContainingFile();
        BindingContext bindingContext = AnalyzeSingleFileUtil.getContextForSingleFile(file);
        FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
        StringBuilder builder = new StringBuilder();
        List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters();
        List<JetValueArgument> valueArguments = argumentList.getArguments();
        int currentParameterIndex = context.getCurrentParameterIndex();
        int boldStartOffset = -1;
        int boldEndOffset = -1;
        boolean isGrey = false;
        boolean isDeprecated = false; // todo: add deprecation check
        Color color = context.getDefaultParameterColor();
        PsiElement parent = argumentList.getParent();
        if (parent instanceof JetCallElement) {
          JetCallElement callExpression = (JetCallElement) parent;
          JetExpression calleeExpression = callExpression.getCalleeExpression();
          JetSimpleNameExpression refExpression = null;
          if (calleeExpression instanceof JetSimpleNameExpression) {
            refExpression = (JetSimpleNameExpression) calleeExpression;
          } else if (calleeExpression instanceof JetConstructorCalleeExpression) {
            JetConstructorCalleeExpression constructorCalleeExpression =
                (JetConstructorCalleeExpression) calleeExpression;
            if (constructorCalleeExpression.getConstructorReferenceExpression()
                instanceof JetSimpleNameExpression) {
              refExpression =
                  (JetSimpleNameExpression)
                      constructorCalleeExpression.getConstructorReferenceExpression();
            }
          }
          if (refExpression != null) {
            DeclarationDescriptor declarationDescriptor =
                bindingContext.get(BindingContext.REFERENCE_TARGET, refExpression);
            if (declarationDescriptor != null) {
              if (declarationDescriptor == functionDescriptor) {
                color = GREEN_BACKGROUND;
              }
            }
          }
        }

        boolean[] usedIndexes = new boolean[valueParameters.size()];
        boolean namedMode = false;
        Arrays.fill(usedIndexes, false);
        if ((currentParameterIndex >= valueParameters.size()
                && (valueParameters.size() > 0 || currentParameterIndex > 0))
            && (valueParameters.size() == 0
                || valueParameters.get(valueParameters.size() - 1).getVarargElementType()
                    == null)) {
          isGrey = true;
        }
        if (valueParameters.size() == 0)
          builder.append(CodeInsightBundle.message("parameter.info.no.parameters"));
        for (int i = 0; i < valueParameters.size(); ++i) {
          if (i != 0) builder.append(", ");
          boolean highlightParameter =
              i == currentParameterIndex
                  || (!namedMode
                      && i < currentParameterIndex
                      && valueParameters.get(valueParameters.size() - 1).getVarargElementType()
                          != null);
          if (highlightParameter) boldStartOffset = builder.length();
          if (!namedMode) {
            if (valueArguments.size() > i) {
              JetValueArgument argument = valueArguments.get(i);
              if (argument.isNamed()) {
                namedMode = true;
              } else {
                ValueParameterDescriptor param = valueParameters.get(i);
                builder.append(renderParameter(param, false, bindingContext));
                if (i < currentParameterIndex) {
                  if (argument.getArgumentExpression() != null) {
                    // check type
                    JetType paramType = getActualParameterType(param);
                    JetType exprType =
                        bindingContext.get(
                            BindingContext.EXPRESSION_TYPE, argument.getArgumentExpression());
                    if (exprType != null
                        && !JetTypeChecker.INSTANCE.isSubtypeOf(exprType, paramType)) isGrey = true;
                  } else isGrey = true;
                }
                usedIndexes[i] = true;
              }
            } else {
              ValueParameterDescriptor param = valueParameters.get(i);
              builder.append(renderParameter(param, false, bindingContext));
            }
          }
          if (namedMode) {
            boolean takeAnyArgument = true;
            if (valueArguments.size() > i) {
              JetValueArgument argument = valueArguments.get(i);
              if (argument.isNamed()) {
                for (int j = 0; j < valueParameters.size(); ++j) {
                  JetSimpleNameExpression referenceExpression =
                      argument.getArgumentName().getReferenceExpression();
                  ValueParameterDescriptor param = valueParameters.get(j);
                  if (referenceExpression != null
                      && !usedIndexes[j]
                      && param.getName().equals(referenceExpression.getReferencedNameAsName())) {
                    takeAnyArgument = false;
                    usedIndexes[j] = true;
                    builder.append(renderParameter(param, true, bindingContext));
                    if (i < currentParameterIndex) {
                      if (argument.getArgumentExpression() != null) {
                        // check type
                        JetType paramType = getActualParameterType(param);
                        JetType exprType =
                            bindingContext.get(
                                BindingContext.EXPRESSION_TYPE, argument.getArgumentExpression());
                        if (exprType != null
                            && !JetTypeChecker.INSTANCE.isSubtypeOf(exprType, paramType))
                          isGrey = true;
                      } else isGrey = true;
                    }
                    break;
                  }
                }
              }
            }

            if (takeAnyArgument) {
              if (i < currentParameterIndex) isGrey = true;

              for (int j = 0; j < valueParameters.size(); ++j) {
                ValueParameterDescriptor param = valueParameters.get(j);
                if (!usedIndexes[j]) {
                  usedIndexes[j] = true;
                  builder.append(renderParameter(param, true, bindingContext));
                  break;
                }
              }
            }
          }
          if (highlightParameter) boldEndOffset = builder.length();
        }
        if (builder.toString().isEmpty()) context.setUIComponentEnabled(false);
        else
          context.setupUIComponentPresentation(
              builder.toString(),
              boldStartOffset,
              boldEndOffset,
              isGrey,
              isDeprecated,
              false,
              color);
      } else context.setUIComponentEnabled(false);
    }
  }
Beispiel #9
0
  public static TabledDescriptorRenderer renderConflictingSubstitutionsInferenceError(
      ExtendedInferenceErrorData inferenceErrorData, TabledDescriptorRenderer result) {
    assert inferenceErrorData.constraintSystem.hasConflictingConstraints();

    Collection<CallableDescriptor> substitutedDescriptors = Lists.newArrayList();
    Collection<TypeSubstitutor> substitutors =
        ConstraintsUtil.getSubstitutorsForConflictingParameters(
            inferenceErrorData.constraintSystem);
    for (TypeSubstitutor substitutor : substitutors) {
      CallableDescriptor substitutedDescriptor =
          inferenceErrorData.descriptor.substitute(substitutor);
      substitutedDescriptors.add(substitutedDescriptor);
    }

    TypeParameterDescriptor firstConflictingParameter =
        ConstraintsUtil.getFirstConflictingParameter(inferenceErrorData.constraintSystem);
    assert firstConflictingParameter != null;

    result.text(
        newText()
            .normal("Cannot infer type parameter ")
            .strong(firstConflictingParameter.getName())
            .normal(" in"));
    // String type = strong(firstConflictingParameter.getName());
    TableRenderer table = newTable();
    result.table(table);
    table.descriptor(inferenceErrorData.descriptor).text("None of the following substitutions");

    for (CallableDescriptor substitutedDescriptor : substitutedDescriptors) {
      JetType receiverType =
          DescriptorUtils.getReceiverParameterType(substitutedDescriptor.getReceiverParameter());

      final Collection<ConstraintPosition> errorPositions = Sets.newHashSet();
      List<JetType> parameterTypes = Lists.newArrayList();
      for (ValueParameterDescriptor valueParameterDescriptor :
          substitutedDescriptor.getValueParameters()) {
        parameterTypes.add(valueParameterDescriptor.getType());
        if (valueParameterDescriptor.getIndex() >= inferenceErrorData.valueArgumentsTypes.size())
          continue;
        JetType actualType =
            inferenceErrorData.valueArgumentsTypes.get(valueParameterDescriptor.getIndex());
        if (!JetTypeChecker.INSTANCE.isSubtypeOf(actualType, valueParameterDescriptor.getType())) {
          errorPositions.add(
              ConstraintPosition.getValueParameterPosition(valueParameterDescriptor.getIndex()));
        }
      }

      if (receiverType != null
          && inferenceErrorData.receiverArgumentType != null
          && !JetTypeChecker.INSTANCE.isSubtypeOf(
              inferenceErrorData.receiverArgumentType, receiverType)) {
        errorPositions.add(ConstraintPosition.RECEIVER_POSITION);
      }

      Predicate<ConstraintPosition> isErrorPosition =
          new Predicate<ConstraintPosition>() {
            @Override
            public boolean apply(@Nullable ConstraintPosition constraintPosition) {
              return errorPositions.contains(constraintPosition);
            }
          };
      table.functionArgumentTypeList(receiverType, parameterTypes, isErrorPosition);
    }

    table
        .text("can be applied to")
        .functionArgumentTypeList(
            inferenceErrorData.receiverArgumentType, inferenceErrorData.valueArgumentsTypes);

    return result;
  }
 public static boolean isBoolean(@NotNull JetType type) {
   return JetTypeChecker.INSTANCE.isSubtypeOf(
       type, JetStandardLibrary.getInstance().getBooleanType());
 }