Skip to content

Commit 24946d8

Browse files
authored
Merge pull request #6467 from dotty-staging/fix-#6385
Fix #6385: Don't instantiate hk type constructors too early
2 parents bd54027 + 4c7ca9a commit 24946d8

File tree

11 files changed

+75
-14
lines changed

11 files changed

+75
-14
lines changed

compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala

-10
Original file line numberDiff line numberDiff line change
@@ -520,16 +520,6 @@ trait ConstraintHandling[AbstractContext] {
520520
}
521521
}
522522

523-
/** Instantiate `param` to `tp` if the constraint stays satisfiable */
524-
protected def tryInstantiate(param: TypeParamRef, tp: Type)(implicit actx: AbstractContext): Boolean = {
525-
val saved = constraint
526-
constraint =
527-
if (addConstraint(param, tp, fromBelow = true) &&
528-
addConstraint(param, tp, fromBelow = false)) constraint.replace(param, tp)
529-
else saved
530-
constraint ne saved
531-
}
532-
533523
/** Check that constraint is fully propagated. See comment in Config.checkConstraintsPropagated */
534524
def checkPropagated(msg: => String)(result: Boolean)(implicit actx: AbstractContext): Boolean = {
535525
if (Config.checkConstraintsPropagated && result && addConstraintInvocations == 0) {

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

+3-3
Original file line numberDiff line numberDiff line change
@@ -818,7 +818,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
818818
tycon1.dealiasKeepRefiningAnnots match {
819819
case tycon1: TypeParamRef =>
820820
(tycon1 == tycon2 ||
821-
canConstrain(tycon1) && tryInstantiate(tycon1, tycon2)) &&
821+
canConstrain(tycon1) && isSubType(tycon1, tycon2)) &&
822822
isSubArgs(args1, args2, tp1, tparams)
823823
case tycon1: TypeRef =>
824824
tycon2.dealiasKeepRefiningAnnots match {
@@ -892,7 +892,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
892892
tl => tparams1.map(tparam => tl.integrate(tparams, tparam.paramInfo).bounds),
893893
tl => tp1base.tycon.appliedTo(args1.take(lengthDiff) ++
894894
tparams1.indices.toList.map(tl.paramRefs(_))))
895-
(assumedTrue(tycon2) || tryInstantiate(tycon2, tycon1.ensureLambdaSub)) &&
895+
(assumedTrue(tycon2) || isSubType(tycon1.ensureLambdaSub, tycon2)) &&
896896
recur(tp1, tycon1.appliedTo(args2))
897897
}
898898
}
@@ -977,7 +977,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
977977
case param1: TypeParamRef =>
978978
def canInstantiate = tp2 match {
979979
case AppliedType(tycon2, args2) =>
980-
tryInstantiate(param1, tycon2.ensureLambdaSub) && isSubArgs(args1, args2, tp1, tycon2.typeParams)
980+
isSubType(param1, tycon2.ensureLambdaSub) && isSubArgs(args1, args2, tp1, tycon2.typeParams)
981981
case _ =>
982982
false
983983
}

compiler/src/dotty/tools/dotc/typer/Inferencing.scala

+27
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,33 @@ object Inferencing {
138138
}
139139
}
140140

