Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit bcfa3be

Browse files
authoredAug 21, 2016
Merge pull request #1456 from dotty-staging/fix-#1444
Fix #1444: Pass implicits to parameterless traits if needed
2 parents ac423a3 + 2302886 commit bcfa3be

File tree

7 files changed

+95
-15
lines changed

7 files changed

+95
-15
lines changed
 

‎src/dotty/tools/dotc/transform/Mixin.scala

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -189,16 +189,17 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
189189
var argNum = 0
190190
def nextArgument() = initArgs.get(mixin) match {
191191
case Some(arguments) =>
192-
try arguments(argNum) finally argNum += 1
192+
val result = arguments(argNum)
193+
argNum += 1
194+
result
193195
case None =>
194-
val (msg, pos) = impl.parents.find(_.tpe.typeSymbol == mixin) match {
195-
case Some(parent) => ("lacks argument list", parent.pos)
196-
case None =>
197-
("""is indirectly implemented,
198-
|needs to be implemented directly so that arguments can be passed""".stripMargin,
199-
cls.pos)
200-
}
201-
ctx.error(i"parameterized $mixin $msg", pos)
196+
assert(
197+
impl.parents.forall(_.tpe.typeSymbol != mixin),
198+
i"missing parameters for $mixin from $impl should have been caught in typer")
199+
ctx.error(
200+
em"""parameterized $mixin is indirectly implemented,
201+
|needs to be implemented directly so that arguments can be passed""",
202+
cls.pos)
202203
EmptyTree
203204
}
204205

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

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1132,8 +1132,43 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
11321132
def typedClassDef(cdef: untpd.TypeDef, cls: ClassSymbol)(implicit ctx: Context) = track("typedClassDef") {
11331133
val TypeDef(name, impl @ Template(constr, parents, self, _)) = cdef
11341134
val superCtx = ctx.superCallContext
1135+
1136+
/** If `ref` is an implicitly parameterized trait, pass an implicit argument list.
1137+
* Otherwise, if `ref` is a parameterized trait, error.
1138+
* Note: Traits and classes currently always have at least an empty parameter list ()
1139+
* before the implicit parameters (this is inserted if not given in source).
1140+
* We skip this parameter list when deciding whether a trait is parameterless or not.
1141+
* @param ref The tree referring to the (parent) trait
1142+
* @param psym Its type symbol
1143+
* @param cinfo The info of its constructor
1144+
*/
1145+
def maybeCall(ref: Tree, psym: Symbol, cinfo: Type): Tree = cinfo match {
1146+
case cinfo: PolyType =>
1147+
maybeCall(ref, psym, cinfo.resultType)
1148+
case cinfo @ MethodType(Nil, _) if cinfo.resultType.isInstanceOf[ImplicitMethodType] =>
1149+
val icall = New(ref).select(nme.CONSTRUCTOR).appliedToNone
1150+
typedExpr(untpd.TypedSplice(icall))(superCtx)
1151+
case cinfo @ MethodType(Nil, _) if !cinfo.resultType.isInstanceOf[MethodType] =>
1152+
ref
1153+
case cinfo: MethodType =>
1154+
if (!ctx.erasedTypes) { // after constructors arguments are passed in super call.
1155+
typr.println(i"constr type: $cinfo")
1156+
ctx.error(em"parameterized $psym lacks argument list", ref.pos)
1157+
}
1158+
ref
1159+
case _ =>
1160+
ref
1161+
}
1162+
11351163
def typedParent(tree: untpd.Tree): Tree =
1136-
if (tree.isType) typedType(tree)(superCtx)
1164+
if (tree.isType) {
1165+
val result = typedType(tree)(superCtx)
1166+
val psym = result.tpe.typeSymbol
1167+
if (psym.is(Trait) && !cls.is(Trait) && !cls.superClass.isSubClass(psym))
1168+
maybeCall(result, psym, psym.primaryConstructor.info)
1169+
else
1170+
result
1171+
}
11371172
else {
11381173
val result = typedExpr(tree)(superCtx)
11391174
checkParentCall(result, cls)

‎tests/neg/i1263.scala

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
object Test {
2+
trait Foo(val s: String)
3+
4+
val foo1 = new Foo("bar") {}
5+
val foo2 = new Foo { override val s = "bar" } // error: parameterized trait lacks argument list
6+
def main(args: Array[String]): Unit = {
7+
assert(foo1.s == "bar")
8+
assert(foo2.s == "bar")
9+
}
10+
}
11+
object Test1 {
12+
trait Foo(private val s0: String) {
13+
def s = s0
14+
}
15+
16+
val foo1 = new Foo("bar") {}
17+
def main(args: Array[String]): Unit = {
18+
assert(foo1.s == "bar")
19+
}
20+
}
21+
object Test2 {
22+
trait Foo(protected val s: String)
23+
24+
val foo1 = new Foo("bar") {}
25+
}
26+
object Test3 {
27+
trait Foo(final val s: String)
28+
29+
val foo1 = new Foo("bar") {}
30+
def main(args: Array[String]): Unit = {
31+
assert(foo1.s == "bar")
32+
}
33+
}

‎tests/neg/traitParamsMixin.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ trait T(x: Int) {
22
def f = x
33
}
44

5-
class C extends T // error
6-
75
trait U extends T
86

97
class D extends U { // error

‎tests/neg/traitParamsTyper.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ trait T(x: Int) {
22
def f = x
33
}
44

5+
class C0 extends T // error
6+
57
class C(x: Int) extends T() // error
68

79
trait U extends C with T

‎tests/pos/i1444.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
object Test {
2+
3+
class Cls(implicit x:X)
4+
class ClsImpl extends Cls //this works
5+
6+
trait Tr1(implicit x:X)
7+
class TrtImpl extends Tr1 //Compiler: Error: parameterized trait Tr1 lacks argument list
8+
9+
trait Tr2()(implicit x:X)
10+
class Tr2Impl extends Tr2() //this works
11+
12+
trait X
13+
implicit object AnX extends X
14+
}

‎tests/run/i1263.scala

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@ object Test {
22
trait Foo(val s: String)
33

44
val foo1 = new Foo("bar") {}
5-
val foo2 = new Foo { override val s = "bar" }
65
def main(args: Array[String]): Unit = {
76
assert(foo1.s == "bar")
8-
assert(foo2.s == "bar")
97
}
108
}
119
object Test1 {
@@ -22,7 +20,6 @@ object Test2 {
2220
trait Foo(protected val s: String)
2321

2422
val foo1 = new Foo("bar") {}
25-
val foo2 = new Foo { override val s = "bar" }
2623
}
2724
object Test3 {
2825
trait Foo(final val s: String)

0 commit comments

Comments
 (0)