Skip to content

Commit

Permalink
Lookup symbols for refinements in RefinedType and RecType
Browse files Browse the repository at this point in the history
  • Loading branch information
tanishiking committed Jun 29, 2021
1 parent 7dd91ad commit 226e26f
Show file tree
Hide file tree
Showing 9 changed files with 372 additions and 174 deletions.
71 changes: 55 additions & 16 deletions compiler/src/dotty/tools/dotc/semanticdb/TypeOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import core.Types._
import core.Annotations.Annotation
import core.Flags
import core.Names.Name
import core.StdNames.tpnme
import ast.tpd._

import collection.mutable
Expand All @@ -16,29 +17,69 @@ import dotty.tools.dotc.{semanticdb => s}

class TypeOps:
import SymbolScopeOps._
private val symtab = mutable.Map[(LambdaType, Name), Symbol]()
private val paramRefSymtab = mutable.Map[(LambdaType, Name), Symbol]()
private val refinementSymtab = mutable.Map[(RefinedType, Name), Symbol]()
given typeOps: TypeOps = this
extension (tpe: Type)
def toSemanticSig(using LinkMode, Context, SemanticSymbolBuilder)(sym: Symbol): s.Signature =

def enter(keyTpe: Type): Unit =
keyTpe match {
def enterParamRef(tpe: Type): Unit =
tpe match {
case lam: LambdaType =>
symtab((lam, sym.name)) = sym
paramRefSymtab((lam, sym.name)) = sym

// for class constructor
// class C[T] { ... }
case cls: ClassInfo if sym.info.isInstanceOf[LambdaType] =>
val lam = sym.info.asInstanceOf[LambdaType]
cls.cls.typeParams.foreach { param =>
symtab((lam, param.name)) = param
paramRefSymtab((lam, param.name)) = param
}

// type X[T] = ...
case tb: TypeBounds =>
enter(tb.lo)
enter(tb.hi)
enterParamRef(tb.lo)
enterParamRef(tb.hi)

case _ => ()
}
enter(sym.owner.info)

def enterRefined(tpe: Type): Unit =
tpe match {
case refined: RefinedType =>
val key = (refined, sym.name)
refinementSymtab(key) = sym

case rec: RecType =>
enterRefined(rec.parent)

case cls: ClassInfo
if (cls.cls.name == tpnme.REFINE_CLASS) =>
sym.owner.owner.info match {
// def foo(x: Parent { refinement }) = ...
case refined: RefinedType =>
val key = (refined, sym.name)
refinementSymtab(key) = sym

// type x = Person { refinement }
case tb: TypeBounds =>
// tb = TypeBounds(
// lo = RefinedType(...)
// hi = RefinedType(...)
// )
enterRefined(tb.lo)
enterRefined(tb.hi)

// def s(x: Int): { refinement } = ...
case expr: ExprType =>
enterRefined(expr.resType)
case m: MethodType =>
enterRefined(m.resType)
case _ => ()
}
case _ => ()
}
enterParamRef(sym.owner.info)
enterRefined(sym.owner.info)

def loop(tpe: Type): s.Signature = tpe match {
case mt: MethodType =>
Expand Down Expand Up @@ -67,8 +108,7 @@ class TypeOps:
def tparams(tpe: Type): (Type, List[Symbol]) = tpe match {
case lambda: HKTypeLambda =>
val paramSyms = lambda.paramNames.flatMap { paramName =>
val key = (lambda, paramName)
symtab.get(key)
paramRefSymtab.get((lambda, paramName))
}
(lambda.resType, paramSyms)
case _ => (tpe, Nil)
Expand Down Expand Up @@ -124,7 +164,7 @@ class TypeOps:

case tref: ParamRef =>
val key = (tref.binder, tref.paramName)
symtab.get(key) match {
paramRefSymtab.get(key) match {
case Some(ref) =>
val ssym = ref.symbolName
tref match {
Expand Down Expand Up @@ -182,10 +222,9 @@ class TypeOps:
val (parent, refinedInfos) = flatten(rt, List.empty)
val stpe = s.WithType(flattenParent(parent))

// Create dummy symbols for refinements
// since there's no way to retrieve symbols of refinements from RefinedType at this moment.
val decls = for (name, info) <- refinedInfos
yield newSymbol(sym, name, Flags.EmptyFlags, info)
val decls = refinedInfos.flatMap { (name, _) =>
refinementSymtab.get((rt, name))
}
val sdecls = decls.sscope(using LinkMode.HardlinkChildren)
s.StructuralType(stpe, Some(sdecls))

Expand Down
9 changes: 5 additions & 4 deletions tests/semanticdb/expect/Advanced.expect.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ class C/*<-advanced::C#*/[T/*<-advanced::C#[T]*/] {

class Structural/*<-advanced::Structural#*/ {
def s1/*<-advanced::Structural#s1().*/: { val x/*<-local0*/: Int/*->scala::Int#*/ } = ???/*->scala::Predef.`???`().*/
def s2/*<-advanced::Structural#s2().*/: { val x/*<-local2*/: Int/*->scala::Int#*/ } = new { val x/*<-local3*/: Int/*->scala::Int#*/ = ???/*->scala::Predef.`???`().*/ }
def s3/*<-advanced::Structural#s3().*/: { def m/*<-local8*/(x/*<-local7*/: Int/*->scala::Int#*/): Int/*->scala::Int#*/ } = new { def m/*<-local10*/(x/*<-local9*/: Int/*->scala::Int#*/): Int/*->scala::Int#*/ = ???/*->scala::Predef.`???`().*/ }
def s2/*<-advanced::Structural#s2().*/: { val x/*<-local1*/: Int/*->scala::Int#*/ } = new { val x/*<-local2*/: Int/*->scala::Int#*/ = ???/*->scala::Predef.`???`().*/ }
def s3/*<-advanced::Structural#s3().*/: { def m/*<-local6*/(x/*<-local5*/: Int/*->scala::Int#*/): Int/*->scala::Int#*/ } = new { def m/*<-local8*/(x/*<-local7*/: Int/*->scala::Int#*/): Int/*->scala::Int#*/ = ???/*->scala::Predef.`???`().*/ }
def s4/*<-advanced::Structural#s4().*/(a/*<-advanced::Structural#s4().(a)*/: Int/*->scala::Int#*/): { val x/*<-local11*/: Int/*->scala::Int#*/ } = ???/*->scala::Predef.`???`().*/
}

class Wildcards/*<-advanced::Wildcards#*/ {
Expand All @@ -34,8 +35,8 @@ object Test/*<-advanced::Test.*/ {

{
(???/*->scala::Predef.`???`().*/ : Any/*->scala::Any#*/) match {
case e3/*<-local19*/: List/*->scala::package.List#*/[_] =>
val e3x/*<-local21*/ = e3/*->local19*/.head/*->scala::collection::IterableOps#head().*/
case e3/*<-local12*/: List/*->scala::package.List#*/[_] =>
val e3x/*<-local14*/ = e3/*->local12*/.head/*->scala::collection::IterableOps#head().*/
()
}
}
Expand Down
1 change: 1 addition & 0 deletions tests/semanticdb/expect/Advanced.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class Structural {
def s1: { val x: Int } = ???
def s2: { val x: Int } = new { val x: Int = ??? }
def s3: { def m(x: Int): Int } = new { def m(x: Int): Int = ??? }
def s4(a: Int): { val x: Int } = ???
}

class Wildcards {
Expand Down
1 change: 1 addition & 0 deletions tests/semanticdb/expect/Methods.expect.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class Methods/*<-example::Methods#*/[T/*<-example::Methods#[T]*/] {
def m11/*<-example::Methods#m11(+1).*/(x/*<-example::Methods#m11(+1).(x)*/: Example/*->example::Example.*/.type) = ???/*->scala::Predef.`???`().*/
def m12a/*<-example::Methods#m12a().*/(x/*<-example::Methods#m12a().(x)*/: {}) = ???/*->scala::Predef.`???`().*/
def m12b/*<-example::Methods#m12b().*/(x/*<-example::Methods#m12b().(x)*/: { val x/*<-local0*/: Int/*->scala::Int#*/ }) = ???/*->scala::Predef.`???`().*/
def m12c/*<-example::Methods#m12c().*/(x/*<-example::Methods#m12c().(x)*/: { val x/*<-local1*/: Int/*->scala::Int#*/; def y/*<-local2*/: Int/*->scala::Int#*/ }) = ???/*->scala::Predef.`???`().*/
def m13/*<-example::Methods#m13().*/(x/*<-example::Methods#m13().(x)*/: Int/*->scala::Int#*/ @unchecked/*->scala::unchecked#*/) = ???/*->scala::Predef.`???`().*/
def m15/*<-example::Methods#m15().*/(x/*<-example::Methods#m15().(x)*/: => Int/*->scala::Int#*/) = ???/*->scala::Predef.`???`().*/
def m16/*<-example::Methods#m16().*/(x/*<-example::Methods#m16().(x)*/: Int/*->scala::Int#*/*) = ???/*->scala::Predef.`???`().*/
Expand Down
1 change: 1 addition & 0 deletions tests/semanticdb/expect/Methods.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class Methods[T] {
def m11(x: Example.type) = ???
def m12a(x: {}) = ???
def m12b(x: { val x: Int }) = ???
def m12c(x: { val x: Int; def y: Int }) = ???
def m13(x: Int @unchecked) = ???
def m15(x: => Int) = ???
def m16(x: Int*) = ???
Expand Down
18 changes: 18 additions & 0 deletions tests/semanticdb/expect/RecOrRefined.expect.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package example

def m1/*<-example::RecOrRefined$package.m1().*/(a/*<-example::RecOrRefined$package.m1().(a)*/: Int/*->scala::Int#*/ { val x/*<-local0*/: Int/*->scala::Int#*/ }) = ???/*->scala::Predef.`???`().*/
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.`???`().*/
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.`???`().*/

class Record/*<-example::Record#*/(elems/*<-example::Record#elems.*/: (String/*->scala::Predef.String#*/, Any/*->scala::Any#*/)*) extends Selectable/*->scala::Selectable#*/:
private val fields/*<-example::Record#fields.*/ = elems/*->example::Record#elems.*/.toMap/*->scala::collection::IterableOnceOps#toMap().*//*->scala::`<:<`.refl().*/
def selectDynamic/*<-example::Record#selectDynamic().*/(name/*<-example::Record#selectDynamic().(name)*/: String/*->scala::Predef.String#*/): Any/*->scala::Any#*/ = fields/*->example::Record#fields.*//*->scala::collection::MapOps#apply().*/(name/*->example::Record#selectDynamic().(name)*/)

type Person/*<-example::RecOrRefined$package.Person#*/ = Record/*->example::Record#*/ {
val name/*<-local6*/: String/*->scala::Predef.String#*/
val age/*<-local7*/: Int/*->scala::Int#*/
}

// RecType
class C/*<-example::C#*/ { type T1/*<-example::C#T1#*/; type T2/*<-example::C#T2#*/ }
type C2/*<-example::RecOrRefined$package.C2#*/ = C/*->example::C#*/ { type T1/*<-local8*/; type T2/*<-local9*/ = T1/*->local8*/ }
18 changes: 18 additions & 0 deletions tests/semanticdb/expect/RecOrRefined.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package example

def m1(a: Int { val x: Int }) = ???
def m2(x: { val x: Int; def y: Int }) = ???
def m3(x: { val x: Int; def y: Int; type z }) = ???

class Record(elems: (String, Any)*) extends Selectable:
private val fields = elems.toMap
def selectDynamic(name: String): Any = fields(name)

type Person = Record {
val name: String
val age: Int
}

// RecType
class C { type T1; type T2 }
type C2 = C { type T1; type T2 = T1 }
8 changes: 4 additions & 4 deletions tests/semanticdb/expect/semanticdb-Types.expect.scala
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ object Test/*<-types::Test.*/ {

val compoundType1/*<-types::Test.C#compoundType1.*/: { def k/*<-local0*/: Int/*->scala::Int#*/ } = ???/*->scala::Predef.`???`().*/
val compoundType2/*<-types::Test.C#compoundType2.*/: M/*->types::Test.M#*/ with N/*->types::Test.N#*/ = ???/*->scala::Predef.`???`().*/
val compoundType3/*<-types::Test.C#compoundType3.*/: M/*->types::Test.M#*/ with N/*->types::Test.N#*/ { def k/*<-local2*/: Int/*->scala::Int#*/ } = ???/*->scala::Predef.`???`().*/
val compoundType4/*<-types::Test.C#compoundType4.*/ = new { def k/*<-local4*/: Int/*->scala::Int#*/ = ???/*->scala::Predef.`???`().*/ }
val compoundType3/*<-types::Test.C#compoundType3.*/: M/*->types::Test.M#*/ with N/*->types::Test.N#*/ { def k/*<-local1*/: Int/*->scala::Int#*/ } = ???/*->scala::Predef.`???`().*/
val compoundType4/*<-types::Test.C#compoundType4.*/ = new { def k/*<-local2*/: Int/*->scala::Int#*/ = ???/*->scala::Predef.`???`().*/ }
val compoundType5/*<-types::Test.C#compoundType5.*/ = new M/*->types::Test.M#*/ with N/*->types::Test.N#*/
val compoundType6/*<-types::Test.C#compoundType6.*/ = new M/*->types::Test.M#*/ with N/*->types::Test.N#*/ { def k/*<-local9*/: Int/*->scala::Int#*/ = ???/*->scala::Predef.`???`().*/ }
val compoundType6/*<-types::Test.C#compoundType6.*/ = new M/*->types::Test.M#*/ with N/*->types::Test.N#*/ { def k/*<-local7*/: Int/*->scala::Int#*/ = ???/*->scala::Predef.`???`().*/ }

val annType1/*<-types::Test.C#annType1.*/: T/*->types::T#*/ @ann(42) = ???/*->scala::Predef.`???`().*/
val annType2/*<-types::Test.C#annType2.*/: T/*->types::T#*/ @ann1/*->types::ann1#*/ @ann2/*->types::ann2#*/ = ???/*->scala::Predef.`???`().*/
Expand All @@ -74,7 +74,7 @@ object Test/*<-types::Test.*/ {
val existentialType4/*<-types::Test.C#existentialType4.*/ = Class/*->java::lang::Class#*/.forName/*->java::lang::Class#forName().*/("foo.Bar")

def typeLambda1/*<-types::Test.C#typeLambda1().*/[M/*<-types::Test.C#typeLambda1().[M]*/[_]] = ???/*->scala::Predef.`???`().*/
typeLambda1/*->types::Test.C#typeLambda1().*/[({ type L/*<-local13*/[T/*<-local12*/] = List/*->scala::package.List#*/[T/*->local12*/] })#L]
typeLambda1/*->types::Test.C#typeLambda1().*/[({ type L/*<-local11*/[T/*<-local10*/] = List/*->scala::package.List#*/[T/*->local10*/] })#L]

object ClassInfoType1/*<-types::Test.C#ClassInfoType1.*/
class ClassInfoType2/*<-types::Test.C#ClassInfoType2#*/ extends B/*->types::B#*/ { def x/*<-types::Test.C#ClassInfoType2#x().*/ = 42 }
Expand Down
Loading

0 comments on commit 226e26f

Please sign in to comment.