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

Extract semanticDB for lifted definitions #21856

Merged
merged 3 commits into from
Oct 30, 2024
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
14 changes: 14 additions & 0 deletions compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,14 @@ object ExtractSemanticDB:
|| sym.owner == defn.OpsPackageClass
|| qualifier.exists(excludeQual)

/** This block is created by lifting i.e. EtaExpansion */
private def isProbablyLifted(block: Block)(using Context) =
def isSyntheticDef(t: Tree) =
t match
case t: (ValDef | DefDef) => t.symbol.isSyntheticWithIdent
case _ => false
block.stats.forall(isSyntheticDef)

private def traverseAnnotsOfDefinition(sym: Symbol)(using Context): Unit =
for annot <- sym.annotations do
if annot.tree.span.exists
Expand Down Expand Up @@ -438,6 +446,12 @@ object ExtractSemanticDB:
registerUseGuarded(None, sym, tree.span, tree.source)
case _ => ()

// If tree is lifted, ignore Synthetic status on all the definitions and traverse all childrens
case tree: Block if isProbablyLifted(tree) =>
tree.stats.foreach:
case t: (ValDef | DefDef) if !excludeChildren(t.symbol) => traverseChildren(t)
case _ => ()
traverse(tree.expr)

case _ =>
traverseChildren(tree)
Expand Down
13 changes: 3 additions & 10 deletions compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,6 @@ abstract class Lifter {
/** The tree of a lifted definition */
protected def liftedDef(sym: TermSymbol, rhs: Tree)(using Context): MemberDef = ValDef(sym, rhs)

/** Is lifting performed on erased terms? */
protected def isErased = false

private def lift(defs: mutable.ListBuffer[Tree], expr: Tree, prefix: TermName = EmptyTermName)(using Context): Tree =
if (noLift(expr)) expr
else {
Expand Down Expand Up @@ -117,8 +114,7 @@ abstract class Lifter {
case Apply(fn, args) =>
val fn1 = liftApp(defs, fn)
val args1 = liftArgs(defs, fn.tpe, args)
if isErased then untpd.cpy.Apply(tree)(fn1, args1).withType(tree.tpe) // application may be partial
else cpy.Apply(tree)(fn1, args1)
cpy.Apply(tree)(fn1, args1)
case TypeApply(fn, targs) =>
cpy.TypeApply(tree)(liftApp(defs, fn), targs)
case Select(pre, name) if isPureRef(tree) =>
Expand All @@ -141,7 +137,7 @@ abstract class Lifter {
*
* unless `pre` is idempotent.
*/
def liftNonIdempotentPrefix(defs: mutable.ListBuffer[Tree], tree: Tree)(using Context): Tree =
private def liftNonIdempotentPrefix(defs: mutable.ListBuffer[Tree], tree: Tree)(using Context): Tree =
if (isIdempotentExpr(tree)) tree else lift(defs, tree)

/** Lift prefix `pre` of an application `pre.f(...)` to
Expand All @@ -154,7 +150,7 @@ abstract class Lifter {
* Note that default arguments will refer to the prefix, we do not want
* to re-evaluate a complex expression each time we access a getter.
*/
def liftPrefix(defs: mutable.ListBuffer[Tree], tree: Tree)(using Context): Tree =
private def liftPrefix(defs: mutable.ListBuffer[Tree], tree: Tree)(using Context): Tree =
tree match
case tree: Literal => tree
case tree: This => tree
Expand Down Expand Up @@ -218,9 +214,6 @@ object LiftCoverage extends LiftImpure {
}
}

object LiftErased extends LiftComplex:
override def isErased = true

/** Lift all impure or complex arguments to `def`s */
object LiftToDefs extends LiftComplex {
override def liftedFlags: FlagSet = Method
Expand Down
9 changes: 9 additions & 0 deletions tests/semanticdb/expect/Synthetic.expect.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,13 @@ class Synthetic/*<-example::Synthetic#*/ {
given Int/*->scala::Int#*/ = 1
foo/*->example::Synthetic#Contexts.foo().*/(0)
}

// Argument lifting
val _ =
def f/*<-local14*/(s/*<-local12*/: String/*->scala::Predef.String#*/)(i/*<-local13*/: Int/*->scala::Int#*/ = s/*->local12*/.length/*->java::lang::String#length().*/()) = i/*->local13*/ +/*->scala::Int#`+`(+4).*/ 1
def g/*<-local18*/(s/*<-local16*/: String/*->scala::Predef.String#*/, t/*<-local17*/: String/*->scala::Predef.String#*/) = s/*->local16*/ +/*->java::lang::String#`+`().*/ t/*->local17*/

def impure/*<-local20*/(s/*<-local19*/: String/*->scala::Predef.String#*/) = { ???/*->scala::Predef.`???`().*/; s/*->local19*/ }
val _ = f/*->local14*/(impure/*->local20*/(""))()
val _ = g/*->local18*/(t/*->local17*/ = impure/*->local20*/(""), s/*->local16*/ = "a")
}
9 changes: 9 additions & 0 deletions tests/semanticdb/expect/Synthetic.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,13 @@ class Synthetic {
given Int = 1
foo(0)
}

// Argument lifting
val _ =
def f(s: String)(i: Int = s.length()) = i + 1
def g(s: String, t: String) = s + t

def impure(s: String) = { ???; s }
val _ = f(impure(""))()
val _ = g(t = impure(""), s = "a")
}
46 changes: 41 additions & 5 deletions tests/semanticdb/metac.expect
Original file line number Diff line number Diff line change
Expand Up @@ -2841,7 +2841,7 @@ Schema => SemanticDB v4
Uri => NamedApplyBlock.scala
Text => empty
Language => Scala
Symbols => 43 entries
Symbols => 41 entries
Occurrences => 41 entries

Symbols:
Expand Down Expand Up @@ -2886,8 +2886,6 @@ example/NamedApplyBlockMethods.foo().(b) => param b: Int
example/NamedApplyBlockMethods.foo().(c) => param c: Int
example/NamedApplyBlockMethods.local. => val method local Int
example/NamedApplyBlockMethods.recursive(). => method recursive => Int
local0 => val local c$1: Int
local1 => val local b$1: Int @uncheckedVariance
Comment on lines -2889 to -2890
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These are lifted arguments from the recursive call in tests/semanticdb/expect/NamedApplyBlock.scala. Not sure if we want to include them in the symbols list?

Copy link
Contributor

Choose a reason for hiding this comment

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

I would say no. Doesn't seem to be too useful.


Occurrences:
[0:8..0:15): example <- example/
Expand Down Expand Up @@ -3533,8 +3531,8 @@ Schema => SemanticDB v4
Uri => Synthetic.scala
Text => empty
Language => Scala
Symbols => 52 entries
Occurrences => 137 entries
Symbols => 62 entries
Occurrences => 165 entries
Synthetics => 39 entries

Symbols:
Expand Down Expand Up @@ -3590,6 +3588,16 @@ local8 => param a: Int
local9 => param b: Int
local10 => final implicit lazy val given local x: Int
local11 => final implicit lazy val given local given_Int: Int
local12 => param s: String
local13 => param i: Int
local14 => local f: (param s: String)(param i: Int): Int
local15 => local f$default$2: (param s: String): Int @uncheckedVariance
local15(s) => param s: String
local16 => param s: String
local17 => param t: String
local18 => local g: (param s: String, param t: String): String
local19 => param s: String
local20 => local impure: (param s: String): String

Occurrences:
[0:8..0:15): example <- example/
Expand Down Expand Up @@ -3729,6 +3737,34 @@ Occurrences:
[56:8..56:10): m4 <- example/Synthetic#Contexts.m4().
[57:12..57:15): Int -> scala/Int#
[58:6..58:9): foo -> example/Synthetic#Contexts.foo().
[63:8..63:9): f <- local14
[63:10..63:11): s <- local12
[63:13..63:19): String -> scala/Predef.String#
[63:21..63:22): i <- local13
[63:24..63:27): Int -> scala/Int#
[63:30..63:31): s -> local12
[63:32..63:38): length -> java/lang/String#length().
[63:44..63:45): i -> local13
[63:46..63:47): + -> scala/Int#`+`(+4).
[64:8..64:9): g <- local18
[64:10..64:11): s <- local16
[64:13..64:19): String -> scala/Predef.String#
[64:21..64:22): t <- local17
[64:24..64:30): String -> scala/Predef.String#
[64:34..64:35): s -> local16
[64:36..64:37): + -> java/lang/String#`+`().
[64:38..64:39): t -> local17
[66:8..66:14): impure <- local20
[66:15..66:16): s <- local19
[66:18..66:24): String -> scala/Predef.String#
[66:30..66:33): ??? -> scala/Predef.`???`().
[66:35..66:36): s -> local19
[67:12..67:13): f -> local14
[67:14..67:20): impure -> local20
[68:12..68:13): g -> local18
[68:14..68:15): t -> local17
[68:18..68:24): impure -> local20
[68:30..68:31): s -> local16

Synthetics:
[5:2..5:13):List(1).map => *[Int]
Expand Down
Loading