Skip to content

Commit d7290ee

Browse files
committed
Try to avoid static symbols if leaving them would make a leak
Possible fix for #9314 Typer.ensureNoLocalRefs doesn't avoid local static refs like anonymous class instances to allow typing more specific expected types with e.g. refinements. Unfortunately this can cause leaks when expected types have to be inferred. This PR tries to fix this problem by adding a fallback that avoids all local symbols if this leak were to happen.
1 parent 65a86ae commit d7290ee

File tree

3 files changed

+11
-4
lines changed

3 files changed

+11
-4
lines changed

compiler/src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -507,12 +507,12 @@ object TypeOps:
507507
* does not update `ctx.nestingLevel` when entering a block so I'm leaving
508508
* this as Future Work™.
509509
*/
510-
def avoid(tp: Type, symsToAvoid: => List[Symbol])(using Context): Type = {
510+
def avoid(tp: Type, symsToAvoid: => List[Symbol], avoidStatic: Boolean = false)(using Context): Type = {
511511
val widenMap = new AvoidMap {
512512
@threadUnsafe lazy val forbidden = symsToAvoid.toSet
513513
def toAvoid(tp: NamedType) =
514514
val sym = tp.symbol
515-
!sym.isStatic && forbidden.contains(sym)
515+
(!sym.isStatic || avoidStatic) && forbidden.contains(sym)
516516

517517
override def apply(tp: Type): Type = tp match
518518
case tp: TypeVar if mapCtx.typerState.constraint.contains(tp) =>

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,8 +1115,11 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
11151115
fullyDefinedType(tree.tpe, "block", tree.srcPos)
11161116
var avoidingType = TypeOps.avoid(tree.tpe, localSyms)
11171117
val ptDefined = isFullyDefined(pt, ForceDegree.none)
1118-
if (ptDefined && !(avoidingType.widenExpr <:< pt)) avoidingType = pt
1119-
val tree1 = ascribeType(tree, avoidingType)
1118+
var tree1 = ascribeType(tree, avoidingType)
1119+
if ptDefined && !(avoidingType.widenExpr <:< pt) then
1120+
tree1 = ascribeType(tree, pt)
1121+
else if !noLeaks(tree1) then
1122+
tree1 = ascribeType(tree, TypeOps.avoid(tree.tpe, localSyms, avoidStatic = true))
11201123
assert(ptDefined || noLeaks(tree1) || tree1.tpe.isErroneous,
11211124
// `ptDefined` needed because of special case of anonymous classes
11221125
i"leak: ${escapingRefs(tree1, localSyms).toList}%, % in $tree1")

tests/pos/i9314.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
final class fooAnnot[T](member: T) extends scala.annotation.StaticAnnotation // must have type parameter
2+
3+
@fooAnnot(new RecAnnotated {}) // must pass instance of anonymous subclass
4+
trait RecAnnotated

0 commit comments

Comments
 (0)