scala3 icon indicating copy to clipboard operation
scala3 copied to clipboard

Add Synthetics section to SemanticDB

Open tanishiking opened this issue 3 years ago • 4 comments

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

  • Unique to Scala3
    • [ ] Context parameter application
      • [x] https://github.com/lampepfl/dotty/pull/13288
      • [ ] https://github.com/scalameta/scalameta/issues/2460
    • [ ] Anonymous Context Parameters
      • https://github.com/scalameta/scalameta/issues/2458
    • [ ] Extension method?
  • Scala2 compatible
    • [ ] Inferred method application
      • https://github.com/tanishiking/dotty/pull/5
    • [ ] Inferred Type Application
    • [x] Implicit parameters
      • https://github.com/lampepfl/dotty/pull/13288
    • [x] Implicit Conversions
      • https://github.com/lampepfl/dotty/pull/13288
    • [ ] macro expansion (low priority)
    • [ ] For loop desugaring (low priority)

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
            }
          }
        }
      }
    }
  }
}

tanishiking avatar Jul 23 '21 07:07 tanishiking