diff options
author | Martin Odersky <odersky@gmail.com> | 2014-11-18 15:18:19 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2014-11-18 15:18:19 +0100 |
commit | ea06d6618f63339fec0af8ca6835a3f34a100d0f (patch) | |
tree | 049d0deba496172146edd358da5aa5c5fa4e2458 | |
parent | b60f085e543e71577e0132b938facd0b6d544e81 (diff) | |
download | dotty-ea06d6618f63339fec0af8ca6835a3f34a100d0f.tar.gz dotty-ea06d6618f63339fec0af8ca6835a3f34a100d0f.tar.bz2 dotty-ea06d6618f63339fec0af8ca6835a3f34a100d0f.zip |
Check that overriding members refine the types of overridden ones.
Somehow this was lost in porting (or was this done somewhere else
in scalac?).
-rw-r--r-- | src/dotty/tools/dotc/core/Denotations.scala | 14 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 16 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/RefChecks.scala | 19 | ||||
-rw-r--r-- | test/dotc/tests.scala | 2 | ||||
-rw-r--r-- | tests/neg/overrides.scala | 11 |
5 files changed, 40 insertions, 22 deletions
diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala index 5ed0ebfb2..236bdb7f4 100644 --- a/src/dotty/tools/dotc/core/Denotations.scala +++ b/src/dotty/tools/dotc/core/Denotations.scala @@ -240,20 +240,8 @@ object Denotations { val sym1 = denot1.symbol val sym2 = denot2.symbol val sym2Accessible = sym2.isAccessibleFrom(pre) - def resultType(tp: Type) = tp match { - case tp @ MethodType(Nil, _) => tp.resultType - case ExprType(rt) => rt - case _ => NoType - } - def isAsGood(tp1: Type, tp2: Type) = - tp1 <:< tp2 || { - val rtp1 = resultType(tp1) - val rtp2 = resultType(tp2) - rtp1 <:< rtp2 - } def prefer(info1: Type, sym1: Symbol, info2: Type, sym2: Symbol) = - isAsGood(info1, info2) && - (sym1.isAsConcrete(sym2) || !(info2 <:< info1)) + info1.overrides(info2) && (sym1.isAsConcrete(sym2) || !info2.overrides(info1)) if (sym2Accessible && prefer(info2, sym2, info1, sym1)) denot2 else { val sym1Accessible = sym1.isAccessibleFrom(pre) diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 5228c077e..a09c0cd71 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -533,6 +533,22 @@ object Types { ctx.typeComparer.isSameType(this, that) } + /** Is this type a legal type for a member that overrides another + * member of type `that`? This is the same as `<:<`, except that + * the types ()T and => T are identified, and T is seen as overriding + * either type. + */ + final def overrides(that: Type)(implicit ctx: Context) = { + def result(tp: Type): Type = tp match { + case ExprType(_) | MethodType(Nil, _) => tp.resultType + case _ => tp + } + this <:< that || { + val rthat = result(that) + (rthat ne that) && result(this) <:< rthat + } + } + /** Is this type close enough to that type so that members * with the two type would override each other?d * This means: diff --git a/src/dotty/tools/dotc/typer/RefChecks.scala b/src/dotty/tools/dotc/typer/RefChecks.scala index 29ac33498..6995076c5 100644 --- a/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/src/dotty/tools/dotc/typer/RefChecks.scala @@ -134,14 +134,13 @@ object RefChecks { def infoString0(sym: Symbol, showLocation: Boolean) = { val sym1 = sym.underlyingSymbol def info = self.memberInfo(sym1) - if (showLocation) sym1.showLocated - else - i"$sym1${ - if (sym1.isAliasType) i", which equals $info" - else if (sym1.isAbstractType) i" with bounds $info" - else if (sym1.is(Module)) "" - else if (sym1.isTerm) i" of type $info" - else ""}" + i"${if (showLocation) sym1.showLocated else sym1}${ + if (sym1.isAliasType) i", which equals $info" + else if (sym1.isAbstractType) i" with bounds $info" + else if (sym1.is(Module)) "" + else if (sym1.isTerm) i" of type $info" + else "" + }" } /* Check that all conditions for overriding `other` by `member` @@ -287,6 +286,10 @@ object RefChecks { overrideError("cannot be used here - term macros cannot override abstract methods") } else if (other.is(Macro) && !member.is(Macro)) { // (1.10) overrideError("cannot be used here - only term macros can override term macros") + } else if (member.isTerm && !isDefaultGetter(member.name) && !(memberTp overrides otherTp)) { + // types don't need to have their bounds in an overriding relationship + // since we automatically form their intersection when selecting. + overrideError("has incompatible type" + err.whyNoMatchStr(memberTp, otherTp)) } else { checkOverrideDeprecated() } diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index fb2b747a6..8a8c162c6 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -73,7 +73,7 @@ class tests extends CompilerTest { @Test def neg_autoTupling2 = compileFile(negDir, "autoTuplingTest", xerrors = 4) @Test def neg_companions = compileFile(negDir, "companions", xerrors = 1) @Test def neg_over = compileFile(negDir, "over", xerrors = 1) - @Test def neg_overrides = compileFile(negDir, "overrides", xerrors = 4) + @Test def neg_overrides = compileFile(negDir, "overrides", xerrors = 5) @Test def neg_projections = compileFile(negDir, "projections", xerrors = 1) @Test def neg_i39 = compileFile(negDir, "i39", xerrors = 1) @Test def neg_i50_volatile = compileFile(negDir, "i50-volatile", xerrors = 4) diff --git a/tests/neg/overrides.scala b/tests/neg/overrides.scala index 4befe1623..d502af8dd 100644 --- a/tests/neg/overrides.scala +++ b/tests/neg/overrides.scala @@ -57,3 +57,14 @@ class X { class Y extends X { def f: A[Int] = ??? } + + +class A1 +class B1 + +class X1 { + def f(): A1 = ??? +} +class Y1 extends X1 { + override def f(): B1 = ??? +} |