diff --git a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala index 086c844e9d03..3c2c08ded7a0 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala @@ -251,6 +251,11 @@ class ExtractSemanticDB extends Phase: case tree: Inlined => traverse(tree.call) + + case tree: TypeApply => + synth.tryFindSynthetic(tree).foreach(synthetics.addOne) + traverseChildren(tree) + case tree: TypeTree => tree.typeOpt match // Any types could be appear inside of `TypeTree`, but diff --git a/compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala b/compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala index c6d87c67a578..0818b7cf1be1 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala @@ -11,14 +11,44 @@ import scala.collection.mutable class SyntheticsExtractor: import Scala3.{_, given} + val visited = collection.mutable.HashSet[Tree]() + def tryFindSynthetic(tree: Tree)(using Context, SemanticSymbolBuilder, TypeOps): Option[s.Synthetic] = extension (synth: s.Synthetic) def toOpt: Some[s.Synthetic] = Some(synth) - if tree.span.isSynthetic then + val forSynthetic = tree match // not yet supported (for synthetics) + case tree: Apply if isForSynthetic(tree) => true + case tree: TypeApply if isForSynthetic(tree) => true + case _ => false + + if visited.contains(tree) || forSynthetic then None + else tree match - case tree: Apply if isForSynthetic(tree) => - None // not yet supported (for synthetics) + case tree: TypeApply + if tree.span.isSynthetic && + tree.args.forall(arg => !arg.symbol.is(Scala2x)) && + !tree.span.isZeroExtent => + visited.add(tree) + val fnTree = tree.fun match + // Something like `List.apply[Int](1,2,3)` + case select @ Select(qual, _) if isSyntheticName(select) => + s.SelectTree( + s.OriginalTree(range(qual.span, tree.source)), + Some(select.toSemanticId) + ) + case _ => + s.OriginalTree( + range(tree.fun.span, tree.source) + ) + val targs = tree.args.map(targ => targ.tpe.toSemanticType(targ.symbol)(using LinkMode.SymlinkChildren)) + s.Synthetic( + range(tree.span, tree.source), + s.TypeApplyTree( + fnTree, targs + ) + ).toOpt + case tree: Apply if tree.args.nonEmpty && tree.args.forall(arg => @@ -46,7 +76,6 @@ class SyntheticsExtractor: ).toOpt case _ => None - else None private given TreeOps: AnyRef with extension (tree: Tree) @@ -95,4 +124,15 @@ class SyntheticsExtractor: case select: Select => isForComprehensionSyntheticName(select) case _ => false + private def isSyntheticName(select: Select): Boolean = + select.span.toSynthetic == select.qualifier.span.toSynthetic && ( + select.name == nme.apply || + select.name == nme.update || + select.name == nme.foreach || + select.name == nme.withFilter || + select.name == nme.flatMap || + select.name == nme.map || + select.name == nme.unapplySeq || + select.name == nme.unapply) + end SyntheticsExtractor diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index 07b3174b3d93..732e9b07aa85 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -224,6 +224,7 @@ Text => empty Language => Scala Symbols => 23 entries Occurrences => 52 entries +Synthetics => 2 entries Symbols: annot/Alias. => final object Alias extends Object { self: Alias.type => +2 decls } @@ -304,6 +305,10 @@ Occurrences: [39:11..39:26): ClassAnnotation -> com/javacp/annot/ClassAnnotation# [39:28..39:33): param -> scala/annotation/meta/param# +Synthetics: +[25:2..25:20):@throws[Exception] => *[Exception] +[25:2..25:20):@throws[Exception] => *[Exception] + expect/Anonymous.scala ---------------------- @@ -314,6 +319,7 @@ Text => empty Language => Scala Symbols => 14 entries Occurrences => 30 entries +Synthetics => 2 entries Symbols: example/Anonymous# => class Anonymous extends Object { self: Anonymous & Anonymous => +6 decls } @@ -363,6 +369,10 @@ Occurrences: [18:6..18:9): foo <- example/Anonymous#foo. [18:16..18:19): Foo -> example/Anonymous#Foo# +Synthetics: +[10:2..10:9):locally => *[Unit] +[13:2..13:9):locally => *[Unit] + expect/AnonymousGiven.scala --------------------------- @@ -397,6 +407,7 @@ Text => empty Language => Scala Symbols => 109 entries Occurrences => 113 entries +Synthetics => 2 entries Symbols: classes/C1# => final class C1 extends AnyVal { self: C1 => +2 decls } @@ -624,6 +635,10 @@ Occurrences: [53:4..53:9): local -> local4 [53:10..53:11): + -> scala/Int#`+`(+4). +Synthetics: +[51:16..51:27):List(1).map => *[Int] +[51:16..51:20):List => *.apply[Int] + expect/Empty.scala ------------------ @@ -826,6 +841,7 @@ Text => empty Language => Scala Symbols => 181 entries Occurrences => 148 entries +Synthetics => 10 entries Symbols: _empty_/Enums. => final object Enums extends Object { self: Enums.type => +30 decls } @@ -1160,6 +1176,18 @@ Occurrences: [68:9..68:16): Neptune <- _empty_/Enums.Planet.Neptune. [68:25..68:31): Planet -> _empty_/Enums.Planet# +Synthetics: +[46:28..46:35):C <:< C => *[C, C] +[49:27..49:31):Refl => *.apply[T] +[52:9..52:13):Refl => *.unapply[Option[B]] +[52:19..52:30):opt.flatMap => *[B] +[52:31..52:50):identity[Option[B]] => *[Function1[A, Option[B]]] +[54:14..54:18):Some => *.apply[Some[Int]] +[54:14..54:34):Some(Some(1)).unwrap => *(given_<:<_T_T[Option[Int]]) +[54:19..54:23):Some => *.apply[Int] +[54:28..54:34):unwrap => *[Some[Int], Int] +[56:52..56:64):Enum[Planet] => *[Planet] + expect/EtaExpansion.scala ------------------------- @@ -1170,6 +1198,7 @@ Text => empty Language => Scala Symbols => 3 entries Occurrences => 8 entries +Synthetics => 5 entries Symbols: example/EtaExpansion# => class EtaExpansion extends Object { self: EtaExpansion => +1 decls } @@ -1186,6 +1215,13 @@ Occurrences: [4:10..4:18): foldLeft -> scala/collection/LinearSeqOps#foldLeft(). [4:25..4:26): + -> java/lang/String#`+`(). +Synthetics: +[3:2..3:13):Some(1).map => *[Int] +[3:2..3:6):Some => *.apply[Int] +[3:14..3:22):identity => *[Int] +[4:2..4:18):List(1).foldLeft => *[String] +[4:2..4:6):List => *.apply[Int] + expect/Example.scala -------------------- @@ -1334,6 +1370,7 @@ Text => empty Language => Scala Symbols => 13 entries Occurrences => 52 entries +Synthetics => 6 entries Symbols: example/ForComprehension# => class ForComprehension extends Object { self: ForComprehension => +1 decls } @@ -1404,6 +1441,14 @@ Occurrences: [40:6..40:7): e -> local9 [41:6..41:7): f -> local10 +Synthetics: +[4:9..4:13):List => *.apply[Int] +[5:9..5:13):List => *.apply[Int] +[10:9..10:13):List => *.apply[Int] +[11:9..11:13):List => *.apply[Int] +[19:9..19:13):List => *.apply[Tuple2[Int, Int]] +[33:9..33:13):List => *.apply[Tuple4[Int, Int, Int, Int]] + expect/Givens.scala ------------------- @@ -1414,6 +1459,7 @@ Text => empty Language => Scala Symbols => 29 entries Occurrences => 65 entries +Synthetics => 3 entries Symbols: a/b/Givens. => final object Givens extends Object { self: Givens.type => +12 decls } @@ -1513,6 +1559,11 @@ Occurrences: [26:57..26:58): A -> a/b/Givens.foo().(A) [26:59..26:64): empty -> a/b/Givens.Monoid#empty(). +Synthetics: +[12:17..12:25):sayHello => *[Int] +[13:19..13:29):sayGoodbye => *[Int] +[14:18..14:27):saySoLong => *[Int] + expect/ImplicitConversion.scala ------------------------------- @@ -1655,6 +1706,7 @@ Text => empty Language => Scala Symbols => 8 entries Occurrences => 52 entries +Synthetics => 2 entries Symbols: example/InstrumentTyper# => class InstrumentTyper extends Object { self: AnyRef & InstrumentTyper => +5 decls } @@ -1720,6 +1772,10 @@ Occurrences: [24:30..24:36): Option -> scala/Option# [24:37..24:40): Int -> scala/Int# +Synthetics: +[8:12..8:16):List => *.apply[Matchable] +[20:4..20:8):List => *.apply[Nothing] + expect/InventedNames.scala -------------------------- @@ -1907,6 +1963,7 @@ Text => empty Language => Scala Symbols => 6 entries Occurrences => 10 entries +Synthetics => 1 entries Symbols: example/Local# => class Local extends Object { self: Local => +2 decls } @@ -1928,6 +1985,9 @@ Occurrences: [4:25..4:26): a -> local1 [5:4..5:6): id -> local2 +Synthetics: +[5:4..5:6):id => *[Int] + expect/Locals.scala ------------------- @@ -1938,6 +1998,7 @@ Text => empty Language => Scala Symbols => 3 entries Occurrences => 6 entries +Synthetics => 1 entries Symbols: local0 => val local x: Int @@ -1952,6 +2013,9 @@ Occurrences: [5:4..5:8): List -> scala/package.List. [5:9..5:10): x -> local0 +Synthetics: +[5:4..5:8):List => *.apply[Int] + expect/MetacJava.scala ---------------------- @@ -2049,7 +2113,7 @@ Text => empty Language => Scala Symbols => 3 entries Occurrences => 80 entries -Synthetics => 1 entries +Synthetics => 2 entries Symbols: example/MethodUsages# => class MethodUsages extends Object { self: MethodUsages => +2 decls } @@ -2139,6 +2203,7 @@ Occurrences: [34:8..34:9): m -> example/Methods#m17.m(). Synthetics: +[13:2..13:6):m.m7 => *[Int] [13:2..13:26):m.m7(m, new m.List[Int]) => *(Int) expect/Methods.scala @@ -2715,7 +2780,7 @@ Text => empty Language => Scala Symbols => 68 entries Occurrences => 110 entries -Synthetics => 1 entries +Synthetics => 3 entries Symbols: example/C# => class C extends Object { self: C => +3 decls } @@ -2900,7 +2965,9 @@ Occurrences: [32:57..32:59): as -> example/PickOneRefinement_1#run().(as) Synthetics: +[15:23..15:34):elems.toMap => *[String, Any] [15:23..15:34):elems.toMap => *(refl[Tuple2[String, Any]]) +[32:47..32:56):s.pickOne => *[String] expect/RightAssociativeExtension.scala -------------------------------------- @@ -2989,7 +3056,7 @@ Text => empty Language => Scala Symbols => 52 entries Occurrences => 132 entries -Synthetics => 21 entries +Synthetics => 36 entries Symbols: example/Synthetic# => class Synthetic extends Object { self: Synthetic => +23 decls } @@ -3180,15 +3247,26 @@ Occurrences: [58:6..58:9): foo -> example/Synthetic#Contexts.foo(). Synthetics: +[5:2..5:13):List(1).map => *[Int] +[5:2..5:6):List => *.apply[Int] [6:2..6:18):Array.empty[Int] => intArrayOps(*) [7:2..7:8):"fooo" => augmentString(*) [10:13..10:24):"name:(.*)" => augmentString(*) +[11:17..11:25):LazyList => *.apply[Int] +[13:4..13:28):#:: 2 #:: LazyList.empty => *[Int] [13:8..13:28):2 #:: LazyList.empty => toDeferrer[Int](*) +[13:10..13:28):#:: LazyList.empty => *[Int] [13:14..13:28):LazyList.empty => toDeferrer[Nothing](*) +[13:14..13:28):LazyList.empty => *[Nothing] +[15:25..15:33):LazyList => *.apply[Int] +[17:14..17:38):#:: 2 #:: LazyList.empty => *[Int] [17:18..17:38):2 #:: LazyList.empty => toDeferrer[Int](*) +[17:20..17:38):#:: LazyList.empty => *[Int] [17:24..17:38):LazyList.empty => toDeferrer[Nothing](*) +[17:24..17:38):LazyList.empty => *[Nothing] [19:12..19:13):1 => intWrapper(*) [19:26..19:27):0 => intWrapper(*) +[19:46..19:50):x -> => *[Int] [19:46..19:47):x => ArrowAssoc[Int](*) [20:12..20:13):1 => intWrapper(*) [20:26..20:27):0 => intWrapper(*) @@ -3197,6 +3275,10 @@ Synthetics: [32:35..32:49):Array.empty[T] => *(evidence$1) [36:22..36:27):new F => orderingToOrdered[F](*) [36:22..36:27):new F => *(ordering) +[40:9..40:43):scala.concurrent.Future.successful => *[Int] +[41:9..41:43):scala.concurrent.Future.successful => *[Int] +[44:9..44:43):scala.concurrent.Future.successful => *[Int] +[45:9..45:43):scala.concurrent.Future.successful => *[Int] [51:24..51:30):foo(0) => *(x$1) [52:27..52:33):foo(0) => *(x) [55:6..55:12):foo(x) => *(x) @@ -3252,6 +3334,7 @@ Text => empty Language => Scala Symbols => 22 entries Occurrences => 46 entries +Synthetics => 7 entries Symbols: example/ValPattern# => class ValPattern extends Object { self: ValPattern => +14 decls } @@ -3325,6 +3408,15 @@ Occurrences: [39:10..39:17): leftVar -> local3 [40:10..40:18): rightVar -> local4 +Synthetics: +[6:4..6:8):Some => *.apply[Int] +[8:6..8:10):List => *.unapplySeq[Nothing] +[8:11..8:15):Some => *.unapply[Nothing] +[12:4..12:8):Some => *.apply[Int] +[25:4..25:11):locally => *[Unit] +[28:8..28:12):Some => *.apply[Int] +[32:8..32:12):Some => *.apply[Int] + expect/Vals.scala ----------------- @@ -3845,6 +3937,7 @@ Text => empty Language => Scala Symbols => 3 entries Occurrences => 6 entries +Synthetics => 1 entries Symbols: example/`local-file`# => class local-file extends Object { self: local-file => +1 decls } @@ -3859,6 +3952,9 @@ Occurrences: [5:4..5:9): local -> local0 [5:10..5:11): + -> scala/Int#`+`(+4). +Synthetics: +[3:2..3:9):locally => *[Int] + expect/nullary.scala -------------------- @@ -3869,6 +3965,7 @@ Text => empty Language => Scala Symbols => 17 entries Occurrences => 29 entries +Synthetics => 1 entries Symbols: _empty_/Concrete# => class Concrete extends NullaryTest[Int, List] { self: Concrete => +3 decls } @@ -3920,6 +4017,9 @@ Occurrences: [18:7..18:15): Concrete -> _empty_/Concrete# [18:17..18:25): nullary3 -> _empty_/Concrete#nullary3(). +Synthetics: +[13:17..13:21):List => *.apply[Int] + expect/recursion.scala ---------------------- @@ -3930,6 +4030,7 @@ Text => empty Language => Scala Symbols => 36 entries Occurrences => 46 entries +Synthetics => 3 entries Symbols: local0 => case val method N$1 <: Nat @@ -4017,6 +4118,11 @@ Occurrences: [23:35..23:39): Zero -> recursion/Nats.Zero. [23:40..23:42): ++ -> recursion/Nats.Nat#`++`(). +Synthetics: +[5:50..5:54):Succ => *.apply[Nat.this.type] +[10:13..10:17):Succ => *.unapply[N$1] +[20:11..20:15):Succ => *.unapply[N$2] + expect/semanticdb-Definitions.scala ----------------------------------- @@ -4059,6 +4165,7 @@ Text => empty Language => Scala Symbols => 50 entries Occurrences => 73 entries +Synthetics => 2 entries Symbols: flags/p/package. => final package object p extends Object { self: p.type => +23 decls } @@ -4187,6 +4294,10 @@ Occurrences: [25:27..25:28): t <- local1 [25:33..25:36): ??? -> scala/Predef.`???`(). +Synthetics: +[23:6..23:10):List => *.unapplySeq[Nothing] +[24:19..24:23):List => *.unapplySeq[Nothing] + expect/semanticdb-Types.scala ----------------------------- @@ -4197,6 +4308,7 @@ Text => empty Language => Scala Symbols => 144 entries Occurrences => 225 entries +Synthetics => 1 entries Symbols: local0 => abstract method k => Int @@ -4571,6 +4683,9 @@ Occurrences: [119:32..119:38): Option -> scala/Option# [119:39..119:42): Int -> scala/Int# +Synthetics: +[68:20..68:24):@ann => *[Int] + expect/semanticdb-extract.scala ------------------------------- @@ -4581,6 +4696,7 @@ Text => empty Language => Scala Symbols => 18 entries Occurrences => 20 entries +Synthetics => 3 entries Symbols: _empty_/AnObject. => final object AnObject extends Object { self: AnObject.type => +6 decls } @@ -4624,6 +4740,11 @@ Occurrences: [16:17..16:18): x <- _empty_/AnObject.Foo#x. [16:20..16:23): Int -> scala/Int# +Synthetics: +[11:2..11:6):List => *.apply[Int] +[12:2..12:12):List.apply => *[Nothing] +[13:2..13:14):List.`apply` => *[Nothing] + expect/toplevel.scala --------------------- @@ -4634,7 +4755,7 @@ Text => empty Language => Scala Symbols => 18 entries Occurrences => 43 entries -Synthetics => 1 entries +Synthetics => 2 entries Symbols: _empty_/MyProgram# => final class MyProgram extends Object { self: MyProgram => +2 decls } @@ -4702,5 +4823,6 @@ Occurrences: [7:30..7:33): foo -> _empty_/toplevel$package.foo(). Synthetics: +[5:40..5:60):(1 to times) foreach => *[Unit] [5:41..5:42):1 => intWrapper(*)