Skip to content

Commit afff105

Browse files
committed
support pattern vals
1 parent 298b2b4 commit afff105

File tree

8 files changed

+236
-200
lines changed

8 files changed

+236
-200
lines changed

compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,10 @@ class ExtractSemanticDB extends Phase with
114114

115115
for annot <- tree.symbol.annotations do
116116
if annot.tree.span.exists
117-
&& annot.symbol.owner != defn.ScalaAnnotationInternal
118-
then
119-
traverse(annot.tree)
117+
&& annot.tree.span.hasLength
118+
annot.tree match
119+
case tree: Typed => () // hack for inline code
120+
case tree => traverse(tree)
120121

121122
tree match
122123
case tree: PackageDef =>
@@ -162,6 +163,9 @@ class ExtractSemanticDB extends Phase with
162163
tree.vparamss.foreach(_.foreach(vparam => registerSymbolSimple(vparam.symbol)))
163164
case _ =>
164165
// ignore rhs
166+
case PatternValDef(pat, rhs) =>
167+
traverse(rhs)
168+
PatternValDef.collectUnapplyFuncs(pat).foreach(traverse)
165169
case tree =>
166170
if !excludeChildren(tree.symbol)
167171
traverseChildren(tree)
@@ -216,6 +220,37 @@ class ExtractSemanticDB extends Phase with
216220
case _ =>
217221
traverseChildren(tree)
218222

223+
end traverse
224+
225+
private object PatternValDef with
226+
227+
def unapply(tree: ValDef)(given Context): Option[(Tree, Tree)] = tree.rhs match
228+
229+
case Match(Typed(selected: Tree, tpt: TypeTree), CaseDef(pat: Tree, _, _) :: Nil)
230+
if tpt.span.exists && !tpt.span.hasLength && tpt.tpe.isAnnotatedByUnchecked =>
231+
Some((pat, selected))
232+
233+
case _ => None
234+
235+
private inline def (tpe: Types.Type) isAnnotatedByUnchecked(given Context) = tpe match
236+
case Types.AnnotatedType(_, annot) => annot.symbol == defn.UncheckedAnnot
237+
case _ => false
238+
239+
def collectUnapplyFuncs(pat: Tree): List[Tree] =
240+
241+
@tailrec
242+
def impl(acc: List[Tree], pats: List[Tree]): List[Tree] = pats match
243+
case pat::pats => pat match
244+
case Typed(UnApply(fun: Tree, _, args), _) => impl(fun::acc, args:::pats)
245+
case UnApply(fun: Tree, _, args) => impl(fun::acc, args:::pats)
246+
case _ => impl(acc, pats)
247+
248+
case Nil => acc
249+
250+
impl(Nil, pat::Nil)
251+
252+
end PatternValDef
253+
219254
private def (tree: NamedDefTree) adjustedNameSpan(given Context): Span =
220255
if tree.span.exists && tree.name.isAnonymousFunctionName || tree.name.isAnonymousClassName
221256
Span(tree.span.point)

compiler/src/dotty/tools/dotc/semanticdb/Tools.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ object Tools with
127127
&& range.startCharacter != range.endCharacter
128128
&& !(occ.symbol.isConstructor && occ.role.isDefinition)
129129
val line = sourceFile.lineContent(sourceFile.lineToOffset(range.startLine))
130+
assert(range.startCharacter <= line.length && range.endCharacter <= line.length,
131+
s"Line is only ${line.length} - start line was ${range.startLine} in source ${sourceFile.name}"
132+
)
130133
sb.append(" ").append(line.substring(range.startCharacter, range.endCharacter))
131134
case _ =>
132135
sb.append("[):")

compiler/test/dotty/tools/dotc/semanticdb/SemanticdbTests.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,12 +132,15 @@ object SemanticdbTests with
132132
val isPrimaryConstructor =
133133
symtab.get(occ.symbol).exists(_.isPrimary)
134134
if !occ.symbol.isPackage && !isPrimaryConstructor
135+
assert(end <= doc.text.length,
136+
s"doc is only ${doc.text.length} - offset=$offset, end=$end , symbol=${occ.symbol} in source ${sourceFile.name}")
135137
sb.append(doc.text.substring(offset, end))
136138
sb.append("/*")
137139
.append(if (occ.role.isDefinition) "<-" else "->")
138140
.append(occ.symbol.replace("/", "::"))
139141
.append("*/")
140142
offset = end
143+
assert(offset <= doc.text.length, s"absurd offset = $offset when doc is length ${doc.text.length}")
141144
sb.append(doc.text.substring(offset))
142145
sb.toString
143146
end printTextDocument

tests/semanticdb/expect/Flags.expect.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ package object p {
2121
sealed trait Z/*<-flags::p::package.Z#*/
2222
class AA/*<-flags::p::package.AA#*/(x/*<-flags::p::package.AA#x.*/: Int/*->scala::Int#*/, val y/*<-flags::p::package.AA#y.*/: Int/*->scala::Int#*/, var z/*<-flags::p::package.AA#z().*/: Int/*->scala::Int#*/)
2323
class S/*<-flags::p::package.S#*/[@specialized/*->scala::specialized#*/ T/*<-flags::p::package.S#[T]*/]
24-
val List/*->scala::package.List.*//*->scala::collection::SeqFactory#unapplySeq().*/(xs1/*<-flags::p::package.xs1.*//*<-local0*/)/*->local0*/ = ???/*->scala::Predef.`???`().*/
25-
???/*->scala::Predef.`???`().*/ match { case List/*->scala::package.List.*//*->scala::collection::SeqFactory#unapplySeq().*/(xs2/*<-local1*/) => ???/*->scala::Predef.`???`().*/ }
26-
???/*->scala::Predef.`???`().*/ match { case _: List/*->scala::package.List#*/[t/*<-local2*/] => ???/*->scala::Predef.`???`().*/ }
24+
val List/*->scala::package.List.*//*->scala::collection::SeqFactory#unapplySeq().*/(xs1/*<-flags::p::package.xs1.*/) = ???/*->scala::Predef.`???`().*/
25+
???/*->scala::Predef.`???`().*/ match { case List/*->scala::package.List.*//*->scala::collection::SeqFactory#unapplySeq().*/(xs2/*<-local0*/) => ???/*->scala::Predef.`???`().*/ }
26+
???/*->scala::Predef.`???`().*/ match { case _: List/*->scala::package.List#*/[t/*<-local1*/] => ???/*->scala::Predef.`???`().*/ }
2727
}

