Skip to content

Commit fcaf860

Browse files
committed
Map regular function types to impure function types when unpickling
Map regular function types to impure function types when unpickling a class under -Ycc that was not itself compiled with -Ycc.
1 parent eedef75 commit fcaf860

File tree

6 files changed

+73
-4
lines changed

6 files changed

+73
-4
lines changed

compiler/src/dotty/tools/dotc/cc/CaptureOps.scala

+15-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ package cc
55
import core.*
66
import Types.*, Symbols.*, Contexts.*, Annotations.*
77
import ast.{tpd, untpd}
8-
import Decorators.*
8+
import Decorators.*, NameOps.*
99
import config.Printers.capt
1010
import util.Property.Key
1111
import tpd.*
@@ -71,3 +71,17 @@ extension (tp: Type)
7171
atd.derivedAnnotatedType(parent.stripCapturing, annot)
7272
case _ =>
7373
tp
74+
75+
/** Under -Ycc, map regular function type to impure function type
76+
*/
77+
def adaptFunctionType(using Context): Type = tp match
78+
case AppliedType(fn, args)
79+
if ctx.settings.Ycc.value && defn.isFunctionClass(fn.typeSymbol) =>
80+
val fname = fn.typeSymbol.name
81+
defn.FunctionType(
82+
fname.functionArity,
83+
isContextual = fname.isContextFunction,
84+
isErased = fname.isErasedFunction,
85+
isImpure = true).appliedTo(args)
86+
case _ =>
87+
tp

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

+15-2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import util.SourceFile
2929
import ast.{Trees, tpd, untpd}
3030
import Trees._
3131
import Decorators._
32+
import transform.SymUtils._
33+
import cc.adaptFunctionType
3234

3335
import dotty.tools.tasty.{TastyBuffer, TastyReader}
3436
import TastyBuffer._
@@ -83,6 +85,9 @@ class TreeUnpickler(reader: TastyReader,
8385
/** The root owner tree. See `OwnerTree` class definition. Set by `enterTopLevel`. */
8486
private var ownerTree: OwnerTree = _
8587

88+
/** Was unpickled class compiled with -Ycc? */
89+
private var wasCaptureChecked: Boolean = false
90+
8691
private def registerSym(addr: Addr, sym: Symbol) =
8792
symAtAddr(addr) = sym
8893

@@ -353,7 +358,7 @@ class TreeUnpickler(reader: TastyReader,
353358
// Note that the lambda "rt => ..." is not equivalent to a wildcard closure!
354359
// Eta expansion of the latter puts readType() out of the expression.
355360
case APPLIEDtype =>
356-
readType().appliedTo(until(end)(readType()))
361+
postProcessFunction(readType().appliedTo(until(end)(readType())))
357362
case TYPEBOUNDS =>
358363
val lo = readType()
359364
if nothingButMods(end) then
@@ -466,6 +471,12 @@ class TreeUnpickler(reader: TastyReader,
466471
def readTermRef()(using Context): TermRef =
467472
readType().asInstanceOf[TermRef]
468473

474+
/** Under -Ycc, map all function types to impure function types,
475+
* unless the unpickled class was also compiled with -Ycc.
476+
*/
477+
private def postProcessFunction(tp: Type)(using Context): Type =
478+
if wasCaptureChecked then tp else tp.adaptFunctionType
479+
469480
// ------ Reading definitions -----------------------------------------------------
470481

471482
private def nothingButMods(end: Addr): Boolean =
@@ -601,6 +612,8 @@ class TreeUnpickler(reader: TastyReader,
601612
}
602613
registerSym(start, sym)
603614
if (isClass) {
615+
if sym.owner.is(Package) && annots.exists(_.symbol == defn.CaptureCheckedAnnot) then
616+
wasCaptureChecked = true
604617
sym.completer.withDecls(newScope)
605618
forkAt(templateStart).indexTemplateParams()(using localContext(sym))
606619
}
@@ -1261,7 +1274,7 @@ class TreeUnpickler(reader: TastyReader,
12611274
val args = until(end)(readTpt())
12621275
val tree = untpd.AppliedTypeTree(tycon, args)
12631276
val ownType = ctx.typeAssigner.processAppliedType(tree, tycon.tpe.safeAppliedTo(args.tpes))
1264-
tree.withType(ownType)
1277+
tree.withType(postProcessFunction(ownType))
12651278
case ANNOTATEDtpt =>
12661279
Annotated(readTpt(), readTerm())
12671280
case LAMBDAtpt =>

compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala

+4-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import scala.collection.mutable
3030
import scala.collection.mutable.ListBuffer
3131
import scala.annotation.switch
3232
import reporting._
33+
import cc.adaptFunctionType
3334

3435
object Scala2Unpickler {
3536

@@ -818,7 +819,9 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
818819
// special-case in erasure, see TypeErasure#eraseInfo.
819820
OrType(args(0), args(1), soft = false)
820821
}
821-
else if (args.nonEmpty) tycon.safeAppliedTo(EtaExpandIfHK(sym.typeParams, args.map(translateTempPoly)))
822+
else if args.nonEmpty then
823+
tycon.safeAppliedTo(EtaExpandIfHK(sym.typeParams, args.map(translateTempPoly)))
824+
.adaptFunctionType
822825
else if (sym.typeParams.nonEmpty) tycon.EtaExpand(sym.typeParams)
823826
else tycon
824827
case TYPEBOUNDStpe =>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
object Lib:
2+
extension [A](xs: Seq[A])
3+
def mapp[B](f: A => B): Seq[B] =
4+
xs.map(f.asInstanceOf[A -> B])
5+
6+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import language.experimental.saferExceptions
2+
import Lib.*
3+
4+
class LimitExceeded extends Exception
5+
6+
val limit = 10e9
7+
8+
def f(x: Double): Double throws LimitExceeded =
9+
if x < limit then x * x else throw LimitExceeded()
10+
11+
@main def test(xs: Double*) =
12+
try println(xs.mapp(f).sum)
13+
catch case ex: LimitExceeded => println("too large")
14+
15+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import language.experimental.saferExceptions
2+
3+
class LimitExceeded extends Exception
4+
5+
val limit = 10e9
6+
7+
extension [A](xs: Seq[A])
8+
def mapp[B](f: A => B): Seq[B] =
9+
xs.map(f.asInstanceOf[A -> B])
10+
11+
def f(x: Double): Double throws LimitExceeded =
12+
if x < limit then x * x else throw LimitExceeded()
13+
14+
@main def test(xs: Double*) =
15+
try println(xs.mapp(f).sum + xs.map(f).sum)
16+
catch case ex: LimitExceeded => println("too large")
17+
18+

0 commit comments

Comments
 (0)