Skip to content
Open
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
19 changes: 18 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,23 @@ jobs:
if: needs.checksecret.outputs.HAVE_SECRETS == 'true'
uses: scalacenter/sbt-dependency-submission@53544c3e7bf54b0cb7f375f016e5b7446b96b706

mima:
runs-on: ubuntu-latest
needs: [ 'checksecret' ]
strategy:
fail-fast: false
matrix:
java: [ '17' ]
scala: [ '2.11', '2.12', '2.13', '3' ]
steps:
- uses: 7mind/github-env@minimal
- name: MIMA Binary Compatibility Checks
env:
CI_PULL_REQUEST: ${{ github.event_name == 'pull_request' }}
CI_BRANCH: ${{ github.ref_name }}
CI_BRANCH_TAG: ${{ github.ref_name }}
run: nix develop --command mdl -u java_version:${{ matrix.java }} -u scala_version:${{ matrix.scala }} --github-actions :gen :mima

publish-artifacts:
runs-on: ubuntu-latest
needs: [ 'build', 'checksecret' ]
Expand Down Expand Up @@ -119,7 +136,7 @@ jobs:
all-good:
if: always()
runs-on: ubuntu-latest
needs: [ 'build' ]
needs: [ 'build', 'mima' ]
steps:
- name: Decide whether the needed jobs succeeded or failed
uses: re-actors/alls-green@release/v1
Expand Down
23 changes: 21 additions & 2 deletions .mdl/defs/actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ bash sbtgen.sc --js --native

# action: test

Run tests and binary compatibility checks
Run tests

```bash
# Declare dependencies and use their outputs
Expand All @@ -194,7 +194,26 @@ sbt -batch -no-colors -v \
--java-home "$JAVA_HOME" \
"$VERSION_COMMAND clean" \
"$VERSION_COMMAND Test/compile" \
"$VERSION_COMMAND test" \
"$VERSION_COMMAND test"
```

# action: mima

Run binary compatibility checks

```bash
# Declare dependencies and use their outputs
soft action.gen retain.action.check-sbtgen-staleness

JAVA_HOME="${action.setup-jdk.java-home}"
PATH="${action.setup-jdk.path}"
JAVA_OPTIONS="${action.setup-jvm-options.java-options}"
_JAVA_OPTIONS="$JAVA_OPTIONS"
VERSION_COMMAND="${action.setup-scala.version-command}"

sbt -batch -no-colors -v \
--java-home "$JAVA_HOME" \
"$VERSION_COMMAND compile" \
"$VERSION_COMMAND mimaReportBinaryIssues"
```

Expand Down
6 changes: 3 additions & 3 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package izumi.reflect.internal.bincompat

import izumi.reflect.macrortti.LightTypeTagRef.{AbstractReference, Lambda, SymName}

