@@ -27,7 +27,7 @@ import typer.ConstFold
2727import typer .Checking .checkNonCyclic
2828import typer .Nullables ._
2929import util .Spans ._
30- import util .SourceFile
30+ import util .{ SourceFile , Property }
3131import ast .{Trees , tpd , untpd }
3232import Trees ._
3333import Decorators ._
@@ -1163,6 +1163,36 @@ class TreeUnpickler(reader: TastyReader,
11631163 readPathTerm()
11641164 }
11651165
1166+ /** Adapt constructor calls where class has only using clauses from old to new scheme.
1167+ * or class has mixed using clauses and other clauses.
1168+ * Old: leading (), new: nothing, or trailing () if all clauses are using clauses.
1169+ * This is neccessary so that we can read pre-3.2 Tasty correctly. There,
1170+ * constructor calls use the old scheme, but constructor definitions already
1171+ * use the new scheme, since they are reconstituted with normalizeIfConstructor.
1172+ */
1173+ def constructorApply (fn : Tree , args : List [Tree ]): Tree =
1174+ if fn.tpe.widen.isContextualMethod && args.isEmpty then
1175+ fn.withAttachment(SuppressedApplyToNone , ())
1176+ else
1177+ val fn1 = fn match
1178+ case Apply (fn1, Nil ) if fn.removeAttachment(InsertedApplyToNone ).isDefined =>
1179+ // We thought we inserted a final `()` but hit a user-written `()` instead.
1180+ // Remove the inserted `()`.
1181+ fn1
1182+ case _ =>
1183+ fn
1184+ val res = tpd.Apply (fn1, args)
1185+ if fn.removeAttachment(SuppressedApplyToNone ).isEmpty then
1186+ res
1187+ else res.tpe.widen match
1188+ case mt @ MethodType (params) =>
1189+ if params.isEmpty then
1190+ // Assume it's the final synthesized `()` parameter
1191+ res.appliedToNone.withAttachment(InsertedApplyToNone , ())
1192+ else if mt.isContextualMethod then
1193+ res.withAttachment(SuppressedApplyToNone , ())
1194+ else res
1195+
11661196 def readLengthTerm (): Tree = {
11671197 val end = readEnd()
11681198 val result =
@@ -1173,7 +1203,9 @@ class TreeUnpickler(reader: TastyReader,
11731203 tpd.Super (qual, mixId, mixTpe.typeSymbol)
11741204 case APPLY =>
11751205 val fn = readTerm()
1176- tpd.Apply (fn, until(end)(readTerm()))
1206+ val args = until(end)(readTerm())
1207+ if fn.symbol.isConstructor then constructorApply(fn, args)
1208+ else tpd.Apply (fn, args)
11771209 case TYPEAPPLY =>
11781210 tpd.TypeApply (readTerm(), until(end)(readTpt()))
11791211 case TYPED =>
@@ -1560,4 +1592,14 @@ object TreeUnpickler {
15601592 inline val AllDefs = 2 // add everything
15611593
15621594 class TreeWithoutOwner extends Exception
1595+
1596+ /** An attachment key indicating that an old-style leading () in a constructor
1597+ * call that is followed by a using clause was suppressed.
1598+ */
1599+ val SuppressedApplyToNone : Property .Key [Unit ] = Property .Key ()
1600+
1601+ /** An attachment key indicating that a trailing () in a constructor
1602+ * call that has otherwise only using clauses was inserted.
1603+ */
1604+ val InsertedApplyToNone : Property .Key [Unit ] = Property .Key ()
15631605}
0 commit comments