From 6afb888d4bfc8a796ae1db3ef8c646e0bb514003 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Tue, 3 Aug 2021 14:37:22 -0700 Subject: [PATCH] Repeated params must correspond in override Refchecks runs after elimRepeated and did not error on an attempt to override RepeatedParam with Seq. Also show RepeatedParam in error message. --- .../dotty/tools/dotc/core/Decorators.scala | 16 ++++++++++++++ .../dotty/tools/dotc/typer/RefChecks.scala | 22 ++++++++++++------- tests/neg/override-scala2-macro.check | 4 ++-- tests/neg/overrides.scala | 20 +++++++++++++++++ 4 files changed, 52 insertions(+), 10 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Decorators.scala b/compiler/src/dotty/tools/dotc/core/Decorators.scala index 49897a7bb275..b4fc851cc406 100644 --- a/compiler/src/dotty/tools/dotc/core/Decorators.scala +++ b/compiler/src/dotty/tools/dotc/core/Decorators.scala @@ -222,6 +222,22 @@ object Decorators { def nestedExists(p: T => Boolean): Boolean = xss match case xs :: xss1 => xs.exists(p) || xss1.nestedExists(p) case nil => false + def nestedZipExists(yss: List[List[U]])(f: (T, U) => Boolean): Boolean = + @tailrec def zipExists(p1: List[T], p2: List[U]): Boolean = + p1 match + case h :: t => + p2 match + case h2 :: t2 => f(h, h2) || zipExists(t, t2) + case _ => false + case _ => false + @tailrec def loop(ps1: List[List[T]], ps2: List[List[U]]): Boolean = + ps1 match + case h :: t => + ps2 match + case h2 :: t2 => zipExists(h, h2) || loop(t, t2) + case _ => false + case _ => false + loop(xss, yss) end extension extension (text: Text) diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 6e9d4caa7f6a..88b9dd20d885 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -253,7 +253,7 @@ object RefChecks { def infoString(sym: Symbol) = infoString0(sym, sym.owner != clazz) def infoStringWithLocation(sym: Symbol) = infoString0(sym, true) - def infoString0(sym: Symbol, showLocation: Boolean) = { + def infoString0(sym: Symbol, showLocation: Boolean) = atPhase(typerPhase) { val sym1 = sym.underlyingSymbol def info = self.memberInfo(sym1) val infoStr = @@ -265,6 +265,11 @@ object RefChecks { i"${if (showLocation) sym1.showLocated else sym1}$infoStr" } + def incompatibleRepeatedParam(member: Symbol, other: Symbol): Boolean = + member.is(Method, butNot = JavaDefined) && other.is(Method, butNot = JavaDefined) && atPhase(typerPhase) { + member.info.paramInfoss.nestedZipExists(other.info.paramInfoss)(_.isRepeatedParam != _.isRepeatedParam) + } + /* Check that all conditions for overriding `other` by `member` * of class `clazz` are met. */ @@ -350,10 +355,8 @@ object RefChecks { //Console.println(infoString(member) + " overrides " + infoString(other) + " in " + clazz);//DEBUG /* Is the intersection between given two lists of overridden symbols empty? */ - def intersectionIsEmpty(syms1: Iterator[Symbol], syms2: Iterator[Symbol]) = { - val set2 = syms2.toSet - !(syms1 exists (set2 contains _)) - } + def intersectionIsEmpty(syms1: Iterator[Symbol], syms2: Iterator[Symbol]) = + !syms1.exists(syms2.toSet.contains) // o: public | protected | package-protected (aka java's default access) // ^-may be overridden by member with access privileges-v @@ -414,6 +417,8 @@ object RefChecks { + "\n(Note: this can be resolved by declaring an override in " + clazz + ".)") else if member.is(Exported) then overrideError("cannot override since it comes from an export") + else if incompatibleRepeatedParam(member, other) then + overrideError("cannot override because erased signatures conflict in repeated parameter") else overrideError("needs `override` modifier") else if (other.is(AbsOverride) && other.isIncompleteIn(clazz) && !member.is(AbsOverride)) @@ -839,6 +844,7 @@ object RefChecks { def isSignatureMatch(sym: Symbol) = sym.isType || { val self = clazz.thisType sym.asSeenFrom(self).matches(member.asSeenFrom(self)) + && !incompatibleRepeatedParam(sym, member) } /* The rules for accessing members which have an access boundary are more @@ -871,8 +877,8 @@ object RefChecks { } // 4. Check that every defined member with an `override` modifier overrides some other member. - for (member <- clazz.info.decls) - if (member.isAnyOverride && !(clazz.thisType.baseClasses exists (hasMatchingSym(_, member)))) { + for member <- clazz.info.decls do + if member.isAnyOverride && !clazz.thisType.baseClasses.exists(hasMatchingSym(_, member)) then if (checks != noPrinter) for (bc <- clazz.info.baseClasses.tail) { val sym = bc.info.decl(member.name).symbol @@ -896,7 +902,7 @@ object RefChecks { } member.resetFlag(Override) member.resetFlag(AbsOverride) - } + end if } // Note: if a symbol has both @deprecated and @migration annotations and both diff --git a/tests/neg/override-scala2-macro.check b/tests/neg/override-scala2-macro.check index ff5e478342dd..fadf3a003402 100644 --- a/tests/neg/override-scala2-macro.check +++ b/tests/neg/override-scala2-macro.check @@ -1,5 +1,5 @@ -- [E164] Declaration Error: tests/neg/override-scala2-macro.scala:2:22 ------------------------------------------------ 2 | override inline def f[A >: Any](args: A*): String = ??? // error | ^ - |error overriding method f in class StringContext of type [A >: Any](args: Seq[A]): String; - | method f of type [A >: Any](args: Seq[A]): String cannot be used here - only Scala-2 macros can override Scala-2 macros + |error overriding method f in class StringContext of type [A >: Any](args: A*): String; + | method f of type [A >: Any](args: A*): String cannot be used here - only Scala-2 macros can override Scala-2 macros diff --git a/tests/neg/overrides.scala b/tests/neg/overrides.scala index 48f3260721e9..b5650ae23432 100644 --- a/tests/neg/overrides.scala +++ b/tests/neg/overrides.scala @@ -104,3 +104,23 @@ class C extends A { } } +package p6 { + class A { def apply(xs: Int*) = 42 } + class B extends A { override def apply(xs: Seq[Int]) = 42 } // error +} +package p7 { + class A { def apply(xs: Int*) = 42 } + class B extends A { def apply(xs: Seq[Int]) = 42 } // error +} +package p8 { + class A { def apply(xs: Seq[Int]) = 42 } + class B extends A { override def apply(xs: Int*) = 42 } // error +} +package p9 { + class A { def apply(xs: Seq[Int]) = 42 } + class B extends A { def apply(xs: Int*) = 42 } // error +} +package p10 { + class A { def apply(s: String)(xs: Int*) = 42 } + class B extends A { def apply(s: String)(xs: Seq[Int]) = 42 } // error +}