Skip to content

Revert #14452 and make compile-time operations on stable arguments stable #15268

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 5 commits into from
Jun 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package dotty.tools.benchmarks

import org.openjdk.jmh.annotations.*
import java.util.concurrent.TimeUnit.SECONDS
import dotty.tools.dotc.{Driver, Run, Compiler}
import dotty.tools.dotc.core.Mode
import dotty.tools.dotc.core.Types.{TermRef, Type}
import dotty.tools.dotc.core.Contexts.{ContextBase, Context, ctx, withMode}

@Fork(value = 5)
@Warmup(iterations = 5, time = 1, timeUnit = SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = SECONDS)
@State(Scope.Thread)
class TypeOpsBenchmark:
var tp: Type = null
var context: Context = null

@Param(Array("int", "singletonsSum", "intsSum", "deepSingletonsSum", "deepIntsSum", "singletonsIntersection", "singletonsUnion"))
var valName: String = "int"

@Setup(Level.Iteration)
def setup(): Unit =
val driver = new Driver:
override def finish(compiler: Compiler, run: Run)(using Context): Unit =
withMode(Mode.Printing) {
val pkg = run.units(0).tpdTree.symbol
tp = pkg.requiredClass("Test").requiredValueRef(valName).underlying
context = ctx
}
super.finish(compiler, run)
driver.process(Array(
"-classpath", System.getProperty("BENCH_CLASS_PATH"),
"-Ystop-after:typer",
"tests/someTypes.scala"
))

@Benchmark
def isStable(): Unit = tp.isStable(using context)

@Benchmark
def normalized(): Unit = tp.normalized(using context)

@Benchmark
def simplified(): Unit = tp.simplified(using context)

@Benchmark
def dealias(): Unit = tp.dealias(using context)

@Benchmark
def widen(): Unit = tp.widen(using context)

@Benchmark
def atoms(): Unit = tp.atoms(using context)

@Benchmark
def isProvisional(): Unit = tp.isProvisional(using context)
22 changes: 22 additions & 0 deletions bench-micro/tests/someTypes.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import compiletime.ops.int.+

class Test:
val int: Int = 5

val int2: Int = 6

val singletonsSum: int.type + int2.type = ???

val intsSum: Int + Int = ???

val deepSingletonsSum:
((int.type + int2.type) + (int.type + int2.type)) + ((int.type + int2.type) + (int.type + int2.type)) +
((int.type + int2.type) + (int.type + int2.type)) + ((int.type + int2.type) + (int.type + int2.type)) = ???

val deepIntsSum:
((Int + Int) + (Int + Int)) + ((Int + Int) + (Int + Int)) +
((Int + Int) + (Int + Int)) + ((Int + Int) + (Int + Int)) = ???

val singletonsIntersection: int.type & int2.type = ???

val singletonsUnion: int.type | int2.type = ???
1 change: 1 addition & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ val `scala3-tasty-inspector` = Build.`scala3-tasty-inspector`
val `scala3-language-server` = Build.`scala3-language-server`
val `scala3-bench` = Build.`scala3-bench`
val `scala3-bench-bootstrapped` = Build.`scala3-bench-bootstrapped`
val `scala3-bench-micro` = Build.`scala3-bench-micro`
val `stdlib-bootstrapped` = Build.`stdlib-bootstrapped`
val `stdlib-bootstrapped-tasty-tests` = Build.`stdlib-bootstrapped-tasty-tests`
val `tasty-core` = Build.`tasty-core`
Expand Down
25 changes: 24 additions & 1 deletion compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ object Types {
// see: tests/explicit-nulls/pos/flow-stable.scala.disabled
tp.tp1.isStable && (realizability(tp.tp2) eq Realizable) ||
tp.tp2.isStable && (realizability(tp.tp1) eq Realizable)
case tp: AppliedType => tp.cachedIsStable
case _ => false
}

