/** * 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; }
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; }
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); } }
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()); }