private[reflect] abstract class LambdaObjBincompat extends scala.runtime.AbstractFunction2[List[SymName.LambdaParamName], AbstractReference, Lambda] {
@deprecated("Lambda constructor is deprecated, use Lambda.make", "3.1.0")
override def apply(inputs: List[SymName.LambdaParamName], outputs: AbstractReference): Lambda = new Lambda(inputs, outputs)
}
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ class TagMacro(val c: blackbox.Context) {
val firstParamIdx = 0
val ctorLambdaParameter = SymName.LambdaParamName(firstParamIdx, LightTypeTagRef.LambdaConstants.tagMacro, arity)

val ctorApplyingLambda = LightTypeTagRef.Lambda(
val ctorApplyingLambda = LightTypeTagRef.Lambda.make(
ctorLambdaParameter :: usageOrderDistinctNonLambdaArgs ::: declarationOrderLambdaParamArgs,
FullReference(ctorLambdaParameter, usages)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ final class LightTypeTagImpl[U <: Universe with Singleton](val u: U, withCache:
case l: Lambda =>
l
case applied: AppliedReference =>
val l = Lambda(lambdaParamsUnpacked, applied)
val l = Lambda.make(lambdaParamsUnpacked, applied)
// Some(l).filter(_.allArgumentsReferenced) // do not include non-lambda parents such as Product into lambda's inheritance tree
// No, include ALL bases for lambdas (this should be more correct since lambda is a template for a full parameterized db after combine)
if (l.someArgumentsReferenced) l else applied
Expand Down Expand Up @@ -478,12 +478,12 @@ final class LightTypeTagImpl[U <: Universe with Singleton](val u: U, withCache:
val polyTypeResult = Dealias.fullNormDealiasSquashHKTToPolyTypeResultType(polyType)

val tparams = polyType.typeParams
val nestingLevel = if (level > 0) Some(level) else None
val lambdaParams = makeLambdaParams(nestingLevel, tparams)
assert(level >= 0)
val lambdaParams = makeLambdaParams(Some(level), tparams)

thisLevel.log(s"✴️ λ type $t has parameters $lambdaParams and result $polyTypeResult terminal names = $terminalNames")
val reference = makeRefSub(polyTypeResult, lambdaParams.toMap, Set.empty)
val out = Lambda(lambdaParams.map(_._2), reference)
val out = Lambda.make(lambdaParams.map(_._2), reference)
if (!out.allArgumentsReferenced) {
val kvParams = lambdaParams.map { case (k, v) => s"$v = $k" }
thisLevel.log(
Expand Down Expand Up @@ -597,7 +597,7 @@ final class LightTypeTagImpl[U <: Universe with Singleton](val u: U, withCache:
val out = tpe0 match {
case l if isLambdaOutput => // this is required for handling SwapF2, etc.
IzAssert(!isHKTOrPolyType(l), l -> l.getClass)
val out = Lambda(terminalNames.values.toList, unpackAsProperType(l, terminalNames))
val out = Lambda.make(terminalNames.values.toList, unpackAsProperType(l, terminalNames))
out

case l: PolyTypeApi =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ final class TagMacro(using override val qctx: Quotes) extends InspectorBase {
val ctorLambdaParameter = SymName.LambdaParamName(firstParamIdx, LightTypeTagRef.LambdaConstants.tagMacro, arity)

val ctorApplyingLambda =
LightTypeTagRef.Lambda(
LightTypeTagRef.Lambda.make(
ctorLambdaParameter :: completeTail,
FullReference(ctorLambdaParameter, usages)
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package izumi.reflect.dottyreflection

import izumi.reflect.internal.fundamentals.collections.IzCollections.toRich
import izumi.reflect.macrortti.LightTypeTagRef
import izumi.reflect.macrortti.{LightTypeTagRef, RuntimeAPI}
import izumi.reflect.macrortti.LightTypeTagRef.*

import scala.collection.immutable.Queue
Expand Down Expand Up @@ -42,9 +42,11 @@ abstract class FullDbInspector(protected val shift: Int) extends InspectorBase {
extractBase(appliedType, selfRef(), onlyIndirect = onlyIndirect) ++ extractLambdaBase(appliedType, onlyIndirect = onlyIndirect)

case typeLambda: TypeLambda =>
val resultTypeParents = new Run(inspector.nextLam(typeLambda), basesTermination, toLambdaTermination).inspectTypeBoundsToFull(typeLambda.resType)
val innerInspector = inspector.nextLam(typeLambda)
val rawParams = innerInspector.context.last.params.map(_.asParam)
val resultTypeParents = new Run(innerInspector, basesTermination, toLambdaTermination).inspectTypeBoundsToFull(typeLambda.resType)

makeLambdaParents(selfRef(), resultTypeParents)
makeLambdaParents(selfRef(), rawParams, resultTypeParents)

case a: AndType =>
inspectTypeReprToFullBases(a.left, onlyIndirect = false) ++ inspectTypeReprToFullBases(a.right, onlyIndirect = false)
Expand All @@ -55,9 +57,13 @@ abstract class FullDbInspector(protected val shift: Int) extends InspectorBase {
case typeRef: TypeRef =>
processSymbol(typeRef, selfRef(), onlyIndirect = onlyIndirect)

case _: ParamRef =>
// do not process type parameters for bases db
Nil
case p: ParamRef =>
// inspect bounds of type parameters to capture parent relationships
// for types referenced in lambda param boundaries (e.g. [A >: H4 <: H2])
p._underlying match {
case tb: TypeBounds => processTypeBounds(tb)
case _ => Nil
}

case termRef: TermRef =>
extractBase(termRef, selfRef(), onlyIndirect = onlyIndirect)
Expand Down Expand Up @@ -91,22 +97,39 @@ abstract class FullDbInspector(protected val shift: Int) extends InspectorBase {
case Some(typeLambda) =>
toLambdaTermination.addTerminatingClsSym(appliedType)

val resultTypeParents = new Run(inspector.nextLam(typeLambda), basesTermination, toLambdaTermination)
val innerInspector = inspector.nextLam(typeLambda)
val rawParams = innerInspector.context.last.params.map(_.asParam)
val resultTypeParents = new Run(innerInspector, basesTermination, toLambdaTermination)
.inspectTypeBoundsToFull(typeLambda.resType)

makeLambdaParents(inspector.inspectTypeRepr(typeLambda), resultTypeParents)
makeLambdaParents(inspector.inspectTypeRepr(typeLambda), rawParams, resultTypeParents)
}
}
}

private def makeLambdaParents(
selfRef: AbstractReference,
rawParams: List[SymName.LambdaParamName],
resultTypeParents: List[(AbstractReference, AbstractReference)]
): List[(AbstractReference, AbstractReference)] = {
val selfL = selfRef.asInstanceOf[Lambda]

// resultTypeParents use raw (non-normalized) param names from the Inspector context.
// selfL has been normalized by Lambda.make. We need to rewrite the raw param names
// in resultTypeParents to match selfL's normalized param names.
val paramMapping: Map[SymName.LambdaParamName, AbstractReference] =
rawParams.zip(selfL.input).collect {
case (raw, norm) if raw != norm => raw -> LightTypeTagRef.NameReference(norm)
}.toMap
val rewriter = new RuntimeAPI.Rewriter(paramMapping)
def normalizeEntry(ref: AbstractReference): AbstractReference =
if (paramMapping.isEmpty) ref else rewriter.replaceRefs(ref)

val out = resultTypeParents.flatMap {
case (child0, parent0) =>
case (child0raw, parent0raw) =>
val child0 = normalizeEntry(child0raw)
val parent0 = normalizeEntry(parent0raw)

val child = if (child0 == selfL.output) { // if child == typeLambda.resType, use typeLambda itself
selfL
} else {
Expand All @@ -118,7 +141,7 @@ abstract class FullDbInspector(protected val shift: Int) extends InspectorBase {
case l: Lambda =>
l
case applied: AppliedReference =>
val l = LightTypeTagRef.Lambda(selfL.input, applied)
val l = LightTypeTagRef.Lambda.make(selfL.input, applied)
if (l.someArgumentsReferenced) l else applied
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ abstract class Inspector(protected val shift: Int, val context: Queue[Inspector.
val inspector = nextLam(l)
val resType = inspector.inspectTypeRepr(l.resType)
val paramNames = inspector.context.last.params.map(_.asParam)
LightTypeTagRef.Lambda(paramNames, resType)
LightTypeTagRef.Lambda.make(paramNames, resType)

case t: ThisType =>
next().inspectTypeRepr(t.tref)
Expand Down Expand Up @@ -238,21 +238,33 @@ abstract class Inspector(protected val shift: Int, val context: Queue[Inspector.
// Upper boundaries we'll recover later in fulldb and inheritancedb
// But lower boundaries we don't recover
log(s"invertTypeMemberWithTypeLambdaBounds: found symName=$symName, input=$input")
LightTypeTagRef.Lambda(input, FullReference(symName, input.map(p => TypeParam(NameReference(p), Variance.Invariant)), prefix))
LightTypeTagRef.Lambda.make(input, FullReference(symName, input.map(p => TypeParam(NameReference(p), Variance.Invariant)), prefix))
case other =>
other
}

private def inspectBoundsImpl(tb: TypeBounds): Boundaries = {
val hi = next().inspectTypeRepr(tb.hi)
val low = next().inspectTypeRepr(tb.low)
if (hi == LightTypeTagInheritance.tpeAny && low == LightTypeTagInheritance.tpeNothing) {
if (isTrivialLowerBound(low) && isTrivialUpperBound(hi)) {
Boundaries.Empty
} else {
Boundaries.Defined(low, hi)
}
}

private def isTrivialLowerBound(ref: AbstractReference): Boolean = ref match {
case n: NameReference => n == LightTypeTagInheritance.tpeNothing
case LightTypeTagRef.Lambda(_, output) => isTrivialLowerBound(output)
case _ => false
}

private def isTrivialUpperBound(ref: AbstractReference): Boolean = ref match {
case n: NameReference => n == LightTypeTagInheritance.tpeAny
case LightTypeTagRef.Lambda(_, output) => isTrivialUpperBound(output)
case _ => false
}

private[dottyreflection] def inspectSymbol(symbol: Symbol, outerTypeRef: Option[TypeRef], prefixSource: Option[NamedType]): AbstractReference = {
symbol match {
case s if s.isClassDef || s.isValDef || s.isBind =>
Expand Down Expand Up @@ -342,7 +354,11 @@ abstract class Inspector(protected val shift: Int, val context: Queue[Inspector.
assert(contextParam.name == paramName, s"$contextParam should match $paramName")
}

NameReference(contextParam.asParam, Boundaries.Empty, None)
val boundaries = t._underlying match {
case tb: TypeBounds => inspectBoundsImpl(tb)
case _ => Boundaries.Empty
}
NameReference(contextParam.asParam, boundaries, None)

} else {
val lt = t.binder.asInstanceOf[LambdaType]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package izumi.reflect.internal.bincompat

import izumi.reflect.macrortti.LightTypeTagRef.{AbstractReference, Lambda, SymName}

private[reflect] trait LambdaObjBincompat {
@deprecated("bincompat only", "3.1.0")
private[internal] def apply(inputs: List[SymName.LambdaParamName], outputs: AbstractReference): Lambda = new Lambda(inputs, outputs)
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ private[macrortti] trait LTTOrdering {
// Mirror Lambda#equals
val compare1 = Ordering.Int.compare(lx.input.size, ly.input.size)
if (compare1 != 0) return compare1
OrderingAbstractReference.compare(lx.normalizedOutput, ly.normalizedOutput)
OrderingAbstractReference.compare(lx.output, ly.output)

case (IntersectionReference(refsx), IntersectionReference(refsy)) =>
OrderingArrayAbstractReference.compare(refSetToSortedArray(refsx), refSetToSortedArray(refsy))
Expand Down
Loading