-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Add Matchable trait #10670
Add Matchable trait #10670
Conversation
22319f3
to
260fbf2
Compare
test performance please |
performance test scheduled: 2 job(s) in queue, 1 running. |
73f9dc7
to
691abf3
Compare
BreakagesTwo tests broke.
Also, ZIO broke with errors like this one:
This should be investigated further. I had a quick look how much would break once we turn on a warning with each conversion from |
Performance test finished successfully: Visit http://dotty-bench.epfl.ch/10670/ to see the changes. Benchmarks is based on merging with master (e1166a0) |
Test performance please |
test performance please |
@odersky I looked into the ZIO issue and was able to isolate it to this line in def isSubtype[A](assertion: Assertion[A])(implicit C: ClassTag[A]): Assertion[Any] =
Assertion.assertionRec("isSubtype")(param(C.runtimeClass.getSimpleName))(assertion) { actual =>
if (C.runtimeClass.isAssignableFrom(actual.getClass())) Some(actual.asInstanceOf[A])
else None
} The call to This can be resolved by reimplementing the method as: def isSubtype[A](assertion: Assertion[A])(implicit C: ClassTag[A]): Assertion[Any] =
Assertion.assertionRec("isSubtype")(param(className(C)))(assertion)(C.unapply(_))
def className[A](C: ClassTag[A]): String =
try {
C.runtimeClass.getSimpleName
} catch {
// See https://github.com/scala/bug/issues/2034.
case t: InternalError if t.getMessage == "Malformed class name" =>
C.runtimeClass.getName
} With this change all ZIO tests in the community build pass on your commit before you reverted the Note that this change was actually already implement in ZIO in February in zio/zio#2971 so we have a bit of an issue that the ZIO version in the community build is relatively old. Not sure what the best process is to update it at this point and ensure it stays current in the future. In any case, there does appear to be some difference in semantics with this PR right now. Not sure if it is possible or advisable to address it but regardless I don't think ZIO should be a blocker for moving forward with this PR. |
@adamgfraser I've opened #10696 to update ZIO in the community build. |
performance test scheduled: 1 job(s) in queue, 0 running. |
Performance test finished successfully: Visit http://dotty-bench.epfl.ch/10670/ to see the changes. Benchmarks is based on merging with master (c042be9) |
@adamgfraser Thank you for digging into this. What must have happened is that I believe it is overall safer not to move |
ac2ad69
to
273e7b5
Compare
A holy grail of the FP community is to statically prevent violation of parametric reasoning, e.g. rule out implementations like the following bogus definition of the identity function: def identity[A](a: A): A =
if a == 1 then 2.asInstanceOf[A]
else if a.isInstanceOf[Int] then a.hashCode.asInstanceOf[A]
else a match
case "foo" => "bar".asInstanceOf[A]
case x: Boolean => !x.asInstanceOf[A]
case x => x (This does not compile without casts, but with improved flow-typing, presumably could!) Toward this aim, I'd be quite excited about any proposal that moves us even incrementally in this direction; or which allows Unfortunately, some Scala developers have become unreasonably scared of "Any", because of fear of how a value of that type would be used (indeed, Scala 2.x aggressively warns on the use of |
The current scheme is now the bare minimum needed to move forward: An empty marker trait The plan is that over time we will move methods like Since the current PR is risk-free and useful I propose we merge it, even at that late state in the game. |
@odersky is there any plans at all, perhaps in the far future, to also deprecate or remove methods like |
273e7b5
to
5ff7997
Compare
I believe this PR needs the following additional tests:
|
Sounds great.
Double thumbs up from me. 👍 👍 |
Otherwise, the code looks good |
History of squashed individual commits: Fix scala3doc Hierarchy test and CompilationTest Also, drop code that's no longer needed since we made Matchable an empty trait Re-enable tasty-interpreter test Since no more casts are inserted, this means tasty-interpreter runs as before. Make Matchable an empty marker trait Revert getClass changes Move getClass back to Any. This is needed to make zio pass. Make Matchable a trait Rename Scrutable => Matchable Re-enable utest zio is still broken with failures at runtime. Check nesteded scrutinees for scrutability Disable zio Move isInstanceOf to Scrutable Avoid reloading `AnyVal` Widen before checking types in assumedCanEqual Require scrutinees to be Scrutable Add test Rename Classable -> Scrutable Move getClass to Classable Avoid duplication in TreeInfo and Inliner Disable utest Trial: Towards a parametric top type
Also, add back tests
04db456
to
0a28853
Compare
There is a bug with https://github.com/lampepfl/dotty/pull/10670/files#diff-8893c00063ce469a750bdbdbca40265550e0901a39a8a45e2f83aa6d51230aa0R1161. a389a11 reproduces it. |
Don't check for matchability if - pattern type is a subtype of tested type - we are unapplying a typetest or classtag test
232d686
to
7fad5c7
Compare
This PR addresses the problem discussed in #10662. In a nutshell the question is how to avoid situations like these:
IArray
is an opaque type that's defined in the standard library as follows:One could be tempted to just decree that opaque types cannot be used as scrutinees in matches, but that would fall short:
So we need a more systematic way to guard type abstractions like the ones provided by opaque types, or abstract types, or type parameters.
That's what this PR provides. It adds a new synthetic trait
Matchable
that gets erased toObject
and changes the hierarchy of toplevel classes and their members to the following:Moreover, in a pattern match against a constructor or type ascription the scrutinee should be of type
Matchable
. The compiler will insert a cast fromAny
toMatchable
where this is needed. More precisely, given an expressionE
or typeT
, whereT
does not derive fromMatchable
, and an expected type which is eitherMatchable
or[ ].getClass
or[ ].isInstanceOf
, we insert the castE.asInstanceOf[T & Matchable]
. With that change, everything(*) compiles as before. However, the cast can be tuned to come with a warning. The current PR enables the warning for-source 3.1
orsource 3.1-migration
and later. For-source 3.0
we don't want a warning yet since we want to maintain the property that we can cross-compile without warnings between 2.13 and 3.0.With this change the problematic examples (both versions) are rejected:
(*) currently there's a problem with zio that needs investigation
EDIT: With the speedy help of @adamgfraser we could figure out the zio problems and a fix is available. However, diagnosing that problem makes me retreat a bit in the interest of safety. I think it is safest not to move any methods from
Any
toMatchable
and letMatchable
instead be a pure marker trait that controls the ability to pattern match. That's the crucial parametricity guarantee we want to give; the methods inAny
themselves are not a problem since they are read-only (except forasInstanceOf
, of course, but that's our unsafe escape hatch).With that latest restricted version, all tests and all community build projects pass without modifications. That's not surprising, since the generated code with
Matchable
is the same as the generated code withoutMatchable
. There are some additional warnings, which will be turned on after 3.0. There's also the chance that some inferred type will beMatchable
instead ofAny
, but it looks quite far-fetched to construct a problem from that in practice.