Skip to content

Commit 7740fb7

Browse files
committed
Bugfix: More lenient definition when an inferred type is OK for visible definition
We now allow an inferred type of the form `{C.this} T` if `C` is a pure class. This is OK since such a type is equivalent to `T`.
1 parent 824580e commit 7740fb7

File tree

5 files changed

+30
-2
lines changed

5 files changed

+30
-2
lines changed

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,17 @@ extension (tp: Type)
168168

169169
extension (sym: Symbol)
170170

171+
/** A class is pure if one of its base types has an explicitly declared self type
172+
* with an empty capture set.
173+
*/
174+
def isPureClass(using Context): Boolean = sym match
175+
case cls: ClassSymbol =>
176+
cls.baseClasses.exists(bc =>
177+
val selfType = bc.givenSelfType
178+
selfType.exists && selfType.captureSet.isAlwaysEmpty)
179+
case _ =>
180+
false
181+
171182
/** Does this symbol allow results carrying the universal capability?
172183
* Currently this is true only for function type applies (since their
173184
* results are unboxed) and `erasedValue` since this function is magic in

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -877,10 +877,15 @@ class CheckCaptures extends Recheck, SymTransformer:
877877
isLocal // local symbols still need an explicit types if
878878
&& !sym.owner.is(Trait) // - they are defined in a trait, since we do OverridingPairs checking before capture inference
879879
&& !sym.allOverriddenSymbols.nonEmpty // - they override some other symbol, since we do override checking before capture inference
880+
def isNotPureThis(ref: CaptureRef) = ref match {
881+
case ref: ThisType => !ref.cls.isPureClass
882+
case _ => true
883+
}
880884
if !canUseInferred then
881885
val inferred = t.tpt.knownType
882886
def checkPure(tp: Type) = tp match
883-
case CapturingType(_, refs) if !refs.elems.isEmpty =>
887+
case CapturingType(_, refs)
888+
if !refs.elems.filter(isNotPureThis).isEmpty =>
884889
val resultStr = if t.isInstanceOf[DefDef] then " result" else ""
885890
report.error(
886891
em"""Non-local $sym cannot have an inferred$resultStr type

compiler/test/dotc/pos-test-pickling.blacklist

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ boxmap-paper.scala
8484
# Function types print differnt after unpickling since test mispredicts Feature.preFundsEnabled
8585
caps-universal.scala
8686

87-
8887
# GADT cast applied to singleton type difference
8988
i4176-gadt.scala
9089

tests/pos-custom-args/captures/capt-test.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ def map[A, B](f: A => B)(xs: LIST[A]): LIST[B] =
2121
class C
2222
type Cap = {*} C
2323

24+
class Foo(x: Cap):
25+
this: {x} Foo =>
26+
2427
def test(c: Cap, d: Cap) =
2528
def f(x: Cap): Unit = if c == x then ()
2629
def g(x: Cap): Unit = if d == x then ()
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
trait A:
2+
self: A =>
3+
def foo: Int
4+
5+
abstract class B extends A:
6+
def foo: Int
7+
8+
class C extends B:
9+
def foo = 1
10+
def derived = this

0 commit comments

Comments
 (0)