Skip to content

A simpler implementation of init checker #12495

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 50 commits into from
May 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
c8fe7e8
Add Domain and Semantic
liufengyun May 9, 2021
006f714
Add evaluator skeleton
liufengyun May 9, 2021
5373188
Add concrete domain definitions
liufengyun May 12, 2021
b31bbda
Define join
liufengyun May 12, 2021
d955d26
Implement this resolution
liufengyun May 12, 2021
b3ebab0
Add utility extractors
liufengyun May 12, 2021
ea7185f
Handle Select node
liufengyun May 12, 2021
021b58e
Handle more expressions
liufengyun May 12, 2021
34e476a
Handle method call
liufengyun May 12, 2021
ab926d9
Handle method call in abstract semantics
liufengyun May 13, 2021
21cfb0f
Don't thread-through heap thanks to monotonicity
liufengyun May 13, 2021
237ceec
Refactor eval for list of expressions
liufengyun May 13, 2021
3058635
Implement case for new expressions
liufengyun May 13, 2021
a8c70d5
Handle instantiation in abstract semantics
liufengyun May 14, 2021
6c7f170
Initial implementation of object initialization
liufengyun May 14, 2021
f8abf7e
Refactor: use extension methods for heap operations
liufengyun May 14, 2021
0a39a8f
Be faithful to initialization semantics
liufengyun May 14, 2021
4f298c0
First example works
liufengyun May 14, 2021
dd65e1a
Show stacktrace for errors
liufengyun May 14, 2021
849a5df
Refactor domain: Introduce Warm and ThisRef
liufengyun May 14, 2021
252f3e4
Remove useless file
liufengyun May 14, 2021
fff6f48
Only cache top-level expressions
liufengyun May 15, 2021
44031b8
Handle more tree forms in parents
liufengyun May 15, 2021
962fb94
Simplify Warm.call and Warm.select
liufengyun May 15, 2021
a6f27df
Fix crash
liufengyun May 15, 2021
3d6c79a
Respect lazy fields
liufengyun May 15, 2021
683a4a1
Handle access param of warm objects
liufengyun May 15, 2021
5a3e3d1
Handle parameterless method calls
liufengyun May 15, 2021
3fccd63
Implement promotion
liufengyun May 15, 2021
7717c5b
Handle constructor call effects on warm objects
liufengyun May 15, 2021
d3383f6
Refactor cache: don't use location as cache key
liufengyun May 15, 2021
9831b97
Add test
liufengyun May 16, 2021
366c972
Check term usage in types for type soundness
liufengyun May 16, 2021
9960e5a
Support early promotion of warm objects
liufengyun May 16, 2021
89a0845
Handle by-name arguments
liufengyun May 16, 2021
01fc3e6
Ignore known safe method calls
liufengyun May 16, 2021
390691e
Fix crash: impossible to construct super calls for leaked objects
liufengyun May 16, 2021
c6ea1a2
Fix joining empty sequence of values
liufengyun May 16, 2021
fa3d6ed
Fix crash: use the correct outer class
liufengyun May 16, 2021
f4aa49b
Reorganize tests
liufengyun May 16, 2021
48f7b97
Refactor: move heap from ThisRef for sharing more information
liufengyun May 16, 2021
ee84531
Handle cycles in early promotion
liufengyun May 16, 2021
d94d794
Handle exception with super calls
liufengyun May 16, 2021
2f2253d
Handle package and static objects in this resolution
liufengyun May 16, 2021
062bb98
Handle poly functions
liufengyun May 17, 2021
a7af9d8
Add test for structural types
liufengyun May 17, 2021
b978ad9
Fix test for poly functions
liufengyun May 17, 2021
3c25533
Remove unused field
liufengyun May 18, 2021
f67b3cd
Address review
liufengyun May 19, 2021
12bfbd2
Address review: Add more documentation
liufengyun May 21, 2021
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
11 changes: 10 additions & 1 deletion compiler/src/dotty/tools/dotc/transform/init/Checker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ class Checker extends MiniPhase {
// cache of class summary
private val cache = new Cache

private val semantic = new Semantic

override val runsAfter = Set(Pickler.name)

override def isEnabled(using Context): Boolean =
Expand Down Expand Up @@ -57,7 +59,14 @@ class Checker extends MiniPhase {
env = Env(ctx.withOwner(cls), cache)
)

Checking.checkClassBody(tree)
// Checking.checkClassBody(tree)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we remove checkClassBody or is it too early? Also cache, summarization, etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we will remove the existing version in another PR.


import semantic._
val tpl = tree.rhs.asInstanceOf[Template]
val thisRef = ThisRef(cls)
val heap = Objekt(cls, fields = mutable.Map.empty)
val res = eval(tpl, thisRef, cls)(using heap, ctx, Vector.empty)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We discussed that we could in theory call init here instead of eval. I there are tricky reasons to prefer eval, fine, but if not, then init would make the intent clearer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here the reason is only for consistency and tries to follow the Scala specification on initialization literally.
Inside the interpreter, beyond the cosmetical reason, another reason to reuse the cache infrastructure in early promotion of warm objects.

res.errors.foreach(_.issue)
}

tree
Expand Down
7 changes: 3 additions & 4 deletions compiler/src/dotty/tools/dotc/transform/init/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,6 @@ object Checking {
val f = denot.symbol
if !f.isOneOf(excludedFlags) && f.hasSource then
buffer += Promote(FieldReturn(warm, f)(source))(source)
buffer += FieldAccess(warm, f)(source)
}

classRef.membersBasedOnFlags(Flags.Method, Flags.Deferred).foreach { denot =>
Expand All @@ -342,7 +341,7 @@ object Checking {
for (eff <- buffer.toList) {
val errs = check(eff)
if !errs.isEmpty then
return UnsafePromotion(warm, eff.source, state.path, errs.toList).toErrors
return UnsafePromotion(eff.source, state.path, errs.toList).toErrors
}
Errors.empty

Expand All @@ -355,7 +354,7 @@ object Checking {
Errors.empty
else pot match {
case pot: ThisRef =>
PromoteThis(pot, eff.source, state.path).toErrors
PromoteThis(eff.source, state.path).toErrors

case _: Cold =>
PromoteCold(eff.source, state.path).toErrors
Expand All @@ -374,7 +373,7 @@ object Checking {
}

if (errs1.nonEmpty || errs2.nonEmpty)
UnsafePromotion(pot, eff.source, state.path, errs1 ++ errs2).toErrors
UnsafePromotion(eff.source, state.path, errs1 ++ errs2).toErrors
else
Errors.empty

Expand Down
11 changes: 6 additions & 5 deletions compiler/src/dotty/tools/dotc/transform/init/Errors.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import Types._, Symbols._, Contexts._
import Effects._, Potentials._

object Errors {
type Errors = List[Error]
type Errors = Seq[Error]
val empty: Errors = Nil

def show(errs: Errors)(using Context): String =
Expand Down Expand Up @@ -70,12 +70,12 @@ object Errors {
}

/** Promote `this` under initialization to fully-initialized */
case class PromoteThis(pot: ThisRef, source: Tree, trace: Vector[Tree]) extends Error {
case class PromoteThis(source: Tree, trace: Vector[Tree]) extends Error {
def show(using Context): String = "Promote the value under initialization to fully-initialized."
}

/** Promote `this` under initialization to fully-initialized */
case class PromoteWarm(pot: Warm, source: Tree, trace: Vector[Tree]) extends Error {
case class PromoteWarm(source: Tree, trace: Vector[Tree]) extends Error {
def show(using Context): String =
"Promoting the value under initialization to fully-initialized."
}
Expand All @@ -98,11 +98,12 @@ object Errors {

case class CallUnknown(meth: Symbol, source: Tree, trace: Vector[Tree]) extends Error {
def show(using Context): String =
"Calling the external method " + meth.show + " may cause initialization errors" + "."
val prefix = if meth.is(Flags.Method) then "Calling the external method " else "Accessing the external field"
prefix + meth.show + " may cause initialization errors" + "."
}

/** Promote a value under initialization to fully-initialized */
case class UnsafePromotion(pot: Potential, source: Tree, trace: Vector[Tree], errors: Errors) extends Error {
case class UnsafePromotion(source: Tree, trace: Vector[Tree], errors: Errors) extends Error {
assert(errors.nonEmpty)

override def issue(using Context): Unit =
Expand Down
Loading