Skip to content

Fix #6288: Allow Singletons in Unions #6299

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

Merged
merged 25 commits into from
May 2, 2019
Merged

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Apr 13, 2019

No description provided.

@smarter
Copy link
Member

smarter commented Apr 13, 2019

For reference, here's the open issue about this: #1551

@odersky
Copy link
Contributor Author

odersky commented Apr 13, 2019

test performance please

@dottybot
Copy link
Member

performance test scheduled: 1 job(s) in queue, 0 running.

@dottybot
Copy link
Member

Performance test finished successfully:

Visit http://dotty-bench.epfl.ch/6299/ to see the changes.

Benchmarks is based on merging with master (c3e88b7)

@odersky
Copy link
Contributor Author

odersky commented Apr 14, 2019

test performance please

@dottybot
Copy link
Member

performance test scheduled: 1 job(s) in queue, 0 running.

@dottybot
Copy link
Member

Performance test finished successfully:

Visit http://dotty-bench.epfl.ch/6299/ to see the changes.

Benchmarks is based on merging with master (c3e88b7)

@odersky
Copy link
Contributor Author

odersky commented Apr 15, 2019

test performance please

@dottybot
Copy link
Member

performance test scheduled: 1 job(s) in queue, 0 running.

@dottybot
Copy link
Member

Performance test finished successfully:

Visit http://dotty-bench.epfl.ch/6299/ to see the changes.

Benchmarks is based on merging with master (25a3773)

@odersky
Copy link
Contributor Author

odersky commented Apr 15, 2019

test performance please

@odersky odersky marked this pull request as ready for review April 15, 2019 10:33
@dottybot
Copy link
Member

performance test scheduled: 2 job(s) in queue, 1 running.

@dottybot
Copy link
Member

Performance test finished successfully:

Visit http://dotty-bench.epfl.ch/6299/ to see the changes.

Benchmarks is based on merging with master (8e323b1)

@odersky
Copy link
Contributor Author

odersky commented Apr 16, 2019

@nicolasstucki I had to disable compiling tasty-interpreters in BootstrappedOnlyCompile since I got errors of this form:

51 |    else jvmReflection.interpretNew(fn.symbol, evaluatedArgss(argss))
   |                                    ^^^^^^^^^
   |                                    Found:    Interpreter.this.reflect.Symbol
   |                                    Required: Interpreter.this.jvmReflection.reflect'.Symbol
   |                                    
   |                                    where:    reflect  is a value in class TreeInterpreter
   |                                              reflect' is a value in class JVMReflection

Can you take a look what went wrong here, and hopefully bring them back?

@odersky odersky force-pushed the fix-#6288 branch 2 times, most recently from 263091b to 2e9084e Compare April 17, 2019 11:58
@odersky
Copy link
Contributor Author

odersky commented Apr 17, 2019

test performance please

@dottybot
Copy link
Member

performance test scheduled: 2 job(s) in queue, 1 running.

@dottybot
Copy link
Member

Performance test finished successfully:

Visit http://dotty-bench.epfl.ch/6299/ to see the changes.

Benchmarks is based on merging with master (afb7a8b)

Copy link
Contributor

@nicolasstucki nicolasstucki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Otherwise LGTM

def canCompare(atoms: Set[Type]): Boolean =
ctx.phase.isTyper || {
val hasSkolems = new ExistsAccumulator(_.isInstanceOf[SkolemType]) {
override val stopAtStatic = true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a def

val x = 3
opaque type T = x.type
object T {
def wrap(a: x.type): T = a // Error
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intended to be a neg test?

@nicolasstucki
Copy link
Contributor

I added a commit fixing the checkfile of tasty-extractors-1 and then reverted it because there was a conflict with master. I will fix it once this is merged.

Copy link
Member

@smarter smarter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please rebase to make sure this doesn't conflict with recent changes such as the full bootstrap.

* two different skolems in all phases `p`, where `p.isTyper` is false.
* But in that case comparing two sets of atoms that contain skolems
* for equality would give the wrong result, so we should not use the sets
* for comparisons.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't not using the sets a potential performance problem ? Have you considered having both OrType#atoms and OrType#atomsUnifySkolems instead, where the latter would replace all skolems referring to the same type by a single instance ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe skolems are sufficiently rare. If it turns out that we get a performance problem, what you suggest could be a good alternative.

@@ -1499,30 +1542,38 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
/** The greatest lower bound of a list types */
final def glb(tps: List[Type]): Type = ((AnyType: Type) /: tps)(glb)

def widenInUnions(implicit ctx: Context): Boolean = ctx.scala2Mode || ctx.erasedTypes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have examples of Scala 2 code that breaks without the scala2Mode here ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't tried. But it's better to be conservative, I think.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure, all these inference differences (that we'll have to document at some point) make it more risky for a codebase to turn off Scala2 mode since there's a non-zero chance any of them could cause a slient change of runtime behavior (e.g. because a different implicit ends up being selected). They're also only lightly tested since most of our tests are run without Scala2 mode enabled, meaning a higher risk of unforeseen interactions. So I'd limit them to things that significantly help in cross-compilation, but we can revisit this some other time.

val isSingle1 = tp1.isInstanceOf[SingletonType]
val isSingle2 = tp2.isInstanceOf[SingletonType]
return {
if (tp2w eq tp2) orDominator(tp1w | tp2)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be helpful to add comments like // 2.1 above conditions to relate them with the comment above and make sure they stay in sync in the future.

else if (tp2w frozen_<:< tp1w) orDominator(tp1 | tp2w)
else if (isSingle1 && !isSingle2) orDominator(tp1w | tp2)
else if (isSingle2 && !isSingle1) orDominator(tp1 | tp2w)
else if (tp1 frozen_<:< tp2w) tp2w
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is a case for 2.5 looking like else if (tp2 frozen_<:< tp1w) tp1w missing here ?

else if (isSingle1 && !isSingle2) orDominator(tp1w | tp2)
else if (isSingle2 && !isSingle1) orDominator(tp1 | tp2w)
else if (tp1 frozen_<:< tp2w) tp2w
else orDominator(tp1w | tp2)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2.6 says "pick tp1", that doesn't seem to match the code.

tp
}

/** Widen all top-level singletons reachable by dealising
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/** Widen all top-level singletons reachable by dealising
/** Widen all top-level singletons reachable by dealiasing

@odersky
Copy link
Contributor Author

odersky commented Apr 29, 2019

@nicolasstucki I tried to update the check file but still get errors for the runMacros test. Can you take a look? Thanks!

odersky and others added 20 commits May 2, 2019 15:30
Widen in lubs only if

 - the type is unstable, or
 - we are after erasure

This need to be complemented by performance work as otherwise complexity of
subtype checking will explode.
We also need to undo the RefinedType self type of opaque
type companions. Otherwise, programs die in erasure if
tracing is enabled.
Since we do not widen singletons in unions, it is now easy to get
large union types consisting of singletons. We need to specialize
the code dealing with them in order not to get deep subtype recursions
and drastic compilation speed slowdowns.
This was the situation before the PR. I thought that simply checking whether
the instance is a subtype of the bound is equivalent, but compare-singletons.scala
shows that this is not the case. Here, we have a type variable X such that
`r.type <:< X <:< Singleton` where `r: R` and `R <: Singleton`. With the
previous changes in this PR, we instantiate `X` to `R`. With the revert
in this commit we instantiate it to `r.type` instead.
This relieves some of the load of `join` and offers more opportunities
to improve union types by constraining further. Without this step
we might lose some improvements compared to the situation before
where we always widened singletons in OrTypes. I don't have a test
case that demonstrates the difference, though.
This was detected when failing to compile the 2.13 library.
The problem is minimized in test pos/padTo.scala. The failure
arose because with the introduction of singletons in unions
we get more "interesting" union types to approximate. But
it can be also produced without singleton types.
Further join refinements
Using --update-checkfiles
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants