Skip to content

[backport] Tasty: set experimental to zero #12438

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions tasty/src/dotty/tools/tasty/TastyFormat.scala
Original file line number Diff line number Diff line change
Expand Up @@ -301,14 +301,27 @@ object TastyFormat {
* is able to read final TASTy documents if the file's
* `MinorVersion` is strictly less than the current value.
*/
final val ExperimentalVersion: Int = 3
final val ExperimentalVersion: Int = 0

/**This method implements a binary relation (`<:<`) between two TASTy versions.
*
* We label the lhs `file` and rhs `compiler`.
* if `file <:< compiler` then the TASTy file is valid to be read.
*
* TASTy versions have a partial order,
* for example `a <:< b` and `b <:< a` are both false if `a` and `b` have different major versions.
* A TASTy version, e.g. `v := 28.0-3` is composed of three fields:
* - v.major == 28
* - v.minor == 0
* - v.experimental == 3
*
* TASTy versions have a partial order, for example,
* `a <:< b` and `b <:< a` are both false if
* - `a` and `b` have different `major` fields.
* - `a` and `b` have different `experimental` fields, both non-zero.
*
* A zero value for an `experimental` field is considered
* to be a stable TASTy version, and has higher precedence
* than a TASTy version with the same `major`/`minor` fields
* but a non-zero `experimental` field.
*
* We follow the given algorithm:
* ```
Expand Down
42 changes: 25 additions & 17 deletions tasty/test/dotty/tools/tasty/TastyVersionFormatTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,61 +11,69 @@ class TastyVersionFormatTest {
import TastyVersionFormatTest._

/** aliases `TastyVersion.apply` */
def compiler(major: Int, minor: Int, experimental: Int) = TastyVersion(major, minor, experimental)
def compiler(major: Int, minor: Int, experimental: Experimental) = TastyVersion(major, minor, experimental)

/** aliases `TastyVersion.apply` */
def file(major: Int, minor: Int, experimental: Int) = TastyVersion(major, minor, experimental)
def file(major: Int, minor: Int, experimental: Experimental) = TastyVersion(major, minor, experimental)

@Test def accept_ExperimentalReadEQExperimental_EQMinor: Unit = {
assert(file(28,1,1) <:< compiler(28,1,1)) // same minor, same experimental
assert(file(28,1,Exp(1)) <:< compiler(28,1,Exp(1))) // same minor, same experimental
}

@Test def accept_ExperimentalReadFinal_LTMinor: Unit = {
assert(file(28,0,0) <:< compiler(28,1,1)) // preceding minor
assert(file(28,0,Final) <:< compiler(28,1,Exp(1))) // preceding minor
}

@Test def accept_FinalReadFinal_LTEqualMinor: Unit = {
assert(file(28,0,0) <:< compiler(28,1,0)) // preceding minor
assert(file(28,0,0) <:< compiler(28,0,0)) // same minor
assert(file(28,0,Final) <:< compiler(28,1,Final)) // preceding minor
assert(file(28,0,Final) <:< compiler(28,0,Final)) // same minor
}

/** these cases are unrelated because a final compiler can only read final tasty of <= minor version */
@Test def reject_FinalReadFinal_GTMinor: Unit = {
assert(file(28,2,0) unrelatedTo compiler(28,1,0)) // succeeding minor
assert(file(28,2,Final) unrelatedTo compiler(28,1,Final)) // succeeding minor
}

/** these cases are unrelated because a final compiler can not read experimental tasty */
@Test def reject_FinalReadExperimental: Unit = {
assert(file(28,0,1) unrelatedTo compiler(28,1,0)) // preceding minor
assert(file(28,1,1) unrelatedTo compiler(28,1,0)) // same minor
assert(file(28,2,1) unrelatedTo compiler(28,1,0)) // succeeding minor
assert(file(28,0,Exp(1)) unrelatedTo compiler(28,1,Final)) // preceding minor
assert(file(28,1,Exp(1)) unrelatedTo compiler(28,1,Final)) // same minor
assert(file(28,2,Exp(1)) unrelatedTo compiler(28,1,Final)) // succeeding minor
}

/** These cases are unrelated because an experimental compiler can only read final tasty of < minor version */
@Test def reject_ExperimentalReadFinal_GTEqualMinor: Unit = {
assert(file(28,2,0) unrelatedTo compiler(28,1,1)) // succeeding minor
assert(file(28,1,0) unrelatedTo compiler(28,1,1)) // equal minor
assert(file(28,2,Final) unrelatedTo compiler(28,1,Exp(1))) // succeeding minor
assert(file(28,1,Final) unrelatedTo compiler(28,1,Exp(1))) // equal minor
}

/**These cases are unrelated because both compiler and file are experimental,
* and with unequal experimental part.
*/
@Test def reject_ExperimentalReadNEExperimental: Unit = {
assert(file(28,1,2) unrelatedTo compiler(28,1,1)) // same minor version, succeeding experimental
assert(file(28,1,1) unrelatedTo compiler(28,1,2)) // same minor version, preceding experimental
assert(file(28,1,Exp(2)) unrelatedTo compiler(28,1,Exp(1))) // same minor version, succeeding experimental
assert(file(28,1,Exp(1)) unrelatedTo compiler(28,1,Exp(2))) // same minor version, preceding experimental
}

/** these cases are unrelated because the major version must be identical */
@Test def reject_NEMajor: Unit = {
assert(file(27,0,0) unrelatedTo compiler(28,0,0)) // less than
assert(file(29,0,0) unrelatedTo compiler(28,0,0)) // greater than
assert(file(27,0,Final) unrelatedTo compiler(28,0,Final)) // less than
assert(file(29,0,Final) unrelatedTo compiler(28,0,Final)) // greater than
}

}

object TastyVersionFormatTest {

case class TastyVersion(major: Int, minor: Int, experimental: Int) { file =>
type Experimental = Int
val Final: Experimental = 0
def Exp(i: Int): Experimental = i.ensuring(_ > 0)

case class TastyVersion(major: Int, minor: Int, experimental: Experimental) { file =>
assert(major >= 0)
assert(minor >= 0)
assert(experimental >= 0)

def <:<(compiler: TastyVersion): Boolean = TastyFormat.isVersionCompatible(
fileMajor = file.major,
fileMinor = file.minor,
Expand Down