Skip to content

Commit f4266b4

Browse files
committed
More systematic fix
The idea of cloning FunProtos has promise, but we need to make sure that all clones refer to the same core state.
1 parent 319d478 commit f4266b4

File tree

7 files changed

+48
-51
lines changed

7 files changed

+48
-51
lines changed

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -981,7 +981,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
981981

982982
def applyOverloaded(receiver: Tree, method: TermName, args: List[Tree], targs: List[Type], expectedType: Type, isAnnotConstructor: Boolean = false)(implicit ctx: Context): Tree = {
983983
val typer = ctx.typer
984-
val proto = new FunProtoTyped(args, expectedType, typer)
984+
val proto = new FunProtoTyped(args, expectedType)(typer)
985985
val denot = receiver.tpe.member(method)
986986
assert(denot.exists, i"no member $receiver . $method, members = ${receiver.tpe.decls}")
987987
val selected =

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
208208
": " ~ toText(tp.memberProto) ~ " }"
209209
case tp: ViewProto =>
210210
return toText(tp.argType) ~ " ?=>? " ~ toText(tp.resultType)
211-
case tp @ FunProto(args, resultType, _) =>
211+
case tp @ FunProto(args, resultType) =>
212212
val argsText = args match {
213213
case dummyTreeOfType(tp) :: Nil if !(tp isRef defn.NullClass) => "null: " ~ toText(tp)
214214
case _ => toTextGlobal(args, ", ")

compiler/src/dotty/tools/dotc/transform/Erasure.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,7 @@ object Erasure {
500500
val Apply(fun, args) = tree
501501
if (fun.symbol == defn.cbnArg)
502502
typedUnadapted(args.head, pt)
503-
else typedExpr(fun, FunProto(args, pt, this)) match {
503+
else typedExpr(fun, FunProto(args, pt)(this)) match {
504504
case fun1: Apply => // arguments passed in prototype were already passed
505505
fun1
506506
case fun1 =>

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
690690
def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = {
691691

692692
def realApply(implicit ctx: Context): Tree = track("realApply") {
693-
val originalProto = new FunProto(tree.args, IgnoredProto(pt), this)(argCtx(tree))
693+
val originalProto = new FunProto(tree.args, IgnoredProto(pt))(this)(argCtx(tree))
694694
val fun1 = typedExpr(tree.fun, originalProto)
695695

696696
// Warning: The following lines are dirty and fragile. We record that auto-tupling was demanded as
@@ -1365,7 +1365,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
13651365
alts filter (isApplicable(_, argTypes, resultType))
13661366

13671367
val candidates = pt match {
1368-
case pt @ FunProto(args, resultType, _) =>
1368+
case pt @ FunProto(args, resultType) =>
13691369
val numArgs = args.length
13701370
val normArgs = args.mapConserve {
13711371
case Block(Nil, expr) => expr

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -897,7 +897,7 @@ trait Implicits { self: Typer =>
897897

898898
lazy val funProto = fullProto match {
899899
case proto: ViewProto =>
900-
FunProto(untpd.TypedSplice(dummyTreeOfType(proto.argType)) :: Nil, proto.resultType, self)
900+
FunProto(untpd.TypedSplice(dummyTreeOfType(proto.argType)) :: Nil, proto.resultType)(self)
901901
case proto => proto
902902
}
903903

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

Lines changed: 40 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -210,28 +210,38 @@ object ProtoTypes {
210210

211211
trait ApplyingProto extends ProtoType
212212

213+
class FunProtoState {
214+
215+
/** The list of typed arguments, if all arguments are typed */
216+
var typedArgs: List[Tree] = Nil
217+
218+
/** A map in which typed arguments can be stored to be later integrated in `typedArgs`. */
219+
var typedArg: SimpleIdentityMap[untpd.Tree, Tree] = SimpleIdentityMap.Empty
220+
221+
/** A map recording the typer states and constraints in which arguments stored in myTypedArg were typed */
222+
var evalState: SimpleIdentityMap[untpd.Tree, (TyperState, Constraint)] = SimpleIdentityMap.Empty
223+
224+
/** The tupled version of this prototype, if it has been computed */
225+
var tupled: Type = NoType
226+
227+
/** If true, the application of this prototype was canceled. */
228+
var toDrop: Boolean = false
229+
}
230+
213231
/** A prototype for expressions that appear in function position
214232
*
215233
* [](args): resultType
216234
*/
217-
case class FunProto(args: List[untpd.Tree], resType: Type, typer: Typer)(implicit ctx: Context)
235+
case class FunProto(args: List[untpd.Tree], resType: Type)(typer: Typer, state: FunProtoState = new FunProtoState)(implicit ctx: Context)
218236
extends UncachedGroundType with ApplyingProto {
219-
private var myTypedArgs: List[Tree] = Nil
220-
221237
override def resultType(implicit ctx: Context) = resType
222238

223-
/** A map in which typed arguments can be stored to be later integrated in `typedArgs`. */
224-
private var myTypedArg: SimpleIdentityMap[untpd.Tree, Tree] = SimpleIdentityMap.Empty
225-
226-
/** A map recording the typer states and constraints in which arguments stored in myTypedArg were typed */
227-
private var evalState: SimpleIdentityMap[untpd.Tree, (TyperState, Constraint)] = SimpleIdentityMap.Empty
228-
229239
def isMatchedBy(tp: Type)(implicit ctx: Context) =
230240
typer.isApplicable(tp, Nil, unforcedTypedArgs, resultType)
231241

232242
def derivedFunProto(args: List[untpd.Tree] = this.args, resultType: Type, typer: Typer = this.typer) =
233243
if ((args eq this.args) && (resultType eq this.resultType) && (typer eq this.typer)) this
234-
else new FunProto(args, resultType, typer)
244+
else new FunProto(args, resultType)(typer)
235245

236246
override def notApplied = WildcardType
237247

@@ -244,19 +254,19 @@ object ProtoTypes {
244254
* @return True if all arguments have types (in particular, no types were forgotten).
245255
*/
246256
def allArgTypesAreCurrent()(implicit ctx: Context): Boolean = {
247-
evalState foreachBinding { (arg, tstateConstr) =>
257+
state.evalState foreachBinding { (arg, tstateConstr) =>
248258
if ((tstateConstr._1.uncommittedAncestor.constraint `ne` ctx.typerState.constraint) ||
249259
tstateConstr._2.isRetracted) {
250-
typr.println(i"need to invalidate $arg / ${myTypedArg(arg)}, ${tstateConstr._2}, current = ${ctx.typerState.constraint}")
251-
myTypedArg = myTypedArg.remove(arg)
252-
evalState = evalState.remove(arg)
260+
typr.println(i"need to invalidate $arg / ${state.typedArg(arg)}, ${tstateConstr._2}, current = ${ctx.typerState.constraint}")
261+
state.typedArg = state.typedArg.remove(arg)
262+
state.evalState = state.evalState.remove(arg)
253263
}
254264
}
255-
myTypedArg.size == args.length
265+
state.typedArg.size == args.length
256266
}
257267

258268
private def cacheTypedArg(arg: untpd.Tree, typerFn: untpd.Tree => Tree, force: Boolean)(implicit ctx: Context): Tree = {
259-
var targ = myTypedArg(arg)
269+
var targ = state.typedArg(arg)
260270
if (targ == null) {
261271
if (!force && untpd.functionWithUnknownParamType(arg).isDefined)
262272
// If force = false, assume ? rather than reporting an error.
@@ -270,8 +280,8 @@ object ProtoTypes {
270280
// typerstate if there are no errors. If we also omitted the next two lines
271281
// when warning were emitted, `pos/t1756.scala` would fail when run with -feature.
272282
// It would produce an orphan type parameter for CI when pickling.
273-
myTypedArg = myTypedArg.updated(arg, targ)
274-
evalState = evalState.updated(arg, (ctx.typerState, ctx.typerState.constraint))
283+
state.typedArg = state.typedArg.updated(arg, targ)
284+
state.evalState = state.evalState.updated(arg, (ctx.typerState, ctx.typerState.constraint))
275285
}
276286
}
277287
}
@@ -285,9 +295,9 @@ object ProtoTypes {
285295
* "missing parameter type" error
286296
*/
287297
private def typedArgs(force: Boolean): List[Tree] = {
288-
if (myTypedArgs.size != args.length)
289-
myTypedArgs = args.mapconserve(cacheTypedArg(_, typer.typed(_), force))
290-
myTypedArgs
298+
if (state.typedArgs.size != args.length)
299+
state.typedArgs = args.mapconserve(cacheTypedArg(_, typer.typed(_), force))
300+
state.typedArgs
291301
}
292302

293303
def typedArgs: List[Tree] = typedArgs(force = true)
@@ -306,24 +316,19 @@ object ProtoTypes {
306316
* @pre `arg` has been typed before
307317
*/
308318
def typeOfArg(arg: untpd.Tree)(implicit ctx: Context): Type =
309-
myTypedArg(arg).tpe
310-
311-
private var myTupled: Type = NoType
319+
state.typedArg(arg).tpe
312320

313321
/** The same proto-type but with all arguments combined in a single tuple */
314-
def tupled: FunProto = myTupled match {
322+
def tupled: FunProto = state.tupled match {
315323
case pt: FunProto =>
316324
pt
317325
case _ =>
318-
myTupled = new FunProto(untpd.Tuple(args) :: Nil, resultType, typer)
326+
state.tupled = new FunProto(untpd.Tuple(args) :: Nil, resultType)(typer)
319327
tupled
320328
}
321329

322330
/** Somebody called the `tupled` method of this prototype */
323-
def isTupled: Boolean = myTupled.isInstanceOf[FunProto]
324-
325-
/** If true, the application of this prototype was canceled. */
326-
private var toDrop: Boolean = false
331+
def isTupled: Boolean = state.tupled.isInstanceOf[FunProto]
327332

328333
/** Cancel the application of this prototype. This can happen for a nullary
329334
* application `f()` if `f` refers to a symbol that exists both in parameterless
@@ -333,10 +338,10 @@ object ProtoTypes {
333338
*/
334339
def markAsDropped() = {
335340
assert(args.isEmpty)
336-
toDrop = true
341+
state.toDrop = true
337342
}
338343

339-
def isDropped: Boolean = toDrop
344+
def isDropped: Boolean = state.toDrop
340345

341346
override def toString = s"FunProto(${args mkString ","} => $resultType)"
342347

@@ -350,23 +355,15 @@ object ProtoTypes {
350355

351356
override def withContext(newCtx: Context) =
352357
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-
}
358+
else new FunProto(args, resType)(typer, state)(newCtx)
362359
}
363360

364361

365362
/** A prototype for expressions that appear in function position
366363
*
367364
* [](args): resultType, where args are known to be typed
368365
*/
369-
class FunProtoTyped(args: List[tpd.Tree], resultType: Type, typer: Typer)(implicit ctx: Context) extends FunProto(args, resultType, typer)(ctx) {
366+
class FunProtoTyped(args: List[tpd.Tree], resultType: Type)(typer: Typer)(implicit ctx: Context) extends FunProto(args, resultType)(typer)(ctx) {
370367
override def typedArgs = args
371368
override def withContext(ctx: Context) = this
372369
}
@@ -405,7 +402,7 @@ object ProtoTypes {
405402
}
406403

407404
class UnapplyFunProto(argType: Type, typer: Typer)(implicit ctx: Context) extends FunProto(
408-
untpd.TypedSplice(dummyTreeOfType(argType))(ctx) :: Nil, WildcardType, typer)
405+
untpd.TypedSplice(dummyTreeOfType(argType))(ctx) :: Nil, WildcardType)(typer)
409406

410407
/** A prototype for expressions [] that are type-parameterized:
411408
*

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -870,7 +870,7 @@ class Typer extends Namer
870870
expr1.tpe
871871
case _ =>
872872
val protoArgs = args map (_ withType WildcardType)
873-
val callProto = FunProto(protoArgs, WildcardType, this)
873+
val callProto = FunProto(protoArgs, WildcardType)(this)
874874
val expr1 = typedExpr(expr, callProto)
875875
fnBody = cpy.Apply(fnBody)(untpd.TypedSplice(expr1), args)
876876
expr1.tpe
@@ -2054,7 +2054,7 @@ class Typer extends Namer
20542054
tryInsertImplicitOnQualifier(tree, pt.withContext(ctx), locked).getOrElse(fallBack)
20552055

20562056
pt match {
2057-
case pt @ FunProto(Nil, _, _)
2057+
case pt @ FunProto(Nil, _)
20582058
if tree.symbol.allOverriddenSymbols.exists(_.info.isNullaryMethod) &&
20592059
tree.getAttachment(DroppedEmptyArgs).isEmpty =>
20602060
tree.putAttachment(DroppedEmptyArgs, ())

0 commit comments

Comments
 (0)