-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Make erased
capability-safe
#23419
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
base: main
Are you sure you want to change the base?
Make erased
capability-safe
#23419
Conversation
Since we will force erased expressions to be pure values, they are always initialized.
# Conflicts: # compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
- erasedValue[<ConstantType>] is now considered to be pure - calls of synthetic case class apply are considered pure if the case class is NoInits - Companions of Scala-2 classes Tuple and Some are assumed to be NoInits
@@ -6,15 +6,15 @@ object App { | |||
trait A { type L >: Any} | |||
def upcast(erased a: A)(x: Any): a.L = x | |||
erased val p: A { type L <: Nothing } = p | |||
def coerce(x: Any): Int = upcast(p)(x) // error | |||
def coerce(x: Any): Int = upcast(p)(x) // ok? | |||
|
|||
def coerceInline(x: Any): Int = upcast(compiletime.erasedValue[A {type L <: Nothing}])(x) // error | |||
|
|||
trait B { type L <: Nothing } | |||
def upcast_dep_parameter(erased a: B)(x: a.L) : Int = x | |||
erased val q : B { type L >: Any } = compiletime.erasedValue |
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.
Should this be rejected? This should be unsafeErasedValue
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.
It gets rejected for a different reason before.
@@ -6,15 +6,15 @@ object App { | |||
trait A { type L >: Any} | |||
def upcast(erased a: A)(x: Any): a.L = x | |||
erased val p: A { type L <: Nothing } = p | |||
def coerce(x: Any): Int = upcast(p)(x) // error | |||
def coerce(x: Any): Int = upcast(p)(x) // ok? |
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 should be rejected, perhaps by initialization checker?
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.
Yes, but that's not part of the test. If we turn on the initialization checker we won't make it to erasure to detect the other problems.
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.
Basically, all that remains is a realizability check. The rest is would be detected if the check is omitted.
The purpose of
erased
is to give compile-time evidence without requiring a runtime value. The compile time evidence is typically for a type class instance or a capability. The previous design oferased
is not safe in this respect, as any value can be summoned by various means, includingerasedValue
expression of the required type,This PR implements a set of changes to make
erased
a trustable evidence.erased def
.erased
vals as late initialized.erasedValue
, which, unlikeerasedValue itself
,are treated as pure expressions.