Expand Down Expand Up @@ -4161,10 +4162,32 @@ object Types {
private var myStableHash: Byte = 0
private var myGround: Byte = 0

private var myIsStablePeriod: Period = Nowhere
private var myIsStable: Boolean = false

def isGround(acc: TypeAccumulator[Boolean])(using Context): Boolean =
if myGround == 0 then myGround = if acc.foldOver(true, this) then 1 else -1
myGround > 0

private[Types] def cachedIsStable(using Context): Boolean =
// We need to invalidate the cache when the period changes because the
// case `TermRef` of `Type#isStable` reads denotations, which depend on
// the period. See docs/_docs/internals/periods.md for more information.
if myIsStablePeriod != ctx.period then
val res: Boolean = computeIsStable
// We don't cache if the type is provisional because `Type#isStable`
// calls `Type#stripTypeVar` which might return different results later.
if !isProvisional then
myIsStablePeriod = ctx.period
myIsStable = res
res
else
myIsStable

private def computeIsStable(using Context): Boolean = tycon match
case tycon: TypeRef if defn.isCompiletimeAppliedType(tycon.symbol) && args.forall(_.isStable) => true
case _ => false

override def underlying(using Context): Type = tycon

override def superType(using Context): Type =
Expand Down Expand Up @@ -4242,7 +4265,7 @@ object Types {
// final val one = 1
// type Two = one.type + one.type
// ```
case tp: TermRef => tp.underlying
case tp: TypeProxy if tp.underlying.isStable => tp.underlying.fixForEvaluation
Copy link
Member Author

Choose a reason for hiding this comment

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

Reasoning here: no need to check that tp is stable because it will be if its underlying type is stable. Could someone confirm if this is correct?

Otherwise, we might want:

case tp: TypeProxy if tp.isStable && tp.underlying.isStable => tp.underlying.fixForEvaluation

or

case tp: SingletonType if tp.isStable && tp.underlying.isStable => tp.underlying.fixForEvaluation

Copy link
Contributor

Choose a reason for hiding this comment

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

I think at least morally this is correct.

case tp => tp
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/plugins/Plugins.scala
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ trait Plugins {
}
else _roughPluginsList

/** Load all available plugins. Skips plugins that
/** Load all available plugins. Skips plugins that
* either have the same name as another one, or which
* define a phase name that another one does.
*/
Expand Down
6 changes: 3 additions & 3 deletions library/src/scala/compiletime/ops/any.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ object any:
* ```
* @syntax markdown
*/
type ==[+X, +Y] <: Boolean
type ==[X, Y] <: Boolean

/** Inequality comparison of two singleton types.
* ```scala
Expand All @@ -20,7 +20,7 @@ object any:
* ```
* @syntax markdown
*/
type !=[+X, +Y] <: Boolean
type !=[X, Y] <: Boolean

/** Tests if a type is a constant.
* ```scala
Expand Down Expand Up @@ -48,4 +48,4 @@ object any:
* ```
* @syntax markdown
*/
type ToString[+X] <: String
type ToString[X] <: String
8 changes: 4 additions & 4 deletions library/src/scala/compiletime/ops/boolean.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ object boolean:
* ```
* @syntax markdown
*/
type ![+X <: Boolean] <: Boolean
type ![X <: Boolean] <: Boolean

/** Exclusive disjunction of two `Boolean` singleton types.
* ```scala
Expand All @@ -19,7 +19,7 @@ object boolean:
* ```
* @syntax markdown
*/
type ^[+X <: Boolean, +Y <: Boolean] <: Boolean
type ^[X <: Boolean, Y <: Boolean] <: Boolean

/** Conjunction of two `Boolean` singleton types.
* ```scala
Expand All @@ -28,7 +28,7 @@ object boolean:
* ```
* @syntax markdown
*/
type &&[+X <: Boolean, +Y <: Boolean] <: Boolean
type &&[X <: Boolean, Y <: Boolean] <: Boolean

/** Disjunction of two `Boolean` singleton types.
* ```scala
Expand All @@ -37,4 +37,4 @@ object boolean:
* ```
* @syntax markdown
*/
type ||[+X <: Boolean, +Y <: Boolean] <: Boolean
type ||[X <: Boolean, Y <: Boolean] <: Boolean
32 changes: 16 additions & 16 deletions library/src/scala/compiletime/ops/double.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,39 @@ object double:
* ```
* @syntax markdown
*/
type +[+X <: Double, +Y <: Double] <: Double
type +[X <: Double, Y <: Double] <: Double

/** Subtraction of two `Double` singleton types.
* ```scala
* val sub: 4.0 - 2.0 = 2.0
* ```
* @syntax markdown
*/
type -[+X <: Double, +Y <: Double] <: Double
type -[X <: Double, Y <: Double] <: Double

/** Multiplication of two `Double` singleton types.
* ```scala
* val mul: 4.0 * 2.0 = 8.0
* ```
* @syntax markdown
*/
type *[+X <: Double, +Y <: Double] <: Double
type *[X <: Double, Y <: Double] <: Double

/** Integer division of two `Double` singleton types.
* ```scala
* val div: 5.0 / 2.0 = 2.5
* ```
* @syntax markdown
*/
type /[+X <: Double, +Y <: Double] <: Double
type /[X <: Double, Y <: Double] <: Double

/** Remainder of the division of `X` by `Y`.
* ```scala
* val mod: 5.0 % 2.0 = 1.0
* ```
* @syntax markdown
*/
type %[+X <: Double, +Y <: Double] <: Double
type %[X <: Double, Y <: Double] <: Double

/** Less-than comparison of two `Double` singleton types.
* ```scala
Expand All @@ -49,7 +49,7 @@ object double:
* ```
* @syntax markdown
*/
type <[+X <: Double, +Y <: Double] <: Boolean
type <[X <: Double, Y <: Double] <: Boolean

/** Greater-than comparison of two `Double` singleton types.
* ```scala
Expand All @@ -58,7 +58,7 @@ object double:
* ```
* @syntax markdown
*/
type >[+X <: Double, +Y <: Double] <: Boolean
type >[X <: Double, Y <: Double] <: Boolean

/** Greater-or-equal comparison of two `Double` singleton types.
* ```scala
Expand All @@ -67,7 +67,7 @@ object double:
* ```
* @syntax markdown
*/
type >=[+X <: Double, +Y <: Double] <: Boolean
type >=[X <: Double, Y <: Double] <: Boolean

/** Less-or-equal comparison of two `Double` singleton types.
* ```scala
Expand All @@ -76,15 +76,15 @@ object double:
* ```
* @syntax markdown
*/
type <=[+X <: Double, +Y <: Double] <: Boolean
type <=[X <: Double, Y <: Double] <: Boolean

/** Absolute value of an `Double` singleton type.
* ```scala
* val abs: Abs[-1.0] = 1.0
* ```
* @syntax markdown
*/
type Abs[+X <: Double] <: Double
type Abs[X <: Double] <: Double

/** Negation of an `Double` singleton type.
* ```scala
Expand All @@ -93,44 +93,44 @@ object double:
* ```
* @syntax markdown
*/
type Negate[+X <: Double] <: Double
type Negate[X <: Double] <: Double

/** Minimum of two `Double` singleton types.
* ```scala
* val min: Min[-1.0, 1.0] = -1.0
* ```
* @syntax markdown
*/
type Min[+X <: Double, +Y <: Double] <: Double
type Min[X <: Double, Y <: Double] <: Double

/** Maximum of two `Double` singleton types.
* ```scala
* val max: Max[-1.0, 1.0] = 1.0
* ```
* @syntax markdown
*/
type Max[+X <: Double, +Y <: Double] <: Double
type Max[X <: Double, Y <: Double] <: Double

/** Int conversion of a `Double` singleton type.
* ```scala
* val x: ToInt[1.0] = 1
* ```
* @syntax markdown
*/
type ToInt[+X <: Double] <: Int
type ToInt[X <: Double] <: Int

/** Long conversion of a `Double` singleton type.
* ```scala
* val x: ToLong[1.0] = 1L
* ```
* @syntax markdown
*/
type ToLong[+X <: Double] <: Long
type ToLong[X <: Double] <: Long

/** Float conversion of a `Double` singleton type.
* ```scala
* val x: ToFloat[1.0] = 1.0f
* ```
* @syntax markdown
*/
type ToFloat[+X <: Double] <: Float
type ToFloat[X <: Double] <: Float
Loading