Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refine estimation of default arguments in overloading resolution #15962

Merged
merged 2 commits into from
Sep 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 22 additions & 12 deletions compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1935,11 +1935,19 @@ trait Applications extends Compatibility {
val ptypes = tp.paramInfos
val numParams = ptypes.length
def isVarArgs = ptypes.nonEmpty && ptypes.last.isRepeatedParam
def hasDefault = alt.symbol.hasDefaultParams
if (numParams == numArgs) true
else if (numParams < numArgs) isVarArgs
else if (numParams > numArgs + 1) hasDefault
else isVarArgs || hasDefault
def numDefaultParams =
if alt.symbol.hasDefaultParams then
trimParamss(tp, alt.symbol.rawParamss) match
case params :: _ => params.count(_.is(HasDefault))
case _ => 0
else 0
if numParams < numArgs then isVarArgs
else if numParams == numArgs then true
else
val numNecessaryArgs = numParams - numDefaultParams
if numNecessaryArgs <= numArgs then true
else if numNecessaryArgs == numArgs + 1 then isVarArgs
else false
case _ =>
numArgs == 0
}
Expand Down Expand Up @@ -2080,6 +2088,14 @@ trait Applications extends Compatibility {
}
end resolveOverloaded1

/** The largest suffix of `paramss` that has the same first parameter name as `t` */
def trimParamss(t: Type, paramss: List[List[Symbol]])(using Context): List[List[Symbol]] = t match
case MethodType(Nil) => trimParamss(t.resultType, paramss)
case t: MethodOrPoly =>
val firstParamName = t.paramNames.head
paramss.dropWhile(_.head.name != firstParamName)
case _ => Nil

