Skip to content

Fix #6385: Don't instantiate hk type constructors too early #6467

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
Original file line number Diff line number Diff line change
Expand Up @@ -520,16 +520,6 @@ trait ConstraintHandling[AbstractContext] {
}
}

/** Instantiate `param` to `tp` if the constraint stays satisfiable */
protected def tryInstantiate(param: TypeParamRef, tp: Type)(implicit actx: AbstractContext): Boolean = {
val saved = constraint
constraint =
if (addConstraint(param, tp, fromBelow = true) &&
addConstraint(param, tp, fromBelow = false)) constraint.replace(param, tp)
else saved
constraint ne saved
}

/** Check that constraint is fully propagated. See comment in Config.checkConstraintsPropagated */
def checkPropagated(msg: => String)(result: Boolean)(implicit actx: AbstractContext): Boolean = {
if (Config.checkConstraintsPropagated && result && addConstraintInvocations == 0) {
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -818,7 +818,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
tycon1.dealiasKeepRefiningAnnots match {
case tycon1: TypeParamRef =>
(tycon1 == tycon2 ||
canConstrain(tycon1) && tryInstantiate(tycon1, tycon2)) &&
canConstrain(tycon1) && isSubType(tycon1, tycon2)) &&
isSubArgs(args1, args2, tp1, tparams)
case tycon1: TypeRef =>
tycon2.dealiasKeepRefiningAnnots match {
Expand Down Expand Up @@ -892,7 +892,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
tl => tparams1.map(tparam => tl.integrate(tparams, tparam.paramInfo).bounds),
tl => tp1base.tycon.appliedTo(args1.take(lengthDiff) ++
tparams1.indices.toList.map(tl.paramRefs(_))))
(assumedTrue(tycon2) || tryInstantiate(tycon2, tycon1.ensureLambdaSub)) &&
(assumedTrue(tycon2) || isSubType(tycon1.ensureLambdaSub, tycon2)) &&
recur(tp1, tycon1.appliedTo(args2))
}
}
Expand Down Expand Up @@ -977,7 +977,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
case param1: TypeParamRef =>
def canInstantiate = tp2 match {
case AppliedType(tycon2, args2) =>
tryInstantiate(param1, tycon2.ensureLambdaSub) && isSubArgs(args1, args2, tp1, tycon2.typeParams)
isSubType(param1, tycon2.ensureLambdaSub) && isSubArgs(args1, args2, tp1, tycon2.typeParams)
case _ =>
false
}
Expand Down
27 changes: 27 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/Inferencing.scala
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,33 @@ object Inferencing {
}
}

/** For all type parameters occurring in `tp`:
* If the bounds of `tp` in the current constraint are equal wrt =:=,
* instantiate the type parameter to the lower bound's approximation
* (approximation because of possible F-bounds).
*/
def replaceSingletons(tp: Type)(implicit ctx: Context): Unit = {
val tr = new TypeTraverser {
def traverse(tp: Type): Unit = {
tp match {
case param: TypeParamRef =>
val constraint = ctx.typerState.constraint
constraint.entry(param) match {
case TypeBounds(lo, hi)
if (hi frozen_<:< lo) =>
val inst = ctx.typeComparer.approximation(param, fromBelow = true)
typr.println(i"replace singleton $param := $inst")
ctx.typerState.constraint = constraint.replace(param, inst)
case _ =>
}
case _ =>
}
traverseChildren(tp)
}
}
tr.traverse(tp)
}

/** If `tree` has a type lambda type, infer its type parameters by comparing with expected type `pt` */
def inferTypeParams(tree: Tree, pt: Type)(implicit ctx: Context): Tree = tree.tpe match {
case tl: TypeLambda =>
Expand Down
6 changes: 5 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2607,7 +2607,11 @@ class Typer extends Namer
def adaptNoArgsImplicitMethod(wtp: MethodType): Tree = {
assert(wtp.isImplicitMethod)
val tvarsToInstantiate = tvarsInParams(tree, locked).distinct
wtp.paramInfos.foreach(instantiateSelected(_, tvarsToInstantiate))
def instantiate(tp: Type): Unit = {
instantiateSelected(tp, tvarsToInstantiate)
replaceSingletons(tp)
}
wtp.paramInfos.foreach(instantiate)
val constr = ctx.typerState.constraint

def dummyArg(tp: Type) = untpd.Ident(nme.???).withTypeUnchecked(tp)
Expand Down
1 change: 1 addition & 0 deletions compiler/test/dotc/pos-test-pickling.blacklist
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
i94-nada.scala
i1812.scala
i1867.scala
i3067.scala
Expand Down
1 change: 1 addition & 0 deletions compiler/test/dotty/tools/dotc/CompilationTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ class CompilationTests extends ParallelTesting {
compileFile("tests/neg-custom-args/nopredef.scala", defaultOptions.and("-Yno-predef")),
compileFile("tests/neg-custom-args/noimports.scala", defaultOptions.and("-Yno-imports")),
compileFile("tests/neg-custom-args/noimports2.scala", defaultOptions.and("-Yno-imports")),
compileFile("tests/neg-custom-args/i1650.scala", allowDeepSubtypes),
compileFile("tests/neg-custom-args/i3882.scala", allowDeepSubtypes),
compileFile("tests/neg-custom-args/i4372.scala", allowDeepSubtypes),
compileFile("tests/neg-custom-args/i1754.scala", allowDeepSubtypes),
Expand Down
File renamed without changes.
11 changes: 11 additions & 0 deletions tests/neg/i6385a.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class Box[F[_]]

class C[X]
class D[X] extends C[String]

object Test {
def f[F[_]](x: Box[F]) = ???
def db: Box[D] = ???
def cb: Box[C] = db // error
f[[X] => C[X]](db) // error
}
File renamed without changes.
10 changes: 10 additions & 0 deletions tests/pos/i4147.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
trait Higher[F[_]]
trait Super[A]
trait Sub[A] extends Super[A]

object Test {
implicit def higherSub: Higher[Sub] = ???
implicit def deriv[F[_]](implicit bla: Higher[F]): F[String] = ???

val x: Super[String] = deriv
}
17 changes: 17 additions & 0 deletions tests/pos/i6385.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
trait Tc1[A]
trait Tc2[A] extends Tc1[A]

class PinTypeTo[K[_]]
object PinTypeTo {
implicit val pinType: PinTypeTo[Tc2] = new PinTypeTo[Tc2]
}

class X
object X {
implicit def Tc2Instance[F[x] >: Tc2[x]: PinTypeTo]: F[X] = new Tc2[X] {}
}

object app extends App {
implicitly[Tc2[X]]
implicitly[Tc1[X]]
}