package dotty.tools
package dotc
package reporting
import core.Contexts.Context
import diagnostic.messages._
import dotty.tools.dotc.parsing.Tokens
import org.junit.Assert._
import org.junit.{Ignore, Test}
class ErrorMessagesTests extends ErrorMessagesTest {
// In the case where there are no errors, we can do "expectNoErrors" in the
// `Report`
@Test def noErrors =
checkMessagesAfter("frontend")("""class Foo""")
.expectNoErrors
@Test def typeMismatch =
checkMessagesAfter("frontend") {
"""
|object Foo {
| def bar: String = 1
|}
""".stripMargin
}
.expect { (ictx, messages) =>
implicit val ctx: Context = ictx
val defn = ictx.definitions
// Assert that we only got one error message
assertMessageCount(1, messages)
// Pattern match out the expected error
val TypeMismatch(found, expected, _, _) :: Nil = messages
// The type of the right hand side will actually be the constant 1,
// therefore we check if it "derivesFrom" `IntClass`
assert(found.derivesFrom(defn.IntClass), s"found was: $found")
// The expected type is `scala.String` which we dealias to
// `java.lang.String` and compare with `=:=` to `defn.StringType` which
// is a type reference to `java.lang.String`
assert(expected.dealias =:= defn.StringType, s"expected was: $expected")
}
@Test def overridesNothing =
checkMessagesAfter("refchecks") {
"""
|object Foo {
| override def bar: Unit = {}
|}
""".stripMargin
}
.expect { (ictx, messages) =>
implicit val ctx: Context = ictx
val defn = ictx.definitions
assertMessageCount(1, messages)
val OverridesNothing(member) :: Nil = messages
assertEquals("bar", member.name.show)
}
@Test def overridesNothingDifferentSignature =
checkMessagesAfter("refchecks") {
"""
|class Bar {
| def bar(s: String): Unit = {}
| def bar(s: Int): Unit = {}
| final def bar(s: Long): Unit = {}
|}
|object Foo extends Bar {
| override def bar: Unit = {}
|}
""".stripMargin
}
.expect { (ictx, messages) =>
implicit val ctx: Context = ictx
val defn = ictx.definitions
assertMessageCount(1, messages)
val OverridesNothingButNameExists(member, sameName) :: Nil = messages
// check expected context data
assertEquals("bar", member.name.show)
assertEquals(3, sameName.size)
assert(sameName.forall(_.symbol.name.show == "bar"),
"at least one method had an unexpected name")
}
@Test def forwardReference =
checkMessagesAfter("refchecks") {
"""
|object Forward {
| def block = {
| a.toInt
| val b = 2
| val a = BigDecimal("4")
| }
|}
""".stripMargin
}
.expect { (ictx, messages) =>
implicit val ctx: Context = ictx
val defn = ictx.definitions
assertMessageCount(1, messages)
val ForwardReferenceExtendsOverDefinition(value, definition) :: Nil = messages
assertEquals("value b", value.show)
assertEquals("value a", definition.show)
}
@Test def unexpectedToken =
checkMessagesAfter("frontend") {
"""
|object Forward {
| def val = "ds"
|}
""".stripMargin
}
.expect { (ictx, messages) =>
implicit val ctx: Context = ictx
val defn = ictx.definitions
assertMessageCount(1, messages)
val ExpectedTokenButFound(expected, found, foundName) :: Nil = messages
assertEquals(Tokens.IDENTIFIER, expected)
assertEquals(Tokens.VAL, found)
assertEquals("val", foundName.show)
}
@Test def expectedToken =
checkMessagesAfter("frontend") {
"""
|object Forward {
| def `val` = "ds"
|}
""".stripMargin
}
.expectNoErrors
@Test def leftAndRightAssociative =
checkMessagesAfter("frontend") {
"""
|object Ops {
| case class I(j: Int) {
| def +-(i: Int) = i
| def +:(i: Int) = i
| }
| val v = I(1) +- I(4) +: I(4)
|}
""".stripMargin
}
.expect { (ictx, messages) =>
implicit val ctx: Context = ictx
val defn = ictx.definitions
assertMessageCount(1, messages)
val MixedLeftAndRightAssociativeOps(op1, op2, op2LeftAssoc) :: Nil = messages
assertEquals("+-", op1.show)
assertEquals("+:", op2.show)
assertFalse(op2LeftAssoc)
}
@Test def cantInstantiateAbstract =
checkMessagesAfter("refchecks") {
"""
|object Scope {
| abstract class Concept
| new Concept()
|}
""".stripMargin
}
.expect { (ictx, messages) =>
implicit val ctx: Context = ictx
val defn = ictx.definitions
assertMessageCount(1, messages)
val CantInstantiateAbstractClassOrTrait(cls, isTrait) :: Nil = messages
assertEquals("Concept", cls.name.show)
assertFalse("expected class", isTrait)
}
@Test def cantInstantiateTrait =
checkMessagesAfter("refchecks") {
"""
|object Scope {
| trait Concept
| new Concept()
|}
""".stripMargin
}
.expect { (ictx, messages) =>
implicit val ctx: Context = ictx
val defn = ictx.definitions
assertMessageCount(1, messages)
val CantInstantiateAbstractClassOrTrait(cls, isTrait) :: Nil = messages
assertEquals("Concept", cls.name.show)
assertTrue("expected trait", isTrait)
}
@Test def constructorModifier =
checkMessagesAfter("frontend") {
"""
|class AnotherClass @deprecated ()
""".stripMargin
}
.expect { (ictx, messages) =>
implicit val ctx: Context = ictx
val defn = ictx.definitions
assertMessageCount(1, messages)
val AnnotatedPrimaryConstructorRequiresModifierOrThis(cls) :: Nil = messages
assertEquals("AnotherClass", cls.show)
}
@Test def overloadedMethodNeedsReturnType =
checkMessagesAfter("frontend") {
"""
|class Scope() {
| def foo(i: Int) = foo(i.toString)
| def foo(s: String) = s
|}
""".stripMargin
}
.expect { (ictx, messages) =>
implicit val ctx: Context = ictx
val defn = ictx.definitions
assertMessageCount(1, messages)
val OverloadedOrRecursiveMethodNeedsResultType(tree) :: Nil = messages
assertEquals("foo", tree.show)
}
@Test def recursiveMethodNeedsReturnType =
checkMessagesAfter("frontend") {
"""
|class Scope() {
| def i = i + 5
|}
""".stripMargin
}
.expect { (ictx, messages) =>
implicit val ctx: Context = ictx
val defn = ictx.definitions
assertMessageCount(1, messages)
val OverloadedOrRecursiveMethodNeedsResultType(tree) :: Nil = messages
assertEquals("i", tree.show)
}
@Test def recursiveValueNeedsReturnType =
checkMessagesAfter("frontend") {
"""
|class Scope() {
| lazy val i = i + 5
|}
""".stripMargin
}
.expect { (ictx, messages) =>
implicit val ctx: Context = ictx
val defn = ictx.definitions
assertMessageCount(1, messages)
val RecursiveValueNeedsResultType(tree) :: Nil = messages
assertEquals("i", tree.show)
}
@Test def cyclicReferenceInvolving =
checkMessagesAfter("frontend") {
"""
|class A {
| val x: T = ???
| type T <: x.type // error: cyclic reference involving value x
|}
""".stripMargin
}
.expect { (ictx, messages) =>
implicit val ctx: Context = ictx
val defn = ictx.definitions
assertMessageCount(1, messages)
val CyclicReferenceInvolving(denot) :: Nil = messages
assertEquals("value x", denot.show)
}
@Test def cyclicReferenceInvolvingImplicit =
checkMessagesAfter("frontend") {
"""
|object implicitDefs {
| def foo(implicit x: String) = 1
| def bar() = {
| implicit val x = foo
| x
| }
|}
""".stripMargin
}
.expect { (ictx, messages) =>
implicit val ctx: Context = ictx
val defn = ictx.definitions
assertMessageCount(1, messages)
val CyclicReferenceInvolvingImplicit(tree) :: Nil = messages
assertEquals("x", tree.name.show)
}
@Test def superQualMustBeParent =
checkMessagesAfter("frontend") {
"""
|class A {
| def foo(): Unit = ()
|}
|
|class B {
|}
|
|class C extends A {
| super[B].foo
|}
""".stripMargin
}
.expect { (ictx, messages) =>
implicit val ctx: Context = ictx
val defn = ictx.definitions
assertMessageCount(1, messages)
val SuperQualMustBeParent(qual, cls) :: Nil = messages
assertEquals("B", qual.show)
assertEquals("class C", cls.show)
}
}