aboutsummaryrefslogblamecommitdiff
path: root/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala
blob: be160ac7fba0c97260525e4d334c2c72cfacb622 (plain) (tree)
1
2
3
4
5
6
7
8
9





                            
                                      
                         
                               




                                                                             
                                                   


                          
                                    










                                                  
                                     












                                                                              










































                                                                           






















                                                                                      



























                                                                             






















                                                                                   






































                                                                             













                                                                                  














                                             
                                                                            


                                    
                                            











                                      
                                                                            


                                  
















                                                               

















                                                                        




















                                                                  

















                                        
 





                                                              
 
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)
      }
}