/** Resolve overloading by mapping to a different problem where each alternative's
* type is mapped with `f`, alternatives with non-existing types are dropped, and the
* expected type is `pt`. Map the results back to the original alternatives.
Expand All @@ -2089,13 +2105,7 @@ trait Applications extends Compatibility {
val t = f(alt)
if t.exists then
val mappedSym = alt.symbol.asTerm.copy(info = t)
mappedSym.rawParamss = alt.symbol.rawParamss
// we need rawParamss to find parameters with default arguments,
// but we do not need to be precise right now, since this is just a pre-test before
// we look up default getters. If at some point we extract default arguments from the
// parameter symbols themselves, we have to find the right parameter by name, not position.
// That means it's OK to copy parameters wholesale rather than tailoring them to always
// correspond to the type transformation.
mappedSym.rawParamss = trimParamss(t, alt.symbol.rawParamss)
Some((TermRef(NoPrefix, mappedSym), alt))
else
None
Expand Down
22 changes: 22 additions & 0 deletions tests/neg/i15898.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
object O {
class AC(code: => Unit) {
def apply() = code

def this(code: => Unit, key: Int = 1, modifiers: Int = 0) = {
this(code)
}
}

class Doc {
def method: Boolean = true
}

val doc = new Doc

val ac = new AC(doc.method) // error

def foo[T](code: => Unit): Unit = ()
def foo[T](code: => Unit, key: Int = 1, modifiers: Int = 0): Unit = foo(code)
foo(doc.method) // error
foo[Int](doc.method) // error
}
24 changes: 24 additions & 0 deletions tests/pending/pos/i15915.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
class _Monoid[A]
object _Monoid {
implicit val Monoid: _Monoid[Int] = new _Monoid[Int]
}

class Lifecycle[A]
object Lifecycle {

implicit def monoidForLifecycle[Monoid[_], A](
implicit
monoidType: GetMonoidType[Monoid],
monoidA: Monoid[A]
): Monoid[Lifecycle[A]] = new _Monoid().asInstanceOf[Monoid[Lifecycle[A]]]

}

sealed class GetMonoidType[C[_]]
object GetMonoidType {
implicit val getMonoid: GetMonoidType[_Monoid] = new GetMonoidType[_Monoid]
}

object App extends App {
println(implicitly[_Monoid[Lifecycle[Int]]])
}
31 changes: 31 additions & 0 deletions tests/pending/pos/i15926.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//@main def main(): Unit =
// println(summon[Sum[Minus[Succ[Zero]], Minus[Succ[Zero]]] =:= Minus[Succ[Succ[Zero]]]])

sealed trait IntT
sealed trait NatT extends IntT
final case class Zero() extends NatT
final case class Succ[+N <: NatT](n: N) extends NatT
final case class Minus[+N <: Succ[NatT]](n: N) extends IntT

type NatSum[X <: NatT, Y <: NatT] <: NatT = Y match
case Zero => X
case Succ[y] => NatSum[Succ[X], y]

type NatDif[X <: NatT, Y <: NatT] <: IntT = Y match
case Zero => X
case Succ[y] => X match
case Zero => Minus[Y]
case Succ[x] => NatDif[x, y]

type Sum[X <: IntT, Y <: IntT] <: IntT = Y match
case Zero => X
case Minus[y] => X match
case Minus[x] => Minus[NatSum[x, y]]
case _ => NatDif[X, y]
case _ => X match
case Minus[x] => NatDif[Y, x]
case _ => NatSum[X, Y]

def test =
val x: Sum[Minus[Succ[Zero]], Minus[Succ[Zero]]] = ???
val y = x
65 changes: 65 additions & 0 deletions tests/pending/run/i15893.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
sealed trait NatT
case class Zero() extends NatT
case class Succ[+N <: NatT](n: N) extends NatT

type Mod2[N <: NatT] <: NatT = N match
case Zero => Zero
case Succ[Zero] => Succ[Zero]
case Succ[Succ[predPredN]] => Mod2[predPredN]


def mod2(n: NatT): NatT = n match
case Zero() => Zero()
case Succ(Zero()) => Succ(Zero())
case Succ(Succ(predPredN)) => mod2(predPredN)

/*
inline def inlineMod2(inline n: NatT): NatT = inline n match
case Zero() => Zero()
case Succ(Zero()) => Succ(Zero())
case Succ(Succ(predPredN)) => inlineMod2(predPredN)

transparent inline def transparentInlineMod2(inline n: NatT): NatT = inline n match
case Zero() => Zero()
case Succ(Zero()) => Succ(Zero())
case Succ(Succ(predPredN)) => transparentInlineMod2(predPredN)
*/
def dependentlyTypedMod2[N <: NatT](n: N): Mod2[N] = n match // exhaustivity warning; unexpected
case Zero(): Zero => Zero()
case Succ(Zero()): Succ[Zero] => Succ(Zero())
case Succ(Succ(predPredN)): Succ[Succ[_]] => dependentlyTypedMod2(predPredN)
/*
inline def inlineDependentlyTypedMod2[N <: NatT](inline n: N): Mod2[N] = inline n match
case Zero(): Zero => Zero()
case Succ(Zero()): Succ[Zero] => Succ(Zero())
case Succ(Succ(predPredN)): Succ[Succ[_]] => inlineDependentlyTypedMod2(predPredN)

transparent inline def transparentInlineDependentlyTypedMod2[N <: NatT](inline n: N): Mod2[N] = inline n match
case Zero(): Zero => Zero()
case Succ(Zero()): Succ[Zero] => Succ(Zero())
case Succ(Succ(predPredN)): Succ[Succ[_]] => transparentInlineDependentlyTypedMod2(predPredN)

def foo(n: NatT): NatT = mod2(n) match
case Succ(Zero()) => Zero()
case _ => n

inline def inlineFoo(inline n: NatT): NatT = inline inlineMod2(n) match
case Succ(Zero()) => Zero()
case _ => n

inline def transparentInlineFoo(inline n: NatT): NatT = inline transparentInlineMod2(n) match
case Succ(Zero()) => Zero()
case _ => n
*/
@main def main(): Unit =
/*
println(mod2(Succ(Succ(Succ(Zero()))))) // prints Succ(Zero()), as expected
println(foo(Succ(Succ(Succ(Zero()))))) // prints Zero(), as expected
println(inlineMod2(Succ(Succ(Succ(Zero()))))) // prints Succ(Zero()), as expected
println(inlineFoo(Succ(Succ(Succ(Zero()))))) // prints Succ(Succ(Succ(Zero()))); unexpected
println(transparentInlineMod2(Succ(Succ(Succ(Zero()))))) // prints Succ(Zero()), as expected
println(transparentInlineFoo(Succ(Succ(Succ(Zero()))))) // prints Zero(), as expected
*/
println(dependentlyTypedMod2(Succ(Succ(Succ(Zero()))))) // runtime error; unexpected
// println(inlineDependentlyTypedMod2(Succ(Succ(Succ(Zero()))))) // doesn't compile; unexpected
// println(transparentInlineDependentlyTypedMod2(Succ(Succ(Succ(Zero()))))) // doesn't compile; unexpected
22 changes: 22 additions & 0 deletions tests/pos/i15898.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
object O {
class AC(code: => Unit) {
def apply() = code

def this(code: => Unit, key: Int, modifiers: Int = 0) = {
this(code)
}
}

class Doc {
def method: Boolean = true
}

val doc = new Doc

val ac = new AC(doc.method)

def foo[T](code: => Unit): Unit = ()
def foo[T](code: => Unit, key: Int, modifiers: Int = 0): Unit = foo(code)
foo(doc.method)
foo[Int](doc.method)
}