Skip to content

Backport "Extract semanticDB for lifted definitions" to 3.3 LTS #53

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

Closed
wants to merge 2 commits into from
Closed
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")
}
Loading