Skip to content

Commit

Permalink
Fix lack of type avoidance in argument lifting
Browse files Browse the repository at this point in the history
We need to manually increase the nestingLevel of symbols created by
EtaExpansion#lift to compensate for the fact that they will end up in a block.

Fixes scala#15174.
  • Loading branch information
smarter authored and bishabosha committed May 20, 2022
1 parent 045e483 commit 495b7e8
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 4 deletions.
7 changes: 4 additions & 3 deletions compiler/src/dotty/tools/dotc/core/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -512,14 +512,15 @@ object Symbols {
// ---- Symbol creation methods ----------------------------------

/** Create a symbol from its fields (info may be lazy) */
def newSymbol[N <: Name](
def newSymbol[N <: Name](using Context)(
owner: Symbol,
name: N,
flags: FlagSet,
info: Type,
privateWithin: Symbol = NoSymbol,
coord: Coord = NoCoord)(using Context): Symbol { type ThisName = N } = {
val sym = new Symbol(coord, ctx.base.nextSymId, ctx.nestingLevel).asInstanceOf[Symbol { type ThisName = N }]
coord: Coord = NoCoord,
nestingLevel: Int = ctx.nestingLevel): Symbol { type ThisName = N } = {
val sym = new Symbol(coord, ctx.base.nextSymId, nestingLevel).asInstanceOf[Symbol { type ThisName = N }]
val denot = SymDenotation(sym, owner, name, flags, info, privateWithin)
sym.denot = denot
sym
Expand Down
5 changes: 4 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ abstract class Lifter {
// don't instantiate here, as the type params could be further constrained, see tests/pos/pickleinf.scala
var liftedType = expr.tpe.widen.deskolemized
if (liftedFlags.is(Method)) liftedType = ExprType(liftedType)
val lifted = newSymbol(ctx.owner, name, liftedFlags | Synthetic, liftedType, coord = spanCoord(expr.span))
val lifted = newSymbol(ctx.owner, name, liftedFlags | Synthetic, liftedType, coord = spanCoord(expr.span),
// Lifted definitions will be added to a local block, so they need to be
// at a higher nesting level to prevent leaks. See tests/pos/i15174.scala
nestingLevel = ctx.nestingLevel + 1)
defs += liftedDef(lifted, expr)
.withSpan(expr.span)
.changeNonLocalOwners(lifted)
Expand Down
34 changes: 34 additions & 0 deletions tests/pos/i15174.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
trait Error
sealed abstract class Codec[A] {
type AvroType
def encode(a: A): Either[Error, AvroType]
// def decode(value: Any): Either[Error, A]
}

object Codec {
type Aux[AvroType0, A] = Codec[A] {
type AvroType = AvroType0
}

final def instance[AvroType0, A](
encode: A => Either[Error, AvroType0],
// decode: Any => Either[Error, A]
): Codec.Aux[AvroType0, A] = ???

implicit final def option[A](implicit codec: Codec[A]): Codec[Option[A]] = ???
given Codec.Aux[Int, Int] = ???
}


@main def test() = {
implicit val codec: Codec[Option[Int]] =
Codec.instance(
Codec.option[Int].encode
// expands to:
// {
// val a: Codec[Option[Int]] = Codec.option[Int](Codec.given_Aux_Int_Int)
// a.encode
// },
// Codec.option[Int].decode
)
}

0 comments on commit 495b7e8

Please sign in to comment.