From 513a76c537fa958207a05aa4c1c34ff68e7f18ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0pan=C4=9Bl?= Date: Tue, 14 May 2024 11:22:26 +0200 Subject: [PATCH 1/3] Add PathDependentTypeTest --- .../surface/PathDependentTypeTest.scala | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 airframe-surface/src/test/scala/wvlet/airframe/surface/PathDependentTypeTest.scala diff --git a/airframe-surface/src/test/scala/wvlet/airframe/surface/PathDependentTypeTest.scala b/airframe-surface/src/test/scala/wvlet/airframe/surface/PathDependentTypeTest.scala new file mode 100644 index 000000000..24410996f --- /dev/null +++ b/airframe-surface/src/test/scala/wvlet/airframe/surface/PathDependentTypeTest.scala @@ -0,0 +1,44 @@ +/* + * 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 + +// extracted from wvlet.airframe.di.PathDependentTypeTest + +class PathDependentTypeTest extends AirSpec { + test("pass dependent types") { + import PathDependentType.* + val s = Surface.of[MyProfile#Backend#Database] + assert(s.name == "Database") + assert(s.toString == "Database:=DatabaseDef") + } +} + +object PathDependentType { + object MyBackend extends MyBackend + + class MyService(val p: MyProfile#Backend#Database) + + trait MyProfile { + type Backend = MyBackend + } + + trait MyBackend { + type Database = DatabaseDef + class DatabaseDef { + def hello = "hello my" + } + } +} From 24f394e716c2811ea49ac04d04959afc7e4c29c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0pan=C4=9Bl?= Date: Tue, 14 May 2024 09:35:11 +0200 Subject: [PATCH 2/3] Simplify extractSymbol - avoid .tree --- .../surface/CompileTimeSurfaceFactory.scala | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) 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 6e493f3df..3434f3a8d 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 @@ -172,15 +172,16 @@ private[surface] class CompileTimeSurfaceFactory[Q <: Quotes](using quotes: Q): } private def extractSymbol(t: TypeRepr) = - val dealiased = t.dealias - val symbolInOwner = t.typeSymbol.maybeOwner.declarations.find(_.name.toString == t.typeSymbol.name.toString) - symbolInOwner.map(_.tree) match - case Some(TypeDef(_, b: TypeTree)) if t == dealiased => - // t.dealias does not dealias for path dependent types, so extracting the dealiased type from AST. - surfaceOf(b.tpe) - case _ => - if t != dealiased then surfaceOf(dealiased) - else surfaceOf(t.simplified) + val dealiased = t.dealias + if t != dealiased then surfaceOf(dealiased) + else + // t.dealias does not dealias for path dependent types, so try to find a matching inner type + val symbolInOwner = t.typeSymbol.maybeOwner.declarations.find(_.name.toString == t.typeSymbol.name.toString) + symbolInOwner match + case Some(sym) => + surfaceOf(sym.typeRef.dealias) + case _ => + surfaceOf(t.simplified) private def aliasFactory: Factory = { case t if t.typeSymbol.typeRef.isOpaqueAlias => From b9928d59f8663f0bc5817cec92af5cb191184848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0pan=C4=9Bl?= Date: Tue, 14 May 2024 11:22:40 +0200 Subject: [PATCH 3/3] Add logging --- .../airframe/surface/CompileTimeSurfaceFactory.scala | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) 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 3434f3a8d..0719a87a1 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 @@ -173,14 +173,22 @@ private[surface] class CompileTimeSurfaceFactory[Q <: Quotes](using quotes: Q): private def extractSymbol(t: TypeRepr) = val dealiased = t.dealias - if t != dealiased then surfaceOf(dealiased) + + println(s"dealiased ${dealiased.show} of ${t.show}") + println(s" maybeOwner.declarations ${t.typeSymbol.maybeOwner.declarations.map(_.name).mkString(",")}") + + if t != dealiased then + println(s"dealiased as ${dealiased.show}") + surfaceOf(dealiased) else // t.dealias does not dealias for path dependent types, so try to find a matching inner type val symbolInOwner = t.typeSymbol.maybeOwner.declarations.find(_.name.toString == t.typeSymbol.name.toString) symbolInOwner match case Some(sym) => + println(s"Match 1 $sym in $symbolInOwner as ${sym.typeRef.show} -> ${sym.typeRef.dealias.show}") surfaceOf(sym.typeRef.dealias) case _ => + println(s"Match 2 $symbolInOwner as ${t.simplified.show}") surfaceOf(t.simplified) private def aliasFactory: Factory = {