Special diagnostics when no type arguments passed on teh right-hand side of 'is' expression

Example:

if (a is Map) // ERROR: Say 'Map<*, *>' if you don't want to pass type arguments
This commit is contained in:
Andrey Breslav
2012-11-27 13:50:00 +04:00
parent 1378f836f5
commit dff5f382ab
7 changed files with 77 additions and 3 deletions
@@ -91,6 +91,7 @@ public interface Errors {
SimpleDiagnosticFactory<JetNullableType> REDUNDANT_NULLABLE = SimpleDiagnosticFactory.create(WARNING, NULLABLE_TYPE);
DiagnosticFactory1<JetNullableType, JetType> BASE_WITH_NULLABLE_UPPER_BOUND = DiagnosticFactory1.create(WARNING, NULLABLE_TYPE);
DiagnosticFactory1<JetElement, Integer> WRONG_NUMBER_OF_TYPE_ARGUMENTS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory2<JetUserType, Integer, String> NO_TYPE_ARGUMENTS_ON_RHS_OF_IS_EXPRESSION = DiagnosticFactory2.create(ERROR);
DiagnosticFactory1<JetTypeProjection, ClassifierDescriptor> CONFLICTING_PROJECTION = DiagnosticFactory1.create(ERROR, VARIANCE_IN_PROJECTION);
DiagnosticFactory1<JetTypeProjection, ClassifierDescriptor> REDUNDANT_PROJECTION = DiagnosticFactory1.create(WARNING, VARIANCE_IN_PROJECTION);
@@ -419,6 +419,8 @@ public class DefaultErrorMessages {
MAP.put(TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH, "Type inference failed. Expected type mismatch: found: {0} required: {1}", RENDER_TYPE, RENDER_TYPE);
MAP.put(WRONG_NUMBER_OF_TYPE_ARGUMENTS, "{0,choice,0#No type arguments|1#Type argument|1<{0,number,integer} type argument} expected", null);
MAP.put(NO_TYPE_ARGUMENTS_ON_RHS_OF_IS_EXPRESSION, "{0,choice,0#No type arguments|1#Type argument|1<{0,number,integer} type argument} expected. " +
"Use ''{1}'' if you don''t want to pass type parameters", null, TO_STRING);
MAP.put(DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED,
"This expression is treated as an argument to the function call on the previous line. " +
@@ -16,6 +16,7 @@
package org.jetbrains.jet.lang.resolve;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.ModuleConfiguration;
@@ -142,7 +143,12 @@ public class TypeResolver {
else {
if (actualArgumentCount != expectedArgumentCount) {
if (actualArgumentCount == 0) {
trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(type, expectedArgumentCount));
if (rhsOfIsExpression(type)) {
trace.report(NO_TYPE_ARGUMENTS_ON_RHS_OF_IS_EXPRESSION.on(type, expectedArgumentCount, allStarProjectionsString(typeConstructor)));
}
else {
trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(type, expectedArgumentCount));
}
}
else {
trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(type.getTypeArgumentList(), expectedArgumentCount));
@@ -233,6 +239,19 @@ public class TypeResolver {
return result[0];
}
private static boolean rhsOfIsExpression(@NotNull JetUserType type) {
// Look for the FIRST expression containing this type
JetExpression outerExpression = PsiTreeUtil.getParentOfType(type, JetExpression.class);
if (outerExpression instanceof JetIsExpression) {
JetIsExpression isExpression = (JetIsExpression) outerExpression;
// If this expression is JetIsExpression, and the type is the outermost on the RHS
if (type.getParent() == isExpression.getTypeRef()) {
return true;
}
}
return false;
}
private JetScope getScopeForTypeParameter(final TypeParameterDescriptor typeParameterDescriptor, boolean checkBounds) {
if (checkBounds) {
return typeParameterDescriptor.getUpperBoundsAsType().getMemberScope();
@@ -317,4 +336,15 @@ public class TypeResolver {
}
return null;
}
@NotNull
private static String allStarProjectionsString(@NotNull TypeConstructor constructor) {
int size = constructor.getParameters().size();
assert size != 0 : "No projections possible for a nilary type constructor" + constructor;
ClassifierDescriptor declarationDescriptor = constructor.getDeclarationDescriptor();
assert declarationDescriptor != null : "No declaration descriptor for type constructor " + constructor;
String name = declarationDescriptor.getName().getName();
return TypeUtils.getTypeNameAndStarProjectionsString(name, size);
}
}
@@ -497,4 +497,18 @@ public class TypeUtils {
}
return false;
}
@NotNull
public static String getTypeNameAndStarProjectionsString(@NotNull String name, int size) {
StringBuilder builder = new StringBuilder(name);
builder.append("<");
for (int i = 0; i < size; i++) {
builder.append("*");
if (i == size - 1) break;
builder.append(", ");
}
builder.append(">");
return builder.toString();
}
}
@@ -0,0 +1,16 @@
package p
public fun foo(a: Any) {
a is Map<!WRONG_NUMBER_OF_TYPE_ARGUMENTS!><Int><!>
a is <!NO_TYPE_ARGUMENTS_ON_RHS_OF_IS_EXPRESSION!>Map<!>
a is Map<out Any?, Any?>
a is Map<*, *>
a is Map<<!SYNTAX!><!>>
a is <!CANNOT_CHECK_FOR_ERASED!>List<<!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>Map<!>><!>
a is <!NO_TYPE_ARGUMENTS_ON_RHS_OF_IS_EXPRESSION!>List<!>
a is Int
(a <!USELESS_CAST!>as<!> <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>Map<!>) is Int
}
@@ -15,13 +15,16 @@
*/
package org.jetbrains.jet.checkers;
import junit.framework.Assert;
import junit.framework.Test;
import junit.framework.TestSuite;
import java.io.File;
import org.jetbrains.jet.JetTestUtils;
import org.jetbrains.jet.test.InnerTestClasses;
import org.jetbrains.jet.test.TestMetadata;
import java.io.File;
import org.jetbrains.jet.checkers.AbstractDiagnosticsTestWithEagerResolve;
/** This class is generated by {@link org.jetbrains.jet.generators.tests.GenerateTests}. DO NOT MODIFY MANUALLY */
@InnerTestClasses({JetDiagnosticsTestGenerated.Tests.class, JetDiagnosticsTestGenerated.Script.class})
@@ -1766,6 +1769,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
doTest("compiler/testData/diagnostics/tests/generics/Projections.kt");
}
@TestMetadata("RawTypeInIsExpression.kt")
public void testRawTypeInIsExpression() throws Exception {
doTest("compiler/testData/diagnostics/tests/generics/RawTypeInIsExpression.kt");
}
@TestMetadata("RecursiveUpperBoundCheck.kt")
public void testRecursiveUpperBoundCheck() throws Exception {
doTest("compiler/testData/diagnostics/tests/generics/RecursiveUpperBoundCheck.kt");
@@ -15,13 +15,16 @@
*/
package org.jetbrains.jet.lang.resolve.lazy;
import junit.framework.Assert;
import junit.framework.Test;
import junit.framework.TestSuite;
import java.io.File;
import org.jetbrains.jet.JetTestUtils;
import org.jetbrains.jet.test.InnerTestClasses;
import org.jetbrains.jet.test.TestMetadata;
import java.io.File;
import org.jetbrains.jet.lang.resolve.lazy.AbstractLazyResolveNamespaceComparingTest;
/** This class is generated by {@link org.jetbrains.jet.generators.tests.GenerateTests}. DO NOT MODIFY MANUALLY */
@InnerTestClasses({LazyResolveNamespaceComparingTestGenerated.LoadKotlin.class, LazyResolveNamespaceComparingTestGenerated.LoadJava.class, LazyResolveNamespaceComparingTestGenerated.NamespaceComparator.class})