-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
CC: Give more info when context function parameters leak (#20244)
Previously we had: parameter `$contextual1` leaks into outer capture set of type parameter `T` of method `apply`. We now give info in what type the parameter appeared and who owns the method. It's still not great, but at least we see more info that could tell us about the context.
- Loading branch information
Showing
5 changed files
with
102 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/effect-swaps.scala:64:8 ---------------------------------- | ||
63 | Result: | ||
64 | Future: // error, escaping label from Result | ||
| ^ | ||
| Found: Result.Ok[box Future[box T^?]^{fr, contextual$1}] | ||
| Required: Result[Future[T], Nothing] | ||
65 | fr.await.ok | ||
|-------------------------------------------------------------------------------------------------------------------- | ||
|Inline stack trace | ||
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
|This location contains code that was inlined from effect-swaps.scala:41 | ||
41 | boundary(Ok(body)) | ||
| ^^^^^^^^ | ||
-------------------------------------------------------------------------------------------------------------------- | ||
| | ||
| longer explanation available when compiling with `-explain` | ||
-- Error: tests/neg-custom-args/captures/effect-swaps.scala:68:15 ------------------------------------------------------ | ||
68 | Result.make: //lbl ?=> // error, escaping label from Result | ||
| ^^^^^^^^^^^ | ||
|local reference contextual$9 from (using contextual$9: boundary.Label[Result[box Future[box T^?]^{fr, contextual$9}, box E^?]]^): | ||
| box Future[box T^?]^{fr, contextual$9} leaks into outer capture set of type parameter T of method make in object Result |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import annotation.capability | ||
|
||
object boundary: | ||
|
||
@capability final class Label[-T] | ||
|
||
/** Abort current computation and instead return `value` as the value of | ||
* the enclosing `boundary` call that created `label`. | ||
*/ | ||
def break[T](value: T)(using label: Label[T]): Nothing = ??? | ||
|
||
def apply[T](body: Label[T] ?=> T): T = ??? | ||
end boundary | ||
|
||
import boundary.{Label, break} | ||
|
||
@capability trait Async | ||
object Async: | ||
def blocking[T](body: Async ?=> T): T = ??? | ||
|
||
class Future[+T]: | ||
this: Future[T]^ => | ||
def await(using Async): T = ??? | ||
object Future: | ||
def apply[T](op: Async ?=> T)(using Async): Future[T]^{op} = ??? | ||
|
||
enum Result[+T, +E]: | ||
case Ok[+T](value: T) extends Result[T, Nothing] | ||
case Err[+E](error: E) extends Result[Nothing, E] | ||
|
||
|
||
object Result: | ||
extension [T, E](r: Result[T, E]^)(using Label[Err[E]]) | ||
|
||
/** `_.ok` propagates Err to current Label */ | ||
def ok: T = r match | ||
case Ok(value) => value | ||
case Err(value) => break[Err[E]](Err(value)) | ||
|
||
transparent inline def apply[T, E](inline body: Label[Result[T, E]] ?=> T): Result[T, E] = | ||
boundary(Ok(body)) | ||
|
||
// same as apply, but not an inline method | ||
def make[T, E](body: Label[Result[T, E]] ?=> T): Result[T, E] = | ||
boundary(Ok(body)) | ||
|
||
end Result | ||
|
||
def test[T, E](using Async) = | ||
import Result.* | ||
Async.blocking: async ?=> | ||
val good1: List[Future[Result[T, E]]] => Future[Result[List[T], E]] = frs => | ||
Future: | ||
Result: | ||
frs.map(_.await.ok) // OK | ||
|
||
val good2: Result[Future[T], E] => Future[Result[T, E]] = rf => | ||
Future: | ||
Result: | ||
rf.ok.await // OK, Future argument has type Result[T] | ||
|
||
def fail3(fr: Future[Result[T, E]]^) = | ||
Result: | ||
Future: // error, escaping label from Result | ||
fr.await.ok | ||
|
||
def fail4[T, E](fr: Future[Result[T, E]]^) = | ||
Result.make: //lbl ?=> // error, escaping label from Result | ||
Future: fut ?=> | ||
fr.await.ok |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
-- Error: tests/neg-custom-args/captures/leaking-iterators.scala:56:2 -------------------------------------------------- | ||
56 | usingLogFile: log => // error | ||
| ^^^^^^^^^^^^ | ||
| local reference log leaks into outer capture set of type parameter R of method usingLogFile | ||
| local reference log leaks into outer capture set of type parameter R of method usingLogFile in package cctest |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,12 @@ | ||
-- Error: tests/neg-custom-args/captures/usingLogFile.scala:23:14 ------------------------------------------------------ | ||
23 | val later = usingLogFile { f => () => f.write(0) } // error | ||
| ^^^^^^^^^^^^ | ||
| local reference f leaks into outer capture set of type parameter T of method usingLogFile | ||
| local reference f leaks into outer capture set of type parameter T of method usingLogFile in object Test2 | ||
-- Error: tests/neg-custom-args/captures/usingLogFile.scala:28:23 ------------------------------------------------------ | ||
28 | private val later2 = usingLogFile { f => Cell(() => f.write(0)) } // error | ||
| ^^^^^^^^^^^^ | ||
| local reference f leaks into outer capture set of type parameter T of method usingLogFile | ||
| local reference f leaks into outer capture set of type parameter T of method usingLogFile in object Test2 | ||
-- Error: tests/neg-custom-args/captures/usingLogFile.scala:44:16 ------------------------------------------------------ | ||
44 | val later = usingFile("out", f => (y: Int) => xs.foreach(x => f.write(x + y))) // error | ||
| ^^^^^^^^^ | ||
| local reference f leaks into outer capture set of type parameter T of method usingFile | ||
| local reference f leaks into outer capture set of type parameter T of method usingFile in object Test3 |