summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Typers.scala
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@typesafe.com>2016-07-07 16:55:36 -0700
committerAdriaan Moors <adriaan@lightbend.com>2016-08-11 10:59:16 -0700
commit16e7cf335bf9fbd7f68b043b9d670336c6897809 (patch)
tree1d42d7376192ab8539e4a38e7afe7895793b95bd /src/compiler/scala/tools/nsc/typechecker/Typers.scala
parentb79c0d124e839e9e7ae5db883488c0134642472b (diff)
downloadscala-16e7cf335bf9fbd7f68b043b9d670336c6897809.tar.gz
scala-16e7cf335bf9fbd7f68b043b9d670336c6897809.tar.bz2
scala-16e7cf335bf9fbd7f68b043b9d670336c6897809.zip
Align double definition check with spec
Remove weird special cases for private-local fields and parameter accessor (fields). One change with the new trait val encoding: ``` scala> trait T { private[this] var x: String = "1" ; def x(): Int = 1 } <console>:11: error: method x is defined twice; the conflicting variable x was defined at line 11:37 trait T { private[this] var x: String = "1" ; def x(): Int = 1 } ^ ``` Whereas: ``` scala> class T { private[this] var x: String = "1" ; def x(): Int = 1 } defined class T ``` Before, both the `class` and `trait` definition were accepted. (Because there is no accessor for a private[this] val/var, and a MethodType does not match the type of a value.) (Dotty accepts neither the class or the trait definition.)
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Typers.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala61
1 files changed, 41 insertions, 20 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 2bbf8ed74e..efb0830204 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -2208,6 +2208,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}
def typedDefDef(ddef: DefDef): DefDef = {
+ // an accessor's type completer may mutate a type inside `ddef` (`== context.unit.synthetics(ddef.symbol)`)
+ // concretely: it sets the setter's parameter type or the getter's return type (when derived from a valdef with empty tpt)
val meth = ddef.symbol.initialize
reenterTypeParams(ddef.tparams)
@@ -3038,13 +3040,13 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
result
}
- /* 'accessor' and 'accessed' are so similar it becomes very difficult to
- * follow the logic, so I renamed one to something distinct.
- */
+ // TODO: adapt to new trait field encoding, figure out why this exaemption is made
+ // 'accessor' and 'accessed' are so similar it becomes very difficult to
+ //follow the logic, so I renamed one to something distinct.
def accesses(looker: Symbol, accessed: Symbol) = accessed.isLocalToThis && (
- (accessed.isParamAccessor)
- || (looker.hasAccessorFlag && !accessed.hasAccessorFlag && accessed.isPrivate)
- )
+ (accessed.isParamAccessor)
+ || (looker.hasAccessorFlag && !accessed.hasAccessorFlag && accessed.isPrivate)
+ )
def checkNoDoubleDefs: Unit = {
val scope = if (inBlock) context.scope else context.owner.info.decls
@@ -3052,20 +3054,39 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
while ((e ne null) && e.owner == scope) {
var e1 = scope.lookupNextEntry(e)
while ((e1 ne null) && e1.owner == scope) {
- if (!accesses(e.sym, e1.sym) && !accesses(e1.sym, e.sym) &&
- (e.sym.isType || inBlock || (e.sym.tpe matches e1.sym.tpe)))
- // default getters are defined twice when multiple overloads have defaults. an
- // error for this is issued in RefChecks.checkDefaultsInOverloaded
- if (!e.sym.isErroneous && !e1.sym.isErroneous && !e.sym.hasDefault &&
- !e.sym.hasAnnotation(BridgeClass) && !e1.sym.hasAnnotation(BridgeClass)) {
- log("Double definition detected:\n " +
- ((e.sym.getClass, e.sym.info, e.sym.ownerChain)) + "\n " +
- ((e1.sym.getClass, e1.sym.info, e1.sym.ownerChain)))
-
- DefDefinedTwiceError(e.sym, e1.sym)
- scope.unlink(e1) // need to unlink to avoid later problems with lub; see #2779
- }
- e1 = scope.lookupNextEntry(e1)
+ val sym = e.sym
+ val sym1 = e1.sym
+
+ /** From the spec (refchecks checks other conditions regarding erasing to the same type and default arguments):
+ *
+ * A block expression [... its] statement sequence may not contain two definitions or
+ * declarations that bind the same name --> `inBlock`
+ *
+ * It is an error if a template directly defines two matching members.
+ *
+ * A member definition $M$ _matches_ a member definition $M'$, if $M$ and $M'$ bind the same name,
+ * and one of following holds:
+ * 1. Neither $M$ nor $M'$ is a method definition.
+ * 2. $M$ and $M'$ define both monomorphic methods with equivalent argument types.
+ * 3. $M$ defines a parameterless method and $M'$ defines a method with an empty parameter list `()` or _vice versa_.
+ * 4. $M$ and $M'$ define both polymorphic methods with equal number of argument types $\overline T$, $\overline T'$
+ * and equal numbers of type parameters $\overline t$, $\overline t'$, say,
+ * and $\overline T' = [\overline t'/\overline t]\overline T$.
+ */
+ if (!(accesses(sym, sym1) || accesses(sym1, sym)) // TODO: does this purely defer errors until later?
+ && (inBlock || !(sym.isMethod || sym1.isMethod) || (sym.tpe matches sym1.tpe))
+ // default getters are defined twice when multiple overloads have defaults.
+ // The error for this is deferred until RefChecks.checkDefaultsInOverloaded
+ && (!sym.isErroneous && !sym1.isErroneous && !sym.hasDefault &&
+ !sym.hasAnnotation(BridgeClass) && !sym1.hasAnnotation(BridgeClass))) {
+ log("Double definition detected:\n " +
+ ((sym.getClass, sym.info, sym.ownerChain)) + "\n " +
+ ((sym1.getClass, sym1.info, sym1.ownerChain)))
+
+ DefDefinedTwiceError(sym, sym1)
+ scope.unlink(e1) // need to unlink to avoid later problems with lub; see #2779
+ }
+ e1 = scope.lookupNextEntry(e1)
}
e = e.next
}