wip: equality constraints
diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java
index db345e7..48d7777 100644
--- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java
+++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java
@@ -12607,6 +12607,11 @@
             runTest("compiler/testData/codegen/box/inference/integerLiteralTypeInLamdaReturnType.kt");
         }
 
+        @TestMetadata("interactionWihtIntersectionTypesAndJava.kt")
+        public void testInteractionWihtIntersectionTypesAndJava() throws Exception {
+            runTest("compiler/testData/codegen/box/inference/interactionWihtIntersectionTypesAndJava.kt");
+        }
+
         @TestMetadata("kt10822.kt")
         public void testKt10822() throws Exception {
             runTest("compiler/testData/codegen/box/inference/kt10822.kt");
diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/AbstractTypeCheckerContextForConstraintSystem.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/AbstractTypeCheckerContextForConstraintSystem.kt
index 2dcbce8..5060ebb 100644
--- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/AbstractTypeCheckerContextForConstraintSystem.kt
+++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/AbstractTypeCheckerContextForConstraintSystem.kt
@@ -32,6 +32,8 @@
         isFromNullabilityConstraint: Boolean = false
     )
 
+    abstract fun addEqualityConstraint(typeVariable: TypeConstructorMarker, type: KotlinTypeMarker)
+
     override fun getLowerCapturedTypePolicy(subType: SimpleTypeMarker, superType: CapturedTypeMarker): LowerCapturedTypePolicy {
         return when {
             isMyTypeVariable(subType) -> {
diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintInjector.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintInjector.kt
index 20a3674..486e5bc 100644
--- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintInjector.kt
+++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintInjector.kt
@@ -56,8 +56,52 @@
 
         val typeCheckerContext = TypeCheckerContext(c, IncorporationConstraintPosition(position, initialConstraint))
 
-        addSubTypeConstraintAndIncorporateIt(c, a, b, typeCheckerContext)
-        addSubTypeConstraintAndIncorporateIt(c, b, a, typeCheckerContext)
+        with(c) {
+            if (a.isSimpleType() && !a.isMarkedNullable() && a.typeConstructor().isTypeVariable()) {
+                addEqualityConstraintForVariableAndIncorporateIt(c, a, b, typeCheckerContext)
+            } else {
+                addSubTypeConstraintAndIncorporateIt(c, a, b, typeCheckerContext)
+                addSubTypeConstraintAndIncorporateIt(c, b, a, typeCheckerContext)
+            }
+        }
+
+    }
+
+    private fun addEqualityConstraintForVariableAndIncorporateIt(
+        c: Context,
+        typeVariable: KotlinTypeMarker,
+        upperType: KotlinTypeMarker,
+        typeCheckerContext: TypeCheckerContext
+    ) {
+        typeCheckerContext.setConstrainingTypesToPrintDebugInfo(typeVariable, upperType)
+        typeCheckerContext.addEqualityConstraint(typeVariable.typeConstructor(c), upperType)
+
+        while (typeCheckerContext.hasConstraintsToProcess()) {
+            for ((typeVariable, constraint) in typeCheckerContext.extractAllConstraints()!!) {
+                if (c.shouldWeSkipConstraint(typeVariable, constraint)) continue
+
+                val constraints =
+                    c.notFixedTypeVariables[typeVariable.freshTypeConstructor(c)] ?: typeCheckerContext.fixedTypeVariable(typeVariable)
+
+                // it is important, that we add constraint here(not inside TypeCheckerContext), because inside incorporation we read constraints
+                constraints.addConstraint(constraint)?.let {
+                    if (!constraint.isNullabilityConstraint) {
+                        constraintIncorporator.incorporate(typeCheckerContext, typeVariable, it)
+                    }
+                }
+            }
+
+            val contextOps = c as? ConstraintSystemOperation
+            if (!typeCheckerContext.hasConstraintsToProcess() ||
+                (contextOps != null && c.notFixedTypeVariables.all { typeVariable ->
+                    typeVariable.value.constraints.any { constraint ->
+                        constraint.kind == EQUALITY && contextOps.isProperType(constraint.type)
+                    }
+                })
+            ) {
+                break
+            }
+        }
     }
 
     private fun addSubTypeConstraintAndIncorporateIt(
@@ -102,7 +146,7 @@
     }
 
     private fun Context.shouldWeSkipConstraint(typeVariable: TypeVariableMarker, constraint: Constraint): Boolean {
-        assert(constraint.kind != EQUALITY)
+//        assert(constraint.kind != EQUALITY)
 
         val constraintType = constraint.type
 
@@ -216,6 +260,10 @@
             isFromNullabilityConstraint: Boolean
         ) = addConstraint(typeVariable, subType, LOWER, isFromNullabilityConstraint)
 
+        override fun addEqualityConstraint(typeVariable: TypeConstructorMarker, type: KotlinTypeMarker) {
+            addConstraint(typeVariable, type, EQUALITY, false)
+        }
+
         private fun isCapturedTypeFromSubtyping(type: KotlinTypeMarker) =
             when ((type as? CapturedTypeMarker)?.captureStatus()) {
                 null, CaptureStatus.FROM_EXPRESSION -> false
diff --git a/compiler/testData/codegen/box/inference/interactionWihtIntersectionTypesAndJava.kt b/compiler/testData/codegen/box/inference/interactionWihtIntersectionTypesAndJava.kt
new file mode 100644
index 0000000..5acc169
--- /dev/null
+++ b/compiler/testData/codegen/box/inference/interactionWihtIntersectionTypesAndJava.kt
@@ -0,0 +1,46 @@
+// FULL_JDK
+// TARGET_BACKEND: JVM
+// WITH_RUNTIME
+
+// FILE: Bag.java
+
+import java.util.*;
+import java.util.function.Supplier;
+
+public class Bag<K, V, C extends E, E extends Collection<V>> {
+    public Bag(Map<K, C> backingMap, Supplier<? extends C> innerCollectionCreator) {
+        // TODO
+    }
+
+    public final void add(K key, V value) {
+        //TODO
+    }
+
+    public static class ListBag<K, V> extends Bag<K, V, List<V>, List<V>> {
+        public ListBag(Map<K, List<V>> backingMap, Supplier<? extends List<V>> innerCollectionCreator) {
+            super(backingMap, innerCollectionCreator);
+        }
+    }
+}
+
+// FILE: test.kt
+
+import java.util.*
+
+fun <K, V, C : E, E : Collection<V>, B : Bag<K, V, C, E>> Iterable<V>.groupByTo(
+    destination: B,
+    keySelector: (V) -> K
+): B = TODO()
+
+enum class Format { Foo, Bar }
+class Instance(val format: Format)
+
+fun test(allInstances: List<Instance>, e: EnumMap<Format, List<Instance>>) {
+    val doesntWork = allInstances.groupByTo(
+        Bag.ListBag(e, ::LinkedList)
+    ) { it.format }
+}
+
+fun box(): String {
+    return "OK"
+}
\ No newline at end of file
diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java
index 469ad6a..7652661 100644
--- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java
+++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java
@@ -13832,6 +13832,11 @@
             runTest("compiler/testData/codegen/box/inference/integerLiteralTypeInLamdaReturnType.kt");
         }
 
+        @TestMetadata("interactionWihtIntersectionTypesAndJava.kt")
+        public void testInteractionWihtIntersectionTypesAndJava() throws Exception {
+            runTest("compiler/testData/codegen/box/inference/interactionWihtIntersectionTypesAndJava.kt");
+        }
+
         @TestMetadata("kt10822.kt")
         public void testKt10822() throws Exception {
             runTest("compiler/testData/codegen/box/inference/kt10822.kt");
diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java
index 456f567..f96021d 100644
--- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java
+++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java
@@ -13832,6 +13832,11 @@
             runTest("compiler/testData/codegen/box/inference/integerLiteralTypeInLamdaReturnType.kt");
         }
 
+        @TestMetadata("interactionWihtIntersectionTypesAndJava.kt")
+        public void testInteractionWihtIntersectionTypesAndJava() throws Exception {
+            runTest("compiler/testData/codegen/box/inference/interactionWihtIntersectionTypesAndJava.kt");
+        }
+
         @TestMetadata("kt10822.kt")
         public void testKt10822() throws Exception {
             runTest("compiler/testData/codegen/box/inference/kt10822.kt");
diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java
index 8b66528..8a4eea6 100644
--- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java
+++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java
@@ -12607,6 +12607,11 @@
             runTest("compiler/testData/codegen/box/inference/integerLiteralTypeInLamdaReturnType.kt");
         }
 
+        @TestMetadata("interactionWihtIntersectionTypesAndJava.kt")
+        public void testInteractionWihtIntersectionTypesAndJava() throws Exception {
+            runTest("compiler/testData/codegen/box/inference/interactionWihtIntersectionTypesAndJava.kt");
+        }
+
         @TestMetadata("kt10822.kt")
         public void testKt10822() throws Exception {
             runTest("compiler/testData/codegen/box/inference/kt10822.kt");