tests/semanticdb/expect/Synthetic.expect.scala

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,17 @@ class Synthetic/*<-example::Synthetic#*/ {
99

1010
// See https://github.com/scalameta/scalameta/issues/977
1111
val Name/*<-example::Synthetic#Name.*/ = /*->scala::Predef.augmentString().*/"name:(.*)".r/*->scala::collection::StringOps#r().*/
12-
val x/*<-local0*//*<-example::Synthetic#x.*/ #::/*->scala::package.`#::`.*//*->scala::package.`#::`.unapply().*/ xs/*<-local1*//*<-example::Synthetic#xs.*//*->scala::Tuple2.apply().*//*->local0*//*->local1*/ = LazyList/*->scala::package.LazyList.*//*->scala::collection::IterableFactory#apply().*/(1, 2)
13-
val Name/*->example::Synthetic#Name.*//*->scala::util::matching::Regex#unapplySeq().*/(name/*<-example::Synthetic#name.*//*<-local2*/)/*->local2*/ = "name:foo"
12+
val x/*<-example::Synthetic#x.*/ #::/*->scala::package.`#::`.*//*->scala::package.`#::`.unapply().*/ xs/*<-example::Synthetic#xs.*/ = LazyList/*->scala::package.LazyList.*//*->scala::collection::IterableFactory#apply().*/(1, 2)
13+
val Name/*->example::Synthetic#Name.*//*->scala::util::matching::Regex#unapplySeq().*/(name/*<-example::Synthetic#name.*/) = "name:foo"
1414
1 #:: /*->scala::collection::immutable::LazyList.toDeferrer().*/2 #:: /*->scala::collection::immutable::LazyList.toDeferrer().*/LazyList/*->scala::package.LazyList.*/.empty/*->scala::collection::immutable::LazyList.empty().*//*->scala::collection::immutable::LazyList.Deferrer#`#::`().*/
1515

16+
val a1/*<-example::Synthetic#a1.*/ #::/*->scala::package.`#::`.*//*->scala::package.`#::`.unapply().*/ a2/*<-example::Synthetic#a2.*/ #::/*->scala::package.`#::`.*//*->scala::package.`#::`.unapply().*/ as/*<-example::Synthetic#as.*/ = LazyList/*->scala::package.LazyList.*//*->scala::collection::IterableFactory#apply().*/(1, 2)
17+
1618
val lst/*<-example::Synthetic#lst.*/ = 1 #:: /*->scala::collection::immutable::LazyList.toDeferrer().*/2 #:: /*->scala::collection::immutable::LazyList.toDeferrer().*/LazyList/*->scala::package.LazyList.*/.empty/*->scala::collection::immutable::LazyList.empty().*//*->scala::collection::immutable::LazyList.Deferrer#`#::`().*/
1719

18-
for (x/*<-local3*/ <- /*->scala::LowPriorityImplicits#intWrapper().*/1 to/*->scala::runtime::RichInt#to().*/ 10/*->scala::collection::immutable::Range#foreach().*/; y/*<-local4*/ <- /*->scala::LowPriorityImplicits#intWrapper().*/0 until/*->scala::runtime::RichInt#until().*/ 10/*->scala::collection::immutable::Range#foreach().*/) println/*->scala::Predef.println(+1).*/(/*->scala::Predef.ArrowAssoc().*/x/*->local3*/ ->/*->scala::Predef.ArrowAssoc#`->`().*/ x/*->local3*/)
19-
for (i/*<-local5*/ <- /*->scala::LowPriorityImplicits#intWrapper().*/1 to/*->scala::runtime::RichInt#to().*/ 10/*->scala::collection::StrictOptimizedIterableOps#flatMap().*/; j/*<-local6*/ <- /*->scala::LowPriorityImplicits#intWrapper().*/0 until/*->scala::runtime::RichInt#until().*/ 10/*->scala::collection::immutable::Range#map().*/) yield (/*->scala::Tuple2.apply().*/i/*->local5*/, j/*->local6*/)
20-
for (i/*<-local7*/ <- /*->scala::LowPriorityImplicits#intWrapper().*/1 to/*->scala::runtime::RichInt#to().*/ 10/*->scala::collection::StrictOptimizedIterableOps#flatMap().*/; j/*<-local8*/ <- /*->scala::LowPriorityImplicits#intWrapper().*/0 until/*->scala::runtime::RichInt#until().*/ 10/*->scala::collection::IterableOps#withFilter().*/ if i/*->local7*/ %/*->scala::Int#`%`(+3).*/ 2 ==/*->scala::Int#`==`(+3).*/ 0/*->scala::collection::WithFilter#map().*/) yield (/*->scala::Tuple2.apply().*/i/*->local7*/, j/*->local8*/)
20+
for (x/*<-local0*/ <- /*->scala::LowPriorityImplicits#intWrapper().*/1 to/*->scala::runtime::RichInt#to().*/ 10/*->scala::collection::immutable::Range#foreach().*/; y/*<-local1*/ <- /*->scala::LowPriorityImplicits#intWrapper().*/0 until/*->scala::runtime::RichInt#until().*/ 10/*->scala::collection::immutable::Range#foreach().*/) println/*->scala::Predef.println(+1).*/(/*->scala::Predef.ArrowAssoc().*/x/*->local0*/ ->/*->scala::Predef.ArrowAssoc#`->`().*/ x/*->local0*/)
21+
for (i/*<-local2*/ <- /*->scala::LowPriorityImplicits#intWrapper().*/1 to/*->scala::runtime::RichInt#to().*/ 10/*->scala::collection::StrictOptimizedIterableOps#flatMap().*/; j/*<-local3*/ <- /*->scala::LowPriorityImplicits#intWrapper().*/0 until/*->scala::runtime::RichInt#until().*/ 10/*->scala::collection::immutable::Range#map().*/) yield (/*->scala::Tuple2.apply().*/i/*->local2*/, j/*->local3*/)
22+
for (i/*<-local4*/ <- /*->scala::LowPriorityImplicits#intWrapper().*/1 to/*->scala::runtime::RichInt#to().*/ 10/*->scala::collection::StrictOptimizedIterableOps#flatMap().*/; j/*<-local5*/ <- /*->scala::LowPriorityImplicits#intWrapper().*/0 until/*->scala::runtime::RichInt#until().*/ 10/*->scala::collection::IterableOps#withFilter().*/ if i/*->local4*/ %/*->scala::Int#`%`(+3).*/ 2 ==/*->scala::Int#`==`(+3).*/ 0/*->scala::collection::WithFilter#map().*/) yield (/*->scala::Tuple2.apply().*/i/*->local4*/, j/*->local5*/)
2123

2224
object s/*<-example::Synthetic#s.*/ {
2325
def apply/*<-example::Synthetic#s.apply().*/() = 2
@@ -36,13 +38,13 @@ class Synthetic/*<-example::Synthetic#*/ {
3638

3739
import scala.concurrent.ExecutionContext/*->scala::concurrent::ExecutionContext.*/.Implicits/*->scala::concurrent::ExecutionContext.Implicits.*/.global/*->scala::concurrent::ExecutionContext.Implicits.global().*/
3840
for {
39-
a/*<-local9*/ <- scala.concurrent.Future/*->scala::concurrent::Future.*/.successful/*->scala::concurrent::Future.successful().*/(1)/*->scala::concurrent::Future#foreach().*/
40-
b/*<-local10*/ <- scala.concurrent.Future/*->scala::concurrent::Future.*/.successful/*->scala::concurrent::Future.successful().*/(2)/*->scala::concurrent::Future#foreach().*/
41-
} println/*->scala::Predef.println(+1).*/(a/*->local9*/)/*->scala::concurrent::ExecutionContext.Implicits.global().*/
41+
a/*<-local6*/ <- scala.concurrent.Future/*->scala::concurrent::Future.*/.successful/*->scala::concurrent::Future.successful().*/(1)/*->scala::concurrent::Future#foreach().*/
42+
b/*<-local7*/ <- scala.concurrent.Future/*->scala::concurrent::Future.*/.successful/*->scala::concurrent::Future.successful().*/(2)/*->scala::concurrent::Future#foreach().*/
43+
} println/*->scala::Predef.println(+1).*/(a/*->local6*/)/*->scala::concurrent::ExecutionContext.Implicits.global().*/
4244
for {
43-
a/*<-local11*/ <- scala.concurrent.Future/*->scala::concurrent::Future.*/.successful/*->scala::concurrent::Future.successful().*/(1)/*->scala::concurrent::Future#flatMap().*/
44-
b/*<-local12*/ <- scala.concurrent.Future/*->scala::concurrent::Future.*/.successful/*->scala::concurrent::Future.successful().*/(2)/*->scala::concurrent::Future#withFilter().*/
45-
if a/*->local11*/ </*->scala::Int#`<`(+3).*/ b/*->local12*//*->scala::concurrent::Future#map().*//*->scala::concurrent::ExecutionContext.Implicits.global().*/
46-
} yield a/*->local11*//*->scala::concurrent::ExecutionContext.Implicits.global().*/
45+
a/*<-local8*/ <- scala.concurrent.Future/*->scala::concurrent::Future.*/.successful/*->scala::concurrent::Future.successful().*/(1)/*->scala::concurrent::Future#flatMap().*/
46+
b/*<-local9*/ <- scala.concurrent.Future/*->scala::concurrent::Future.*/.successful/*->scala::concurrent::Future.successful().*/(2)/*->scala::concurrent::Future#withFilter().*/
47+
if a/*->local8*/ </*->scala::Int#`<`(+3).*/ b/*->local9*//*->scala::concurrent::Future#map().*//*->scala::concurrent::ExecutionContext.Implicits.global().*/
48+
} yield a/*->local8*//*->scala::concurrent::ExecutionContext.Implicits.global().*/
4749

4850
}

tests/semanticdb/expect/Synthetic.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ class Synthetic {
1313
val Name(name) = "name:foo"
1414
1 #:: 2 #:: LazyList.empty
1515

16+
val a1 #:: a2 #:: as = LazyList(1, 2)
17+
1618
val lst = 1 #:: 2 #:: LazyList.empty
1719

1820
for (x <- 1 to 10; y <- 0 until 10) println(x -> x)

tests/semanticdb/expect/ValPattern.expect.scala

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ package example
33
class ValPattern/*<-example::ValPattern#*/ {
44

55
val (left/*<-example::ValPattern#left.*/, right/*<-example::ValPattern#right.*/) = (/*->scala::Tuple2.apply().*/1, 2)
6-
val Some/*->scala::Some.*//*->scala::Some.unapply().*/(number1/*<-example::ValPattern#number1.*//*<-local0*/)/*->local0*/ =
6+
val Some/*->scala::Some.*//*->scala::Some.unapply().*/(number1/*<-example::ValPattern#number1.*/) =
77
Some/*->scala::Some.*//*->scala::Some.apply().*/(1)
88

99
var (leftVar/*<-example::ValPattern#leftVar().*/, rightVar/*<-example::ValPattern#rightVar().*/) = (/*->scala::Tuple2.apply().*/1, 2)
10-
var Some/*->scala::Some.*//*->scala::Some.unapply().*/(number1Var/*<-example::ValPattern#number1Var().*//*<-local1*/)/*->local1*/ =
10+
var Some/*->scala::Some.*//*->scala::Some.unapply().*/(number1Var/*<-example::ValPattern#number1Var().*/) =
1111
Some/*->scala::Some.*//*->scala::Some.apply().*/(1)
1212

1313
def app/*<-example::ValPattern#app().*/(): Unit/*->scala::Unit#*/ = {
@@ -22,21 +22,21 @@ class ValPattern/*<-example::ValPattern#*/ {
2222
)
2323
)
2424
locally/*->dotty::DottyPredef.locally().*/ {
25-
val (left/*<-local2*/, right/*<-local3*/) = (/*->scala::Tuple2.apply().*/1, 2)
26-
val Some/*->scala::Some.*//*->scala::Some.unapply().*/(number1/*<-local4*/)/*->local4*/ =
25+
val (left/*<-local0*/, right/*<-local1*/) = (/*->scala::Tuple2.apply().*/1, 2)
26+
val Some/*->scala::Some.*//*->scala::Some.unapply().*/(number1/*<-local2*/) =
2727
Some/*->scala::Some.*//*->scala::Some.apply().*/(1)
2828

29-
var (leftVar/*<-local5*/, rightVar/*<-local6*/) = (/*->scala::Tuple2.apply().*/1, 2)
30-
var Some/*->scala::Some.*//*->scala::Some.unapply().*/(number1Var/*<-local7*/)/*->local7*/ =
29+
var (leftVar/*<-local3*/, rightVar/*<-local4*/) = (/*->scala::Tuple2.apply().*/1, 2)
30+
var Some/*->scala::Some.*//*->scala::Some.unapply().*/(number1Var/*<-local5*/) =
3131
Some/*->scala::Some.*//*->scala::Some.apply().*/(1)
3232
println/*->scala::Predef.println(+1).*/(
3333
(
34-
/*->scala::Tuple6.apply().*/number1/*->local4*/,
35-
left/*->local2*/,
36-
right/*->local3*/,
37-
number1Var/*->local7*/,
38-
leftVar/*->local5*/,
39-
rightVar/*->local6*/
34+
/*->scala::Tuple6.apply().*/number1/*->local2*/,
35+
left/*->local0*/,
36+
right/*->local1*/,
37+
number1Var/*->local5*/,
38+
leftVar/*->local3*/,
39+
rightVar/*->local4*/
4040
)
4141
)
4242
}

0 commit comments

Comments
 (0)