Implemented missed checks for local functions #KT-10449 Fixed

Relevant code/test fixes
This commit is contained in:
Mikhail Glukhikh
2015-12-23 11:35:25 +03:00
parent 15746cbf56
commit 99a32b93fb
14 changed files with 58 additions and 38 deletions
@@ -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()
@@ -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;
}
}
@@ -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
@@ -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)
@@ -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,5 +1,5 @@
fun testInvoke() {
operator fun Nothing.invoke() = this
operator fun Nothing.invoke(): Nothing = this
todo()<!UNREACHABLE_CODE!>()<!>
}
@@ -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
View File
@@ -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
}
@@ -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
}
@@ -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() })