-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Fix #3564: Allow annotated singleton types #3723
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
Conversation
test performance please |
performance test scheduled: 1 job(s) in queue, 0 running. |
@@ -802,7 +802,7 @@ object PatternMatcher { | |||
} | |||
|
|||
expectedTp.dealias match { | |||
case expectedTp: SingletonType => | |||
case SingletonType(expectedTp) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is wrong because the extractor for SingletonType will take only one branch of an AndType:
trait Foo {
def hi: Int
}
object Test {
def foo(x: Any) = x match {
case x: ("1" & Foo) =>
x.hi
case _ =>
}
def main(args: Array[String]): Unit = {
foo("1")
}
}
This code used to run correctly, but now crashes with java.lang.ClassCastException: java.lang.String cannot be cast to Foo
. In general I would rather not consider AndType
to be singleton types, I think it's too easy to get incorrect semantics that way like what's happening here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. It looks easiest to revert and not let AndTypes be SingletonTypes, even though semantically it would be nice if they could be.
Previously, singleton types were widened before an annotation was added. Now such a widening is no longer performed. The change necessitated a systematic generalization of what it means to be a singleton, where we now need to dealias in several places before checking for SingletonType.
test performance please |
performance test scheduled: 1 job(s) in queue, 0 running. |
@smarter I changed the scheme so that AndTypes no longer qualify as singletons |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Somehow we now loose annotations in some situations:
on master:
scala> val x = 1: @unchecked
val x: Int @unchecked = 1
scala> val x = 1: Int @unchecked
val x: Int @unchecked = 1
With this PR:
scala> val x = 1: @unchecked
val x: Int = 1
scala> val x = 1: Int @unchecked
val x: Int @unchecked = 1
Performance test finished successfully: Visit http://dotty-bench.epfl.ch/3723/ to see the changes. Benchmarks is based on merging with master (b199bf4) |
Yes, it's because widen drops annotations and local type inference does a widen. It is a change of behavior but it's not clear that the old behavior was the correct one. I tried to leave the annotation on when widening but that's unintuitive (for comparison, we drop the annotation on dealiasing), and it also caused a lot of failures e.g. in compileStdLib. So I think the new scheme is the least bad one. |
@@ -1593,7 +1593,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit | |||
if (ctx.mode is Mode.Type) | |||
assignType(cpy.Annotated(tree)(arg1, annot1), arg1, annot1) | |||
else { | |||
val tpt = TypeTree(AnnotatedType(arg1.tpe.widen, Annotation(annot1))) | |||
val tpt = TypeTree(AnnotatedType(arg1.tpe, Annotation(annot1))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually thinking about this more, I think we should keep the .widen
here.
I think we can only reach this case when the user write:
val x = 1: @unchecked
In this case I think it's fine to interpret this code as if the user had written:
val x = 1: Int @unchecked
If the user really wants to put the annotation on the singleton type, which is rather unusual, he can still explicitly write:
val x = 1: 1 @unchecked
This one will work fine because of the .widen
which was dropped in TypeAssigner
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But that means #3564 fails, because we have precisely the case where we annotate a singleton with @uncheckedVariance.
Also, I would argue that someone writing
expr: @unchecked
is really annotating the expression expr
, not its type. The type is an artifact of the way we express annotated expressions. So it is better that the annotation does not leak into inferred types of the lhs, say. See also #3427, which is another bug that would be fixed by this PR, but would not be fixed by the proposed change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But that means #3564 fails, because we have precisely the case where we annotate a singleton with @uncheckedvariance.
I don't think so, in #3564 a singleton type is annotated, so ctx.mode is Type
is true, this case is handled two lines above the current one, and only the .widen
that was in TypeAssigner
is relevant there.
So it is better that the annotation does not leak into inferred types of the lhs, say.
OK. I'm fine with this but note that this is a change of behavior with respect to Scala 2.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I changed the logic in Typer only, and #3564 started failing again.
Previously, singleton types were widened before an annotation was added. Now such
a widening is no longer performed. The change necessitated a systematic generalization
of what it means to be a singleton, where we now use in many places
an extractor instead of a type test. This has the added benefit that we now also
classify as singletons intersections involving a singleton type and aliases to a singleton
type.