Skip to content

Commit f2efd30

Browse files
committed
Added 'NoInfer' and 'Exact' annotations
1 parent 9b1030d commit f2efd30

File tree

9 files changed

+114
-0
lines changed

9 files changed

+114
-0
lines changed

compiler/testData/builtin-classes.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,10 @@ public abstract class Enum</*0*/ E : kotlin.Enum<E>> : kotlin.Comparable<E> {
456456
}
457457
}
458458

459+
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE}) @kotlin.annotation.Retention(value = AnnotationRetention.SOURCE) @kotlin.annotation.annotation() internal final class Exact : kotlin.Annotation {
460+
/*primary*/ public constructor Exact()
461+
}
462+
459463
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE}) @kotlin.annotation.MustBeDocumented() @kotlin.annotation.annotation() public final class Extension : kotlin.Annotation {
460464
/*primary*/ public constructor Extension()
461465
}
@@ -1040,6 +1044,10 @@ public interface MutableSet</*0*/ E> : kotlin.Set<E>, kotlin.MutableCollection<E
10401044
public abstract override /*1*/ fun retainAll(/*0*/ c: kotlin.Collection<kotlin.Any?>): kotlin.Boolean
10411045
}
10421046

1047+
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE}) @kotlin.annotation.Retention(value = AnnotationRetention.SOURCE) @kotlin.annotation.annotation() internal final class NoInfer : kotlin.Annotation {
1048+
/*primary*/ public constructor NoInfer()
1049+
}
1050+
10431051
public final class Nothing {
10441052
/*primary*/ private constructor Nothing()
10451053
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//!DIAGNOSTICS: -UNUSED_VARIABLE
2+
3+
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
4+
fun <T, U: T> List<@Exact T>.firstTyped(): U = throw Exception()
5+
6+
fun test1(l: List<Number>) {
7+
8+
val i: Int = l.firstTyped()
9+
10+
val s: String = l.<!TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>firstTyped<!>()
11+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package
2+
3+
public fun test1(/*0*/ l: kotlin.List<kotlin.Number>): kotlin.Unit
4+
@kotlin.Suppress(names = {"INVISIBLE_MEMBER", "INVISIBLE_REFERENCE"}) public fun </*0*/ T, /*1*/ U : T> kotlin.List<@kotlin.Exact() T>.firstTyped(): U
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//!DIAGNOSTICS: -UNUSED_PARAMETER
2+
3+
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
4+
fun <T> test1(t1: T, t2: @NoInfer T): T = t1
5+
6+
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
7+
fun <T> @NoInfer T.test2(t1: T): T = t1
8+
9+
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
10+
fun <T> test3(t1: @NoInfer T): T = t1
11+
12+
fun usage() {
13+
test1(1, <!TYPE_MISMATCH!>"312"<!>)
14+
<!TYPE_MISMATCH!>1<!>.test2("")
15+
<!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>test3<!>("")
16+
}
17+
18+
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
19+
fun <T> List<T>.contains1(e: @NoInfer T): Boolean = true
20+
21+
fun test(l: List<Number>) {
22+
l.contains1(<!TYPE_MISMATCH!>""<!>)
23+
}
24+
25+
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
26+
fun <T> assertEquals1(e1: T, e2: @NoInfer T): Boolean = true
27+
28+
fun test(s: String) {
29+
assertEquals1(s, <!CONSTANT_EXPECTED_TYPE_MISMATCH!>11<!>)
30+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package
2+
3+
@kotlin.Suppress(names = {"INVISIBLE_MEMBER", "INVISIBLE_REFERENCE"}) public fun </*0*/ T> assertEquals1(/*0*/ e1: T, /*1*/ e2: @kotlin.NoInfer() T): kotlin.Boolean
4+
public fun test(/*0*/ l: kotlin.List<kotlin.Number>): kotlin.Unit
5+
public fun test(/*0*/ s: kotlin.String): kotlin.Unit
6+
@kotlin.Suppress(names = {"INVISIBLE_MEMBER", "INVISIBLE_REFERENCE"}) public fun </*0*/ T> test1(/*0*/ t1: T, /*1*/ t2: @kotlin.NoInfer() T): T
7+
@kotlin.Suppress(names = {"INVISIBLE_MEMBER", "INVISIBLE_REFERENCE"}) public fun </*0*/ T> test3(/*0*/ t1: @kotlin.NoInfer() T): T
8+
public fun usage(): kotlin.Unit
9+
@kotlin.Suppress(names = {"INVISIBLE_MEMBER", "INVISIBLE_REFERENCE"}) public fun </*0*/ T> kotlin.List<T>.contains1(/*0*/ e: @kotlin.NoInfer() T): kotlin.Boolean
10+
@kotlin.Suppress(names = {"INVISIBLE_MEMBER", "INVISIBLE_REFERENCE"}) public fun </*0*/ T> @kotlin.NoInfer() T.test2(/*0*/ t1: T): T

compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7293,6 +7293,27 @@ public void testUseFunctionLiteralsToInferType() throws Exception {
72937293
doTest(fileName);
72947294
}
72957295

7296+
@TestMetadata("compiler/testData/diagnostics/tests/inference/annotationsForResolve")
7297+
@TestDataPath("$PROJECT_ROOT")
7298+
@RunWith(JUnit3RunnerWithInners.class)
7299+
public static class AnnotationsForResolve extends AbstractJetDiagnosticsTest {
7300+
public void testAllFilesPresentInAnnotationsForResolve() throws Exception {
7301+
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/annotationsForResolve"), Pattern.compile("^(.+)\\.kt$"), true);
7302+
}
7303+
7304+
@TestMetadata("exactAnnotation.kt")
7305+
public void testExactAnnotation() throws Exception {
7306+
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/annotationsForResolve/exactAnnotation.kt");
7307+
doTest(fileName);
7308+
}
7309+
7310+
@TestMetadata("noInferAnnotation.kt")
7311+
public void testNoInferAnnotation() throws Exception {
7312+
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/annotationsForResolve/noInferAnnotation.kt");
7313+
doTest(fileName);
7314+
}
7315+
}
7316+
72967317
@TestMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes")
72977318
@TestDataPath("$PROJECT_ROOT")
72987319
@RunWith(JUnit3RunnerWithInners.class)

core/builtins/src/kotlin/Annotations.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,17 @@ public annotation class HiddenDeclaration
118118
@Retention(SOURCE)
119119
@MustBeDocumented
120120
private annotation class external
121+
122+
/**
123+
* Specifies that the corresponding type should be ignored during type inference.
124+
*/
125+
@Target(TYPE)
126+
@Retention(SOURCE)
127+
internal annotation class NoInfer
128+
129+
/**
130+
* Specifies that the constraint built for the type during type inference should be an equality one.
131+
*/
132+
@Target(TYPE)
133+
@Retention(SOURCE)
134+
internal annotation class Exact

core/descriptors/src/org/jetbrains/kotlin/resolve/isAnnotatedAsHidden.kt renamed to core/descriptors/src/org/jetbrains/kotlin/resolve/annotationsForResolve.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,17 @@
1717
package org.jetbrains.kotlin.resolve.descriptorUtil
1818

1919
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
20+
import org.jetbrains.kotlin.descriptors.annotations.Annotated
2021
import org.jetbrains.kotlin.name.FqName
2122

2223
private val HIDDEN_ANNOTATION_FQ_NAME = FqName("kotlin.HiddenDeclaration")
2324

2425
public fun DeclarationDescriptor.isAnnotatedAsHidden(): Boolean = annotations.findAnnotation(HIDDEN_ANNOTATION_FQ_NAME) != null
26+
27+
private val NO_INFER_ANNOTATION_FQ_NAME = FqName("kotlin.NoInfer")
28+
29+
public fun Annotated.hasNoInferAnnotation(): Boolean = annotations.findAnnotation(NO_INFER_ANNOTATION_FQ_NAME) != null
30+
31+
private val EXACT_ANNOTATION_FQ_NAME = FqName("kotlin.Exact")
32+
33+
public fun Annotated.hasExactAnnotation(): Boolean = annotations.findAnnotation(EXACT_ANNOTATION_FQ_NAME) != null

core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.Constrain
2929
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind
3030
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.TYPE_BOUND_POSITION
3131
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.derivedFrom
32+
import org.jetbrains.kotlin.resolve.descriptorUtil.hasNoInferAnnotation
33+
import org.jetbrains.kotlin.resolve.descriptorUtil.hasExactAnnotation
3234
import org.jetbrains.kotlin.resolve.scopes.JetScope
3335
import org.jetbrains.kotlin.types.*
3436
import org.jetbrains.kotlin.types.TypeUtils.DONT_CARE
@@ -286,6 +288,11 @@ public class ConstraintSystemImpl : ConstraintSystem {
286288
if (isErrorOrSpecialType(subType, constraintPosition) || isErrorOrSpecialType(superType, constraintPosition)) return
287289
if (subType == null || superType == null) return
288290

291+
if (subType.hasNoInferAnnotation() || superType.hasNoInferAnnotation()) return
292+
if ((subType.hasExactAnnotation() || superType.hasExactAnnotation()) && (constraintKind != EQUAL)) {
293+
return doAddConstraint(EQUAL, subType, superType, constraintContext, typeCheckingProcedure)
294+
}
295+
289296
assert(!superType.isFunctionPlaceholder) {
290297
"The type for " + constraintPosition + " shouldn't be a placeholder for function type"
291298
}

0 commit comments

Comments
 (0)