diff --git a/core/descriptors/src/org/jetbrains/jet/renderer/DescriptorRenderer.java b/core/descriptors/src/org/jetbrains/jet/renderer/DescriptorRenderer.java index 3765eb18c48..d73ac4f075d 100644 --- a/core/descriptors/src/org/jetbrains/jet/renderer/DescriptorRenderer.java +++ b/core/descriptors/src/org/jetbrains/jet/renderer/DescriptorRenderer.java @@ -68,6 +68,8 @@ public interface DescriptorRenderer extends Renderer { DescriptorRenderer HTML_FOR_UNINFERRED_TYPE_PARAMS = new DescriptorRendererBuilder() .setUninferredTypeParameterAsName(true) + .setModifiers() + .setShortNames(true) .setTextFormat(TextFormat.HTML).build(); @NotNull diff --git a/idea/src/org/jetbrains/jet/plugin/highlighter/renderersUtil.kt b/idea/src/org/jetbrains/jet/plugin/highlighter/renderersUtil.kt index bf7b2a8d467..f69c38be3c8 100644 --- a/idea/src/org/jetbrains/jet/plugin/highlighter/renderersUtil.kt +++ b/idea/src/org/jetbrains/jet/plugin/highlighter/renderersUtil.kt @@ -28,9 +28,16 @@ import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe import org.jetbrains.jet.lang.resolve.DescriptorUtils import org.jetbrains.jet.lang.resolve.name.FqName import org.jetbrains.jet.plugin.highlighter.IdeRenderers +import org.jetbrains.jet.lang.types.ErrorUtils +import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor fun renderResolvedCall(resolvedCall: ResolvedCall): String { - val htmlRenderer = DescriptorRenderer.HTML + val htmlRenderer = DescriptorRenderer.HTML_FOR_UNINFERRED_TYPE_PARAMS + val stringBuilder = StringBuilder("") + val indent = "  " + + fun append(any: Any): StringBuilder = stringBuilder.append(any) + fun renderParameter(parameter: ValueParameterDescriptor): String { val varargElementType = parameter.getVarargElementType() val parameterType = varargElementType ?: parameter.getType() @@ -44,21 +51,54 @@ fun renderResolvedCall(resolvedCall: ResolvedCall): return renderedParameter } - val stringBuilder = StringBuilder("") - val funDescriptor = resolvedCall.getResultingDescriptor() + fun appendTypeParametersSubstitution() { + val parametersToArgumentsMap = resolvedCall.getTypeArguments() + fun TypeParameterDescriptor.isInferred(): Boolean { + val typeArgument = parametersToArgumentsMap[this] + if (typeArgument == null) return false + return !ErrorUtils.isUninferredParameter(typeArgument) + } - val receiverParameter = funDescriptor.getReceiverParameter() - if (receiverParameter != null) { - stringBuilder.append(htmlRenderer.renderType(receiverParameter.getType())).append(".") + val typeParameters = resolvedCall.getCandidateDescriptor().getTypeParameters() + val (inferredTypeParameters, notInferredTypeParameters) = typeParameters.partition { parameter -> parameter.isInferred() } + + append("
$indentwhere ") + if (!notInferredTypeParameters.isEmpty()) { + append(notInferredTypeParameters.map { typeParameter -> IdeRenderers.error(typeParameter.getName()) }.makeString()) + append(" cannot be inferred") + if (!inferredTypeParameters.isEmpty()) { + append("; ") + } + } + + val typeParameterToTypeArgumentMap = resolvedCall.getTypeArguments() + if (!inferredTypeParameters.isEmpty()) { + append(inferredTypeParameters.map { typeParameter -> + "${typeParameter.getName()} = ${htmlRenderer.renderType(typeParameterToTypeArgumentMap[typeParameter]!!)}" + }.makeString()) + } } - stringBuilder.append(funDescriptor.getName()).append("(") - stringBuilder.append(funDescriptor.getValueParameters().map(::renderParameter).makeString(",")) - stringBuilder.append(if (resolvedCall.hasUnmappedArguments()) IdeRenderers.error(")") else ")") - stringBuilder.append(" defined in ") - val containingDeclaration = funDescriptor.getContainingDeclaration() - val fqName = DescriptorUtils.getFqName(containingDeclaration) - stringBuilder.append(if (FqName.ROOT.equalsTo(fqName)) "root package" else fqName.asString()) + val resultingDescriptor = resolvedCall.getResultingDescriptor() + val receiverParameter = resultingDescriptor.getReceiverParameter() + if (receiverParameter != null) { + append(htmlRenderer.renderType(receiverParameter.getType())).append(".") + } + append(resultingDescriptor.getName()).append("(") + append(resultingDescriptor.getValueParameters().map { parameter -> renderParameter(parameter) }.makeString()) + append(if (resolvedCall.hasUnmappedArguments()) IdeRenderers.error(")") else ")") + + if (!resolvedCall.getCandidateDescriptor().getTypeParameters().isEmpty()) { + appendTypeParametersSubstitution() + append(" for
$indent") + append(htmlRenderer.render(resolvedCall.getCandidateDescriptor())) + } + else { + append(" defined in ") + val containingDeclaration = resultingDescriptor.getContainingDeclaration() + val fqName = DescriptorUtils.getFqName(containingDeclaration) + append(if (FqName.ROOT.equalsTo(fqName)) "root package" else fqName.asString()) + } return stringBuilder.toString() } diff --git a/idea/testData/diagnosticMessage/noneApplicable1.html b/idea/testData/diagnosticMessage/noneApplicable1.html index 59758159fb0..7d57dac4a43 100644 --- a/idea/testData/diagnosticMessage/noneApplicable1.html +++ b/idea/testData/diagnosticMessage/noneApplicable1.html @@ -1,8 +1,9 @@ -None of the following functions can be called with the arguments supplied.
    -
  • foo(kotlin.Int, kotlin.String, kotlin.Boolean) defined in root package
  • -
  • foo(kotlin.Boolean, kotlin.String) defined in root package
  • -
  • foo(kotlin.Int) defined in root package
  • +None of the following functions can be called with the arguments supplied. +
      +
    • foo(Int, String, Boolean) defined in root package
    • +
    • foo(Boolean, String) defined in root package
    • +
    • foo(Int) defined in root package
    \ No newline at end of file diff --git a/idea/testData/diagnosticMessage/noneApplicableGeneric.kt b/idea/testData/diagnosticMessage/noneApplicableGeneric.kt new file mode 100644 index 00000000000..8e83f23d270 --- /dev/null +++ b/idea/testData/diagnosticMessage/noneApplicableGeneric.kt @@ -0,0 +1,15 @@ +// !DIAGNOSTICS_NUMBER: 1 +// !DIAGNOSTICS: NONE_APPLICABLE +// !MESSAGE_TYPE: HTML + +package p + +fun foo(t: T, a: Any, l: List) = 1 +fun foo(t: T, r: R, lt: MutableList, lr: MutableList) = 2 +fun foo(t: T, a: Any, lt: MutableList, lr: MutableList) = 3 + +fun use(vararg a: Any?) = a + +fun test(a: Any, li: MutableList, ls: MutableList) { + use(foo(11, a, li, ls)) +} \ No newline at end of file diff --git a/idea/testData/diagnosticMessage/noneApplicableGeneric1.html b/idea/testData/diagnosticMessage/noneApplicableGeneric1.html new file mode 100644 index 00000000000..b81b5fb2c2e --- /dev/null +++ b/idea/testData/diagnosticMessage/noneApplicableGeneric1.html @@ -0,0 +1,15 @@ + + +None of the following functions can be called with the arguments supplied. +
      +
    • foo(Int, Any, List<`Int>)
      + where T = Int for
      + fun <`T> foo(t: T, a: Any, l: List<`T>): Int defined in p
    • +
    • foo(Int, R, MutableList<`Int>, MutableList<`R>)
      + where R cannot be inferred; T = Int for
      + fun <`T, R> foo(t: T, r: R, lt: MutableList<`T>, lr: MutableList<`R>): Int defined in p
    • +
    • foo(T, Any, MutableList<`T>, MutableList<`T>)
      + where T cannot be inferred for
      + fun <`T> foo(t: T, a: Any, lt: MutableList<`T>, lr: MutableList<`T>): Int defined in p
    • +
    + \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/highlighter/DiagnosticMessageTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/highlighter/DiagnosticMessageTestGenerated.java index 65b1f93c93f..6148d25316f 100644 --- a/idea/tests/org/jetbrains/jet/plugin/highlighter/DiagnosticMessageTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/highlighter/DiagnosticMessageTestGenerated.java @@ -101,6 +101,11 @@ public class DiagnosticMessageTestGenerated extends AbstractDiagnosticMessageTes doTest("idea/testData/diagnosticMessage/noneApplicable.kt"); } + @TestMetadata("noneApplicableGeneric.kt") + public void testNoneApplicableGeneric() throws Exception { + doTest("idea/testData/diagnosticMessage/noneApplicableGeneric.kt"); + } + @TestMetadata("numberValueTypes.kt") public void testNumberValueTypes() throws Exception { doTest("idea/testData/diagnosticMessage/numberValueTypes.kt");