Fix overload resolution ambiguity for types intersection
There are two different forms of types intestion: 1. Type parameters with multiple bounds 2. Smart casts The problem was that when member scope of type intersection contained effective duplicates and that lead to overload resolution ambiguity in strange cases like `x.hashCode()` For first type we do effectively the same thing as when building member scope for class extending several interfaces: group all descriptors by both-way-overridability relation and then choose most-specific in each group. For smart casts we do basically the same thing but with special treatments: 1. From all descriptors that _equal_ to most specific we choose the one that works without smartcast if possible (i.e. we choose first from candidates list) 2. If smart-cast value seems to be unstable we use only member scope of receiver type + all descriptors from smart cast possible types that has incompatible signature. If we'd include all of them and choose one as more specific, and it would lead to false SMART_CAST_IMPOSIBLE (see test unstableSmartCast.kt) #KT-3996 Fixed #KT-10315 Fixed
This commit is contained in:
@@ -42,7 +42,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.*
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.getImplicitReceiversHierarchy
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsImportingScope
|
||||
import org.jetbrains.kotlin.resolve.validation.InfixValidator
|
||||
import org.jetbrains.kotlin.resolve.selectMostSpecificInEachOverridableGroup
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
@@ -251,6 +251,11 @@ public class TaskPrioritizer(
|
||||
c.context.call
|
||||
)
|
||||
}
|
||||
|
||||
if (explicitReceiver.types.size > 1) {
|
||||
members.retainAll( members.selectMostSpecificInEachOverridableGroup { descriptor } )
|
||||
}
|
||||
|
||||
members
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,11 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.hasClassValueDescriptor
|
||||
import org.jetbrains.kotlin.resolve.scopes.ImportingScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.ResolutionScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.*
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.CastImplicitClassReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.selectMostSpecificInEachOverridableGroup
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.isDynamic
|
||||
@@ -71,7 +75,7 @@ internal class ReceiverScopeTowerLevel(
|
||||
val dispatchReceiver: ReceiverValue
|
||||
): AbstractScopeTowerLevel(scopeTower) {
|
||||
|
||||
private fun <D: CallableDescriptor> collectMembers(
|
||||
private fun <D : CallableDescriptor> collectMembers(
|
||||
getMembers: ResolutionScope.(KotlinType?) -> Collection<D>
|
||||
): Collection<CandidateWithBoundDispatchReceiver<D>> {
|
||||
val result = ArrayList<CandidateWithBoundDispatchReceiver<D>>(0)
|
||||
@@ -81,13 +85,23 @@ internal class ReceiverScopeTowerLevel(
|
||||
|
||||
val smartCastPossibleTypes = scopeTower.dataFlowInfo.getSmartCastTypes(dispatchReceiver)
|
||||
val unstableError = if (scopeTower.dataFlowInfo.isStableReceiver(dispatchReceiver)) null else UnstableSmartCastDiagnostic
|
||||
val unstableCandidates = if (unstableError != null) ArrayList<CandidateWithBoundDispatchReceiver<D>>(0) else null
|
||||
|
||||
for (possibleType in smartCastPossibleTypes) {
|
||||
possibleType.memberScope.getMembers(possibleType).mapTo(result) {
|
||||
possibleType.memberScope.getMembers(possibleType).mapTo(unstableCandidates ?: result) {
|
||||
createCandidateDescriptor(it, dispatchReceiver.smartCastReceiver(possibleType), unstableError, dispatchReceiverSmartCastType = possibleType)
|
||||
}
|
||||
}
|
||||
|
||||
if (smartCastPossibleTypes.isNotEmpty()) {
|
||||
if (unstableCandidates == null) {
|
||||
result.retainAll(result.selectMostSpecificInEachOverridableGroup { descriptor })
|
||||
}
|
||||
else {
|
||||
result.addAll(unstableCandidates.selectMostSpecificInEachOverridableGroup { descriptor })
|
||||
}
|
||||
}
|
||||
|
||||
if (dispatchReceiver.type.isDynamic()) {
|
||||
scopeTower.dynamicScope.getMembers(null).mapTo(result) {
|
||||
createCandidateDescriptor(it, dispatchReceiver, DynamicDescriptorDiagnostic)
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem;
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl;
|
||||
import org.jetbrains.kotlin.resolve.scopes.ChainedScope;
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
|
||||
import org.jetbrains.kotlin.resolve.scopes.TypeIntersectionScope;
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
||||
|
||||
import java.util.*;
|
||||
@@ -124,19 +125,12 @@ public class TypeIntersector {
|
||||
|
||||
TypeConstructor constructor = new IntersectionTypeConstructor(Annotations.Companion.getEMPTY(), resultingTypes);
|
||||
|
||||
MemberScope[] scopes = new MemberScope[resultingTypes.size()];
|
||||
int i = 0;
|
||||
for (KotlinType type : resultingTypes) {
|
||||
scopes[i] = type.getMemberScope();
|
||||
i++;
|
||||
}
|
||||
|
||||
return KotlinTypeImpl.create(
|
||||
Annotations.Companion.getEMPTY(),
|
||||
constructor,
|
||||
allNullable,
|
||||
Collections.<TypeProjection>emptyList(),
|
||||
new ChainedScope("member scope for intersection type " + constructor, scopes)
|
||||
TypeIntersectionScope.create("member scope for intersection type " + constructor, resultingTypes)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
interface A {
|
||||
fun foo(): Any?
|
||||
fun bar(): String
|
||||
}
|
||||
|
||||
interface B {
|
||||
fun foo(): String
|
||||
}
|
||||
|
||||
fun <T> bar(x: T): String where T : A, T : B {
|
||||
if (x.foo().length != 2 || x.foo() != "OK") return "fail 1"
|
||||
if (x.bar() != "ok") return "fail 2"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
class C : A, B {
|
||||
override fun foo() = "OK"
|
||||
override fun bar() = "ok"
|
||||
}
|
||||
|
||||
fun box(): String = bar(C())
|
||||
@@ -0,0 +1,27 @@
|
||||
interface A {
|
||||
fun foo(): Any?
|
||||
}
|
||||
|
||||
interface B {
|
||||
fun foo(): String
|
||||
}
|
||||
|
||||
fun bar(x: Any?): String {
|
||||
if (x is A) {
|
||||
val k = x.foo()
|
||||
if (k != "OK") return "fail 1"
|
||||
}
|
||||
|
||||
if (x is B) {
|
||||
val k = x.foo()
|
||||
if (k.length != 2) return "fail 2"
|
||||
}
|
||||
|
||||
if (x is A && x is B) {
|
||||
return x.foo()
|
||||
}
|
||||
|
||||
return "fail 4"
|
||||
}
|
||||
|
||||
fun box(): String = bar(object : A, B { override fun foo() = "OK" })
|
||||
@@ -10,6 +10,6 @@ open class SuperFoo {
|
||||
|
||||
class Foo : SuperFoo()
|
||||
|
||||
// 0 INVOKEVIRTUAL SuperFoo.baz
|
||||
// 1 CHECKCAST Foo
|
||||
// 1 INVOKEVIRTUAL Foo.baz
|
||||
// 1 INVOKEVIRTUAL SuperFoo.baz
|
||||
// 0 CHECKCAST Foo
|
||||
// 0 INVOKEVIRTUAL Foo.baz
|
||||
Vendored
+1
-1
@@ -10,7 +10,7 @@ class C() {
|
||||
fun test(a : Any?) {
|
||||
if (a is B) {
|
||||
if (a is C) {
|
||||
a.<!OVERLOAD_RESOLUTION_AMBIGUITY!>bar<!>();
|
||||
<!DEBUG_INFO_SMARTCAST!>a<!>.bar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
// !CHECK_TYPE
|
||||
|
||||
interface A {
|
||||
fun foo(): CharSequence
|
||||
}
|
||||
|
||||
interface B {
|
||||
fun foo(): String?
|
||||
}
|
||||
|
||||
fun <T> test(x: T) where T : B, T : A {
|
||||
x.<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!>()
|
||||
}
|
||||
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
package
|
||||
|
||||
public fun </*0*/ T : B> test(/*0*/ x: T): kotlin.Unit where T : A
|
||||
|
||||
public interface A {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): kotlin.CharSequence
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface B {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): kotlin.String?
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// !CHECK_TYPE
|
||||
// FILE: A.java
|
||||
public interface A {
|
||||
String foo();
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
|
||||
interface B {
|
||||
fun foo(): String?
|
||||
}
|
||||
|
||||
interface C {
|
||||
fun foo(): String
|
||||
}
|
||||
|
||||
fun <T> test(x: T) where T : B, T : A, T : C {
|
||||
x.foo().checkType { _<String>() }
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package
|
||||
|
||||
public /*synthesized*/ fun A(/*0*/ function: () -> kotlin.String!): A
|
||||
public fun </*0*/ T : B> test(/*0*/ x: T): kotlin.Unit where T : A, T : C
|
||||
|
||||
public interface A {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): kotlin.String!
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface B {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): kotlin.String?
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface C {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// !CHECK_TYPE
|
||||
|
||||
interface A {
|
||||
fun foo(): CharSequence?
|
||||
}
|
||||
|
||||
interface B {
|
||||
fun foo(): String
|
||||
}
|
||||
|
||||
fun <T> test(x: T) where T : B, T : A {
|
||||
x.foo().checkType { _<String>() }
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package
|
||||
|
||||
public fun </*0*/ T : B> test(/*0*/ x: T): kotlin.Unit where T : A
|
||||
|
||||
public interface A {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): kotlin.CharSequence?
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface B {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// !CHECK_TYPE
|
||||
|
||||
interface A {
|
||||
val foo: Any?
|
||||
}
|
||||
|
||||
interface C: A {
|
||||
override val foo: String?
|
||||
}
|
||||
interface B: A {
|
||||
override var foo: String
|
||||
}
|
||||
|
||||
fun <T> test(a: T) where T : B, T : C {
|
||||
a.foo = ""
|
||||
a.foo = <!NULL_FOR_NONNULL_TYPE!>null<!>
|
||||
|
||||
a.foo.checkType { _<String>() }
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package
|
||||
|
||||
public fun </*0*/ T : B> test(/*0*/ a: T): kotlin.Unit where T : C
|
||||
|
||||
public interface A {
|
||||
public abstract val foo: kotlin.Any?
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface B : A {
|
||||
public abstract override /*1*/ var foo: kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface C : A {
|
||||
public abstract override /*1*/ val foo: kotlin.String?
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
// !CHECK_TYPE
|
||||
|
||||
interface A {
|
||||
val foo: Any?
|
||||
}
|
||||
|
||||
interface C: A {
|
||||
override val foo: String
|
||||
}
|
||||
interface B: A {
|
||||
override var foo: String?
|
||||
}
|
||||
|
||||
fun <T> test(a: T) where T : B, T : C {
|
||||
a.<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!> = ""
|
||||
a.<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!> = null
|
||||
|
||||
a.<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!>.<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>checkType<!> { <!UNRESOLVED_REFERENCE!>_<!><String>() }
|
||||
}
|
||||
Vendored
+24
@@ -0,0 +1,24 @@
|
||||
package
|
||||
|
||||
public fun </*0*/ T : B> test(/*0*/ a: T): kotlin.Unit where T : C
|
||||
|
||||
public interface A {
|
||||
public abstract val foo: kotlin.Any?
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface B : A {
|
||||
public abstract override /*1*/ var foo: kotlin.String?
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface C : A {
|
||||
public abstract override /*1*/ val foo: kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
interface A {
|
||||
fun foo()
|
||||
}
|
||||
|
||||
interface C: A
|
||||
interface B: A
|
||||
|
||||
fun <T> test(x: T) where T : C?, T : B? {
|
||||
x?.foo()
|
||||
if (x != null) {
|
||||
<!DEBUG_INFO_SMARTCAST!>x<!>.foo()
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package
|
||||
|
||||
public fun </*0*/ T : C?> test(/*0*/ x: T): kotlin.Unit where T : B?
|
||||
|
||||
public interface A {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface B : A {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface C : A {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
// !CHECK_TYPE
|
||||
|
||||
interface A {
|
||||
fun <T, E> foo(): E
|
||||
}
|
||||
|
||||
interface B {
|
||||
fun <Q, W> foo(): W
|
||||
}
|
||||
|
||||
fun <T> test(x: T) where T : B, T : A {
|
||||
x.foo<String, Int>().checkType { _<Int>() }
|
||||
}
|
||||
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
package
|
||||
|
||||
public fun </*0*/ T : B> test(/*0*/ x: T): kotlin.Unit where T : A
|
||||
|
||||
public interface A {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun </*0*/ T, /*1*/ E> foo(): E
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface B {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun </*0*/ Q, /*1*/ W> foo(): W
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -27,7 +27,7 @@ fun <T : CharSequence?> foo(x: T) {
|
||||
|
||||
if (x is String) {
|
||||
<!DEBUG_INFO_SMARTCAST!>x<!>.length
|
||||
<!DEBUG_INFO_SMARTCAST!>x<!><!UNNECESSARY_SAFE_CALL!>?.<!>length
|
||||
x<!UNNECESSARY_SAFE_CALL!>?.<!>length
|
||||
|
||||
<!DEBUG_INFO_SMARTCAST!>x<!>.bar1()
|
||||
x.bar2()
|
||||
|
||||
+2
-2
@@ -31,6 +31,6 @@ import p.*
|
||||
|
||||
fun test(b: B<String>?) {
|
||||
if (b is C) {
|
||||
<!DEBUG_INFO_SMARTCAST!>b<!>?.foo("")
|
||||
b?.foo("")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -33,6 +33,6 @@ import p.*
|
||||
|
||||
fun test(b: B<Tr>?) {
|
||||
if (b is C) {
|
||||
<!DEBUG_INFO_SMARTCAST!>b<!>?.foo(null)
|
||||
b?.foo(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParamsNameMismatch.kt
Vendored
+2
-2
@@ -31,6 +31,6 @@ import p.*
|
||||
|
||||
fun <Y> test(b: B<Y>?, y: Y) {
|
||||
if (b is C) {
|
||||
<!DEBUG_INFO_SMARTCAST!>b<!>?.foo(y)
|
||||
b?.foo(y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -31,6 +31,6 @@ import p.*
|
||||
|
||||
fun test(b: B<String>?) {
|
||||
if (b is C) {
|
||||
<!DEBUG_INFO_SMARTCAST!>b<!>?.foo()
|
||||
b?.foo()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -31,6 +31,6 @@ import p.*
|
||||
|
||||
fun test(b: B?) {
|
||||
if (b is C) {
|
||||
b?.<!OVERLOAD_RESOLUTION_AMBIGUITY!>getParent<!>()
|
||||
<!DEBUG_INFO_SMARTCAST!>b<!>?.getParent()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -31,6 +31,6 @@ import p.*
|
||||
|
||||
fun test(b: B?) {
|
||||
if (b is C) {
|
||||
<!DEBUG_INFO_SMARTCAST!>b<!>?.foo(1, "")
|
||||
b?.foo(1, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -31,6 +31,6 @@ import p.*
|
||||
|
||||
fun B.test() {
|
||||
if (this is C) {
|
||||
"".<!DEBUG_INFO_IMPLICIT_RECEIVER_SMARTCAST!>getParent<!>()
|
||||
"".getParent()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+3
-3
@@ -31,12 +31,12 @@ import p.*
|
||||
|
||||
fun test(b: B?) {
|
||||
if (b is C) {
|
||||
<!DEBUG_INFO_SMARTCAST!>b<!>?.foo<String>("")
|
||||
b?.foo<String>("")
|
||||
}
|
||||
}
|
||||
|
||||
fun test1(b: B?) {
|
||||
if (b is C) {
|
||||
<!DEBUG_INFO_SMARTCAST!>b<!>?.foo("")
|
||||
b?.foo("")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+3
-3
@@ -31,10 +31,10 @@ import p.*
|
||||
|
||||
fun test(b: B?) {
|
||||
if (b !is C) return
|
||||
<!DEBUG_INFO_SMARTCAST!>b<!>?.foo("")
|
||||
b?.foo("")
|
||||
}
|
||||
|
||||
fun test1(b: B?) {
|
||||
if (b !is C) return
|
||||
<!DEBUG_INFO_SMARTCAST!>b<!>?.foo<String>("")
|
||||
}
|
||||
b?.foo<String>("")
|
||||
}
|
||||
|
||||
+2
-2
@@ -35,10 +35,10 @@ import p.*
|
||||
|
||||
fun test(b: B?) {
|
||||
if (b !is C) return
|
||||
<!DEBUG_INFO_SMARTCAST!>b<!>?.foo("")
|
||||
b?.foo("")
|
||||
}
|
||||
|
||||
fun test1(b: B?) {
|
||||
if (b !is C) return
|
||||
<!DEBUG_INFO_SMARTCAST!>b<!>?.foo<String>("")
|
||||
b?.foo<String>("")
|
||||
}
|
||||
Vendored
+3
-3
@@ -31,10 +31,10 @@ import p.*
|
||||
|
||||
fun test(b: B?) {
|
||||
if (b !is C) return
|
||||
<!DEBUG_INFO_SMARTCAST!>b<!>?.foo("")
|
||||
b?.foo("")
|
||||
}
|
||||
|
||||
fun test1(b: B?) {
|
||||
if (b !is C) return
|
||||
<!DEBUG_INFO_SMARTCAST!>b<!>?.foo<String>("")
|
||||
}
|
||||
b?.foo<String>("")
|
||||
}
|
||||
|
||||
+2
-2
@@ -30,6 +30,6 @@ import p.*
|
||||
|
||||
fun test(b: B?) {
|
||||
if (b is C) {
|
||||
<!DEBUG_INFO_SMARTCAST!>b<!>?.foo(1, "")
|
||||
b?.foo(1, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -31,6 +31,6 @@ import p.*
|
||||
|
||||
fun test(b: B?) {
|
||||
if (b is C) {
|
||||
<!DEBUG_INFO_SMARTCAST!>b<!>?.getParent()
|
||||
b?.getParent()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -38,6 +38,6 @@ import p.*
|
||||
|
||||
fun test(b: B?, a: G1<Int>, b1: G2<B, String>) {
|
||||
if (b is C) {
|
||||
<!DEBUG_INFO_SMARTCAST!>b<!>?.foo(a, b1)
|
||||
b?.foo(a, b1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -33,6 +33,6 @@ import p.*
|
||||
|
||||
fun test(b: B?) {
|
||||
if (b is C && b is D) {
|
||||
b<!UNNECESSARY_SAFE_CALL!>?.<!><!OVERLOAD_RESOLUTION_AMBIGUITY!>getParent<!>()
|
||||
b<!UNNECESSARY_SAFE_CALL!>?.<!>getParent()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -29,6 +29,6 @@ import p.*
|
||||
|
||||
fun test(b: B?) {
|
||||
if (b is C) {
|
||||
b<!UNNECESSARY_SAFE_CALL!>?.<!><!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!>("")
|
||||
b<!UNNECESSARY_SAFE_CALL!>?.<!>foo("")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ class C() {
|
||||
fun test(a : Any?) {
|
||||
if (a is B) {
|
||||
if (a is C) {
|
||||
a.<!OVERLOAD_RESOLUTION_AMBIGUITY!>bar<!>();
|
||||
<!DEBUG_INFO_SMARTCAST!>a<!>.bar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
open class A {
|
||||
open fun foo() = "FAIL"
|
||||
|
||||
fun bar() = if (this is C) <!DEBUG_INFO_IMPLICIT_RECEIVER_SMARTCAST!>foo<!>() else "FAIL"
|
||||
fun bar() = if (this is C) foo() else "FAIL"
|
||||
}
|
||||
|
||||
open class B : A()
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
interface A {
|
||||
fun <T, E> foo(): E
|
||||
}
|
||||
|
||||
interface B {
|
||||
fun <Q, W> foo(): Q
|
||||
}
|
||||
|
||||
fun test(c: Any) {
|
||||
if (c is B && c is A) {
|
||||
c.<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!><String, Int>()
|
||||
}
|
||||
}
|
||||
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
package
|
||||
|
||||
public fun test(/*0*/ c: kotlin.Any): kotlin.Unit
|
||||
|
||||
public interface A {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun </*0*/ T, /*1*/ E> foo(): E
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface B {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun </*0*/ Q, /*1*/ W> foo(): Q
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// !CHECK_TYPE
|
||||
|
||||
interface A {
|
||||
fun foo(): CharSequence
|
||||
}
|
||||
|
||||
interface B {
|
||||
fun foo(): String?
|
||||
}
|
||||
|
||||
fun test(c: Any) {
|
||||
if (c is B && c is A) {
|
||||
c.<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!>()
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package
|
||||
|
||||
public fun test(/*0*/ c: kotlin.Any): kotlin.Unit
|
||||
|
||||
public interface A {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): kotlin.CharSequence
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface B {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): kotlin.String?
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
// !CHECK_TYPE
|
||||
// FILE: A.java
|
||||
public interface A {
|
||||
String foo();
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
|
||||
interface B {
|
||||
fun foo(): String?
|
||||
}
|
||||
|
||||
interface C {
|
||||
fun foo(): String
|
||||
}
|
||||
|
||||
fun foo(x: Any?) {
|
||||
if (x is A && x is B) {
|
||||
<!DEBUG_INFO_SMARTCAST!>x<!>.foo().checkType { <!TYPE_MISMATCH!>_<!><String>() }
|
||||
<!DEBUG_INFO_SMARTCAST!>x<!>.foo().checkType { _<String?>() }
|
||||
}
|
||||
|
||||
if (x is B && x is A) {
|
||||
<!DEBUG_INFO_SMARTCAST!>x<!>.foo().checkType { <!TYPE_MISMATCH!>_<!><String>() }
|
||||
<!DEBUG_INFO_SMARTCAST!>x<!>.foo().checkType { _<String?>() }
|
||||
}
|
||||
|
||||
if (x is A && x is C) {
|
||||
<!DEBUG_INFO_SMARTCAST!>x<!>.foo().checkType { _<String>() }
|
||||
<!DEBUG_INFO_SMARTCAST!>x<!>.foo().checkType { <!TYPE_MISMATCH!>_<!><String?>() }
|
||||
}
|
||||
|
||||
if (x is C && x is A) {
|
||||
<!DEBUG_INFO_SMARTCAST!>x<!>.foo().checkType { _<String>() }
|
||||
<!DEBUG_INFO_SMARTCAST!>x<!>.foo().checkType { <!TYPE_MISMATCH!>_<!><String?>() }
|
||||
}
|
||||
|
||||
if (x is A && x is B && x is C) {
|
||||
<!DEBUG_INFO_SMARTCAST!>x<!>.foo().checkType { _<String>() }
|
||||
<!DEBUG_INFO_SMARTCAST!>x<!>.foo().checkType { <!TYPE_MISMATCH!>_<!><String?>() }
|
||||
}
|
||||
|
||||
if (x is B && x is A && x is C) {
|
||||
<!DEBUG_INFO_SMARTCAST!>x<!>.foo().checkType { _<String>() }
|
||||
<!DEBUG_INFO_SMARTCAST!>x<!>.foo().checkType { <!TYPE_MISMATCH!>_<!><String?>() }
|
||||
}
|
||||
|
||||
if (x is B && x is C && x is A) {
|
||||
<!DEBUG_INFO_SMARTCAST!>x<!>.foo().checkType { _<String>() }
|
||||
<!DEBUG_INFO_SMARTCAST!>x<!>.foo().checkType { <!TYPE_MISMATCH!>_<!><String?>() }
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package
|
||||
|
||||
public /*synthesized*/ fun A(/*0*/ function: () -> kotlin.String!): A
|
||||
public fun foo(/*0*/ x: kotlin.Any?): kotlin.Unit
|
||||
|
||||
public interface A {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): kotlin.String!
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface B {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): kotlin.String?
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface C {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// !CHECK_TYPE
|
||||
|
||||
interface Common {
|
||||
fun foo(): CharSequence?
|
||||
}
|
||||
|
||||
interface A : Common {
|
||||
override fun foo(): CharSequence
|
||||
}
|
||||
|
||||
interface B : Common {
|
||||
override fun foo(): String
|
||||
}
|
||||
|
||||
fun test(c: Common) {
|
||||
if (c is B && c is A) {
|
||||
<!DEBUG_INFO_SMARTCAST!>c<!>.foo().checkType { _<String>() }
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package
|
||||
|
||||
public fun test(/*0*/ c: Common): kotlin.Unit
|
||||
|
||||
public interface A : Common {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract override /*1*/ fun foo(): kotlin.CharSequence
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface B : Common {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract override /*1*/ fun foo(): kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface Common {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): kotlin.CharSequence?
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// !CHECK_TYPE
|
||||
|
||||
interface A {
|
||||
fun foo(): CharSequence?
|
||||
}
|
||||
|
||||
interface B {
|
||||
fun foo(): String
|
||||
}
|
||||
|
||||
fun test(c: Any) {
|
||||
if (c is B && c is A) {
|
||||
<!DEBUG_INFO_SMARTCAST!>c<!>.foo().checkType { _<String>() }
|
||||
}
|
||||
}
|
||||
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
package
|
||||
|
||||
public fun test(/*0*/ c: kotlin.Any): kotlin.Unit
|
||||
|
||||
public interface A {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): kotlin.CharSequence?
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface B {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// !CHECK_TYPE
|
||||
|
||||
interface A {
|
||||
val foo: Any?
|
||||
}
|
||||
|
||||
interface C: A {
|
||||
override val foo: String?
|
||||
}
|
||||
interface B: A {
|
||||
override var foo: String
|
||||
}
|
||||
|
||||
fun test(a: A) {
|
||||
if (a is B && a is C) {
|
||||
<!DEBUG_INFO_SMARTCAST!>a<!>.foo = ""
|
||||
<!DEBUG_INFO_SMARTCAST!>a<!>.foo = <!NULL_FOR_NONNULL_TYPE!>null<!>
|
||||
|
||||
<!DEBUG_INFO_SMARTCAST!>a<!>.foo.checkType { _<String>() }
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package
|
||||
|
||||
public fun test(/*0*/ a: A): kotlin.Unit
|
||||
|
||||
public interface A {
|
||||
public abstract val foo: kotlin.Any?
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface B : A {
|
||||
public abstract override /*1*/ var foo: kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface C : A {
|
||||
public abstract override /*1*/ val foo: kotlin.String?
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// !CHECK_TYPE
|
||||
|
||||
interface A {
|
||||
val foo: Any?
|
||||
}
|
||||
|
||||
interface C: A {
|
||||
override val foo: String
|
||||
}
|
||||
interface B: A {
|
||||
override var foo: String?
|
||||
}
|
||||
|
||||
fun test(a: A) {
|
||||
if (a is B && a is C) {
|
||||
a.<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!> = ""
|
||||
a.<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!> = null
|
||||
a.<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!>
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package
|
||||
|
||||
public fun test(/*0*/ a: A): kotlin.Unit
|
||||
|
||||
public interface A {
|
||||
public abstract val foo: kotlin.Any?
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface B : A {
|
||||
public abstract override /*1*/ var foo: kotlin.String?
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface C : A {
|
||||
public abstract override /*1*/ val foo: kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// !CHECK_TYPE
|
||||
|
||||
interface A {
|
||||
fun foo(): CharSequence?
|
||||
}
|
||||
|
||||
interface B : A {
|
||||
override fun foo(): String
|
||||
}
|
||||
|
||||
fun test(a: A) {
|
||||
if (a is B) {
|
||||
<!DEBUG_INFO_SMARTCAST!>a<!>.foo()
|
||||
<!DEBUG_INFO_SMARTCAST!>a<!>.foo().checkType { _<String>() }
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package
|
||||
|
||||
public fun test(/*0*/ a: A): kotlin.Unit
|
||||
|
||||
public interface A {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): kotlin.CharSequence?
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface B : A {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract override /*1*/ fun foo(): kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
interface A {
|
||||
fun foo()
|
||||
}
|
||||
|
||||
interface C: A
|
||||
interface B: A
|
||||
|
||||
fun test(c: C) {
|
||||
if (c is B) {
|
||||
c.foo() // OVERLOAD_RESOLUTION_AMBIGUITY: B.foo() and C.foo()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package
|
||||
|
||||
public fun test(/*0*/ c: C): kotlin.Unit
|
||||
|
||||
public interface A {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface B : A {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface C : A {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
// !CHECK_TYPE
|
||||
|
||||
interface A {
|
||||
fun foo(): CharSequence?
|
||||
fun baz(x: Any) {}
|
||||
}
|
||||
|
||||
interface B {
|
||||
fun foo(): String
|
||||
fun baz(x: Int): String =""
|
||||
fun baz(x: Int, y: Int) {}
|
||||
|
||||
fun foobar(): CharSequence?
|
||||
}
|
||||
|
||||
interface C {
|
||||
fun foo(): String
|
||||
fun baz(x: Int): String =""
|
||||
fun baz(x: Int, y: Int) {}
|
||||
|
||||
fun foobar(): String
|
||||
}
|
||||
|
||||
var x: A = null!!
|
||||
|
||||
fun test() {
|
||||
x.foo().checkType { _<CharSequence?>() }
|
||||
|
||||
if (x is B && x is C) {
|
||||
x.foo().checkType { _<CharSequence?>() }
|
||||
x.baz("")
|
||||
x.baz(1).checkType { _<Unit>() }
|
||||
<!SMARTCAST_IMPOSSIBLE!>x<!>.baz(1, 2)
|
||||
|
||||
<!SMARTCAST_IMPOSSIBLE!>x<!>.foobar().checkType { _<String>() }
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package
|
||||
|
||||
public var x: A
|
||||
public fun test(): kotlin.Unit
|
||||
|
||||
public interface A {
|
||||
public open fun baz(/*0*/ x: kotlin.Any): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): kotlin.CharSequence?
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface B {
|
||||
public open fun baz(/*0*/ x: kotlin.Int): kotlin.String
|
||||
public open fun baz(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): kotlin.String
|
||||
public abstract fun foobar(): kotlin.CharSequence?
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface C {
|
||||
public open fun baz(/*0*/ x: kotlin.Int): kotlin.String
|
||||
public open fun baz(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): kotlin.String
|
||||
public abstract fun foobar(): kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// !CHECK_TYPE
|
||||
|
||||
interface A {
|
||||
fun <T, E> foo(): E
|
||||
}
|
||||
|
||||
interface B {
|
||||
fun <Q, W> foo(): W
|
||||
}
|
||||
|
||||
fun test(c: Any) {
|
||||
if (c is B && c is A) {
|
||||
<!DEBUG_INFO_SMARTCAST!>c<!>.foo<String, Int>().checkType { _<Int>() }
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package
|
||||
|
||||
public fun test(/*0*/ c: kotlin.Any): kotlin.Unit
|
||||
|
||||
public interface A {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun </*0*/ T, /*1*/ E> foo(): E
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface B {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun </*0*/ Q, /*1*/ W> foo(): W
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
// !CHECK_TYPE
|
||||
|
||||
interface A {
|
||||
fun <T, E> foo(): E
|
||||
}
|
||||
|
||||
interface B : A {
|
||||
override fun <Q, W> foo(): W
|
||||
}
|
||||
|
||||
fun test(a: A) {
|
||||
if (a is B) {
|
||||
a.foo<String, Int>().checkType { _<Int>() }
|
||||
}
|
||||
}
|
||||
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
package
|
||||
|
||||
public fun test(/*0*/ a: A): kotlin.Unit
|
||||
|
||||
public interface A {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun </*0*/ T, /*1*/ E> foo(): E
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface B : A {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract override /*1*/ fun </*0*/ Q, /*1*/ W> foo(): W
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -4,5 +4,5 @@ fun test(c : Class<*>) {
|
||||
val sc = <!UNCHECKED_CAST!>c as Class<String><!>
|
||||
// No ambiguous overload
|
||||
c.getAnnotations();
|
||||
sc.getAnnotations();
|
||||
}
|
||||
sc.getAnnotations();
|
||||
}
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ fun foo(): Int {
|
||||
override fun run() = Unit
|
||||
}
|
||||
// Unnecessary but not important smart cast
|
||||
<!DEBUG_INFO_SMARTCAST!>k<!>.run()
|
||||
k.run()
|
||||
return <!DEBUG_INFO_SMARTCAST!>c<!> + d
|
||||
}
|
||||
else return -1
|
||||
|
||||
@@ -14,10 +14,10 @@ fun foo(): Boolean {
|
||||
var v: A
|
||||
v = B()
|
||||
// No smart cast needed, but not a problem if ever
|
||||
if (<!DEBUG_INFO_SMARTCAST!>v<!>.ok()) {
|
||||
if (v.ok()) {
|
||||
v = C()
|
||||
}
|
||||
// No smart cast needed, and no smart cast possible!
|
||||
// We cannot choose between B and C
|
||||
return v.ok()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6909,6 +6909,57 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class MultipleBoundsMemberScope extends AbstractDiagnosticsTest {
|
||||
public void testAllFilesPresentInMultipleBoundsMemberScope() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("conflictingReturnType.kt")
|
||||
public void testConflictingReturnType() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/conflictingReturnType.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("flexibleTypes.kt")
|
||||
public void testFlexibleTypes() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/flexibleTypes.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("mostSpecific.kt")
|
||||
public void testMostSpecific() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/mostSpecific.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("properties.kt")
|
||||
public void testProperties() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/properties.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("propertiesConflict.kt")
|
||||
public void testPropertiesConflict() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/propertiesConflict.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/simple.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("validTypeParameters.kt")
|
||||
public void testValidTypeParameters() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/validTypeParameters.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/generics/nullability")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@@ -15474,6 +15525,87 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class IntersectionScope extends AbstractDiagnosticsTest {
|
||||
public void testAllFilesPresentInIntersectionScope() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/smartCasts/intersectionScope"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("conflictTypeParameters.kt")
|
||||
public void testConflictTypeParameters() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/conflictTypeParameters.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("conflictingReturnType.kt")
|
||||
public void testConflictingReturnType() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/conflictingReturnType.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("flexibleTypes.kt")
|
||||
public void testFlexibleTypes() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/flexibleTypes.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("mostSpecific.kt")
|
||||
public void testMostSpecific() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/mostSpecific.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("mostSpecificIrrelevant.kt")
|
||||
public void testMostSpecificIrrelevant() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/mostSpecificIrrelevant.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("properties.kt")
|
||||
public void testProperties() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/properties.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("propertiesConflict.kt")
|
||||
public void testPropertiesConflict() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/propertiesConflict.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("refineReturnType.kt")
|
||||
public void testRefineReturnType() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/refineReturnType.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/simple.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("unstableSmartCast.kt")
|
||||
public void testUnstableSmartCast() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/unstableSmartCast.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("validTypeParameters.kt")
|
||||
public void testValidTypeParameters() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/validTypeParameters.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("validTypeParametersNoSmartCast.kt")
|
||||
public void testValidTypeParametersNoSmartCast() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/validTypeParametersNoSmartCast.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/smartCasts/loops")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+12
@@ -928,6 +928,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("intersectionTypeMultipleBounds.kt")
|
||||
public void testIntersectionTypeMultipleBounds() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/casts/intersectionTypeMultipleBounds.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("intersectionTypeSmartcast.kt")
|
||||
public void testIntersectionTypeSmartcast() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/casts/intersectionTypeSmartcast.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("is.kt")
|
||||
public void testIs() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/casts/is.kt");
|
||||
|
||||
+3
-11
@@ -23,14 +23,13 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.resolve.scopes.ChainedScope;
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
|
||||
import org.jetbrains.kotlin.resolve.scopes.LazyScopeAdapter;
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
|
||||
import org.jetbrains.kotlin.resolve.scopes.TypeIntersectionScope;
|
||||
import org.jetbrains.kotlin.storage.NotNullLazyValue;
|
||||
import org.jetbrains.kotlin.storage.StorageManager;
|
||||
import org.jetbrains.kotlin.types.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -79,14 +78,7 @@ public abstract class AbstractTypeParameterDescriptor extends DeclarationDescrip
|
||||
new Function0<MemberScope>() {
|
||||
@Override
|
||||
public MemberScope invoke() {
|
||||
List<MemberScope> scopes = new ArrayList<MemberScope>();
|
||||
for (KotlinType bound : getUpperBounds()) {
|
||||
scopes.add(bound.getMemberScope());
|
||||
}
|
||||
return new ChainedScope(
|
||||
"Scope for type parameter " + name.asString(),
|
||||
scopes.toArray(new MemberScope[scopes.size()])
|
||||
);
|
||||
return TypeIntersectionScope.create("Scope for type parameter " + name.asString(), getUpperBounds());
|
||||
}
|
||||
}
|
||||
))
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve;
|
||||
import kotlin.CollectionsKt;
|
||||
import kotlin.Unit;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import org.jetbrains.annotations.Mutable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
@@ -331,7 +332,7 @@ public class OverridingUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isMoreSpecific(@NotNull CallableMemberDescriptor a, @NotNull CallableMemberDescriptor b) {
|
||||
public static boolean isMoreSpecific(@NotNull CallableDescriptor a, @NotNull CallableDescriptor b) {
|
||||
KotlinType aReturnType = a.getReturnType();
|
||||
KotlinType bReturnType = b.getReturnType();
|
||||
|
||||
@@ -341,7 +342,7 @@ public class OverridingUtil {
|
||||
if (a instanceof SimpleFunctionDescriptor) {
|
||||
assert b instanceof SimpleFunctionDescriptor : "b is " + b.getClass();
|
||||
|
||||
return KotlinTypeChecker.DEFAULT.isSubtypeOf(aReturnType, bReturnType);
|
||||
return isReturnTypeMoreSpecific(a, aReturnType, b, bReturnType);
|
||||
}
|
||||
if (a instanceof PropertyDescriptor) {
|
||||
assert b instanceof PropertyDescriptor : "b is " + b.getClass();
|
||||
@@ -349,20 +350,20 @@ public class OverridingUtil {
|
||||
PropertyDescriptor pa = (PropertyDescriptor) a;
|
||||
PropertyDescriptor pb = (PropertyDescriptor) b;
|
||||
if (pa.isVar() && pb.isVar()) {
|
||||
return KotlinTypeChecker.DEFAULT.equalTypes(aReturnType, bReturnType);
|
||||
return DEFAULT.createTypeChecker(a.getTypeParameters(), b.getTypeParameters()).equalTypes(aReturnType, bReturnType);
|
||||
}
|
||||
else {
|
||||
// both vals or var vs val: val can't be more specific then var
|
||||
return !(!pa.isVar() && pb.isVar()) && KotlinTypeChecker.DEFAULT.isSubtypeOf(aReturnType, bReturnType);
|
||||
return !(!pa.isVar() && pb.isVar()) && isReturnTypeMoreSpecific(a, aReturnType, b, bReturnType);
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unexpected callable: " + a.getClass());
|
||||
}
|
||||
|
||||
private static boolean isMoreSpecificThenAllOf(@NotNull CallableMemberDescriptor candidate, @NotNull Collection<CallableMemberDescriptor> descriptors) {
|
||||
private static boolean isMoreSpecificThenAllOf(@NotNull CallableDescriptor candidate, @NotNull Collection<CallableDescriptor> descriptors) {
|
||||
// NB subtyping relation in Kotlin is not transitive in presence of flexible types:
|
||||
// String? <: String! <: String, but not String? <: String
|
||||
for (CallableMemberDescriptor descriptor : descriptors) {
|
||||
for (CallableDescriptor descriptor : descriptors) {
|
||||
if (!isMoreSpecific(candidate, descriptor)) {
|
||||
return false;
|
||||
}
|
||||
@@ -370,20 +371,40 @@ public class OverridingUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static CallableMemberDescriptor selectMostSpecificMemberFromSuper(@NotNull Collection<CallableMemberDescriptor> overridables) {
|
||||
private static boolean isReturnTypeMoreSpecific(
|
||||
@NotNull CallableDescriptor a,
|
||||
@NotNull KotlinType aReturnType,
|
||||
@NotNull CallableDescriptor b,
|
||||
@NotNull KotlinType bReturnType
|
||||
) {
|
||||
KotlinTypeChecker typeChecker = DEFAULT.createTypeChecker(a.getTypeParameters(), b.getTypeParameters());
|
||||
return typeChecker.isSubtypeOf(aReturnType, bReturnType);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <H> H selectMostSpecificMember(
|
||||
@NotNull Collection<H> overridables,
|
||||
@NotNull Function1<H, CallableDescriptor> descriptorByHandle
|
||||
) {
|
||||
assert !overridables.isEmpty() : "Should have at least one overridable descriptor";
|
||||
|
||||
if (overridables.size() == 1) {
|
||||
return CollectionsKt.first(overridables);
|
||||
}
|
||||
|
||||
Collection<CallableMemberDescriptor> candidates = new ArrayList<CallableMemberDescriptor>(2);
|
||||
CallableMemberDescriptor transitivelyMostSpecific = null;
|
||||
for (CallableMemberDescriptor overridable : overridables) {
|
||||
if (isMoreSpecificThenAllOf(overridable, overridables)) {
|
||||
Collection<H> candidates = new ArrayList<H>(2);
|
||||
List<CallableDescriptor> callableMemberDescriptors = CollectionsKt.map(overridables, descriptorByHandle);
|
||||
|
||||
H transitivelyMostSpecific = CollectionsKt.first(overridables);
|
||||
CallableDescriptor transitivelyMostSpecificDescriptor = descriptorByHandle.invoke(transitivelyMostSpecific);
|
||||
|
||||
for (H overridable : overridables) {
|
||||
CallableDescriptor descriptor = descriptorByHandle.invoke(overridable);
|
||||
if (isMoreSpecificThenAllOf(descriptor, callableMemberDescriptors)) {
|
||||
candidates.add(overridable);
|
||||
}
|
||||
if (transitivelyMostSpecific == null || isMoreSpecific(overridable, transitivelyMostSpecific)) {
|
||||
if (isMoreSpecific(descriptor, transitivelyMostSpecificDescriptor)
|
||||
&& !isMoreSpecific(transitivelyMostSpecificDescriptor, descriptor)) {
|
||||
transitivelyMostSpecific = overridable;
|
||||
}
|
||||
}
|
||||
@@ -395,9 +416,9 @@ public class OverridingUtil {
|
||||
return CollectionsKt.first(candidates);
|
||||
}
|
||||
|
||||
CallableMemberDescriptor firstNonFlexible = null;
|
||||
for (CallableMemberDescriptor candidate : candidates) {
|
||||
if (firstNonFlexible == null && !FlexibleTypesKt.isFlexible(candidate.getReturnType())) {
|
||||
H firstNonFlexible = null;
|
||||
for (H candidate : candidates) {
|
||||
if (!FlexibleTypesKt.isFlexible(descriptorByHandle.invoke(candidate).getReturnType())) {
|
||||
firstNonFlexible = candidate;
|
||||
break;
|
||||
}
|
||||
@@ -427,7 +448,14 @@ public class OverridingUtil {
|
||||
// Should be 'foo(s: String): String'.
|
||||
Modality modality = getMinimalModality(effectiveOverridden);
|
||||
Visibility visibility = allInvisible ? Visibilities.INVISIBLE_FAKE : Visibilities.INHERITED;
|
||||
CallableMemberDescriptor mostSpecific = selectMostSpecificMemberFromSuper(effectiveOverridden);
|
||||
CallableMemberDescriptor mostSpecific =
|
||||
selectMostSpecificMember(effectiveOverridden,
|
||||
new Function1<CallableMemberDescriptor, CallableDescriptor>() {
|
||||
@Override
|
||||
public CallableMemberDescriptor invoke(CallableMemberDescriptor descriptor) {
|
||||
return descriptor;
|
||||
}
|
||||
});
|
||||
CallableMemberDescriptor fakeOverride =
|
||||
mostSpecific.copy(current, modality, visibility, CallableMemberDescriptor.Kind.FAKE_OVERRIDE, false);
|
||||
for (CallableMemberDescriptor descriptor : effectiveOverridden) {
|
||||
@@ -462,35 +490,79 @@ public class OverridingUtil {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <H> is something that handles CallableDescriptor inside
|
||||
* @return
|
||||
*/
|
||||
@NotNull
|
||||
private static Collection<CallableMemberDescriptor> extractMembersOverridableInBothWays(
|
||||
@NotNull CallableMemberDescriptor overrider,
|
||||
@NotNull Queue<CallableMemberDescriptor> extractFrom,
|
||||
@NotNull DescriptorSink sink
|
||||
public static <H> Collection<H> extractMembersOverridableInBothWays(
|
||||
@NotNull H overrider,
|
||||
@NotNull @Mutable Collection<H> extractFrom,
|
||||
@NotNull Function1<H, CallableDescriptor> descriptorByHandle,
|
||||
@NotNull Function1<H, Unit> onConflict
|
||||
) {
|
||||
Collection<CallableMemberDescriptor> overridable = new ArrayList<CallableMemberDescriptor>();
|
||||
Collection<H> overridable = new ArrayList<H>();
|
||||
overridable.add(overrider);
|
||||
for (Iterator<CallableMemberDescriptor> iterator = extractFrom.iterator(); iterator.hasNext(); ) {
|
||||
CallableMemberDescriptor candidate = iterator.next();
|
||||
CallableDescriptor overriderDescriptor = descriptorByHandle.invoke(overrider);
|
||||
for (Iterator<H> iterator = extractFrom.iterator(); iterator.hasNext(); ) {
|
||||
H candidate = iterator.next();
|
||||
CallableDescriptor candidateDescriptor = descriptorByHandle.invoke(candidate);
|
||||
if (overrider == candidate) {
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
OverrideCompatibilityInfo.Result result1 = DEFAULT.isOverridableBy(candidate, overrider, null).getResult();
|
||||
OverrideCompatibilityInfo.Result result2 = DEFAULT.isOverridableBy(overrider, candidate, null).getResult();
|
||||
if (result1 == OVERRIDABLE && result2 == OVERRIDABLE) {
|
||||
OverrideCompatibilityInfo.Result finalResult = getBothWaysOverridability(overriderDescriptor, candidateDescriptor);
|
||||
|
||||
if (finalResult == OVERRIDABLE) {
|
||||
overridable.add(candidate);
|
||||
iterator.remove();
|
||||
}
|
||||
else if (result1 == CONFLICT || result2 == CONFLICT) {
|
||||
sink.conflict(overrider, candidate);
|
||||
else if (finalResult == CONFLICT) {
|
||||
onConflict.invoke(candidate);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
return overridable;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static OverrideCompatibilityInfo.Result getBothWaysOverridability(
|
||||
CallableDescriptor overriderDescriptor,
|
||||
CallableDescriptor candidateDescriptor
|
||||
) {
|
||||
OverrideCompatibilityInfo.Result result1 = DEFAULT.isOverridableBy(candidateDescriptor, overriderDescriptor, null).getResult();
|
||||
OverrideCompatibilityInfo.Result result2 = DEFAULT.isOverridableBy(overriderDescriptor, candidateDescriptor, null).getResult();
|
||||
|
||||
return result1 == OVERRIDABLE && result2 == OVERRIDABLE
|
||||
? OVERRIDABLE
|
||||
: ((result1 == CONFLICT || result2 == CONFLICT) ? CONFLICT : INCOMPATIBLE);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Collection<CallableMemberDescriptor> extractMembersOverridableInBothWays(
|
||||
@NotNull final CallableMemberDescriptor overrider,
|
||||
@NotNull Queue<CallableMemberDescriptor> extractFrom,
|
||||
@NotNull final DescriptorSink sink
|
||||
) {
|
||||
return extractMembersOverridableInBothWays(overrider, extractFrom,
|
||||
// ID
|
||||
new Function1<CallableMemberDescriptor, CallableDescriptor>() {
|
||||
@Override
|
||||
public CallableDescriptor invoke(CallableMemberDescriptor descriptor) {
|
||||
return descriptor;
|
||||
}
|
||||
},
|
||||
new Function1<CallableMemberDescriptor, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(CallableMemberDescriptor descriptor) {
|
||||
sink.conflict(overrider, descriptor);
|
||||
return Unit.INSTANCE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public static void resolveUnknownVisibilityForMember(
|
||||
@NotNull CallableMemberDescriptor memberDescriptor,
|
||||
@Nullable Function1<CallableMemberDescriptor, Unit> cannotInferVisibility
|
||||
|
||||
@@ -17,12 +17,8 @@
|
||||
package org.jetbrains.kotlin.resolve
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.isFlexible
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
import org.jetbrains.kotlin.utils.SmartSet
|
||||
import java.util.*
|
||||
|
||||
fun <TDescriptor : CallableDescriptor> TDescriptor.findTopMostOverriddenDescriptors(): List<TDescriptor> {
|
||||
@@ -46,3 +42,42 @@ fun <TDescriptor : CallableDescriptor> TDescriptor.findOriginalTopMostOverridden
|
||||
(it.original as TDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <H> is something that handles CallableDescriptor inside
|
||||
*/
|
||||
public fun <H : Any> Collection<H>.selectMostSpecificInEachOverridableGroup(
|
||||
descriptorByHandle: H.() -> CallableDescriptor
|
||||
): Collection<H> {
|
||||
if (size <= 1) return this
|
||||
val queue = LinkedList<H>(this)
|
||||
val result = SmartSet.create<H>()
|
||||
|
||||
while (queue.isNotEmpty()) {
|
||||
val nextHandle: H = queue.first()
|
||||
|
||||
val conflictedHandles = SmartSet.create<H>()
|
||||
|
||||
val overridableGroup =
|
||||
OverridingUtil.extractMembersOverridableInBothWays(nextHandle, queue, descriptorByHandle) { conflictedHandles.add(it) }
|
||||
|
||||
if (overridableGroup.size == 1 && overridableGroup.isEmpty()) {
|
||||
result.add(overridableGroup.single())
|
||||
continue
|
||||
}
|
||||
|
||||
val mostSpecific = OverridingUtil.selectMostSpecificMember(overridableGroup, descriptorByHandle)
|
||||
val mostSpecificDescriptor = mostSpecific.descriptorByHandle()
|
||||
|
||||
overridableGroup.filterNotTo(conflictedHandles) {
|
||||
OverridingUtil.isMoreSpecific(mostSpecificDescriptor, it.descriptorByHandle())
|
||||
}
|
||||
|
||||
if (conflictedHandles.isNotEmpty()) {
|
||||
result.addAll(conflictedHandles)
|
||||
}
|
||||
|
||||
result.add(mostSpecific)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.util.collectionUtils.getFromAllScopes
|
||||
import org.jetbrains.kotlin.utils.Printer
|
||||
|
||||
public class ChainedScope(
|
||||
private val debugName: String,
|
||||
internal val debugName: String,
|
||||
vararg scopes: MemberScope
|
||||
) : MemberScope {
|
||||
private val scopeChain = scopes.clone()
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.scopes
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.selectMostSpecificInEachOverridableGroup
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.utils.Printer
|
||||
|
||||
class TypeIntersectionScope private constructor(override val workerScope: ChainedScope) : AbstractScopeAdapter() {
|
||||
override fun getContributedFunctions(name: Name, location: LookupLocation) =
|
||||
super.getContributedFunctions(name, location).selectMostSpecificInEachOverridableGroup { this }
|
||||
|
||||
override fun getContributedVariables(name: Name, location: LookupLocation) =
|
||||
super.getContributedVariables(name, location).selectMostSpecificInEachOverridableGroup { this }
|
||||
|
||||
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> {
|
||||
val (callables, other) = super.getContributedDescriptors(kindFilter, nameFilter).partition { it is CallableDescriptor }
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return (callables as Collection<CallableDescriptor>).selectMostSpecificInEachOverridableGroup { this } + other
|
||||
}
|
||||
|
||||
override fun printScopeStructure(p: Printer) {
|
||||
p.print("TypeIntersectionScope for: " + workerScope.debugName)
|
||||
super.printScopeStructure(p)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun create(message: String, types: List<KotlinType>): MemberScope {
|
||||
val chainedScope = ChainedScope(message, *types.map { it.memberScope }.toTypedArray())
|
||||
if (types.size <= 1) return chainedScope
|
||||
|
||||
return TypeIntersectionScope(chainedScope)
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -30,6 +30,6 @@ fun test(a: A?) {
|
||||
|
||||
if (a is B && a is D) {
|
||||
//when it's resolved, the message should be 'Smart cast to A'
|
||||
a.<error>foo</error>
|
||||
<info>a</info>.<error>foo</error>
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user