From a7a88282a2672bfd75b2d66d56af33309acebda7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0pan=C4=9Bl?= Date: Wed, 28 Feb 2024 23:42:05 +0100 Subject: [PATCH] surface (fix): Fixes #3418 Handle surface of List of generic tuples (#3427) Again starting with the test, passing in Scala 2 Let us see if I will be able to fix it, this time I am not yet sure where to start. --- .../surface/CompileTimeSurfaceFactory.scala | 38 +++++++++------ .../scala/wvlet/airframe/surface/i3418.scala | 47 +++++++++++++++++++ 2 files changed, 70 insertions(+), 15 deletions(-) create mode 100644 airframe-surface/src/test/scala/wvlet/airframe/surface/i3418.scala diff --git a/airframe-surface/src/main/scala-3/wvlet/airframe/surface/CompileTimeSurfaceFactory.scala b/airframe-surface/src/main/scala-3/wvlet/airframe/surface/CompileTimeSurfaceFactory.scala index 659917356..58831ffe9 100644 --- a/airframe-surface/src/main/scala-3/wvlet/airframe/surface/CompileTimeSurfaceFactory.scala +++ b/airframe-surface/src/main/scala-3/wvlet/airframe/surface/CompileTimeSurfaceFactory.scala @@ -522,21 +522,29 @@ private[surface] class CompileTimeSurfaceFactory[Q <: Quotes](using quotes: Q): .collect { case (s: Symbol, i: Int, v: ValDef) => // E.g. case class Foo(a: String)(implicit b: Int) // println(s"=== ${v.show} ${s.flags.show} ${s.flags.is(Flags.Implicit)}") - // Substitue type param to actual types - val resolved: TypeRepr = v.tpt.tpe match - case a: AppliedType => - val resolvedTypeArgs = a.args.map { - case p if p.typeSymbol.isTypeParam && typeArgTable.contains(p.typeSymbol.name) => - typeArgTable(p.typeSymbol.name) - case other => - other - } - // Need to use the base type of the applied type to replace the type parameters - a.tycon.appliedTo(resolvedTypeArgs) - case TypeRef(_, name) if typeArgTable.contains(name) => - typeArgTable(name) - case other => - other + // Substitute type param to actual types + + def resolveType(t: TypeRepr): TypeRepr = + t match + case a: AppliedType => + // println(s"=== a.args ${a.args}") + // println(s"=== typeArgTable ${typeArgTable}") + val resolvedTypeArgs = a.args.map { + case p if p.typeSymbol.isTypeParam && typeArgTable.contains(p.typeSymbol.name) => + typeArgTable(p.typeSymbol.name) + case other => + resolveType(other) + } + // println(s"=== resolvedTypeArgs ${resolvedTypeArgs}") + // Need to use the base type of the applied type to replace the type parameters + a.tycon.appliedTo(resolvedTypeArgs) + case TypeRef(_, name) if typeArgTable.contains(name) => + typeArgTable(name) + case other => + other + + val resolved: TypeRepr = resolveType(v.tpt.tpe) + val isSecret = hasSecretAnnotation(s) val isRequired = hasRequiredAnnotation(s) val isImplicit = s.flags.is(Flags.Implicit) diff --git a/airframe-surface/src/test/scala/wvlet/airframe/surface/i3418.scala b/airframe-surface/src/test/scala/wvlet/airframe/surface/i3418.scala new file mode 100644 index 000000000..94e091620 --- /dev/null +++ b/airframe-surface/src/test/scala/wvlet/airframe/surface/i3418.scala @@ -0,0 +1,47 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package wvlet.airframe.surface + +import wvlet.airspec.AirSpec + +object i3418 extends AirSpec { + + case class A[P](data: List[(String, P)]) + case class AA[T, P](data: List[(T, P)]) + + case class S(a: A[Int]) + case class SS(a: AA[String, Long]) + + test("Support generic List of tuples") { + val s = Surface.of[S] + debug(s.params) + s.params.size shouldBe 1 + val p1 = s.params(0) + p1.name shouldBe "a" + val a1 = p1.surface.params(0) + a1.name shouldBe "data" + a1.surface.name shouldBe "List[Tuple2[String,Int]]" + } + + test("Support generic List of tuples with two type parameters") { + val s = Surface.of[SS] + debug(s.params) + s.params.size shouldBe 1 + val p1 = s.params(0) + p1.name shouldBe "a" + val a1 = p1.surface.params(0) + a1.name shouldBe "data" + a1.surface.name shouldBe "List[Tuple2[String,Long]]" + } +}