Skip to content

Commit 98604b3

Browse files
tanishikingtgodzik
authored andcommitted
Add Singature information for Semanticdb
Reset local symbol index for each TextDocument, updateExpect PrettyPrint signature and update metac.expect Integrate SymbolInformationOps into Scala3#SymbolOps Model WithType for AndType #12885 (comment) Resolve ParamRef by constructing SymbolTable To construct symbol table before referring the ParamRef it's required to traverse the child trees before registering the symbol. Lookup symbols for refinements in RefinedType and RecType Re-insert assertion to localIdx Previously, there were the risks that localIdx receives the symbol that doens't have `span` because `TypeOps` generates dummy symbols for refinements in `RefinedType` and `RecType`. However, with the following commits, 7dd91ad 226e26f now we never generate dummy symbol in `TypeOps`. So re-insert the assertion we deleted when copying this method from `ExtractSemanticDB`. see: https://github.com/lampepfl/dotty/pull/12885/files#r658150249 Convert AndType to IntersectionType Refactor enterRefined Refactor: move all extension (of Symbol) method into Scala3 Don't add type parameters as parameters to MethodSignature Refactor not to use isInstanceOf for designator of TypeRef and TermRef Use intersection type for the parent of RefinedType Convert wildcard type as ExistentialType For wildcard type `C[_ <: T]`, it's internal type representation will be `AppliedType(TypeBounds(lo = <Nothing>, hi = <T>))`. As scalameta for Scala2 does, we'll convert the wildcard type to `ExistentialType(TypeRef(NoPrefix, C, <local0>), Scope(hardlinks = List(<local0>)))` where `<local0>` has - display_name: "_" and, - signature: type_signature(..., lo = <Nothing>, hi = <T>) See: https://github.com/lampepfl/dotty/pull/12885/files#r663797616 https://scalameta.org/docs/semanticdb/specification.html#type-2 Now, when we compile the following Scala program to semanticdb ```scala class Wildcards { def e1: List[_ <: Int] = ??? } ``` The semanticdb's SymbolInformation for `e1` looks like: From scala3 ``` symbols { symbol: "advanced/Wildcards#e1()." kind: METHOD display_name: "e1" language: SCALA signature { value_signature { tpe { by_name_type { tpe { existential_type { tpe { type_ref { symbol: "scala/collection/immutable/List#" type_arguments { type_ref { symbol: "local0" } } } } declarations { hardlinks { symbol: "local0" kind: TYPE display_name: "_" language: SCALA signature { type_signature { type_parameters { } lower_bound { type_ref { symbol: "scala/Nothing#" } } upper_bound { type_ref { symbol: "scala/Int#" } } } } } } } } } } } } } ``` On the other hand, generated from scalameta's metac with scalac 2.13.6 ```sh $ metac --version Scala compiler version 2.13.6 -- Copyright 2002-2021, LAMP/EPFL and Lightbend, Inc. ``` ``` symbols { symbol: "advanced/Wildcards#e()." kind: METHOD display_name: "e" language: SCALA signature { method_signature { type_parameters { } return_type { existential_type { tpe { type_ref { symbol: "scala/package.List#" type_arguments { type_ref { symbol: "local0" } } } } declarations { hardlinks { symbol: "local0" kind: TYPE properties: 4 display_name: "_" language: SCALA signature { type_signature { type_parameters { } lower_bound { type_ref { symbol: "scala/Nothing#" } } upper_bound { type_ref { symbol: "scala/Int#" } } } } access { public_access { } } } } } } } } access { public_access { } } } ``` Use finalResultType for MethodSignature to get actual return type. Register the symbol of nested method with "actual" binder For example: `def foo(x: T)(y: T): T` and for `<y>.owner.info` would be like `MethodType(...<x>, resType = MethodType(...<y>, resType = <T>))`. (Let's say the outer `MethodType` "outer", and `MethodType` who is `resType` of outer "inner") Before this commit, we register <y> to the symbol table with `(<y>, outer)`, which should be `(<y>, inner)`. For such a nested method signature, we have to find the "actual" binder for parameters and register them to the symbol table. Remove unused parameter sym from toSemanticType Fix pprint issue for SingleType When the prefix of SingleType is Type.Emtpy, we had been printing them as `<?>.sym.type`, but it should be `sym.type` Convert symbols to local index for funParamSymbol Refactor style of if Co-authored-by: Jamie Thompson <[email protected]> Fix printing upper type bounds Add evidence params to SemanticDB Add refinements to RefinedType generated by opaque types Fix empty refinement for RefinedType for the result of polymorphic method Print definition of ExistentialType instead of displaySymbol Update comment Co-authored-by: Jamie Thompson <[email protected]> None for empty decls Warn if symbol lookup failed for paramRef and RefinedType Workaround symbol not found for higher kinded type param Suppress warning for known issue of exporting Polymorphic type Support multiple type param clauses for extension method By combining two type param clause into one Exclude synthetic symbols from occurrences Fallback to Type.member for refinements who can't access to the tree For example, ```scala trait SpecialRefinement { def pickOne(as: String*): Option[Any] } class PickOneRefinement_1[S <: SpecialRefinement { def pickOne(as: String*): Option[String] }] { def run(s: S, as: String*): Option[String] = s.pickOne(as:_*) } ``` In the typed AST, the SpecialRefinement is inside of the TypeTree and cannot access to the refinement (pickOne) from tree, therefore we can't register the symbol of pickOne to symbol table. In this case, fallback to `Type.member` to find the symbol of `pickOne`. Fallback to Type.member for ParamRef Workaround symbol not found for HKTypeLambda in upper bounds and fix type for curried applied type Remove unnecessary comment Do not create newSymbol for wildcard type symbol instead, create a proxy data that will be converted to semanticdb symbol who represents wildcard symbol Warn if unexpected type appear while converting type to SemanticDB type Dealias LazyRef while converting types to SemanticDB Do not emit warning for unexpected type Because there could be an unexpected types for incompilable sources and if we show the warning for uncompilable sources, it could be confusing. Do not create a newSymbol for ParamRef Make wildcard type symbol global Hardlink fake symbols Excude symbols that doesn't present in source from occurrence Make namePresenInSource safe for IndexOutOfRange Make package objects present in source Fallback to fake symbol for refinements in RefinedType of upper bound see: #12885 (comment) #12885 (comment) Add occurrences of secondary constructors Add fakeSymbols to symbol section and don't hardlink fake syms Convert tp <:< FromJavaObject to tp <:< Any Do not add wildcard symbol of existential type to symbol section Refactor styles
1 parent 6b8afe7 commit 98604b3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+3501
-2229
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package dotty.tools
2+
package dotc
3+
package semanticdb
4+
5+
import dotty.tools.dotc.{semanticdb => s}
6+
7+
import core.Contexts.Context
8+
import core.Constants._
9+
10+
object ConstantOps:
11+
extension (const: Constant)
12+
def toSemanticConst(using Context): s.Constant = const.tag match {
13+
case UnitTag => s.UnitConstant()
14+
case BooleanTag => s.BooleanConstant(const.booleanValue)
15+
case ByteTag => s.ByteConstant(const.byteValue)
16+
case ShortTag => s.ShortConstant(const.shortValue)
17+
case CharTag => s.CharConstant(const.charValue)
18+
case IntTag => s.IntConstant(const.intValue)
19+
case LongTag => s.LongConstant(const.longValue)
20+
case FloatTag => s.FloatConstant(const.floatValue)
21+
case DoubleTag => s.DoubleConstant(const.doubleValue)
22+
case StringTag => s.StringConstant(const.stringValue)
23+
case NullTag => s.NullConstant()
24+
case _ => throw new Error(s"Constant ${const} can't be converted to Semanticdb Constant.")
25+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package dotty.tools.dotc.semanticdb
2+
3+
import java.lang.System.{lineSeparator => EOL}
4+
import dotty.tools.dotc.semanticdb.{Descriptor => d}
5+
6+
class DescriptorParser(s: String) {
7+
var i = s.length
8+
def fail() = {
9+
val message = "invalid symbol format"
10+
val caret = " " * i + "^"
11+
sys.error(s"$message$EOL$s$EOL$caret")
12+
}
13+
14+
val BOF = '\u0000'
15+
val EOF = '\u001A'
16+
var currChar = EOF
17+
def readChar(): Char = {
18+
if (i <= 0) {
19+
if (i == 0) {
20+
i -= 1
21+
currChar = BOF
22+
currChar
23+
} else {
24+
fail()
25+
}
26+
} else {
27+
i -= 1
28+
currChar = s(i)
29+
currChar
30+
}
31+
}
32+
33+
def parseValue(): String = {
34+
if (currChar == '`') {
35+
val end = i
36+
while (readChar() != '`') {}
37+
readChar()
38+
s.substring(i + 2, end)
39+
} else {
40+
val end = i + 1
41+
if (!Character.isJavaIdentifierPart(currChar)) fail()
42+
while (Character.isJavaIdentifierPart(readChar()) && currChar != BOF) {}
43+
s.substring(i + 1, end)
44+
}
45+
}
46+
47+
def parseDisambiguator(): String = {
48+
val end = i + 1
49+
if (currChar != ')') fail()
50+
while (readChar() != '(') {}
51+
readChar()
52+
s.substring(i + 1, end)
53+
}
54+
55+
def parseDescriptor(): Descriptor = {
56+
if (currChar == '.') {
57+
readChar()
58+
if (currChar == ')') {
59+
val disambiguator = parseDisambiguator()
60+
val value = parseValue()
61+
d.Method(value, disambiguator)
62+
} else {
63+
d.Term(parseValue())
64+
}
65+
} else if (currChar == '#') {
66+
readChar()
67+
d.Type(parseValue())
68+
} else if (currChar == '/') {
69+
readChar()
70+
d.Package(parseValue())
71+
} else if (currChar == ')') {
72+
readChar()
73+
val value = parseValue()
74+
if (currChar != '(') fail()
75+
else readChar()
76+
d.Parameter(value)
77+
} else if (currChar == ']') {
78+
readChar()
79+
val value = parseValue()
80+
if (currChar != '[') fail()
81+
else readChar()
82+
d.TypeParameter(value)
83+
} else {
84+
fail()
85+
}
86+
}
87+
88+
def entryPoint(): (Descriptor, String) = {
89+
readChar()
90+
val desc = parseDescriptor()
91+
(desc, s.substring(0, i + 1))
92+
}
93+
}
94+
95+
object DescriptorParser {
96+
def apply(symbol: String): (Descriptor, String) = {
97+
val parser = new DescriptorParser(symbol)
98+
parser.entryPoint()
99+
}
100+
}
101+
102+
sealed trait Descriptor {
103+
def isNone: Boolean = this == d.None
104+
def isTerm: Boolean = this.isInstanceOf[d.Term]
105+
def isMethod: Boolean = this.isInstanceOf[d.Method]
106+
def isType: Boolean = this.isInstanceOf[d.Type]
107+
def isPackage: Boolean = this.isInstanceOf[d.Package]
108+
def isParameter: Boolean = this.isInstanceOf[d.Parameter]
109+
def isTypeParameter: Boolean = this.isInstanceOf[d.TypeParameter]
110+
def value: String
111+
}
112+
object Descriptor {
113+
case object None extends Descriptor { def value: String = "" }
114+
final case class Term(value: String) extends Descriptor
115+
final case class Method(value: String, disambiguator: String) extends Descriptor
116+
final case class Type(value: String) extends Descriptor
117+
final case class Package(value: String) extends Descriptor
118+
final case class Parameter(value: String) extends Descriptor
119+
final case class TypeParameter(value: String) extends Descriptor
120+
}

0 commit comments

Comments
 (0)