Skip to content

Commit 0e3c8ad

Browse files
committed
Fallback to fake symbol for refinements in RefinedType of upper bound
see: #12885 (comment) #12885 (comment)
1 parent c3bd0d5 commit 0e3c8ad

File tree

6 files changed

+155
-109
lines changed

6 files changed

+155
-109
lines changed

compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,18 @@ object Scala3:
3636
* - SymbolInformation with signature TypeSignature of given type bound.
3737
*/
3838
case class WildcardTypeSymbol(owner: Symbol, bounds: TypeBounds) extends FakeSymbol
39+
40+
case class TermParamRefSymbol(owner: Symbol, name: Name, tp: Type) extends FakeSymbol
3941
case class TypeParamRefSymbol(owner: Symbol, name: Name, tp: TypeBounds) extends FakeSymbol
42+
case class RefinementSymbol(name: Name, tp: Type) extends FakeSymbol
4043
type SemanticSymbol = Symbol | FakeSymbol
4144
extension (sym: SemanticSymbol)
4245
def name(using Context): Name = sym match
4346
case s: Symbol => s.name
4447
case s: WildcardTypeSymbol => nme.WILDCARD
48+
case s: TermParamRefSymbol => s.name
4549
case s: TypeParamRefSymbol => s.name
50+
case s: RefinementSymbol => s.name
4651

4752
def symbolName(using builder: SemanticSymbolBuilder)(using Context): String =
4853
sym match
@@ -65,6 +70,14 @@ object Scala3:
6570
displayName = nme.WILDCARD.show,
6671
signature = s.bounds.toSemanticSig(NoSymbol),
6772
)
73+
case s: TermParamRefSymbol =>
74+
SymbolInformation(
75+
symbol = symbolName,
76+
language = Language.SCALA,
77+
kind = SymbolInformation.Kind.PARAMETER,
78+
displayName = s.name.show.unescapeUnicode,
79+
signature = s.tp.toSemanticSig(NoSymbol),
80+
)
6881
case s: TypeParamRefSymbol =>
6982
SymbolInformation(
7083
symbol = symbolName,
@@ -73,6 +86,22 @@ object Scala3:
7386
displayName = s.name.show.unescapeUnicode,
7487
signature = s.tp.toSemanticSig(NoSymbol),
7588
)
89+
case s: RefinementSymbol =>
90+
val signature = s.tp.toSemanticSig(NoSymbol)
91+
val kind = signature match
92+
case _: TypeSignature => SymbolInformation.Kind.TYPE
93+
case _: MethodSignature => SymbolInformation.Kind.METHOD
94+
case _: ValueSignature => SymbolInformation.Kind.FIELD
95+
case _ => SymbolInformation.Kind.UNKNOWN_KIND
96+
SymbolInformation(
97+
symbol = symbolName,
98+
language = Language.SCALA,
99+
kind = kind,
100+
displayName = s.name.show.unescapeUnicode,
101+
properties =
102+
SymbolInformation.Property.ABSTRACT.value,
103+
signature = signature,
104+
)
76105

77106
enum SymbolKind derives CanEqual:
78107
kind =>

compiler/src/dotty/tools/dotc/semanticdb/SemanticSymbolBuilder.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,22 @@ class SemanticSymbolBuilder:
3636
addSymName(b, sym.owner)
3737
b.append('['); addName(b, sym.name); b.append(']')
3838
b.toString
39+
case sym: TermParamRefSymbol =>
40+
val b = StringBuilder(20)
41+
addSymName(b, sym.owner)
42+
b.append('('); addName(b, sym.name); b.append(')')
43+
b.toString
3944
case sym: TypeParamRefSymbol =>
4045
val b = StringBuilder(20)
4146
addSymName(b, sym.owner)
4247
b.append('['); addName(b, sym.name); b.append(']')
4348
b.toString
49+
case sym: RefinementSymbol =>
50+
val b = StringBuilder(20)
51+
val localIdx = nextLocalIdx
52+
nextLocalIdx += 1
53+
b.append(Symbols.LocalPrefix).append(localIdx)
54+
b.toString
4455

4556
def funParamSymbol(sym: Symbol)(using Context): Name => String =
4657
if sym.isGlobal then

compiler/src/dotty/tools/dotc/semanticdb/TypeOps.scala

Lines changed: 42 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import ast.tpd._
1414
import collection.mutable
1515

1616
import dotty.tools.dotc.{semanticdb => s}
17-
import Scala3.{SemanticSymbol, WildcardTypeSymbol, TypeParamRefSymbol}
17+
import Scala3.{SemanticSymbol, WildcardTypeSymbol, TypeParamRefSymbol, TermParamRefSymbol, RefinementSymbol}
1818

1919
class TypeOps:
2020
import SymbolScopeOps._
@@ -24,31 +24,29 @@ class TypeOps:
2424
given typeOps: TypeOps = this
2525

2626
extension [T <: LambdaType | RefinedType](symtab: mutable.Map[(T, Name), Symbol])
27-
private def lookupOrErr(
27+
private def lookup(
2828
binder: T,
2929
name: Name,
30-
parent: Symbol,
3130
)(using Context): Option[Symbol] =
32-
// In case refinement or type param cannot be accessed from traverser and
33-
// no symbols are registered to the symbol table, fall back to Type.member
34-
val sym = symtab.lookup(binder, name, parent)
35-
if sym.exists then
36-
Some(sym)
37-
else
38-
symbolNotFound(binder, name, parent)
39-
None
31+
symtab.get((binder, name))
4032

41-
private def lookup(
33+
extension [T <: LambdaType](symtab: mutable.Map[(T, Name), Symbol])
34+
private def lookupOrErr(
4235
binder: T,
4336
name: Name,
4437
parent: Symbol,
45-
)(using Context): Symbol =
38+
)(using Context): Option[Symbol] =
4639
// In case refinement or type param cannot be accessed from traverser and
4740
// no symbols are registered to the symbol table, fall back to Type.member
48-
symtab.getOrElse(
49-
(binder, name),
50-
binder.member(name).symbol
51-
)
41+
symtab.lookup(binder, name) match
42+
case found @ Some(_) => found
43+
case None =>
44+
val member = binder.member(name).symbol
45+
if !member.exists then
46+
symbolNotFound(binder, name, parent)
47+
None
48+
else
49+
Some(member)
5250

5351
private def symbolNotFound(binder: Type, name: Name, parent: Symbol)(using ctx: Context): Unit =
5452
warn(s"Ignoring ${name} of symbol ${parent}, type ${binder}")
@@ -143,17 +141,21 @@ class TypeOps:
143141
case mp: MethodOrPoly =>
144142
def flatten(
145143
t: Type,
146-
paramss: List[List[Symbol]],
147-
tparams: List[Symbol]
148-
): (Type, List[List[Symbol]], List[Symbol]) = t match {
144+
paramss: List[List[SemanticSymbol]],
145+
tparams: List[SemanticSymbol]
146+
): (Type, List[List[SemanticSymbol]], List[SemanticSymbol]) = t match {
149147
case mt: MethodType =>
150-
val syms = mt.paramNames.flatMap { paramName =>
151-
paramRefSymtab.lookupOrErr(mt, paramName, sym)
148+
val syms: List[SemanticSymbol] = mt.paramNames.zip(mt.paramInfos).map { (name, info) =>
149+
paramRefSymtab.lookup(mt, name).getOrElse(
150+
TermParamRefSymbol(sym, name, info)
151+
)
152152
}
153153
flatten(mt.resType, paramss :+ syms, tparams)
154154
case pt: PolyType =>
155-
val syms = pt.paramNames.flatMap { paramName =>
156-
paramRefSymtab.lookupOrErr(pt, paramName, sym)
155+
val syms: List[SemanticSymbol] = pt.paramNames.zip(pt.paramInfos).map { (name, info) =>
156+
paramRefSymtab.lookup(pt, name).getOrElse(
157+
TypeParamRefSymbol(sym, name, info)
158+
)
157159
}
158160
flatten(pt.resType, paramss, tparams ++ syms)
159161
case other =>
@@ -180,16 +182,14 @@ class TypeOps:
180182
// for `type X[T] = T` is equivalent to `[T] =>> T`
181183
def tparams(tpe: Type): (Type, List[SemanticSymbol]) = tpe match {
182184
case lambda: HKTypeLambda =>
183-
val paramSyms: List[SemanticSymbol] = lambda.paramNames.zip(lambda.paramInfos).flatMap { (paramName, bounds) =>
185+
val paramSyms: List[SemanticSymbol] = lambda.paramNames.zip(lambda.paramInfos).map { (paramName, bounds) =>
184186
// def x[T[_]] = ???
185187
if paramName.isWildcard then
186-
Some(WildcardTypeSymbol(sym, bounds))
188+
WildcardTypeSymbol(sym, bounds)
187189
else
188-
val found = paramRefSymtab.lookup(lambda, paramName, sym)
189-
if found.exists then
190-
Some(found)
191-
else
192-
Some(TypeParamRefSymbol(sym, paramName, bounds))
190+
paramRefSymtab.lookup(lambda, paramName).getOrElse(
191+
TypeParamRefSymbol(sym, paramName, bounds)
192+
)
193193
}
194194
(lambda.resType, paramSyms)
195195
case _ => (tpe, Nil)
@@ -239,11 +239,9 @@ class TypeOps:
239239
s.Type.Empty
240240

241241
case tref: TypeParamRef =>
242-
val found = paramRefSymtab.lookup(tref.binder, tref.paramName, sym)
243-
val tsym =
244-
if found.exists then
245-
Some(found)
246-
else
242+
val tsym = paramRefSymtab.lookup(tref.binder, tref.paramName) match
243+
case found @ Some(sym) => found
244+
case None =>
247245
tref.binder.typeParams.find(param => param.paramName == tref.paramName) match
248246
case Some(param) =>
249247
val info = param.paramInfo
@@ -301,8 +299,10 @@ class TypeOps:
301299
val (parent, refinedInfos) = flatten(rt, List.empty)
302300
val stpe = s.IntersectionType(flattenParent(parent))
303301

304-
val decls = refinedInfos.flatMap { (name, info) =>
305-
refinementSymtab.lookupOrErr(rt, name, sym)
302+
val decls: List[SemanticSymbol] = refinedInfos.map { (name, info) =>
303+
refinementSymtab.lookup(rt, name).getOrElse(
304+
RefinementSymbol(name, info)
305+
)
306306
}
307307
val sdecls = decls.sscopeOpt(using LinkMode.HardlinkChildren)
308308
s.StructuralType(stpe, sdecls)
@@ -331,6 +331,10 @@ class TypeOps:
331331
)
332332
s.AnnotatedType(sannots, sparent)
333333

334+
case AppliedType(tycon, args) if tycon == defn.RepeatedParamType && args.length == 1 =>
335+
val stpe = loop(args(0))
336+
s.RepeatedType(stpe)
337+
334338
case app @ AppliedType(tycon, args) =>
335339
val targs = args.map { arg =>
336340
arg match
Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,34 @@
11
package example
22

3-
def m1/*<-example::RecOrRefined$package.m1().*/(a/*<-example::RecOrRefined$package.m1().(a)*/: Int/*->scala::Int#*/ { val x/*<-local0*/: Int/*->scala::Int#*/ }) = ???/*->scala::Predef.`???`().*/
4-
def m2/*<-example::RecOrRefined$package.m2().*/(x/*<-example::RecOrRefined$package.m2().(x)*/: { val x/*<-local1*/: Int/*->scala::Int#*/; def y/*<-local2*/: Int/*->scala::Int#*/ }) = ???/*->scala::Predef.`???`().*/
5-
def m3/*<-example::RecOrRefined$package.m3().*/(x/*<-example::RecOrRefined$package.m3().(x)*/: { val x/*<-local3*/: Int/*->scala::Int#*/; def y/*<-local4*/: Int/*->scala::Int#*/; type z/*<-local5*/ }) = ???/*->scala::Predef.`???`().*/
3+
def m1/*<-example::RecOrRefined$package.m1().*/(a/*<-example::RecOrRefined$package.m1().(a)*/: Int/*->scala::Int#*/ { val x/*<-local1*/: Int/*->scala::Int#*/ }) = ???/*->scala::Predef.`???`().*/
4+
def m2/*<-example::RecOrRefined$package.m2().*/(x/*<-example::RecOrRefined$package.m2().(x)*/: { val x/*<-local2*/: Int/*->scala::Int#*/; def y/*<-local3*/: Int/*->scala::Int#*/ }) = ???/*->scala::Predef.`???`().*/
5+
def m3/*<-example::RecOrRefined$package.m3().*/(x/*<-example::RecOrRefined$package.m3().(x)*/: { val x/*<-local4*/: Int/*->scala::Int#*/; def y/*<-local5*/: Int/*->scala::Int#*/; type z/*<-local6*/ }) = ???/*->scala::Predef.`???`().*/
66
trait PolyHolder/*<-example::PolyHolder#*/ {
77
def foo/*<-example::PolyHolder#foo().*/[T/*<-example::PolyHolder#foo().[T]*/](t/*<-example::PolyHolder#foo().(t)*/: T/*->example::PolyHolder#foo().[T]*/): Any/*->scala::Any#*/
88
}
99

10-
def m4/*<-example::RecOrRefined$package.m4().*/(x/*<-example::RecOrRefined$package.m4().(x)*/: PolyHolder/*->example::PolyHolder#*/ { def foo/*<-local8*/[T/*<-local6*/](t/*<-local7*/: T/*->local6*/): T/*->local6*/ }) = ???/*->scala::Predef.`???`().*/
11-
def m5/*<-example::RecOrRefined$package.m5().*/[Z/*<-example::RecOrRefined$package.m5().[Z]*/](x/*<-example::RecOrRefined$package.m5().(x)*/: Int/*->scala::Int#*/): PolyHolder/*->example::PolyHolder#*/ { def foo/*<-local11*/[T/*<-local9*/](t/*<-local10*/: T/*->local9*/): T/*->local9*/ } = ???/*->scala::Predef.`???`().*/
10+
def m4/*<-example::RecOrRefined$package.m4().*/(x/*<-example::RecOrRefined$package.m4().(x)*/: PolyHolder/*->example::PolyHolder#*/ { def foo/*<-local9*/[T/*<-local7*/](t/*<-local8*/: T/*->local7*/): T/*->local7*/ }) = ???/*->scala::Predef.`???`().*/
11+
def m5/*<-example::RecOrRefined$package.m5().*/[Z/*<-example::RecOrRefined$package.m5().[Z]*/](x/*<-example::RecOrRefined$package.m5().(x)*/: Int/*->scala::Int#*/): PolyHolder/*->example::PolyHolder#*/ { def foo/*<-local12*/[T/*<-local10*/](t/*<-local11*/: T/*->local10*/): T/*->local10*/ } = ???/*->scala::Predef.`???`().*/
1212

13-
type m6/*<-example::RecOrRefined$package.m6#*/ = [X/*<-example::RecOrRefined$package.m6#[X]*/] =>> PolyHolder/*->example::PolyHolder#*/ { def foo/*<-local14*/[T/*<-local12*/](t/*<-local13*/: T/*->local12*/): T/*->local12*/ }
13+
type m6/*<-example::RecOrRefined$package.m6#*/ = [X/*<-example::RecOrRefined$package.m6#[X]*/] =>> PolyHolder/*->example::PolyHolder#*/ { def foo/*<-local15*/[T/*<-local13*/](t/*<-local14*/: T/*->local13*/): T/*->local13*/ }
1414

1515
class Record/*<-example::Record#*/(elems/*<-example::Record#elems.*/: (String/*->scala::Predef.String#*/, Any/*->scala::Any#*/)*) extends Selectable/*->scala::Selectable#*/:
1616
private val fields/*<-example::Record#fields.*/ = elems/*->example::Record#elems.*/.toMap/*->scala::collection::IterableOnceOps#toMap().*/
1717
def selectDynamic/*<-example::Record#selectDynamic().*/(name/*<-example::Record#selectDynamic().(name)*/: String/*->scala::Predef.String#*/): Any/*->scala::Any#*/ = fields/*->example::Record#fields.*/(name/*->example::Record#selectDynamic().(name)*/)
1818

1919
type Person/*<-example::RecOrRefined$package.Person#*/ = Record/*->example::Record#*/ {
20-
val name/*<-local15*/: String/*->scala::Predef.String#*/
21-
val age/*<-local16*/: Int/*->scala::Int#*/
20+
val name/*<-local16*/: String/*->scala::Predef.String#*/
21+
val age/*<-local17*/: Int/*->scala::Int#*/
2222
}
2323

2424
// RecType
2525
class C/*<-example::C#*/ { type T1/*<-example::C#T1#*/; type T2/*<-example::C#T2#*/ }
26-
type C2/*<-example::RecOrRefined$package.C2#*/ = C/*->example::C#*/ { type T1/*<-local17*/; type T2/*<-local18*/ = T1/*->local17*/ }
26+
type C2/*<-example::RecOrRefined$package.C2#*/ = C/*->example::C#*/ { type T1/*<-local18*/; type T2/*<-local19*/ = T1/*->local18*/ }
2727

2828
trait SpecialRefinement/*<-example::SpecialRefinement#*/ {
29-
def pickOne/*<-example::SpecialRefinement#pickOne().*/(as/*<-example::SpecialRefinement#pickOne().(as)*/: String/*->scala::Predef.String#*/*): Option/*->scala::Option#*/[Any/*->scala::Any#*/]
29+
def pickOne/*<-example::SpecialRefinement#pickOne().*/[T/*<-example::SpecialRefinement#pickOne().[T]*/](as/*<-example::SpecialRefinement#pickOne().(as)*/: T/*->example::SpecialRefinement#pickOne().[T]*/*): Option/*->scala::Option#*/[Any/*->scala::Any#*/]
3030
}
3131

32-
class PickOneRefinement_1/*<-example::PickOneRefinement_1#*/[S/*<-example::PickOneRefinement_1#[S]*/ <: SpecialRefinement { def pickOne(as: String*): Option[String] }] {
32+
class PickOneRefinement_1/*<-example::PickOneRefinement_1#*/[S/*<-example::PickOneRefinement_1#[S]*/ <: SpecialRefinement { def pickOne[T](as: T*): Option[String] }] {
3333
def run/*<-example::PickOneRefinement_1#run().*/(s/*<-example::PickOneRefinement_1#run().(s)*/: S/*->example::PickOneRefinement_1#[S]*/, as/*<-example::PickOneRefinement_1#run().(as)*/: String/*->scala::Predef.String#*/*): Option/*->scala::Option#*/[String/*->scala::Predef.String#*/] = s/*->example::PickOneRefinement_1#run().(s)*/.pickOne/*->example::SpecialRefinement#pickOne().*/(as/*->example::PickOneRefinement_1#run().(as)*/:_*)
3434
}

tests/semanticdb/expect/RecOrRefined.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ class C { type T1; type T2 }
2626
type C2 = C { type T1; type T2 = T1 }
2727

2828
trait SpecialRefinement {
29-
def pickOne(as: String*): Option[Any]
29+
def pickOne[T](as: T*): Option[Any]
3030
}
3131

32-
class PickOneRefinement_1[S <: SpecialRefinement { def pickOne(as: String*): Option[String] }] {
32+
class PickOneRefinement_1[S <: SpecialRefinement { def pickOne[T](as: T*): Option[String] }] {
3333
def run(s: S, as: String*): Option[String] = s.pickOne(as:_*)
3434
}

0 commit comments

Comments
 (0)