Skip to content

Commit

Permalink
Map regular function types to impure function types when unpickling
Browse files Browse the repository at this point in the history
Map regular function types to impure function types when unpickling a class
under -Ycc that was not itself compiled with -Ycc.
  • Loading branch information
odersky committed Mar 26, 2022
1 parent 0444048 commit ba262b1
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 4 deletions.
16 changes: 15 additions & 1 deletion compiler/src/dotty/tools/dotc/cc/CaptureOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ package cc
import core.*
import Types.*, Symbols.*, Contexts.*, Annotations.*
import ast.{tpd, untpd}
import Decorators.*
import Decorators.*, NameOps.*
import config.Printers.capt
import util.Property.Key
import tpd.*
Expand Down Expand Up @@ -71,3 +71,17 @@ extension (tp: Type)
atd.derivedAnnotatedType(parent.stripCapturing, annot)
case _ =>
tp

/** Under -Ycc, map regular function type to impure function type
*/
def adaptFunctionType(using Context): Type = tp match
case AppliedType(fn, args)
if ctx.settings.Ycc.value && defn.isFunctionClass(fn.typeSymbol) =>
val fname = fn.typeSymbol.name
defn.FunctionType(
fname.functionArity,
isContextual = fname.isContextFunction,
isErased = fname.isErasedFunction,
isImpure = true).appliedTo(args)
case _ =>
tp
17 changes: 15 additions & 2 deletions compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import util.SourceFile
import ast.{Trees, tpd, untpd}
import Trees._
import Decorators._
import transform.SymUtils._
import cc.adaptFunctionType

import dotty.tools.tasty.{TastyBuffer, TastyReader}
import TastyBuffer._
Expand Down Expand Up @@ -85,6 +87,9 @@ class TreeUnpickler(reader: TastyReader,
/** The root owner tree. See `OwnerTree` class definition. Set by `enterTopLevel`. */
private var ownerTree: OwnerTree = _

/** Was unpickled class compiled with -Ycc? */
private var wasCaptureChecked: Boolean = false

private def registerSym(addr: Addr, sym: Symbol) =
symAtAddr(addr) = sym

Expand Down Expand Up @@ -355,7 +360,7 @@ class TreeUnpickler(reader: TastyReader,
// Note that the lambda "rt => ..." is not equivalent to a wildcard closure!
// Eta expansion of the latter puts readType() out of the expression.
case APPLIEDtype =>
readType().appliedTo(until(end)(readType()))
postProcessFunction(readType().appliedTo(until(end)(readType())))
case TYPEBOUNDS =>
val lo = readType()
if nothingButMods(end) then
Expand Down Expand Up @@ -468,6 +473,12 @@ class TreeUnpickler(reader: TastyReader,
def readTermRef()(using Context): TermRef =
readType().asInstanceOf[TermRef]

/** Under -Ycc, map all function types to impure function types,
* unless the unpickled class was also compiled with -Ycc.
*/
private def postProcessFunction(tp: Type)(using Context): Type =
if wasCaptureChecked then tp else tp.adaptFunctionType

// ------ Reading definitions -----------------------------------------------------

private def nothingButMods(end: Addr): Boolean =
Expand Down Expand Up @@ -603,6 +614,8 @@ class TreeUnpickler(reader: TastyReader,
}
registerSym(start, sym)
if (isClass) {
if sym.owner.is(Package) && annots.exists(_.symbol == defn.CaptureCheckedAnnot) then
wasCaptureChecked = true
sym.completer.withDecls(newScope)
forkAt(templateStart).indexTemplateParams()(using localContext(sym))
}
Expand Down Expand Up @@ -1263,7 +1276,7 @@ class TreeUnpickler(reader: TastyReader,
val args = until(end)(readTpt())
val tree = untpd.AppliedTypeTree(tycon, args)
val ownType = ctx.typeAssigner.processAppliedType(tree, tycon.tpe.safeAppliedTo(args.tpes))
tree.withType(ownType)
tree.withType(postProcessFunction(ownType))
case ANNOTATEDtpt =>
Annotated(readTpt(), readTerm())
case LAMBDAtpt =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import scala.collection.mutable
import scala.collection.mutable.ListBuffer
import scala.annotation.switch
import reporting._
import cc.adaptFunctionType

object Scala2Unpickler {

Expand Down Expand Up @@ -820,7 +821,9 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
// special-case in erasure, see TypeErasure#eraseInfo.
OrType(args(0), args(1), soft = false)
}
else if (args.nonEmpty) tycon.safeAppliedTo(EtaExpandIfHK(sym.typeParams, args.map(translateTempPoly)))
else if args.nonEmpty then
tycon.safeAppliedTo(EtaExpandIfHK(sym.typeParams, args.map(translateTempPoly)))
.adaptFunctionType
else if (sym.typeParams.nonEmpty) tycon.EtaExpand(sym.typeParams)
else tycon
case TYPEBOUNDStpe =>
Expand Down
6 changes: 6 additions & 0 deletions tests/pos-custom-args/captures/capt-separate/Lib_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
object Lib:
extension [A](xs: Seq[A])
def mapp[B](f: A => B): Seq[B] =
xs.map(f.asInstanceOf[A -> B])


15 changes: 15 additions & 0 deletions tests/pos-custom-args/captures/capt-separate/Test_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import language.experimental.saferExceptions
import Lib.*

class LimitExceeded extends Exception

val limit = 10e9

def f(x: Double): Double throws LimitExceeded =
if x < limit then x * x else throw LimitExceeded()

@main def test(xs: Double*) =
try println(xs.mapp(f).sum)
catch case ex: LimitExceeded => println("too large")


18 changes: 18 additions & 0 deletions tests/pos-custom-args/captures/saferExceptions.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import language.experimental.saferExceptions

class LimitExceeded extends Exception

val limit = 10e9

extension [A](xs: Seq[A])
def mapp[B](f: A => B): Seq[B] =
xs.map(f.asInstanceOf[A -> B])

def f(x: Double): Double throws LimitExceeded =
if x < limit then x * x else throw LimitExceeded()

@main def test(xs: Double*) =
try println(xs.mapp(f).sum + xs.map(f).sum)
catch case ex: LimitExceeded => println("too large")


0 comments on commit ba262b1

Please sign in to comment.