Skip to content

Commit 319d478

Browse files
committed
Fix #4466: Update contexts of FunProto when something else is tried
Type inference does backtracking over several possibilities, with fresh contexts for each branch. If a FunProto is kept from one branch to the next we have to make sure that it uses the right context in the new branch.
1 parent c2de29d commit 319d478

File tree

5 files changed

+43
-8
lines changed

5 files changed

+43
-8
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1593,6 +1593,7 @@ object Types {
15931593
def isMatchedBy(tp: Type)(implicit ctx: Context): Boolean
15941594
def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context): T
15951595
def map(tm: TypeMap)(implicit ctx: Context): ProtoType
1596+
def withContext(ctx: Context): ProtoType = this
15961597
}
15971598

15981599
/** Implementations of this trait cache the results of `narrow`. */

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

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -216,15 +216,15 @@ object ProtoTypes {
216216
*/
217217
case class FunProto(args: List[untpd.Tree], resType: Type, typer: Typer)(implicit ctx: Context)
218218
extends UncachedGroundType with ApplyingProto {
219-
private[this] var myTypedArgs: List[Tree] = Nil
219+
private var myTypedArgs: List[Tree] = Nil
220220

221221
override def resultType(implicit ctx: Context) = resType
222222

223223
/** A map in which typed arguments can be stored to be later integrated in `typedArgs`. */
224-
private[this] var myTypedArg: SimpleIdentityMap[untpd.Tree, Tree] = SimpleIdentityMap.Empty
224+
private var myTypedArg: SimpleIdentityMap[untpd.Tree, Tree] = SimpleIdentityMap.Empty
225225

226226
/** A map recording the typer states and constraints in which arguments stored in myTypedArg were typed */
227-
private[this] var evalState: SimpleIdentityMap[untpd.Tree, (TyperState, Constraint)] = SimpleIdentityMap.Empty
227+
private var evalState: SimpleIdentityMap[untpd.Tree, (TyperState, Constraint)] = SimpleIdentityMap.Empty
228228

229229
def isMatchedBy(tp: Type)(implicit ctx: Context) =
230230
typer.isApplicable(tp, Nil, unforcedTypedArgs, resultType)
@@ -308,7 +308,7 @@ object ProtoTypes {
308308
def typeOfArg(arg: untpd.Tree)(implicit ctx: Context): Type =
309309
myTypedArg(arg).tpe
310310

311-
private[this] var myTupled: Type = NoType
311+
private var myTupled: Type = NoType
312312

313313
/** The same proto-type but with all arguments combined in a single tuple */
314314
def tupled: FunProto = myTupled match {
@@ -323,7 +323,7 @@ object ProtoTypes {
323323
def isTupled: Boolean = myTupled.isInstanceOf[FunProto]
324324

325325
/** If true, the application of this prototype was canceled. */
326-
private[this] var toDrop: Boolean = false
326+
private var toDrop: Boolean = false
327327

328328
/** Cancel the application of this prototype. This can happen for a nullary
329329
* application `f()` if `f` refers to a symbol that exists both in parameterless
@@ -347,6 +347,18 @@ object ProtoTypes {
347347
ta(ta.foldOver(x, typedArgs.tpes), resultType)
348348

349349
override def deepenProto(implicit ctx: Context) = derivedFunProto(args, resultType.deepenProto, typer)
350+
351+
override def withContext(newCtx: Context) =
352+
if (newCtx `eq` ctx) this
353+
else {
354+
val result = new FunProto(args, resType, typer)(newCtx)
355+
result.myTypedArgs = myTypedArgs
356+
result.myTypedArg = myTypedArg
357+
result.evalState = evalState
358+
result.myTupled = myTupled
359+
result.toDrop = toDrop
360+
result
361+
}
350362
}
351363

352364

@@ -356,6 +368,7 @@ object ProtoTypes {
356368
*/
357369
class FunProtoTyped(args: List[tpd.Tree], resultType: Type, typer: Typer)(implicit ctx: Context) extends FunProto(args, resultType, typer)(ctx) {
358370
override def typedArgs = args
371+
override def withContext(ctx: Context) = this
359372
}
360373

361374
/** A prototype for implicitly inferred views:

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2043,14 +2043,15 @@ class Typer extends Namer
20432043
}
20442044

20452045
def tryApply(implicit ctx: Context) = {
2046-
val sel = typedSelect(untpd.Select(untpd.TypedSplice(tree), nme.apply), pt)
2046+
val pt1 = pt.withContext(ctx)
2047+
val sel = typedSelect(untpd.Select(untpd.TypedSplice(tree), nme.apply), pt1)
20472048
sel.pushAttachment(InsertedApply, ())
20482049
if (sel.tpe.isError) sel
2049-
else try adapt(simplify(sel, pt, locked), pt, locked) finally sel.removeAttachment(InsertedApply)
2050+
else try adapt(simplify(sel, pt1, locked), pt1, locked) finally sel.removeAttachment(InsertedApply)
20502051
}
20512052

20522053
def tryImplicit(fallBack: => Tree) =
2053-
tryInsertImplicitOnQualifier(tree, pt, locked).getOrElse(fallBack)
2054+
tryInsertImplicitOnQualifier(tree, pt.withContext(ctx), locked).getOrElse(fallBack)
20542055

20552056
pt match {
20562057
case pt @ FunProto(Nil, _, _)

tests/pos/i4466a.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class Foo {
2+
def apply(bar: Bar[Int]): Unit = ()
3+
def apply(i: Int): Unit = ()
4+
}
5+
6+
class Bar[X](x: X)
7+
8+
class Main {
9+
val foo = new Foo
10+
foo(new Bar(0))
11+
}

tests/pos/i4466b.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
object Foo {
2+
case class Bar(map: Map[String, String])
3+
4+
object Bar {
5+
def apply(str: String): Bar = ???
6+
}
7+
8+
Bar(Map("A" -> "B"))
9+
}

0 commit comments

Comments
 (0)