@@ -5,12 +5,12 @@ import scala.quoted._
55
66trait MemberLookup {
77
8- def lookup (using Quotes )(
8+ def lookup (using Quotes , DocContext )(
99 query : Query ,
1010 owner : quotes.reflect.Symbol ,
1111 ): Option [(quotes.reflect.Symbol , String )] = lookupOpt(query, Some (owner))
1212
13- def lookupOpt (using Quotes )(
13+ def lookupOpt (using Quotes , DocContext )(
1414 query : Query ,
1515 ownerOpt : Option [quotes.reflect.Symbol ],
1616 ): Option [(quotes.reflect.Symbol , String )] =
@@ -26,55 +26,69 @@ trait MemberLookup {
2626 def nearestMembered (sym : Symbol ): Symbol =
2727 if sym.isClassDef || sym.flags.is(Flags .Package ) then sym else nearestMembered(sym.owner)
2828
29- val res =
29+ val res : Option [( Symbol , String )] = {
3030 def toplevelLookup (querystrings : List [String ]) =
3131 downwardLookup(querystrings, defn.PredefModule .moduleClass)
3232 .orElse(downwardLookup(querystrings, defn.ScalaPackage ))
3333 .orElse(downwardLookup(querystrings, defn.RootPackage ))
34+ .orElse(downwardLookup(querystrings, defn.EmptyPackageClass ))
3435
3536 ownerOpt match {
3637 case Some (owner) =>
3738 val nearest = nearestMembered(owner)
3839 val nearestCls = nearestClass(owner)
3940 val nearestPkg = nearestPackage(owner)
40- def relativeLookup (querystrings : List [String ]) =
41- // TODO walk the owner chain?
42- downwardLookup(querystrings, nearestPkg).orElse(toplevelLookup(querystrings))
41+ def relativeLookup (querystrings : List [String ], owner : Symbol ): Option [Symbol ] = {
42+ val isMeaningful =
43+ owner.exists
44+ // those are just an optimisation, they can be dropped if problems show up
45+ && owner.ne(defn.ScalaPackage )
46+ && owner.ne(defn.RootClass )
47+ && owner.ne(defn.EmptyPackageClass )
48+
49+ if ! isMeaningful then None else {
50+ downwardLookup(querystrings, owner) match {
51+ case None => relativeLookup(querystrings, owner.owner)
52+ case some => some
53+ }
54+ }
55+ }
56+
4357 query match {
44- case Query .StrictMemberId (id) => localLookup(id, nearest).map(_ -> id)
45- case Query .Id (id) =>
46- (localLookup(id, nearest) orElse relativeLookup(List (id))).map(_ -> id)
58+ case Query .StrictMemberId (id) =>
59+ localLookup(id, nearest).nextOption.map(_ -> id)
4760 case Query .QualifiedId (Query .Qual .This , _, rest) =>
4861 downwardLookup(rest.asList, nearestCls).map(_ -> rest.join)
4962 case Query .QualifiedId (Query .Qual .Package , _, rest) =>
5063 downwardLookup(rest.asList, nearestPkg).map(_ -> rest.join)
51- case Query .QualifiedId (Query .Qual .Id (id), _, rest) if id == nearestCls.name =>
52- downwardLookup(rest.asList, nearestCls).map(_ -> rest.join)
53- case Query .QualifiedId (Query .Qual .Id (id), _, rest) if id == nearestPkg.name =>
54- downwardLookup(rest.asList, nearestPkg).map(_ -> rest.join)
55- case query : Query .QualifiedId =>
56- relativeLookup(query.asList).map(_ -> query.join)
64+ case query =>
65+ val ql = query.asList
66+ toplevelLookup(ql)
67+ .orElse(relativeLookup(ql, nearest))
68+ .map(_ -> query.join)
5769 }
5870
5971 case None =>
6072 toplevelLookup(query.asList).map(_ -> query.join)
6173 }
74+ }
6275
6376 // println(s"looked up `$query` in ${owner.show}[${owner.flags.show}] as ${res.map(_.show)}")
6477
6578 res
6679 catch
6780 case e : Exception =>
6881 // TODO (https://github.com/lampepfl/scala3doc/issues/238): proper reporting
69- println(s " [WARN] Unable to find a link for ${query} ${ownerOpt.fold(" " )(o => " in " + o.name)}" )
82+ val msg = s " Unable to find a link for ${query} ${ownerOpt.fold(" " )(o => " in " + o.name)}"
83+ report.warn(msg, e)
7084 None
7185
7286 private def hackMembersOf (using Quotes )(rsym : quotes.reflect.Symbol ) = {
7387 import quotes .reflect ._
7488 import dotty .tools .dotc
7589 given dotc .core.Contexts .Context = quotes.asInstanceOf [scala.quoted.runtime.impl.QuotesImpl ].ctx
7690 val sym = rsym.asInstanceOf [dotc.core.Symbols .Symbol ]
77- val members = sym.info.decls.iterator.filter(_.isCompleted )
91+ val members = sym.info.decls.iterator.filter(s => hackIsNotAbsent(s. asInstanceOf [ Symbol ]) )
7892 // println(s"members of ${sym.show} : ${members.map(_.show).mkString(", ")}")
7993 members.asInstanceOf [Iterator [Symbol ]]
8094 }
@@ -83,16 +97,14 @@ trait MemberLookup {
8397 import dotty .tools .dotc
8498 given dotc .core.Contexts .Context = quotes.asInstanceOf [scala.quoted.runtime.impl.QuotesImpl ].ctx
8599 val sym = rsym.asInstanceOf [dotc.core.Symbols .Symbol ]
86- sym.isCompleted
100+ // note: Predef has .info = NoType for some reason
101+ sym.isCompleted && sym.info.exists
87102 }
88103
89- private def localLookup (using Quotes )(query : String , owner : quotes.reflect.Symbol ): Option [quotes.reflect.Symbol ] = {
104+ private def localLookup (using Quotes )(query : String , owner : quotes.reflect.Symbol ): Iterator [quotes.reflect.Symbol ] = {
90105 import quotes .reflect ._
91106
92- inline def whenExists (s : Symbol )(otherwise : => Option [Symbol ]): Option [Symbol ] =
93- if s.exists then Some (s) else otherwise
94-
95- def findMatch (syms : Iterator [Symbol ]): Option [Symbol ] = {
107+ def findMatch (syms : Iterator [Symbol ]): Iterator [Symbol ] = {
96108 // Scaladoc overloading support allows terminal * (and they're meaningless)
97109 val cleanQuery = query.stripSuffix(" *" )
98110 val (q, forceTerm, forceType) =
@@ -114,23 +126,24 @@ trait MemberLookup {
114126 if s.flags.is(Flags .Module ) then s.moduleClass else s
115127
116128 // val syms0 = syms.toList
117- // val matched0 = syms0.find (matches)
129+ // val matched0 = syms0.filter (matches)
118130 // if matched0.isEmpty then
119131 // println(s"Failed to look up $q in $owner; all members below:")
120132 // syms0.foreach { s => println(s"\t$s") }
121- // val matched = matched0
133+ // val matched = matched0.iterator
122134
123135 // def showMatched() = matched.foreach { s =>
124- // println(s">>> ${s.show} ")
136+ // println(s">>> $s ")
125137 // println(s">>> ${s.pos}")
126138 // println(s">>> [${s.flags.show}]")
127139 // println(s">>> {${if s.isTerm then "isterm" else ""};${if s.isType then "istype" else ""}}")
128140 // println(s">>> moduleClass = ${if hackResolveModule(s) == s then hackResolveModule(s).show else "none"}")
129141 // }
130- // println(s"localLookup for class ${owner.show} of `$q`{forceTerm=$forceTerm}")
142+ // println(s"localLookup in class ${owner} for `$q`{forceTerm=$forceTerm}")
143+ // println(s"\t${matched0.mkString(", ")}")
131144 // showMatched()
132145
133- val matched = syms.find (matches)
146+ val matched = syms.filter (matches)
134147 matched.map(hackResolveModule)
135148 }
136149
@@ -147,20 +160,43 @@ trait MemberLookup {
147160 case tpt : TypeTree => tpt.tpe
148161 }
149162
150- tpe.classSymbol.flatMap { s =>
151- findMatch(hackMembersOf(s))
163+ tpe.classSymbol match {
164+ case Some (s) => findMatch(hackMembersOf(s))
165+ case None => Iterator .empty
152166 }
153167 case _ =>
154168 findMatch(hackMembersOf(owner))
155169 }
156170 }
157171
158- private def downwardLookup (using Quotes )(query : List [String ], owner : quotes.reflect.Symbol ): Option [quotes.reflect.Symbol ] =
172+ private def downwardLookup (using Quotes )(query : List [String ], owner : quotes.reflect.Symbol ): Option [quotes.reflect.Symbol ] = {
173+ import quotes .reflect ._
159174 query match {
160175 case Nil => None
161- case q :: Nil => localLookup(q, owner)
162- case q :: qs => localLookup(q, owner).flatMap(downwardLookup(qs, _))
176+ case q :: Nil => localLookup(q, owner).nextOption
177+ case q :: qs =>
178+ val lookedUp =
179+ localLookup(q, owner).toSeq
180+
181+ if lookedUp.isEmpty then None else {
182+ // tm/tp - term/type symbols which we looked up and which allow further lookup
183+ // pk - package symbol
184+ // Note: packages collide with both term and type definitions
185+ // Note: classes and types collide
186+ var pk : Option [Symbol ] = None
187+ var tp : Option [Symbol ] = None
188+ var tm : Option [Symbol ] = None
189+ lookedUp.foreach { s =>
190+ if s.isPackageDef then pk = Some (s)
191+ else if s.flags.is(Flags .Module ) then tm = Some (s)
192+ else if s.isClassDef || s.isTypeDef then tp = Some (s)
193+ }
194+ pk.flatMap(downwardLookup(qs, _))
195+ .orElse(tp.flatMap(downwardLookup(qs, _)))
196+ .orElse(tm.flatMap(downwardLookup(qs, _)))
197+ }
163198 }
199+ }
164200}
165201
166202object MemberLookup extends MemberLookup
0 commit comments