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

Use initialization checker for soundness #11716

Merged
merged 7 commits into from
Mar 17, 2021

Conversation

liufengyun
Copy link
Contributor

@liufengyun liufengyun commented Mar 12, 2021

Use initialization checker for soundness

Fix #5854, #4042 and part of #11572

-- Warning: tests/init/neg/i11572.scala:8:6 ------------------------------------
8 |  val t: Bounded = new Bounded {
  |      ^
  |      Access non-initialized value t. Calling trace:
  |       -> }	[ i11572.scala:11 ]
  |        -> override type T >: t.T <: t.T	[ i11572.scala:10 ]
1 warning found
-- Warning: tests/init/neg/i5854.scala:3:6 -------------------------------------
3 |  val b: { type A >: Any <: Nothing } = loop()         // error
  |      ^
  |  Access non-initialized value b. Calling trace:
  |   -> val a: String = (((1: Any): b.A): Nothing): String	[ i5854.scala:2 ]
1 warning found

-- Warning: tests/init/neg/i11572.scala:8:6 ------------------------------------
8 |  val t: Bounded = new Bounded {
  |      ^
  |      Access non-initialized value t. Calling trace:
  |       -> }	[ i11572.scala:11 ]
  |        -> override type T >: t.T <: t.T	[ i11572.scala:10 ]
1 warning found
@@ -12,8 +12,8 @@ import core.Contexts._
import Potentials._

object Effects {
type Effects = Set[Effect]
val empty: Effects = Set.empty
type Effects = Vector[Effect]
Copy link
Contributor

Choose a reason for hiding this comment

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

Is the change from Set to Vector related to checking TypeDefs, or is it an orthogonal improvement?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's orthogonal. Set is bad for concatenation, and we can afford to have duplicate entries in summaries.

We get types like the following in effpi:

    effpi.examples.demo.audit.types.Pay#replyTo
@liufengyun liufengyun changed the title WIP: Use initialization checker for soundness Use initialization checker for soundness Mar 12, 2021
@liufengyun liufengyun marked this pull request as ready for review March 12, 2021 20:16
Copy link
Contributor

@natsukagami natsukagami left a comment

Choose a reason for hiding this comment

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

I don't think I fully understand what effectsOfType does, but the rest looks OK!

@@ -213,6 +214,19 @@ object Summarization {
else summary
}

private def effectsOfType(tp: Type, source: Tree)(implicit env: Env): Effects =
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this function calculating the effects of constructing an instance of type tp?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's calculating field access effects in types. In Scala we can have types like p.f.T, here we summarize the effects for p.f.

@liufengyun
Copy link
Contributor Author

@olhotak Could you also have a look at the changes?

var summary = Summary.empty
val traverser = new TypeTraverser {
def traverse(tp: Type): Unit = tp match {
case TermRef(_: SingletonType, _) =>
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we restrict to SingletonType here as a prefix of the TermRef?

What could the prefix be other than a SingletonType and why is it OK to skip those cases?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the community build, the project effpi (which use compiler plugin for session protocol checking) generates types like the following:

effpi.examples.demo.audit.types.Pay#replyTo

The type looks dubious, but the compiler seems to be fine with it. For such a type, our code will simply recur on the prefix effpi.examples.demo.audit.types.Pay and look for term selections recursively.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm still confused.

That type is a TypeRef, right? And we recurse on its prefix below in case _ => traverseChildren(tp), right? What would go wrong if this case was just case _: TermRef => instead of the pattern with the SingletonType?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't make it clear: it's a display problem, it's a TermRef where the prefix is a TypeRef.

If we only have _: TermRef, we will need to do more error-handling in analyze(tp) to avoid crash: currently it's pretty strict about what types it may get.

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, sorry, yes, this makes sense now.

Then I just wonder why the restriction is for the prefix to be a SingletonType rather than the prefix being something like TermRef | NoPrefix. Can a SingletonType be more things than that and are those things that we want?

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, the prefix can also be ThisType, which is usually what we care about. If the prefix is NoPrefix, the variable is a local variable --- the analysis currently enforces that all local variables are hot.

@olhotak
Copy link
Contributor

olhotak commented Mar 17, 2021

I have another question above about TermRef/SingletonType.

We should check the various pieces of code in the comments of #50, scala/bug#9633, #4042, #4031, #5854. I think you have some of these already but there seem to be a lot of examples there: there are probably more that should be added as test cases.

Otherwise LGTM.

@liufengyun
Copy link
Contributor Author

We should check the various pieces of code in the comments of #50, scala/bug#9633, #4042, #4031, #5854. I think you have some of these already but there seem to be a lot of examples there: there are probably more that should be added as test cases.

I added some more tests. I didn't include tests that use null as a value, as that can be easily handled by null-safety.

@olhotak
Copy link
Contributor

olhotak commented Mar 17, 2021

We should check the various pieces of code in the comments of #50, scala/bug#9633, #4042, #4031, #5854. I think you have some of these already but there seem to be a lot of examples there: there are probably more that should be added as test cases.

I added some more tests. I didn't include tests that use null as a value, as that can be easily handled by null-safety.

Good point. I will ask @noti0na1 to look at which of the above examples are fixed by -Yexplicit-nulls and add them as tests (separately from this PR).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants