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