diff options
author | Adriaan Moors <adriaan.moors@typesafe.com> | 2016-07-07 16:55:36 -0700 |
---|---|---|
committer | Adriaan Moors <adriaan@lightbend.com> | 2016-08-11 10:59:16 -0700 |
commit | 16e7cf335bf9fbd7f68b043b9d670336c6897809 (patch) | |
tree | 1d42d7376192ab8539e4a38e7afe7895793b95bd /src/compiler/scala/tools/nsc/typechecker/Typers.scala | |
parent | b79c0d124e839e9e7ae5db883488c0134642472b (diff) | |
download | scala-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.scala | 61 |
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 } |