Skip to content

Add Synthetics section to SemanticDB #13135

Closed
0 of 3 issues completed
Closed
0 of 3 issues completed
@tanishiking

Description

@tanishiking

https://scalameta.org/docs/semanticdb/specification.html#synthetic

"Synthetics" is a section of a TextDocument that stores trees added by compilers that do not appear in the original source. Examples include inferred type arguments, implicit parameters, or desugarings of for loops.

One of the main consumers of Synthetics information of SemanticDB is decraotion feature of metals, and once Scala3 extract these information, those features are available for Scala3 in Metals.

TODO

If there's something we should add to Synthetic section, please let me know :)

Using parameter application

def foo(using x: Int) = ???
def bar(using x: Int) = foo
  
// synthetic
def foo(using x: Int): Nothing = ???
def bar(using x: Int): Nothing = foo(x)

what should we do for anonymous context params?

def foo(using Int) = ???
def bar(using Int) = foo
 
// synthetic
def foo(using x$1: Int): Nothing = ???
def bar(using x$1: Int): Nothing = classes.foo(x$1)

should we add x$1 to synthetics?

Synthetic(
  <foo>,
  ApplyTree(
    OriginalTree(<foo>),
    List(
        IdTree(<x>),
    )
  ))
)

Anonymous context params

def foo(using Int) = ???
 
// synthetic
def foo(using x$1: Int) = ???
Synthetic(
  <using>,
  IdTree(<x$1>)
)

Extension method application?

Wondering how should we design the Synthetics Tree for the extension method...

extension (x: Int)
  def plus(y: Int) = x + y

def main() = 1.plus(3)
// synthetic
def main() = plus(1)(3)

Maybe we don't need to extract synthetics for the extension method at this moment, because the main consumer of the synthetics section of SemancticDB is metals's Decoration feature.
While extracting Implicit conversion for Scala2 is important for implicit decoration's readability, showing plus(1)(3) for the extension method doesn't help developers to read those programs.

Scala2 compatible synthetics

Inferred method application

val x = List(1)
val List(a, b) = List(1, 2)

// synthetics
val x = List.apply[Int](1)
val List.unapplySeq[Int](a, b) = List.apply[Int](1, 2)
Synthetic(
  <List>,
  TypeApplyTree(
    SelectTree(
      OriginalTree(<List>),
      Some(IdTree(<List.apply>))),
    List(TypeRef(None, <Int>, List()))
  )
)

Synthetic(
  <List>,
  TypeApplyTree(
    SelectTree(
      OriginalTree(<List>),
      Some(IdTree(<SeqFactory.unapplySeq>))),
    List(TypeRef(None, <Nothing>, List()))
  )
)

Inferred Type Application

List(1).map(_ + 2)
1 #:: 2 #:: Stream.empty

// synthetic
List.apply[Int](1).map[Int](_ + 2)
1 #:: 2 #:: Stream.empty[Int]
Synthetic(
  <List>,
  TypeApplyTree(
    SelectTree(
      OriginalTree(<List>),
      Some(IdTree(<List.apply>))),
    List(TypeRef(None, <Int>, List()))
  )
)
Synthetic(
  <List(1).map>,
  TypeApplyTree(
    OriginalTree(<List(1).map>),
    List(
      TypeRef(None, <Int>, List()),
      TypeRef(None, <List>,
        List(TypeRef(None, <Int>, List()))))
  )
)

Synthetic(
  <#:: 2 #:: Stream.empty>,
  TypeApplyTree(
    OriginalTree(<#:: 2 #:: Stream.empty>),
    List(
      TypeRef(None, <Int>, List())))
)

Implicit parameters

Seq.apply[Int](1,2,3).sorted[Int]

// synthetic
Seq.apply[Int](1,2,3).sorted[Int](Ordering.Int)
Synthetic(
  <Seq.apply[Int](1,2,3).sorted[Int]>,
  ApplyTree(
    OriginalTree(<Seq.apply[Int](1,2,3).sorted[Int]),
    List(
        IdTree(<Ordering.Int>),
    )
  ))
)

implicit conversion

