Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix capture set variable installation in Setup #18885

Merged
merged 3 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions compiler/src/dotty/tools/dotc/cc/Setup.scala
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,8 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
end postProcess
end setupTraverser

private def superTypeIsImpure(tp: Type)(using Context): Boolean = {
/** Checks whether an abstract type could be impure. See also: [[needsVariable]]. */
private def instanceCanBeImpure(tp: Type)(using Context): Boolean = {
tp.dealiasKeepAnnots match
case CapturingType(_, refs) =>
!refs.isAlwaysEmpty
Expand All @@ -555,17 +556,18 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
sym == defn.AnyClass
Linyxus marked this conversation as resolved.
Show resolved Hide resolved
// we assume Any is a shorthand of {cap} Any, so if Any is an upper
// bound, the type is taken to be impure.
|| !sym.isPureClass
else
sym != defn.Caps_Cap && superTypeIsImpure(tp.superType)
sym != defn.Caps_Cap && instanceCanBeImpure(tp.superType)
case tp: (RefinedOrRecType | MatchType) =>
superTypeIsImpure(tp.underlying)
instanceCanBeImpure(tp.underlying)
case tp: AndType =>
superTypeIsImpure(tp.tp1) || superTypeIsImpure(tp.tp2)
instanceCanBeImpure(tp.tp1) || instanceCanBeImpure(tp.tp2)
case tp: OrType =>
superTypeIsImpure(tp.tp1) && superTypeIsImpure(tp.tp2)
instanceCanBeImpure(tp.tp1) && instanceCanBeImpure(tp.tp2)
case _ =>
false
}.showing(i"super type is impure $tp = $result", capt)
}.showing(i"instance can be impure $tp = $result", capt)

/** Should a capture set variable be added on type `tp`? */
def needsVariable(tp: Type)(using Context): Boolean = {
Expand All @@ -577,7 +579,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
else
val tp1 = tp.dealiasKeepAnnots
if tp1 ne tp then needsVariable(tp1)
else superTypeIsImpure(tp1)
else instanceCanBeImpure(tp1)
case tp: (RefinedOrRecType | MatchType) =>
needsVariable(tp.underlying)
case tp: AndType =>
Expand Down Expand Up @@ -708,4 +710,4 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
def postCheck()(using Context): Unit =
for chk <- todoAtPostCheck do chk(ctx)
todoAtPostCheck.clear()
end Setup
end Setup
6 changes: 6 additions & 0 deletions tests/pos-custom-args/captures/cc-setup-impure-classes.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import language.experimental.captureChecking

trait Resource
def id[X](x: X): x.type = x
def foo[M <: Resource](r: M^): Unit = id(r) // was error, should be ok
def bar[M](r: M^): Unit = id(r) // ok
16 changes: 16 additions & 0 deletions tests/pos-custom-args/captures/future-traverse.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import language.experimental.captureChecking

trait Builder[-A, +C]
trait BuildFrom[-From, -A, +C] {
def newBuilder(from: From): Builder[A, C]
}

trait Future[+T] { this: Future[T]^ =>
import Future.*
def foldLeft[R](r: R): R = r
def traverse[A, B, M[X] <: IterableOnce[X]](in: M[A]^, bf: BuildFrom[M[A]^, B, M[B]^]): Unit =
foldLeft(successful(bf.newBuilder(in)))
}
object Future {
def successful[T](result: T): Future[T] = ???
}
Loading