-
-
Notifications
You must be signed in to change notification settings - Fork 40
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
Implicit type tag in TLA expressions #557
Conversation
@romac, you probably know Scala better than all of us. Please have a look. |
Not so unexpectedly, Google Guice fails the integration tests. There seems to be a cure. |
If the formatting is introducing a ton of noise, then could you break this into 2 PRs? 1st: reformat all the files you will touch. 2nd, once that's in add the actual feature changes here? Since you have pulled in extra reviewers and taken the time to give such a careful explanation in the PR description, I assume this is quite subtle and deserves careful review. It would take a week or more to give a 6000+ line PR a proper review. |
Shall I just reformat the whole codebase with |
Yep, makes sense to me! Thank you for taking the time to help support high quality reviews 🙏 |
I'll just add that it's really hard to comment on file changes with PRs which include reformatting. Both the new functionality and the reformatting are part of the same commit in this case, so it's difficult to find and isolate the stuff that needs to be commented on, from the noise. |
I am closing this PR. Let's continue the review process in #561, which has better fine-grained structure. |
This PR contains a change to
TlaEx
. It is the core structure of the whole project, so we have to discuss the proposed solution and its impact. See the discussion below.Apart from this change, this PR contains 130 files that import a single implicit parameter:
Unfortunately,
scalafmt
turned this simple change into a massive PR.Tests added for any new codemake fmt-fix
(or had formatting run automatically on all files edited)Documentation added for any new functionalityEntry added to UNRELEASED.md for any new functionalityThe problem. Having the new type checker, we have to figure out how to integrate the type information in the TLA+ expressions. The old type checker is run in the very end of the pipeline. Hence the preprocessing code does not have to care about types at all. The new type checker is run before any preprocessing, which allows us to give much better feedback to the user.
There are several issues here:
SanyImporter
should work for both typed and untyped code.For the context, our definitions for
TlaEx
and its case classes looked like that before this PR:Alternative solutions. Here are the alternatives that I considered (on top of the solution proposed in this PR):
AnnotationStore
. However, if we annotate every single expression, the overhead will be massive.TlaEx
that would carry the type. This solution seems to be fragile and ugly. The type-unaware code could easily erase the types.TlaEx
,ValEx
,NameEx
,OperEx
, andLetInEx
, e.g.,TypedTlaEx[T](myType: T) extends TlaEx
. This would produce two parallel data structures. I am not even sure how to compose them, asOperEx
receives other expressions as its arguments. Again, type-unaware code could easily erase the types.Proposed solution: types as implicit parameters. The most clean solution seems to be to use implicit parameters. Although we have tried to avoid implicits in Scala, it looks like the right job for them.
Below are the definitions of type tags that we introduce for annotating TLA+ expressions (see
at.forsyte.apalache.tla.lir
):Then we introduce a type tag as an implicit parameter of
TlaEx
:The case classes also carry an implicit parameter, e.g.,
ValEx
:The cool thing about this solution is that we can introduce this change without modifying lots of code. Essentially, all users of
TlaEx
have to import the implicit valueuntyped
:(I had to extend several transformations to received an implicit parameter and pass it with
implicitly
.)The pattern matching code works as before. The type-aware code can access the tag via
ex.myType
. The type-unaware transformations may copy the types without unpacking them. On top of that, type-aware code can work with different type systems, asTyped
is parameterized. If we try to mix different type systems, the compiler will help us.The only downside that I see is that all of us have to read the chapter on implicit parameters in Programming in Scala. But we have to understand implicits anyways, if we want to use advanced frameworks as cats.