Skip to content

Commit 555cafa

Browse files
committed
Fix default arguments for inferable parameters
Default arguments must be passed as `given` arguments to match. Without this change we get a stackoverflow in implied-priority.scala.
1 parent b18f417 commit 555cafa

File tree

2 files changed

+118
-1
lines changed

2 files changed

+118
-1
lines changed

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2547,7 +2547,10 @@ class Typer extends Namer
25472547
if (arg.tpe.isError) Nil else untpd.NamedArg(pname, untpd.TypedSplice(arg)) :: Nil
25482548
}
25492549
tryEither { implicit ctx =>
2550-
typed(untpd.Apply(untpd.TypedSplice(tree), namedArgs), pt, locked)
2550+
val app = cpy.Apply(tree)(untpd.TypedSplice(tree), namedArgs)
2551+
if (wtp.isContextual) app.pushAttachment(untpd.ApplyGiven, ())
2552+
typr.println(i"try with default implicit args $app")
2553+
typed(app, pt, locked)
25512554
} { (_, _) =>
25522555
issueErrors()
25532556
}

tests/run/implied-priority.scala

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
class Arg[T]
2+
3+
// Traditional scheme: use location in class hierarchy
4+
5+
class E[T](val str: String)
6+
7+
class LowPriorityImplicits {
8+
implied t1[T] for E[T]("low")
9+
}
10+
11+
object NormalImplicits extends LowPriorityImplicits {
12+
implied t2[T] given Arg[T] for E[T]("norm")
13+
}
14+
15+
def test1 = {
16+
import implied NormalImplicits._
17+
assert(the[E[String]].str == "low")
18+
19+
{ implied for Arg[String]
20+
assert(the[E[String]].str == "norm")
21+
}
22+
}
23+
24+
// Priority arguments:
25+
26+
object Priority {
27+
class Low
28+
object Low { implied for Low }
29+
class High extends Low
30+
object High { implied for High }
31+
}
32+
33+
object Impl2 {
34+
implied t1[T] given Priority.Low for E[T]("low")
35+
implied t2[T] given Priority.High given Arg[T] for E[T]("norm")
36+
}
37+
38+
def test2 = {
39+
import implied Impl2._
40+
assert(the[E[String]].str == "low")
41+
42+
{ implied for Arg[String]
43+
assert(the[E[String]].str == "norm")
44+
}
45+
}
46+
47+
// Adding an override to an existing hierarchy:
48+
// If all of the alternatives in the existing hierarchy take implicit arguments,
49+
// an alternative without implicit arguments would override all of them.
50+
51+
object Impl2a {
52+
implied t3[T] for E[T]("hi")
53+
}
54+
55+
def test2a = {
56+
import implied Impl2._
57+
import implied Impl2a._
58+
59+
implied for Arg[String]
60+
assert(the[E[String]].str == "hi")
61+
}
62+
63+
// If not, we can use result refinement:
64+
65+
object Impl3 {
66+
implied t1[T] for E[T]("low")
67+
}
68+
69+
object Override {
70+
trait HighestPriority
71+
72+
implied over[T] for E[T]("hi"), HighestPriority
73+
}
74+
75+
def test3 = {
76+
import implied Impl3._
77+
assert(the[E[String]].str == "low")
78+
79+
{ import implied Override._
80+
assert(the[E[String]].str == "hi")
81+
}
82+
}
83+
84+
// Adding a fallback to an existing hierarchy:
85+
object Impl4 {
86+
implied t1 for E[String]("string")
87+
implied t2[T] given Arg[T] for E[T]("generic")
88+
}
89+
90+
object fb {
91+
def withFallback[T] given (ev: E[T] = new E[T]("fallback")): E[T] = ev
92+
implied [T] given (ev: E[T] = new E[T]("fallback")) for E[T] = ev
93+
}
94+
95+
def test4 = {
96+
import implied Impl4._
97+
import fb._
98+
assert(withFallback[String].str == "string")
99+
assert(withFallback[Int].str == "fallback")
100+
101+
{ implied for Arg[Int]
102+
assert(withFallback[Int].str == "generic")
103+
}
104+
}
105+
106+
107+
object Test extends App {
108+
test1
109+
test2
110+
test2a
111+
test3
112+
test4
113+
}
114+

0 commit comments

Comments
 (0)