Skip to content

Fix #1444: Pass implicits to parameterless traits if needed #1456

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

Merged
merged 2 commits into from
Aug 21, 2016
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
19 changes: 10 additions & 9 deletions src/dotty/tools/dotc/transform/Mixin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -189,16 +189,17 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
var argNum = 0
def nextArgument() = initArgs.get(mixin) match {
case Some(arguments) =>
try arguments(argNum) finally argNum += 1
val result = arguments(argNum)
argNum += 1
result
case None =>
val (msg, pos) = impl.parents.find(_.tpe.typeSymbol == mixin) match {
case Some(parent) => ("lacks argument list", parent.pos)
case None =>
("""is indirectly implemented,
|needs to be implemented directly so that arguments can be passed""".stripMargin,
cls.pos)
}
ctx.error(i"parameterized $mixin $msg", pos)
assert(
impl.parents.forall(_.tpe.typeSymbol != mixin),
i"missing parameters for $mixin from $impl should have been caught in typer")
ctx.error(
em"""parameterized $mixin is indirectly implemented,
|needs to be implemented directly so that arguments can be passed""",
cls.pos)
EmptyTree
}

Expand Down
37 changes: 36 additions & 1 deletion src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1132,8 +1132,43 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def typedClassDef(cdef: untpd.TypeDef, cls: ClassSymbol)(implicit ctx: Context) = track("typedClassDef") {
val TypeDef(name, impl @ Template(constr, parents, self, _)) = cdef
val superCtx = ctx.superCallContext

/** If `ref` is an implicitly parameterized trait, pass an implicit argument list.
* Otherwise, if `ref` is a parameterized trait, error.
* Note: Traits and classes currently always have at least an empty parameter list ()
* before the implicit parameters (this is inserted if not given in source).
* We skip this parameter list when deciding whether a trait is parameterless or not.
* @param ref The tree referring to the (parent) trait
* @param psym Its type symbol
* @param cinfo The info of its constructor
*/
def maybeCall(ref: Tree, psym: Symbol, cinfo: Type): Tree = cinfo match {
case cinfo: PolyType =>
maybeCall(ref, psym, cinfo.resultType)
case cinfo @ MethodType(Nil, _) if cinfo.resultType.isInstanceOf[ImplicitMethodType] =>
val icall = New(ref).select(nme.CONSTRUCTOR).appliedToNone
typedExpr(untpd.TypedSplice(icall))(superCtx)
case cinfo @ MethodType(Nil, _) if !cinfo.resultType.isInstanceOf[MethodType] =>
ref
case cinfo: MethodType =>
if (!ctx.erasedTypes) { // after constructors arguments are passed in super call.
typr.println(i"constr type: $cinfo")
ctx.error(em"parameterized $psym lacks argument list", ref.pos)
}
ref
case _ =>
ref
}

def typedParent(tree: untpd.Tree): Tree =
if (tree.isType) typedType(tree)(superCtx)
if (tree.isType) {
val result = typedType(tree)(superCtx)
val psym = result.tpe.typeSymbol
if (psym.is(Trait) && !cls.is(Trait) && !cls.superClass.isSubClass(psym))
maybeCall(result, psym, psym.primaryConstructor.info)
else
result
}
else {
val result = typedExpr(tree)(superCtx)
checkParentCall(result, cls)
Expand Down
33 changes: 33 additions & 0 deletions tests/neg/i1263.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
object Test {
trait Foo(val s: String)

val foo1 = new Foo("bar") {}
val foo2 = new Foo { override val s = "bar" } // error: parameterized trait lacks argument list
def main(args: Array[String]): Unit = {
assert(foo1.s == "bar")
assert(foo2.s == "bar")
}
}
object Test1 {
trait Foo(private val s0: String) {
def s = s0
}

val foo1 = new Foo("bar") {}
def main(args: Array[String]): Unit = {
assert(foo1.s == "bar")
}
}
object Test2 {
trait Foo(protected val s: String)

val foo1 = new Foo("bar") {}
}
object Test3 {
trait Foo(final val s: String)

val foo1 = new Foo("bar") {}
def main(args: Array[String]): Unit = {
assert(foo1.s == "bar")
}
}
2 changes: 0 additions & 2 deletions tests/neg/traitParamsMixin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ trait T(x: Int) {
def f = x
}

class C extends T // error

trait U extends T

class D extends U { // error
Expand Down
2 changes: 2 additions & 0 deletions tests/neg/traitParamsTyper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ trait T(x: Int) {
def f = x
}

class C0 extends T // error

class C(x: Int) extends T() // error

trait U extends C with T
Expand Down
14 changes: 14 additions & 0 deletions tests/pos/i1444.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
object Test {

class Cls(implicit x:X)
class ClsImpl extends Cls //this works

trait Tr1(implicit x:X)
class TrtImpl extends Tr1 //Compiler: Error: parameterized trait Tr1 lacks argument list

trait Tr2()(implicit x:X)
class Tr2Impl extends Tr2() //this works

trait X
implicit object AnX extends X
}
3 changes: 0 additions & 3 deletions tests/run/i1263.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ object Test {
trait Foo(val s: String)

val foo1 = new Foo("bar") {}
val foo2 = new Foo { override val s = "bar" }
def main(args: Array[String]): Unit = {
assert(foo1.s == "bar")
assert(foo2.s == "bar")
}
}
object Test1 {
Expand All @@ -22,7 +20,6 @@ object Test2 {
trait Foo(protected val s: String)

val foo1 = new Foo("bar") {}
val foo2 = new Foo { override val s = "bar" }
}
object Test3 {
trait Foo(final val s: String)
Expand Down