From b51e3dc4642a5e68fd3fe6fcfd54ca73d62ba845 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Tue, 21 Jan 2014 19:23:54 +0400 Subject: [PATCH] added ConstraintSystemTest --- .../lang/diagnostics/rendering/Renderers.java | 2 +- .../calls/inference/ConstraintsUtil.java | 6 + .../declarations/declarations.kt | 10 + .../constraintSystem/simpleSuccessful.bounds | 18 ++ .../constraintSystem/ConstraintSystemTest.kt | 173 ++++++++++++++++++ .../constraintSystem/MyDeclarations.kt | 76 ++++++++ 6 files changed, 284 insertions(+), 1 deletion(-) create mode 100644 compiler/testData/constraintSystem/declarations/declarations.kt create mode 100644 compiler/testData/constraintSystem/simpleSuccessful.bounds create mode 100644 compiler/tests/org/jetbrains/jet/resolve/constraintSystem/ConstraintSystemTest.kt create mode 100644 compiler/tests/org/jetbrains/jet/resolve/constraintSystem/MyDeclarations.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/Renderers.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/Renderers.java index 92de4a0f236..4e47ba7ca74 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/Renderers.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/Renderers.java @@ -376,7 +376,7 @@ public class Renderers { typeBounds.add(constraintSystem.getTypeBounds(variable)); } Function renderTypeBounds = rendererToFunction(RENDER_TYPE_BOUNDS); - return "type parameter bounds: \n" + StringUtil.join(typeBounds, renderTypeBounds, ";\n") + "\n" + + return "type parameter bounds:\n" + StringUtil.join(typeBounds, renderTypeBounds, ";\n") + "\n" + "status:\n" + ConstraintsUtil.getDebugMessageForStatus(constraintSystem.getStatus()); } }; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintsUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintsUtil.java index a3867e38394..aec3e3562d3 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintsUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintsUtil.java @@ -123,6 +123,12 @@ public class ConstraintsUtil { interestingMethods.add(method); } } + Collections.sort(interestingMethods, new Comparator() { + @Override + public int compare(@NotNull Method method1, @NotNull Method method2) { + return method1.getName().compareTo(method2.getName()); + } + }); for (Iterator iterator = interestingMethods.iterator(); iterator.hasNext(); ) { Method method = iterator.next(); try { diff --git a/compiler/testData/constraintSystem/declarations/declarations.kt b/compiler/testData/constraintSystem/declarations/declarations.kt new file mode 100644 index 00000000000..dbb6e644c2b --- /dev/null +++ b/compiler/testData/constraintSystem/declarations/declarations.kt @@ -0,0 +1,10 @@ +fun foo() = 42 + +trait A +trait B : A +trait C : B + +trait Consumer +trait Producer + +trait My \ No newline at end of file diff --git a/compiler/testData/constraintSystem/simpleSuccessful.bounds b/compiler/testData/constraintSystem/simpleSuccessful.bounds new file mode 100644 index 00000000000..d2988a81023 --- /dev/null +++ b/compiler/testData/constraintSystem/simpleSuccessful.bounds @@ -0,0 +1,18 @@ +VARIABLES T + +SUBTYPE T Int +SUPERTYPE T Int ! + +type parameter bounds: +T >: Int(SPECIAL), <: Int(SPECIAL) +status: +-hasConflictingConstraints: false +-hasContradiction: false +-hasErrorInConstrainingTypes: false +-hasTypeConstructorMismatch: false +-hasUnknownParameters: false +-hasViolatedUpperBound: false +-isSuccessful: true + +result: +T=Int diff --git a/compiler/tests/org/jetbrains/jet/resolve/constraintSystem/ConstraintSystemTest.kt b/compiler/tests/org/jetbrains/jet/resolve/constraintSystem/ConstraintSystemTest.kt new file mode 100644 index 00000000000..ba56fbfa253 --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/resolve/constraintSystem/ConstraintSystemTest.kt @@ -0,0 +1,173 @@ +/* + * 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.constraintSystem + +import com.google.common.collect.ImmutableMap +import com.google.common.collect.Maps +import com.intellij.psi.PsiElement +import org.jetbrains.jet.ConfigurationKind +import org.jetbrains.jet.JetLiteFixture +import org.jetbrains.jet.JetTestUtils +import org.jetbrains.jet.analyzer.AnalyzeExhaust +import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment +import org.jetbrains.jet.di.InjectorForTests +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor +import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor +import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor +import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory +import org.jetbrains.jet.lang.diagnostics.rendering.Renderers +import org.jetbrains.jet.lang.psi.* +import org.jetbrains.jet.lang.resolve.* +import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition +import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl +import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM +import org.jetbrains.jet.lang.resolve.scopes.JetScope +import org.jetbrains.jet.lang.types.JetType +import org.jetbrains.jet.lang.types.Variance +import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns +import java.io.File +import java.io.IOException +import java.util.Collections +import com.intellij.openapi.project.Project +import java.util.HashMap +import java.util.regex.Pattern +import org.jetbrains.jet.resolve.constraintSystem.ConstraintSystemTest.MyConstraintKind +import org.jetbrains.jet.resolve.constraintSystem.ConstraintSystemTest.MyConstraint +import java.util.ArrayList +import kotlin.test.assertEquals +import org.junit.Assert + +public class ConstraintSystemTest() : JetLiteFixture() { + + val constraintPattern = Pattern.compile("(SUBTYPE|SUPERTYPE|EQUALITY)\\s+(\\w+)\\s+(\\w+)", Pattern.MULTILINE) + val variablesPattern = Pattern.compile("VARIABLES\\s+(.*)") + + private var builtIns: KotlinBuiltIns? = null + private var typeResolver: TypeResolver? = null + private var expressionTypingServices: ExpressionTypingServices? = null + private var functionDescriptor: FunctionDescriptor? = null + private var scopeToResolveTypeParameters: JetScope? = null + + override fun createEnvironment(): JetCoreEnvironment { + return createEnvironmentWithMockJdk(ConfigurationKind.ALL) + } + + override fun setUp() { + super.setUp() + + builtIns = KotlinBuiltIns.getInstance() + + val injector = InjectorForTests(getProject(), JetTestUtils.createEmptyModule()!!) + typeResolver = injector.getTypeResolver() + expressionTypingServices = injector.getExpressionTypingServices() + + analyzeDeclarations() + } + + override fun getTestDataPath(): String { + return super.getTestDataPath() + "/constraintSystem/" + } + + private fun analyzeDeclarations(): MyDeclarations { + val fileName = "declarations/declarations.kt" + + val psiFile = createPsiFile(null, fileName, loadFile(fileName)) + val analyzeExhaust = AnalyzerFacadeForJVM.analyzeOneFileWithJavaIntegration(psiFile, Collections.emptyList())!! + val bindingContext = analyzeExhaust.getBindingContext() + return MyDeclarations(bindingContext, getProject(), typeResolver!!) + } + + public fun testSimpleSuccessful() { + doTest("compiler/testData/constraintSystem/simpleSuccessful.bounds") + } + + public fun doTest(filePath: String) { + val file = File(filePath) + val fileText = JetTestUtils.doLoadFile(file)!! + + val constraintSystem = ConstraintSystemImpl() + val myDeclarations = analyzeDeclarations() + + val typeParameterDescriptors = HashMap() + val variables = parseVariables(fileText) + for (variable in variables) { + typeParameterDescriptors.put(myDeclarations.getParameterDescriptor(variable), Variance.INVARIANT) + } + constraintSystem.registerTypeVariables(typeParameterDescriptors) + + val constraints = parseConstraints(fileText) + for (constraint in constraints) { + val firstType = myDeclarations.getType(constraint.firstType) + val secondType = myDeclarations.getType(constraint.secondType) + val position = if (constraint.isWeak) ConstraintPosition.getTypeBoundPosition(0)!! else ConstraintPosition.SPECIAL + when (constraint.kind) { + MyConstraintKind.SUBTYPE -> constraintSystem.addSubtypeConstraint(firstType, secondType, position) + MyConstraintKind.SUPERTYPE -> constraintSystem.addSupertypeConstraint(firstType, secondType, position) + } + } + + val expectedStatus = parseStatus(fileText) + val resultingStatus = Renderers.RENDER_CONSTRAINT_SYSTEM.render(constraintSystem) + Assert.assertEquals("Constraint system status mismatch", expectedStatus, resultingStatus) + + val resultingSubstitutor = constraintSystem.getResultingSubstitutor() + val result = StringBuilder() append "result:\n" + for ((typeParameter, variance) in typeParameterDescriptors) { + val resultForTypeParameter = resultingSubstitutor.substitute(myDeclarations.getType(typeParameter.getName().asString()), variance) + result append "${typeParameter.getName()}=${resultForTypeParameter}" + } + + val expectedResult = parseResult(fileText) + Assert.assertEquals("Constraint system substitution mismatch", expectedResult, result.toString()) + } + + class MyConstraint(val kind: MyConstraintKind, val firstType: String, val secondType: String, val isWeak: Boolean) + enum class MyConstraintKind { + SUBTYPE SUPERTYPE + } + + private fun parseVariables(text: String): List { + val matcher = variablesPattern.matcher(text) + if (matcher.find()) { + val variablesText = matcher.group(1)!! + val variables = variablesText.split(' ') + return variables.toList() + } + throw AssertionError("Type variable names should be declared") + } + + private fun parseConstraints(text: String): List { + val constraints = ArrayList() + val matcher = constraintPattern.matcher(text) + while (matcher.find()) { + val kind = MyConstraintKind.valueOf(matcher.group(1)!!) + val firstType = matcher.group(2)!! + val secondType = matcher.group(3)!! + val isWeak = matcher.groupCount() == 4 && matcher.group(4) == "!" + constraints.add(MyConstraint(kind, firstType, secondType, isWeak)) + } + return constraints + } + + private fun parseStatus(text: String) = text.substring(text.indexOf("type parameter bounds"), text.indexOf("result")).trim() + + private fun parseResult(text: String) = text.substring(text.indexOf("result"), text.length()) +} + + + diff --git a/compiler/tests/org/jetbrains/jet/resolve/constraintSystem/MyDeclarations.kt b/compiler/tests/org/jetbrains/jet/resolve/constraintSystem/MyDeclarations.kt new file mode 100644 index 00000000000..9dc777aef73 --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/resolve/constraintSystem/MyDeclarations.kt @@ -0,0 +1,76 @@ +/* + * 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.constraintSystem + +import com.google.common.collect.ImmutableMap +import com.google.common.collect.Maps +import com.intellij.psi.PsiElement +import org.jetbrains.jet.ConfigurationKind +import org.jetbrains.jet.JetLiteFixture +import org.jetbrains.jet.JetTestUtils +import org.jetbrains.jet.analyzer.AnalyzeExhaust +import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment +import org.jetbrains.jet.di.InjectorForTests +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor +import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor +import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor +import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory +import org.jetbrains.jet.lang.diagnostics.rendering.Renderers +import org.jetbrains.jet.lang.psi.* +import org.jetbrains.jet.lang.resolve.* +import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition +import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl +import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM +import org.jetbrains.jet.lang.resolve.scopes.JetScope +import org.jetbrains.jet.lang.types.JetType +import org.jetbrains.jet.lang.types.Variance +import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns +import java.io.File +import java.io.IOException +import java.util.Collections +import com.intellij.openapi.project.Project + +public class MyDeclarations( + private val context: BindingContext, + private val project: Project, + private val typeResolver: TypeResolver +) { + private val functionFoo: FunctionDescriptor + private val scopeToResolveTypeParameters: JetScope + + { + val functions = context.getSliceContents(BindingContext.FUNCTION) + functionFoo = functions.values().iterator().next() + val function = (BindingContextUtils.descriptorToDeclaration(context, functionFoo) as JetFunction) + val fooBody = function.getBodyExpression() + scopeToResolveTypeParameters = context.get(BindingContext.RESOLUTION_SCOPE, fooBody)!! + } + + fun getParameterDescriptor(name: String): TypeParameterDescriptor { + for (typeParameter in functionFoo.getTypeParameters()) { + if (typeParameter.getName().asString() == name) { + return typeParameter; + } + } + throw AssertionError("Unsupported type parameter name: " + name + ".") + } + + fun getType(name: String) = typeResolver.resolveType( + scopeToResolveTypeParameters, JetPsiFactory.createType(project, name), + JetTestUtils.DUMMY_TRACE, true) +}