001/* 002 * Copyright 2010-2013 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.jetbrains.jet.lang.diagnostics.rendering; 018 019import com.google.common.base.Predicate; 020import com.google.common.collect.Lists; 021import com.google.common.collect.Sets; 022import com.intellij.openapi.util.text.StringUtil; 023import com.intellij.psi.PsiElement; 024import com.intellij.util.Function; 025import org.jetbrains.annotations.NotNull; 026import org.jetbrains.annotations.Nullable; 027import org.jetbrains.jet.lang.descriptors.*; 028import org.jetbrains.jet.lang.psi.JetClass; 029import org.jetbrains.jet.lang.psi.JetClassOrObject; 030import org.jetbrains.jet.lang.resolve.DescriptorUtils; 031import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition; 032import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintsUtil; 033import org.jetbrains.jet.lang.resolve.calls.inference.InferenceErrorData; 034import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; 035import org.jetbrains.jet.lang.types.JetType; 036import org.jetbrains.jet.lang.types.TypeSubstitutor; 037import org.jetbrains.jet.lang.types.Variance; 038import org.jetbrains.jet.lang.types.checker.JetTypeChecker; 039import org.jetbrains.jet.renderer.DescriptorRenderer; 040 041import java.util.Collection; 042import java.util.Iterator; 043import java.util.List; 044 045import static org.jetbrains.jet.lang.diagnostics.rendering.TabledDescriptorRenderer.*; 046import static org.jetbrains.jet.lang.resolve.calls.inference.InferenceErrorData.ExtendedInferenceErrorData; 047 048public class Renderers { 049 public static final Renderer<Object> TO_STRING = new Renderer<Object>() { 050 @NotNull 051 @Override 052 public String render(@NotNull Object element) { 053 return element.toString(); 054 } 055 056 @Override 057 public String toString() { 058 return "TO_STRING"; 059 } 060 }; 061 062 public static final Renderer<Object> NAME = new Renderer<Object>() { 063 @NotNull 064 @Override 065 public String render(@NotNull Object element) { 066 if (element instanceof Named) { 067 return ((Named) element).getName().asString(); 068 } 069 return element.toString(); 070 } 071 }; 072 073 public static final Renderer<PsiElement> ELEMENT_TEXT = new Renderer<PsiElement>() { 074 @NotNull 075 @Override 076 public String render(@NotNull PsiElement element) { 077 return element.getText(); 078 } 079 }; 080 081 public static final Renderer<JetClassOrObject> RENDER_CLASS_OR_OBJECT = new Renderer<JetClassOrObject>() { 082 @NotNull 083 @Override 084 public String render(@NotNull JetClassOrObject classOrObject) { 085 String name = classOrObject.getName() != null ? " '" + classOrObject.getName() + "'" : ""; 086 if (classOrObject instanceof JetClass) { 087 return "Class" + name; 088 } 089 return "Object" + name; 090 091 } 092 }; 093 094 public static final Renderer<JetType> RENDER_TYPE = new Renderer<JetType>() { 095 @NotNull 096 @Override 097 public String render(@NotNull JetType type) { 098 return DescriptorRenderer.TEXT.renderType(type); 099 } 100 }; 101 102 public static final Renderer<Collection<? extends ResolvedCall<?>>> AMBIGUOUS_CALLS = 103 new Renderer<Collection<? extends ResolvedCall<? extends CallableDescriptor>>>() { 104 @NotNull 105 @Override 106 public String render(@NotNull Collection<? extends ResolvedCall<? extends CallableDescriptor>> argument) { 107 StringBuilder stringBuilder = new StringBuilder("\n"); 108 for (ResolvedCall<? extends CallableDescriptor> call : argument) { 109 stringBuilder.append(DescriptorRenderer.TEXT.render(call.getResultingDescriptor())).append("\n"); 110 } 111 return stringBuilder.toString(); 112 } 113 }; 114 115 public static <T> Renderer<Collection<? extends T>> commaSeparated(final Renderer<T> itemRenderer) { 116 return new Renderer<Collection<? extends T>>() { 117 @NotNull 118 @Override 119 public String render(@NotNull Collection<? extends T> object) { 120 StringBuilder result = new StringBuilder(); 121 for (Iterator<? extends T> iterator = object.iterator(); iterator.hasNext(); ) { 122 T next = iterator.next(); 123 result.append(itemRenderer.render(next)); 124 if (iterator.hasNext()) { 125 result.append(", "); 126 } 127 } 128 return result.toString(); 129 } 130 }; 131 } 132 133 public static final Renderer<ExtendedInferenceErrorData> TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS_RENDERER = 134 new Renderer<ExtendedInferenceErrorData>() { 135 @NotNull 136 @Override 137 public String render(@NotNull ExtendedInferenceErrorData inferenceErrorData) { 138 return renderConflictingSubstitutionsInferenceError(inferenceErrorData, TabledDescriptorRenderer.create()).toString(); 139 } 140 }; 141 142 public static final Renderer<ExtendedInferenceErrorData> TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH_RENDERER = 143 new Renderer<ExtendedInferenceErrorData>() { 144 @NotNull 145 @Override 146 public String render(@NotNull ExtendedInferenceErrorData inferenceErrorData) { 147 return renderTypeConstructorMismatchError(inferenceErrorData, TabledDescriptorRenderer.create()).toString(); 148 } 149 }; 150 151 public static final Renderer<ExtendedInferenceErrorData> TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER_RENDERER = 152 new Renderer<ExtendedInferenceErrorData>() { 153 @NotNull 154 @Override 155 public String render(@NotNull ExtendedInferenceErrorData inferenceErrorData) { 156 return renderNoInformationForParameterError(inferenceErrorData, TabledDescriptorRenderer.create()).toString(); 157 } 158 }; 159 160 public static final Renderer<InferenceErrorData> TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER = 161 new Renderer<InferenceErrorData>() { 162 @NotNull 163 @Override 164 public String render(@NotNull InferenceErrorData inferenceErrorData) { 165 return renderUpperBoundViolatedInferenceError(inferenceErrorData, TabledDescriptorRenderer.create()).toString(); 166 } 167 }; 168 169 public static TabledDescriptorRenderer renderConflictingSubstitutionsInferenceError(ExtendedInferenceErrorData inferenceErrorData, 170 TabledDescriptorRenderer result) { 171 assert inferenceErrorData.constraintSystem.hasConflictingConstraints(); 172 173 Collection<CallableDescriptor> substitutedDescriptors = Lists.newArrayList(); 174 Collection<TypeSubstitutor> substitutors = ConstraintsUtil.getSubstitutorsForConflictingParameters( 175 inferenceErrorData.constraintSystem); 176 for (TypeSubstitutor substitutor : substitutors) { 177 CallableDescriptor substitutedDescriptor = inferenceErrorData.descriptor.substitute(substitutor); 178 substitutedDescriptors.add(substitutedDescriptor); 179 } 180 181 TypeParameterDescriptor firstConflictingParameter = ConstraintsUtil.getFirstConflictingParameter(inferenceErrorData.constraintSystem); 182 assert firstConflictingParameter != null; 183 184 result.text(newText() 185 .normal("Cannot infer type parameter ") 186 .strong(firstConflictingParameter.getName()) 187 .normal(" in ")); 188 //String type = strong(firstConflictingParameter.getName()); 189 TableRenderer table = newTable(); 190 result.table(table); 191 table.descriptor(inferenceErrorData.descriptor) 192 .text("None of the following substitutions"); 193 194 for (CallableDescriptor substitutedDescriptor : substitutedDescriptors) { 195 JetType receiverType = DescriptorUtils.getReceiverParameterType(substitutedDescriptor.getReceiverParameter()); 196 197 final Collection<ConstraintPosition> errorPositions = Sets.newHashSet(); 198 List<JetType> parameterTypes = Lists.newArrayList(); 199 for (ValueParameterDescriptor valueParameterDescriptor : substitutedDescriptor.getValueParameters()) { 200 parameterTypes.add(valueParameterDescriptor.getType()); 201 if (valueParameterDescriptor.getIndex() >= inferenceErrorData.valueArgumentsTypes.size()) continue; 202 JetType actualType = inferenceErrorData.valueArgumentsTypes.get(valueParameterDescriptor.getIndex()); 203 if (!JetTypeChecker.INSTANCE.isSubtypeOf(actualType, valueParameterDescriptor.getType())) { 204 errorPositions.add(ConstraintPosition.getValueParameterPosition(valueParameterDescriptor.getIndex())); 205 } 206 } 207 208 if (receiverType != null && inferenceErrorData.receiverArgumentType != null && 209 !JetTypeChecker.INSTANCE.isSubtypeOf(inferenceErrorData.receiverArgumentType, receiverType)) { 210 errorPositions.add(ConstraintPosition.RECEIVER_POSITION); 211 } 212 213 Predicate<ConstraintPosition> isErrorPosition = new Predicate<ConstraintPosition>() { 214 @Override 215 public boolean apply(@Nullable ConstraintPosition constraintPosition) { 216 return errorPositions.contains(constraintPosition); 217 } 218 }; 219 table.functionArgumentTypeList(receiverType, parameterTypes, isErrorPosition); 220 } 221 222 table.text("can be applied to") 223 .functionArgumentTypeList(inferenceErrorData.receiverArgumentType, inferenceErrorData.valueArgumentsTypes); 224 225 return result; 226 } 227 228 public static TabledDescriptorRenderer renderTypeConstructorMismatchError(final ExtendedInferenceErrorData inferenceErrorData, 229 TabledDescriptorRenderer renderer) { 230 Predicate<ConstraintPosition> isErrorPosition = new Predicate<ConstraintPosition>() { 231 @Override 232 public boolean apply(@Nullable ConstraintPosition constraintPosition) { 233 assert constraintPosition != null; 234 return inferenceErrorData.constraintSystem.hasTypeConstructorMismatchAt(constraintPosition); 235 } 236 }; 237 return renderer.table(TabledDescriptorRenderer.newTable() 238 .descriptor(inferenceErrorData.descriptor) 239 .text("cannot be applied to") 240 .functionArgumentTypeList( 241 inferenceErrorData.receiverArgumentType, 242 inferenceErrorData.valueArgumentsTypes, 243 isErrorPosition)); 244 } 245 246 public static TabledDescriptorRenderer renderNoInformationForParameterError(ExtendedInferenceErrorData inferenceErrorData, 247 TabledDescriptorRenderer renderer) { 248 TypeParameterDescriptor firstUnknownParameter = null; 249 for (TypeParameterDescriptor typeParameter : inferenceErrorData.constraintSystem.getTypeVariables()) { 250 if (inferenceErrorData.constraintSystem.getTypeConstraints(typeParameter).isEmpty()) { 251 firstUnknownParameter = typeParameter; 252 break; 253 } 254 } 255 assert firstUnknownParameter != null; 256 257 return renderer 258 .text(newText().normal("Not enough information to infer parameter ") 259 .strong(firstUnknownParameter.getName()) 260 .normal(" in ")) 261 .table(newTable() 262 .descriptor(inferenceErrorData.descriptor) 263 .text("Please specify it explicitly.")); 264 } 265 266 public static TabledDescriptorRenderer renderUpperBoundViolatedInferenceError(InferenceErrorData inferenceErrorData, TabledDescriptorRenderer result) { 267 TypeParameterDescriptor typeParameterDescriptor = null; 268 for (TypeParameterDescriptor typeParameter : inferenceErrorData.descriptor.getTypeParameters()) { 269 if (!ConstraintsUtil.checkUpperBoundIsSatisfied(inferenceErrorData.constraintSystem, typeParameter, true)) { 270 typeParameterDescriptor = typeParameter; 271 break; 272 } 273 } 274 assert typeParameterDescriptor != null; 275 276 result.text(newText().normal("Type parameter bound for ").strong(typeParameterDescriptor.getName()).normal(" in ")) 277 .table(newTable(). 278 descriptor(inferenceErrorData.descriptor)); 279 280 JetType inferredValueForTypeParameter = ConstraintsUtil.getValue(inferenceErrorData.constraintSystem.getTypeConstraints(typeParameterDescriptor)); 281 assert inferredValueForTypeParameter != null; 282 JetType upperBound = typeParameterDescriptor.getUpperBoundsAsType(); 283 JetType upperBoundWithSubstitutedInferredTypes = inferenceErrorData.constraintSystem.getResultingSubstitutor().substitute(upperBound, Variance.INVARIANT); 284 assert upperBoundWithSubstitutedInferredTypes != null; 285 286 Renderer<JetType> typeRenderer = result.getTypeRenderer(); 287 result.text(newText() 288 .normal(" is not satisfied: inferred type ") 289 .error(typeRenderer.render(inferredValueForTypeParameter)) 290 .normal(" is not a subtype of ") 291 .strong(typeRenderer.render(upperBoundWithSubstitutedInferredTypes))); 292 return result; 293 } 294 295 public static final Renderer<Collection<ClassDescriptor>> CLASSES_OR_SEPARATED = new Renderer<Collection<ClassDescriptor>>() { 296 @NotNull 297 @Override 298 public String render(@NotNull Collection<ClassDescriptor> descriptors) { 299 StringBuilder sb = new StringBuilder(); 300 int index = 0; 301 for (ClassDescriptor descriptor : descriptors) { 302 sb.append(DescriptorUtils.getFQName(descriptor).asString()); 303 index++; 304 if (index <= descriptors.size() - 2) { 305 sb.append(", "); 306 } 307 else if (index == descriptors.size() - 1) { 308 sb.append(" or "); 309 } 310 } 311 return sb.toString(); 312 } 313 }; 314 315 public static final Renderer<Collection<JetType>> RENDER_COLLECTION_OF_TYPES = new Renderer<Collection<JetType>>() { 316 @NotNull 317 @Override 318 public String render(@NotNull Collection<JetType> types) { 319 return StringUtil.join(types, new Function<JetType, String>() { 320 @Override 321 public String fun(JetType type) { 322 return RENDER_TYPE.render(type); 323 } 324 }, ", "); 325 } 326 }; 327 328 329 private Renderers() { 330 } 331}