"fooo".stripPrefix("o")
 
// synthetic
augmentString("fooo").stripPrefix("o")
Synthetic(
  <"fooo">,
  ApplyTree(
    IdTree(<Predef.augmentString>),
    List(OriginalTree(<"fooo">)))
)

Macro Expansion

Array.empty[Int] 
Synthetic(
  <Array.empty[Int]>,
  ApplyTree(
    OriginalTree(<Array.empty[Int]>),
    List(
      MacroExpansionTree(
        IdTree(<ClassTag.Int>),
        TypeRef(None, <ClassTag>,
          List(TypeRef(None, <Int>, List())))))))

For loop desugaring

object Test {
  for {
    i <- 1 to 10
    j <- 0 until 10
    if i % 2 == 0
  } yield (i, j)
}
documents {
  schema: SEMANTICDB4
  synthetics {
    range {
      start_line: 1
      start_character: 2
      end_line: 5
      end_character: 16
    }
    tree {
      apply_tree {
        function {
          type_apply_tree {
            function {
              select_tree {
                qualifier {
                  original_tree {
                    range {
                      start_line: 2
                      start_character: 9
                      end_line: 2
                      end_character: 16
                    }
                  }
                }
                id {
                  symbol: "scala/collection/StrictOptimizedIterableOps#flatMap()."
                }
              }
            }
            type_arguments {
              type_ref {
                symbol: "scala/Tuple2#"
                type_arguments {
                  type_ref {
                    symbol: "scala/Int#"
                  }
                }
                type_arguments {
                  type_ref {
                    symbol: "scala/Int#"
                  }
                }
              }
            }
          }
        }
        arguments {
          function_tree {
            parameters {
              symbol: "local0"
            }
            body {
              apply_tree {
                function {
                  type_apply_tree {
                    function {
                      select_tree {
                        qualifier {
                          apply_tree {
                            function {
                              select_tree {
                                qualifier {
                                  original_tree {
                                    range {
                                      start_line: 3
                                      start_character: 9
                                      end_line: 3
                                      end_character: 19
                                    }
                                  }
                                }
                                id {
                                  symbol: "scala/collection/IterableOps#withFilter()."
                                }
                              }
                            }
                            arguments {
                              function_tree {
                                parameters {
                                  symbol: "local1"
                                }
                                body {
                                  original_tree {
                                    range {
                                      start_line: 4
                                      start_character: 7
                                      end_line: 4
                                      end_character: 17
                                    }
                                  }
                                }
                              }
                            }
                          }
                        }
                        id {
                          symbol: "scala/collection/WithFilter#map()."
                        }
                      }
                    }
                    type_arguments {
                      type_ref {
                        symbol: "scala/Tuple2#"
                        type_arguments {
                          type_ref {
                            symbol: "scala/Int#"
                          }
                        }
                        type_arguments {
                          type_ref {
                            symbol: "scala/Int#"
                          }
                        }
                      }
                    }
                  }
                }
                arguments {
                  function_tree {
                    parameters {
                      symbol: "local1"
                    }
                    body {
                      original_tree {
                        range {
                          start_line: 5
                          start_character: 10
                          end_line: 5
                          end_character: 16
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  synthetics {
    range {
      start_line: 2
      start_character: 9
      end_line: 2
      end_character: 10
    }
    tree {
      apply_tree {
        function {
          id_tree {
            symbol: "scala/LowPriorityImplicits#intWrapper()."
          }
        }
        arguments {
          original_tree {
            range {
              start_line: 2
              start_character: 9
              end_line: 2
              end_character: 10
            }
          }
        }
      }
    }
  }
  synthetics {
    range {
      start_line: 3
      start_character: 9
      end_line: 3
      end_character: 10
    }
    tree {
      apply_tree {
        function {
          id_tree {
            symbol: "scala/LowPriorityImplicits#intWrapper()."
          }
        }
        arguments {
          original_tree {
            range {
              start_line: 3
              start_character: 9
              end_line: 3
              end_character: 10
            }
          }
        }
      }
    }
  }
}

Sub-issues

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions