Skip to content

Commit 4c05795

Browse files
committed
add tests from language reference and fix accordingly
1 parent 9bddab3 commit 4c05795

File tree

2 files changed

+100
-15
lines changed

2 files changed

+100
-15
lines changed

compiler/src/dotty/tools/dotc/util/Signatures.scala

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import core.Names._
1111
import core.Types._
1212
import util.Spans.Span
1313
import reporting._
14+
import dotty.tools.dotc.core.NameKinds
1415

1516

1617
object Signatures {
@@ -124,26 +125,37 @@ object Signatures {
124125
*
125126
* @return true if denot is "unapply", false otherwise
126127
*/
127-
def isUnapplyDenotation: Boolean = denot.name equals core.Names.termName("unapply")
128+
def isUnapplyDenotation: Boolean = List(core.Names.termName("unapply"), core.Names.termName("unapplySeq")) contains denot.name
128129

129130
def extractParamNamess(resultType: Type): List[List[Name]] =
130-
if resultType.resultType.widen.typeSymbol.flags.is(Flags.CaseClass) &&
131-
symbol.flags.is(Flags.Synthetic) then
131+
if resultType.resultType.widen.typeSymbol.flags.is(Flags.CaseClass) && symbol.flags.is(Flags.Synthetic) then
132132
resultType.resultType.widen.typeSymbol.primaryConstructor.paramInfo.paramNamess
133133
else
134134
Nil
135135

136136
def extractParamTypess(resultType: Type): List[List[Type]] =
137137
resultType match {
138138
case ref: TypeRef if !ref.symbol.isPrimitiveValueClass =>
139-
ref.symbol.primaryConstructor.paramInfo.paramInfoss
140-
case AppliedType(TypeRef(_, cls), AppliedType(_, args) :: Nil)
139+
if (
140+
ref.symbol.asClass.baseClasses.contains(ctx.definitions.ProductClass) &&
141+
!ref.symbol.is(Flags.CaseClass)
142+
) || ref.symbol.isStaticOwner then
143+
val productAccessors = ref.memberDenots(
144+
underscoreMembersFilter,
145+
(name, buf) => buf += ref.member(name).asSingleDenotation
146+
)
147+
List(productAccessors.map(_.info.finalResultType).toList)
148+
else
149+
ref.symbol.primaryConstructor.paramInfo.paramInfoss
150+
case AppliedType(TypeRef(_, cls), (appliedType @ AppliedType(tycon, args)) :: Nil)
141151
if (cls == ctx.definitions.OptionClass || cls == ctx.definitions.SomeClass) =>
142-
List(args)
152+
tycon match
153+
case TypeRef(_, cls) if cls == ctx.definitions.SeqClass => List(List(appliedType))
154+
case _ => List(args)
143155
case AppliedType(_, args) =>
144156
List(args)
145157
case MethodTpe(_, _, resultType) =>
146-
extractParamTypess(resultType)
158+
extractParamTypess(resultType.widenDealias)
147159
case _ =>
148160
Nil
149161
}
@@ -195,6 +207,11 @@ object Signatures {
195207
}
196208
}
197209

210+
object underscoreMembersFilter extends NameFilter {
211+
def apply(pre: Type, name: Name)(using Context): Boolean = name.startsWith("_")
212+
def isStable = true
213+
}
214+
198215
/**
199216
* The number of parameters that are applied in `tree`.
200217
*

language-server/test/dotty/tools/languageserver/SignatureHelpTest.scala

Lines changed: 76 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,9 @@ class SignatureHelpTest {
4141
| case s => println(s"s has an odd number of characters")
4242
"""
4343
.signatureHelp(m1, Nil, Some(0), 0)
44-
4544
}
4645

47-
@Test def unapplyCustomType: Unit = {
46+
@Test def unapplyCustomClass: Unit = {
4847
val signature = S("", Nil, List(List(P("", "Int"))), None)
4948

5049
code"""class Nat(val x: Int):
@@ -59,7 +58,6 @@ class SignatureHelpTest {
5958
| case _ => ()
6059
"""
6160
.signatureHelp(m1, List(signature), Some(0), 0)
62-
6361
}
6462

6563
@Test def unapplyTypeClass: Unit = {
@@ -78,7 +76,6 @@ class SignatureHelpTest {
7876
|}"""
7977
.signatureHelp(m1, List(signature), Some(0), 0)
8078
.signatureHelp(m2, List(signature), Some(0), 1)
81-
8279
}
8380

8481
@Test def unapplyClass: Unit = {
@@ -97,9 +94,84 @@ class SignatureHelpTest {
9794
|}"""
9895
.signatureHelp(m1, List(signature), Some(0), 0)
9996
.signatureHelp(m2, List(signature), Some(0), 1)
97+
}
98+
99+
@Test def productMatch: Unit = {
100+
val signature = S("", Nil, List(List(P("", "Char"), P("", "Char"))), None)
101+
102+
code"""class FirstChars(s: String) extends Product:
103+
| def _1 = s.charAt(0)
104+
| def _2 = s.charAt(1)
105+
|
106+
|object FirstChars:
107+
| def unapply(s: String): FirstChars = new FirstChars(s)
108+
|
109+
|object Test:
110+
| "Hi!" match
111+
| case FirstChars(ch${m1}, ch${m2}) => ???
112+
"""
113+
.signatureHelp(m1, List(signature), Some(0), 0)
114+
.signatureHelp(m2, List(signature), Some(0), 1)
115+
}
116+
117+
@Test def nameBasedMatch: Unit = {
118+
val signature = S("", Nil, List(List(P("", "Int"), P("", "String"))), None)
119+
120+
code"""object ProdEmpty:
121+
| def _1: Int = ???
122+
| def _2: String = ???
123+
| def isEmpty = true
124+
| def unapply(s: String): this.type = this
125+
| def get = this
126+
|
127+
|object Test:
128+
| "" match
129+
| case ProdEmpty(${m1}, ${m2}) => ???
130+
| case _ => ()
131+
"""
132+
.signatureHelp(m1, List(signature), Some(0), 0)
133+
.signatureHelp(m2, List(signature), Some(0), 1)
134+
}
135+
136+
@Test def sequenceMatch: Unit = {
137+
val signature = S("", Nil, List(List(P("", "Seq[Char]"))), None)
100138

139+
code"""object CharList:
140+
| def unapplySeq(s: String): Option[Seq[Char]] = Some(s.toList)
141+
|
142+
|object Test:
143+
| "example" match
144+
| case CharList(c${m1}1, c${m2}2, c${m3}3, c4, _, _, ${m4}) => ???
145+
| case _ =>
146+
| println("Expected *exactly* 7 characters!")
147+
"""
148+
.signatureHelp(m1, List(signature), Some(0), 0)
149+
.signatureHelp(m2, List(signature), Some(0), 1)
150+
.signatureHelp(m3, List(signature), Some(0), 2)
151+
.signatureHelp(m4, List(signature), Some(0), 6)
101152
}
102153

154+
@Test def productSequenceMatch: Unit = {
155+
val signature = S("", Nil, List(List(P("", "String"), P("", "Seq[Int]"))), None)
156+
157+
code"""class Foo(val name: String, val children: Int *)
158+
|object Foo:
159+
| def unapplySeq(f: Foo): Option[(String, Seq[Int])] =
160+
| Some((f.name, f.children))
161+
|
162+
|def foo(f: Foo) = f match
163+
| case Foo(na${m1}e, n${m2} : _*) =>
164+
| case Foo(nam${m3}e, ${m4}x, ${m5}y, n${m6}s : _*) =>
165+
"""
166+
.signatureHelp(m1, List(signature), Some(0), 0)
167+
.signatureHelp(m2, List(signature), Some(0), 1)
168+
.signatureHelp(m3, List(signature), Some(0), 0)
169+
.signatureHelp(m4, List(signature), Some(0), 1)
170+
.signatureHelp(m5, List(signature), Some(0), 2)
171+
.signatureHelp(m6, List(signature), Some(0), 3)
172+
}
173+
174+
103175
@Test def unapplyManyType: Unit = {
104176
val signature = S("", Nil, List(List(P("", "Int"), P("", "String"))), None)
105177

@@ -115,7 +187,6 @@ class SignatureHelpTest {
115187
|}"""
116188
.signatureHelp(m1, List(signature), Some(0), 0)
117189
.signatureHelp(m2, List(signature), Some(0), 1)
118-
119190
}
120191

121192
@Test def unapplyTypeCaseClass: Unit = {
@@ -131,7 +202,6 @@ class SignatureHelpTest {
131202
|}"""
132203
.signatureHelp(m1, List(signature), Some(0), 0)
133204
.signatureHelp(m2, List(signature), Some(0), 1)
134-
135205
}
136206

137207
@Test def unapplyCaseClass: Unit = {
@@ -147,7 +217,6 @@ class SignatureHelpTest {
147217
|}"""
148218
.signatureHelp(m1, List(signature), Some(0), 0)
149219
.signatureHelp(m2, List(signature), Some(0), 1)
150-
151220
}
152221

153222
@Test def unapplyOption: Unit = {
@@ -194,7 +263,6 @@ class SignatureHelpTest {
194263
.signatureHelp(m1, List(signature), Some(0), 0)
195264
}
196265

197-
198266
/** Implicit parameter lists consisting solely of DummyImplicits are hidden. */
199267
@Test def hiddenDummyParams: Unit = {
200268
val foo1Sig =

0 commit comments

Comments
 (0)