Skip to content

Commit b40b519

Browse files
authored
Merge pull request #6271 from dotty-staging/topic/i6238
Preserve TypeLambdas in wildApprox
2 parents bbbf2ec + 1a6ca25 commit b40b519

File tree

3 files changed

+200
-22
lines changed

3 files changed

+200
-22
lines changed

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

+29-22
Original file line numberDiff line numberDiff line change
@@ -579,47 +579,48 @@ object ProtoTypes {
579579
/** Approximate occurrences of parameter types and uninstantiated typevars
580580
* by wildcard types.
581581
*/
582-
private def wildApprox(tp: Type, theMap: WildApproxMap, seen: Set[TypeParamRef])(implicit ctx: Context): Type = tp match {
582+
private def wildApprox(tp: Type, theMap: WildApproxMap, seen: Set[TypeParamRef], internal: Set[TypeLambda])(implicit ctx: Context): Type = tp match {
583583
case tp: NamedType => // default case, inlined for speed
584584
val isPatternBoundTypeRef = tp.isInstanceOf[TypeRef] && tp.symbol.is(Flags.Case) && !tp.symbol.isClass
585585
if (isPatternBoundTypeRef) WildcardType(tp.underlying.bounds)
586586
else if (tp.symbol.isStatic || (tp.prefix `eq` NoPrefix)) tp
587-
else tp.derivedSelect(wildApprox(tp.prefix, theMap, seen))
587+
else tp.derivedSelect(wildApprox(tp.prefix, theMap, seen, internal))
588588
case tp @ AppliedType(tycon, args) =>
589-
wildApprox(tycon, theMap, seen) match {
589+
wildApprox(tycon, theMap, seen, internal) match {
590590
case _: WildcardType => WildcardType // this ensures we get a * type
591591
case tycon1 => tp.derivedAppliedType(tycon1,
592-
args.mapConserve(arg => wildApprox(arg, theMap, seen)))
592+
args.mapConserve(arg => wildApprox(arg, theMap, seen, internal)))
593593
}
594594
case tp: RefinedType => // default case, inlined for speed
595595
tp.derivedRefinedType(
596-
wildApprox(tp.parent, theMap, seen),
596+
wildApprox(tp.parent, theMap, seen, internal),
597597
tp.refinedName,
598-
wildApprox(tp.refinedInfo, theMap, seen))
598+
wildApprox(tp.refinedInfo, theMap, seen, internal))
599599
case tp: AliasingBounds => // default case, inlined for speed
600-
tp.derivedAlias(wildApprox(tp.alias, theMap, seen))
600+
tp.derivedAlias(wildApprox(tp.alias, theMap, seen, internal))
601+
case tp @ TypeParamRef(tl, _) if internal.contains(tl) => tp
601602
case tp @ TypeParamRef(poly, pnum) =>
602603
def wildApproxBounds(bounds: TypeBounds) =
603604
if (seen.contains(tp)) WildcardType
604-
else WildcardType(wildApprox(bounds, theMap, seen + tp).bounds)
605+
else WildcardType(wildApprox(bounds, theMap, seen + tp, internal).bounds)
605606
def unconstrainedApprox = wildApproxBounds(poly.paramInfos(pnum))
606607
def approxPoly =
607608
if (ctx.mode.is(Mode.TypevarsMissContext)) unconstrainedApprox
608609
else
609610
ctx.typerState.constraint.entry(tp) match {
610611
case bounds: TypeBounds => wildApproxBounds(bounds)
611612
case NoType => unconstrainedApprox
612-
case inst => wildApprox(inst, theMap, seen)
613+
case inst => wildApprox(inst, theMap, seen, internal)
613614
}
614615
approxPoly
615616
case TermParamRef(mt, pnum) =>
616-
WildcardType(TypeBounds.upper(wildApprox(mt.paramInfos(pnum), theMap, seen)))
617+
WildcardType(TypeBounds.upper(wildApprox(mt.paramInfos(pnum), theMap, seen, internal)))
617618
case tp: TypeVar =>
618-
wildApprox(tp.underlying, theMap, seen)
619+
wildApprox(tp.underlying, theMap, seen, internal)
619620
case tp: AndType =>
620621
def approxAnd = {
621-
val tp1a = wildApprox(tp.tp1, theMap, seen)
622-
val tp2a = wildApprox(tp.tp2, theMap, seen)
622+
val tp1a = wildApprox(tp.tp1, theMap, seen, internal)
623+
val tp2a = wildApprox(tp.tp2, theMap, seen, internal)
623624
def wildBounds(tp: Type) =
624625
if (tp.isInstanceOf[WildcardType]) tp.bounds else TypeBounds.upper(tp)
625626
if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
@@ -630,33 +631,39 @@ object ProtoTypes {
630631
approxAnd
631632
case tp: OrType =>
632633
def approxOr = {
633-
val tp1a = wildApprox(tp.tp1, theMap, seen)
634-
val tp2a = wildApprox(tp.tp2, theMap, seen)
634+
val tp1a = wildApprox(tp.tp1, theMap, seen, internal)
635+
val tp2a = wildApprox(tp.tp2, theMap, seen, internal)
635636
if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
636637
WildcardType(tp1a.bounds | tp2a.bounds)
637638
else
638639
tp.derivedOrType(tp1a, tp2a)
639640
}
640641
approxOr
641642
case tp: SelectionProto =>
642-
tp.derivedSelectionProto(tp.name, wildApprox(tp.memberProto, theMap, seen), NoViewsAllowed)
643+
tp.derivedSelectionProto(tp.name, wildApprox(tp.memberProto, theMap, seen, internal), NoViewsAllowed)
643644
case tp: ViewProto =>
644645
tp.derivedViewProto(
645-
wildApprox(tp.argType, theMap, seen),
646-
wildApprox(tp.resultType, theMap, seen))
646+
wildApprox(tp.argType, theMap, seen, internal),
647+
wildApprox(tp.resultType, theMap, seen, internal))
647648
case _: ThisType | _: BoundType => // default case, inlined for speed
648649
tp
650+
case tl: TypeLambda =>
651+
val internal1 = internal + tl
652+
tl.derivedLambdaType(
653+
paramInfos = tl.paramInfos.mapConserve(wildApprox(_, theMap, seen, internal1).bounds),
654+
resType = wildApprox(tl.resType, theMap, seen, internal1)
655+
)
649656
case _ =>
650-
(if (theMap != null && seen.eq(theMap.seen)) theMap else new WildApproxMap(seen))
657+
(if (theMap != null && seen.eq(theMap.seen)) theMap else new WildApproxMap(seen, internal))
651658
.mapOver(tp)
652659
}
653660

654-
final def wildApprox(tp: Type)(implicit ctx: Context): Type = wildApprox(tp, null, Set.empty)
661+
final def wildApprox(tp: Type)(implicit ctx: Context): Type = wildApprox(tp, null, Set.empty, Set.empty)
655662

656663
@sharable object AssignProto extends UncachedGroundType with MatchAlways
657664

658-
private[ProtoTypes] class WildApproxMap(val seen: Set[TypeParamRef])(implicit ctx: Context) extends TypeMap {
659-
def apply(tp: Type): Type = wildApprox(tp, this, seen)
665+
private[ProtoTypes] class WildApproxMap(val seen: Set[TypeParamRef], val internal: Set[TypeLambda])(implicit ctx: Context) extends TypeMap {
666+
def apply(tp: Type): Type = wildApprox(tp, this, seen, internal)
660667
}
661668

662669
/** Dummy tree to be used as an argument of a FunProto or ViewProto type */

tests/pos/i6238.scala

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
object K1 {
2+
class Foo[T]
3+
4+
class Bar[F[_]]
5+
object Bar {
6+
implicit def barF[F[_]](implicit fooF: Foo[Bar[F]]): Bar[F] = null
7+
}
8+
9+
class A[T]
10+
object A {
11+
implicit def fooA[F[_[_]]](implicit barB: F[B]): Foo[F[A]] = null
12+
}
13+
14+
class B[T]
15+
object B {
16+
implicit def fooB[F[_[_]]]: Foo[F[B]] = null
17+
}
18+
}
19+
20+
object K1U {
21+
class Foo[T]
22+
23+
class Bar[F[_ <: Int]]
24+
object Bar {
25+
implicit def barF[F[_ <: Int]](implicit fooF: Foo[Bar[F]]): Bar[F] = null
26+
}
27+
28+
class A[T <: Int]
29+
object A {
30+
implicit def fooA[F[_[_ <: Int]]](implicit barB: F[B]): Foo[F[A]] = null
31+
}
32+
33+
class B[T <: Int]
34+
object B {
35+
implicit def fooB[F[_[_ <: Int]]]: Foo[F[B]] = null
36+
}
37+
}
38+
39+
object K1L {
40+
class Foo[T]
41+
42+
class Bar[F[_ >: Int]]
43+
object Bar {
44+
implicit def barF[F[_ >: Int]](implicit fooF: Foo[Bar[F]]): Bar[F] = null
45+
}
46+
47+
class A[T >: Int]
48+
object A {
49+
implicit def fooA[F[_[_ >: Int]]](implicit barB: F[B]): Foo[F[A]] = null
50+
}
51+
52+
class B[T >: Int]
53+
object B {
54+
implicit def fooB[F[_[_ >: Int]]]: Foo[F[B]] = null
55+
}
56+
}
57+
58+
object K11 {
59+
class Foo[T]
60+
61+
class Bar[F[_[_]]]
62+
object Bar {
63+
implicit def barF[F[_[_]]](implicit fooF: Foo[Bar[F]]): Bar[F] = null
64+
}
65+
66+
class A[T[_]]
67+
object A {
68+
implicit def fooA[F[_[_[_]]]](implicit barB: F[B]): Foo[F[A]] = null
69+
}
70+
71+
class B[T[_]]
72+
object B {
73+
implicit def fooB[F[_[_[_]]]]: Foo[F[B]] = null
74+
}
75+
}
76+
77+
object K2 {
78+
class Foo[T]
79+
80+
class Bar[F[_, _]]
81+
object Bar {
82+
implicit def barF[F[_, _]](implicit fooF: Foo[Bar[F]]): Bar[F] = null
83+
}
84+
85+
class A[T, U]
86+
object A {
87+
implicit def fooA[F[_[_, _]]](implicit barB: F[B]): Foo[F[A]] = null
88+
}
89+
90+
class B[T, U]
91+
object B {
92+
implicit def fooB[F[_[_, _]]]: Foo[F[B]] = null
93+
}
94+
}
95+
96+
object Test {
97+
{
98+
import K1._
99+
implicitly[Bar[A]]
100+
}
101+
102+
{
103+
import K1U._
104+
implicitly[Bar[A]]
105+
}
106+
107+
{
108+
import K1L._
109+
implicitly[Bar[A]]
110+
}
111+
112+
{
113+
import K11._
114+
implicitly[Bar[A]]
115+
}
116+
117+
{
118+
import K2._
119+
implicitly[Bar[A]]
120+
}
121+
}

tests/run/implicit-functors2.scala

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
object Utils {
2+
type Id[t] = t
3+
type Const[c] = [t] => c
4+
}
5+
6+
import Utils._
7+
8+
abstract class ErasedInstances { type FT }
9+
class ErasedProductInstances(override val toString: String) extends ErasedInstances
10+
class ErasedCoproductInstances(override val toString: String) extends ErasedInstances
11+
12+
object K1 {
13+
type Instances[F[_[_]], T[_]] = ErasedInstances { type FT = F[T] ; type C = F }
14+
}
15+
16+
class Functor[F[_]](override val toString: String)
17+
18+
object Functor {
19+
inline def apply[F[_]](implicit ff: Functor[F]): Functor[F] = ff
20+
21+
implicit val functorId: Functor[Id] = new Functor("functorId")
22+
23+
implicit def functorNested[F[_], G[_]](implicit ff: Functor[F], fg: Functor[G]): Functor[[t] => F[G[t]]] = new Functor(s"functorNested($ff, $fg)")
24+
25+
implicit def functorGen[F[_]](implicit inst: K1.Instances[Functor, F]): Functor[F] = new Functor(s"functorGen($inst")
26+
27+
implicit def functorConst[T]: Functor[Const[T]] = new Functor(s"functorConst")
28+
}
29+
30+
sealed trait Opt[+A]
31+
object Opt {
32+
implicit def optInstances[F[_[_]]](implicit fs: F[Sm], fn: F[[t] => Nn.type]): ErasedCoproductInstances { type FT = F[Opt] ; type C = F } =
33+
new ErasedCoproductInstances(s"optInstances($fs, $fn)") { type FT = F[Opt] ; type C = F }
34+
}
35+
36+
case class Sm[+A](value: A) extends Opt[A]
37+
object Sm {
38+
implicit def smInstances[F[_[_]]](implicit fi: F[Id]): ErasedProductInstances { type FT = F[Sm] ; type C = F } =
39+
new ErasedProductInstances(s"smInstances($fi)") { type FT = F[Sm] ; type C = F }
40+
}
41+
42+
case object Nn extends Opt[Nothing]
43+
44+
object Test extends App {
45+
assert(Functor[Const[Nn.type]].toString == "functorConst")
46+
assert(Functor[Sm].toString == "functorGen(smInstances(functorId)")
47+
assert(Functor[Opt].toString == "functorGen(optInstances(functorGen(smInstances(functorId), functorConst)")
48+
assert(Functor[[t] => Opt[Opt[t]]].toString == "functorNested(functorGen(optInstances(functorGen(smInstances(functorId), functorConst), functorGen(optInstances(functorGen(smInstances(functorId), functorConst))")
49+
}
50+

0 commit comments

Comments
 (0)