Skip to content

Commit 17324cc

Browse files
committed
Tweak check to fail if type param follows explicit param
1 parent 19af0d2 commit 17324cc

File tree

2 files changed

+40
-11
lines changed

2 files changed

+40
-11
lines changed

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1570,25 +1570,26 @@ trait Applications extends Compatibility {
15701570
def trySelectUnapply(qual: untpd.Tree)(fallBack: (Tree, TyperState) => Tree): Tree = {
15711571
// try first for non-overloaded, then for overloaded occurrences
15721572
def tryWithName(name: TermName)(fallBack: (Tree, TyperState) => Tree)(using Context): Tree =
1573-
// `true` if there are type parameters not followed by explicit term parameters.
1574-
def hasTrailingTypeParams(paramss: List[List[Symbol]], trailingTypeParams: Boolean): Boolean =
1575-
paramss match
1576-
case params :: paramss =>
1577-
val isTrailingTypeParams =
1573+
// `true` if there are no type parameters following the first explicit term parameter.
1574+
def hasOnlyLeadingTypeParams(fun: Symbol): Boolean =
1575+
def checkForIt(paramss: List[List[Symbol]], leading: Int): Boolean =
1576+
inline def isLeading = leading > 0
1577+
paramss match
1578+
case params :: paramss =>
15781579
params match
1579-
case param :: _ if param.isType => true
1580-
case param :: _ if param.isTerm && !param.isOneOf(GivenOrImplicit) => false
1581-
case _ => trailingTypeParams
1582-
hasTrailingTypeParams(paramss, isTrailingTypeParams)
1583-
case nil => trailingTypeParams
1580+
case param :: _ if param.isType && !isLeading => false
1581+
case param :: _ if param.isTerm && !param.isOneOf(GivenOrImplicit) => checkForIt(paramss, leading - 1)
1582+
case _ => checkForIt(paramss, leading)
1583+
case nil => true
1584+
checkForIt(fun.paramSymss, leading = if fun.is(Extension) then 2 else 1)
15841585

15851586
def tryWithProto(qual: untpd.Tree, targs: List[Tree], pt: Type)(using Context) =
15861587
val proto = UnapplyFunProto(pt, this)
15871588
val unapp = untpd.Select(qual, name)
15881589
val result =
15891590
if targs.isEmpty then typedExpr(unapp, proto)
15901591
else typedExpr(unapp, PolyProto(targs, proto)).appliedToTypeTrees(targs)
1591-
if result.symbol.exists && hasTrailingTypeParams(result.symbol.paramSymss, trailingTypeParams = false) then
1592+
if result.symbol.exists && !hasOnlyLeadingTypeParams(result.symbol) then
15921593
// We don't accept `unapply` or `unapplySeq` methods with type
15931594
// parameters after the last explicit term parameter because we
15941595
// can't encode them: `UnApply` nodes cannot take type paremeters.

tests/pos/i23499.scala

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
2+
3+
def summonsTest =
4+
given Type[String] = ???
5+
val opt1: Option[Wrapper[String]] = Wrapper.unapply[String] // ok
6+
val opt2 = Wrapper.unapply[String]
7+
opt2.map(_.getValue) // only error when using workaround
8+
9+
def patternMatchTest =
10+
Type[String] match
11+
case Wrapper(v) => v.getValue // was error // was error
12+
13+
type Type[A] = Class[A] // any rhs would work here
14+
object Type:
15+
def apply[A]: Type[A] = ???
16+
17+
trait Wrapper[T]:
18+
def getValue: T = ???
19+
object Wrapper:
20+
def unapply[T](implicit ev: Type[T]): Option[Wrapper[T]] = None
21+
22+
/* Workaround:
23+
@annotation.targetName("unapplyValue")
24+
def unapply[T](ev: Type[T]): Option[Wrapper[T]] = unapply(using ev)
25+
26+
@annotation.targetName("unapplySummon")
27+
def unapply[T](using Type[T]): Option[Wrapper[T]] = ???
28+
*/

0 commit comments

Comments
 (0)