Added captured types and approximation

CapturedType captures type projection while solving the constraint system.
During the substitution type containing captured types is approximated
to get rid of captured types and (for simple cases) replace them with corresponding type projections.

Note that Array<Array< CapturedType(out Int) >> is (over)approximated by Array<out<Array<out Int>>

See 'Mixed-site variance' by Ross Tate for details.

 #KT-2570 Fixed
 #KT-2872 Fixed
 #KT-3213 Fixed
This commit is contained in:
Svetlana Isakova
2014-09-23 15:29:47 +04:00
parent e798b7c6d1
commit cd359a046c
36 changed files with 798 additions and 114 deletions
@@ -4899,7 +4899,7 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
@TestMetadata("compiler/testData/diagnostics/tests/inference")
@TestDataPath("$PROJECT_ROOT")
@InnerTestClasses({Inference.Constraints.class, Inference.NestedCalls.class, Inference.Regressions.class, Inference.ReportingImprovements.class, Inference.Substitutions.class, Inference.UpperBounds.class, Inference.Varargs.class})
@InnerTestClasses({Inference.CapturedTypes.class, Inference.Constraints.class, Inference.NestedCalls.class, Inference.Regressions.class, Inference.ReportingImprovements.class, Inference.Substitutions.class, Inference.UpperBounds.class, Inference.Varargs.class})
@RunWith(JUnit3RunnerWithInners.class)
public static class Inference extends AbstractJetDiagnosticsTest {
public void testAllFilesPresentInInference() throws Exception {
@@ -5086,6 +5086,45 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class CapturedTypes extends AbstractJetDiagnosticsTest {
public void testAllFilesPresentInCapturedTypes() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/capturedTypes"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("captureForPlatformTypes.kt")
public void testCaptureForPlatformTypes() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes/captureForPlatformTypes.kt");
doTest(fileName);
}
@TestMetadata("capturedType.kt")
public void testCapturedType() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedType.kt");
doTest(fileName);
}
@TestMetadata("capturedTypeAndApproximation.kt")
public void testCapturedTypeAndApproximation() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedTypeAndApproximation.kt");
doTest(fileName);
}
@TestMetadata("kt2570.kt")
public void testKt2570() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes/kt2570.kt");
doTest(fileName);
}
@TestMetadata("kt2872.kt")
public void testKt2872() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes/kt2872.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/diagnostics/tests/inference/constraints")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -0,0 +1,75 @@
/*
* Copyright 2010-2014 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.jet.resolve.typeApproximation
import org.jetbrains.jet.JetLiteFixture
import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment
import org.jetbrains.jet.ConfigurationKind
import java.io.File
import org.jetbrains.jet.lang.resolve.lazy.JvmResolveUtil
import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
import org.jetbrains.jet.lang.types.TypeSubstitutor
import org.jetbrains.jet.lang.types.TypeProjectionImpl
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
import org.jetbrains.jet.lang.types.Variance
import org.jetbrains.jet.lang.types.typesApproximation.approximateCapturedTypes
import org.jetbrains.jet.JetTestUtils
import org.jetbrains.jet.lang.psi.JetPsiFactory
import org.jetbrains.jet.lang.resolve.calls.inference.CapturedTypeConstructor
import org.jetbrains.jet.lang.types.JetTypeImpl
import org.jetbrains.jet.lang.resolve.calls.inference.createCapturedType
abstract public class AbstractCapturedTypeApproximationTest() : JetLiteFixture() {
override fun createEnvironment(): JetCoreEnvironment = createEnvironmentWithMockJdk(ConfigurationKind.ALL)
public fun doTest(filePath: String) {
val file = File(filePath)
val text = JetTestUtils.doLoadFile(file)!!
val jetFile = JetPsiFactory(getProject()).createFile(text)
val bindingContext = JvmResolveUtil.analyzeOneFileWithJavaIntegration(jetFile).bindingContext
val functions = bindingContext.getSliceContents(BindingContext.FUNCTION)
val functionFoo = functions.values().firstOrNull { it.getName().asString() == "foo" } ?:
throw AssertionError("Function 'foo' is not declared")
val typeParameter = functionFoo.getTypeParameters().first()
val parameter = functionFoo.getValueParameters().first().getType()
val result = StringBuilder {
val endIndex = text.indexOf("// T captures")
appendln(if (endIndex == -1) text else text.substring(0, endIndex).trimTrailing())
for (variance in listOf(Variance.IN_VARIANCE, Variance.OUT_VARIANCE)) {
val captured = createCapturedType(TypeProjectionImpl(variance, KotlinBuiltIns.getInstance().getIntType()))
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameter.getTypeConstructor() to TypeProjectionImpl(captured)))
val typeWithCapturedType = typeSubstitutor.substituteWithoutApproximation(
TypeProjectionImpl(Variance.INVARIANT, parameter))!!.getType()
val (lower, upper) = approximateCapturedTypes(typeWithCapturedType)
appendln()
appendln("// T captures '${(captured.getConstructor() as CapturedTypeConstructor).typeProjection}'")
appendln("// lower: $lower")
appendln("// upper: $upper")
}
}.toString()
JetTestUtils.assertEqualsToFile(file, result)
}
}
@@ -0,0 +1,86 @@
/*
* Copyright 2010-2014 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.jet.resolve.typeApproximation;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.jet.JUnit3RunnerWithInners;
import org.jetbrains.jet.JetTestUtils;
import org.jetbrains.jet.test.InnerTestClasses;
import org.jetbrains.jet.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("compiler/testData/capturedTypeApproximation")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class CapturedTypeApproximationTestGenerated extends AbstractCapturedTypeApproximationTest {
public void testAllFilesPresentInCapturedTypeApproximation() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/capturedTypeApproximation"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("contravariant.kt")
public void testContravariant() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/capturedTypeApproximation/contravariant.kt");
doTest(fileName);
}
@TestMetadata("covariant.kt")
public void testCovariant() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/capturedTypeApproximation/covariant.kt");
doTest(fileName);
}
@TestMetadata("invariant.kt")
public void testInvariant() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/capturedTypeApproximation/invariant.kt");
doTest(fileName);
}
@TestMetadata("nestedCov.kt")
public void testNestedCov() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/capturedTypeApproximation/nestedCov.kt");
doTest(fileName);
}
@TestMetadata("nestedInv.kt")
public void testNestedInv() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/capturedTypeApproximation/nestedInv.kt");
doTest(fileName);
}
@TestMetadata("nestedInvLevel2.kt")
public void testNestedInvLevel2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/capturedTypeApproximation/nestedInvLevel2.kt");
doTest(fileName);
}
@TestMetadata("useSiteVarianceIn.kt")
public void testUseSiteVarianceIn() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/capturedTypeApproximation/useSiteVarianceIn.kt");
doTest(fileName);
}
@TestMetadata("useSiteVarianceOut.kt")
public void testUseSiteVarianceOut() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/capturedTypeApproximation/useSiteVarianceOut.kt");
doTest(fileName);
}
}
@@ -235,7 +235,7 @@ public class TypeSubstitutorTest extends KotlinTestWithEnvironment {
public void testOutInProjection() throws Exception {
doTest(
"C<out Any>",
"C<out Any?>",
"C<out T>",
map("T", "in String")
);