diff options
author | Martin Odersky <odersky@gmail.com> | 2016-08-16 18:34:36 +0200 |
---|---|---|
committer | Guillaume Martres <smarter@ubuntu.com> | 2016-08-20 20:31:13 -0700 |
commit | e5315cce416c665d7c6d2740d171343829b30f4c (patch) | |
tree | 95a6c77e958a0cdc779e02408c6848d36254b9f4 | |
parent | 5a5f9d7ed37ca6449ef61ee5e0f6fbf9731df795 (diff) | |
download | dotty-e5315cce416c665d7c6d2740d171343829b30f4c.tar.gz dotty-e5315cce416c665d7c6d2740d171343829b30f4c.tar.bz2 dotty-e5315cce416c665d7c6d2740d171343829b30f4c.zip |
Fix #1444: Add implicit arguments to supertraits
If a super trait is given as a type (i.e. no argument list), implicit args were
not passed. This is fixed now. Also, we now check for parameterized traits lacking
type arguments in Typer instead of in Mixin.
Fixes #1444.
-rw-r--r-- | src/dotty/tools/dotc/transform/Mixin.scala | 19 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 37 | ||||
-rw-r--r-- | tests/neg/i1263.scala | 33 | ||||
-rw-r--r-- | tests/neg/traitParamsMixin.scala | 2 | ||||
-rw-r--r-- | tests/neg/traitParamsTyper.scala | 2 | ||||
-rw-r--r-- | tests/pos/i1444.scala | 14 | ||||
-rw-r--r-- | tests/run/i1263.scala | 3 |
7 files changed, 95 insertions, 15 deletions
diff --git a/src/dotty/tools/dotc/transform/Mixin.scala b/src/dotty/tools/dotc/transform/Mixin.scala index 8cdc82f7a..27cfc835a 100644 --- a/src/dotty/tools/dotc/transform/Mixin.scala +++ b/src/dotty/tools/dotc/transform/Mixin.scala @@ -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 } diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 2b690ef51..81e6e9430 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -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) diff --git a/tests/neg/i1263.scala b/tests/neg/i1263.scala new file mode 100644 index 000000000..e6d8c37b5 --- /dev/null +++ b/tests/neg/i1263.scala @@ -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") + } +} diff --git a/tests/neg/traitParamsMixin.scala b/tests/neg/traitParamsMixin.scala index dfb9fbe2f..aa91012d5 100644 --- a/tests/neg/traitParamsMixin.scala +++ b/tests/neg/traitParamsMixin.scala @@ -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 diff --git a/tests/neg/traitParamsTyper.scala b/tests/neg/traitParamsTyper.scala index e97906b50..c4b612033 100644 --- a/tests/neg/traitParamsTyper.scala +++ b/tests/neg/traitParamsTyper.scala @@ -2,6 +2,8 @@ trait T(x: Int) { def f = x } +class C extends T // error + class C(x: Int) extends T() // error trait U extends C with T diff --git a/tests/pos/i1444.scala b/tests/pos/i1444.scala new file mode 100644 index 000000000..da858d50f --- /dev/null +++ b/tests/pos/i1444.scala @@ -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 +} diff --git a/tests/run/i1263.scala b/tests/run/i1263.scala index 630e5758e..e97606ef6 100644 --- a/tests/run/i1263.scala +++ b/tests/run/i1263.scala @@ -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 { @@ -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) |