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

report an error when a type annotation is too general #2109

Merged
merged 11 commits into from
Aug 30, 2022

Conversation

konnov
Copy link
Collaborator

@konnov konnov commented Aug 26, 2022

Closes #2102. This PR adds a small test in EtcTypeChecker that ensures that a polymorphic type annotation is as precise as the inferred principal type.

  • The new version of the type checker has found a bug in the type annotation of ReduceSet of __rewire_finite_sets_ext_in_apalache.tla. Due to the incorrect order of arguments, the type was more specific. This is actually a bug in the community modules.

  • Also, it found a bug in our type annotation of FoldLeft in SequencesExt. This is purely a bug in the type annotation, not propagated to the community modules.

  • Tests added for any new code

  • Ran make fmt-fix (or had formatting run automatically on all files edited)

  • Documentation added for any new functionality

  • Entries added to ./unreleased/ for any new functionality

@codecov-commenter
Copy link

codecov-commenter commented Aug 26, 2022

Codecov Report

Merging #2109 (17681c0) into main (ef2a18e) will increase coverage by 0.00%.
The diff coverage is 83.33%.

@@           Coverage Diff           @@
##             main    #2109   +/-   ##
=======================================
  Coverage   76.98%   76.98%           
=======================================
  Files         425      425           
  Lines       13769    13778    +9     
  Branches     1881     1884    +3     
=======================================
+ Hits        10600    10607    +7     
- Misses       3169     3171    +2     
Impacted Files Coverage Δ
...te/apalache/tla/typecheck/etc/EtcTypeChecker.scala 84.33% <83.33%> (-0.38%) ⬇️
...he/io/annotations/parser/CommentPreprocessor.scala 96.70% <0.00%> (-1.10%) ⬇️
...a/at/forsyte/apalache/tla/lir/TlaLevelFinder.scala 95.83% <0.00%> (+2.08%) ⬆️

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

Copy link
Contributor

@shonfeder shonfeder left a comment

Choose a reason for hiding this comment

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

A few small suggestions on comments, and some questions (for my own edification) on the tests.

.unreleased/features/2102-polytypes-precision.md Outdated Show resolved Hide resolved
.unreleased/features/2102-polytypes-precision.md Outdated Show resolved Hide resolved
Comment on lines -524 to 525
// @type: a => b;
// @type: a => a;
// let F == lambda x \in Set(a): ((c, c) => c) x d in F(Int)
Copy link
Contributor

Choose a reason for hiding this comment

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

For my own edification: I don't know how to read the body of this lambda. What is ((c, c) => c) x d? It looks like it's applying an implication to two arguments? Or is that only on the type level? But then what's the labmda doing? And how does F end up being typed as the identify function?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This expression is written in the syntax of EtcExpr, a lambda calculus over types. The body of the lambda is an application of x and d to a type, which in this case is an operator of two arguments of type c and returns type c.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It is an identity from the types of view.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thank you for explaining. It helps a lot. So is the lambda here a type-level lambda? It seems like it's kind of mixing type level syntax with pseudo-TNT syntax, or am I just totally missing the thread here :D?

It is an identity from the types of view.

So, we are maybe getting outside the scope of this PR, but one thing that I think is throwing me off here is that, afaik, it is not possible to write an operator that actually has type a => a and also relies on some constant d that comes from outside the operator.

The only way we can write an operator of type a => a is if we treat the provided argument as fully abstract, because we can't know anything about the value of type a, since we don't know what type it is (or, equivalently, it must work for any type). So afaik, there would be no way of having a d available that could work for any possible type for application to (c, c) => c. afaiu, This is why (in a HM-ish type system) any function with type a => a must be (isomorphic to) the identity function.

The fact that this test is going through makes me think that either our type inference is off, or we're constructing type here that shouldn't actually be possible to assign to any expression (or else I am just quite confused about what is going on here). But in any of these three cases, it seems like we might be looking to either fix the test, fix the type inference, or fix my understanding :)

Comment on lines +568 to 569
// @type: a => a;
// let F == lambda x \in Set(a): ((c, c) => c) x d
Copy link
Contributor

Choose a reason for hiding this comment

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

Same question here: I may be being dense, but I don't understand how it is that F here turns out to be the identity function. Is (c, c) => c somehow the k combinator?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It's the same thing again. We have a lambda that applies an operator of type (c, c) => c) to x and d. We are interested not in the structure of this operator, but only in its type.

Copy link
Contributor

Choose a reason for hiding this comment

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

That helps a bit, but the annotation here is really quite confusing, imo, as it seems to be mixing up value and type level syntax. Would this comment convey the same thing but within using types to stand in for expressions?

Suggested change
// @type: a => a;
// let F == lambda x \in Set(a): ((c, c) => c) x d
// @type: (c, c) => c;
// let G(a, b) = a
// @type: a => a;
// let F == lambda x \in Set(a): G x d

In any case, I can see that this comment is not change by this PR, so it should be outside the scope of the PR. You've cleared up my confusion, thanks.

The part of this that should perhaps be addressed (at least in discussion) is described in #2109 (comment).

konnov and others added 3 commits August 29, 2022 09:37
Co-authored-by: Shon Feder <shon@informal.systems>
Copy link
Contributor

@shonfeder shonfeder left a comment

Choose a reason for hiding this comment

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

Marking this OK for merge, as we can followup with any needed fixes to testing or inference or docs.

@shonfeder shonfeder enabled auto-merge (squash) August 30, 2022 13:50
@shonfeder shonfeder merged commit 3399b83 into main Aug 30, 2022
This was referenced Sep 5, 2022
@thpani thpani deleted the igor/imprecise-annotations2102 branch October 17, 2022 09:09
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 the user when their polymorphic type annotations are imprecise
3 participants