aboutsummaryrefslogblamecommitdiff
path: root/src/dotty/tools/dotc/typer/ErrorReporting.scala
blob: 8bbf1eba08da997b27f2170437629c2a96273286 (plain) (tree)
1
2
3
4
5
6
7
8
9
10






                   
                                                                  

                       

                                           




                       
                                                                                    




                                                                                    







                                                      
                                                    
         
                                                      
               
                            







                                                      
                     


                                                         

                                                                         










                                                                   



                                                      








                                                            



                                                     
 



                                                                   



















                                                                                         



                                                      





                                                                                
 
package dotty.tools
package dotc
package typer

import ast._
import core._
import Trees._
import Types._, Contexts._, Decorators._, Denotations._, Symbols._
import Applications._
import util.Positions._
import printing.Showable
import reporting.Reporter.SuppressedMessage

object ErrorReporting {

  import tpd._

  def errorTree(tree: untpd.Tree, msg: => String)(implicit ctx: Context): tpd.Tree =
    tree withType errorType(msg, tree.pos)

  def errorType(msg: => String, pos: Position)(implicit ctx: Context): ErrorType = {
    ctx.error(msg, pos)
    ErrorType
  }

  class Errors(implicit ctx: Context) {

    def expectedTypeStr(tp: Type): String = tp match {
      case tp: FunProtoType =>
        val result = tp.resultType match {
          case tp: WildcardType => ""
          case tp => i"and expected result type $tp"
        }
        i"arguments (${tp.typedArgs.tpes}%, %)$result"
      case _ =>
        i"expected type $tp"
    }

    def anonymousTypeMemberStr(tpe: Type) = {
      val kind = tpe match {
          case _: TypeBounds => "type with bounds"
          case _: PolyType | _: MethodType => "method"
          case _ => "value of type"
        }
        i"$kind $tpe"
    }

    def overloadedAltsStr(alts: List[SingleDenotation]) =
      i"overloaded alternatives of ${denotStr(alts.head)} with types\n" +
      i" ${alts map (_.info)}%\n %"

    def denotStr(denot: Denotation): String =
      if (denot.isOverloaded) overloadedAltsStr(denot.alternatives)
      else if (denot.symbol.exists) denot.symbol.showLocated
      else anonymousTypeMemberStr(denot.info)

    def refStr(tp: Type): String = tp match {
      case tp: NamedType => denotStr(tp.denot)
      case _ => anonymousTypeMemberStr(tp)
    }

    def exprStr(tree: Tree): String = refStr(tree.tpe)

    def patternConstrStr(tree: Tree): String = ???

    def typeMismatch(tree: Tree, pt: Type): Tree = {
      val result = errorTree(tree,
        i"""type mismatch:
           | found   : ${tree.tpe}
           | required: $pt""".stripMargin)
      if (ctx.settings.explaintypes.value)
        new ExplainingTypeComparer().isSubType(tree.tpe, pt)
      result
    }

  }

  def err(implicit ctx: Context): Errors = new Errors

  /** Implementation of i"..." string interpolator */
  implicit class InfoString(val sc: StringContext) extends AnyVal {

    def i(args: Any*)(implicit ctx: Context): String = {

      def isSensical(arg: Any): Boolean = arg match {
        case tpe: Type if tpe.isErroneous => false
        case NoType => false
        case sym: Symbol if sym.isCompleted =>
          sym.info != ErrorType && sym.info != TypeAlias(ErrorType) && sym.info != NoType
        case _ => true
      }

      def treatArg(arg: Any, suffix: String): (Any, String) = arg match {
        case arg: Showable =>
          (arg.show, suffix)
        case arg: List[_] if suffix.head == '%' =>
          val (sep, rest) = suffix.tail.span(_ != '%')
          if (rest.nonEmpty) (arg mkString sep, rest.tail)
          else (arg, suffix)
        case _ =>
          (arg, suffix)
      }

      if (ctx.reporter.hasErrors &&
          ctx.suppressNonSensicalErrors &&
          !ctx.settings.YshowSuppressedErrors.value &&
          !args.forall(isSensical(_)))
        throw new SuppressedMessage
      val prefix :: suffixes = sc.parts.toList
      val (args1, suffixes1) = (args, suffixes).zipped.map(treatArg(_, _)).unzip
      new StringContext(prefix :: suffixes1.toList: _*).s(args1: _*)
    }
  }
}