141+
/** For all type parameters occurring in `tp`:
142+
* If the bounds of `tp` in the current constraint are equal wrt =:=,
143+
* instantiate the type parameter to the lower bound's approximation
144+
* (approximation because of possible F-bounds).
145+
*/
146+
def replaceSingletons(tp: Type)(implicit ctx: Context): Unit = {
147+
val tr = new TypeTraverser {
148+
def traverse(tp: Type): Unit = {
149+
tp match {
150+
case param: TypeParamRef =>
151+
val constraint = ctx.typerState.constraint
152+
constraint.entry(param) match {
153+
case TypeBounds(lo, hi)
154+
if (hi frozen_<:< lo) =>
155+
val inst = ctx.typeComparer.approximation(param, fromBelow = true)
156+
typr.println(i"replace singleton $param := $inst")
157+
ctx.typerState.constraint = constraint.replace(param, inst)
158+
case _ =>
159+
}
160+
case _ =>
161+
}
162+
traverseChildren(tp)
163+
}
164+
}
165+
tr.traverse(tp)
166+
}
167+
141168
/** If `tree` has a type lambda type, infer its type parameters by comparing with expected type `pt` */
142169
def inferTypeParams(tree: Tree, pt: Type)(implicit ctx: Context): Tree = tree.tpe match {
143170
case tl: TypeLambda =>

compiler/src/dotty/tools/dotc/typer/Typer.scala

+5-1
Original file line numberDiff line numberDiff line change
@@ -2607,7 +2607,11 @@ class Typer extends Namer
26072607
def adaptNoArgsImplicitMethod(wtp: MethodType): Tree = {
26082608
assert(wtp.isImplicitMethod)
26092609
val tvarsToInstantiate = tvarsInParams(tree, locked).distinct
2610-
wtp.paramInfos.foreach(instantiateSelected(_, tvarsToInstantiate))
2610+
def instantiate(tp: Type): Unit = {
2611+
instantiateSelected(tp, tvarsToInstantiate)
2612+
replaceSingletons(tp)
2613+
}
2614+
wtp.paramInfos.foreach(instantiate)
26112615
val constr = ctx.typerState.constraint
26122616

26132617
def dummyArg(tp: Type) = untpd.Ident(nme.???).withTypeUnchecked(tp)

compiler/test/dotc/pos-test-pickling.blacklist

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
i94-nada.scala
12
i1812.scala
23
i1867.scala
34
i3067.scala

compiler/test/dotty/tools/dotc/CompilationTests.scala

+1
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ class CompilationTests extends ParallelTesting {
164164
compileFile("tests/neg-custom-args/nopredef.scala", defaultOptions.and("-Yno-predef")),
165165
compileFile("tests/neg-custom-args/noimports.scala", defaultOptions.and("-Yno-imports")),
166166
compileFile("tests/neg-custom-args/noimports2.scala", defaultOptions.and("-Yno-imports")),
167+
compileFile("tests/neg-custom-args/i1650.scala", allowDeepSubtypes),
167168
compileFile("tests/neg-custom-args/i3882.scala", allowDeepSubtypes),
168169
compileFile("tests/neg-custom-args/i4372.scala", allowDeepSubtypes),
169170
compileFile("tests/neg-custom-args/i1754.scala", allowDeepSubtypes),
File renamed without changes.

tests/neg/i6385a.scala

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class Box[F[_]]
2+
3+
class C[X]
4+
class D[X] extends C[String]
5+
6+
object Test {
7+
def f[F[_]](x: Box[F]) = ???
8+
def db: Box[D] = ???
9+
def cb: Box[C] = db // error
10+
f[[X] => C[X]](db) // error
11+
}
File renamed without changes.

tests/pos/i4147.scala

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
trait Higher[F[_]]
2+
trait Super[A]
3+
trait Sub[A] extends Super[A]
4+
5+
object Test {
6+
implicit def higherSub: Higher[Sub] = ???
7+
implicit def deriv[F[_]](implicit bla: Higher[F]): F[String] = ???
8+
9+
val x: Super[String] = deriv
10+
}

tests/pos/i6385.scala

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
trait Tc1[A]
2+
trait Tc2[A] extends Tc1[A]
3+
4+
class PinTypeTo[K[_]]
5+
object PinTypeTo {
6+
implicit val pinType: PinTypeTo[Tc2] = new PinTypeTo[Tc2]
7+
}
8+
9+
class X
10+
object X {
11+
implicit def Tc2Instance[F[x] >: Tc2[x]: PinTypeTo]: F[X] = new Tc2[X] {}
12+
}
13+
14+
object app extends App {
15+
implicitly[Tc2[X]]
16+
implicitly[Tc1[X]]
17+
}

0 commit comments

Comments
 (0)