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
SIP-23 Implementation of literal types #5310
Conversation
// valueOf ----------------------------------------------------------- | ||
|
||
/** Retrieve the single value of a type with a unique inhabitant. */ | ||
@inline def valueOf[T](implicit vt: ValueOf[T]): T {} = vt.value |
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.
The signature should be def valueOf[T]: T {}
. Avoid exposing the implicit parameter. (Have a look at classOf
for how it is done.)
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.
See comment on ValueOf
below. It's the type class which is important, this def very much less so.
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.
The style of the signature is not related to its importance. It should not be defined this way, regardless of importance.
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.
Have a look at resolveClassTag
to see how it's possible to resolve an implicit for your call without having to specify that your method takes one (and therefore allowing people to accidentally or maliciously pass one explicitly).
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.
@soc What's wrong with this signature? stdlib have a lot of methods with implicit parameters. Isn't it the same as def classTag[T](implicit ctag: ClassTag[T]) = ctag
?
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.
In my book magicless also wins, except in the most important circumstances.
A method that will be available to every single developer by default, on every IDE auto-complete, is one of those important circumstances. It needs to consistent. It's the standard library, not some random third-party library people can opt out of.
After years of doing the deprecation/removal dance, valueOf
with ValueTag
is one of the things that would get fixed or removed in short order.
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 think perhaps it would be appropriate to add a comment to classOf
, explaining (or trying to explain) why it don't have the obvious implementation.
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 can have a look at my new classOf[T] == classTag[T].runtimeClass
implementation, I'm pretty sure I added some comment there.
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.
T {}
is a little confusion because it does not respect .widen
:
@ val t = typeOf[0 {}]
t: Type = RefinedType(List(FoldableConstantType(Constant(0))), SynchronizedOps())
@ val w = t.widen
w: Type = RefinedType(List(FoldableConstantType(Constant(0))), SynchronizedOps())
@ println(t eq w)
true
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.
How about encode it as Id[0]
, which is less magic.
@ type Id[+A] = A
defined type Id
@ val dontWidenMe: Id[0] = 0
dontWidenMe: Id[0] = 0
@ Some(dontWidenMe)
res72: Some[Id[0]] = Some(0)
Why is the macro API left unchanged? What if metaprogrammers want to explicitly control the flavor of constant types? Also, could you document the differences between LiteralConstantType and FoldableConstantType? At the moment, these are classes with no comments or documentation. |
@xeno-by four reasons,
|
src/library/scala/ValueOf.scala
Outdated
* Instances of `ValueOf[T]` are provided implicitly for all eligible types. Typically | ||
* an instance would be required where a runtime value corresponding to a type level | ||
* computation is needed. For example, we might define a type of list which encodes its | ||
* length in its type, in which case the lenght of the list can be computed as a |
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.
Typo: lenght
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.
Well spotted.
I think those failures are spurious ... |
/rebuild |
Just found a couple of minor things from early experiments:
@milessabin Would you like me to continue reporting issues on this PR, or is there somewhere better? |
else if (in.token == INTERPOLATIONID) | ||
if (in.token == SYMBOLLIT) { | ||
if(settings.YliteralTypes) | ||
finish(Symbol(in.strVal.intern())) |
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'd prefer to represent these with a distinct type from Symbol
to avoid a memory leak in a resident compiler (Symbol
-s are stored in a hash map).
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 forgot that it is actually a weak map, so we can keep things as they are.
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.
@propensive yes, please do report issues here. |
@retronym re. Co-authored-by ... yes, of course. |
spec/03-types.md
Outdated
value which [conforms](06-expressions.html#expression-typing) to | ||
`scala.AnyRef`, the type denotes the set of values consisting of `null` and the | ||
value denoted by $p$ (i.e., the value $v$ for which `v eq p`). Where the path | ||
does not conform to `scala.AnyRef` the type denotes the set consiting of only |
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.
s/consiting/consisting/
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.
Well spotted.
07341a0
to
bb0ac9b
Compare
SIP-23 has been reviewed in today's SIP meeting. The assigned reviewer is @adriaanm, which will provide actionable feedback shortly. |
@propensive apropos your observation about the different rendering of types in the REPL: the distinction is between inferred constant types ( |
Does this apply to non-literal singleton types as well? It would be quite useful in some cases I've had. This change should also be documented in 6.26.4. |
JFYI this is green now @milessabin. |
Community build here: https://scala-ci.typesafe.com/view/scala-2.13.x/job/scala-2.13.x-integrate-community-build/889/. Although it looks like the community build hasn't be green for a while ... or am I misreading the Jenkins dashboard? |
yeah the 2.13 community build is kind of a shambles right now. a bunch of projects are green, but many aren't. so it can give some assurance, but far less assurance, currently, than the 2.12 community build gives. I haven't prioritized it because as soon as the new collections land in 2.13, I expect everything to break anyway. the laborious process of getting everything green again will begin in earnest at that point. |
compared to the previous run, there seem to be 3 additional failures. Theoretically they could be due to changes in the respective repos. To investigate. scala-continuations:
scala-parallel-collections:
slick:
|
The scala-continuations one is probably due to the introduction of the new subtypes of |
I don't know how difficult is the backport to 2.12, but if you do it for TLS anyways, then you can use it as dummy PR to 2.12, just to test the community build. |
There is a comment in https://github.com/milessabin/scala/blob/352a0c8c4eccbca1c0c98de784c2ed87cc5b7fe9/src/library/scala/Predef.scala#L203
I guess it's the time now to make |
We’re not accepting new features in 2.12 anymore, even under a flag. Sorry,
we have to keep this train moving forward. Any maintenance burden we take
on for old versions is less time to spend on 2.13 and 2.14 (soon!)
…On Mon, Jan 22, 2018 at 08:35 杨博 (Yang Bo) ***@***.***> wrote:
There is a comment in
https://github.com/milessabin/scala/blob/352a0c8c4eccbca1c0c98de784c2ed87cc5b7fe9/src/library/scala/Predef.scala#L203
@inline <https://github.com/inline> def implicitly[T](implicit e: T) = e
// for summoning implicit values from the nether world -- TODO: when
dependent method types are on by default, give this result type e.type,
so that inliner has better chance of knowing which method to inline in
calls like implicitly[MatchingStrategy[Option]].zero
I guess it's the time now.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#5310 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAFjy1xw6tVtSVBzbCeXA7IRqrc8MHB_ks5tNDopgaJpZM4JYDkI>
.
|
@adriaanm I meant 2.13 milessabin#6 |
Was this in reply to me @adriaanm ? I was just suggesting how to test for community-build regressions, since the 2.13 build is currently failing. |
You could also use the |
@lrytz I'm not quite sure what you're proposing ... do you mean rebase this PR onto the commit corresponding to the last green community build and then run against that? TBQH, I think it would probably be quicker and easier to checkout and try building the three newly failing projects. |
Ah, my assumption is that the community build is not broken due to 2.13.x being broken, but because the community projects moved ahead with incompatible changes - that's the more common case anyway. So if you take the last green run and freeze all community projects at the SHAs they had at this point, the build will probably also pass with current 2.13.x (or the baseline of this PR). |
Instead of running locally, you can push the frozen SHAs to a branch of your scala/community-builds fork, and then specify that when starting the community build (https://scala-ci.typesafe.com/view/scala-2.13.x/job/scala-2.13.x-integrate-community-build/build?delay=0sec) |
My understanding is that the main reason the 2.13 community build is currently broken is that we had inadvertently released 2.13.0-M1 and 2.13.0-M2 with There are two paths forward for fixing it:
we sometimes go the fix-it-ourselves route, but in this case several of the broken projects are pretty big/complicated (e.g. scalaz and shapeless), so I think it might be better to just cross our fingers and ship M3 without strong assurance from the community build. |
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.
LGTM
Let's deal with the community build in the next weeks. As Seth said, this isn't the first PR to affect the community build in 2.13.x. |
|
Wow! Congratulation @milessabin for threading this needle! |
Woo! Thanks @milessabin and all reviewers and contributors to this effort. |
Thanks for helping me getting this across the line @adriaanm! |
Race condition in the merges of scala#6270 (added the test) and scala#5310 (changes its output).
Implements literal types. Enabled by
-Yliteral-types
or-Xexperimental
.This is a continuation of work by @folone and @adriaanm. The work on @adriaanm's branch was the starting point and all the TODO items on the corresponding PR have been completed.
final
on a val definition to explicitly request an unwidened type to be inferred is preserved. Type parameter inference remains the same unless the inference of a singleton type is explicitly requested via a<: Singleton
bound.scala.ValueOf[T]
type class and correspondingscala.Predef.valueOf[T]
operator has been added yielding the unique value of types with a single inhabitant.isInstanceOf
/asInstanceOf
tests/conversions are implemented via equality/identity tests for singleton types.scala.Symbol
literal types has been added.-Yliteral-types
enabled on all tests there are 15 test result changes, all of which are expected. See below for details.LiteralConstantType
andFoldableConstantType
subtypes of the API typeConstantType
.-Yliteral-types
both enabled and disabled.Related bugs fixed in this PR
Test result changes with
-Yliteral-types
enabled for all testsNew warnings due to Symbol literals becoming pure:
Error messages changed due to more precise types being reported:
Pos tests which correctly become neg with -Yliteral-types
Neg tests which correctly become pos with -Yliteral-types:
Error messages changed correctly:
Compiler/REPL output changed due to more precise types being reported:
Compiler/REPL output changed due to Symbols becoming first-class literals:
Run tests which correctly fail due to improved inference
Unavoidable failure due to the enablement of the feature: