Skip to content

Commit 7781469

Browse files
committed
Merge branch 'v1.32.x'
2 parents 5c63bda + 6cf549d commit 7781469

File tree

12 files changed

+128
-71
lines changed

12 files changed

+128
-71
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
target
1010
out
11+
.bloop
1112

1213
*.sjsir
1314
*.class

build.sbt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ lazy val commons = project.in(file("."))
149149
commonSettings,
150150
noPublishSettings,
151151
name := "commons",
152+
ideExcludedDirectories := Seq(baseDirectory.value / ".bloop"),
152153
scalacOptions in ScalaUnidoc in unidoc += "-Ymacro-expand:none",
153154
unidocProjectFilter in ScalaUnidoc in unidoc :=
154155
inAnyProject -- inProjects(

commons-core/src/main/scala/com/avsystem/commons/rest/openapi/WhenAbsentInfo.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ case class WhenAbsentInfo[T](
1111
@infer("for @whenAbsent value: ") asJson: AsRaw[JsonValue, T]
1212
) extends TypedMetadata[T] {
1313
val fallbackValue: Opt[JsonValue] =
14-
Try(annot.value).toOpt.map(asJson.asRaw)
14+
Try(annot.value).fold(_ => Opt.Empty, v => asJson.asRaw(v).opt)
1515
}

commons-core/src/test/scala/com/avsystem/commons/rest/openapi/RestSchemaTest.scala

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class RestSchemaTest extends FunSuite {
2121

2222
@description("kejs klass")
2323
case class KejsKlass(
24-
@name("integer") int: Int,
24+
@name("integer") @customWa(42) int: Int,
2525
@description("serious dependency") dep: Dependency,
2626
@description("serious string") str: Opt[String] = Opt.Empty
2727
)
@@ -35,7 +35,8 @@ class RestSchemaTest extends FunSuite {
3535
| "properties": {
3636
| "integer": {
3737
| "type": "integer",
38-
| "format": "int32"
38+
| "format": "int32",
39+
| "default": 42
3940
| },
4041
| "dep": {
4142
| "description": "serious dependency",
@@ -53,7 +54,6 @@ class RestSchemaTest extends FunSuite {
5354
| }
5455
| },
5556
| "required": [
56-
| "integer",
5757
| "dep"
5858
| ]
5959
|}""".stripMargin)
@@ -70,4 +70,23 @@ class RestSchemaTest extends FunSuite {
7070
| "description": "wrapped string"
7171
|}""".stripMargin)
7272
}
73+
74+
case class GenCC[+T >: Null](@customWa[T](null) value: T)
75+
object GenCC extends RestDataCompanion[GenCC[String]]
76+
77+
test("generic case class") {
78+
println(GenCC.restStructure.asInstanceOf[RestStructure.Record[_]].fields.head.fallbackValue)
79+
80+
assert(schemaStr[GenCC[String]] ==
81+
"""{
82+
| "type": "object",
83+
| "properties": {
84+
| "value": {
85+
| "type": "string",
86+
| "default": null
87+
| }
88+
| }
89+
|}""".stripMargin
90+
)
91+
}
7392
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.avsystem.commons
2+
package rest.openapi
3+
4+
import com.avsystem.commons.annotation.AnnotationAggregate
5+
import com.avsystem.commons.serialization.whenAbsent
6+
7+
class customWa[+T](value: => T) extends AnnotationAggregate {
8+
@whenAbsent(value) type Implied
9+
}

commons-macros/src/main/scala/com/avsystem/commons/macros/MacroCommons.scala

Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,24 @@ trait MacroCommons { bundle =>
107107
def indent(str: String, indent: String): String =
108108
str.replaceAllLiterally("\n", s"\n$indent")
109109

110+
private def annotations(s: Symbol): List[Annotation] = {
111+
s.info // srsly scalac, load these goddamned annotations
112+
s.annotations
113+
}
114+
115+
def treeAsSeenFrom(tree: Tree, seenFrom: Type): Tree = seenFrom match {
116+
case NoType => tree
117+
case TypeRef(_, sym, Nil) if sym.isStatic => tree
118+
case _ =>
119+
val res = tree.duplicate
120+
res.foreach { t =>
121+
if (t.tpe != null) {
122+
internal.setType(t, t.tpe.asSeenFrom(seenFrom, seenFrom.typeSymbol))
123+
}
124+
}
125+
res
126+
}
127+
110128
class Annot(annotTree: Tree, val subject: Symbol, val directSource: Symbol, val aggregate: Option[Annot]) {
111129
def aggregationChain: List[Annot] =
112130
aggregate.fold(List.empty[Annot])(a => a :: a.aggregationChain)
@@ -137,7 +155,17 @@ trait MacroCommons { bundle =>
137155
case _ => annotTree
138156
}
139157

140-
def tpe: Type = annotTree.tpe
158+
def tpe: Type =
159+
annotTree.tpe
160+
161+
def symbol: ClassSymbol =
162+
tpe.typeSymbol.asClass
163+
164+
lazy val argsByName: Map[Name, Tree] = {
165+
val Apply(_, args) = tree
166+
val paramNames = primaryConstructorOf(tpe).typeSignature.paramLists.head.map(_.name)
167+
(paramNames zip args).toMap
168+
}
141169

142170
def findArg[T: ClassTag](valSym: Symbol): T =
143171
findArg[T](valSym, abort(s"(bug) no default value for ${tree.tpe} parameter ${valSym.name} provided by macro"))
@@ -157,20 +185,28 @@ trait MacroCommons { bundle =>
157185
case t if param.asTerm.isParamWithDefault && t.symbol.isSynthetic &&
158186
t.symbol.name.decodedName.toString.contains("$default$") => whenDefault
159187
case t if classTag[T] == classTag[Tree] => t.asInstanceOf[T]
160-
case _ =>
161-
abort(s"Expected literal ${classTag[T].runtimeClass} as ${valSym.name} parameter of $clsTpe annotation")
188+
case _ => abort(s"Expected literal ${classTag[T].runtimeClass.getSimpleName} " +
189+
s"as ${valSym.name} parameter of $clsTpe annotation")
162190
}
163191
}
164192
.getOrElse(abort(s"Could not find argument corresponding to constructor parameter ${subSym.name}"))
165193
case _ => abort(s"Not a primary constructor call tree: $tree")
166194
}
167195

196+
private object argsInliner extends Transformer {
197+
override def transform(tree: Tree): Tree = tree match {
198+
case Select(th@This(_), name) if th.symbol == symbol && tree.symbol.asTerm.isParamAccessor =>
199+
argsByName.get(name).map(_.duplicate).getOrElse(tree)
200+
case _ => super.transform(tree)
201+
}
202+
}
203+
168204
lazy val aggregated: List[Annot] = {
169205
if (tpe <:< AnnotationAggregateType) {
170-
val argsInliner = new AnnotationArgInliner(tree)
171206
val impliedMember = tpe.member(TypeName("Implied"))
172-
impliedMember.annotations.map(a =>
173-
new Annot(argsInliner.transform(a.tree), subject, impliedMember, Some(this)))
207+
annotations(impliedMember).map { a =>
208+
new Annot(argsInliner.transform(treeAsSeenFrom(a.tree, tpe)), subject, impliedMember, Some(this))
209+
}
174210
} else Nil
175211
}
176212

@@ -184,21 +220,6 @@ trait MacroCommons { bundle =>
184220
}
185221
}
186222

187-
class AnnotationArgInliner(baseAnnot: Tree) extends Transformer {
188-
private val argsByName: Map[Name, Tree] = {
189-
val Apply(_, args) = baseAnnot
190-
val paramNames = primaryConstructorOf(baseAnnot.tpe).typeSignature.paramLists.head.map(_.name)
191-
(paramNames zip args).toMap
192-
}
193-
194-
override def transform(tree: Tree): Tree = tree match {
195-
case Select(th@This(_), name) if th.symbol == baseAnnot.tpe.typeSymbol
196-
&& tree.symbol.asTerm.isParamAccessor =>
197-
argsByName.get(name).map(_.duplicate).getOrElse(tree)
198-
case _ => super.transform(tree)
199-
}
200-
}
201-
202223
private def orConstructorParam(applyParam: Symbol): Symbol = {
203224
val owner = applyParam.owner
204225
if (owner.name == TermName("apply") && owner.isSynthetic)
@@ -210,19 +231,24 @@ trait MacroCommons { bundle =>
210231
private def maybeWithSuperSymbols(s: Symbol, withSupers: Boolean): Iterator[Symbol] =
211232
if (withSupers) withSuperSymbols(s) else Iterator(s)
212233

213-
def allAnnotations(s: Symbol, tpeFilter: Type, withInherited: Boolean = true, fallback: List[Tree] = Nil): List[Annot] = {
234+
def allAnnotations(s: Symbol, tpeFilter: Type,
235+
seenFrom: Type = NoType, withInherited: Boolean = true, fallback: List[Tree] = Nil): List[Annot] = {
236+
214237
val initSym = orConstructorParam(s)
215238
def inherited(annot: Annotation, superSym: Symbol): Boolean =
216239
!(superSym != initSym && isSealedHierarchyRoot(superSym) && annot.tree.tpe <:< NotInheritedFromSealedTypes)
217240

218241
val nonFallback = maybeWithSuperSymbols(initSym, withInherited)
219-
.flatMap(ss => ss.annotations.filter(inherited(_, ss)).map(a => new Annot(a.tree, s, ss, None)))
242+
.flatMap(ss => annotations(ss).filter(inherited(_, ss))
243+
.map(a => new Annot(treeAsSeenFrom(a.tree, seenFrom), s, ss, None)))
220244

221245
(nonFallback ++ fallback.iterator.map(t => new Annot(t, s, s, None)))
222246
.flatMap(_.withAllAggregated).filter(_.tpe <:< tpeFilter).toList
223247
}
224248

225-
def findAnnotation(s: Symbol, tpe: Type, withInherited: Boolean = true, fallback: List[Tree] = Nil): Option[Annot] = {
249+
def findAnnotation(s: Symbol, tpe: Type,
250+
seenFrom: Type = NoType, withInherited: Boolean = true, fallback: List[Tree] = Nil): Option[Annot] = {
251+
226252
val initSym = orConstructorParam(s)
227253
def find(annots: List[Annot]): Option[Annot] = annots match {
228254
case head :: tail =>
@@ -245,7 +271,8 @@ trait MacroCommons { bundle =>
245271
!(superSym != initSym && isSealedHierarchyRoot(superSym) && annot.tree.tpe <:< NotInheritedFromSealedTypes)
246272

247273
maybeWithSuperSymbols(initSym, withInherited)
248-
.map(ss => find(ss.annotations.filter(inherited(_, ss)).map(a => new Annot(a.tree, s, ss, None))))
274+
.map(ss => find(annotations(ss).filter(inherited(_, ss))
275+
.map(a => new Annot(treeAsSeenFrom(a.tree, seenFrom), s, ss, None))))
249276
.collectFirst { case Some(annot) => annot }
250277
.orElse(find(fallback.map(t => new Annot(t, s, s, None))))
251278
}
@@ -393,7 +420,7 @@ trait MacroCommons { bundle =>
393420
symbolImplicitNotFoundMsg(tpe, tpe.typeSymbol, tpe.typeSymbol.typeSignature.typeParams, tpe.typeArgs)
394421

395422
private def symbolImplicitNotFoundMsg(tpe: Type, sym: Symbol, tparams: List[Symbol], typeArgs: List[Type]): String =
396-
sym.annotations.find(_.tree.tpe <:< ImplicitNotFoundAT)
423+
annotations(sym).find(_.tree.tpe <:< ImplicitNotFoundAT)
397424
.map(_.tree.children.tail.head).collect { case StringLiteral(error) => error }
398425
.map { error =>
399426
val tpNames = tparams.map(_.name.decodedName.toString)
@@ -759,19 +786,19 @@ trait MacroCommons { bundle =>
759786
def paramSymbolToValDef(sym: Symbol): ValDef = {
760787
val ts = sym.asTerm
761788
val implicitFlag = if (sym.isImplicit) Flag.IMPLICIT else NoFlags
762-
val mods = Modifiers(Flag.PARAM | implicitFlag, typeNames.EMPTY, ts.annotations.map(_.tree))
789+
val mods = Modifiers(Flag.PARAM | implicitFlag, typeNames.EMPTY, annotations(ts).map(_.tree))
763790
ValDef(mods, ts.name, treeForType(sym.typeSignature), EmptyTree)
764791
}
765792

766793
def getterSymbolToValDef(sym: Symbol): ValDef = {
767794
val ms = sym.asMethod
768795
val mutableFlag = if (ms.isVar) Flag.MUTABLE else NoFlags
769-
val mods = Modifiers(Flag.DEFERRED | mutableFlag, typeNames.EMPTY, ms.annotations.map(_.tree))
796+
val mods = Modifiers(Flag.DEFERRED | mutableFlag, typeNames.EMPTY, annotations(ms).map(_.tree))
770797
ValDef(mods, ms.name, treeForType(sym.typeSignature), EmptyTree)
771798
}
772799

773800
def existentialSingletonToValDef(sym: Symbol, name: TermName, tpe: Type): ValDef = {
774-
val mods = Modifiers(Flag.DEFERRED, typeNames.EMPTY, sym.annotations.map(_.tree))
801+
val mods = Modifiers(Flag.DEFERRED, typeNames.EMPTY, annotations(sym).map(_.tree))
775802
ValDef(mods, name, treeForType(tpe), EmptyTree)
776803
}
777804

@@ -790,7 +817,7 @@ trait MacroCommons { bundle =>
790817
else NoFlags
791818

792819
val flags = paramOrDeferredFlag | syntheticFlag | varianceFlag
793-
val mods = Modifiers(flags, typeNames.EMPTY, ts.annotations.map(_.tree))
820+
val mods = Modifiers(flags, typeNames.EMPTY, annotations(ts).map(_.tree))
794821
val (typeParams, signature) = sym.typeSignature match {
795822
case PolyType(polyParams, resultType) => (polyParams, resultType)
796823
case sig => (ts.typeParams, sig)
@@ -1024,7 +1051,7 @@ trait MacroCommons { bundle =>
10241051
def positionPoint(sym: Symbol): Int =
10251052
if (c.enclosingPosition.source == sym.pos.source) sym.pos.point
10261053
else positionCache.getOrElseUpdate(sym,
1027-
sym.annotations.find(_.tree.tpe <:< PositionedAT).map(_.tree).map {
1054+
annotations(sym).find(_.tree.tpe <:< PositionedAT).map(_.tree).map {
10281055
case Apply(_, List(MaybeTyped(Lit(point: Int), _))) => point
10291056
case t => abort(s"expected literal int as argument of @positioned annotation on $sym, got $t")
10301057
} getOrElse {

commons-macros/src/main/scala/com/avsystem/commons/macros/meta/AdtMetadataMacros.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class AdtMetadataMacros(ctx: blackbox.Context) extends AbstractMacroCommons(ctx)
1717

1818
sealed trait AdtSymbol extends MacroSymbol with SelfMatchedSymbol {
1919
def tpe: Type
20+
def seenFrom: Type = tpe
2021
lazy val symbol: Symbol = tpe.dealias.typeSymbol
2122

2223
def cases: List[AdtSymbol]
@@ -66,14 +67,13 @@ class AdtMetadataMacros(ctx: blackbox.Context) extends AbstractMacroCommons(ctx)
6667
}
6768

6869
class AdtParam(val owner: AdtClass, val symbol: Symbol, val index: Int) extends MacroParam {
70+
def seenFrom: Type = owner.tpe
6971
def shortDescription: String = "ADT parameter"
7072
def description: String = s"$shortDescription $nameStr of ${owner.description}"
7173
}
7274

7375
case class MatchedAdtParam(param: AdtParam, mdParam: AdtParamMetadataParam, indexInRaw: Int) extends MatchedSymbol {
7476
def real: MacroSymbol = param
75-
def annot(tpe: Type): Option[Annot] = findAnnotation(real.symbol, tpe)
76-
def allAnnots(tpe: Type): List[Annot] = allAnnotations(real.symbol, tpe)
7777
def rawName: String = param.nameStr
7878
}
7979

commons-macros/src/main/scala/com/avsystem/commons/macros/meta/MacroMetadatas.scala

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ trait MacroMetadatas extends MacroSymbols {
5353
}
5454

5555
abstract class MetadataParam(val owner: MetadataConstructor, val symbol: Symbol) extends MacroParam {
56+
def seenFrom: Type = owner.ownerType
5657
def shortDescription = "metadata parameter"
5758
def description = s"$shortDescription $nameStr of ${owner.description}"
5859
def pathStr: String = owner.atParam.fold(nameStr)(cp => s"${cp.pathStr}.$nameStr")
@@ -91,27 +92,26 @@ trait MacroMetadatas extends MacroSymbols {
9192
def shortDescription = "metadata class"
9293
def description = s"$shortDescription $ownerType"
9394

94-
def paramByStrategy(paramSym: Symbol, annot: Annot): MetadataParam =
95-
annot.tpe.asSeenFrom(ownerType, ownerType.typeSymbol) match {
96-
case t if t <:< InferAT =>
97-
val clue = annot.findArg[String](InferAT.member(TermName("clue")), "")
98-
new ImplicitParam(this, paramSym, clue)
99-
case t if t <:< ReifyAnnotAT => new ReifiedAnnotParam(this, paramSym)
100-
case t if t <:< ReifyNameAT =>
101-
val useRawName = annot.findArg[Boolean](ReifyNameAT.member(TermName("useRawName")), false)
102-
new ReifiedNameParam(this, paramSym, useRawName)
103-
case t if t <:< IsAnnotatedAT =>
104-
new IsAnnotatedParam(this, paramSym, t.typeArgs.head)
105-
case t => reportProblem(s"metadata param strategy $t is not allowed here")
106-
}
95+
def paramByStrategy(paramSym: Symbol, annot: Annot): MetadataParam = annot.tpe match {
96+
case t if t <:< InferAT =>
97+
val clue = annot.findArg[String](InferAT.member(TermName("clue")), "")
98+
new ImplicitParam(this, paramSym, clue)
99+
case t if t <:< ReifyAnnotAT => new ReifiedAnnotParam(this, paramSym)
100+
case t if t <:< ReifyNameAT =>
101+
val useRawName = annot.findArg[Boolean](ReifyNameAT.member(TermName("useRawName")), false)
102+
new ReifiedNameParam(this, paramSym, useRawName)
103+
case t if t <:< IsAnnotatedAT =>
104+
new IsAnnotatedParam(this, paramSym, t.typeArgs.head)
105+
case t => reportProblem(s"metadata param strategy $t is not allowed here")
106+
}
107107

108108
def compositeConstructor(param: CompositeParam): MetadataConstructor
109109

110110
lazy val paramLists: List[List[MetadataParam]] =
111111
symbol.typeSignatureIn(ownerType).paramLists.map(_.map { ps =>
112112
if (findAnnotation(ps, CompositeAT).nonEmpty)
113113
new CompositeParam(this, ps)
114-
else findAnnotation(ps, MetadataParamStrategyType).map(paramByStrategy(ps, _)).getOrElse {
114+
else findAnnotation(ps, MetadataParamStrategyType, ownerType).map(paramByStrategy(ps, _)).getOrElse {
115115
if (ps.isImplicit) new ImplicitParam(this, ps, "")
116116
else new InvalidParam(this, ps, "no metadata param strategy annotation found")
117117
}
@@ -201,7 +201,7 @@ trait MacroMetadatas extends MacroSymbols {
201201
case ParamArity.Optional(_) =>
202202
Ok(mkOptional(matchedSymbol.annot(annotTpe).map(validatedAnnotTree)))
203203
case ParamArity.Multi(_, _) =>
204-
Ok(mkMulti(allAnnotations(matchedSymbol.real.symbol, annotTpe).map(validatedAnnotTree)))
204+
Ok(mkMulti(matchedSymbol.allAnnots(annotTpe).map(validatedAnnotTree)))
205205
}
206206
}
207207
}

0 commit comments

Comments
 (0)