summaryrefslogtreecommitdiff
path: root/src/compiler/scala/reflect/macros/compiler/Errors.scala
blob: 4c30a9a85cfef9b2fd13dfe08a00463c04d0713f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package scala.reflect.macros
package compiler

import scala.compat.Platform.EOL
import scala.reflect.macros.util.Traces

trait Errors extends Traces {
  self: DefaultMacroCompiler =>

  import global._
  import analyzer._
  import definitions._
  import treeInfo._
  import typer.TyperErrorGen._
  import typer.infer.InferErrorGen._
  private val runDefinitions = currentRun.runDefinitions
  import runDefinitions._
  def globalSettings = global.settings

  // sanity check errors

  private def implRefError(message: String) = {
    val Applied(culprit, _, _) = macroDdef.rhs
    abort(culprit.pos, message)
  }

  private def bundleRefError(message: String) = {
    val Applied(core, _, _) = macroDdef.rhs
    val culprit = core match {
      case Select(Applied(core, _, _), _) => core
      case _ => core
    }
    abort(culprit.pos, message)
  }

  def MacroImplReferenceWrongShapeError() = implRefError(
      "macro implementation reference has wrong shape. required:\n"+
      "macro [<static object>].<method name>[[<type args>]] or\n" +
      "macro [<macro bundle>].<method name>[[<type args>]]")

  def MacroImplWrongNumberOfTypeArgumentsError() = {
    val diagnostic = if (macroImpl.typeParams.length > targs.length) "has too few type arguments" else "has too many arguments"
    implRefError(s"macro implementation reference $diagnostic for " + treeSymTypeMsg(macroImplRef))
  }

  def MacroImplNotPublicError() = implRefError("macro implementation must be public")

  def MacroImplOverloadedError() = implRefError("macro implementation cannot be overloaded")

  def MacroImplNonTagImplicitParameters(params: List[Symbol]) = implRefError("macro implementations cannot have implicit parameters other than WeakTypeTag evidences")

  def MacroBundleNonStaticError() = bundleRefError("macro bundles must be static")

  def MacroBundleWrongShapeError() = bundleRefError("macro bundles must be monomorphic traits extending either BlackboxMacro or WhiteboxMacro and not implementing their `val c: BlackboxContext/WhiteboxContext` member")

  // compatibility errors

  // helpers

  private def lengthMsg(flavor: String, violation: String, extra: Symbol) = {
    val noun = if (flavor == "value") "parameter" else "type parameter"
    val message = noun + " lists have different length, " + violation + " extra " + noun
    val suffix = if (extra ne NoSymbol) " " + extra.defString else ""
    message + suffix
  }

  private def abbreviateCoreAliases(s: String): String = {
    val coreAliases = List("WeakTypeTag", "Expr", "Tree")
    coreAliases.foldLeft(s)((res, x) => res.replace("c.universe." + x, "c." + x))
  }

  private def showMeth(pss: List[List[Symbol]], restpe: Type, abbreviate: Boolean, untype: Boolean) = {
    def preprocess(tpe: Type) = if (untype) untypeMetalevel(tpe) else tpe
    var pssPart = (pss map (ps => ps map (p => p.defStringSeenAs(preprocess(p.info))) mkString ("(", ", ", ")"))).mkString
    if (abbreviate) pssPart = abbreviateCoreAliases(pssPart)
    var retPart = preprocess(restpe).toString
    if (abbreviate || macroDdef.tpt.tpe == null) retPart = abbreviateCoreAliases(retPart)
    pssPart + ": " + retPart
  }

  // not exactly an error generator, but very related
  // and I dearly wanted to push it away from Macros.scala
  private def checkConforms(slot: String, rtpe: Type, atpe: Type) = {
    val verbose = macroDebugVerbose

    def check(rtpe: Type, atpe: Type): Boolean = {
      def success() = { if (verbose) println(rtpe + " <: " + atpe + "?" + EOL + "true"); true }
      (rtpe, atpe) match {
        case _ if rtpe eq atpe => success()
        case (TypeRef(_, RepeatedParamClass, rtpe :: Nil), TypeRef(_, RepeatedParamClass, atpe :: Nil)) => check(rtpe, atpe)
        case (ExprClassOf(_), TreeType()) if rtpe.prefix =:= atpe.prefix => success()
        case (SubtreeType(), ExprClassOf(_)) if rtpe.prefix =:= atpe.prefix => success()
        case _ => rtpe <:< atpe
      }
    }

    val ok =
      if (verbose) withTypesExplained(check(rtpe, atpe))
      else check(rtpe, atpe)
    if (!ok) {
      if (!verbose) explainTypes(rtpe, atpe)
      val msg = {
        val ss = Seq(rtpe, atpe) map (this abbreviateCoreAliases _.toString)
        s"type mismatch for $slot: ${ss(0)} does not conform to ${ss(1)}"
      }
      compatibilityError(msg)
    }
  }

  private def compatibilityError(message: String) =
    implRefError(
      "macro implementation has incompatible shape:"+
      "\n required: " + showMeth(rparamss, rret, abbreviate = true, untype = false) +
      "\n or      : " + showMeth(rparamss, rret, abbreviate = true, untype = true) +
      "\n found   : " + showMeth(aparamss, aret, abbreviate = false, untype = false) +
      "\n" + message)

  def MacroImplParamssMismatchError() = compatibilityError("number of parameter sections differ")

  def MacroImplExtraParamsError(aparams: List[Symbol], rparams: List[Symbol]) = compatibilityError(lengthMsg("value", "found", aparams(rparams.length)))

  def MacroImplMissingParamsError(aparams: List[Symbol], rparams: List[Symbol]) = compatibilityError(abbreviateCoreAliases(lengthMsg("value", "required", rparams(aparams.length))))

  def checkMacroImplParamTypeMismatch(atpe: Type, rparam: Symbol) = checkConforms("parameter " + rparam.name, rparam.tpe, atpe)

  def checkMacroImplResultTypeMismatch(atpe: Type, rret: Type) = checkConforms("return type", atpe, rret)

  def MacroImplParamNameMismatchError(aparam: Symbol, rparam: Symbol) = compatibilityError("parameter names differ: " + rparam.name + " != " + aparam.name)

  def MacroImplVarargMismatchError(aparam: Symbol, rparam: Symbol) = {
    def fail(paramName: Name) = compatibilityError("types incompatible for parameter " + paramName + ": corresponding is not a vararg parameter")
    if (isRepeated(rparam) && !isRepeated(aparam)) fail(rparam.name)
    if (!isRepeated(rparam) && isRepeated(aparam)) fail(aparam.name)
  }

  def MacroImplTargMismatchError(atargs: List[Type], atparams: List[Symbol]) =
    compatibilityError(NotWithinBoundsErrorMessage("", atargs, atparams, macroDebugVerbose || settings.explaintypes.value))

  def MacroImplTparamInstantiationError(atparams: List[Symbol], e: NoInstance) = {
    val badps = atparams map (_.defString) mkString ", "
    compatibilityError(f"type parameters $badps cannot be instantiated%n${e.getMessage}")
  }
}