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:
+4
-5
@@ -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() {
|
||||
}
|
||||
}
|
||||
|
||||
+249
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
+38
-111
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user