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

fix: Make datatype cycle detection independent of auto-init #4997

Merged
merged 24 commits into from
Jan 24, 2024

Conversation

RustanLeino
Copy link
Collaborator

This PR makes the "datatype has no instances" checks more liberal.

Fixes #4939

Description

An inductive datatype is allowed to be defined as an empty type. For example, in

predicate P(x: int) { false }
type Subset = x: int | P(x) witness *
datatype Record = Record(Subset)

Record is an empty type, because Subset is, since P(x) is always false. But if P(x) was instead defined to be true for some x's, then Record would be nonempty. Determining whether or not Record is empty goes well beyond the syntactic checks of the type system.

However, if a datatype is empty because of some "obvious" cycle among datatype definitions, then that is both detectable by syntactic checks and likely unintended by the programmer. By this PR, Dafny will search for such type declarations and give error messages if an inductive datatype is necessarily involved in such an "obvious" cycle.

Previous behavior

Dafny had attempted this check before, too, but then the rule was too strict. The check had been implemented as part of the machinery that computed "grounding constructors". That search consulted the auto-init status of the types that a datatype depends on. Since traits are of the "possibly empty" auto-init category, if every constructor of a datatype depended on a trait (that is, the constructors had a parameter whose type is a trait), then Dafny would report an error.

This PR removes the error reporting done by the machinery that computes grounding constructors. It adds a new, separate check in the resolver to determine the "obvious" cycles.

Grounding constructors

The name "grounding constructor" was originally to mean "a constructor that can be used to construct an instance of the datatype". This name is rather outdated, because Dafny's syntactic checks do not ensure datatypes to be nonempty anyway (case in point: type Record above). A name like "initializing constructor" would be more to the point--the compiler uses this constructor in a generated method for creating an arbitrary value of the type. (At run time, this method will never be called if the datatype really is empty, but since the compiler does not know this, it still has to generate valid target code for this method.)

Alternative designs

One alternative design would be to change the new "because of a cycle, this datatype has no instances" error message to be just a warning. This alternative has some merit, since Dafny already supports empty types.

Another alternative would be to not perform the check at all, and to report neither an error nor a warning for datatypes with no instances. This would give more flexibility. However, since there are simple ways to write an empty type, a program where a datatype cycle causes a type to have no instances is most likely a mistake that the programmer would want to know about and fix.

By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license.

@ssomayyajula ssomayyajula self-requested a review January 19, 2024 23:47
@RustanLeino RustanLeino marked this pull request as ready for review January 20, 2024 16:18
@RustanLeino RustanLeino enabled auto-merge (squash) January 20, 2024 16:20
@RustanLeino RustanLeino merged commit fc3660f into dafny-lang:master Jan 24, 2024
20 checks passed
@RustanLeino RustanLeino deleted the issue-4939 branch January 24, 2024 22:42
RustanLeino added a commit to RustanLeino/dafny that referenced this pull request Feb 6, 2024
Fixes dafny-lang#4983
Actually, this was fixed already in dafny-lang#4997
@RustanLeino
Copy link
Collaborator Author

This PR also fixes #4983. Tests for that issue have been added in PR #5058.

RustanLeino added a commit that referenced this pull request Feb 7, 2024
This PR fixes and closes three reported bugs related to datatypes
extending traits:

* Reference-type traits used with `import opened` were not recognized as
reference types (issue #4936).
* Implicit conversions from a datatype to a parent trait had caused
malformed Boogie (issue #4983). This was actually fixed in PR #4997, but
the present PR adds tests for it.
* Equality (and disequality) comparisons with a datatype (or codatatype)
on the _left_ and a parent trait on the _right_ had caused malformed
Boogie (issue #4994).

Fixes #4936
Closes #4983
Fixes #4994


<small>By submitting this pull request, I confirm that my contribution
is made under the terms of the [MIT
license](https://github.com/dafny-lang/dafny/blob/master/LICENSE.txt).</small>
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.

False cyclic dependency with datatype extending trait
2 participants