From 80039d85333d8558123c8dfef7886ad7717984d2 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Fri, 19 Oct 2012 18:37:04 +0400 Subject: [PATCH] A warning for redundant '?' in types --- .../jet/lang/diagnostics/Errors.java | 1 + .../rendering/DefaultErrorMessages.java | 1 + .../jet/lang/resolve/DescriptorResolver.java | 42 ++++++++++++------- .../jet/lang/resolve/TypeResolver.java | 17 ++++---- .../tests/ProjectionsInSupertypes.kt | 2 +- .../tests/nullableTypes/redundantNullable.kt | 9 ++++ .../redundantNullableInSupertype.kt | 8 ++++ .../checkers/JetDiagnosticsTestGenerated.java | 18 ++++++++ .../checker/ProjectionsInSupertypes.jet | 2 +- 9 files changed, 75 insertions(+), 25 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/nullableTypes/redundantNullable.kt create mode 100644 compiler/testData/diagnostics/tests/nullableTypes/redundantNullableInSupertype.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index 741515498a4..db02ff5c048 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -283,6 +283,7 @@ public interface Errors { SimpleDiagnosticFactory ANONYMOUS_INITIALIZER_WITHOUT_CONSTRUCTOR = SimpleDiagnosticFactory.create(ERROR); SimpleDiagnosticFactory NULLABLE_SUPERTYPE = SimpleDiagnosticFactory.create(ERROR, NULLABLE_TYPE); + SimpleDiagnosticFactory REDUNDANT_NULLABLE = SimpleDiagnosticFactory.create(WARNING, NULLABLE_TYPE); DiagnosticFactory1 UNSAFE_CALL = DiagnosticFactory1.create(ERROR); SimpleDiagnosticFactory AMBIGUOUS_LABEL = SimpleDiagnosticFactory.create(ERROR); DiagnosticFactory1 UNSUPPORTED = DiagnosticFactory1.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java index 16b5d3b7e1c..1ad2c160b3c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java @@ -306,6 +306,7 @@ public class DefaultErrorMessages { MAP.put(ANONYMOUS_INITIALIZER_WITHOUT_CONSTRUCTOR, "Anonymous initializers are only allowed in the presence of a primary constructor"); MAP.put(NULLABLE_SUPERTYPE, "A supertype cannot be nullable"); + MAP.put(REDUNDANT_NULLABLE, "Redundant '?'"); MAP.put(UNSAFE_CALL, "Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type {0}", RENDER_TYPE); MAP.put(AMBIGUOUS_LABEL, "Ambiguous label"); MAP.put(UNSUPPORTED, "Unsupported [{0}]", TO_STRING); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java index 07421d387d3..fcfbb212764 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java @@ -200,21 +200,8 @@ public class DescriptorResolver { JetTypeReference typeReference = delegationSpecifier.getTypeReference(); if (typeReference != null) { result.add(resolver.resolveType(extensibleScope, typeReference, trace, checkBounds)); - JetTypeElement typeElement = typeReference.getTypeElement(); - while (typeElement instanceof JetNullableType) { - JetNullableType nullableType = (JetNullableType) typeElement; - trace.report(NULLABLE_SUPERTYPE.on(nullableType)); - typeElement = nullableType.getInnerType(); - } - if (typeElement instanceof JetUserType) { - JetUserType userType = (JetUserType) typeElement; - List typeArguments = userType.getTypeArguments(); - for (JetTypeProjection typeArgument : typeArguments) { - if (typeArgument.getProjectionKind() != JetProjectionKind.NONE) { - trace.report(PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE.on(typeArgument)); - } - } - } + JetTypeElement bareSuperType = checkNullableSupertypeAndStripQuestionMarks(trace, typeReference.getTypeElement()); + checkProjectionsInImmediateArguments(trace, bareSuperType); } else { result.add(ErrorUtils.createErrorType("No type reference")); @@ -223,6 +210,31 @@ public class DescriptorResolver { return result; } + @Nullable + private static JetTypeElement checkNullableSupertypeAndStripQuestionMarks(@NotNull BindingTrace trace, @Nullable JetTypeElement typeElement) { + while (typeElement instanceof JetNullableType) { + JetNullableType nullableType = (JetNullableType) typeElement; + typeElement = nullableType.getInnerType(); + // report only for innermost '?', the rest gets a 'redundant' warning + if (!(typeElement instanceof JetNullableType)) { + trace.report(NULLABLE_SUPERTYPE.on(nullableType)); + } + } + return typeElement; + } + + private static void checkProjectionsInImmediateArguments(@NotNull BindingTrace trace, @Nullable JetTypeElement typeElement) { + if (typeElement instanceof JetUserType) { + JetUserType userType = (JetUserType) typeElement; + List typeArguments = userType.getTypeArguments(); + for (JetTypeProjection typeArgument : typeArguments) { + if (typeArgument.getProjectionKind() != JetProjectionKind.NONE) { + trace.report(PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE.on(typeArgument)); + } + } + } + } + @NotNull public SimpleFunctionDescriptor resolveFunctionDescriptor( DeclarationDescriptor containingDescriptor, diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java index 9a4d670cc25..5bf1197ff91 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java @@ -77,7 +77,7 @@ public class TypeResolver { final List annotations = annotationResolver.getResolvedAnnotations(typeReference.getAnnotations(), trace); JetTypeElement typeElement = typeReference.getTypeElement(); - JetType type = resolveTypeElement(scope, annotations, typeElement, false, trace, checkBounds); + JetType type = resolveTypeElement(scope, annotations, typeElement, trace, checkBounds); trace.record(BindingContext.TYPE, typeReference, type); trace.record(BindingContext.TYPE_RESOLUTION_SCOPE, typeReference, scope); @@ -86,7 +86,7 @@ public class TypeResolver { @NotNull private JetType resolveTypeElement(final JetScope scope, final List annotations, - JetTypeElement typeElement, final boolean nullable, final BindingTrace trace, final boolean checkBounds) { + JetTypeElement typeElement, final BindingTrace trace, final boolean checkBounds) { final JetType[] result = new JetType[1]; if (typeElement != null) { @@ -118,7 +118,7 @@ public class TypeResolver { result[0] = new JetTypeImpl( annotations, typeParameterDescriptor.getTypeConstructor(), - nullable || TypeUtils.hasNullableLowerBound(typeParameterDescriptor), + TypeUtils.hasNullableLowerBound(typeParameterDescriptor), Collections.emptyList(), scopeForTypeParameter ); @@ -151,7 +151,7 @@ public class TypeResolver { result[0] = new JetTypeImpl( annotations, typeConstructor, - nullable, + false, arguments, classDescriptor.getMemberScope(arguments) ); @@ -174,7 +174,11 @@ public class TypeResolver { @Override public void visitNullableType(JetNullableType nullableType) { - result[0] = resolveTypeElement(scope, annotations, nullableType.getInnerType(), true, trace, checkBounds); + JetType baseType = resolveTypeElement(scope, annotations, nullableType.getInnerType(), trace, checkBounds); + if (baseType.isNullable()) { + trace.report(REDUNDANT_NULLABLE.on(nullableType)); + } + result[0] = TypeUtils.makeNullable(baseType); } @Override @@ -222,9 +226,6 @@ public class TypeResolver { if (result[0] == null) { return ErrorUtils.createErrorType(typeElement == null ? "No type element" : typeElement.getText()); } - if (nullable) { - return TypeUtils.makeNullable(result[0]); - } return result[0]; } diff --git a/compiler/testData/diagnostics/tests/ProjectionsInSupertypes.kt b/compiler/testData/diagnostics/tests/ProjectionsInSupertypes.kt index 9d74079159d..03b68107997 100644 --- a/compiler/testData/diagnostics/tests/ProjectionsInSupertypes.kt +++ b/compiler/testData/diagnostics/tests/ProjectionsInSupertypes.kt @@ -3,4 +3,4 @@ trait B {} trait C {} trait D {} -trait Test : A<in Int>, B<out Int>, C<*>???, D {} +trait Test : A<in Int>, B<out Int>, C<*>???, D {} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/nullableTypes/redundantNullable.kt b/compiler/testData/diagnostics/tests/nullableTypes/redundantNullable.kt new file mode 100644 index 00000000000..cf75b008b94 --- /dev/null +++ b/compiler/testData/diagnostics/tests/nullableTypes/redundantNullable.kt @@ -0,0 +1,9 @@ +class Generic + +fun redundantNullable( + i: Int??, + three: Int???, + gOut: Generic??, + gIn: Generic?> +) { +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/nullableTypes/redundantNullableInSupertype.kt b/compiler/testData/diagnostics/tests/nullableTypes/redundantNullableInSupertype.kt new file mode 100644 index 00000000000..1b52fb5f78a --- /dev/null +++ b/compiler/testData/diagnostics/tests/nullableTypes/redundantNullableInSupertype.kt @@ -0,0 +1,8 @@ +trait X: Any?? { + +} + +fun interaction(t: T) { + if (t == null) {} + +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 203a9b3a443..22a5d648e1b 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -2288,6 +2288,24 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage } + @TestMetadata("compiler/testData/diagnostics/tests/nullableTypes") + public static class NullableTypes extends AbstractDiagnosticsTestWithEagerResolve { + public void testAllFilesPresentInNullableTypes() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.checkers.AbstractDiagnosticsTestWithEagerResolve", new File("compiler/testData/diagnostics/tests/nullableTypes"), "kt", true); + } + + @TestMetadata("redundantNullable.kt") + public void testRedundantNullable() throws Exception { + doTest("compiler/testData/diagnostics/tests/nullableTypes/redundantNullable.kt"); + } + + @TestMetadata("redundantNullableInSupertype.kt") + public void testRedundantNullableInSupertype() throws Exception { + doTest("compiler/testData/diagnostics/tests/nullableTypes/redundantNullableInSupertype.kt"); + } + + } + @TestMetadata("compiler/testData/diagnostics/tests/objects") public static class Objects extends AbstractDiagnosticsTestWithEagerResolve { public void testAllFilesPresentInObjects() throws Exception { diff --git a/idea/testData/checker/ProjectionsInSupertypes.jet b/idea/testData/checker/ProjectionsInSupertypes.jet index efddb978e07..02d64a69469 100644 --- a/idea/testData/checker/ProjectionsInSupertypes.jet +++ b/idea/testData/checker/ProjectionsInSupertypes.jet @@ -3,4 +3,4 @@ trait B {} trait C {} trait D {} -trait Test : A<in Int>, B<out Int>, C<*>???, D {} \ No newline at end of file +trait Test : A<in Int>, B<out Int>, C<*>???, D {} \ No newline at end of file