Skip to content

Commit ac9a42d

Browse files
committed
Check that external and internal views of inferred result types are the same
For an inferred result type, check that the type that pickled is a supertype of the type that got inferred by capture checking. This replaces the previous checks that the inferred type must be pure.
1 parent adfb39f commit ac9a42d

File tree

3 files changed

+29
-27
lines changed

3 files changed

+29
-27
lines changed

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

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,24 +1119,21 @@ class CheckCaptures extends Recheck, SymTransformer:
11191119
case _ => true
11201120
}
11211121
if !canUseInferred then
1122+
// Test that the inferred type is compatible with the previously known
1123+
// type that other compilation units see. Compatibility means: all inferred
1124+
// capture sets don't contradict the externally known type, so
1125+
// we can use <:< instead of frozen_<:<
11221126
val inferred = t.tpt.knownType
1123-
val checkPure = new TypeTraverser:
1124-
def traverse(tp: Type) = tp match
1125-
case CapturingType(_, refs)
1126-
if !refs.elems.filter(isNotPureThis).isEmpty =>// && variance >= 0 =>
1127-
val resultStr = if t.isInstanceOf[DefDef] then " result" else ""
1128-
val partStr =
1129-
if tp eq inferred then "with non-empty capture set"
1130-
else i"since its part $tp has non-empty capture set"
1131-
report.error(
1132-
em"""Non-local $sym cannot have an inferred$resultStr type
1133-
|$inferred
1134-
|$partStr $refs.
1135-
|The type needs to be declared explicitly.""".withoutDisambiguation(),
1136-
t.srcPos)
1137-
case _ =>
1138-
traverseChildren(tp)
1139-
checkPure.traverse(inferred)
1127+
val previous = t.tpt.tpe
1128+
if !(inferred <:< previous) then
1129+
val resultStr = if t.isInstanceOf[DefDef] then " result" else ""
1130+
report.error(
1131+
em"""Non-local $sym cannot have an inferred$resultStr type
1132+
| $inferred
1133+
|since that type does not conform to the externally known type
1134+
| $previous
1135+
|The type needs to be declared explicitly.""".withoutDisambiguation(),
1136+
t.srcPos)
11401137
case t @ TypeApply(fun, args) =>
11411138
fun.knownType.widen match
11421139
case tl: PolyType =>

tests/neg-custom-args/captures/i15116.check

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,31 @@
22
3 | val x = Foo(m) // error
33
| ^^^^^^^^^^^^^^
44
| Non-local value x cannot have an inferred type
5-
| Foo{val m: String^{Bar.this.m}}^{Bar.this.m}
6-
| with non-empty capture set {Bar.this.m}.
5+
| Foo{val m: String^{Bar.this.m}}^{Bar.this.m}
6+
| since that type does not conform to the externally known type
7+
| Foo
78
| The type needs to be declared explicitly.
89
-- Error: tests/neg-custom-args/captures/i15116.scala:5:6 --------------------------------------------------------------
910
5 | val x = Foo(m) // error
1011
| ^^^^^^^^^^^^^^
1112
| Non-local value x cannot have an inferred type
12-
| Foo{val m: String^}^{Baz.this}
13-
| with non-empty capture set {Baz.this}.
13+
| Foo{val m: String^}^{Baz.this}
14+
| since that type does not conform to the externally known type
15+
| Foo
1416
| The type needs to be declared explicitly.
1517
-- Error: tests/neg-custom-args/captures/i15116.scala:7:6 --------------------------------------------------------------
1618
7 | val x = Foo(m) // error
1719
| ^^^^^^^^^^^^^^
1820
| Non-local value x cannot have an inferred type
19-
| Foo{val m: String^{Bar1.this.m}}^{Bar1.this.m}
20-
| with non-empty capture set {Bar1.this.m}.
21+
| Foo{val m: String^{Bar1.this.m}}^{Bar1.this.m}
22+
| since that type does not conform to the externally known type
23+
| Foo
2124
| The type needs to be declared explicitly.
2225
-- Error: tests/neg-custom-args/captures/i15116.scala:9:6 --------------------------------------------------------------
2326
9 | val x = Foo(m) // error
2427
| ^^^^^^^^^^^^^^
2528
| Non-local value x cannot have an inferred type
26-
| Foo{val m: String^}^{Baz2.this}
27-
| with non-empty capture set {Baz2.this}.
29+
| Foo{val m: String^}^{Baz2.this}
30+
| since that type does not conform to the externally known type
31+
| Foo
2832
| The type needs to be declared explicitly.

tests/neg-custom-args/captures/usingLogFile.check

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@
2828
47 | val later = usingLogFile { f => () => f.write(0) } // error
2929
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3030
| Non-local value later cannot have an inferred type
31-
| () => Unit
32-
| with non-empty capture set {x$0, cap}.
31+
| () => Unit
32+
| since that type does not conform to the externally known type
33+
| () -> Unit
3334
| The type needs to be declared explicitly.
3435
-- Error: tests/neg-custom-args/captures/usingLogFile.scala:62:16 ------------------------------------------------------
3536
62 | val later = usingFile("out", f => (y: Int) => xs.foreach(x => f.write(x + y))) // error

0 commit comments

Comments
 (0)