Skip to content

Commit 4fb1fd4

Browse files
authored
Merge pull request #443 from sjrd/scala-3.5
Upgrade to Scala 3.5.0 and support its TASTy format.
2 parents 59811cb + 9c02c87 commit 4fb1fd4

File tree

18 files changed

+359
-37
lines changed

18 files changed

+359
-37
lines changed

build.sbt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import sbt.internal.util.ManagedLogger
33

44
import org.scalajs.jsenv.nodejs.NodeJSEnv
55

6-
val usedScalaCompiler = "3.4.0"
6+
val usedScalaCompiler = "3.5.0"
77
val usedTastyRelease = usedScalaCompiler
88
val scala2Version = "2.13.14"
99

@@ -52,7 +52,7 @@ val strictCompileSettings = Seq(
5252
scalacOptions ++= Seq(
5353
"-Xfatal-warnings",
5454
"-Yexplicit-nulls",
55-
"-Ysafe-init",
55+
"-Wsafe-init",
5656
"-source:future",
5757
),
5858
)
@@ -129,7 +129,8 @@ lazy val tastyQuery =
129129
)
130130
},
131131

132-
tastyMiMaPreviousArtifacts := mimaPreviousArtifacts.value,
132+
// Temporarily disabled until we have a published version of tasty-query that can handle 3.4.x.
133+
//tastyMiMaPreviousArtifacts := mimaPreviousArtifacts.value,
133134
tastyMiMaConfig ~= { prev =>
134135
import tastymima.intf._
135136
prev

tasty-query/shared/src/main/scala/tastyquery/Definitions.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ final class Definitions private[tastyquery] (
4343
scalaPackage.getPackageDeclOrCreate(termName("compiletime"))
4444
private val scalaCollectionImmutablePackage =
4545
scalaCollectionPackage.getPackageDeclOrCreate(termName("immutable"))
46+
private val scalaQuotedPackage =
47+
scalaPackage.getPackageDeclOrCreate(termName("quoted"))
4648
private val scalaRuntimePackage =
4749
scalaPackage.getPackageDeclOrCreate(termName("runtime"))
4850

@@ -439,6 +441,8 @@ final class Definitions private[tastyquery] (
439441
lazy val SeqClass = scalaCollectionImmutablePackage.requiredClass("Seq")
440442
lazy val Function0Class = scalaPackage.requiredClass("Function0")
441443

444+
private[tastyquery] lazy val ContextFunction1Class = scalaPackage.requiredClass("ContextFunction1")
445+
442446
def FunctionNClass(n: Int): ClassSymbol =
443447
withRestrictedContext(scalaPackage.findDecl(typeName(s"Function$n")).asClass)
444448

@@ -482,6 +486,9 @@ final class Definitions private[tastyquery] (
482486

483487
private[tastyquery] lazy val PolyFunctionClass = scalaPackage.optionalClass("PolyFunction")
484488

489+
private[tastyquery] lazy val QuotedExprClass = scalaQuotedPackage.requiredClass("Expr")
490+
private[tastyquery] lazy val QuotesClass = scalaQuotedPackage.requiredClass("Quotes")
491+
485492
private[tastyquery] def isPolyFunctionSub(tpe: Type)(using Context): Boolean =
486493
PolyFunctionClass.exists(cls => tpe.baseType(cls).isDefined)
487494

tasty-query/shared/src/main/scala/tastyquery/Erasure.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ private[tastyquery] object Erasure:
111111
preErase(tpe.parent, keepUnit)
112112
case tpe: RecType =>
113113
preErase(tpe.parent, keepUnit)
114+
case tpe: FlexibleType =>
115+
preErase(tpe.nonNullableType, keepUnit)
114116
case _: ByNameType =>
115117
defn.Function0Class.erasure
116118
case tpe: RepeatedType =>

tasty-query/shared/src/main/scala/tastyquery/Printers.scala

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ private[tastyquery] object Printers:
7777
print("[")
7878
printCommaSeparatedList(tpe.args)(print(_))
7979
print("]")
80+
case tpe: FlexibleType =>
81+
print(tpe.nonNullableType)
82+
print("?")
8083
case tpe: ByNameType =>
8184
print("=> ")
8285
print(tpe.resultType)
@@ -445,6 +448,32 @@ private[tastyquery] object Printers:
445448
print(c)
446449
print(">")
447450
printBlock(bindings, expr)(print(_))
451+
452+
case Quote(body, bodyType) =>
453+
print("'[")
454+
print(bodyType)
455+
print("]")
456+
printBlock(Nil, body)(print(_))
457+
458+
case Splice(expr, spliceType) =>
459+
print("$[")
460+
print(spliceType)
461+
print("]")
462+
printBlock(Nil, expr)(print(_))
463+
464+
case SplicePattern(pattern, targs, args, spliceType) =>
465+
print("$[")
466+
print(spliceType)
467+
print("]")
468+
print(pattern)
469+
if targs.nonEmpty then
470+
print("[")
471+
printCommaSeparatedList(targs)(print(_))
472+
print("]")
473+
if args.nonEmpty then
474+
print("(")
475+
printCommaSeparatedList(args)(print(_))
476+
print(")")
448477
end print
449478

450479
def print(caze: CaseDef): Unit =
@@ -577,6 +606,26 @@ private[tastyquery] object Printers:
577606

578607
case ExprPattern(expr) =>
579608
print(expr)
609+
610+
case QuotePattern(bindings, body, quotes, patternType) =>
611+
print("'<")
612+
print(quotes)
613+
print(">")
614+
body match
615+
case Left(termBody) =>
616+
print("{ ")
617+
for binding <- bindings do
618+
print(binding)
619+
print("; ")
620+
print(termBody)
621+
print(" }")
622+
case Right(typeBody) =>
623+
print("[ ")
624+
for binding <- bindings do
625+
print(binding)
626+
print("; ")
627+
print(typeBody)
628+
print(" ]")
580629
end print
581630

582631
def print(tree: TypeTree): Unit = tree match

tasty-query/shared/src/main/scala/tastyquery/Subtyping.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,9 @@ private[tastyquery] object Subtyping:
238238
isSubType(tp1, tp2.first) || isSubType(tp1, tp2.second)
239239
|| level4(tp1, tp2)
240240

241+
case tp2: FlexibleType =>
242+
isSubType(tp1, tp2.nullableType)
243+
241244
case tp2: ByNameType =>
242245
tp1 match
243246
case tp1: ByNameType => isSubType(tp1.resultType, tp2.resultType)
@@ -478,6 +481,9 @@ private[tastyquery] object Subtyping:
478481
case tp1: RecType =>
479482
isSubType(tp1.parent, tp2)
480483

484+
case tp1: FlexibleType =>
485+
isSubType(tp1.nonNullableType, tp2)
486+
481487
case tp1: AndType =>
482488
// TODO Try and simplify first
483489
isSubType(tp1.first, tp2) || isSubType(tp1.second, tp2)

tasty-query/shared/src/main/scala/tastyquery/Traversers.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,14 @@ object Traversers:
120120
traverse(expr)
121121
traverse(caller)
122122
traverse(bindings)
123+
case Quote(body, bodyType) =>
124+
traverse(body)
125+
case Splice(expr, spliceType) =>
126+
traverse(expr)
127+
case SplicePattern(pattern, targs, args, spliceType) =>
128+
traverse(pattern)
129+
traverse(targs)
130+
traverse(args)
123131
case _: ImportIdent | _: Ident | _: This | _: Literal =>
124132
()
125133

@@ -139,6 +147,10 @@ object Traversers:
139147
traverse(expr)
140148
case WildcardPattern(tpe) =>
141149
()
150+
case QuotePattern(bindings, body, quotes, patternType) =>
151+
traverse(bindings)
152+
body.fold(traverse(_), traverse(_))
153+
traverse(quotes)
142154

143155
// TypeTree-ish
144156
case TypeIdent(tpe) =>

tasty-query/shared/src/main/scala/tastyquery/Trees.scala

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,33 @@ object Trees {
638638
override final def withPos(pos: SourcePosition): ExprPattern = ExprPattern(expr)(pos)
639639
end ExprPattern
640640

641+
/** A tree representing a quote pattern `'{ type binding1; ...; body }` or `'[ type binding1; ...; body ]`.
642+
*
643+
* The `bindings` contain the list of quote pattern type variable definitions (`TypeTreeBind`s)
644+
* in the order in which they are defined in the source.
645+
*
646+
* @param bindings
647+
* Type variable definitions
648+
* @param body
649+
* Quoted pattern (without type variable definitions):
650+
* `Left(termTree)` for a term quote pattern `'{ ... }` or
651+
* `Right(typeTree)` for a type quote pattern `'[ ... ]`
652+
* @param quotes
653+
* A reference to the given `Quotes` instance in scope
654+
* @param patternType
655+
* The type of the pattern
656+
*/
657+
final case class QuotePattern(
658+
bindings: List[TypeTreeBind],
659+
body: Either[TermTree, TypeTree],
660+
quotes: TermTree,
661+
patternType: Type
662+
)(pos: SourcePosition)
663+
extends PatternTree(pos) {
664+
override def withPos(pos: SourcePosition): QuotePattern =
665+
QuotePattern(bindings, body, quotes, patternType)(pos)
666+
}
667+
641668
/** Seq(elems)
642669
* @param tpt The element type of the sequence.
643670
*/
@@ -717,6 +744,65 @@ object Trees {
717744
override final def withPos(pos: SourcePosition): Inlined = Inlined(expr, caller, bindings)(pos)
718745
}
719746

747+
/** A tree representing a quote `'{ body }`.
748+
*
749+
* @param body
750+
* The tree that was quoted
751+
* @param bodyType
752+
* Explicit type of quoted body, which is the source of truth from which we build the type of the quote
753+
*/
754+
final case class Quote(body: TermTree, bodyType: Type)(pos: SourcePosition) extends TermTree(pos) {
755+
protected final def calculateType(using Context): TermType =
756+
// `Quotes ?=> Expr[bodyType]`
757+
defn.ContextFunction1Class.staticRef.appliedTo(
758+
List(defn.QuotesClass.staticRef, defn.QuotedExprClass.staticRef.appliedTo(bodyType))
759+
)
760+
end calculateType
761+
762+
override final def withPos(pos: SourcePosition): Quote =
763+
Quote(body, bodyType)(pos)
764+
}
765+
766+
/** A tree representing a splice `${ expr }`.
767+
*
768+
* @param expr
769+
* The tree that was spliced
770+
*/
771+
final case class Splice(expr: TermTree, spliceType: Type)(pos: SourcePosition) extends TermTree(pos) {
772+
protected final def calculateType(using Context): TermType =
773+
spliceType
774+
775+
override final def withPos(pos: SourcePosition): Splice =
776+
Splice(expr, spliceType)(pos)
777+
}
778+
779+
/** A tree representing a pattern splice `${ pattern }`, `$ident` or `$ident(args*)` in a quote pattern.
780+
*
781+
* Parser will only create `${ pattern }` and `$ident`, hence they will not have args.
782+
* While typing, the `$ident(args*)` the args are identified and desugared into a `SplicePattern`
783+
* containing them.
784+
*
785+
* `SplicePattern` can only be contained within a `QuotePattern`.
786+
*
787+
* @param pattern
788+
* The pattern that was spliced
789+
* @param targs
790+
* The type arguments of the splice (the HOAS arguments)
791+
* @param args
792+
* The arguments of the splice (the HOAS arguments)
793+
* @param spliceType
794+
* The type of the splice, i.e., of this tree
795+
*/
796+
final case class SplicePattern(pattern: PatternTree, targs: List[TypeTree], args: List[TermTree], spliceType: Type)(
797+
pos: SourcePosition
798+
) extends TermTree(pos) {
799+
protected final def calculateType(using Context): TermType =
800+
spliceType
801+
802+
override final def withPos(pos: SourcePosition): SplicePattern =
803+
SplicePattern(pattern, targs, args, spliceType)(pos)
804+
}
805+
720806
// --- TypeTrees ------------------------------------------------------------
721807

722808
sealed abstract class TypeArgTree(pos: SourcePosition) extends Tree(pos):

tasty-query/shared/src/main/scala/tastyquery/TypeMaps.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ private[tastyquery] object TypeMaps {
5353
tp.derivedAnnotatedType(underlying, annot)
5454
protected def derivedMatchType(tp: MatchType, bound: Type, scrutinee: Type, cases: List[MatchTypeCase]): Type =
5555
tp.derivedMatchType(bound, scrutinee, cases)
56+
protected def derivedFlexibleType(tp: FlexibleType, nonNullableType: Type): Type =
57+
tp.derivedFlexibleType(nonNullableType)
5658
protected def derivedByNameType(tp: ByNameType, restpe: Type): Type =
5759
tp.derivedByNameType(restpe)
5860
protected def derivedRepeatedType(tp: RepeatedType, elemType: Type): Type =
@@ -123,6 +125,9 @@ private[tastyquery] object TypeMaps {
123125
case tp: TypeLambda =>
124126
mapOverLambda(tp)
125127

128+
case tp: FlexibleType =>
129+
derivedFlexibleType(tp, this(tp.nonNullableType))
130+
126131
case tp: ByNameType =>
127132
derivedByNameType(tp, this(tp.resultType))
128133

tasty-query/shared/src/main/scala/tastyquery/TypeOps.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ private[tastyquery] object TypeOps:
114114
apply(z, tp.thistpe)
115115
case tp: AppliedType =>
116116
tp.args.foldLeft(apply(z, tp.tycon))(this)
117+
case tp: FlexibleType =>
118+
apply(z, tp.nonNullableType)
117119
case tp: ByNameType =>
118120
apply(z, tp.resultType)
119121
case tp: RepeatedType =>

tasty-query/shared/src/main/scala/tastyquery/Types.scala

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ import tastyquery.Utils.*
5858
* +- AppliedType `C[T1, ..., Tn]`
5959
* +- ByNameType type of a by-name parameter `=> T`
6060
* +- ThisType `C.this`
61+
* +- FlexibleType `U?`
6162
* +- OrType `A | B`
6263
* +- AndType `A & B`
6364
* +- TypeLambda `[T1, ..., Tn] => R`
@@ -579,7 +580,8 @@ object Types {
579580
self.superType.typeParams
580581
case self: AnnotatedType =>
581582
self.superType.typeParams
582-
case _: SingletonType | _: RefinedType | _: ByNameType | _: RepeatedType | _: MatchType | _: RecType =>
583+
case _: SingletonType | _: RefinedType | _: FlexibleType | _: ByNameType | _: RepeatedType | _: MatchType |
584+
_: RecType =>
583585
// These types are always proper types
584586
Nil
585587
case _: NothingType | _: AnyKindType =>
@@ -1533,6 +1535,22 @@ object Types {
15331535
override def toString(): String = s"AppliedType($tycon, $args)"
15341536
}
15351537

1538+
/** A flexible type `T?`, with `T | Null <: T? <: T`. */
1539+
final class FlexibleType(val nonNullableType: Type) extends TypeProxy {
1540+
private val myNullableType: Memo[Type] = uninitializedMemo
1541+
1542+
final def nullableType(using Context): Type = memoized(myNullableType) {
1543+
OrType(nonNullableType, defn.NullType)
1544+
}
1545+
1546+
override def underlying(using Context): Type = nonNullableType
1547+
1548+
private[tastyquery] final def derivedFlexibleType(nonNullableType: Type): FlexibleType =
1549+
if nonNullableType eq this.nonNullableType then this else FlexibleType(nonNullableType)
1550+
1551+
override def toString(): String = s"FlexibleType($nonNullableType)"
1552+
}
1553+
15361554
/** A by-name parameter type of the form `=> T`. */
15371555
final class ByNameType(val resultType: Type) extends TypeProxy {
15381556
override def underlying(using Context): Type = resultType

0 commit comments

Comments
 (0)