diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 9d57dbf2cbd..ed99c9b7006 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -547,6 +547,7 @@ public interface Errors { DiagnosticFactory0 INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION = DiagnosticFactory0.create(ERROR, DEFAULT); DiagnosticFactory2 COMPONENT_FUNCTION_MISSING = DiagnosticFactory2.create(ERROR, DEFAULT); + DiagnosticFactory1 COMPONENT_FUNCTION_ON_NULLABLE = DiagnosticFactory1.create(ERROR, DEFAULT); DiagnosticFactory2>> COMPONENT_FUNCTION_AMBIGUITY = DiagnosticFactory2.create(ERROR, DEFAULT); DiagnosticFactory3 COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH = DiagnosticFactory3.create(ERROR, DEFAULT); @@ -589,6 +590,7 @@ public interface Errors { DiagnosticFactory1 NEXT_NONE_APPLICABLE = DiagnosticFactory1.create(ERROR); DiagnosticFactory0 ITERATOR_MISSING = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 ITERATOR_ON_NULLABLE = DiagnosticFactory0.create(ERROR); DiagnosticFactory1>> ITERATOR_AMBIGUITY = DiagnosticFactory1.create(ERROR); DiagnosticFactory2 DELEGATE_SPECIAL_FUNCTION_MISSING = DiagnosticFactory2.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index f6eac8ca293..a7809882b2f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -214,6 +214,7 @@ public class DefaultErrorMessages { MAP.put(INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION, "Initializer required for destructuring declaration"); MAP.put(COMPONENT_FUNCTION_MISSING, "Destructuring declaration initializer of type {1} must have a ''{0}()'' function", TO_STRING, RENDER_TYPE); + MAP.put(COMPONENT_FUNCTION_ON_NULLABLE, "Not nullable value required to call ''{0}()'' function of destructuring declaration initializer", TO_STRING); MAP.put(COMPONENT_FUNCTION_AMBIGUITY, "Function ''{0}()'' is ambiguous for this expression: {1}", TO_STRING, AMBIGUOUS_CALLS); MAP.put(COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH, "''{0}()'' function returns ''{1}'', but ''{2}'' is expected", TO_STRING, RENDER_TYPE, RENDER_TYPE); @@ -368,6 +369,7 @@ public class DefaultErrorMessages { MAP.put(NEXT_NONE_APPLICABLE, "None of the next() functions is applicable for iterator() of type ''{0}''", RENDER_TYPE); MAP.put(ITERATOR_MISSING, "For-loop range must have an iterator() method"); + MAP.put(ITERATOR_ON_NULLABLE, "Not nullable value required to call an iterator() method on for-loop range"); MAP.put(ITERATOR_AMBIGUITY, "Method ''iterator()'' is ambiguous for this expression: {0}", AMBIGUOUS_CALLS); MAP.put(DELEGATE_SPECIAL_FUNCTION_MISSING, "Missing ''{0}'' method on delegate of type ''{1}''", STRING, RENDER_TYPE); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.java index d2cf7a0bf38..93e0ee0b8a9 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.java @@ -25,7 +25,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.diagnostics.Diagnostic; -import org.jetbrains.kotlin.diagnostics.Severity; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; @@ -39,8 +38,6 @@ import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt; import org.jetbrains.kotlin.util.slicedMap.*; import java.util.Collection; -import java.util.EnumMap; -import java.util.Map; import static org.jetbrains.kotlin.diagnostics.Errors.AMBIGUOUS_LABEL; import static org.jetbrains.kotlin.resolve.BindingContext.*; @@ -223,7 +220,7 @@ public class BindingContextUtils { map.forEach(new Function3() { @Override public Void invoke(WritableSlice slice, Object key, Object value) { - if (filter == null || filter.accept(slice, null, key)) { + if (filter == null || filter.accept(slice, key)) { trace.record(slice, key, value); } @@ -234,7 +231,7 @@ public class BindingContextUtils { if (!commitDiagnostics) return; for (Diagnostic diagnostic : diagnostics.getOwnDiagnostics()) { - if (filter == null || filter.accept(null, diagnostic, diagnostic.getPsiElement())) { + if (filter == null || filter.accept(null, diagnostic.getPsiElement())) { trace.report(diagnostic); } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java index 2720d14926c..b297cd15d34 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java @@ -23,7 +23,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.descriptors.*; -import org.jetbrains.kotlin.diagnostics.Diagnostic; import org.jetbrains.kotlin.diagnostics.rendering.Renderers; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.*; @@ -334,7 +333,7 @@ public class DelegatedPropertyResolver { dataFlowInfo, traceToResolveDelegatedProperty); traceToResolveDelegatedProperty.commit(new TraceEntryFilter() { @Override - public boolean accept(@Nullable WritableSlice slice, @Nullable Diagnostic diagnostic, Object key) { + public boolean accept(@Nullable WritableSlice slice, Object key) { return slice != CONSTRAINT_SYSTEM_COMPLETER; } }, true); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TraceEntryFilter.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TraceEntryFilter.java index 2e5a0577c40..914ebf18234 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TraceEntryFilter.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TraceEntryFilter.java @@ -17,9 +17,8 @@ package org.jetbrains.kotlin.resolve; import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.diagnostics.Diagnostic; import org.jetbrains.kotlin.util.slicedMap.WritableSlice; public interface TraceEntryFilter { - boolean accept(@Nullable WritableSlice slice, @Nullable Diagnostic diagnostic, Object key); + boolean accept(@Nullable WritableSlice slice, Object key); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java index 34476585649..e174e6c8447 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java @@ -17,7 +17,6 @@ package org.jetbrains.kotlin.types.expressions; import com.google.common.collect.Lists; -import com.intellij.openapi.util.Ref; import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; @@ -32,7 +31,6 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.Annotations; import org.jetbrains.kotlin.diagnostics.Diagnostic; -import org.jetbrains.kotlin.diagnostics.DiagnosticUtilsKt; import org.jetbrains.kotlin.diagnostics.Errors; import org.jetbrains.kotlin.lexer.KtKeywordToken; import org.jetbrains.kotlin.lexer.KtTokens; @@ -1181,7 +1179,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { traceInterpretingRightAsNullableAny.commit(new TraceEntryFilter() { @Override - public boolean accept(@Nullable WritableSlice slice, @Nullable Diagnostic diagnostic, Object key) { + public boolean accept(@Nullable WritableSlice slice, Object key) { // the type of the right (and sometimes left) expression isn't 'Any?' actually if ((key == right || key == left) && slice == EXPRESSION_TYPE_INFO) return false; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FakeCallResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FakeCallResolver.kt index 3fd6e67d6b9..6ee27c0288c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FakeCallResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FakeCallResolver.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.types.expressions import com.intellij.openapi.project.Project import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Severity import org.jetbrains.kotlin.name.Name @@ -28,10 +29,10 @@ import org.jetbrains.kotlin.psi.KtSimpleNameExpression import org.jetbrains.kotlin.resolve.TemporaryBindingTrace import org.jetbrains.kotlin.resolve.calls.CallResolver import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults +import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl import org.jetbrains.kotlin.resolve.calls.util.CallMaker import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.utils.doNothing import java.util.* enum class FakeCallKind { @@ -88,31 +89,34 @@ class FakeCallResolver( val fakeTrace = TemporaryBindingTrace.create(context.trace, "trace to resolve fake call for", name) val fakeBindingTrace = context.replaceBindingTrace(fakeTrace) - var hasUnreportedError = false - val result = makeAndResolveFakeCallInContext(receiver, fakeBindingTrace, valueArguments, name, callElement) { fake -> - fakeTrace.commit({ slice, diagnostic, key -> + var unreportedDiagnostic: Diagnostic? = null + val result = makeAndResolveFakeCallInContext(receiver, fakeBindingTrace, valueArguments, name, callElement) { fake, isSuccess -> + unreportedDiagnostic = fakeTrace.bindingContext.diagnostics.noSuppression().forElement(fake).firstOrNull { it.severity == Severity.ERROR } + + if (!isSuccess) return@makeAndResolveFakeCallInContext + + fakeTrace.commit({ slice, key -> // excluding all entries related to fake expression // convert all errors on this expression to ITERATOR_MISSING on callElement - val isFakeKey = key == fake - if (diagnostic?.severity == Severity.ERROR && isFakeKey) { - hasUnreportedError = true - } - !isFakeKey + key != fake }, true) } val resolutionResults = result.second - if ((!resolutionResults.isSuccess || hasUnreportedError) && reportErrorsOn != null) { + if ((!resolutionResults.isSuccess || unreportedDiagnostic != null) && reportErrorsOn != null) { + val isUnsafeCall = unreportedDiagnostic?.factory == Errors.UNSAFE_CALL val diagnostic = when (callKind) { FakeCallKind.ITERATOR -> when { resolutionResults.isAmbiguity -> Errors.ITERATOR_AMBIGUITY.on(reportErrorsOn, resolutionResults.resultingCalls) + isUnsafeCall -> Errors.ITERATOR_ON_NULLABLE.on(reportErrorsOn) else -> Errors.ITERATOR_MISSING.on(reportErrorsOn) } FakeCallKind.COMPONENT -> when { resolutionResults.isAmbiguity -> Errors.COMPONENT_FUNCTION_AMBIGUITY.on( reportErrorsOn, name, resolutionResults.resultingCalls) + isUnsafeCall -> Errors.COMPONENT_FUNCTION_ON_NULLABLE.on(reportErrorsOn, name) receiver != null -> Errors.COMPONENT_FUNCTION_MISSING.on(reportErrorsOn, name, receiver.type) else -> null } @@ -132,15 +136,13 @@ class FakeCallResolver( valueArguments: List, name: Name, callElement: KtExpression?, - onSuccess: (KtSimpleNameExpression) -> Unit = doNothing() + onComplete: (KtSimpleNameExpression, Boolean) -> Unit = { x, y -> } ): Pair> { val fake = KtPsiFactory(project).createSimpleName(name.asString()) val call = CallMaker.makeCallWithExpressions(callElement ?: fake, receiver, null, fake, valueArguments) val results = callResolver.resolveCallWithGivenName(context, call, fake, name) - if (results.isSuccess) { - onSuccess(fake) - } + onComplete(fake, results.isSuccess) return Pair(call, results) } diff --git a/compiler/testData/diagnostics/tests/controlStructures/ForLoopWithExtensionIteratorOnNullable.kt b/compiler/testData/diagnostics/tests/controlStructures/ForLoopWithExtensionIteratorOnNullable.kt index f98dcdfb41e..feb535e47e4 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/ForLoopWithExtensionIteratorOnNullable.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/ForLoopWithExtensionIteratorOnNullable.kt @@ -8,7 +8,7 @@ fun test() { // Error container.iterator() // for extension iterator, this code compiles, but should not - for (s in container) {} + for (s in container) {} } class OtherContainer(val k: K) { operator fun iterator(): Iterator = null!! @@ -17,5 +17,5 @@ class OtherContainer(val k: K) { fun test2() { val other: OtherContainer? = null // Error - for (s in other) {} + for (s in other) {} } diff --git a/compiler/testData/diagnostics/tests/controlStructures/forLoopWithNullableRange.kt b/compiler/testData/diagnostics/tests/controlStructures/forLoopWithNullableRange.kt index 5f34d4126d5..301875344bf 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/forLoopWithNullableRange.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/forLoopWithNullableRange.kt @@ -8,7 +8,7 @@ class It { } fun test(c: Coll?) { - for (x in c) {} + for (x in c) {} if (c != null) { for(x in c) {} diff --git a/compiler/testData/diagnostics/tests/dataClasses/extensionComponentsOnNullable.kt b/compiler/testData/diagnostics/tests/dataClasses/extensionComponentsOnNullable.kt index 038ca04ec79..a5661ab9f2f 100644 --- a/compiler/testData/diagnostics/tests/dataClasses/extensionComponentsOnNullable.kt +++ b/compiler/testData/diagnostics/tests/dataClasses/extensionComponentsOnNullable.kt @@ -7,7 +7,7 @@ operator fun Data.component2() = y fun foo(): Int { val d: Data? = null // An error must be here - val (x, y) = d + val (x, y) = d return x + y } @@ -16,6 +16,6 @@ data class NormalData(val x: T, val y: T) fun bar(): Int { val d: NormalData? = null // An error must be here - val (x, y) = d + val (x, y) = d return x + y } diff --git a/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/for.kt b/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/for.kt index 4dad6907875..ca8c0f7a26a 100644 --- a/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/for.kt +++ b/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/for.kt @@ -22,7 +22,7 @@ fun test() { val platformJ = J.staticJ for (x in platformNN) {} - for (x in platformN) {} + for (x in platformN) {} for (x in platformJ) {} } diff --git a/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/multiDeclaration.kt b/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/multiDeclaration.kt index 6ef4f06acd5..7d4acfccd85 100644 --- a/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/multiDeclaration.kt +++ b/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/multiDeclaration.kt @@ -27,6 +27,6 @@ fun test() { val platformJ = J.staticJ val (a1, b1) = platformNN - val (a2, b2) = platformN + val (a2, b2) = platformN val (a3, b3) = platformJ } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index 61431274bc2..3d3505e3a15 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -298,7 +298,7 @@ class QuickFixRegistrar : QuickFixContributor { NEXT_MISSING.registerFactory(CreateNextFunctionActionFactory) NEXT_NONE_APPLICABLE.registerFactory(CreateNextFunctionActionFactory) ITERATOR_MISSING.registerFactory(CreateIteratorFunctionActionFactory) - ITERATOR_MISSING.registerFactory(MissingIteratorExclExclFixFactory) + ITERATOR_ON_NULLABLE.registerFactory(MissingIteratorExclExclFixFactory) COMPONENT_FUNCTION_MISSING.registerFactory(CreateComponentFunctionActionFactory) DELEGATE_SPECIAL_FUNCTION_MISSING.registerFactory(CreatePropertyDelegateAccessorsActionFactory) diff --git a/idea/testData/quickfix/expressions/fixNullableWithExclExclAbsentWithBadIterator.kt b/idea/testData/quickfix/expressions/fixNullableWithExclExclAbsentWithBadIterator.kt index 0c01e962396..3ac3b280688 100644 --- a/idea/testData/quickfix/expressions/fixNullableWithExclExclAbsentWithBadIterator.kt +++ b/idea/testData/quickfix/expressions/fixNullableWithExclExclAbsentWithBadIterator.kt @@ -1,6 +1,6 @@ // "Add non-null asserted (!!) call" "false" // ACTION: Replace with a 'forEach' function call -// ERROR: For-loop range must have an iterator() method +// ERROR: Not nullable value required to call an iterator() method on for-loop range class Some { fun iterator(): Iterator = null!!