From e07e7d0b6ddedf7727d205e035c0741ae0cf4de1 Mon Sep 17 00:00:00 2001 From: Rikito Taniguchi Date: Wed, 11 Aug 2021 15:37:05 +0900 Subject: [PATCH 1/7] Add implicit or context param apply to synthetics Support following synthetics - implicit and context parameters application - Anonymous context param name - Invented given Also convert TypeVar to stripped type, which may appear in synthetics --- .../dotc/semanticdb/ExtractSemanticDB.scala | 43 ++++-- .../dotty/tools/dotc/semanticdb/PPrint.scala | 125 ++++++++++++++++-- .../dotty/tools/dotc/semanticdb/Scala3.scala | 26 +++- .../dotc/semanticdb/SyntheticsExtractor.scala | 92 +++++++++++++ .../dotty/tools/dotc/semanticdb/Tools.scala | 23 ++-- .../dotty/tools/dotc/semanticdb/TypeOps.scala | 5 +- .../semanticdb/expect/Synthetic.expect.scala | 11 ++ tests/semanticdb/expect/Synthetic.scala | 11 ++ tests/semanticdb/metac.expect | 87 +++++++++++- 9 files changed, 385 insertions(+), 38 deletions(-) create mode 100644 compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala diff --git a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala index aa1d7b102fb5..18353b307d11 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala @@ -16,7 +16,6 @@ import NameOps._ import util.Spans.Span import util.{SourceFile, SourcePosition} import transform.SymUtils._ -import SymbolInformation.{Kind => k} import scala.jdk.CollectionConverters._ import scala.collection.mutable @@ -46,12 +45,13 @@ class ExtractSemanticDB extends Phase: val unit = ctx.compilationUnit val extractor = Extractor() extractor.extract(unit.tpdTree) - ExtractSemanticDB.write(unit.source, extractor.occurrences.toList, extractor.symbolInfos.toList) + ExtractSemanticDB.write(unit.source, extractor.occurrences.toList, extractor.symbolInfos.toList, extractor.synthetics.toList) /** Extractor of symbol occurrences from trees */ class Extractor extends TreeTraverser: - given s.SemanticSymbolBuilder = s.SemanticSymbolBuilder() - val converter = s.TypeOps() + given builder: s.SemanticSymbolBuilder = s.SemanticSymbolBuilder() + val synth = SyntheticsExtractor() + given converter: s.TypeOps = s.TypeOps() /** The bodies of synthetic locals */ private val localBodies = mutable.HashMap[Symbol, Tree]() @@ -62,6 +62,8 @@ class ExtractSemanticDB extends Phase: /** The extracted symbol infos */ val symbolInfos = new mutable.ListBuffer[SymbolInformation]() + val synthetics = new mutable.ListBuffer[s.Synthetic]() + /** A cache of localN names */ val localNames = new mutable.HashSet[String]() @@ -158,11 +160,22 @@ class ExtractSemanticDB extends Phase: tree match case tree: DefDef => tree.paramss.foreach(_.foreach(param => registerSymbolSimple(param.symbol))) - case tree: ValDef if tree.symbol.is(Given) => traverse(tree.tpt) + case tree: ValDef if tree.symbol.is(Given) => + synth.tryFindSynthetic(tree).foreach { synth => + synthetics += synth + } + traverse(tree.tpt) case _ => if !tree.symbol.isGlobal then localBodies(tree.symbol) = tree.rhs // ignore rhs + + // `given Int` (syntax sugar of `given given_Int: Int`) + case tree: ValDef if tree.symbol.isInventedGiven => + synth.tryFindSynthetic(tree).foreach { synth => + synthetics += synth + } + traverse(tree.tpt) case PatternValDef(pat, rhs) => traverse(rhs) PatternValDef.collectPats(pat).foreach(traverse) @@ -197,6 +210,10 @@ class ExtractSemanticDB extends Phase: case tree: Apply => @tu lazy val genParamSymbol: Name => String = tree.fun.symbol.funParamSymbol traverse(tree.fun) + synth.tryFindSynthetic(tree).foreach { synth => + synthetics += synth + } + for arg <- tree.args do arg match case tree @ NamedArg(name, arg) => @@ -292,12 +309,6 @@ class ExtractSemanticDB extends Phase: end PatternValDef - private def range(span: Span, treeSource: SourceFile)(using Context): Option[Range] = - def lineCol(offset: Int) = (treeSource.offsetToLine(offset), treeSource.column(offset)) - val (startLine, startCol) = lineCol(span.start) - val (endLine, endCol) = lineCol(span.end) - Some(Range(startLine, startCol, endLine, endCol)) - private def registerSymbol(sym: Symbol, symkinds: Set[SymbolKind])(using Context): Unit = val sname = sym.symbolName @@ -466,7 +477,12 @@ object ExtractSemanticDB: val name: String = "extractSemanticDB" - def write(source: SourceFile, occurrences: List[SymbolOccurrence], symbolInfos: List[SymbolInformation])(using Context): Unit = + def write( + source: SourceFile, + occurrences: List[SymbolOccurrence], + symbolInfos: List[SymbolInformation], + synthetics: List[Synthetic], + )(using Context): Unit = def absolutePath(path: Path): Path = path.toAbsolutePath.normalize val semanticdbTarget = val semanticdbTargetSetting = ctx.settings.semanticdbTarget.value @@ -488,7 +504,8 @@ object ExtractSemanticDB: text = "", md5 = internal.MD5.compute(String(source.content)), symbols = symbolInfos, - occurrences = occurrences + occurrences = occurrences, + synthetics = synthetics, ) val docs = TextDocuments(List(doc)) val out = Files.newOutputStream(outpath) diff --git a/compiler/src/dotty/tools/dotc/semanticdb/PPrint.scala b/compiler/src/dotty/tools/dotc/semanticdb/PPrint.scala index edc9ad79518b..2f1e2b760f1c 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/PPrint.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/PPrint.scala @@ -5,8 +5,8 @@ import dotty.tools.dotc.{semanticdb => s} import scala.collection.mutable import dotty.tools.dotc.semanticdb.Scala3.{_, given} import SymbolInformation.Kind._ - -class SymbolInfomationPrinter (symtab: PrinterSymtab): +import dotty.tools.dotc.util.SourceFile +class SymbolInformationPrinter (symtab: PrinterSymtab): val notes = InfoNotes() val infoPrinter = InfoPrinter(notes) @@ -28,8 +28,9 @@ class SymbolInfomationPrinter (symtab: PrinterSymtab): val displayName = if sym.isGlobal then sym.desc.value else sym SymbolInformation(symbol = sym, displayName = displayName) } + end InfoNotes - class InfoPrinter(notes: InfoNotes) { + class InfoPrinter(notes: InfoNotes): private enum SymbolStyle: case Reference, Definition def pprint(info: SymbolInformation): String = @@ -81,7 +82,7 @@ class SymbolInfomationPrinter (symtab: PrinterSymtab): private def pprintDef(info: SymbolInformation) = notes.enter(info) pprint(info.symbol, SymbolStyle.Definition) - private def pprintRef(sym: String): String = pprint(sym, SymbolStyle.Reference) + def pprintRef(sym: String): String = pprint(sym, SymbolStyle.Reference) private def pprintDef(sym: String): String = pprint(sym, SymbolStyle.Definition) private def pprint(sym: String, style: SymbolStyle): String = val info = notes.visit(sym) @@ -137,7 +138,7 @@ class SymbolInfomationPrinter (symtab: PrinterSymtab): case _ => "" - private def pprint(tpe: Type): String = { + protected def pprint(tpe: Type): String = { def prefix(tpe: Type): String = tpe match case TypeRef(pre, sym, args) => val preStr = pre match { @@ -204,7 +205,7 @@ class SymbolInfomationPrinter (symtab: PrinterSymtab): case tpe => s"@${pprint(tpe)}" } - private def pprint(const: Constant): String = const match { + protected def pprint(const: Constant): String = const match { case Constant.Empty => "" case UnitConstant() => @@ -245,7 +246,6 @@ class SymbolInfomationPrinter (symtab: PrinterSymtab): s"private[${ssym}] " case ProtectedWithinAccess(ssym) => s"protected[${ssym}] " - extension (scope: Scope) private def infos: List[SymbolInformation] = if (scope.symlinks.nonEmpty) @@ -258,8 +258,8 @@ class SymbolInfomationPrinter (symtab: PrinterSymtab): case Some(s) => s.infos case None => Nil } - } -end SymbolInfomationPrinter + end InfoPrinter +end SymbolInformationPrinter extension (info: SymbolInformation) def prefixBeforeTpe: String = { @@ -280,3 +280,110 @@ object PrinterSymtab: new PrinterSymtab { override def info(symbol: String): Option[SymbolInformation] = map.get(symbol) } + +def processRange(sb: StringBuilder, range: Range): Unit = + sb.append('[') + .append(range.startLine).append(':').append(range.startCharacter) + .append("..") + .append(range.endLine).append(':').append(range.endCharacter) + .append("):") + + + +class SyntheticPrinter(symtab: PrinterSymtab, source: SourceFile) extends SymbolInformationPrinter(symtab): + + def pprint(synth: Synthetic): String = + val sb = new StringBuilder() + val notes = InfoNotes() + val treePrinter = TreePrinter(source, synth.range, notes) + + synth.range match + case Some(range) => + processRange(sb, range) + sb.append(source.substring(range)) + case None => + sb.append("[):") + sb.append(" => ") + sb.append(treePrinter.pprint(synth.tree)) + sb.toString + + extension (source: SourceFile) + private def substring(range: Option[s.Range]): String = + range match + case Some(range) => source.substring(range) + case None => "" + private def substring(range: s.Range): String = + /** get the line length of a given line */ + def lineLength(line: Int): Int = + val isLastLine = source.lineToOffsetOpt(line).nonEmpty && source.lineToOffsetOpt(line + 1).isEmpty + if isLastLine then source.content.length - source.lineToOffset(line) - 1 + else source.lineToOffset(line + 1) - source.lineToOffset(line) - 1 // -1 for newline char + + val start = source.lineToOffset(range.startLine) + + math.min(range.startCharacter, lineLength(range.startLine)) + val end = source.lineToOffset(range.endLine) + + math.min(range.endCharacter, lineLength(range.endLine)) + new String(source.content, start, end - start) + + + // def pprint(tree: s.Tree, range: Option[Range]): String = + class TreePrinter(source: SourceFile, originalRange: Option[Range], notes: InfoNotes) extends InfoPrinter(notes): + def pprint(tree: Tree): String = + val sb = new StringBuilder() + processTree(tree)(using sb) + sb.toString + + + private def rep[T](xs: Seq[T], seq: String)(f: T => Unit)(using sb: StringBuilder): Unit = + xs.zipWithIndex.foreach { (x, i) => + if i != 0 then sb.append(seq) + f(x) + } + + private def processTree(tree: Tree)(using sb: StringBuilder): Unit = + tree match { + case tree: ApplyTree => + processTree(tree.function) + sb.append("(") + rep(tree.arguments, ", ")(processTree) + sb.append(")") + case tree: FunctionTree => + sb.append("{") + sb.append("(") + rep(tree.parameters, ", ")(processTree) + sb.append(") =>") + processTree(tree.body) + sb.append("}") + case tree: IdTree => + sb.append(pprintRef(tree.symbol)) + case tree: LiteralTree => + sb.append(pprint(tree.constant)) + case tree: MacroExpansionTree => + sb.append("(`macro-expandee` : `") + sb.append(pprint(tree.tpe)) + sb.append(")") + case tree: OriginalTree => + if (tree.range == originalRange && originalRange.nonEmpty) then + sb.append("*") + else + sb.append("orig(") + sb.append(source.substring(tree.range)) + sb.append(")") + case tree: SelectTree => + processTree(tree.qualifier) + sb.append(".") + tree.id match + case Some(tree) => processTree(tree) + case None => () + case tree: TypeApplyTree => + processTree(tree.function) + sb.append("[") + rep(tree.typeArguments, ", ")((t) => sb.append(pprint(t))) + sb.append("]") + + case _ => + sb.append("") + } + + +end SyntheticPrinter diff --git a/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala b/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala index 504b49904a76..555492e5b8a5 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala @@ -10,6 +10,10 @@ import core.Flags._ import core.NameKinds import core.StdNames.nme import SymbolInformation.{Kind => k} +import dotty.tools.dotc.util.SourceFile +import dotty.tools.dotc.util.Spans.Span +import dotty.tools.dotc.ast.tpd +import dotty.tools.dotc.{semanticdb => s} import java.lang.Character.{isJavaIdentifierPart, isJavaIdentifierStart} @@ -26,6 +30,12 @@ object Scala3: private val WILDCARDTypeName = nme.WILDCARD.toTypeName + def range(span: Span, treeSource: SourceFile)(using Context): Option[Range] = + def lineCol(offset: Int) = (treeSource.offsetToLine(offset), treeSource.column(offset)) + val (startLine, startCol) = lineCol(span.start) + val (endLine, endCol) = lineCol(span.end) + Some(Range(startLine, startCol, endLine, endCol)) + sealed trait FakeSymbol { private[Scala3] var sname: Option[String] = None } @@ -221,6 +231,12 @@ object Scala3: def isSyntheticWithIdent(using Context): Boolean = sym.is(Synthetic) && !sym.isAnonymous && !sym.name.isEmptyNumbered + /** Check if the symbol is invented by Desugar.inventGivenOrExtensionName + * return true if the symbol is defined as `given Int = ...` and name is invented as "given_Int" + */ + def isInventedGiven(using Context): Boolean = + sym.is(Given) && sym.name.startsWith("given_") + /** The semanticdb name of the given symbol */ def symbolName(using builder: SemanticSymbolBuilder)(using Context): String = builder.symbolName(sym) @@ -423,9 +439,7 @@ object Scala3: def hasLength = range.endLine > range.startLine || range.endCharacter > range.startCharacter end RangeOps - /** Sort symbol occurrences by their start position. */ - given OccurrenceOrdering: Ordering[SymbolOccurrence] = (x, y) => - x.range -> y.range match + private def compareRange(x: Option[Range], y: Option[Range]): Int = x -> y match case None -> _ | _ -> None => 0 case Some(a) -> Some(b) => val byLine = Integer.compare(a.startLine, b.startLine) @@ -433,10 +447,14 @@ object Scala3: byLine else // byCharacter Integer.compare(a.startCharacter, b.startCharacter) - end OccurrenceOrdering + + /** Sort symbol occurrences by their start position. */ + given Ordering[SymbolOccurrence] = (x, y) => compareRange(x.range, y.range) given Ordering[SymbolInformation] = Ordering.by[SymbolInformation, String](_.symbol)(IdentifierOrdering()) + given Ordering[Synthetic] = (x, y) => compareRange(x.range, y.range) + /** * A comparator for identifier like "Predef" or "Function10". * diff --git a/compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala b/compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala new file mode 100644 index 000000000000..ccc33aba63f9 --- /dev/null +++ b/compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala @@ -0,0 +1,92 @@ +package dotty.tools.dotc.semanticdb + +import dotty.tools.dotc.ast.tpd._ +import dotty.tools.dotc.core.Contexts._ +import dotty.tools.dotc.core.Flags._ +import dotty.tools.dotc.core.StdNames.nme +import dotty.tools.dotc.{semanticdb => s} + +import scala.collection.mutable + +class SyntheticsExtractor: + import Scala3.{_, given} + + 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 || tree.symbol.isInventedGiven then + tree match + case tree: Apply if isForSynthetic(tree) => + None // not yet supported (for synthetics) + case tree: Apply + if tree.args.nonEmpty && + tree.args.forall(arg => + arg.symbol.isOneOf(GivenOrImplicit) && + arg.span.isSynthetic + ) => + s.Synthetic( + range(tree.span, tree.source), + s.ApplyTree( + tree.fun.toSemanticOriginal, + tree.args.map(_.toSemanticTree) + ) + ).toOpt + + // Anonymous context parameter + case tree: ValDef if tree.symbol.is(Given) => + s.Synthetic( + range(tree.span, tree.source), + tree.toSemanticId + ).toOpt + case _ => None + else None + + private given TreeOps: AnyRef with + extension (tree: Tree) + def toSemanticTree(using Context, SemanticSymbolBuilder, TypeOps): s.Tree = + tree match + case tree: Apply => + s.ApplyTree( + tree.fun.toSemanticQualifierTree, + tree.args.map(_.toSemanticTree) + ) + case tree: TypeApply => + s.TypeApplyTree( + tree.fun.toSemanticQualifierTree, + tree.args.map { targ => + targ.tpe.toSemanticType(targ.symbol)(using LinkMode.SymlinkChildren) + } + ) + case tree: Ident => tree.toSemanticId + case tree: Select => tree.toSemanticId + case _ => s.Tree.defaultInstance + + def toSemanticQualifierTree(using Context, SemanticSymbolBuilder): s.Tree = tree match + case sel @ Select(qual, _) if sel.symbol.owner != qual.symbol => + s.SelectTree(qual.toSemanticId, Some(sel.toSemanticId)) + case fun => fun.toSemanticId + + def toSemanticId(using Context, SemanticSymbolBuilder) = + s.IdTree(tree.symbol.symbolName) + + def toSemanticOriginal(using Context) = + s.OriginalTree(range(tree.span, tree.source)) + end TreeOps + + + private def isForSynthetic(tree: Tree): Boolean = + def isForComprehensionSyntheticName(select: Select): Boolean = + select.span.toSynthetic == select.qualifier.span.toSynthetic && ( + select.name == nme.map || + select.name == nme.flatMap || + select.name == nme.withFilter || + select.name == nme.foreach + ) + tree match + case Apply(fun, _) => isForSynthetic(fun) + case TypeApply(fun, _) => isForSynthetic(fun) + case select: Select => isForComprehensionSyntheticName(select) + case _ => false + +end SyntheticsExtractor diff --git a/compiler/src/dotty/tools/dotc/semanticdb/Tools.scala b/compiler/src/dotty/tools/dotc/semanticdb/Tools.scala index ec427523195e..54b57f7c6a2f 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/Tools.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/Tools.scala @@ -53,9 +53,10 @@ object Tools: def metac(doc: TextDocument, realPath: Path)(using sb: StringBuilder): StringBuilder = val symtab = PrinterSymtab.fromTextDocument(doc) - val symPrinter = SymbolInfomationPrinter(symtab) + val symPrinter = SymbolInformationPrinter(symtab) val realURI = realPath.toString - given SourceFile = SourceFile.virtual(doc.uri, doc.text) + given sourceFile: SourceFile = SourceFile.virtual(doc.uri, doc.text) + val synthPrinter = SyntheticPrinter(symtab, sourceFile) sb.append(realURI).nl sb.append("-" * realURI.length).nl sb.nl @@ -66,6 +67,8 @@ object Tools: sb.append("Language => ").append(languageString(doc.language)).nl sb.append("Symbols => ").append(doc.symbols.length).append(" entries").nl sb.append("Occurrences => ").append(doc.occurrences.length).append(" entries").nl + if doc.synthetics.nonEmpty then + sb.append("Synthetics => ").append(doc.synthetics.length).append(" entries").nl sb.nl sb.append("Symbols:").nl doc.symbols.sorted.foreach(s => processSymbol(s, symPrinter)) @@ -73,6 +76,11 @@ object Tools: sb.append("Occurrences:").nl doc.occurrences.sorted.foreach(processOccurrence) sb.nl + if doc.synthetics.nonEmpty then + sb.append("Synthetics:").nl + doc.synthetics.sorted.foreach(s => processSynth(s, synthPrinter)) + sb.nl + sb end metac private def schemaString(schema: Schema) = @@ -92,17 +100,16 @@ object Tools: case UNKNOWN_LANGUAGE | Unrecognized(_) => "unknown" end languageString - private def processSymbol(info: SymbolInformation, printer: SymbolInfomationPrinter)(using sb: StringBuilder): Unit = + private def processSymbol(info: SymbolInformation, printer: SymbolInformationPrinter)(using sb: StringBuilder): Unit = sb.append(printer.pprintSymbolInformation(info)).nl + private def processSynth(synth: Synthetic, printer: SyntheticPrinter)(using sb: StringBuilder): Unit = + sb.append(printer.pprint(synth)).nl + private def processOccurrence(occ: SymbolOccurrence)(using sb: StringBuilder, sourceFile: SourceFile): Unit = occ.range match case Some(range) => - sb.append('[') - .append(range.startLine).append(':').append(range.startCharacter) - .append("..") - .append(range.endLine).append(':').append(range.endCharacter) - .append("):") + processRange(sb, range) if range.endLine == range.startLine && range.startCharacter != range.endCharacter && !(occ.symbol.isConstructor && occ.role.isDefinition) then diff --git a/compiler/src/dotty/tools/dotc/semanticdb/TypeOps.scala b/compiler/src/dotty/tools/dotc/semanticdb/TypeOps.scala index b71327b4c28a..963a153388a3 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/TypeOps.scala @@ -215,7 +215,7 @@ class TypeOps: } loop(tpe) - private def toSemanticType(sym: Symbol)(using LinkMode, SemanticSymbolBuilder, Context): s.Type = + def toSemanticType(sym: Symbol)(using LinkMode, SemanticSymbolBuilder, Context): s.Type = import ConstantOps._ def loop(tpe: Type): s.Type = tpe match { case t if t.isFromJavaObject => @@ -409,6 +409,9 @@ class TypeOps: case _: MatchType => s.Type.Empty + case tvar: TypeVar => + loop(tvar.stripped) + case _ => s.Type.Empty } diff --git a/tests/semanticdb/expect/Synthetic.expect.scala b/tests/semanticdb/expect/Synthetic.expect.scala index 271d3013c0ae..b6b14fe6de81 100644 --- a/tests/semanticdb/expect/Synthetic.expect.scala +++ b/tests/semanticdb/expect/Synthetic.expect.scala @@ -47,4 +47,15 @@ class Synthetic/*<-example::Synthetic#*/ { if a/*->local8*/ scala::Int#`<`(+3).*/ b/*->local9*/ } yield a/*->local8*/ + object Contexts/*<-example::Synthetic#Contexts.*/ { + def foo/*<-example::Synthetic#Contexts.foo().*/(x/*<-example::Synthetic#Contexts.foo().(x)*/: Int/*->scala::Int#*/)(using Int/*->scala::Int#*/) = ???/*->scala::Predef.`???`().*/ + def m1/*<-example::Synthetic#Contexts.m1().*/(using Int/*->scala::Int#*/) = foo/*->example::Synthetic#Contexts.foo().*/(0) + def m2/*<-example::Synthetic#Contexts.m2().*/(using x/*<-example::Synthetic#Contexts.m2().(x)*/: Int/*->scala::Int#*/) = foo/*->example::Synthetic#Contexts.foo().*/(0) + def m3/*<-example::Synthetic#Contexts.m3().*/ = + given x/*<-local10*/: Int/*->scala::Int#*/ = 1 + foo/*->example::Synthetic#Contexts.foo().*/(x/*->local10*/) + def m4/*<-example::Synthetic#Contexts.m4().*/ = + given Int/*->scala::Int#*/ = 1 + foo/*->example::Synthetic#Contexts.foo().*/(0) + } } diff --git a/tests/semanticdb/expect/Synthetic.scala b/tests/semanticdb/expect/Synthetic.scala index 484e07098877..10d13e936468 100644 --- a/tests/semanticdb/expect/Synthetic.scala +++ b/tests/semanticdb/expect/Synthetic.scala @@ -47,4 +47,15 @@ class Synthetic { if a < b } yield a + object Contexts { + def foo(x: Int)(using Int) = ??? + def m1(using Int) = foo(0) + def m2(using x: Int) = foo(0) + def m3 = + given x: Int = 1 + foo(x) + def m4 = + given Int = 1 + foo(0) + } } diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index d66bf1dc17dd..da9d46d2bdff 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -362,6 +362,7 @@ Text => empty Language => Scala Symbols => 5 entries Occurrences => 4 entries +Synthetics => 1 entries Symbols: angiven/AnonymousGiven$package. => final package object angiven extends Object { self: angiven.type => +2 decls } @@ -376,6 +377,9 @@ Occurrences: [4:4..4:7): bar <- angiven/AnonymousGiven$package.bar(). [4:14..4:17): Foo -> angiven/Foo# +Synthetics: +[4:14..4:17):Foo => x$1 + expect/Classes.scala -------------------- @@ -1228,6 +1232,7 @@ Text => empty Language => Scala Symbols => 26 entries Occurrences => 50 entries +Synthetics => 2 entries Symbols: ext/Extension$package. => final package object ext extends Object { self: ext.type => +6 decls } @@ -1309,6 +1314,10 @@ Occurrences: [17:48..17:49): F -> ext/Functor#[F] [17:50..17:51): U -> ext/Functor#map().[U] +Synthetics: +[14:24..14:31):Read[T] => x$2 +[14:46..14:61):summon[Read[T]] => *(x$2) + expect/ForComprehension.scala ----------------------------- @@ -1685,6 +1694,7 @@ Text => empty Language => Scala Symbols => 45 entries Occurrences => 61 entries +Synthetics => 7 entries Symbols: givens/InventedNames$package. => final package object givens extends Object { self: givens.type => +24 decls } @@ -1796,6 +1806,15 @@ Occurrences: [41:8..41:17): given_Z_T -> givens/InventedNames$package.given_Z_T(). [41:18..41:24): String -> scala/Predef.String# +Synthetics: +[14:0..14:20):given String = "str" => given_String +[15:13..15:16):Int => x$1 +[17:0..17:28):given given_Char: Char = '?' => given_Char +[18:0..18:32):given `given_Float`: Float = 3.0 => given_Float +[24:13..24:14):X => x$1 +[34:8..34:20):given_Double => *(intValue) +[40:8..40:15):given_Y => *(given_X) + expect/Issue1749.scala ---------------------- @@ -1806,6 +1825,7 @@ Text => empty Language => Scala Symbols => 7 entries Occurrences => 22 entries +Synthetics => 2 entries Symbols: example/Issue1749# => class Issue1749 extends Object { self: Issue1749 => +3 decls } @@ -1840,6 +1860,10 @@ Occurrences: [13:49..13:55): String -> scala/Predef.String# [14:2..14:5): map -> example/Issue1854#map. +Synthetics: +[8:2..8:10):(x1, x1) => *(Tuple2(Int, Int)) +[8:10..8:10): => *(Int, Int) + expect/Local.scala ------------------ @@ -1992,6 +2016,7 @@ Text => empty Language => Scala Symbols => 3 entries Occurrences => 80 entries +Synthetics => 1 entries Symbols: example/MethodUsages# => class MethodUsages extends Object { self: MethodUsages => +2 decls } @@ -2080,6 +2105,9 @@ Occurrences: [34:4..34:7): m20 -> example/Methods#m20(+2). [34:8..34:9): m -> example/Methods#m17.m(). +Synthetics: +[13:2..13:26):m.m7(m, new m.List[Int]) => *(Int) + expect/Methods.scala -------------------- @@ -2654,6 +2682,7 @@ Text => empty Language => Scala Symbols => 68 entries Occurrences => 110 entries +Synthetics => 1 entries Symbols: example/C# => class C extends Object { self: C => +3 decls } @@ -2837,6 +2866,9 @@ Occurrences: [32:49..32:56): pickOne -> example/SpecialRefinement#pickOne(). [32:57..32:59): as -> example/PickOneRefinement_1#run().(as) +Synthetics: +[15:23..15:34):elems.toMap => *(refl[Tuple2[String, Any]]) + expect/RightAssociativeExtension.scala -------------------------------------- @@ -2922,11 +2954,22 @@ Schema => SemanticDB v4 Uri => Synthetic.scala Text => empty Language => Scala -Symbols => 40 entries -Occurrences => 112 entries +Symbols => 52 entries +Occurrences => 133 entries +Synthetics => 9 entries Symbols: -example/Synthetic# => class Synthetic extends Object { self: Synthetic => +21 decls } +example/Synthetic# => class Synthetic extends Object { self: Synthetic => +23 decls } +example/Synthetic#Contexts. => final object Contexts extends Object { self: Contexts.type => +6 decls } +example/Synthetic#Contexts.foo(). => method foo (param x: Int)(implicit given param x$2: Int): Nothing +example/Synthetic#Contexts.foo().(x$2) => implicit given param x$2: Int +example/Synthetic#Contexts.foo().(x) => param x: Int +example/Synthetic#Contexts.m1(). => method m1 (implicit given param x$1: Int): Nothing +example/Synthetic#Contexts.m1().(x$1) => implicit given param x$1: Int +example/Synthetic#Contexts.m2(). => method m2 (implicit given param x: Int): Nothing +example/Synthetic#Contexts.m2().(x) => implicit given param x: Int +example/Synthetic#Contexts.m3(). => method m3 => Nothing +example/Synthetic#Contexts.m4(). => method m4 => Nothing example/Synthetic#F# => class F extends Object { self: F => +1 decls } example/Synthetic#F#``(). => primary ctor (): F example/Synthetic#J# => class J [typeparam T ] extends Object { self: J[T] => +4 decls } @@ -2966,6 +3009,8 @@ local6 => param a: Int local7 => param b: Int 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 Occurrences: [0:8..0:15): example <- example/ @@ -3080,6 +3125,38 @@ Occurrences: [46:9..46:10): < -> scala/Int#`<`(+3). [46:11..46:12): b -> local9 [47:10..47:11): a -> local8 +[49:9..49:17): Contexts <- example/Synthetic#Contexts. +[50:8..50:11): foo <- example/Synthetic#Contexts.foo(). +[50:12..50:13): x <- example/Synthetic#Contexts.foo().(x) +[50:15..50:18): Int -> scala/Int# +[50:26..50:29): Int -> scala/Int# +[50:33..50:36): ??? -> scala/Predef.`???`(). +[51:8..51:10): m1 <- example/Synthetic#Contexts.m1(). +[51:17..51:20): Int -> scala/Int# +[51:24..51:27): foo -> example/Synthetic#Contexts.foo(). +[52:8..52:10): m2 <- example/Synthetic#Contexts.m2(). +[52:17..52:18): x <- example/Synthetic#Contexts.m2().(x) +[52:20..52:23): Int -> scala/Int# +[52:27..52:30): foo -> example/Synthetic#Contexts.foo(). +[53:8..53:10): m3 <- example/Synthetic#Contexts.m3(). +[54:12..54:13): x <- local10 +[54:15..54:18): Int -> scala/Int# +[55:6..55:9): foo -> example/Synthetic#Contexts.foo(). +[55:10..55:11): x -> local10 +[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(). + +Synthetics: +[32:35..32:49):Array.empty[T] => *(evidence$1) +[36:22..36:27):new F => *(ordering) +[50:26..50:29):Int => x$2 +[51:17..51:20):Int => x$1 +[51:24..51:30):foo(0) => *(x$1) +[52:27..52:33):foo(0) => *(x) +[55:6..55:12):foo(x) => *(x) +[57:6..57:19):given Int = 1 => given_Int +[58:6..58:12):foo(0) => *(given_Int) expect/Traits.scala ------------------- @@ -4512,6 +4589,7 @@ Text => empty Language => Scala Symbols => 19 entries Occurrences => 34 entries +Synthetics => 1 entries Symbols: _empty_/MyProgram# => final class MyProgram extends Object { self: MyProgram => +2 decls } @@ -4570,3 +4648,6 @@ Occurrences: [6:4..6:10): fooRef <- _empty_/toplevel$package.fooRef(). [6:30..6:33): foo -> _empty_/toplevel$package.foo(). +Synthetics: +[5:0..5:0): => *(given_FromString_Int) + From 28c384676b289549533cb854c4a8c31dac6aaa59 Mon Sep 17 00:00:00 2001 From: Rikito Taniguchi Date: Wed, 11 Aug 2021 20:01:20 +0900 Subject: [PATCH 2/7] Support implicit conversion for Synthetics --- .../dotc/semanticdb/SyntheticsExtractor.scala | 12 ++++++ tests/semanticdb/metac.expect | 40 +++++++++++++++++-- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala b/compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala index ccc33aba63f9..6753e7ba01a7 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala @@ -33,6 +33,18 @@ class SyntheticsExtractor: ) ).toOpt + case tree: Apply if tree.fun.symbol.is(Implicit) => + val pos = range(tree.span, tree.source) + s.Synthetic( + pos, + s.ApplyTree( + tree.fun.toSemanticTree, + arguments = List( + s.OriginalTree(pos) + ) + ) + ).toOpt + // Anonymous context parameter case tree: ValDef if tree.symbol.is(Given) => s.Synthetic( diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index da9d46d2bdff..4bdb28cc62b8 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -50,6 +50,7 @@ Text => empty Language => Scala Symbols => 48 entries Occurrences => 105 entries +Synthetics => 3 entries Symbols: advanced/C# => class C [typeparam T ] extends Object { self: C[T] => +3 decls } @@ -208,6 +209,11 @@ Occurrences: [48:37..48:38): x -> advanced/HKClass#foo().(x) [48:39..48:47): toString -> scala/Tuple2#toString(). +Synthetics: +[26:12..26:16):s.s1 => reflectiveSelectable(*) +[28:12..28:16):s.s2 => reflectiveSelectable(*) +[30:12..30:16):s.s3 => reflectiveSelectable(*) + expect/Annotations.scala ------------------------ @@ -1514,6 +1520,7 @@ Text => empty Language => Scala Symbols => 23 entries Occurrences => 48 entries +Synthetics => 6 entries Symbols: example/ImplicitConversion# => class ImplicitConversion extends Object { self: ImplicitConversion => +9 decls } @@ -1590,6 +1597,16 @@ Occurrences: [34:56..34:57): + -> java/lang/String#`+`(). [34:58..34:63): other -> example/ImplicitConversion.newAny2stringadd#`+`().(other) +Synthetics: +[15:2..15:9):message => augmentString(*) +[17:2..17:7):tuple => newAny2stringadd[Tuple2[Int, Int]](*) +[20:15..20:22):message => string2Number(*) +[24:2..26:16):s"""Hello + |$message + |$number""" => augmentString(*) +[28:15..28:19):char => char2int(*) +[29:16..29:20):char => char2long(*) + expect/Imports.scala -------------------- @@ -1825,7 +1842,7 @@ Text => empty Language => Scala Symbols => 7 entries Occurrences => 22 entries -Synthetics => 2 entries +Synthetics => 3 entries Symbols: example/Issue1749# => class Issue1749 extends Object { self: Issue1749 => +3 decls } @@ -1861,6 +1878,7 @@ Occurrences: [14:2..14:5): map -> example/Issue1854#map. Synthetics: +[8:2..8:10):(x1, x1) => orderingToOrdered[Tuple2[Int, Int]](*) [8:2..8:10):(x1, x1) => *(Tuple2(Int, Int)) [8:10..8:10): => *(Int, Int) @@ -2956,7 +2974,7 @@ Text => empty Language => Scala Symbols => 52 entries Occurrences => 133 entries -Synthetics => 9 entries +Synthetics => 24 entries Symbols: example/Synthetic# => class Synthetic extends Object { self: Synthetic => +23 decls } @@ -3148,7 +3166,22 @@ Occurrences: [58:6..58:9): foo -> example/Synthetic#Contexts.foo(). Synthetics: +[6:2..6:18):Array.empty[Int] => intArrayOps(*) +[7:2..7:8):"fooo" => augmentString(*) +[10:13..10:24):"name:(.*)" => augmentString(*) +[13:8..13:28):2 #:: LazyList.empty => toDeferrer[Int](*) +[13:14..13:28):LazyList.empty => toDeferrer[Nothing](*) +[17:18..17:38):2 #:: LazyList.empty => toDeferrer[Int](*) +[17:24..17:38):LazyList.empty => toDeferrer[Nothing](*) +[19:12..19:13):1 => intWrapper(*) +[19:26..19:27):0 => intWrapper(*) +[19:46..19:47):x => ArrowAssoc[Int](*) +[20:12..20:13):1 => intWrapper(*) +[20:26..20:27):0 => intWrapper(*) +[21:12..21:13):1 => intWrapper(*) +[21:26..21:27):0 => intWrapper(*) [32:35..32:49):Array.empty[T] => *(evidence$1) +[36:22..36:27):new F => orderingToOrdered[F](*) [36:22..36:27):new F => *(ordering) [50:26..50:29):Int => x$2 [51:17..51:20):Int => x$1 @@ -4589,7 +4622,7 @@ Text => empty Language => Scala Symbols => 19 entries Occurrences => 34 entries -Synthetics => 1 entries +Synthetics => 2 entries Symbols: _empty_/MyProgram# => final class MyProgram extends Object { self: MyProgram => +2 decls } @@ -4650,4 +4683,5 @@ Occurrences: Synthetics: [5:0..5:0): => *(given_FromString_Int) +[5:41..5:42):1 => intWrapper(*) From 3a9fbd0736d8b583ba7ba387c3a1efd107152f4a Mon Sep 17 00:00:00 2001 From: Rikito Taniguchi Date: Fri, 13 Aug 2021 03:13:49 +0900 Subject: [PATCH 3/7] Exclude named given from synthetics (when name starts with `given_`) --- .../dotc/semanticdb/ExtractSemanticDB.scala | 28 +++------------ .../dotty/tools/dotc/semanticdb/Scala3.scala | 36 +++++++++++++++---- .../dotc/semanticdb/SyntheticsExtractor.scala | 2 +- tests/semanticdb/metac.expect | 4 +-- 4 files changed, 37 insertions(+), 33 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala index 18353b307d11..5ad52224374d 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala @@ -171,11 +171,11 @@ class ExtractSemanticDB extends Phase: // ignore rhs // `given Int` (syntax sugar of `given given_Int: Int`) - case tree: ValDef if tree.symbol.isInventedGiven => - synth.tryFindSynthetic(tree).foreach { synth => - synthetics += synth - } - traverse(tree.tpt) + case tree: ValDef if isInventedGiven(tree) => + synth.tryFindSynthetic(tree).foreach { synth => + synthetics += synth + } + traverse(tree.tpt) case PatternValDef(pat, rhs) => traverse(rhs) PatternValDef.collectPats(pat).foreach(traverse) @@ -349,24 +349,6 @@ class ExtractSemanticDB extends Phase: if !sym.is(Package) then registerSymbol(sym, symkinds) - private def namePresentInSource(sym: Symbol, span: Span, source:SourceFile)(using Context): Boolean = - if !span.exists then false - else - val content = source.content() - val (start, end) = - if content.lift(span.end - 1).exists(_ == '`') then - (span.start + 1, span.end - 1) - else (span.start, span.end) - val nameInSource = content.slice(start, end).mkString - // for secondary constructors `this` - if sym.isConstructor && nameInSource == nme.THISkw.toString then - true - else - val target = - if sym.isPackageObject then sym.owner - else sym - nameInSource == target.name.stripModuleClassSuffix.lastPart.toString - private def spanOfSymbol(sym: Symbol, span: Span, treeSource: SourceFile)(using Context): Span = val contents = if treeSource.exists then treeSource.content() else Array.empty[Char] val idx = contents.indexOfSlice(sym.name.show, span.start) diff --git a/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala b/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala index 555492e5b8a5..d6da9a2c6861 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala @@ -36,6 +36,24 @@ object Scala3: val (endLine, endCol) = lineCol(span.end) Some(Range(startLine, startCol, endLine, endCol)) + def namePresentInSource(sym: Symbol, span: Span, source:SourceFile)(using Context): Boolean = + if !span.exists then false + else + val content = source.content() + val (start, end) = + if content.lift(span.end - 1).exists(_ == '`') then + (span.start + 1, span.end - 1) + else (span.start, span.end) + val nameInSource = content.slice(start, end).mkString + // for secondary constructors `this` + if sym.isConstructor && nameInSource == nme.THISkw.toString then + true + else + val target = + if sym.isPackageObject then sym.owner + else sym + nameInSource == target.name.stripModuleClassSuffix.lastPart.toString + sealed trait FakeSymbol { private[Scala3] var sname: Option[String] = None } @@ -231,12 +249,6 @@ object Scala3: def isSyntheticWithIdent(using Context): Boolean = sym.is(Synthetic) && !sym.isAnonymous && !sym.name.isEmptyNumbered - /** Check if the symbol is invented by Desugar.inventGivenOrExtensionName - * return true if the symbol is defined as `given Int = ...` and name is invented as "given_Int" - */ - def isInventedGiven(using Context): Boolean = - sym.is(Given) && sym.name.startsWith("given_") - /** The semanticdb name of the given symbol */ def symbolName(using builder: SemanticSymbolBuilder)(using Context): String = builder.symbolName(sym) @@ -502,4 +514,16 @@ object Scala3: end IdentifierOrdering + /** Check if the symbol is invented by Desugar.inventGivenOrExtensionName + * return true if the symbol is defined as `given Int = ...` and name is invented as "given_Int" + */ + def isInventedGiven(tree: tpd.Tree)(using Context): Boolean = + tree match + case tree: tpd.ValDef => + val sym = tree.symbol + sym.is(Given) && + sym.name.startsWith("given_") && + !namePresentInSource(sym, tree.nameSpan, tree.source) + case _ => false + end Scala3 diff --git a/compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala b/compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala index 6753e7ba01a7..af02b86b4c5d 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala @@ -15,7 +15,7 @@ class SyntheticsExtractor: extension (synth: s.Synthetic) def toOpt: Some[s.Synthetic] = Some(synth) - if tree.span.isSynthetic || tree.symbol.isInventedGiven then + if tree.span.isSynthetic || isInventedGiven(tree) then tree match case tree: Apply if isForSynthetic(tree) => None // not yet supported (for synthetics) diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index 4bdb28cc62b8..91e6a6cebf87 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -1711,7 +1711,7 @@ Text => empty Language => Scala Symbols => 45 entries Occurrences => 61 entries -Synthetics => 7 entries +Synthetics => 5 entries Symbols: givens/InventedNames$package. => final package object givens extends Object { self: givens.type => +24 decls } @@ -1826,8 +1826,6 @@ Occurrences: Synthetics: [14:0..14:20):given String = "str" => given_String [15:13..15:16):Int => x$1 -[17:0..17:28):given given_Char: Char = '?' => given_Char -[18:0..18:32):given `given_Float`: Float = 3.0 => given_Float [24:13..24:14):X => x$1 [34:8..34:20):given_Double => *(intValue) [40:8..40:15):given_Y => *(given_X) From fd67b6eca4c36d0a0988b59912f3e8d5fcc2e19b Mon Sep 17 00:00:00 2001 From: Rikito Taniguchi Date: Mon, 23 Aug 2021 13:49:58 +0900 Subject: [PATCH 4/7] Refactor ExtractSemanticDB --- .../dotc/semanticdb/ExtractSemanticDB.scala | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala index 5ad52224374d..65897ef3fda9 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala @@ -49,7 +49,7 @@ class ExtractSemanticDB extends Phase: /** Extractor of symbol occurrences from trees */ class Extractor extends TreeTraverser: - given builder: s.SemanticSymbolBuilder = s.SemanticSymbolBuilder() + given s.SemanticSymbolBuilder = s.SemanticSymbolBuilder() val synth = SyntheticsExtractor() given converter: s.TypeOps = s.TypeOps() @@ -156,26 +156,18 @@ class ExtractSemanticDB extends Phase: case tree: DefDef if tree.symbol.isConstructor => // ignore typeparams for secondary ctors tree.trailingParamss.foreach(_.foreach(traverse)) traverse(tree.rhs) - case tree: (DefDef | ValDef) if tree.symbol.isSyntheticWithIdent => + case tree: (DefDef | ValDef) if tree.symbol.isSyntheticWithIdent || isInventedGiven(tree) => tree match case tree: DefDef => tree.paramss.foreach(_.foreach(param => registerSymbolSimple(param.symbol))) case tree: ValDef if tree.symbol.is(Given) => - synth.tryFindSynthetic(tree).foreach { synth => - synthetics += synth - } + synth.tryFindSynthetic(tree).foreach(synthetics.addOne) traverse(tree.tpt) case _ => if !tree.symbol.isGlobal then localBodies(tree.symbol) = tree.rhs // ignore rhs - // `given Int` (syntax sugar of `given given_Int: Int`) - case tree: ValDef if isInventedGiven(tree) => - synth.tryFindSynthetic(tree).foreach { synth => - synthetics += synth - } - traverse(tree.tpt) case PatternValDef(pat, rhs) => traverse(rhs) PatternValDef.collectPats(pat).foreach(traverse) @@ -210,10 +202,7 @@ class ExtractSemanticDB extends Phase: case tree: Apply => @tu lazy val genParamSymbol: Name => String = tree.fun.symbol.funParamSymbol traverse(tree.fun) - synth.tryFindSynthetic(tree).foreach { synth => - synthetics += synth - } - + synth.tryFindSynthetic(tree).foreach(synthetics.addOne) for arg <- tree.args do arg match case tree @ NamedArg(name, arg) => From aef23bce20b273935a629b33ed36a3bb7e610b53 Mon Sep 17 00:00:00 2001 From: Rikito Taniguchi Date: Wed, 25 Aug 2021 02:10:30 +0900 Subject: [PATCH 5/7] Revert invented givens and anonymous using params for the time being We have a discussion how to express the invented variable names in SemanticDB. We'll discuss the design of the tree in the issue and come back in the future. --- .../dotc/semanticdb/ExtractSemanticDB.scala | 3 +-- .../dotty/tools/dotc/semanticdb/Scala3.scala | 12 ------------ .../dotc/semanticdb/SyntheticsExtractor.scala | 8 +------- tests/semanticdb/metac.expect | 17 +++-------------- 4 files changed, 5 insertions(+), 35 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala index 65897ef3fda9..66777e0b2c1a 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala @@ -156,12 +156,11 @@ class ExtractSemanticDB extends Phase: case tree: DefDef if tree.symbol.isConstructor => // ignore typeparams for secondary ctors tree.trailingParamss.foreach(_.foreach(traverse)) traverse(tree.rhs) - case tree: (DefDef | ValDef) if tree.symbol.isSyntheticWithIdent || isInventedGiven(tree) => + case tree: (DefDef | ValDef) if tree.symbol.isSyntheticWithIdent => tree match case tree: DefDef => tree.paramss.foreach(_.foreach(param => registerSymbolSimple(param.symbol))) case tree: ValDef if tree.symbol.is(Given) => - synth.tryFindSynthetic(tree).foreach(synthetics.addOne) traverse(tree.tpt) case _ => if !tree.symbol.isGlobal then diff --git a/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala b/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala index d6da9a2c6861..c8d418f236c7 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala @@ -514,16 +514,4 @@ object Scala3: end IdentifierOrdering - /** Check if the symbol is invented by Desugar.inventGivenOrExtensionName - * return true if the symbol is defined as `given Int = ...` and name is invented as "given_Int" - */ - def isInventedGiven(tree: tpd.Tree)(using Context): Boolean = - tree match - case tree: tpd.ValDef => - val sym = tree.symbol - sym.is(Given) && - sym.name.startsWith("given_") && - !namePresentInSource(sym, tree.nameSpan, tree.source) - case _ => false - end Scala3 diff --git a/compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala b/compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala index af02b86b4c5d..c6d87c67a578 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala @@ -15,7 +15,7 @@ class SyntheticsExtractor: extension (synth: s.Synthetic) def toOpt: Some[s.Synthetic] = Some(synth) - if tree.span.isSynthetic || isInventedGiven(tree) then + if tree.span.isSynthetic then tree match case tree: Apply if isForSynthetic(tree) => None // not yet supported (for synthetics) @@ -45,12 +45,6 @@ class SyntheticsExtractor: ) ).toOpt - // Anonymous context parameter - case tree: ValDef if tree.symbol.is(Given) => - s.Synthetic( - range(tree.span, tree.source), - tree.toSemanticId - ).toOpt case _ => None else None diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index 91e6a6cebf87..4e1ec228b797 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -368,7 +368,6 @@ Text => empty Language => Scala Symbols => 5 entries Occurrences => 4 entries -Synthetics => 1 entries Symbols: angiven/AnonymousGiven$package. => final package object angiven extends Object { self: angiven.type => +2 decls } @@ -383,9 +382,6 @@ Occurrences: [4:4..4:7): bar <- angiven/AnonymousGiven$package.bar(). [4:14..4:17): Foo -> angiven/Foo# -Synthetics: -[4:14..4:17):Foo => x$1 - expect/Classes.scala -------------------- @@ -1238,7 +1234,7 @@ Text => empty Language => Scala Symbols => 26 entries Occurrences => 50 entries -Synthetics => 2 entries +Synthetics => 1 entries Symbols: ext/Extension$package. => final package object ext extends Object { self: ext.type => +6 decls } @@ -1321,7 +1317,6 @@ Occurrences: [17:50..17:51): U -> ext/Functor#map().[U] Synthetics: -[14:24..14:31):Read[T] => x$2 [14:46..14:61):summon[Read[T]] => *(x$2) expect/ForComprehension.scala @@ -1711,7 +1706,7 @@ Text => empty Language => Scala Symbols => 45 entries Occurrences => 61 entries -Synthetics => 5 entries +Synthetics => 2 entries Symbols: givens/InventedNames$package. => final package object givens extends Object { self: givens.type => +24 decls } @@ -1824,9 +1819,6 @@ Occurrences: [41:18..41:24): String -> scala/Predef.String# Synthetics: -[14:0..14:20):given String = "str" => given_String -[15:13..15:16):Int => x$1 -[24:13..24:14):X => x$1 [34:8..34:20):given_Double => *(intValue) [40:8..40:15):given_Y => *(given_X) @@ -2972,7 +2964,7 @@ Text => empty Language => Scala Symbols => 52 entries Occurrences => 133 entries -Synthetics => 24 entries +Synthetics => 21 entries Symbols: example/Synthetic# => class Synthetic extends Object { self: Synthetic => +23 decls } @@ -3181,12 +3173,9 @@ 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) -[50:26..50:29):Int => x$2 -[51:17..51:20):Int => x$1 [51:24..51:30):foo(0) => *(x$1) [52:27..52:33):foo(0) => *(x) [55:6..55:12):foo(x) => *(x) -[57:6..57:19):given Int = 1 => given_Int [58:6..58:12):foo(0) => *(given_Int) expect/Traits.scala From a4f14007d95233fccc1d43f30ccd32e829d3d354 Mon Sep 17 00:00:00 2001 From: Rikito Taniguchi Date: Wed, 25 Aug 2021 02:25:30 +0900 Subject: [PATCH 6/7] Exclude synthesized parseArgument(given_FromString_Int) by @main By checking if the template's owner module symbol has an Invisible flag. --- .../dotc/semanticdb/ExtractSemanticDB.scala | 4 +++ tests/semanticdb/expect/toplevel.expect.scala | 1 + tests/semanticdb/expect/toplevel.scala | 1 + tests/semanticdb/metac.expect | 28 +++++++++++-------- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala index 66777e0b2c1a..d282695c07fa 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala @@ -183,6 +183,10 @@ class ExtractSemanticDB extends Phase: registerUseGuarded(None, privateWithin, spanOfSymbol(privateWithin, tree.span, tree.source), tree.source) else if !excludeSymbol(tree.symbol) then registerSymbol(tree.symbol, symbolKinds(tree)) + case tree: Template if tree.symbol.owner.is(Invisible) => + // do nothing + // exclude the symbols and synthetics generated by @main annotation + // (main class generated by @main has `Invisible` flag, see `MainProxies.scala`). case tree: Template => val ctorSym = tree.constr.symbol for parent <- tree.parentsOrDerived if parent.span.hasLength do diff --git a/tests/semanticdb/expect/toplevel.expect.scala b/tests/semanticdb/expect/toplevel.expect.scala index 67164c326def..6348125a2afd 100644 --- a/tests/semanticdb/expect/toplevel.expect.scala +++ b/tests/semanticdb/expect/toplevel.expect.scala @@ -4,4 +4,5 @@ def combine/*<-_empty_::toplevel$package.combine(+1).*/(x/*<-_empty_::toplevel$p def combine/*<-_empty_::toplevel$package.combine(+2).*/ = 0 def foo/*<-_empty_::toplevel$package.foo().*/ = "foo" @main/*->scala::main#*/ def MyProgram/*<-_empty_::toplevel$package.MyProgram().*/(times/*<-_empty_::toplevel$package.MyProgram().(times)*/: Int/*->scala::Int#*/): Unit/*->scala::Unit#*/ = (1 to/*->scala::runtime::RichInt#to().*/ times/*->_empty_::toplevel$package.MyProgram().(times)*/) foreach/*->scala::collection::immutable::Range#foreach().*/ (_ => println/*->scala::Predef.println(+1).*/("hello")) +@main/*->scala::main#*/ def readInts/*<-_empty_::toplevel$package.readInts().*/(ints/*<-_empty_::toplevel$package.readInts().(ints)*/: Int/*->scala::Int#*/*): Unit/*->scala::Unit#*/ = println/*->scala::Predef.println(+1).*/(ints/*->_empty_::toplevel$package.readInts().(ints)*/.mkString/*->scala::collection::IterableOnceOps#mkString(+1).*/(",")) def fooRef/*<-_empty_::toplevel$package.fooRef().*/ = toplevel$package.foo/*->_empty_::toplevel$package.foo().*/ diff --git a/tests/semanticdb/expect/toplevel.scala b/tests/semanticdb/expect/toplevel.scala index e6af17e14953..c4340efcf212 100644 --- a/tests/semanticdb/expect/toplevel.scala +++ b/tests/semanticdb/expect/toplevel.scala @@ -4,4 +4,5 @@ def combine(x: Int, y: Int, z: Int) = x + y + z def combine = 0 def foo = "foo" @main def MyProgram(times: Int): Unit = (1 to times) foreach (_ => println("hello")) +@main def readInts(ints: Int*): Unit = println(ints.mkString(",")) def fooRef = toplevel$package.foo diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index 4e1ec228b797..ab53219571b6 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -4607,16 +4607,14 @@ Schema => SemanticDB v4 Uri => toplevel.scala Text => empty Language => Scala -Symbols => 19 entries -Occurrences => 34 entries -Synthetics => 2 entries +Symbols => 18 entries +Occurrences => 42 entries +Synthetics => 1 entries Symbols: _empty_/MyProgram# => final class MyProgram extends Object { self: MyProgram => +2 decls } -_empty_/MyProgram#``(). => primary ctor (): MyProgram -_empty_/MyProgram#main(). => static method main (param args: Array[String]): Unit -_empty_/MyProgram#main().(args) => param args: Array[String] -_empty_/toplevel$package. => final package object _empty_ extends Object { self: _empty_.type => +8 decls } +_empty_/readInts# => final class readInts extends Object { self: readInts => +2 decls } +_empty_/toplevel$package. => final package object _empty_ extends Object { self: _empty_.type => +9 decls } _empty_/toplevel$package.MyProgram(). => method MyProgram (param times: Int): Unit _empty_/toplevel$package.MyProgram().(times) => param times: Int _empty_/toplevel$package.a. => val inline method a "" @@ -4630,7 +4628,8 @@ _empty_/toplevel$package.combine(+1).(z) => param z: Int _empty_/toplevel$package.combine(+2). => method combine => Int _empty_/toplevel$package.foo(). => method foo => String _empty_/toplevel$package.fooRef(). => method fooRef => String -local0 => val local error: ParseError +_empty_/toplevel$package.readInts(). => method readInts (param ints: Int*): Unit +_empty_/toplevel$package.readInts().(ints) => param ints: Int* Occurrences: [0:11..0:12): a <- _empty_/toplevel$package.a. @@ -4665,10 +4664,17 @@ Occurrences: [5:46..5:51): times -> _empty_/toplevel$package.MyProgram().(times) [5:53..5:60): foreach -> scala/collection/immutable/Range#foreach(). [5:67..5:74): println -> scala/Predef.println(+1). -[6:4..6:10): fooRef <- _empty_/toplevel$package.fooRef(). -[6:30..6:33): foo -> _empty_/toplevel$package.foo(). +[6:1..6:5): main -> scala/main# +[6:10..6:18): readInts <- _empty_/toplevel$package.readInts(). +[6:19..6:23): ints <- _empty_/toplevel$package.readInts().(ints) +[6:25..6:28): Int -> scala/Int# +[6:32..6:36): Unit -> scala/Unit# +[6:39..6:46): println -> scala/Predef.println(+1). +[6:47..6:51): ints -> _empty_/toplevel$package.readInts().(ints) +[6:52..6:60): mkString -> scala/collection/IterableOnceOps#mkString(+1). +[7:4..7:10): fooRef <- _empty_/toplevel$package.fooRef(). +[7:30..7:33): foo -> _empty_/toplevel$package.foo(). Synthetics: -[5:0..5:0): => *(given_FromString_Int) [5:41..5:42):1 => intWrapper(*) From 0edab1a57b04e5382b90b4ee5f95aab62f221776 Mon Sep 17 00:00:00 2001 From: Rikito Taniguchi Date: Sat, 28 Aug 2021 02:52:48 +0900 Subject: [PATCH 7/7] updateExpect --- tests/semanticdb/metac.expect | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index ab53219571b6..1c95e06cae7c 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -1706,7 +1706,7 @@ Text => empty Language => Scala Symbols => 45 entries Occurrences => 61 entries -Synthetics => 2 entries +Synthetics => 3 entries Symbols: givens/InventedNames$package. => final package object givens extends Object { self: givens.type => +24 decls } @@ -1819,6 +1819,7 @@ Occurrences: [41:18..41:24): String -> scala/Predef.String# Synthetics: +[24:0..24:0): => *(x$1) [34:8..34:20):given_Double => *(intValue) [40:8..40:15):given_Y => *(given_X)