Implemented missed checks for local functions #KT-10449 Fixed
Relevant code/test fixes
This commit is contained in:
@@ -67,12 +67,23 @@ fun KtTypeReference.checkNotEnumEntry(trace: BindingTrace): Boolean {
|
||||
return result
|
||||
}
|
||||
|
||||
internal class DeclarationsCheckerBuilder(
|
||||
private val descriptorResolver: DescriptorResolver,
|
||||
private val originalModifiersChecker: ModifiersChecker,
|
||||
private val annotationChecker: AnnotationChecker,
|
||||
private val identifierChecker: IdentifierChecker
|
||||
) {
|
||||
fun withTrace(trace: BindingTrace) =
|
||||
DeclarationsChecker(descriptorResolver, originalModifiersChecker, annotationChecker, identifierChecker, trace)
|
||||
}
|
||||
|
||||
class DeclarationsChecker(
|
||||
private val descriptorResolver: DescriptorResolver,
|
||||
modifiersChecker: ModifiersChecker,
|
||||
private val annotationChecker: AnnotationChecker,
|
||||
private val identifierChecker: IdentifierChecker,
|
||||
private val trace: BindingTrace) {
|
||||
private val trace: BindingTrace
|
||||
) {
|
||||
|
||||
private val modifiersChecker = modifiersChecker.withTrace(trace)
|
||||
|
||||
@@ -612,7 +623,7 @@ class DeclarationsChecker(
|
||||
checkMemberReceiverExposedType(property.receiverTypeReference, propertyDescriptor)
|
||||
}
|
||||
|
||||
private fun checkFunction(function: KtNamedFunction, functionDescriptor: SimpleFunctionDescriptor) {
|
||||
fun checkFunction(function: KtNamedFunction, functionDescriptor: SimpleFunctionDescriptor) {
|
||||
val typeParameterList = function.typeParameterList
|
||||
val nameIdentifier = function.nameIdentifier
|
||||
if (typeParameterList != null && nameIdentifier != null &&
|
||||
@@ -754,20 +765,21 @@ class DeclarationsChecker(
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal fun checkVarargParameters(trace: BindingTrace, callableDescriptor: CallableDescriptor) {
|
||||
val numberOfVarargParameters = callableDescriptor.valueParameters.count { it.varargElementType != null }
|
||||
if (numberOfVarargParameters > 1) {
|
||||
for (parameter in callableDescriptor.valueParameters) {
|
||||
if (parameter.varargElementType != null) {
|
||||
val parameterDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(parameter)
|
||||
if (parameterDeclaration is KtParameter) {
|
||||
trace.report(MULTIPLE_VARARG_PARAMETERS.on(parameterDeclaration))
|
||||
}
|
||||
private fun checkVarargParameters(trace: BindingTrace, callableDescriptor: CallableDescriptor) {
|
||||
val numberOfVarargParameters = callableDescriptor.valueParameters.count { it.varargElementType != null }
|
||||
if (numberOfVarargParameters > 1) {
|
||||
for (parameter in callableDescriptor.valueParameters) {
|
||||
if (parameter.varargElementType != null) {
|
||||
val parameterDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(parameter)
|
||||
if (parameterDeclaration is KtParameter) {
|
||||
trace.report(MULTIPLE_VARARG_PARAMETERS.on(parameterDeclaration))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private fun removeDuplicateTypes(conflictingTypes: MutableSet<KotlinType>) {
|
||||
val iterator = conflictingTypes.iterator()
|
||||
|
||||
+6
@@ -55,6 +55,7 @@ public class ExpressionTypingComponents {
|
||||
/*package*/ DataFlowAnalyzer dataFlowAnalyzer;
|
||||
/*package*/ Iterable<CallChecker> callCheckers;
|
||||
/*package*/ IdentifierChecker identifierChecker;
|
||||
/*package*/ DeclarationsCheckerBuilder declarationsCheckerBuilder;
|
||||
|
||||
@Inject
|
||||
public void setGlobalContext(@NotNull GlobalContext globalContext) {
|
||||
@@ -175,4 +176,9 @@ public class ExpressionTypingComponents {
|
||||
public void setCallCheckers(@NotNull Iterable<CallChecker> callCheckers) {
|
||||
this.callCheckers = callCheckers;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setDeclarationsCheckerBuilder(@NotNull DeclarationsCheckerBuilder declarationsCheckerBuilder) {
|
||||
this.declarationsCheckerBuilder = declarationsCheckerBuilder;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -24,9 +24,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils;
|
||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.resolve.AnnotationChecker;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.BindingContextUtils;
|
||||
import org.jetbrains.kotlin.resolve.*;
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind;
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope;
|
||||
@@ -87,6 +85,7 @@ public abstract class ExpressionTypingVisitorDispatcher extends KtVisitor<Kotlin
|
||||
protected final FunctionsTypingVisitor functions;
|
||||
protected final ControlStructureTypingVisitor controlStructures;
|
||||
protected final PatternMatchingTypingVisitor patterns;
|
||||
protected final DeclarationsCheckerBuilder declarationsCheckerBuilder;
|
||||
|
||||
private ExpressionTypingVisitorDispatcher(
|
||||
@NotNull ExpressionTypingComponents components,
|
||||
@@ -98,6 +97,7 @@ public abstract class ExpressionTypingVisitorDispatcher extends KtVisitor<Kotlin
|
||||
this.controlStructures = new ControlStructureTypingVisitor(this);
|
||||
this.patterns = new PatternMatchingTypingVisitor(this);
|
||||
this.functions = new FunctionsTypingVisitor(this);
|
||||
this.declarationsCheckerBuilder = components.declarationsCheckerBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-4
@@ -106,10 +106,7 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre
|
||||
function.checkTypeReferences(context.trace)
|
||||
components.modifiersChecker.withTrace(context.trace).checkModifiersForLocalDeclaration(function, functionDescriptor)
|
||||
components.identifierChecker.checkDeclaration(function, context.trace)
|
||||
if (!function.hasBody() && !function.hasModifier(KtTokens.EXTERNAL_KEYWORD)) {
|
||||
context.trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor))
|
||||
}
|
||||
DeclarationsChecker.checkVarargParameters(context.trace, functionDescriptor)
|
||||
components.declarationsCheckerBuilder.withTrace(context.trace).checkFunction(function, functionDescriptor)
|
||||
|
||||
if (isStatement) {
|
||||
return createTypeInfo(components.dataFlowAnalyzer.checkStatementType(function, context), context)
|
||||
|
||||
Vendored
+1
-1
@@ -1,7 +1,7 @@
|
||||
fun box(): String {
|
||||
val obj = "" as java.lang.Object
|
||||
val e = IllegalArgumentException()
|
||||
fun m() = throw e
|
||||
fun m(): Nothing = throw e
|
||||
try {
|
||||
synchronized (m()) {
|
||||
throw AssertionError("Should not have reached this point")
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fun testInvoke() {
|
||||
operator fun Nothing.invoke() = this
|
||||
operator fun Nothing.invoke(): Nothing = this
|
||||
todo()<!UNREACHABLE_CODE!>()<!>
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -8,5 +8,8 @@ interface A3<K, <!BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER!>V<!>> where V
|
||||
interface A4<<!BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER!>K<!>, V> where K : I1, K : I2, K : C, K : V, V : I2, V : I1
|
||||
|
||||
fun <K, V> f1() where V : K, V : <!REPEATED_BOUND!>K<!> {}
|
||||
fun <K, V, W> f2() where W : K, W : <!BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER!>V<!> {}
|
||||
fun <K, V, W> f2() where W : K, W : <!BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER!>V<!> {
|
||||
fun <T> f3() where T : K, T : <!BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER!>V<!> {}
|
||||
fun <T> f4() where T : K, T : <!REPEATED_BOUND!>K<!> {}
|
||||
}
|
||||
fun <K, V, <!BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER!>W<!>> f3() where W : K, W : V, W : Any {}
|
||||
|
||||
@@ -19,5 +19,7 @@ class My(b: B) {
|
||||
fun bar(b: B): String {
|
||||
// Ok: local variable
|
||||
val tmp = if (b is A && b is C) b else null
|
||||
// Error: local function
|
||||
fun <!IMPLICIT_INTERSECTION_TYPE!>foo<!>(b: B) = if (b is A && b is C) b else null
|
||||
return tmp.toString()
|
||||
}
|
||||
+1
-1
@@ -12,7 +12,7 @@ val y: Nothing = throw Exception()
|
||||
|
||||
fun check() {
|
||||
// Error: KT-10449
|
||||
fun local() = bar()
|
||||
fun <!IMPLICIT_NOTHING_RETURN_TYPE!>local<!>() = bar()
|
||||
// Unreachable / unused, but not implicit Nothing
|
||||
<!UNREACHABLE_CODE!>val <!UNUSED_VARIABLE!>x<!> =<!> null!!
|
||||
}
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
fun foo<!DEPRECATED_TYPE_PARAMETER_SYNTAX!><T><!>() {
|
||||
fun bar<!DEPRECATED_TYPE_PARAMETER_SYNTAX!><T><!>() {}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
class Foo<<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>T : Cloneable<!>> where T : Comparable<T> {
|
||||
fun <<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>U : Cloneable<!>> foo(u: U): U where U: Comparable<U> {
|
||||
fun <<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS, BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER!>T: Any<!>> bar() where T: U {}
|
||||
return u
|
||||
}
|
||||
|
||||
|
||||
+9
-7
@@ -1,17 +1,19 @@
|
||||
interface I
|
||||
|
||||
fun foo() {
|
||||
abstract class T
|
||||
|
||||
<selection>fun <A, B, C> bar1(a: A, b: B, c: C): A where B: A, C: B, C: T = c</selection>
|
||||
<selection>fun <A, B, C> bar1(a: A, b: B, c: C): I where B: A, C: I, C: T = c</selection>
|
||||
|
||||
fun <X, Y: X, Z> bar2(x: X, y: Y, z: Z): X where Z: Y, Z: T = z
|
||||
fun <X, Y: X, Z> bar2(x: X, y: Y, z: Z): I where Z: I, Z: T = z
|
||||
|
||||
fun <X, Y, Z: Y> bar3(x: X, y: Y, z: Z): X where Y: X, Z: T = z
|
||||
fun <X, Y, Z: I> bar3(x: X, y: Y, z: Z): T where Y: X, Z: T = z
|
||||
|
||||
fun <X, Y: X, Z: Y> bar4(x: X, y: Y, z: Z): X where Z: T = z
|
||||
fun <X, Y: X, Z: I> bar4(x: X, y: Y, z: Z): T where Z: T = z
|
||||
|
||||
fun <X, Y: X, Z: T> bar5(x: X, y: Y, z: Z): X where Z: Y = z
|
||||
fun <X, Y: X, Z: T> bar5(x: X, y: Y, z: Z): I where Z: I = z
|
||||
|
||||
fun <X, Z: Y, Y> bar6(x: X, y: Y, z: Z): X where Y: X, Z: T = z
|
||||
fun <X, Z: I, Y> bar6(x: X, y: Y, z: Z): I where Y: X, Z: T = z
|
||||
|
||||
fun <X, Y: T, Z> bar7(x: X, y: Y, z: Z): X where Y: X, Z: Y, Z: T = z
|
||||
fun <X, Y: T, Z> bar7(x: X, y: Y, z: Z): T where Y: I, Z: I, Z: T = z
|
||||
}
|
||||
Vendored
+3
-7
@@ -1,9 +1,5 @@
|
||||
fun <A, B, C> bar1(a: A, b: B, c: C): A where B: A, C: B, C: T = c
|
||||
fun <A, B, C> bar1(a: A, b: B, c: C): I where B: A, C: I, C: T = c
|
||||
|
||||
fun <X, Y: X, Z> bar2(x: X, y: Y, z: Z): X where Z: Y, Z: T = z
|
||||
fun <X, Y: X, Z> bar2(x: X, y: Y, z: Z): I where Z: I, Z: T = z
|
||||
|
||||
fun <X, Y, Z: Y> bar3(x: X, y: Y, z: Z): X where Y: X, Z: T = z
|
||||
|
||||
fun <X, Y: X, Z: Y> bar4(x: X, y: Y, z: Z): X where Z: T = z
|
||||
|
||||
fun <X, Y: X, Z: T> bar5(x: X, y: Y, z: Z): X where Z: Y = z
|
||||
fun <X, Y: X, Z: T> bar5(x: X, y: Y, z: Z): I where Z: I = z
|
||||
@@ -968,7 +968,7 @@ class ArraysTest {
|
||||
assertTrue(arrayOf<Long>().sorted().none())
|
||||
assertEquals(listOf(1), arrayOf(1).sorted())
|
||||
|
||||
fun arrayData<A, T: Comparable<T>>(vararg values: T, toArray: Array<out T>.() -> A) = ArraySortedChecker<A, T>(values.toArray(), naturalOrder())
|
||||
fun <A, T: Comparable<T>> arrayData(vararg values: T, toArray: Array<out T>.() -> A) = ArraySortedChecker<A, T>(values.toArray(), naturalOrder())
|
||||
|
||||
with (arrayData("ac", "aD", "aba") { toList().toTypedArray() }) {
|
||||
checkSorted<List<String>>({ sorted() }, { sortedDescending() }, { iterator() })
|
||||
|
||||
Reference in New Issue
Block a user