Skip to content

Commit 31a2f52

Browse files
authored
Merge pull request #3449 from dotty-staging/fix-#3448
Fix #3448 Improve Type inference for IFTs
2 parents 96d8661 + 561ef9c commit 31a2f52

File tree

5 files changed

+51
-13
lines changed

5 files changed

+51
-13
lines changed

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

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -948,11 +948,26 @@ class Definitions {
948948
false
949949
})
950950

951-
952951
def functionArity(tp: Type)(implicit ctx: Context) = tp.dealias.argInfos.length - 1
953952

954-
def isImplicitFunctionType(tp: Type)(implicit ctx: Context) =
955-
isFunctionType(tp) && tp.dealias.typeSymbol.name.isImplicitFunction
953+
/** Return underlying immplicit function type (i.e. instance of an ImplicitFunctionN class)
954+
* or NoType if none exists. The following types are considered as underlying types:
955+
* - the alias of an alias type
956+
* - the instance or origin of a TypeVar (i.e. the result of a stripTypeVar)
957+
* - the upper bound of a TypeParamRef in the current constraint
958+
*/
959+
def asImplicitFunctionType(tp: Type)(implicit ctx: Context): Type =
960+
tp.stripTypeVar.dealias match {
961+
case tp1: TypeParamRef if ctx.typerState.constraint.contains(tp1) =>
962+
asImplicitFunctionType(ctx.typeComparer.bounds(tp1).hiBound)
963+
case tp1 =>
964+
if (isFunctionType(tp1) && tp1.typeSymbol.name.isImplicitFunction) tp1
965+
else NoType
966+
}
967+
968+
/** Is `tp` an implicit function type? */
969+
def isImplicitFunctionType(tp: Type)(implicit ctx: Context): Boolean =
970+
asImplicitFunctionType(tp).exists
956971

957972
// ----- primitive value class machinery ------------------------------------------
958973

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -467,8 +467,8 @@ object ProtoTypes {
467467
case et: ExprType =>
468468
normalize(et.resultType, pt)
469469
case wtp =>
470-
if (defn.isImplicitFunctionType(wtp)) normalize(wtp.dealias.argInfos.last, pt)
471-
else tp
470+
val iftp = defn.asImplicitFunctionType(wtp)
471+
if (iftp.exists) normalize(iftp.argInfos.last, pt) else tp
472472
}
473473
}
474474

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1678,12 +1678,13 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
16781678
case _ => typedUnadapted(desugar(tree), pt)
16791679
}
16801680

1681-
if (defn.isImplicitFunctionType(pt) &&
1681+
val ifpt = defn.asImplicitFunctionType(pt)
1682+
if (ifpt.exists &&
16821683
xtree.isTerm &&
16831684
!untpd.isImplicitClosure(xtree) &&
16841685
!ctx.mode.is(Mode.ImplicitShadowing) &&
16851686
!ctx.isAfterTyper)
1686-
makeImplicitFunction(xtree, pt)
1687+
makeImplicitFunction(xtree, ifpt)
16871688
else xtree match {
16881689
case xtree: untpd.NameTree => typedNamed(xtree, pt)
16891690
case xtree => typedUnnamed(xtree)

tests/run/config.scala

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,6 @@ object Test extends App {
6565
import Configs._
6666
import Exceptions._
6767

68-
type PC[T] = Possibly[Configured[T]]
69-
70-
val names: PC[List[Name]] = readName :: Nil
71-
val firstNames: PC[List[String]] = names.map(_.first)
72-
val longest: PC[String] = firstNames.maxBy(_.length)
73-
7468
def readName: Configured[Possibly[Name]] = {
7569
val parts = config.name.split(" ")
7670
require(parts.length >= 2)
@@ -121,3 +115,18 @@ object OptionTest extends App {
121115
println(readPerson(config1))
122116
println(readPerson(config2))
123117
}
118+
119+
object FancyStuff {
120+
import Configs._
121+
import Exceptions._
122+
import Test._
123+
124+
type PC[T] = Possibly[Configured[T]]
125+
126+
val names: PC[List[Name]] = readName :: Nil
127+
val firstNames: PC[List[String]] = names.map(_.first)
128+
val longest: PC[String] = firstNames.maxBy(_.length)
129+
130+
val xs: List[PC[String]] = List(longest)
131+
val ys: PC[List[String]] = xs.map(x => x)
132+
}

tests/run/i3448.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
object Test extends App {
2+
3+
case class C(x: Int)
4+
type IF[T] = implicit C => T
5+
6+
val x: IF[Int] = implicitly[C].x
7+
8+
val xs0: List[IF[Int]] = List(implicit _ => x)
9+
val xs: List[IF[Int]] = List(x)
10+
val ys: IF[List[Int]] = xs.map(x => x)
11+
val zs = ys(C(22))
12+
assert(zs == List(22))
13+
}

0 commit comments

Comments
 (0)