Open
Description
Compiler version
3.3.0
Minimized code
trait Inst:
opaque type InstrumentedFn[A] = A
class Opt2[F](
instrumentation: Inst
)(
f: (i: Inst) => i.InstrumentedFn[F]
)
Output
[warn] Internal error in extracting SemanticDB while compiling /home/mhammons/Projects/slinc/core/src/fr/hammons/slinc/jitc/Opt2.scala: Ignoring i of symbol val f, type MethodType(List(i), List(TypeRef(ThisType(TypeRef(NoPrefix,module class jitc)),trait Inst)), AppliedType(TypeRef(TermParamRef(i),type InstrumentedFn),List(TypeRef(ThisType(TypeRef(ThisType(TypeRef(NoPrefix,module class jitc)),class Opt2)),type F))))
Expectation
This should hopefully not cause problems for Scala. The use case for this pattern, in my case, is that the Inst
type is attesting that the resulting type F is a function that has been instrumented. The full code I'm using is more like this:
trait Instrumentation:
def getCount(): Int
protected def toInstrumented[A](a: A): Instrumented[A] = a
opaque type Instrumented[A] = A
opaque type InstrumentedFn[A] <: A = A
def instrument[A](a: A): Instrumented[A]
def apply[A, B <: Tuple, C, D, E](fn: A)(using
Fn[A, B, C],
C =:= Instrumented[D],
Fn[E, B, D]
): InstrumentedFn[E] =
fn.asInstanceOf[E]
class CountbasedInstrumentation extends Instrumentation:
private val count = AtomicInteger(0)
def getCount() = count.getAcquire()
private def incrementCount(): Int =
var succeeded = false
var res = 0
while !succeeded do
res = count.getOpaque()
succeeded = count.compareAndSet(res, res + 1)
res + 1
def instrument[A](a: A): Instrumented[A] =
incrementCount()
toInstrumented(a)
object IgnoreInstrumentation extends Instrumentation:
def getCount() = 0
def instrument[A](a: A): Instrumented[A] = toInstrumented(a)
class OptimizableFn[F](
optimizer: JitCService,
inst: Instrumentation = new CountbasedInstrumentation
)(
f: (i: Instrumentation) => i.InstrumentedFn[F],
limit: Int
)(optimized: JitCompiler => F):
private val _fn: AtomicReference[F] = AtomicReference(f(inst))
val uuid = UUID.randomUUID().nn
println(s"created fn $uuid")
private val _optFn: AtomicReference[F] = AtomicReference(
if inst.getCount() >= limit then
var opt: F | Null = null
optimizer.jitC(uuid, jitCompiler => opt = optimized(jitCompiler))
opt
else null
)
def get: F =
val optFn = _optFn.getOpaque()
if optFn != null then optFn
else
if inst.getCount() >= limit then
optimizer.jitC(
uuid,
jitCompiler =>
val opt = optimized(jitCompiler)
_fn.setOpaque(
opt
)
)
_fn.getOpaque().nn
object OptimizableFn:
val modeSetting = "slinc.jitc.mode"
val limitSetting = "slinc.jitc.jit-limit"
def apply[F](optimized: JitCompiler => F)(
unoptimizedFn: (i: Instrumentation) => i.InstrumentedFn[F]
) =
val mode = sys.props.getOrElseUpdate("slinc.jitc.mode", "standard")
mode match
case "standard" =>
val limit =
sys.props.getOrElseUpdate("slinc.jitc.jit-limit", "10000").toIntOption
limit match
case None => throw Error("slinc.jitc.jit-limit should be an integer")
case Some(value) =>
new OptimizableFn[F](
JitCService.standard,
CountbasedInstrumentation()
)(unoptimizedFn, value)(optimized)
case "never" | "disabled" =>
new OptimizableFn[F](JitCService.synchronous, IgnoreInstrumentation)(
unoptimizedFn,
1
)(optimized)
case "immediate" =>
new OptimizableFn[F](JitCService.synchronous, IgnoreInstrumentation)(
unoptimizedFn,
0
)(optimized)
def standard[F](
optimized: JitCompiler => F
)(unoptimizedFn: (i: Instrumentation) => i.InstrumentedFn[F], limit: Int) =
new OptimizableFn[F](JitCService.standard)(unoptimizedFn, limit)(optimized)
Where Fn
is an evidence type that provides info like:
given [A,Z]: Fn[A => Z, Tuple1[A], Z] with {}