-
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
WIP Relax realizability for erased members, treat them like lazy ones #4290
WIP Relax realizability for erased members, treat them like lazy ones #4290
Conversation
Add the rule T <: Any for any *-Type T. This was not include fully before. We did have the rule that T <: Any, if Any is in the base types of T. However, it could be that the base type wrt Any does not exist. Example: Any#L <: Any yielded false before, now yields true. This error manifested itself in i4031.scala. With the new rule, we can drop again the special case in derivedSelect.
A TermRef is stable if its underlying type is stable. Realizability should behave the same way. This obviates the change in z1720.scala.
I had a TypeError crash in refchecks after screwing up a typeclass encoding in a particularly bad way. This commit reports an error instead.
That is, set is(Stable) for symbols that satisfy isStable.
I wrote this because I feared (incorrectly) exponential slowdowns in realizability checking for this code. But debugging suggests that the complexity of realizability checking is constant in the size of these expressions (even after I disable caching of `Stable`). Beware 1: these expressions almost smash the stack by sheer size. Beware 2: this fails with `-Yno-deep-subtypes`, but simply because the checking heuristics assumes people don't try to do this.
This reduces confusion with `Type.isStable`. I'm tempted to call this `isPure`.
Partially address TODO on erased members by treating them like lazy values: they do not exist at runtime, and their initialization might fail, but they're realizable if their type is. I do not treat erased members as _final_ lazy ones because erased definitions are not automatically final, and it's not 100% obvious they should be (after discussion with Nicholas Stucki). Current situation: If `U <: T`, the current rules allow the following override ```scala trait A { erased def foo: T = ... } trait B extends A { erased def foo: U = ... } ``` And just like lazy values, `U` might be unrealizable even when `T` is, so it's unsafe to treat `(a: A).foo` as realizable. The above code might be used (questionably) through ```scala def takeErased(erased a: T): Any def takeBetterErased(erased a: U): String def f(a: A) = a match { case b: B => takeBetterErased(b.foo) case _ => takeErased(a.foo) } ``` It's very unclear whether that's desirable. Alternatively, concrete erased definitions might be made automatically final, and that would be picked up by `isEffectivelyFinal` without further changes.
Hm, the fact that |
TODO look into this again; I was convinced that invalid lazy vals would always fail while erased ones don't, but recursive lazy vals can produce |
final def isStable(implicit ctx: Context) = { | ||
def isUnstableValue = is(UnstableValue) || info.isInstanceOf[ExprType] | ||
isType || is(Stable) || !isUnstableValue | ||
} |
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 WIP PR (missing tests) builds on top of #4036.
Partially address TODO on erased members by treating them like lazy values: they
do not exist at runtime, and their initialization might fail, but they're
realizable if their type is.
I do not treat erased members as final lazy ones because erased definitions
are not automatically final, and it's not 100% obvious they should be (after
discussion with Nicholas Stucki). Current situation:
If
U <: T
, the current rules allow the following overrideAnd just like lazy values,
U
might be unrealizable even whenT
is, so it'sunsafe to treat
(a: A).foo
as realizable.The above code might be used (questionably) through
It's very unclear whether that's desirable.
Alternatively, concrete erased definitions might be made automatically final,
and that would be picked up by
isEffectivelyFinal
without further changes./cc @nicolasstucki @odersky