Skip to content

Commit

Permalink
Merge pull request #6140 from milessabin/topic/si-10528
Browse files Browse the repository at this point in the history
Use solved type vars to improve bounds of undetermined vars
  • Loading branch information
adriaanm committed Jan 15, 2018
2 parents f5d5435 + dd31672 commit 68d6696
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/compiler/scala/tools/nsc/typechecker/Implicits.scala
Expand Up @@ -737,6 +737,7 @@ trait Implicits {
// we must be conservative in leaving type params in undetparams
// prototype == WildcardType: want to remove all inferred Nothings
val AdjustedTypeArgs(okParams, okArgs) = adjustTypeArgs(undetParams, tvars, targs)
enhanceBounds(okParams, okArgs, undetParams)

val subst: TreeTypeSubstituter =
if (okParams.isEmpty) EmptyTreeTypeSubstituter
Expand Down
16 changes: 16 additions & 0 deletions src/compiler/scala/tools/nsc/typechecker/Infer.scala
Expand Up @@ -712,6 +712,17 @@ trait Infer extends Checkable {
argtpes
}

// This is primarily a duplicte of enhanceBounds in typedAppliedTypeTree
// modified to use updateInfo rather than setInfo to avoid wiping out
// type history.
def enhanceBounds(okparams: List[Symbol], okargs: List[Type], undets: List[Symbol]): Unit =
undets.foreach { undet =>
val bounds = undet.info.bounds
val substBounds = bounds.subst(okparams, okargs)
if(bounds ne substBounds)
undet.updateInfo(substBounds)
}

private def isApplicableToMethod(undetparams: List[Symbol], mt: MethodType, argtpes0: List[Type], pt: Type): Boolean = {
val formals = formalTypes(mt.paramTypes, argtpes0.length, removeByName = false)
def missingArgs = missingParams[Type](argtpes0, mt.params, x => Some(x) collect { case NamedType(n, _) => n })
Expand All @@ -728,6 +739,7 @@ trait Infer extends Checkable {
def tryInstantiating(args: List[Type]) = falseIfNoInstance {
val restpe = mt resultType args
val AdjustedTypeArgs.Undets(okparams, okargs, leftUndet) = methTypeArgs(EmptyTree, undetparams, formals, restpe, args, pt)
enhanceBounds(okparams, okargs, leftUndet)
val restpeInst = restpe.instantiateTypeParams(okparams, okargs)
// #2665: must use weak conformance, not regular one (follow the monomorphic case above)
exprTypeArgs(leftUndet, restpeInst, pt, useWeaklyCompatible = true) match {
Expand Down Expand Up @@ -936,11 +948,14 @@ trait Infer extends Checkable {
List()
} else {
val AdjustedTypeArgs.Undets(okParams, okArgs, leftUndet) = adjustTypeArgs(tparams, tvars, targsStrict)
enhanceBounds(okParams, okArgs, leftUndet)

def solved_s = map2(okParams, okArgs)((p, a) => s"$p=$a") mkString ","
def undet_s = leftUndet match {
case Nil => ""
case ps => ps.mkString(", undet=", ",", "")
}

printTyping(tree, s"infer solved $solved_s$undet_s")
substExpr(tree, okParams, okArgs, pt)
leftUndet
Expand Down Expand Up @@ -982,6 +997,7 @@ trait Infer extends Checkable {

val AdjustedTypeArgs.AllArgsAndUndets(okparams, okargs, allargs, leftUndet) =
methTypeArgs(fn, undetparams, formals, restpe, argtpes, pt)
enhanceBounds(okparams, okargs, leftUndet)

if (checkBounds(fn, NoPrefix, NoSymbol, undetparams, allargs, "inferred ")) {
val treeSubst = new TreeTypeSubstituter(okparams, okargs)
Expand Down
3 changes: 3 additions & 0 deletions src/compiler/scala/tools/nsc/typechecker/Typers.scala
Expand Up @@ -5188,6 +5188,9 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
val asym = arg.symbol
def abounds = asym.info.bounds
def tbounds = tparam.info.bounds
// TODO investigate whether this should be merged with the near duplicate in Inferencer
// and whether or not we should avoid using setInfo here as well to avoid potentially
// trampling on type history.
def enhanceBounds(): Unit = {
val TypeBounds(lo0, hi0) = abounds
val TypeBounds(lo1, hi1) = tbounds.subst(tparams, argtypes)
Expand Down
35 changes: 35 additions & 0 deletions test/files/pos/t10528.scala
@@ -0,0 +1,35 @@
object Test {
trait Holder[A]
trait NilHolder[A] extends Holder[A]

trait Solve[A, H <: Holder[A]] {
type Output <: Holder[A]
}
type SolveAux[A, H <: Holder[A], O <: Holder[A]] = Solve[A, H] {type Output = O}

implicit def nilSolve[A] = new Solve[A, NilHolder[A]] {
override type Output = NilHolder[A]
}

trait WrapSolve[A, H <: Holder[A]] {
type Output <: Holder[A]
}

implicit def wrapAux[A, H <: Holder[A], O <: Holder[A]](implicit one : SolveAux[A, H, O]) =
new WrapSolve[A, H] {
override type Output = O
}

val wrapped = implicitly[WrapSolve[String, NilHolder[String]]]
}

object Test2 {
class Inv[T]
class Foo[T, U <: Inv[T]]

implicit def foo[T]: Foo[T, Inv[T]] = new Foo[T, Inv[T]]

def bar[T, U <: Inv[T]](implicit foo: Foo[T, U]): Inv[T] = new Inv[T]

val baz: Inv[Int] = bar
}

0 comments on commit 68d6696

Please sign in to comment.