Skip to content

Fix #9664: check outer of warm values #9665

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

Merged
merged 2 commits into from
Aug 28, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/init/Checker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class Checker extends MiniPhase {
// A concrete class may not be instantiated if the self type is not satisfied
if (instantiable) {
implicit val state: Checking.State = Checking.State(
visited = mutable.Set.empty,
visited = Set.empty,
path = Vector.empty,
thisClass = cls,
fieldsInited = mutable.Set.empty,
Expand Down
25 changes: 19 additions & 6 deletions compiler/src/dotty/tools/dotc/transform/init/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,30 @@ object Checking {
*
*/
case class State(
visited: mutable.Set[Effect], // effects that have been checked
private var visited: Set[Effect], // effects that have been checked
path: Vector[Tree], // the path that leads to the current effect
thisClass: ClassSymbol, // the concrete class of `this`
fieldsInited: mutable.Set[Symbol],
parentsInited: mutable.Set[ClassSymbol],
env: Env
) {

def withVisited(eff: Effect): State = {
visited += eff
visited = visited + eff
copy(path = this.path :+ eff.source)
}

def hasVisited(eff: Effect): Boolean =
visited.contains(eff)

def withOwner(sym: Symbol): State = copy(env = env.withOwner(sym))

def test(op: State ?=> Errors): Errors = {
val saved = visited
val errors = op(using this)
visited = saved
errors
}
}

private implicit def theEnv(implicit state: State): Env = state.env
Expand Down Expand Up @@ -148,7 +159,7 @@ object Checking {
}

private def check(eff: Effect)(implicit state: State): Errors =
if (state.visited.contains(eff)) Errors.empty
if (state.hasVisited(eff)) Errors.empty
else trace("checking effect " + eff.show, init, errs => Errors.show(errs.asInstanceOf[Errors])) {
implicit val state2: State = state.withVisited(eff)

Expand All @@ -162,11 +173,13 @@ object Checking {
PromoteCold(eff.source, state2.path).toErrors

case pot @ Warm(cls, outer) =>
PromoteWarm(pot, eff.source, state2.path).toErrors
val errors = state.test { check(Promote(outer)(eff.source)) }
if (errors.isEmpty) Errors.empty
else PromoteWarm(pot, eff.source, state2.path).toErrors

case Fun(pots, effs) =>
val errs1 = effs.flatMap { check(_) }
val errs2 = pots.flatMap { pot => check(Promote(pot)(eff.source))(state.copy(path = Vector.empty)) }
val errs1 = state.test { effs.flatMap { check(_) } }
val errs2 = state.test { pots.flatMap { pot => check(Promote(pot)(eff.source))(state.copy(path = Vector.empty)) } }
if (errs1.nonEmpty || errs2.nonEmpty)
UnsafePromotion(pot, eff.source, state2.path, errs1 ++ errs2).toErrors
else
Expand Down
2 changes: 1 addition & 1 deletion tests/init/neg/function1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class Foo {
val fun2: Int => Int = n => 1 + n + list.size
fun2(5)

List(5, 9).map(n => 2 + n + list.size)
List(5, 9).map(n => 2 + n + list.size) // error

final val list = List(1, 2, 3) // error

Expand Down
14 changes: 14 additions & 0 deletions tests/init/pos/i9664.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
object Wrap1 {
class E
object E {
final val A = E()
val $values = Array(A)
}
}
object Wrap2 {
class E
object E {
final val A = E()
val ref = A
}
}