diff --git a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala index 8c1f22005af3..05dff8ffadbc 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala @@ -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 @@ -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) diff --git a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala index b09580d51943..26d03db4b7dc 100644 --- a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala +++ b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala @@ -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 { @@ -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) => @@ -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 @@ -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 @@ -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 diff --git a/tests/semanticdb/expect/Synthetic.expect.scala b/tests/semanticdb/expect/Synthetic.expect.scala index 4d797ce2b856..c8ccb2281cbb 100644 --- a/tests/semanticdb/expect/Synthetic.expect.scala +++ b/tests/semanticdb/expect/Synthetic.expect.scala @@ -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") } diff --git a/tests/semanticdb/expect/Synthetic.scala b/tests/semanticdb/expect/Synthetic.scala index 71fb5fdf70a3..0953d6cc4f98 100644 --- a/tests/semanticdb/expect/Synthetic.scala +++ b/tests/semanticdb/expect/Synthetic.scala @@ -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") } diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index dffed5c0d477..26221899035b 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -2841,7 +2841,7 @@ Schema => SemanticDB v4 Uri => NamedApplyBlock.scala Text => empty Language => Scala -Symbols => 43 entries +Symbols => 41 entries Occurrences => 41 entries Symbols: @@ -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 Occurrences: [0:8..0:15): example <- example/ @@ -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: @@ -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/ @@ -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]