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

Code refactoring of initialization checker #16066

Merged
merged 3 commits into from
Oct 13, 2022

Conversation

liufengyun
Copy link
Contributor

@liufengyun liufengyun commented Sep 18, 2022

Fix #15764: Warn for problematic parameter overriding

Check overriding of class parameters

This check issues a warning if the use of a class pamameter in the primary
constructor potentially has different semantics from its use in methods.
The subtle semantic difference is demonstrated by the following exmpale:

    class B(val y: Int):
      println(y)                   // 10
      foo()
      def foo() = println(y)       // 20

    class C(override val y: Int) extends B(10)

    new C(20)

A well-formed program should not depend on such subtle semantic differences.
Therefore, we detect and warn such subtle semantic differences in code.

This check depends on loading TASTY from libraries. It can be enabled with
the compiler option -Ysafe-init.

Edit: Given that #16096 already disallows the overriding of class parameters, we don't need this PR any more. It only contains refactoring now.

@liufengyun liufengyun marked this pull request as ready for review September 19, 2022 18:18
@liufengyun liufengyun requested a review from olhotak September 19, 2022 18:24
def checkTasks(using Context)(taskBuilder: WorkList ?=> Unit): Unit =
val workList = new WorkList
def checkClasses(concreteClasses: List[ClassSymbol])(using Context): Unit =
val workList = new WorkList(concreteClasses)
Copy link
Contributor

Choose a reason for hiding this comment

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

I was surprised that the worklist was already not really a worklist, in that no new classes get added to it while it is processing existing classes. Given that this is the case, this simplification makes sense (i.e. getting rid of the mutable pendingTasks). But it would make sense to take the simplification a step further and get rid of the Worklist class altogether, keeping only its doTask method. Then here we would just do concreteClasses.filter(isConcreteClass).foreach(doTask). Also we should rename concreteClasses to just classes or classesToCheck or allClasses or ...

@liufengyun liufengyun requested a review from odersky September 20, 2022 05:06
@odersky
Copy link
Contributor

odersky commented Sep 20, 2022

@liufengyun As far as I can see all changes are in the init checker only, which I am not very familiar with. Is there anything specific you want me to review?

@liufengyun
Copy link
Contributor Author

liufengyun commented Sep 20, 2022

@liufengyun As far as I can see all changes are in the init checker only, which I am not very familiar with. Is there anything specific you want me to review?

I just want to make sure if the check makes sense from a specification point of view. The check enforces that:

  • A class parameter may only be overridden by a class parameter.
  • If a class parameter overrides another class parameter, they should have the same value.

The two rules help avoid subtle and surprising semantics as shown in the example.

BTW, the new parameter overriding check is independent of the init checker.

@olhotak
Copy link
Contributor

olhotak commented Sep 20, 2022

@liufengyun As far as I can see all changes are in the init checker only, which I am not very familiar with. Is there anything specific you want me to review?

@odersky I think the main question we want you to answer is whether we really do want a warning for this case, and whether being able to generate a warning for this case is worthwhile enough to justify the complexity of adding a static analysis of 350 LOC. It may be better to answer these questions in #15764 than here.

Although the static analysis is fairly simple in theory, there are many cases for the implementation to consider. Those cases do mirror those of the init checker, so they don't seem difficult for someone who is an expert in the init checker like @liufengyun .

@liufengyun If we do merge this, I think an explanation of the static analysis in theory (and the abstract domain) would be helpful, either in a big comment in the code or somewhere in a separate markdown file.

@odersky
Copy link
Contributor

odersky commented Sep 20, 2022 via email

@odersky
Copy link
Contributor

odersky commented Sep 24, 2022

Related: #16092

@liufengyun
Copy link
Contributor Author

Given that #16096 already disallows the overriding of class parameters, we don't need this PR any more. It's more permissive than #16096 for legacy code, e.g., it handles seconary constructors and trait parameters. However, #16096 is much simpler and good enough for legacy code.

We can keep the refactoring improvements while dropping ParamOverridingCheck.scala and related tests.

@liufengyun liufengyun requested a review from olhotak October 10, 2022 12:03
Copy link
Contributor

@olhotak olhotak left a comment

Choose a reason for hiding this comment

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

This is a nice cleanup of part of the init checker and the new comments are very helpful.

Before merging, I just suggest updating the PR title: it doesn't fix #15764 anymore.

@liufengyun liufengyun changed the title Fix #15764: Warn for problematic parameter overriding Code refactoring of initialization checker Oct 13, 2022
@liufengyun liufengyun merged commit 2746428 into scala:main Oct 13, 2022
@liufengyun liufengyun deleted the fix-15764b branch October 13, 2022 05:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Warn for code that depend on subtle semantics of class parameters in constructors
3 participants