Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SemanticDB]Support new Scala3 modifiers in SemanticDB #13239

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ class ExtractSemanticDB extends Phase:
props |= SymbolInformation.Property.FINAL.value
if sym.is(Sealed) then
props |= SymbolInformation.Property.SEALED.value
if sym.isOneOf(GivenOrImplicit) then
Copy link
Member Author

@tanishiking tanishiking Aug 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be better to keep implicit property for givens for backward compatibility, and remove it may be in the next minor version release of Scala3?
(Or we can go because I suppose there are quite a few consumers for this information: probably only metals? and it's controllable)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We tried that already, but it turned out that it was overall simplest the way it is now.

if sym.is(Implicit) then
props |= SymbolInformation.Property.IMPLICIT.value
if sym.is(Lazy, butNot=Module) then
props |= SymbolInformation.Property.LAZY.value
Expand All @@ -449,6 +449,20 @@ class ExtractSemanticDB extends Phase:
props |= SymbolInformation.Property.STATIC.value
if sym.is(Enum) then
props |= SymbolInformation.Property.ENUM.value
if sym.is(Given) then
props |= SymbolInformation.Property.GIVEN.value
if sym.is(Inline) then
props |= SymbolInformation.Property.INLINE.value
if sym.is(Open) then
props |= SymbolInformation.Property.OPEN.value
if sym.is(Open) then
props |= SymbolInformation.Property.OPEN.value
if sym.is(Transparent) then
props |= SymbolInformation.Property.TRANSPARENT.value
if sym.is(Infix) then
props |= SymbolInformation.Property.INFIX.value
if sym.is(Opaque) then
props |= SymbolInformation.Property.OPAQUE.value
props

private def symbolAccess(sym: Symbol, kind: SymbolInformation.Kind)(using Context): Access =
Expand Down
6 changes: 6 additions & 0 deletions compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,12 @@ object Scala3:
def isStatic: Boolean = (info.properties & SymbolInformation.Property.STATIC.value) != 0
def isEnum: Boolean = (info.properties & SymbolInformation.Property.ENUM.value) != 0
def isDefault: Boolean = (info.properties & SymbolInformation.Property.DEFAULT.value) != 0
def isGiven: Boolean = (info.properties & SymbolInformation.Property.GIVEN.value) != 0
def isInline: Boolean = (info.properties & SymbolInformation.Property.INLINE.value) != 0
def isOpen: Boolean = (info.properties & SymbolInformation.Property.OPEN.value) != 0
def isTransparent: Boolean = (info.properties & SymbolInformation.Property.TRANSPARENT.value) != 0
def isInfix: Boolean = (info.properties & SymbolInformation.Property.INFIX.value) != 0
def isOpaque: Boolean = (info.properties & SymbolInformation.Property.OPAQUE.value) != 0

def isUnknownKind: Boolean = info.kind.isUnknownKind
def isLocal: Boolean = info.kind.isLocal
Expand Down
56 changes: 55 additions & 1 deletion compiler/src/dotty/tools/dotc/semanticdb/SymbolInformation.scala
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,12 @@ object SymbolInformation extends SemanticdbGeneratedMessageCompanion[dotty.tool
def isPrimary: _root_.scala.Boolean = false
def isEnum: _root_.scala.Boolean = false
def isDefault: _root_.scala.Boolean = false
def isGiven: _root_.scala.Boolean = false
def isInline: _root_.scala.Boolean = false
def isOpen: _root_.scala.Boolean = false
def isTransparent: _root_.scala.Boolean = false
def isInfix: _root_.scala.Boolean = false
def isOpaque: _root_.scala.Boolean = false

final def asRecognized: _root_.scala.Option[dotty.tools.dotc.semanticdb.SymbolInformation.Property.Recognized] = if (isUnrecognized) _root_.scala.None else _root_.scala.Some(this.asInstanceOf[dotty.tools.dotc.semanticdb.SymbolInformation.Property.Recognized])
}
Expand Down Expand Up @@ -549,10 +555,52 @@ object SymbolInformation extends SemanticdbGeneratedMessageCompanion[dotty.tool
override def isDefault: _root_.scala.Boolean = true
}

@SerialVersionUID(0L)
case object GIVEN extends Property(65536) with Property.Recognized {
val index = 15
val name = "GIVEN"
override def isGiven: _root_.scala.Boolean = true
}

@SerialVersionUID(0L)
case object INLINE extends Property(131072) with Property.Recognized {
val index = 16
val name = "INLINE"
override def isInline: _root_.scala.Boolean = true
}

@SerialVersionUID(0L)
case object OPEN extends Property(262144) with Property.Recognized {
val index = 17
val name = "OPEN"
override def isOpen: _root_.scala.Boolean = true
}

@SerialVersionUID(0L)
case object TRANSPARENT extends Property(524288) with Property.Recognized {
val index = 18
val name = "TRANSPARENT"
override def isTransparent: _root_.scala.Boolean = true
}

@SerialVersionUID(0L)
case object INFIX extends Property(1048576) with Property.Recognized {
val index = 19
val name = "INFIX"
override def isInfix: _root_.scala.Boolean = true
}

@SerialVersionUID(0L)
case object OPAQUE extends Property(2097152) with Property.Recognized {
val index = 20
val name = "OPAQUE"
override def isOpaque: _root_.scala.Boolean = true
}

@SerialVersionUID(0L)
final case class Unrecognized(unrecognizedValue: _root_.scala.Int) extends Property(unrecognizedValue) with SemanticdbUnrecognizedEnum

lazy val values = scala.collection.immutable.Seq(UNKNOWN_PROPERTY, ABSTRACT, FINAL, SEALED, IMPLICIT, LAZY, CASE, COVARIANT, CONTRAVARIANT, VAL, VAR, STATIC, PRIMARY, ENUM, DEFAULT)
lazy val values = scala.collection.immutable.Seq(UNKNOWN_PROPERTY, ABSTRACT, FINAL, SEALED, IMPLICIT, LAZY, CASE, COVARIANT, CONTRAVARIANT, VAL, VAR, STATIC, PRIMARY, ENUM, DEFAULT, GIVEN, INLINE, OPEN, TRANSPARENT, INFIX, OPAQUE)
def fromValue(__value: _root_.scala.Int): Property = __value match {
case 0 => UNKNOWN_PROPERTY
case 4 => ABSTRACT
Expand All @@ -569,6 +617,12 @@ object SymbolInformation extends SemanticdbGeneratedMessageCompanion[dotty.tool
case 8192 => PRIMARY
case 16384 => ENUM
case 32768 => DEFAULT
case 65536 => GIVEN
case 131072 => INLINE
case 262144 => OPEN
case 524288 => TRANSPARENT
case 1048576 => INFIX
case 2097152 => OPAQUE
case __other => Unrecognized(__other)
}

Expand Down
6 changes: 6 additions & 0 deletions compiler/src/dotty/tools/dotc/semanticdb/Tools.scala
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ object Tools:
if info.isPrimary then sb.append("primary ")
if info.isEnum then sb.append("enum ")
if info.isDefault then sb.append("default ")
if info.isGiven then sb.append("given ")
if info.isInline then sb.append("inline ")
if info.isOpen then sb.append("open ")
if info.isTransparent then sb.append("transparent ")
if info.isInfix then sb.append("infix ")
if info.isOpaque then sb.append("opaque ")
info.kind match
case LOCAL => sb.append("local ")
case FIELD => sb.append("field ")
Expand Down
64 changes: 32 additions & 32 deletions tests/semanticdb/metac.expect
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ Occurrences => 5 entries
Symbols:
angiven/AnonymousGiven$package. => final package object angiven
angiven/AnonymousGiven$package.bar(). => method bar
angiven/AnonymousGiven$package.bar().(x$1) => implicit param x$1
angiven/AnonymousGiven$package.bar().(x$1) => given param x$1
angiven/Foo# => trait Foo
angiven/Foo#`<init>`(). => primary ctor <init>

Expand Down Expand Up @@ -437,7 +437,7 @@ classes/C10#s. => private[this] val method s
classes/C11# => class C11
classes/C11#`<init>`(). => primary ctor <init>
classes/C11#foo(). => macro foo
classes/C11#foo(). => macro foo
classes/C11#foo(). => inline macro foo
classes/C12# => class C12
classes/C12#Context# => class Context
classes/C12#Context#Expr# => type Expr
Expand Down Expand Up @@ -935,7 +935,7 @@ _empty_/Enums.Suits.Clubs. => case val static enum method Clubs
_empty_/Enums.Suits.Diamonds. => case val static enum method Diamonds
_empty_/Enums.Suits.Hearts. => case val static enum method Hearts
_empty_/Enums.Suits.Spades. => case val static enum method Spades
_empty_/Enums.Suits.derived$CanEqual. => implicit lazy val method derived$CanEqual
_empty_/Enums.Suits.derived$CanEqual. => lazy val given method derived$CanEqual
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really given? Can they be lazy?

Suggested change
_empty_/Enums.Suits.derived$CanEqual. => lazy val given method derived$CanEqual
_empty_/Enums.Suits.derived$CanEqual. => lazy val given method derived$CanEqual

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is actually Given. This symbol is automatically generated given value by drives CanEqual

enum Suits derives CanEqual:
  case Hearts, Spades, Clubs, Diamonds

// `drives CanEuqual` will automatically generate given instance something like
lazy given val derived$CanEqual: CanEqual[Enums.Suits, Enums.Suits] = 
   CanEqual.derived

https://dotty.epfl.ch/docs/reference/contextual/derivation.html

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, parameterless givens are mapped to lazyvals by default. Some of them are mapped to defs when we can prove that that does not change semantics, so that we can omit generating a field.

_empty_/Enums.Suits.fromOrdinal(). => method fromOrdinal
_empty_/Enums.Suits.fromOrdinal().(ordinal) => param ordinal
_empty_/Enums.Suits.isBlack(). => method isBlack
Expand Down Expand Up @@ -994,13 +994,13 @@ _empty_/Enums.`<:<`.Refl.toString(). => method toString
_empty_/Enums.`<:<`.Refl.unapply(). => method unapply
_empty_/Enums.`<:<`.Refl.unapply().(x$1) => param x$1
_empty_/Enums.`<:<`.Refl.unapply().[C] => typeparam C
_empty_/Enums.`<:<`.`given_<:<_T_T`(). => final implicit method given_<:<_T_T
_empty_/Enums.`<:<`.`given_<:<_T_T`(). => final given method given_<:<_T_T
_empty_/Enums.`<:<`.`given_<:<_T_T`().[T] => typeparam T
_empty_/Enums.`<:<`.fromOrdinal(). => method fromOrdinal
_empty_/Enums.`<:<`.fromOrdinal().(ordinal) => param ordinal
_empty_/Enums.some1. => val method some1
_empty_/Enums.unwrap(). => method unwrap
_empty_/Enums.unwrap().(ev) => implicit param ev
_empty_/Enums.unwrap().(ev) => given param ev
_empty_/Enums.unwrap().(opt) => param opt
_empty_/Enums.unwrap().[A] => typeparam A
_empty_/Enums.unwrap().[B] => typeparam B
Expand Down Expand Up @@ -1445,16 +1445,16 @@ a/b/Givens.Monoid#combine().(x) => param x
a/b/Givens.Monoid#combine().(y) => param y
a/b/Givens.Monoid#empty(). => abstract method empty
a/b/Givens.foo(). => method foo
a/b/Givens.foo().(A) => implicit param A
a/b/Givens.foo().(A) => given param A
a/b/Givens.foo().[A] => typeparam A
a/b/Givens.given_Monoid_String. => final implicit object given_Monoid_String
a/b/Givens.given_Monoid_String. => final given object given_Monoid_String
a/b/Givens.given_Monoid_String.combine(). => method combine
a/b/Givens.given_Monoid_String.combine().(x) => param x
a/b/Givens.given_Monoid_String.combine().(y) => param y
a/b/Givens.given_Monoid_String.empty(). => method empty
a/b/Givens.goodbye1. => val method goodbye1
a/b/Givens.hello1. => val method hello1
a/b/Givens.int2String(). => final implicit macro int2String
a/b/Givens.int2String(). => final given inline macro int2String
a/b/Givens.sayGoodbye(). => method sayGoodbye
a/b/Givens.sayGoodbye().(any) => param any
a/b/Givens.sayGoodbye().[B] => typeparam B
Expand Down Expand Up @@ -1748,37 +1748,37 @@ Occurrences => 72 entries

Symbols:
givens/InventedNames$package. => final package object givens
givens/InventedNames$package.`* *`. => final implicit lazy val method * *
givens/InventedNames$package.`* *`. => final lazy val given method * *
givens/InventedNames$package.a. => val method a
givens/InventedNames$package.b. => val method b
givens/InventedNames$package.c. => val method c
givens/InventedNames$package.d. => val method d
givens/InventedNames$package.e. => val method e
givens/InventedNames$package.f. => val method f
givens/InventedNames$package.g. => val method g
givens/InventedNames$package.given_Char. => final implicit lazy val method given_Char
givens/InventedNames$package.given_Double(). => final implicit method given_Double
givens/InventedNames$package.given_Double().(x$1) => implicit param x$1
givens/InventedNames$package.given_Float. => final implicit lazy val method given_Float
givens/InventedNames$package.given_List_T(). => final implicit method given_List_T
givens/InventedNames$package.given_Char. => final lazy val given method given_Char
givens/InventedNames$package.given_Double(). => final given method given_Double
givens/InventedNames$package.given_Double().(x$1) => given param x$1
givens/InventedNames$package.given_Float. => final lazy val given method given_Float
givens/InventedNames$package.given_List_T(). => final given method given_List_T
givens/InventedNames$package.given_List_T().[T] => typeparam T
givens/InventedNames$package.given_String. => final implicit lazy val method given_String
givens/InventedNames$package.given_X. => final implicit object given_X
givens/InventedNames$package.given_String. => final lazy val given method given_String
givens/InventedNames$package.given_X. => final given object given_X
givens/InventedNames$package.given_X.doX(). => method doX
givens/InventedNames$package.given_Y# => class given_Y
givens/InventedNames$package.given_Y#`<init>`(). => primary ctor <init>
givens/InventedNames$package.given_Y#`<init>`().(x$1) => implicit val param x$1
givens/InventedNames$package.given_Y#`<init>`().(x$1) => val given param x$1
givens/InventedNames$package.given_Y#doY(). => method doY
givens/InventedNames$package.given_Y#x$1. => protected implicit val method x$1
givens/InventedNames$package.given_Y(). => final implicit method given_Y
givens/InventedNames$package.given_Y().(x$1) => implicit param x$1
givens/InventedNames$package.given_Y#x$1. => protected val given method x$1
givens/InventedNames$package.given_Y(). => final given method given_Y
givens/InventedNames$package.given_Y().(x$1) => given param x$1
givens/InventedNames$package.given_Z_T# => class given_Z_T
givens/InventedNames$package.given_Z_T#[T] => typeparam T
givens/InventedNames$package.given_Z_T#`<init>`(). => primary ctor <init>
givens/InventedNames$package.given_Z_T#doZ(). => method doZ
givens/InventedNames$package.given_Z_T(). => final implicit method given_Z_T
givens/InventedNames$package.given_Z_T(). => final given method given_Z_T
givens/InventedNames$package.given_Z_T().[T] => typeparam T
givens/InventedNames$package.intValue. => final implicit lazy val method intValue
givens/InventedNames$package.intValue. => final lazy val given method intValue
givens/InventedNames$package.x. => val method x
givens/InventedNames$package.y. => val method y
givens/InventedNames$package.z. => val method z
Expand Down Expand Up @@ -2575,8 +2575,8 @@ Occurrences => 4 entries

Symbols:
_empty_/NewModifiers. => final object NewModifiers
_empty_/NewModifiers.A# => type A
_empty_/NewModifiers.foo. => val method foo
_empty_/NewModifiers.A# => opaque type A
_empty_/NewModifiers.foo. => val inline method foo

Occurrences:
[0:7..0:19): NewModifiers <- _empty_/NewModifiers.
Expand Down Expand Up @@ -3574,8 +3574,8 @@ Occurrences => 12 entries

Symbols:
inlinedefs/FakePredef. => final object FakePredef
inlinedefs/FakePredef.assert(). => final macro assert
inlinedefs/FakePredef.assert().(assertion) => param assertion
inlinedefs/FakePredef.assert(). => final inline transparent macro assert
inlinedefs/FakePredef.assert().(assertion) => inline param assertion

Occurrences:
[0:8..0:18): inlinedefs <- inlinedefs/
Expand Down Expand Up @@ -3637,9 +3637,9 @@ local5 => val local Nat_this
local6 => val local Nat_this
recursion/Nats. => final object Nats
recursion/Nats.Nat# => sealed trait Nat
recursion/Nats.Nat#`++`(). => macro ++
recursion/Nats.Nat#`+`(). => macro +
recursion/Nats.Nat#`+`().(that) => param that
recursion/Nats.Nat#`++`(). => inline transparent macro ++
recursion/Nats.Nat#`+`(). => inline transparent macro +
recursion/Nats.Nat#`+`().(that) => inline param that
recursion/Nats.Nat#`<init>`(). => primary ctor <init>
recursion/Nats.Succ# => case class Succ
recursion/Nats.Succ#[N] => typeparam N
Expand All @@ -3662,8 +3662,8 @@ recursion/Nats.Succ.unapply().(x$1) => param x$1
recursion/Nats.Succ.unapply().[N] => typeparam N
recursion/Nats.Zero. => final case object Zero
recursion/Nats.j31. => val method j31
recursion/Nats.toIntg(). => macro toIntg
recursion/Nats.toIntg().(n) => param n
recursion/Nats.toIntg(). => inline transparent macro toIntg
recursion/Nats.toIntg().(n) => inline param n

Occurrences:
[1:8..1:17): recursion <- recursion/
Expand Down Expand Up @@ -4385,7 +4385,7 @@ _empty_/MyProgram#main().(args) => param args
_empty_/toplevel$package. => final package object _empty_
_empty_/toplevel$package.MyProgram(). => method MyProgram
_empty_/toplevel$package.MyProgram().(times) => param times
_empty_/toplevel$package.a. => val method a
_empty_/toplevel$package.a. => val inline method a
_empty_/toplevel$package.combine(). => method combine
_empty_/toplevel$package.combine().(x) => param x
_empty_/toplevel$package.combine().(y) => param y
Expand Down