diff --git a/airframe-di/src/main/scala-3/wvlet/airframe/DesignImpl.scala b/airframe-di/src/main/scala-3/wvlet/airframe/DesignImpl.scala index 892e6df179..800378aa5b 100644 --- a/airframe-di/src/main/scala-3/wvlet/airframe/DesignImpl.scala +++ b/airframe-di/src/main/scala-3/wvlet/airframe/DesignImpl.scala @@ -11,7 +11,6 @@ import wvlet.log.LogSupport private[airframe] trait DesignImpl extends LogSupport: self: Design => inline def bind[A]: Binder[A] = - registerTraitFactory[A] new Binder(self, Surface.of[A], SourceCode()).asInstanceOf[Binder[A]] inline def remove[A]: Design = diff --git a/airframe-di/src/main/scala-3/wvlet/airframe/package.scala b/airframe-di/src/main/scala-3/wvlet/airframe/package.scala index a790aaf7a8..bd8f8889a4 100644 --- a/airframe-di/src/main/scala-3/wvlet/airframe/package.scala +++ b/airframe-di/src/main/scala-3/wvlet/airframe/package.scala @@ -41,108 +41,3 @@ val traitFactoryCache = new ConcurrentHashMap[Surface, Session => Any].asScala def getOrElseUpdateTraitFactoryCache(s: Surface, factory: Session => Any): Session => Any = traitFactoryCache.getOrElseUpdate(s, factory) - -@deprecated("Instantiating trait with DI is still experimental in Scala 3", "23.9.1") -inline def registerTraitFactory[A]: Unit = { - // registerTraitFactoryImpl[A] -} - -import scala.quoted.* - -private def shouldGenerateTrait[A](using - tpe: Type[A], - q: Quotes -): Boolean = - import quotes.* - import quotes.reflect.* - - val t = TypeRepr.of[A] - val a = t.typeSymbol - - // Find the public default constructor that has no arguments - val hasPublicDefaultConstructor: Boolean = - val pc = a.primaryConstructor - pc.paramSymss.size == 1 && pc.paramSymss(0).size == 0 - - val hasAbstractMethods: Boolean = - a.methodMembers.exists { x => - x.flags.is(Flags.Method) && - (x.flags.is(Flags.Abstract) || x.flags.is(Flags.Deferred)) - } - val isTaggedType = a.fullName.startsWith("wvlet.airframe.surface.tag.") - val isSealedType = a.flags.is(Flags.Sealed) - val isStatic = a.flags.is(Flags.JavaStatic) - val isLocal = a.flags.is(Flags.Local) - val isTrait = a.flags.is(Flags.Trait) - - val shouldInstantiateTrait = - if !isStatic then - // = Non static type - // If X is non static type (= local class or trait), - // we need to instantiate it first in order to populate its $outer variables - - // We cannot instantiate path-dependent types - if a.fullName.contains("#") then false - else !hasAbstractMethods && hasPublicDefaultConstructor - else if a.isAbstractType then - // = Abstract type - // We cannot build abstract type X that has abstract methods, so bind[X].to[ConcreteType] - // needs to be found in the design - - // If there is no abstract methods, it might be a trait without any method - !hasAbstractMethods - else - // We cannot instantiate any trait or class without the default constructor - // So binding needs to be found in the Design. - hasPublicDefaultConstructor - - // Tagged type or sealed class binding should be found in Design - val result = isTrait && !isTaggedType && !isSealedType && shouldInstantiateTrait - - // println(s"${a.flags.show}, isStatic: ${isStatic}, isAbstract: ${a.isAbstractType}, isSealed: ${isSealedType} ${a.fullName}, " + - // s"has pstr: ${hasPublicDefaultConstructor} is tagged: ${isTaggedType}, has abstract method: ${hasAbstractMethods}") - - result - -@experimental def registerTraitFactoryImpl[A](using - tpe: Type[A], - q: Quotes -): quoted.Expr[Unit] = - import quotes.* - import quotes.reflect.* - - if !shouldGenerateTrait[A] then '{} - else - val name = "$anon" - val parents = List(TypeTree.of[Object], TypeTree.of[A], TypeTree.of[DISupport]) - - def decls(cls: Symbol): List[Symbol] = - List(Symbol.newMethod(cls, "session", MethodType(Nil)(_ => Nil, _ => TypeRepr.of[Session]))) - - val cls = Symbol.newClass(Symbol.spliceOwner, name, parents = parents.map(_.tpe), decls, selfType = None) - val sessionMethodSym = cls.declaredMethod("session").head - def sessionMethodDef(s: Term) = DefDef(sessionMethodSym, argss => Some(s)) - def newCls(s: Term) = - val clsDef = ClassDef(cls, parents, body = List(sessionMethodDef(s))) - val newCls = Typed(Apply(Select(New(TypeIdent(cls)), cls.primaryConstructor), Nil), TypeTree.of[A]) - Block(List(clsDef), newCls) - - // Generate code { (s: Session) => new A with DISupport { def sesion: Session = s } } - val body = Lambda( - owner = Symbol.spliceOwner, - tpe = MethodType(List("s"))(_ => List(TypeRepr.of[Session]), _ => TypeRepr.of[A]), - rhsFn = (sym: Symbol, paramRefs: List[Tree]) => - val s = paramRefs.head.asExprOf[Session].asTerm - val fn = newCls(s) - fn.changeOwner(sym) - ) - // Register trait factory - // { (s: Session) => new A with DISupport { def session = s } } - '{ - wvlet.airframe.getOrElseUpdateTraitFactoryCache( - Surface.of[A], - ${ - body.asExprOf[Session => Any] - } - ) - } diff --git a/airframe-di/src/test/scala-3/wvlet/airframe/di/TraitFactoryTest.scala b/airframe-di/src/test/scala-3/wvlet/airframe/di/TraitFactoryTest.scala deleted file mode 100644 index b129e8743e..0000000000 --- a/airframe-di/src/test/scala-3/wvlet/airframe/di/TraitFactoryTest.scala +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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.di - -import wvlet.airspec.AirSpec -import scala.language.experimental -import wvlet.airframe.* -import wvlet.airframe.surface.Surface - -object TraitFactoryTest extends AirSpec: - - trait A - - test("register trait factory") { - if isScala3 then pending("In Scala 3.3.1, creating a new trait instance via macro is still experimental") - registerTraitFactory[A] - traitFactoryCache.get(Surface.of[A]) shouldBe defined - } - - trait B: - def hello: Unit - - test("do not create trait factory for abstract classes") { - registerTraitFactory[B] - // --- - traitFactoryCache.get(Surface.of[B]) shouldBe empty - } - -// test("do not create trait for a local type") { -// trait Local -// registerTraitFactory[Local] -// traitFactoryCache.get(Surface.of[Local]) shouldBe empty -// } - - class C - - test("should not register trait factory for a simple class") { - registerTraitFactory[C] - traitFactoryCache.get(Surface.of[B]) shouldBe empty - } - - class D(i: Int) - - test("do not creat trait factroy for a class without any public constructor") { - registerTraitFactory[D] - traitFactoryCache.get(Surface.of[B]) shouldBe empty - } diff --git a/airframe-http/.jvm/src/main/scala-3/wvlet/airframe/http/router/RouterBase.scala b/airframe-http/.jvm/src/main/scala-3/wvlet/airframe/http/router/RouterBase.scala index 0910dd7262..869b922a13 100644 --- a/airframe-http/.jvm/src/main/scala-3/wvlet/airframe/http/router/RouterBase.scala +++ b/airframe-http/.jvm/src/main/scala-3/wvlet/airframe/http/router/RouterBase.scala @@ -43,11 +43,9 @@ private[router] object RouterObjectMacros: if TypeRepr.of[Controller] <:< TypeRepr.of[HttpFilterType] then '{ - wvlet.airframe.registerTraitFactory[Controller] Router(filterSurface = Some(Surface.of[Controller])) } else '{ - wvlet.airframe.registerTraitFactory[Controller] Router.empty.add[Controller] }