added default renderers for type inference errors

TabledDescriptorRenderer is responsible for rendering messages with tables (in compiler);
HtmlTabledDescriptorRenderer changes rendering in ide using html tables
This commit is contained in:
Svetlana Isakova
2012-07-10 14:56:38 +04:00
parent ee5ec0b500
commit b3146fa42f
6 changed files with 469 additions and 213 deletions
@@ -395,11 +395,10 @@ public class DefaultErrorMessages {
MAP.put(CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS, "Cannot create an instance of an abstract class");
//todo
MAP.put(TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS, "Type inference failed: {0}", TO_STRING);
MAP.put(TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER, "Type inference failed: {0}", TO_STRING);
MAP.put(TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH, "Type inference failed: {0}", TO_STRING);
MAP.put(TYPE_INFERENCE_UPPER_BOUND_VIOLATED, "Type parameter bound is not satisfied: {0} is not a subtype of {1}", TO_STRING);
MAP.put(TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS, "Type inference failed: {0}", TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS_RENDERER);
MAP.put(TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER, "Type inference failed: {0}", TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER_RENDERER);
MAP.put(TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH, "Type inference failed: {0}", TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH_RENDERER);
MAP.put(TYPE_INFERENCE_UPPER_BOUND_VIOLATED, "{0}", TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER);
MAP.put(WRONG_NUMBER_OF_TYPE_ARGUMENTS, "{0,choice,0#No type arguments|1#Type argument|1<{0,number,integer} type argument} expected", null);
@@ -16,18 +16,32 @@
package org.jetbrains.jet.lang.diagnostics.rendering;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.Named;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition;
import org.jetbrains.jet.lang.resolve.calls.inference.InferenceErrorData;
import org.jetbrains.jet.lang.resolve.calls.inference.TypeBounds;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeSubstitutor;
import org.jetbrains.jet.lang.types.Variance;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.resolve.DescriptorRenderer;
import static org.jetbrains.jet.lang.diagnostics.rendering.TabledDescriptorRenderer.*;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* @author svtk
@@ -117,6 +131,151 @@ public class Renderers {
};
}
public static final Renderer<InferenceErrorData> TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS_RENDERER =
new Renderer<InferenceErrorData>() {
@NotNull
@Override
public String render(@NotNull InferenceErrorData inferenceErrorData) {
return renderConflictingSubstitutionsInferenceError(inferenceErrorData, TabledDescriptorRenderer.create()).toString();
}
};
public static final Renderer<InferenceErrorData> TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH_RENDERER =
new Renderer<InferenceErrorData>() {
@NotNull
@Override
public String render(@NotNull InferenceErrorData inferenceErrorData) {
return renderTypeConstructorMismatchError(inferenceErrorData, TabledDescriptorRenderer.create()).toString();
}
};
public static final Renderer<InferenceErrorData> TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER_RENDERER =
new Renderer<InferenceErrorData>() {
@NotNull
@Override
public String render(@NotNull InferenceErrorData inferenceErrorData) {
return renderNoInformationForParameterError(inferenceErrorData, TabledDescriptorRenderer.create()).toString();
}
};
public static final Renderer<InferenceErrorData> TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER =
new Renderer<InferenceErrorData>() {
@NotNull
@Override
public String render(@NotNull InferenceErrorData inferenceErrorData) {
return renderUpperBoundViolatedInferenceError(inferenceErrorData, TabledDescriptorRenderer.create()).toString();
}
};
public static TabledDescriptorRenderer renderConflictingSubstitutionsInferenceError(InferenceErrorData inferenceErrorData,
TabledDescriptorRenderer result) {
assert inferenceErrorData.constraintSystem.hasConflictingParameters();
Collection<CallableDescriptor> substitutedDescriptors = Lists.newArrayList();
Collection<TypeSubstitutor> substitutors = inferenceErrorData.constraintSystem.getSubstitutors();
for (TypeSubstitutor substitutor : substitutors) {
CallableDescriptor substitutedDescriptor = inferenceErrorData.descriptor.substitute(substitutor);
substitutedDescriptors.add(substitutedDescriptor);
}
TypeParameterDescriptor firstConflictingParameter = inferenceErrorData.constraintSystem.getFirstConflictingParameter();
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 = substitutedDescriptor.getReceiverParameter().exists() ? substitutedDescriptor.getReceiverParameter().getType() : null;
Collection<ConstraintPosition> errorPositions = Sets.newHashSet();
List<JetType> valueArgumentTypes = Lists.newArrayList();
for (ValueParameterDescriptor valueParameterDescriptor : substitutedDescriptor.getValueParameters()) {
valueArgumentTypes.add(valueParameterDescriptor.getType());
JetType actualType = inferenceErrorData.valueArgumentsTypes.get(valueParameterDescriptor.getIndex());
if (!JetTypeChecker.INSTANCE.isSubtypeOf(actualType, valueParameterDescriptor.getType())) {
errorPositions.add(ConstraintPosition.valueParameterPosition(valueParameterDescriptor.getIndex()));
}
}
if (receiverType != null && inferenceErrorData.receiverArgumentType != null &&
!JetTypeChecker.INSTANCE.isSubtypeOf(inferenceErrorData.receiverArgumentType, receiverType)) {
errorPositions.add(ConstraintPosition.RECEIVER_POSITION);
}
table.functionArgumentTypeList(receiverType, valueArgumentTypes, errorPositions);
}
table.text("can be applied to")
.functionArgumentTypeList(inferenceErrorData.receiverArgumentType, inferenceErrorData.valueArgumentsTypes);
return result;
}
public static TabledDescriptorRenderer renderTypeConstructorMismatchError(InferenceErrorData inferenceErrorData,
TabledDescriptorRenderer renderer) {
return renderer.table(TabledDescriptorRenderer.newTable()
.descriptor(inferenceErrorData.descriptor)
.text("cannot be applied to")
.functionArgumentTypeList(
inferenceErrorData.receiverArgumentType,
inferenceErrorData.valueArgumentsTypes,
inferenceErrorData.constraintSystem
.getErrorConstraintPositions()));
}
public static TabledDescriptorRenderer renderNoInformationForParameterError(InferenceErrorData inferenceErrorData,
TabledDescriptorRenderer renderer) {
TypeParameterDescriptor firstUnknownParameter = null;
for (Map.Entry<TypeParameterDescriptor, TypeBounds> entry : inferenceErrorData.constraintSystem.getTypeBoundsMap().entrySet()) {
if (entry.getValue().isEmpty()) {
firstUnknownParameter = entry.getKey();
break;
}
}
assert firstUnknownParameter != null;
return renderer
.text(TabledDescriptorRenderer.newText().normal("Not enough information to infer parameter ")
.strong(firstUnknownParameter.getName())
.normal(" in "))
.table(TabledDescriptorRenderer.newTable()
.descriptor(inferenceErrorData.descriptor)
.text("Please specify it explicitly."));
}
public static TabledDescriptorRenderer renderUpperBoundViolatedInferenceError(InferenceErrorData inferenceErrorData, TabledDescriptorRenderer result) {
TypeParameterDescriptor typeParameterDescriptor = null;
for (TypeParameterDescriptor typeParameter : inferenceErrorData.descriptor.getTypeParameters()) {
if (!inferenceErrorData.constraintSystem.checkUpperBound(typeParameter)) {
typeParameterDescriptor = typeParameter;
break;
}
}
assert typeParameterDescriptor != null;
result.text(newText().normal("Type parameter bound for ").strong(typeParameterDescriptor.getName()).normal(" in "))
.table(newTable().
descriptor(inferenceErrorData.descriptor));
JetType type = inferenceErrorData.constraintSystem.getValue(typeParameterDescriptor);
JetType upperBound = typeParameterDescriptor.getUpperBoundsAsType();
JetType substitute = inferenceErrorData.constraintSystem.getSubstitutor().substitute(upperBound, Variance.INVARIANT);
result.text(newText()
.normal(" is not satisfied: inferred type ")
.error(type)
.normal(" is not a subtype of ")
.strong(substitute));
return result;
}
private Renderers() {
}
}
@@ -0,0 +1,249 @@
/*
* Copyright 2010-2012 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.diagnostics.rendering;
import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.resolve.DescriptorRenderer;
import org.jetbrains.jet.lang.diagnostics.rendering.TabledDescriptorRenderer.TableRenderer.*;
import org.jetbrains.jet.lang.diagnostics.rendering.TabledDescriptorRenderer.TextRenderer.*;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
* @author svtk
*/
public class TabledDescriptorRenderer {
public interface TableOrTextRenderer {}
public static class TableRenderer implements TableOrTextRenderer{
public interface TableRow {
}
public static class DescriptorRow implements TableRow {
public final CallableDescriptor descriptor;
public DescriptorRow(CallableDescriptor descriptor) {
this.descriptor = descriptor;
}
}
public static class FunctionArgumentsRow implements TableRow {
public final JetType receiverType;
public final List<JetType> argumentTypes;
public final Collection<ConstraintPosition> errorPositions;
public FunctionArgumentsRow(JetType receiverType, List<JetType> argumentTypes, Collection<ConstraintPosition> errorPositions) {
this.receiverType = receiverType;
this.argumentTypes = argumentTypes;
this.errorPositions = errorPositions;
}
}
public final List<TableRow> rows = Lists.newArrayList();
public TableRenderer descriptor(CallableDescriptor descriptor) {
rows.add(new DescriptorRow(descriptor));
return this;
}
public TableRenderer functionArgumentTypeList(@Nullable JetType receiverType, @NotNull List<JetType> argumentTypes) {
return functionArgumentTypeList(receiverType, argumentTypes, Collections.<ConstraintPosition>emptyList());
}
public TableRenderer functionArgumentTypeList(@Nullable JetType receiverType,
@NotNull List<JetType> argumentTypes,
Collection<ConstraintPosition> errorPositions) {
rows.add(new FunctionArgumentsRow(receiverType, argumentTypes, errorPositions));
return this;
}
public TableRenderer text(@NotNull String text) {
rows.add(newText().normal(text));
return this;
}
public TableRenderer text(@NotNull TextRenderer textRenderer) {
rows.add(textRenderer);
return this;
}
}
public static class TextRenderer implements TableOrTextRenderer, TableRow {
public static enum TextElementType {STRONG, ERROR, DEFAULT}
public static class TextElement {
public TextElementType type;
public String text;
public TextElement(@NotNull TextElementType type, @NotNull String text) {
this.type = type;
this.text = text;
}
}
public final List<TextElement> elements = Lists.newArrayList();
public TextRenderer normal(@NotNull Object text) {
elements.add(new TextElement(TextElementType.DEFAULT, text.toString()));
return this;
}
public TextRenderer error(@NotNull Object text) {
elements.add(new TextElement(TextElementType.ERROR, text.toString()));
return this;
}
public TextRenderer strong(@NotNull Object text) {
elements.add(new TextElement(TextElementType.STRONG, text.toString()));
return this;
}
}
protected final List<TableOrTextRenderer> renderers = Lists.newArrayList();
public TabledDescriptorRenderer text(@NotNull TextRenderer textRenderer) {
renderers.add(textRenderer);
return this;
}
public TabledDescriptorRenderer table(@NotNull TableRenderer tableRenderer) {
renderers.add(tableRenderer);
return this;
}
public static TextRenderer newText() {
return new TextRenderer();
}
public static TableRenderer newTable() {
return new TableRenderer();
}
//protected final List<TableRenderer> previousTables = Lists.newArrayList();
//private TextRow currentFirstText;
//private List<TableRow> currentRows;
//
//public TabledDescriptorRenderer newElement() {
// previousTables.add(new TableRenderer(currentFirstText, currentRows));
// currentFirstText = null;
// currentRows = Lists.newArrayList();
// return this;
//}
//
//public TabledDescriptorRenderer text(String text) {
// if (currentRows.isEmpty()) {
// currentFirstText = new TextRow(text);
// return this;
// }
// currentRows.add(new TextRow(text));
// return this;
//}
//
//public TabledDescriptorRenderer text(String text, Object... args) {
// return text(String.format(text, args));
//}
//private TabledDescriptorRenderer(@Nullable TextRow firstText, @NotNull List<TableRow> rows) {
// this.currentFirstText = firstText;
// this.currentRows = rows;
//}
//
//protected TabledDescriptorRenderer() {
// this(null, Lists.<TableRow>newArrayList());
//}
@Override
public String toString() {
StringBuilder result = new StringBuilder();
for (TableOrTextRenderer tableOrTextRenderer : renderers) {
if (tableOrTextRenderer instanceof TableRenderer) {
renderTable((TableRenderer)tableOrTextRenderer, result);
}
else {
renderText((TextRenderer)tableOrTextRenderer, result);
}
}
return result.toString();
}
protected void renderText(TextRenderer textRenderer, StringBuilder result) {
for (TextElement element : textRenderer.elements) {
result.append(element.text);
}
}
protected void renderTable(TableRenderer table, StringBuilder result) {
if (table.rows.isEmpty()) return;
for (TableRow row : table.rows) {
if (row instanceof TextRenderer) {
renderText((TextRenderer) row, result);
}
if (row instanceof DescriptorRow) {
result.append(DescriptorRenderer.COMPACT.render(((DescriptorRow) row).descriptor));
}
if (row instanceof FunctionArgumentsRow) {
FunctionArgumentsRow functionArgumentsRow = (FunctionArgumentsRow) row;
renderFunctionArguments(functionArgumentsRow.receiverType, functionArgumentsRow.argumentTypes, result);
}
result.append("\n");
}
}
private void renderFunctionArguments(@Nullable JetType receiverType, @NotNull List<JetType> argumentTypes, StringBuilder result) {
boolean hasReceiver = receiverType != null;
if (hasReceiver) {
result.append("receiver: ");
result.append(Renderers.RENDER_TYPE.render(receiverType));
result.append(" arguments: ");
}
if (argumentTypes.isEmpty()) {
result.append("()");
return;
}
result.append("(");
for (Iterator<JetType> iterator = argumentTypes.iterator(); iterator.hasNext(); ) {
JetType argumentType = iterator.next();
String renderedArgument = Renderers.RENDER_TYPE.render(argumentType);
result.append(renderedArgument);
if (iterator.hasNext()) {
result.append(",");
}
}
result.append(")");
}
public static TabledDescriptorRenderer create() {
return new TabledDescriptorRenderer();
}
}
@@ -16,119 +16,43 @@
package org.jetbrains.jet.plugin.highlighter;
import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.diagnostics.rendering.TabledDescriptorRenderer;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.resolve.DescriptorRenderer;
import static org.jetbrains.jet.plugin.highlighter.IdeRenderers.*;
import org.jetbrains.jet.lang.diagnostics.rendering.TabledDescriptorRenderer.TableRenderer.*;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
* @author svtk
*/
public class TablesRenderer {
public static class Table {
public final TextRow firstText;
public final List<TableRow> rows;
public class HtmlTabledDescriptorRenderer extends TabledDescriptorRenderer {
public Table(TextRow firstText, List<TableRow> rows) {
this.firstText = firstText;
this.rows = rows;
protected void renderText(TextRenderer textRenderer, StringBuilder result) {
for (TextRenderer.TextElement element : textRenderer.elements) {
if (element.type == TextRenderer.TextElementType.DEFAULT) {
result.append(element.text);
}
else if (element.type == TextRenderer.TextElementType.ERROR) {
result.append(error(element.text));
}
else if (element.type == TextRenderer.TextElementType.STRONG) {
result.append(strong(element.text));
}
}
}
public interface TableRow {
}
public static class TextRow implements TableRow {
public final String text;
public TextRow(String text) {
this.text = text;
}
}
public static class DescriptorRow implements TableRow {
public final CallableDescriptor descriptor;
public DescriptorRow(CallableDescriptor descriptor) {
this.descriptor = descriptor;
}
}
public static class FunctionArgumentsRow implements TableRow {
public final JetType receiverType;
public final List<JetType> argumentTypes;
public final Collection<ConstraintPosition> errorPositions;
public FunctionArgumentsRow(JetType receiverType, List<JetType> argumentTypes, Collection<ConstraintPosition> errorPositions) {
this.receiverType = receiverType;
this.argumentTypes = argumentTypes;
this.errorPositions = errorPositions;
}
}
private final List<Table> previousTables = Lists.newArrayList();
private TextRow currentFirstText;
private List<TableRow> currentRows;
public TablesRenderer newElement() {
previousTables.add(new Table(currentFirstText, currentRows));
currentFirstText = null;
currentRows = Lists.newArrayList();
return this;
}
public TablesRenderer text(String text) {
if (currentRows.isEmpty()) {
currentFirstText = new TextRow(text);
return this;
}
currentRows.add(new TextRow(text));
return this;
}
public TablesRenderer text(String text, Object... args) {
return text(String.format(text, args));
}
public TablesRenderer descriptor(CallableDescriptor descriptor) {
currentRows.add(new DescriptorRow(descriptor));
return this;
}
public TablesRenderer functionArgumentTypeList(@Nullable JetType receiverType, @NotNull List<JetType> argumentTypes) {
return functionArgumentTypeList(receiverType, argumentTypes, Collections.<ConstraintPosition>emptyList());
}
public TablesRenderer functionArgumentTypeList(@Nullable JetType receiverType,
@NotNull List<JetType> argumentTypes,
Collection<ConstraintPosition> errorPositions) {
currentRows.add(new FunctionArgumentsRow(receiverType, argumentTypes, errorPositions));
return this;
}
@Override
public String toString() {
StringBuilder result = new StringBuilder();
newElement();
for (Table table : previousTables) {
renderTable(table, result);
}
return result.toString();
}
private static int countRowsNumber(Table table) {
private int countRowsNumber(TableRenderer table) {
int argumentsNumber = 0;
for (TableRow row : table.rows) {
if (row instanceof DescriptorRow) {
@@ -149,21 +73,19 @@ public class TablesRenderer {
return argumentsNumber + 6;
}
private static void renderTable(Table table, StringBuilder result) {
if (table.firstText == null && table.rows.isEmpty()) return;
if (table.firstText != null) {
result.append(table.firstText.text);
}
@Override
protected void renderTable(TableRenderer table, StringBuilder result) {
if (table.rows.isEmpty()) return;
int rowsNumber = countRowsNumber(table);
result.append("<table>");
for (TableRow row : table.rows) {
result.append("<tr>");
if (row instanceof TextRow) {
tdColspan(result, ((TextRow) row).text, rowsNumber);
if (row instanceof TextRenderer) {
StringBuilder rowText = new StringBuilder();
renderText((TextRenderer) row, rowText);
tdColspan(result, rowText.toString(), rowsNumber);
}
if (row instanceof DescriptorRow) {
result.append(DESCRIPTOR_IN_TABLE.render(((DescriptorRow) row).descriptor));
@@ -179,7 +101,7 @@ public class TablesRenderer {
result.append("</table>");
}
private static void renderFunctionArguments(@Nullable JetType receiverType, @NotNull List<JetType> argumentTypes, Collection<ConstraintPosition> errorPositions, StringBuilder result) {
private void renderFunctionArguments(@Nullable JetType receiverType, @NotNull List<JetType> argumentTypes, Collection<ConstraintPosition> errorPositions, StringBuilder result) {
boolean hasReceiver = receiverType != null;
tdSpace(result);
String receiver = "";
@@ -213,20 +135,25 @@ public class TablesRenderer {
td(result, strong(")"));
}
public static TablesRenderer create() {
return new TablesRenderer();
public static HtmlTabledDescriptorRenderer create() {
return new HtmlTabledDescriptorRenderer();
}
TablesRenderer(@Nullable TextRow firstText, @NotNull List<TableRow> rows) {
this.currentFirstText = firstText;
this.currentRows = rows;
protected HtmlTabledDescriptorRenderer() {
super();
}
TablesRenderer() {
this(null, Lists.<TableRow>newArrayList());
}
public static final DescriptorRenderer DESCRIPTOR_IN_TABLE = new DescriptorRenderer.HtmlDescriptorRenderer() {
@Override
protected boolean shouldRenderDefinedIn() {
return false;
}
@Override
protected boolean shouldRenderModifiers() {
return false;
}
public static final DescriptorRenderer DESCRIPTOR_IN_TABLE = new DescriptorRenderer.HtmlDescriptorRenderer(false, false) {
@NotNull
@Override
public String render(@NotNull DeclarationDescriptor declarationDescriptor) {
@@ -44,10 +44,10 @@ public class IdeErrorMessages {
MAP.put(ASSIGN_OPERATOR_AMBIGUITY, "<html>Assignment operators ambiguity. All these functions match.<ul>{0}</ul></table></html>",
HTML_AMBIGUOUS_CALLS);
MAP.put(TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS, "<html>Type inference failed: {0}</html>", HTML_INFERENCE_ERROR_CONFLICTING_SUBSTITUTIONS);
MAP.put(TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER, "<html>Type inference failed: {0}</html>", HTML_INFERENCE_NO_INFORMATION_FOR_PARAMETER);
MAP.put(TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH, "<html>Type inference failed: {0}</html>", HTML_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH);
MAP.put(TYPE_INFERENCE_UPPER_BOUND_VIOLATED, "<html>{0}</html>", HTML_INFERENCE_UPPER_BOUND_VIOLATED);
MAP.put(TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS, "<html>Type inference failed: {0}</html>", HTML_TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS_RENDERER);
MAP.put(TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER, "<html>Type inference failed: {0}</html>", HTML_TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER_RENDERER);
MAP.put(TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH, "<html>Type inference failed: {0}</html>", HTML_TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH_RENDERER);
MAP.put(TYPE_INFERENCE_UPPER_BOUND_VIOLATED, "<html>{0}</html>", HTML_TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER);
MAP.put(WRONG_SETTER_PARAMETER_TYPE, "<html>Setter parameter type must be equal to the type of the property." +
"<table><tr><td>Expected:</td><td>{0}</td></tr>" +
@@ -16,15 +16,12 @@
package org.jetbrains.jet.plugin.highlighter;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters1;
@@ -36,19 +33,19 @@ import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCallImpl;
import org.jetbrains.jet.lang.resolve.calls.ResolvedValueArgument;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition;
import org.jetbrains.jet.lang.resolve.calls.inference.InferenceErrorData;
import org.jetbrains.jet.lang.resolve.calls.inference.TypeBounds;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeSubstitutor;
import org.jetbrains.jet.lang.types.Variance;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.resolve.DescriptorRenderer;
import java.util.*;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static org.jetbrains.jet.lang.diagnostics.rendering.Renderers.*;
/**
* @author svtk
@@ -181,115 +178,40 @@ public class IdeRenderers {
}
}
public static final Renderer<InferenceErrorData> HTML_INFERENCE_ERROR_CONFLICTING_SUBSTITUTIONS =
public static final Renderer<InferenceErrorData> HTML_TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS_RENDERER =
new Renderer<InferenceErrorData>() {
@NotNull
@Override
public String render(@NotNull InferenceErrorData inferenceErrorData) {
Collection<CallableDescriptor> substitutedDescriptors = Lists.newArrayList();
Collection<TypeSubstitutor> substitutors = inferenceErrorData.constraintSystem.getSubstitutors();
for (TypeSubstitutor substitutor : substitutors) {
CallableDescriptor substitutedDescriptor = inferenceErrorData.descriptor.substitute(substitutor);
substitutedDescriptors.add(substitutedDescriptor);
}
String type = strong(inferenceErrorData.constraintSystem.getFirstConflictingParameter().getName());
TablesRenderer table = TablesRenderer.create();
table.text("Cannot infer type parameter %s in", type)
.descriptor(inferenceErrorData.descriptor)
.text("None of the following substitutions");
for (CallableDescriptor substitutedDescriptor : substitutedDescriptors) {
JetType receiverType = substitutedDescriptor.getReceiverParameter().exists() ? substitutedDescriptor.getReceiverParameter().getType() : null;
Collection<ConstraintPosition> errorPositions = Sets.newHashSet();
List<JetType> valueArgumentTypes = Lists.newArrayList();
for (ValueParameterDescriptor valueParameterDescriptor : substitutedDescriptor.getValueParameters()) {
valueArgumentTypes.add(valueParameterDescriptor.getType());
JetType actualType = inferenceErrorData.valueArgumentsTypes.get(valueParameterDescriptor.getIndex());
if (!JetTypeChecker.INSTANCE.isSubtypeOf(actualType, valueParameterDescriptor.getType())) {
errorPositions.add(ConstraintPosition.valueParameterPosition(valueParameterDescriptor.getIndex()));
}
}
if (receiverType != null && inferenceErrorData.receiverArgumentType != null &&
!JetTypeChecker.INSTANCE.isSubtypeOf(inferenceErrorData.receiverArgumentType, receiverType)) {
errorPositions.add(ConstraintPosition.RECEIVER_POSITION);
}
table.functionArgumentTypeList(receiverType, valueArgumentTypes, errorPositions);
}
table.text("can be applied to")
.functionArgumentTypeList(inferenceErrorData.receiverArgumentType, inferenceErrorData.valueArgumentsTypes);
return table.toString();
return renderConflictingSubstitutionsInferenceError(inferenceErrorData, HtmlTabledDescriptorRenderer.create()).toString();
}
};
public static final Renderer<InferenceErrorData> HTML_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH =
public static final Renderer<InferenceErrorData> HTML_TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH_RENDERER =
new Renderer<InferenceErrorData>() {
@NotNull
@Override
public String render(@NotNull InferenceErrorData inferenceErrorData) {
return TablesRenderer.create()
.descriptor(inferenceErrorData.descriptor)
.text("cannot be applied to")
.functionArgumentTypeList(inferenceErrorData.receiverArgumentType, inferenceErrorData.valueArgumentsTypes,
inferenceErrorData.constraintSystem.getErrorConstraintPositions())
.toString();
return renderTypeConstructorMismatchError(inferenceErrorData, HtmlTabledDescriptorRenderer.create()).toString();
}
};
public static final Renderer<InferenceErrorData> HTML_INFERENCE_NO_INFORMATION_FOR_PARAMETER =
public static final Renderer<InferenceErrorData> HTML_TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER_RENDERER =
new Renderer<InferenceErrorData>() {
@NotNull
@Override
public String render(@NotNull InferenceErrorData inferenceErrorData) {
TypeParameterDescriptor firstUnknownParameter = null;
for (Map.Entry<TypeParameterDescriptor, TypeBounds> entry : inferenceErrorData.constraintSystem.getTypeBoundsMap().entrySet()) {
if (entry.getValue().isEmpty()) {
firstUnknownParameter = entry.getKey();
break;
}
}
assert firstUnknownParameter != null;
String firstUnknownParameterName = String.format(STRONG_TEMPLATE, firstUnknownParameter.getName());
return TablesRenderer.create()
.text("Not enough information to infer parameter %s in", firstUnknownParameterName)
.descriptor(inferenceErrorData.descriptor)
.text("Please specify it explicitly.")
.toString();
return renderNoInformationForParameterError(inferenceErrorData, HtmlTabledDescriptorRenderer.create()).toString();
}
};
public static final Renderer<InferenceErrorData> HTML_INFERENCE_UPPER_BOUND_VIOLATED =
public static final Renderer<InferenceErrorData> HTML_TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER =
new Renderer<InferenceErrorData>() {
@NotNull
@Override
public String render(@NotNull InferenceErrorData inferenceErrorData) {
TypeParameterDescriptor typeParameterDescriptor = null;
for (TypeParameterDescriptor typeParameter : inferenceErrorData.descriptor.getTypeParameters()) {
if (!inferenceErrorData.constraintSystem.checkUpperBound(typeParameter)) {
typeParameterDescriptor = typeParameter;
break;
}
}
assert typeParameterDescriptor != null;
TablesRenderer table = TablesRenderer.create();
table.text("Type parameter bound for %s in", strong(typeParameterDescriptor.getName())).
descriptor(inferenceErrorData.descriptor);
JetType type = inferenceErrorData.constraintSystem.getValue(typeParameterDescriptor);
JetType upperBound = typeParameterDescriptor.getUpperBoundsAsType();
JetType substitute = inferenceErrorData.constraintSystem.getSubstitutor().substitute(upperBound, Variance.INVARIANT);
table.newElement()
.text("is not satisfied: inferred type %s is not a subtype of %s.", error(type), strong(substitute));
return table.toString();
return renderUpperBoundViolatedInferenceError(inferenceErrorData, HtmlTabledDescriptorRenderer.create()).toString();
}
};
}