Skip to content

Commit 6e3e34d

Browse files
authored
Merge pull request #13884 from dotty-staging/fix-13842
Try to instantiate type variables in tryInsertImplicitOnQualifier
2 parents 4d81752 + 3183820 commit 6e3e34d

File tree

4 files changed

+53
-16
lines changed

4 files changed

+53
-16
lines changed

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

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,12 @@ object Inferencing {
9696
* their instantiation could uncover new type members. However that search is best
9797
* effort only. It might miss type variables that appear in structures involving
9898
* alias types and type projections.
99+
* @param applied Test is done in a `tryInsertImplicitOnQualifier` application.
100+
* In this case, we always try to instantiate TypeVars in type arguments.
101+
* If `applied` is false, we only try that in arguments that may affect
102+
* the result type.
99103
*/
100-
def couldInstantiateTypeVar(tp: Type)(using Context): Boolean = tp.dealias match
104+
def couldInstantiateTypeVar(tp: Type, applied: Boolean = false)(using Context): Boolean = tp.dealias match
101105
case tvar: TypeVar
102106
if !tvar.isInstantiated
103107
&& ctx.typerState.constraint.contains(tvar)
@@ -120,14 +124,14 @@ object Inferencing {
120124
case _ => Nil
121125
case _ => Nil
122126
case _ => Nil
123-
couldInstantiateTypeVar(tycon)
124-
|| argsInResult.exists(couldInstantiateTypeVar)
127+
couldInstantiateTypeVar(tycon, applied)
128+
|| (if applied then args else argsInResult).exists(couldInstantiateTypeVar(_, applied))
125129
case RefinedType(parent, _, _) =>
126-
couldInstantiateTypeVar(parent)
130+
couldInstantiateTypeVar(parent, applied)
127131
case tp: AndOrType =>
128-
couldInstantiateTypeVar(tp.tp1) || couldInstantiateTypeVar(tp.tp2)
132+
couldInstantiateTypeVar(tp.tp1, applied) || couldInstantiateTypeVar(tp.tp2, applied)
129133
case AnnotatedType(tp, _) =>
130-
couldInstantiateTypeVar(tp)
134+
couldInstantiateTypeVar(tp, applied)
131135
case _ =>
132136
false
133137

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

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ object Typer {
8181
*/
8282
private val InsertedApply = new Property.Key[Unit]
8383

84+
/** An attachment on a result of an implicit conversion or extension method
85+
* that was added by tryInsertImplicitOnQualifier. Needed to prevent infinite
86+
* expansions in error cases (e.g. in fuzzy/i9293.scala).
87+
*/
88+
private val InsertedImplicitOnQualifier = new Property.Key[Unit]
89+
8490
/** An attachment on a tree `t` occurring as part of a `t()` where
8591
* the `()` was dropped by the Typer.
8692
*/
@@ -3141,21 +3147,30 @@ class Typer extends Namer
31413147
}
31423148

31433149
/** If this tree is a select node `qual.name` (possibly applied to type variables)
3144-
* that does not conform to `pt`, try to insert an implicit conversion `c` around
3145-
* `qual` so that `c(qual).name` conforms to `pt`.
3150+
* that does not conform to `pt`, try two mitigations:
3151+
* 1. Instantiate any TypeVars in the widened type of `tree` with their lower bounds.
3152+
* 2. Try to insert an implicit conversion `c` around `qual` so that
3153+
* `c(qual).name` conforms to `pt`.
31463154
*/
31473155
def tryInsertImplicitOnQualifier(tree: Tree, pt: Type, locked: TypeVars)(using Context): Option[Tree] = trace(i"try insert impl on qualifier $tree $pt") {
31483156
tree match
31493157
case tree @ Select(qual, name) if name != nme.CONSTRUCTOR =>
3150-
val selProto = SelectionProto(name, pt, NoViewsAllowed, privateOK = false)
3151-
if selProto.isMatchedBy(qual.tpe) then None
3158+
if couldInstantiateTypeVar(qual.tpe.widen, applied = true)
3159+
then
3160+
Some(adapt(tree, pt, locked))
31523161
else
3153-
tryEither {
3154-
val tree1 = tryExtensionOrConversion(tree, pt, pt, qual, locked, NoViewsAllowed, inSelect = false)
3155-
if tree1.isEmpty then None
3156-
else Some(adapt(tree1, pt, locked))
3157-
} { (_, _) => None
3158-
}
3162+
val selProto = SelectionProto(name, pt, NoViewsAllowed, privateOK = false)
3163+
if selProto.isMatchedBy(qual.tpe) || tree.hasAttachment(InsertedImplicitOnQualifier) then
3164+
None
3165+
else
3166+
tryEither {
3167+
val tree1 = tryExtensionOrConversion(tree, pt, pt, qual, locked, NoViewsAllowed, inSelect = false)
3168+
if tree1.isEmpty then None
3169+
else
3170+
tree1.putAttachment(InsertedImplicitOnQualifier, ())
3171+
Some(adapt(tree1, pt, locked))
3172+
} { (_, _) => None
3173+
}
31593174
case TypeApply(fn, args) if args.forall(_.isInstanceOf[untpd.InferredTypeTree]) =>
31603175
tryInsertImplicitOnQualifier(fn, pt, locked)
31613176
case _ => None

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ i8182.scala
6868
# local lifted value in annotation argument has different position after pickling
6969
i2797a
7070

71+
# Late instantiation of type variable in tryInsertImplicitOnQualifier
72+
# allows to simplify a type that was already computed
73+
i13842.scala
74+
7175
# GADT cast applied to singleton type difference
7276
i4176-gadt.scala
7377

tests/pos/i13842.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
class Parent { class E }
2+
3+
object ChildA extends Parent
4+
5+
object ChildB extends Parent
6+
7+
class Printer[C <: Parent](val child: C):
8+
def print22(e: child.E): String = ""
9+
10+
def test =
11+
Printer(ChildA).print22(new ChildA.E) // does not work
12+
13+
//Printer[ChildA.type](ChildA).print22(new ChildA.E) // works
14+
//val p = Printer(ChildA); p.print22(new ChildA.E) // works

0 commit comments

Comments
 (0)