@@ -5,15 +5,22 @@ import scala.quoted._
55
66trait MemberLookup {
77
8+ def memberLookupResult (using Quotes )(
9+ symbol : quotes.reflect.Symbol ,
10+ label : String ,
11+ inheritingParent : Option [quotes.reflect.Symbol ] = None
12+ ): (quotes.reflect.Symbol , String , Option [quotes.reflect.Symbol ]) =
13+ (symbol, label, inheritingParent)
14+
815 def lookup (using Quotes , DocContext )(
916 query : Query ,
1017 owner : quotes.reflect.Symbol ,
11- ): Option [(quotes.reflect.Symbol , String )] = lookupOpt(query, Some (owner))
18+ ): Option [(quotes.reflect.Symbol , String , Option [quotes.reflect. Symbol ] )] = lookupOpt(query, Some (owner))
1219
1320 def lookupOpt (using Quotes , DocContext )(
1421 query : Query ,
1522 ownerOpt : Option [quotes.reflect.Symbol ],
16- ): Option [(quotes.reflect.Symbol , String )] =
23+ ): Option [(quotes.reflect.Symbol , String , Option [quotes.reflect. Symbol ] )] =
1724 try
1825 import quotes .reflect ._
1926
@@ -26,7 +33,7 @@ trait MemberLookup {
2633 def nearestMembered (sym : Symbol ): Symbol =
2734 if sym.isClassDef || sym.flags.is(Flags .Package ) then sym else nearestMembered(sym.owner)
2835
29- val res : Option [(Symbol , String )] = {
36+ val res : Option [(Symbol , String , Option [ Symbol ] )] = {
3037 def toplevelLookup (querystrings : List [String ]) =
3138 downwardLookup(querystrings, defn.PredefModule .moduleClass)
3239 .orElse(downwardLookup(querystrings, defn.ScalaPackage ))
@@ -38,7 +45,7 @@ trait MemberLookup {
3845 val nearest = nearestMembered(owner)
3946 val nearestCls = nearestClass(owner)
4047 val nearestPkg = nearestPackage(owner)
41- def relativeLookup (querystrings : List [String ], owner : Symbol ): Option [Symbol ] = {
48+ def relativeLookup (querystrings : List [String ], owner : Symbol ): Option [( Symbol , Option [ Symbol ]) ] = {
4249 val isMeaningful =
4350 owner.exists
4451 // those are just an optimisation, they can be dropped if problems show up
@@ -56,20 +63,20 @@ trait MemberLookup {
5663
5764 query match {
5865 case Query .StrictMemberId (id) =>
59- localLookup(id , nearest).nextOption. map(_ -> id )
66+ downwardLookup( List (id) , nearest).map(memberLookupResult(_, id, _) )
6067 case Query .QualifiedId (Query .Qual .This , _, rest) =>
61- downwardLookup(rest.asList, nearestCls).map(_ -> rest.join)
68+ downwardLookup(rest.asList, nearestCls).map(memberLookupResult(_, rest.join, _) )
6269 case Query .QualifiedId (Query .Qual .Package , _, rest) =>
63- downwardLookup(rest.asList, nearestPkg).map(_ -> rest.join)
70+ downwardLookup(rest.asList, nearestPkg).map(memberLookupResult(_, rest.join, _) )
6471 case query =>
6572 val ql = query.asList
6673 toplevelLookup(ql)
6774 .orElse(relativeLookup(ql, nearest))
68- .map(_ -> query.join)
75+ .map(memberLookupResult(_, query.join, _) )
6976 }
7077
7178 case None =>
72- toplevelLookup(query.asList).map(_ -> query.join)
79+ toplevelLookup(query.asList).map(memberLookupResult(_, query.join, _) )
7380 }
7481 }
7582
@@ -88,7 +95,10 @@ trait MemberLookup {
8895 import dotty .tools .dotc
8996 given dotc .core.Contexts .Context = quotes.asInstanceOf [scala.quoted.runtime.impl.QuotesImpl ].ctx
9097 val sym = rsym.asInstanceOf [dotc.core.Symbols .Symbol ]
91- val members = sym.info.decls.iterator.filter(s => hackIsNotAbsent(s.asInstanceOf [Symbol ]))
98+ val members =
99+ sym.info.allMembers.iterator.map(_.symbol).filter(
100+ s => hackIsNotAbsent(s.asInstanceOf [Symbol ])
101+ )
92102 // println(s"members of ${sym.show} : ${members.map(_.show).mkString(", ")}")
93103 members.asInstanceOf [Iterator [Symbol ]]
94104 }
@@ -101,43 +111,37 @@ trait MemberLookup {
101111 sym.isCompleted && sym.info.exists
102112 }
103113
104- private def localLookup (using Quotes )(query : String , owner : quotes.reflect.Symbol ): Iterator [quotes.reflect.Symbol ] = {
114+ private def localLookup (using Quotes )(
115+ sel : MemberLookup .Selector ,
116+ owner : quotes.reflect.Symbol
117+ ): Iterator [quotes.reflect.Symbol ] = {
105118 import quotes .reflect ._
106119
107120 def findMatch (syms : Iterator [Symbol ]): Iterator [Symbol ] = {
108- // Scaladoc overloading support allows terminal * (and they're meaningless)
109- val cleanQuery = query.stripSuffix(" *" )
110- val (q, forceTerm, forceType) =
111- if cleanQuery endsWith " $" then
112- (cleanQuery.init, true , false )
113- else if cleanQuery endsWith " !" then
114- (cleanQuery.init, false , true )
115- else
116- (cleanQuery, false , false )
117-
118121 def matches (s : Symbol ): Boolean =
119- s.name == q && (
120- if forceTerm then s.isTerm
121- else if forceType then s.isType
122- else true
123- )
122+ s.name == sel.ident && sel.kind. match {
123+ case MemberLookup . SelectorKind . ForceTerm => s.isTerm
124+ case MemberLookup . SelectorKind . ForceType => s.isType
125+ case MemberLookup . SelectorKind . NoForce => true
126+ }
124127
125128 def hackResolveModule (s : Symbol ): Symbol =
126129 if s.flags.is(Flags .Module ) then s.moduleClass else s
127130
128131 // val syms0 = syms.toList
129132 // val matched0 = syms0.filter(matches)
130133 // if matched0.isEmpty then
131- // println(s"Failed to look up $q in $owner; all members: {{{")
134+ // println(s"Failed to look up ${sel.ident} in $owner; all members: {{{")
132135 // syms0.foreach { s => println(s"\t$s") }
133136 // println("}}}")
134137 // val matched = matched0.iterator
135138
136139 // def showMatched() = matched0.foreach { s =>
137140 // println(s"\t $s")
138141 // }
139- // println(s"localLookup in class ${owner} for `$q`{forceTerm=$forceTerm}: ")
142+ // println(s"localLookup in class ${owner} for `${sel.ident}`{kind=${sel.kind}}:{{{ ")
140143 // showMatched()
144+ // println("}}}")
141145
142146 val matched = syms.filter(matches)
143147 matched.map(hackResolveModule)
@@ -150,8 +154,6 @@ trait MemberLookup {
150154 })
151155 else
152156 owner.tree match {
153- case tree : ClassDef =>
154- findMatch(tree.body.iterator.collect { case t : Definition if hackIsNotAbsent(t.symbol) => t.symbol })
155157 case tree : TypeDef =>
156158 val tpe =
157159 tree.rhs match {
@@ -168,14 +170,37 @@ trait MemberLookup {
168170 }
169171 }
170172
171- private def downwardLookup (using Quotes )(query : List [String ], owner : quotes.reflect.Symbol ): Option [quotes.reflect.Symbol ] = {
173+ private def downwardLookup (using Quotes )(
174+ query : List [String ], owner : quotes.reflect.Symbol
175+ ): Option [(quotes.reflect.Symbol , Option [quotes.reflect.Symbol ])] = {
172176 import quotes .reflect ._
173177 query match {
174178 case Nil => None
175- case q :: Nil => localLookup(q, owner).nextOption
179+ case q :: Nil =>
180+ val sel = MemberLookup .Selector .fromString(q)
181+ val res = sel.kind match {
182+ case MemberLookup .SelectorKind .NoForce =>
183+ val lookedUp = localLookup(sel, owner).toSeq
184+ // note: those flag lookups are necessary b/c for objects we return their classes
185+ lookedUp.find(s => s.isType && ! s.flags.is(Flags .Module )).orElse(
186+ lookedUp.find(s => s.isTerm || s.flags.is(Flags .Module ))
187+ )
188+ case _ =>
189+ localLookup(sel, owner).nextOption
190+ }
191+ res match {
192+ case None => None
193+ case Some (sym) =>
194+ val externalOwner : Option [quotes.reflect.Symbol ] =
195+ if owner eq sym.owner then None
196+ else if owner.flags.is(Flags .Module ) then Some (owner.moduleClass)
197+ else if owner.isClassDef then Some (owner)
198+ else None
199+ Some (sym -> externalOwner)
200+ }
176201 case q :: qs =>
177- val lookedUp =
178- localLookup(q , owner).toSeq
202+ val sel = MemberLookup . Selector .fromString(q)
203+ val lookedUp = localLookup(sel , owner).toSeq
179204
180205 if lookedUp.isEmpty then None else {
181206 // tm/tp - term/type symbols which we looked up and which allow further lookup
@@ -198,4 +223,25 @@ trait MemberLookup {
198223 }
199224}
200225
201- object MemberLookup extends MemberLookup
226+ object MemberLookup extends MemberLookup {
227+ enum SelectorKind {
228+ case ForceTerm
229+ case ForceType
230+ case NoForce
231+ }
232+
233+ case class Selector (ident : String , kind : SelectorKind )
234+ object Selector {
235+ def fromString (str : String ) = {
236+ // Scaladoc overloading support allows terminal * (and they're meaningless)
237+ val cleanStr = str.stripSuffix(" *" )
238+
239+ if cleanStr endsWith " $" then
240+ Selector (cleanStr.init, SelectorKind .ForceTerm )
241+ else if cleanStr endsWith " !" then
242+ Selector (cleanStr.init, SelectorKind .ForceType )
243+ else
244+ Selector (cleanStr, SelectorKind .NoForce )
245+ }
246+ }
247+ }
0 commit comments