From 4ea915c599d134ceeac67962e3cae88672b25b26 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Thu, 16 Aug 2012 17:03:02 +0200 Subject: removes dead code --- .../scala/tools/nsc/typechecker/Macros.scala | 25 +++++----------------- 1 file changed, 5 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 4765bbabc9..49a7345cb5 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -225,33 +225,22 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { private def macroImplSig(macroDef: Symbol, tparams: List[TypeDef], vparamss: List[List[ValDef]], retTpe: Type): (List[List[Symbol]], Type) = { // had to move method's body to an object because of the recursive dependencies between sigma and param object SigGenerator { - val hasThis = macroDef.owner.isClass - val ownerTpe = macroDef.owner match { - case owner if owner.isModuleClass => new UniqueThisType(macroDef.owner) - case owner if owner.isClass => macroDef.owner.tpe - case _ => NoType - } - val hasTparams = !tparams.isEmpty - def sigma(tpe: Type): Type = { class SigmaTypeMap extends TypeMap { def apply(tp: Type): Type = tp match { case TypeRef(pre, sym, args) => val pre1 = pre match { case ThisType(sym) if sym == macroDef.owner => - SingleType(SingleType(SingleType(NoPrefix, paramsCtx(0)), MacroContextPrefix), ExprValue) + SingleType(SingleType(SingleType(NoPrefix, ctxParam), MacroContextPrefix), ExprValue) case SingleType(NoPrefix, sym) => mfind(vparamss)(_.symbol == sym) match { - case Some(macroDefParam) => - SingleType(SingleType(NoPrefix, param(macroDefParam)), ExprValue) - case _ => - pre + case Some(macroDefParam) => SingleType(SingleType(NoPrefix, param(macroDefParam)), ExprValue) + case _ => pre } case _ => pre } - val args1 = args map mapOver - TypeRef(pre1, sym, args1) + TypeRef(pre1, sym, args map mapOver) case _ => mapOver(tp) } @@ -281,11 +270,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { sigParam }) - val paramsCtx = List(ctxParam) - val paramsThis = List(makeParam(nme.macroThis, macroDef.pos, implType(false, ownerTpe), SYNTHETIC)) - val paramsTparams = tparams map param - val paramssParams = mmap(vparamss)(param) - val paramss = paramsCtx :: paramssParams + val paramss = List(ctxParam) :: mmap(vparamss)(param) val implRetTpe = typeRef(singleType(NoPrefix, ctxParam), getMember(MacroContextClass, tpnme.Expr), List(sigma(retTpe))) } -- cgit v1.2.3 From 78f9ef3906c78413ff8835fdad3849bfe5516be2 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Thu, 16 Aug 2012 22:16:56 +0200 Subject: shaves more than 150 lines off typedMacroBody --- .../tools/nsc/typechecker/ContextErrors.scala | 183 ++++++++++- .../scala/tools/nsc/typechecker/Macros.scala | 340 +++++---------------- .../scala/tools/nsc/typechecker/Typers.scala | 2 +- .../scala/reflect/internal/Definitions.scala | 1 + src/reflect/scala/reflect/internal/TreeInfo.scala | 18 +- test/files/neg/macro-invalidshape-a.check | 3 +- test/files/neg/macro-invalidshape-b.check | 3 +- test/files/neg/macro-invalidshape-c.check | 11 +- .../neg/macro-invalidsig-params-namemismatch.check | 1 - 9 files changed, 285 insertions(+), 277 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index c7728ce389..f6785b6541 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -8,12 +8,14 @@ package typechecker import scala.collection.{ mutable, immutable } import scala.reflect.internal.util.StringOps.{ countElementsAsString, countAsString } -import symtab.Flags.{ PRIVATE, PROTECTED } +import symtab.Flags.{ PRIVATE, PROTECTED, IS_ERROR } +import scala.compat.Platform.EOL trait ContextErrors { self: Analyzer => import global._ + import definitions._ object ErrorKinds extends Enumeration { type ErrorKind = Value @@ -625,11 +627,11 @@ trait ContextErrors { } // cyclic errors - def CyclicAliasingOrSubtypingError(errPos: Position, sym0: Symbol) = - issueTypeError(PosAndMsgTypeError(errPos, "cyclic aliasing or subtyping involving "+sym0)) + def CyclicAliasingOrSubtypingError(errPos: Position, sym0: Symbol) = + issueTypeError(PosAndMsgTypeError(errPos, "cyclic aliasing or subtyping involving "+sym0)) - def CyclicReferenceError(errPos: Position, lockedSym: Symbol) = - issueTypeError(PosAndMsgTypeError(errPos, "illegal cyclic reference involving " + lockedSym)) + def CyclicReferenceError(errPos: Position, lockedSym: Symbol) = + issueTypeError(PosAndMsgTypeError(errPos, "illegal cyclic reference involving " + lockedSym)) } } @@ -706,7 +708,7 @@ trait ContextErrors { // side-effect on the tree, break the overloaded type cycle in infer @inline private def setErrorOnLastTry(lastTry: Boolean, tree: Tree) = if (lastTry) setError(tree) - + def NoBestMethodAlternativeError(tree: Tree, argtpes: List[Type], pt: Type, lastTry: Boolean) = { issueNormalTypeError(tree, applyErrorMsg(tree, " cannot be applied to ", argtpes, pt)) @@ -719,7 +721,7 @@ trait ContextErrors { def AmbiguousMethodAlternativeError(tree: Tree, pre: Type, best: Symbol, firstCompeting: Symbol, argtpes: List[Type], pt: Type, lastTry: Boolean) = { - + if (!(argtpes exists (_.isErroneous)) && !pt.isErroneous) { val msg0 = "argument types " + argtpes.mkString("(", ",", ")") + @@ -729,7 +731,7 @@ trait ContextErrors { setErrorOnLastTry(lastTry, tree) } else setError(tree) // do not even try further attempts because they should all fail // even if this is not the last attempt (because of the SO's possibility on the horizon) - + } def NoBestExprAlternativeError(tree: Tree, pt: Type, lastTry: Boolean) = { @@ -1061,7 +1063,7 @@ trait ContextErrors { setError(arg) } else arg } - + def WarnAfterNonSilentRecursiveInference(param: Symbol, arg: Tree)(implicit context: Context) = { val note = "type-checking the invocation of "+ param.owner +" checks if the named argument expression '"+ param.name + " = ...' is a valid assignment\n"+ "in the current scope. The resulting type inference error (see above) can be fixed by providing an explicit type in the local definition for "+ param.name +"." @@ -1087,4 +1089,167 @@ trait ContextErrors { setError(arg) } } + + // using an exception here is actually a good idea + // because the lifespan of this exception is extremely small and controlled + // moreover exceptions let us avoid an avalanche of "if (!hasError) do stuff" checks + case class MacroBodyTypecheckException() extends Exception + + trait MacroErrors { + self: MacroTyper => + + implicit val context = typer.context + + def fail() = { + // need to set the IS_ERROR flag to prohibit spurious expansions + if (macroDef != null) macroDef setFlag IS_ERROR + // not setting ErrorSymbol as in `infer.setError`, because we still need to know that it's a macro + // otherwise assignTypeToTree in Namers might fail if macroDdef.tpt == EmptyTree + macroDdef setType ErrorType + throw MacroBodyTypecheckException() + } + + def MacroDefIsHardwired() = { + macroLogVerbose("typecheck terminated unexpectedly: macro is hardwired") + assert(!macroDdef.tpt.isEmpty, "hardwired macros must provide result type") + throw MacroBodyTypecheckException() + } + + def MacroFeatureNotEnabled() = { + macroLogVerbose("typecheck terminated unexpectedly: language.experimental.macros feature is not enabled") + macroDef setFlag IS_ERROR + throw MacroBodyTypecheckException() + } + + def MacroDefUntypeableBodyError() = { + // do nothing, just fail + // relevant typecheck errors have already been reported + fail() + } + + def MacroDefInvalidBodyError() = { + issueNormalTypeError(macroDdef, + "macro body has wrong shape:" + + "\n required: macro [].[[]]") + fail() + } + + def MacroImplNotPublicError() = { + issueNormalTypeError(macroDdef.rhs, "macro implementation must be public") + fail() + } + + def MacroImplOverloadedError() = { + issueNormalTypeError(macroDdef.rhs, "macro implementation cannot be overloaded") + fail() + } + + def MacroImplNeedsTypeArgumentsError() = { + issueNormalTypeError(macroDdef.rhs, "macro implementation reference needs type arguments") + fail() + } + + def MacroImplDoesntNeedTypeArgumentsError() = { + issueNormalTypeError(macroDdef.rhs, "macro implementation reference doesn't need type arguments") + fail() + } + + def MacroImplNotStaticError() = { + issueNormalTypeError(macroDdef.rhs, "macro implementation must be in statically accessible object") + fail() + } + + // prohibit implicit params on macro implementations + // we don't have to do this, but it appears to be more clear than allowing them + def MacroImplNonTagImplicitParameters(params: List[Symbol]) = { + issueSymbolTypeError(params.head, "macro implementations cannot have implicit parameters other than AbsTypeTag evidences") + fail() + } + + private def abbreviateCoreAliases(s: String): String = { + var result = s + result = result.replace("c.universe.AbsTypeTag", "c.AbsTypeTag") + result = result.replace("c.universe.Expr", "c.Expr") + result + } + + private def showMeth(pss: List[List[Symbol]], restpe: Type, abbreviate: Boolean) = { + var argsPart = (pss map (ps => ps map (_.defString) mkString ("(", ", ", ")"))).mkString + if (abbreviate) argsPart = abbreviateCoreAliases(argsPart) + var retPart = restpe.toString + if (abbreviate || macroDdef.tpt.tpe == null) retPart = abbreviateCoreAliases(retPart) + argsPart + ": " + retPart + } + + private def compatibilityError(message: String) = { + issueNormalTypeError(macroDdef.rhs, + "macro implementation has wrong shape:"+ + "\n required: " + showMeth(rparamss, rret, abbreviate = true) + + "\n found : " + showMeth(aparamss, aret, abbreviate = false) + + "\n" + message) + fail() + } + + def MacroImplParamssMismatchError() = { + compatibilityError("number of parameter sections differ") + } + + private def lengthMsg(which: String, extra: Symbol) = { + "parameter lists have different length, " + which + " extra parameter " + extra.defString + } + + def MacroImplExtraParamsError(aparams: List[Symbol], rparams: List[Symbol]) = { + compatibilityError(lengthMsg("found", aparams(rparams.length))) + } + + def MacroImplMissingParamsError(aparams: List[Symbol], rparams: List[Symbol]) = { + compatibilityError(abbreviateCoreAliases(lengthMsg("required", rparams(aparams.length)))) + } + + // not exactly an error generator, but very related + // and I dearly wanted to push it away from Macros.scala + def checkSubType(slot: String, rtpe: Type, atpe: Type) = { + val ok = if (macroDebugVerbose) { + if (rtpe eq atpe) println(rtpe + " <: " + atpe + "?" + EOL + "true") + withTypesExplained(rtpe <:< atpe) + } else rtpe <:< atpe + if (!ok) { + compatibilityError("type mismatch for %s: %s does not conform to %s".format(slot, abbreviateCoreAliases(rtpe.toString), abbreviateCoreAliases(atpe.toString))) + } + } + + def checkMacroImplParamTypeMismatch(atpe: Type, rparam: Symbol) = { + checkSubType("parameter " + rparam.name, rparam.tpe, atpe) + } + + def checkMacroImplResultTypeMismatch(atpe: Type, rret: Type) = { + checkSubType("return type", atpe, rret) + } + + def MacroImplParamNameMismatchError(aparam: Symbol, rparam: Symbol) = { + // in the error message rparamss come first + // hence rparam should also come first if possible + compatibilityError("parameter names differ: " + rparam.name + " != " + aparam.name) + } + + def MacroImplVarargMismatchError(aparam: Symbol, rparam: Symbol) = { + if (isRepeated(rparam) && !isRepeated(aparam)) + compatibilityError("types incompatible for parameter " + rparam.name + ": corresponding is not a vararg parameter") + if (!isRepeated(rparam) && isRepeated(aparam)) + compatibilityError("types incompatible for parameter " + aparam.name + ": corresponding is not a vararg parameter") + } + + def MacroImplTargMismatchError(atargs: List[Type], atparams: List[Symbol]) = { + val bounds = atparams map (tp => tp.info.instantiateTypeParams(atparams, atargs).bounds) + compatibilityError("type arguments " + atargs.mkString("[", ",", "]") + + " do not conform to " + atparams.head.owner + "'s type parameter bounds " + + (atparams map (_.defString)).mkString("[", ",", "]")) + } + + def MacroImplTparamInstantiationError(atparams: List[Symbol], ex: NoInstance) = { + compatibilityError( + "type parameters "+(atparams map (_.defString) mkString ", ")+" cannot be instantiated\n"+ + ex.getMessage) + } + } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 49a7345cb5..2c8af627d0 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -32,7 +32,7 @@ import scala.reflect.internal.util.Collections._ * } * * Then, if foo is called in qual.foo[Int](elems), where qual: D, - * the macro application is expanded to a reflective invocation of fooBar with parameters + * the macro application is expanded to a reflective invocation of fooBar with parameters: * * (simpleMacroContext{ type PrefixType = D; val prefix = qual }) * (Expr(elems)) @@ -43,6 +43,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { import global._ import definitions._ + import treeInfo.{isRepeatedParamType => _, _} import MacrosStats._ def globalSettings = global.settings @@ -299,8 +300,8 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { if (paramss.isEmpty || paramss.last.isEmpty) return paramss // no implicit parameters in the signature => nothing to do if (paramss.head.isEmpty || !(paramss.head.head.tpe <:< MacroContextClass.tpe)) return paramss // no context parameter in the signature => nothing to do def transformTag(param: Symbol): Symbol = param.tpe.dealias match { - case TypeRef(SingleType(SingleType(NoPrefix, c), universe), typetag, targ :: Nil) - if c == paramss.head.head && universe == MacroContextUniverse && typetag == AbsTypeTagClass => + case TypeRef(SingleType(SingleType(NoPrefix, c), universe), AbsTypeTagClass, targ :: Nil) + if c == paramss.head.head && universe == MacroContextUniverse => transform(param, targ.typeSymbol) case _ => param @@ -319,105 +320,17 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { * * @return typechecked rhs of the given macro definition */ - def typedMacroBody(typer: Typer, ddef: DefDef): Tree = { - import typer.context - macroLogVerbose("typechecking macro def %s at %s".format(ddef.symbol, ddef.pos)) - - val macroDef = ddef.symbol - val defpos = macroDef.pos - val implpos = ddef.rhs.pos - assert(macroDef.isTermMacro, ddef) - - if (fastTrack contains ddef.symbol) { - macroLogVerbose("typecheck terminated unexpectedly: macro is hardwired") - assert(!ddef.tpt.isEmpty, "hardwired macros must provide result type") - return EmptyTree - } - - if (!typer.checkFeature(ddef.pos, MacrosFeature, immediate = true)) { - macroLogVerbose("typecheck terminated unexpectedly: language.experimental.macros feature is not enabled") - ddef.symbol setFlag IS_ERROR - return EmptyTree - } - - implicit class AugmentedString(s: String) { - def abbreviateCoreAliases: String = { // hack! - var result = s - result = result.replace("c.universe.AbsTypeTag", "c.AbsTypeTag") - result = result.replace("c.universe.Expr", "c.Expr") - result - } - } - - var _hasError = false - def hasError = _hasError - def setError(): Unit = { - _hasError = true - macroDef setFlag IS_ERROR - } - def reportError(pos: Position, msg: String) = { - setError() - context.error(pos, msg) - } - - def invalidBodyError() = - reportError(defpos, - "macro body has wrong shape:" + - "\n required: macro ." + - "\n or : macro ") - def validatePreTyper(rhs: Tree): Unit = rhs match { - // we do allow macro invocations inside macro bodies - // personally I don't mind if pre-typer tree is a macro invocation - // that later resolves to a valid reference to a macro implementation - // however, I don't think that invalidBodyError() should hint at that - // let this be an Easter Egg :) - case Apply(_, _) => ; - case TypeApply(_, _) => ; - case Super(_, _) => ; - case This(_) => ; - case Ident(_) => ; - case Select(_, _) => ; - case _ => invalidBodyError() - } - def validatePostTyper(rhs1: Tree): Unit = { - def loop(tree: Tree): Unit = { - def errorNotStatic() = - reportError(implpos, "macro implementation must be in statically accessible object") - - def ensureRoot(sym: Symbol) = - if (!sym.isModule && !sym.isModuleClass) errorNotStatic() - - def ensureModule(sym: Symbol) = - if (!sym.isModule) errorNotStatic() - - tree match { - case TypeApply(fun, _) => - loop(fun) - case Super(qual, _) => - ensureRoot(macroDef.owner) - loop(qual) - case This(_) => - ensureRoot(tree.symbol) - case Select(qual, name) if name.isTypeName => - loop(qual) - case Select(qual, name) if name.isTermName => - if (tree.symbol != rhs1.symbol) ensureModule(tree.symbol) - loop(qual) - case Ident(name) if name.isTypeName => - ; - case Ident(name) if name.isTermName => - if (tree.symbol != rhs1.symbol) ensureModule(tree.symbol) - case _ => - invalidBodyError() - } - } - - loop(rhs1) - } - - val rhs = ddef.rhs - validatePreTyper(rhs) - if (hasError) macroTraceVerbose("macro def failed to satisfy trivial preconditions: ")(macroDef) + def typedMacroBody(typer: Typer, macroDdef: DefDef): Tree = + try new MacroTyper(typer, macroDdef).typed + catch { case MacroBodyTypecheckException() => EmptyTree } + + class MacroTyper(val typer: Typer, val macroDdef: DefDef) extends MacroErrors { + // Phase I: sanity checks + val macroDef = macroDdef.symbol + macroLogVerbose("typechecking macro def %s at %s".format(macroDef, macroDdef.pos)) + assert(macroDef.isTermMacro, macroDdef) + if (fastTrack contains macroDef) MacroDefIsHardwired() + if (!typer.checkFeature(macroDdef.pos, MacrosFeature, immediate = true)) MacroFeatureNotEnabled() // we use typed1 instead of typed, because otherwise adapt is going to mess us up // if adapt sees ., it will want to perform eta-expansion and will fail @@ -425,11 +338,13 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { // because it's adapt which is responsible for automatic expansion during typechecking def typecheckRhs(rhs: Tree): Tree = { try { + // interestingly enough, just checking isErroneous doesn't cut it + // e.g. a "type arguments [U] do not conform to method foo's type parameter bounds" error + // doesn't manifest itself as an error in the resulting tree val prevNumErrors = reporter.ERROR.count - var rhs1 = if (hasError) EmptyTree else typer.typed1(rhs, EXPRmode, WildcardType) - def typecheckedWithErrors = (rhs1 exists (_.isErroneous)) || reporter.ERROR.count != prevNumErrors + var rhs1 = typer.typed1(rhs, EXPRmode, WildcardType) def rhsNeedsMacroExpansion = rhs1.symbol != null && rhs1.symbol.isTermMacro && !rhs1.symbol.isErroneous - while (!typecheckedWithErrors && rhsNeedsMacroExpansion) { + while (rhsNeedsMacroExpansion) { rhs1 = macroExpand1(typer, rhs1) match { case Success(expanded) => try { @@ -445,167 +360,79 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { result } } + val typecheckedWithErrors = (rhs1 exists (_.isErroneous)) || reporter.ERROR.count != prevNumErrors + if (typecheckedWithErrors) MacroDefUntypeableBodyError() rhs1 } catch { case ex: TypeError => typer.reportTypeError(context, rhs.pos, ex) - typer.infer.setError(rhs) + MacroDefUntypeableBodyError() } } - val prevNumErrors = reporter.ERROR.count // funnily enough, the isErroneous check is not enough - var rhs1 = typecheckRhs(rhs) - val macroImpl = rhs1.symbol - def typecheckedWithErrors = (rhs1 exists (_.isErroneous)) || reporter.ERROR.count != prevNumErrors - if (typecheckedWithErrors) { - setError() - macroTraceVerbose("body of a macro def failed to typecheck: ")(ddef) - } else { - if (!hasError) { - if (macroImpl == null) invalidBodyError() - else { - if (!macroImpl.isMethod) invalidBodyError() - if (!macroImpl.isPublic) reportError(implpos, "macro implementation must be public") - if (macroImpl.isOverloaded) reportError(implpos, "macro implementation cannot be overloaded") - if (!macroImpl.typeParams.isEmpty && !rhs1.isInstanceOf[TypeApply]) reportError(implpos, "macro implementation reference needs type arguments") - if (!hasError) validatePostTyper(rhs1) - } - } - if (!hasError) { - bindMacroImpl(macroDef, rhs1) // we must bind right over here, because return type inference needs this info - } + // Phase II: typecheck the right-hand side of the macro def + val typed = typecheckRhs(macroDdef.rhs) + typed match { + case MacroImplReference(owner, meth, targs) => + if (!meth.isMethod) MacroDefInvalidBodyError() + if (!meth.isPublic) MacroImplNotPublicError() + if (meth.isOverloaded) MacroImplOverloadedError() + if (meth.typeParams.nonEmpty && targs.isEmpty) MacroImplNeedsTypeArgumentsError() + if (meth.typeParams.isEmpty && targs.nonEmpty) MacroImplDoesntNeedTypeArgumentsError() + if (!owner.isStaticOwner && !owner.moduleClass.isStaticOwner) MacroImplNotStaticError() + bindMacroImpl(macroDef, typed) + case _ => + MacroDefInvalidBodyError() } - if (!hasError) { - def checkCompatibility(reqparamss: List[List[Symbol]], actparamss: List[List[Symbol]], reqres: Type, actres: Type): List[String] = { - var hasError = false - var errors = List[String]() - def compatibilityError(msg: String) { - hasError = true - errors :+= msg - } - - val flatreqparams = reqparamss.flatten - val flatactparams = actparamss.flatten - val tparams = macroImpl.typeParams - val tvars = tparams map freshVar - def lengthMsg(which: String, extra: Symbol) = - "parameter lists have different length, "+which+" extra parameter "+extra.defString - if (actparamss.length != reqparamss.length) - compatibilityError("number of parameter sections differ") - - def checkSubType(slot: String, reqtpe: Type, acttpe: Type): Unit = { - val ok = if (macroDebugVerbose) { - if (reqtpe eq acttpe) println(reqtpe + " <: " + acttpe + "?" + EOL + "true") - withTypesExplained(reqtpe <:< acttpe) - } else reqtpe <:< acttpe - if (!ok) { - compatibilityError("type mismatch for %s: %s does not conform to %s".format(slot, reqtpe.toString.abbreviateCoreAliases, acttpe.toString.abbreviateCoreAliases)) - } - } - - if (!hasError) { - try { - for ((rparams, aparams) <- reqparamss zip actparamss) { - if (rparams.length < aparams.length) - compatibilityError(lengthMsg("found", aparams(rparams.length))) - if (aparams.length < rparams.length) - compatibilityError(lengthMsg("required", rparams(aparams.length)).abbreviateCoreAliases) - } - // if the implementation signature is already deemed to be incompatible, we bail out - // otherwise, high-order type magic employed below might crash in weird ways - if (!hasError) { - for ((rparams, aparams) <- reqparamss zip actparamss) { - for ((rparam, aparam) <- rparams zip aparams) { - def isRepeated(param: Symbol) = param.tpe.typeSymbol == RepeatedParamClass - if (rparam.name != aparam.name && !rparam.isSynthetic) { - val rparam1 = rparam - val aparam1 = aparam - compatibilityError("parameter names differ: "+rparam.name+" != "+aparam.name) - } - if (isRepeated(rparam) && !isRepeated(aparam)) - compatibilityError("types incompatible for parameter "+rparam.name+": corresponding is not a vararg parameter") - if (!isRepeated(rparam) && isRepeated(aparam)) - compatibilityError("types incompatible for parameter "+aparam.name+": corresponding is not a vararg parameter") - if (!hasError) { - var atpe = aparam.tpe.substSym(flatactparams, flatreqparams).instantiateTypeParams(tparams, tvars) - atpe = atpe.dealias // SI-5706 - // strip the { type PrefixType = ... } refinement off the Context or otherwise we get compatibility errors - atpe = atpe match { - case RefinedType(List(tpe), Scope(sym)) if tpe == MacroContextClass.tpe && sym.allOverriddenSymbols.contains(MacroContextPrefixType) => tpe - case _ => atpe - } - checkSubType("parameter " + rparam.name, rparam.tpe, atpe) - } - } - } - } - if (!hasError) { - val atpe = actres.substSym(flatactparams, flatreqparams).instantiateTypeParams(tparams, tvars) - checkSubType("return type", atpe, reqres) - } - if (!hasError) { - val targs = solvedTypes(tvars, tparams, tparams map varianceInType(actres), false, - lubDepth(flatactparams map (_.tpe)) max lubDepth(flatreqparams map (_.tpe))) - val boundsOk = typer.silent(_.infer.checkBounds(ddef, NoPrefix, NoSymbol, tparams, targs, "")) - boundsOk match { - case SilentResultValue(true) => ; - case SilentResultValue(false) | SilentTypeError(_) => - val bounds = tparams map (tp => tp.info.instantiateTypeParams(tparams, targs).bounds) - compatibilityError("type arguments " + targs.mkString("[", ",", "]") + - " do not conform to " + tparams.head.owner + "'s type parameter bounds " + - (tparams map (_.defString)).mkString("[", ",", "]")) - } - } - } catch { - case ex: NoInstance => - compatibilityError( - "type parameters "+(tparams map (_.defString) mkString ", ")+" cannot be instantiated\n"+ - ex.getMessage) - } - } + // Phase III: check compatibility between the macro def and its macro impl + // aXXX (e.g. aparamss) => characteristics of the macro impl ("a" stands for "actual") + // rXXX (e.g. rparamss) => characteristics of a reference macro impl signature synthesized from the macro def ("r" stands for "reference") + val macroImpl = typed.symbol + val aparamss = transformTypeTagEvidenceParams(macroImpl.paramss, (param, tparam) => NoSymbol) + val aret = macroImpl.tpe.finalResultType + val macroDefRet = + if (!macroDdef.tpt.isEmpty) typer.typedType(macroDdef.tpt).tpe + else computeMacroDefTypeFromMacroImpl(macroDdef, macroImpl) + val (rparamss, rret) = macroImplSig(macroDef, macroDdef.tparams, macroDdef.vparamss, macroDefRet) + + val implicitParams = aparamss.flatten filter (_.isImplicit) + if (implicitParams.nonEmpty) MacroImplNonTagImplicitParameters(implicitParams) + if (aparamss.length != rparamss.length) MacroImplParamssMismatchError() + + val atparams = macroImpl.typeParams + val atvars = atparams map freshVar + def atpeToRtpe(atpe: Type) = atpe.substSym(aparamss.flatten, rparamss.flatten).instantiateTypeParams(atparams, atvars) - errors.toList - } + try { + map2(aparamss, rparamss)((aparams, rparams) => { + if (aparams.length < rparams.length) MacroImplMissingParamsError(aparams, rparams) + if (rparams.length < aparams.length) MacroImplExtraParamsError(aparams, rparams) + }) - var actparamss = macroImpl.paramss - actparamss = transformTypeTagEvidenceParams(actparamss, (param, tparam) => NoSymbol) - val actres = macroImpl.tpe.finalResultType - val implicitParams = actparamss.flatten filter (_.isImplicit) - if (implicitParams.length > 0) { - // prohibit implicit params on macro implementations - // we don't have to do this, but it appears to be more clear than allowing them - reportError(implicitParams.head.pos, "macro implementations cannot have implicit parameters other than AbsTypeTag evidences") - macroTraceVerbose("macro def failed to satisfy trivial preconditions: ")(macroDef) - } + // cannot fuse these loops because if aparamss.flatten != rparamss.flatten + // then `atpeToRtpe` is going to fail with an unsound substitution + map2(aparamss.flatten, rparamss.flatten)((aparam, rparam) => { + if (aparam.name != rparam.name && !rparam.isSynthetic) MacroImplParamNameMismatchError(aparam, rparam) + if (isRepeated(aparam) ^ isRepeated(rparam)) MacroImplVarargMismatchError(aparam, rparam) + checkMacroImplParamTypeMismatch(stripOffPrefixTypeRefinement(atpeToRtpe(aparam.tpe)), rparam) + }) - if (!hasError) { - val rettpe = if (!ddef.tpt.isEmpty) typer.typedType(ddef.tpt).tpe else computeMacroDefTypeFromMacroImpl(ddef, macroDef, macroImpl) - val (reqparamss, reqres) = macroImplSig(macroDef, ddef.tparams, ddef.vparamss, rettpe) + checkMacroImplResultTypeMismatch(atpeToRtpe(aret), rret) - def showMeth(pss: List[List[Symbol]], restpe: Type, abbreviate: Boolean) = { - var argsPart = (pss map (ps => ps map (_.defString) mkString ("(", ", ", ")"))).mkString - if (abbreviate) argsPart = argsPart.abbreviateCoreAliases - var retPart = restpe.toString - if (abbreviate || ddef.tpt.tpe == null) retPart = retPart.abbreviateCoreAliases - argsPart + ": " + retPart - } - def compatibilityError(addendum: String) = - reportError(implpos, - "macro implementation has wrong shape:"+ - "\n required: "+showMeth(reqparamss, reqres, true) + - "\n found : "+showMeth(actparamss, actres, false)+ - "\n"+addendum) - - val errors = checkCompatibility(reqparamss, actparamss, reqres, actres) - if (errors.nonEmpty) compatibilityError(errors mkString "\n") + val maxLubDepth = lubDepth(aparamss.flatten map (_.tpe)) max lubDepth(rparamss.flatten map (_.tpe)) + val atargs = solvedTypes(atvars, atparams, atparams map varianceInType(aret), upper = false, depth = maxLubDepth) + val boundsOk = typer.silent(_.infer.checkBounds(macroDdef, NoPrefix, NoSymbol, atparams, atargs, "")) + boundsOk match { + case SilentResultValue(true) => // do nothing, success + case SilentResultValue(false) | SilentTypeError(_) => MacroImplTargMismatchError(atargs, atparams) } + } catch { + case ex: NoInstance => MacroImplTparamInstantiationError(atparams, ex) } - - rhs1 } - def computeMacroDefTypeFromMacroImpl(macroDdef: DefDef, macroDef: Symbol, macroImpl: Symbol): Type = { + def computeMacroDefTypeFromMacroImpl(macroDdef: DefDef, macroImpl: Symbol): Type = { // downgrade from metalevel-0 to metalevel-1 var runtimeType = macroImpl.tpe.finalResultType.dealias match { case TypeRef(_, ExprClass, runtimeType :: Nil) => runtimeType @@ -620,7 +447,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { val paramPos = tparams indexOf sym.deSkolemize val sym1 = if (paramPos == -1) sym - else loadMacroImplBinding(macroDef).targs(paramPos).tpe.typeSymbol + else loadMacroImplBinding(macroDdef.symbol).targs(paramPos).tpe.typeSymbol TypeRef(pre, sym1, args) case tpe => tpe @@ -630,13 +457,13 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { // undergo a special transformation, sigma, that adapts them to the different metalevel macroimpl lives in // as a result, we need to reverse this transformation when inferring macrodef ret from macroimpl ret def unsigma(tpe: Type): Type = { - // unfortunately, we cannot dereference ``paramss'', because we're in the middle of inferring a type for ``macroDef'' -// val defParamss = macroDef.paramss + // unfortunately, we cannot dereference ``paramss'', because we're in the middle of inferring a type for ``macroDdef'' +// val defParamss = macroDdef.symbol.paramss val defParamss = mmap(macroDdef.vparamss)(_.symbol) var implParamss = macroImpl.paramss implParamss = transformTypeTagEvidenceParams(implParamss, (param, tparam) => NoSymbol) - val implCtxParam = if (implParamss.length > 0 && implParamss(0).length > 0) implParamss(0)(0) else null + val implCtxParam = if (implParamss.nonEmpty && implParamss(0).nonEmpty) implParamss(0)(0) else null def implParamToDefParam(implParam: Symbol): Symbol = { val indices = (((implParamss drop 1).zipWithIndex) map { case (implParams, index) => (index, implParams indexOf implParam) } filter (_._2 != -1)).headOption val defParam = indices flatMap { @@ -653,7 +480,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { case TypeRef(pre, sym, args) => val pre1 = pre match { case SingleType(SingleType(SingleType(NoPrefix, param), prefix), value) if param == implCtxParam && prefix == MacroContextPrefix && value == ExprValue => - ThisType(macroDef.owner) + ThisType(macroDdef.symbol.owner) case SingleType(SingleType(NoPrefix, param), value) if implParamToDefParam(param) != null && value == ExprValue => val macroDefParam = implParamToDefParam(param) SingleType(NoPrefix, macroDefParam) @@ -669,9 +496,8 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { new UnsigmaTypeMap() apply tpe } - runtimeType = unsigma(runtimeType) - runtimeType + unsigma(runtimeType) } /** Macro classloader that is used to resolve and run macro implementations. @@ -1145,7 +971,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { try { // [Eugene] is there a better way? // [Paul] See Exceptional.scala and Origins.scala. - val relevancyThreshold = realex.getStackTrace().indexWhere(este => este.getMethodName == "macroExpand1") + val relevancyThreshold = realex.getStackTrace().indexWhere(_.getMethodName endsWith "macroExpand1") if (relevancyThreshold == -1) None else { var relevantElements = realex.getStackTrace().take(relevancyThreshold + 1) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 9b07eed5d7..645fe96375 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -5454,7 +5454,7 @@ trait Typers extends Modes with Adaptations with Tags { val isMacroBodyOkay = !tree.symbol.isErroneous && !(tree1 exists (_.isErroneous)) val shouldInheritMacroImplReturnType = ddef.tpt.isEmpty - if (isMacroBodyOkay && shouldInheritMacroImplReturnType) computeMacroDefTypeFromMacroImpl(ddef, tree.symbol, tree1.symbol) else AnyClass.tpe + if (isMacroBodyOkay && shouldInheritMacroImplReturnType) computeMacroDefTypeFromMacroImpl(ddef, tree1.symbol) else AnyClass.tpe } def transformedOr(tree: Tree, op: => Tree): Tree = transformed.get(tree) match { diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index fcbe7d0ed9..5ffb6504a5 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -381,6 +381,7 @@ trait Definitions extends api.StandardDefinitions { def isScalaRepeatedParamType(tp: Type) = tp.typeSymbol == RepeatedParamClass def isJavaRepeatedParamType(tp: Type) = tp.typeSymbol == JavaRepeatedParamClass def isRepeatedParamType(tp: Type) = isScalaRepeatedParamType(tp) || isJavaRepeatedParamType(tp) + def isRepeated(param: Symbol) = param.tpe.typeSymbol == RepeatedParamClass def isCastSymbol(sym: Symbol) = sym == Any_asInstanceOf || sym == Object_asInstanceOf def isJavaVarArgsMethod(m: Symbol) = m.isMethod && isJavaVarArgs(m.info.params) diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 19f264f60e..521d7072dc 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -17,7 +17,7 @@ abstract class TreeInfo { val global: SymbolTable import global._ - import definitions.{ isVarArgsList, isCastSymbol, ThrowableClass, TupleClass } + import definitions.{ isVarArgsList, isCastSymbol, ThrowableClass, TupleClass, MacroContextClass, MacroContextPrefixType } /* Does not seem to be used. Not sure what it does anyway. def isOwnerDefinition(tree: Tree): Boolean = tree match { @@ -591,4 +591,20 @@ abstract class TreeInfo { object DynamicUpdate extends DynamicApplicationExtractor(_ == nme.updateDynamic) object DynamicApplication extends DynamicApplicationExtractor(isApplyDynamicName) object DynamicApplicationNamed extends DynamicApplicationExtractor(_ == nme.applyDynamicNamed) + + object MacroImplReference { + def unapply(tree: Tree): Option[(Symbol, Symbol, List[Tree])] = + tree match { + case TypeApply(fun, targs) => unapply(fun) map { case (owner, sym, _) => (owner, sym, targs) } + case Select(pre, _) => Some(pre.symbol, tree.symbol, Nil) + case Ident(_) => Some(NoSymbol, tree.symbol, Nil) + case _ => None + } + } + + def stripOffPrefixTypeRefinement(tpe: Type): Type = + tpe.dealias match { + case RefinedType(List(tpe), Scope(sym)) if tpe == MacroContextClass.tpe && sym.allOverriddenSymbols.contains(MacroContextPrefixType) => tpe + case _ => tpe + } } diff --git a/test/files/neg/macro-invalidshape-a.check b/test/files/neg/macro-invalidshape-a.check index 246b5c3226..098ec35a00 100644 --- a/test/files/neg/macro-invalidshape-a.check +++ b/test/files/neg/macro-invalidshape-a.check @@ -1,6 +1,5 @@ Macros_Test_2.scala:2: error: macro body has wrong shape: - required: macro . - or : macro + required: macro [].[[]] def foo(x: Any) = macro 2 ^ one error found diff --git a/test/files/neg/macro-invalidshape-b.check b/test/files/neg/macro-invalidshape-b.check index 59701d023b..297ff69199 100644 --- a/test/files/neg/macro-invalidshape-b.check +++ b/test/files/neg/macro-invalidshape-b.check @@ -1,6 +1,5 @@ Macros_Test_2.scala:2: error: macro body has wrong shape: - required: macro . - or : macro + required: macro [].[[]] def foo(x: Any) = macro Impls.foo(null)(null) ^ one error found diff --git a/test/files/neg/macro-invalidshape-c.check b/test/files/neg/macro-invalidshape-c.check index 84d8c35222..6513df166e 100644 --- a/test/files/neg/macro-invalidshape-c.check +++ b/test/files/neg/macro-invalidshape-c.check @@ -1,6 +1,9 @@ -Macros_Test_2.scala:2: error: macro body has wrong shape: - required: macro . - or : macro +Macros_Test_2.scala:2: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses def foo(x: Any) = macro {2; Impls.foo} - ^ + ^ +Macros_Test_2.scala:2: error: missing arguments for method foo in object Impls; +follow this method with `_' if you want to treat it as a partially applied function + def foo(x: Any) = macro {2; Impls.foo} + ^ +one warning found one error found diff --git a/test/files/neg/macro-invalidsig-params-namemismatch.check b/test/files/neg/macro-invalidsig-params-namemismatch.check index f2639d9350..00d781a2ac 100644 --- a/test/files/neg/macro-invalidsig-params-namemismatch.check +++ b/test/files/neg/macro-invalidsig-params-namemismatch.check @@ -2,7 +2,6 @@ Impls_Macros_1.scala:8: error: macro implementation has wrong shape: required: (c: scala.reflect.macros.Context)(x: c.Expr[Int], y: c.Expr[Int]): c.Expr[Any] found : (c: scala.reflect.macros.Context)(y: c.Expr[Int], x: c.Expr[Int]): Nothing parameter names differ: x != y -parameter names differ: y != x def foo(x: Int, y: Int) = macro Impls.foo ^ one error found -- cgit v1.2.3 From ddf27a1e0e4b9eae521651704e74298c33c9af6c Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 17 Aug 2012 11:50:01 +0200 Subject: more cleanup for typedMacroBody --- .../tools/nsc/typechecker/ContextErrors.scala | 209 +++++++++----------- .../scala/tools/nsc/typechecker/Macros.scala | 214 +++++++++------------ .../scala/reflect/internal/Definitions.scala | 2 +- src/reflect/scala/reflect/internal/TreeInfo.scala | 17 +- .../neg/macro-invalidsig-context-bounds.check | 11 +- .../neg/macro-invalidsig-implicit-params.check | 11 +- .../neg/macro-invalidsig-tparams-badtype.check | 2 +- .../neg/macro-invalidsig-tparams-notparams-a.check | 2 +- .../neg/macro-invalidsig-tparams-notparams-b.check | 2 +- test/files/run/macro-def-path-dependent-d.check | 1 - test/files/run/macro-def-path-dependent-d.flags | 1 - .../Impls_Macros_1.scala | 9 - .../run/macro-def-path-dependent-d/Test_2.scala | 3 - test/files/run/macro-def-path-dependent-d1.check | 1 + test/files/run/macro-def-path-dependent-d1.flags | 1 + .../Impls_Macros_1.scala | 9 + .../run/macro-def-path-dependent-d1/Test_2.scala | 3 + test/files/run/macro-def-path-dependent-d2.check | 1 + test/files/run/macro-def-path-dependent-d2.flags | 1 + .../run/macro-def-path-dependent-d2/Impls_1.scala | 7 + .../run/macro-def-path-dependent-d2/Macros_2.scala | 7 + .../run/macro-def-path-dependent-d2/Test_3.scala | 3 + 22 files changed, 247 insertions(+), 270 deletions(-) delete mode 100644 test/files/run/macro-def-path-dependent-d.check delete mode 100644 test/files/run/macro-def-path-dependent-d.flags delete mode 100644 test/files/run/macro-def-path-dependent-d/Impls_Macros_1.scala delete mode 100644 test/files/run/macro-def-path-dependent-d/Test_2.scala create mode 100644 test/files/run/macro-def-path-dependent-d1.check create mode 100644 test/files/run/macro-def-path-dependent-d1.flags create mode 100644 test/files/run/macro-def-path-dependent-d1/Impls_Macros_1.scala create mode 100644 test/files/run/macro-def-path-dependent-d1/Test_2.scala create mode 100644 test/files/run/macro-def-path-dependent-d2.check create mode 100644 test/files/run/macro-def-path-dependent-d2.flags create mode 100644 test/files/run/macro-def-path-dependent-d2/Impls_1.scala create mode 100644 test/files/run/macro-def-path-dependent-d2/Macros_2.scala create mode 100644 test/files/run/macro-def-path-dependent-d2/Test_3.scala (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index f6785b6541..5a110739cd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -16,6 +16,7 @@ trait ContextErrors { import global._ import definitions._ + import treeInfo._ object ErrorKinds extends Enumeration { type ErrorKind = Value @@ -429,8 +430,11 @@ trait ContextErrors { def AbstractionFromVolatileTypeError(vd: ValDef) = issueNormalTypeError(vd, "illegal abstraction from value with volatile type "+vd.symbol.tpe) + private[ContextErrors] def TypedApplyWrongNumberOfTpeParametersErrorMessage(fun: Tree) = + "wrong number of type parameters for "+treeSymTypeMsg(fun) + def TypedApplyWrongNumberOfTpeParametersError(tree: Tree, fun: Tree) = { - issueNormalTypeError(tree, "wrong number of type parameters for "+treeSymTypeMsg(fun)) + issueNormalTypeError(tree, TypedApplyWrongNumberOfTpeParametersErrorMessage(fun)) setError(tree) } @@ -755,21 +759,24 @@ trait ContextErrors { kindErrors.toList.mkString("\n", ", ", "")) } - def NotWithinBounds(tree: Tree, prefix: String, targs: List[Type], - tparams: List[Symbol], kindErrors: List[String]) = { - if (settings.explaintypes.value) { + private[ContextErrors] def NotWithinBoundsErrorMessage(prefix: String, targs: List[Type], tparams: List[Symbol], explaintypes: Boolean) = { + if (explaintypes) { val bounds = tparams map (tp => tp.info.instantiateTypeParams(tparams, targs).bounds) (targs, bounds).zipped foreach ((targ, bound) => explainTypes(bound.lo, targ)) (targs, bounds).zipped foreach ((targ, bound) => explainTypes(targ, bound.hi)) () } - issueNormalTypeError(tree, - prefix + "type arguments " + targs.mkString("[", ",", "]") + - " do not conform to " + tparams.head.owner + "'s type parameter bounds " + - (tparams map (_.defString)).mkString("[", ",", "]")) + prefix + "type arguments " + targs.mkString("[", ",", "]") + + " do not conform to " + tparams.head.owner + "'s type parameter bounds " + + (tparams map (_.defString)).mkString("[", ",", "]") } + def NotWithinBounds(tree: Tree, prefix: String, targs: List[Type], + tparams: List[Symbol], kindErrors: List[String]) = + issueNormalTypeError(tree, + NotWithinBoundsErrorMessage(prefix, targs, tparams, settings.explaintypes.value)) + //substExpr def PolymorphicExpressionInstantiationError(tree: Tree, undetparams: List[Symbol], pt: Type) = issueNormalTypeError(tree, @@ -1093,144 +1100,115 @@ trait ContextErrors { // using an exception here is actually a good idea // because the lifespan of this exception is extremely small and controlled // moreover exceptions let us avoid an avalanche of "if (!hasError) do stuff" checks - case class MacroBodyTypecheckException() extends Exception + case object MacroBodyTypecheckException extends Exception with scala.util.control.ControlThrowable trait MacroErrors { self: MacroTyper => - implicit val context = typer.context + private implicit val context0 = typer.context + val context = typer.context + + // 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 = List("AbsTypeTag", "Expr").foldLeft(s)((res, x) => res.replace("c.universe." + x, "c." + x)) - def fail() = { + private def showMeth(pss: List[List[Symbol]], restpe: Type, abbreviate: Boolean) = { + var argsPart = (pss map (ps => ps map (_.defString) mkString ("(", ", ", ")"))).mkString + if (abbreviate) argsPart = abbreviateCoreAliases(argsPart) + var retPart = restpe.toString + if (abbreviate || macroDdef.tpt.tpe == null) retPart = abbreviateCoreAliases(retPart) + argsPart + ": " + retPart + } + + // not exactly an error generator, but very related + // and I dearly wanted to push it away from Macros.scala + private def checkSubType(slot: String, rtpe: Type, atpe: Type) = { + val ok = if (macroDebugVerbose || settings.explaintypes.value) { + if (rtpe eq atpe) println(rtpe + " <: " + atpe + "?" + EOL + "true") + withTypesExplained(rtpe <:< atpe) + } else rtpe <:< atpe + if (!ok) { + compatibilityError("type mismatch for %s: %s does not conform to %s".format(slot, abbreviateCoreAliases(rtpe.toString), abbreviateCoreAliases(atpe.toString))) + } + } + + // errors + + private def fail() = { // need to set the IS_ERROR flag to prohibit spurious expansions if (macroDef != null) macroDef setFlag IS_ERROR // not setting ErrorSymbol as in `infer.setError`, because we still need to know that it's a macro // otherwise assignTypeToTree in Namers might fail if macroDdef.tpt == EmptyTree macroDdef setType ErrorType - throw MacroBodyTypecheckException() + throw MacroBodyTypecheckException } - def MacroDefIsHardwired() = { - macroLogVerbose("typecheck terminated unexpectedly: macro is hardwired") - assert(!macroDdef.tpt.isEmpty, "hardwired macros must provide result type") - throw MacroBodyTypecheckException() + private def genericError(tree: Tree, message: String) = { + issueNormalTypeError(tree, message) + fail() } - def MacroFeatureNotEnabled() = { - macroLogVerbose("typecheck terminated unexpectedly: language.experimental.macros feature is not enabled") - macroDef setFlag IS_ERROR - throw MacroBodyTypecheckException() - } + private def implRefError(message: String) = genericError(methPart(macroDdef.rhs), message) - def MacroDefUntypeableBodyError() = { - // do nothing, just fail - // relevant typecheck errors have already been reported - fail() - } + private def compatibilityError(message: String) = + implRefError( + "macro implementation has wrong shape:"+ + "\n required: " + showMeth(rparamss, rret, abbreviate = true) + + "\n found : " + showMeth(aparamss, aret, abbreviate = false) + + "\n" + message) - def MacroDefInvalidBodyError() = { - issueNormalTypeError(macroDdef, - "macro body has wrong shape:" + - "\n required: macro [].[[]]") - fail() - } + // Phase I: sanity checks - def MacroImplNotPublicError() = { - issueNormalTypeError(macroDdef.rhs, "macro implementation must be public") - fail() + def MacroDefIsFastTrack() = { + macroLogVerbose("typecheck terminated unexpectedly: macro is fast track") + assert(!macroDdef.tpt.isEmpty, "fast track macros must provide result type") + throw MacroBodyTypecheckException // don't call fail, because we don't need IS_ERROR } - def MacroImplOverloadedError() = { - issueNormalTypeError(macroDdef.rhs, "macro implementation cannot be overloaded") + def MacroFeatureNotEnabled() = { + macroLogVerbose("typecheck terminated unexpectedly: language.experimental.macros feature is not enabled") fail() } - def MacroImplNeedsTypeArgumentsError() = { - issueNormalTypeError(macroDdef.rhs, "macro implementation reference needs type arguments") - fail() - } + // Phase II: typecheck the right-hand side of the macro def - def MacroImplDoesntNeedTypeArgumentsError() = { - issueNormalTypeError(macroDdef.rhs, "macro implementation reference doesn't need type arguments") - fail() - } + // do nothing, just fail. relevant typecheck errors have already been reported + def MacroDefUntypeableBodyError() = fail() - def MacroImplNotStaticError() = { - issueNormalTypeError(macroDdef.rhs, "macro implementation must be in statically accessible object") - fail() - } + def MacroDefInvalidBodyError() = genericError(macroDdef, "macro body has wrong shape:\n required: macro [].[[]]") - // prohibit implicit params on macro implementations - // we don't have to do this, but it appears to be more clear than allowing them - def MacroImplNonTagImplicitParameters(params: List[Symbol]) = { - issueSymbolTypeError(params.head, "macro implementations cannot have implicit parameters other than AbsTypeTag evidences") - fail() - } + def MacroImplNotPublicError() = implRefError("macro implementation must be public") - private def abbreviateCoreAliases(s: String): String = { - var result = s - result = result.replace("c.universe.AbsTypeTag", "c.AbsTypeTag") - result = result.replace("c.universe.Expr", "c.Expr") - result - } + def MacroImplOverloadedError() = implRefError("macro implementation cannot be overloaded") - private def showMeth(pss: List[List[Symbol]], restpe: Type, abbreviate: Boolean) = { - var argsPart = (pss map (ps => ps map (_.defString) mkString ("(", ", ", ")"))).mkString - if (abbreviate) argsPart = abbreviateCoreAliases(argsPart) - var retPart = restpe.toString - if (abbreviate || macroDdef.tpt.tpe == null) retPart = abbreviateCoreAliases(retPart) - argsPart + ": " + retPart - } + def MacroImplWrongNumberOfTypeArgumentsError(macroImplRef: Tree) = implRefError(typer.TyperErrorGen.TypedApplyWrongNumberOfTpeParametersErrorMessage(macroImplRef)) - private def compatibilityError(message: String) = { - issueNormalTypeError(macroDdef.rhs, - "macro implementation has wrong shape:"+ - "\n required: " + showMeth(rparamss, rret, abbreviate = true) + - "\n found : " + showMeth(aparamss, aret, abbreviate = false) + - "\n" + message) - fail() - } + def MacroImplNotStaticError() = implRefError("macro implementation must be in statically accessible object") - def MacroImplParamssMismatchError() = { - compatibilityError("number of parameter sections differ") - } + // Phase III: check compatibility between the macro def and its macro impl + // aXXX (e.g. aparams) => characteristics of the macro impl ("a" stands for "actual") + // rXXX (e.g. rparams) => characteristics of a reference macro impl signature synthesized from the macro def ("r" stands for "reference") - private def lengthMsg(which: String, extra: Symbol) = { - "parameter lists have different length, " + which + " extra parameter " + extra.defString - } + def MacroImplNonTagImplicitParameters(params: List[Symbol]) = compatibilityError("macro implementations cannot have implicit parameters other than AbsTypeTag evidences") - def MacroImplExtraParamsError(aparams: List[Symbol], rparams: List[Symbol]) = { - compatibilityError(lengthMsg("found", aparams(rparams.length))) - } + def MacroImplParamssMismatchError() = compatibilityError("number of parameter sections differ") - def MacroImplMissingParamsError(aparams: List[Symbol], rparams: List[Symbol]) = { - compatibilityError(abbreviateCoreAliases(lengthMsg("required", rparams(aparams.length)))) - } + def MacroImplExtraParamsError(aparams: List[Symbol], rparams: List[Symbol]) = compatibilityError(lengthMsg("value", "found", aparams(rparams.length))) - // not exactly an error generator, but very related - // and I dearly wanted to push it away from Macros.scala - def checkSubType(slot: String, rtpe: Type, atpe: Type) = { - val ok = if (macroDebugVerbose) { - if (rtpe eq atpe) println(rtpe + " <: " + atpe + "?" + EOL + "true") - withTypesExplained(rtpe <:< atpe) - } else rtpe <:< atpe - if (!ok) { - compatibilityError("type mismatch for %s: %s does not conform to %s".format(slot, abbreviateCoreAliases(rtpe.toString), abbreviateCoreAliases(atpe.toString))) - } - } + def MacroImplMissingParamsError(aparams: List[Symbol], rparams: List[Symbol]) = compatibilityError(abbreviateCoreAliases(lengthMsg("value", "required", rparams(aparams.length)))) - def checkMacroImplParamTypeMismatch(atpe: Type, rparam: Symbol) = { - checkSubType("parameter " + rparam.name, rparam.tpe, atpe) - } + def checkMacroImplParamTypeMismatch(atpe: Type, rparam: Symbol) = checkSubType("parameter " + rparam.name, rparam.tpe, atpe) - def checkMacroImplResultTypeMismatch(atpe: Type, rret: Type) = { - checkSubType("return type", atpe, rret) - } + def checkMacroImplResultTypeMismatch(atpe: Type, rret: Type) = checkSubType("return type", atpe, rret) - def MacroImplParamNameMismatchError(aparam: Symbol, rparam: Symbol) = { - // in the error message rparamss come first - // hence rparam should also come first if possible - compatibilityError("parameter names differ: " + rparam.name + " != " + aparam.name) - } + def MacroImplParamNameMismatchError(aparam: Symbol, rparam: Symbol) = compatibilityError("parameter names differ: " + rparam.name + " != " + aparam.name) def MacroImplVarargMismatchError(aparam: Symbol, rparam: Symbol) = { if (isRepeated(rparam) && !isRepeated(aparam)) @@ -1239,17 +1217,12 @@ trait ContextErrors { compatibilityError("types incompatible for parameter " + aparam.name + ": corresponding is not a vararg parameter") } - def MacroImplTargMismatchError(atargs: List[Type], atparams: List[Symbol]) = { - val bounds = atparams map (tp => tp.info.instantiateTypeParams(atparams, atargs).bounds) - compatibilityError("type arguments " + atargs.mkString("[", ",", "]") + - " do not conform to " + atparams.head.owner + "'s type parameter bounds " + - (atparams map (_.defString)).mkString("[", ",", "]")) - } + def MacroImplTargMismatchError(atargs: List[Type], atparams: List[Symbol]) = + compatibilityError(typer.infer.InferErrorGen.NotWithinBoundsErrorMessage("", atargs, atparams, macroDebugVerbose || settings.explaintypes.value)) - def MacroImplTparamInstantiationError(atparams: List[Symbol], ex: NoInstance) = { + def MacroImplTparamInstantiationError(atparams: List[Symbol], ex: NoInstance) = compatibilityError( "type parameters "+(atparams map (_.defString) mkString ", ")+" cannot be instantiated\n"+ ex.getMessage) - } } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 2c8af627d0..1b75d822d4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -24,7 +24,7 @@ import scala.reflect.internal.util.Collections._ * * Then fooBar needs to point to a static method of the following form: * - * def fooBar[T: c.AbsTypeTag] + * def fooBar[T: c.AbsTypeTag] // type tag annotation is optional * (c: scala.reflect.macros.Context) * (xs: c.Expr[List[T]]) * : c.Expr[T] = { @@ -213,11 +213,86 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { MacroImplBinding.unpickle(pickle) } + /** Transforms parameters lists of a macro impl. + * The `transform` function is invoked only for AbsTypeTag evidence parameters. + * + * The transformer takes two arguments: a value parameter from the parameter list + * and a type parameter that is witnesses by the value parameter. + * + * If the transformer returns a NoSymbol, the value parameter is not included from the result. + * If the transformer returns something else, this something else is included in the result instead of the value parameter. + * + * Despite of being highly esoteric, this function significantly simplifies signature analysis. + * For example, it can be used to strip macroImpl.paramss from the evidences (necessary when checking def <-> impl correspondence) + * or to streamline creation of the list of macro arguments. + */ + private def transformTypeTagEvidenceParams(paramss: List[List[Symbol]], transform: (Symbol, Symbol) => Symbol): List[List[Symbol]] = { + if (paramss.isEmpty || paramss.last.isEmpty) return paramss // no implicit parameters in the signature => nothing to do + if (paramss.head.isEmpty || !(paramss.head.head.tpe <:< MacroContextClass.tpe)) return paramss // no context parameter in the signature => nothing to do + def transformTag(param: Symbol): Symbol = param.tpe.dealias match { + case TypeRef(SingleType(SingleType(NoPrefix, c), universe), AbsTypeTagClass, targ :: Nil) + if c == paramss.head.head && universe == MacroContextUniverse => + transform(param, targ.typeSymbol) + case _ => + param + } + val transformed = paramss.last map transformTag filter (_ ne NoSymbol) + if (transformed.isEmpty) paramss.init else paramss.init :+ transformed + } + + def computeMacroDefTypeFromMacroImpl(macroDdef: DefDef, macroImpl: Symbol): Type = { + // Step I. Transform c.Expr[T] to T + var runtimeType = macroImpl.tpe.finalResultType.dealias match { + case TypeRef(_, ExprClass, runtimeType :: Nil) => runtimeType + case _ => AnyTpe // so that macro impls with rhs = ??? don't screw up our inference + } + + // Step II. Transform type parameters of a macro implementation into type arguments in a macro definition's body + runtimeType = runtimeType.substituteTypes(macroImpl.typeParams, loadMacroImplBinding(macroDdef.symbol).targs.map(_.tpe)) + + // Step III. Transform c.prefix.value.XXX to this.XXX and implParam.value.YYY to defParam.YYY + def unsigma(tpe: Type): Type = + transformTypeTagEvidenceParams(macroImpl.paramss, (param, tparam) => NoSymbol) match { + case (implCtxParam :: Nil) :: implParamss => + val implToDef = flatMap2(implParamss, macroDdef.vparamss)(map2(_, _)((_, _))).toMap + object UnsigmaTypeMap extends TypeMap { + def apply(tp: Type): Type = tp match { + case TypeRef(pre, sym, args) => + val pre1 = pre match { + case SingleType(SingleType(SingleType(NoPrefix, c), prefix), value) if c == implCtxParam && prefix == MacroContextPrefix && value == ExprValue => + ThisType(macroDdef.symbol.owner) + case SingleType(SingleType(NoPrefix, implParam), value) if value == ExprValue => + implToDef get implParam map (defParam => SingleType(NoPrefix, defParam.symbol)) getOrElse pre + case _ => + pre + } + val args1 = args map mapOver + TypeRef(pre1, sym, args1) + case _ => + mapOver(tp) + } + } + + UnsigmaTypeMap(tpe) + case _ => + tpe + } + + unsigma(runtimeType) + } + /** A reference macro implementation signature compatible with a given macro definition. * - * In the example above: + * In the example above for the following macro def: + * def foo[T](xs: List[T]): T = macro fooBar + * + * This function will return: * (c: scala.reflect.macros.Context)(xs: c.Expr[List[T]]): c.Expr[T] * + * Note that type tag evidence parameters are not included into the result. + * Type tag context bounds for macro impl tparams are optional. + * Therefore compatibility checks ignore such parameters, and we don't need to bother about them here. + * * @param macroDef The macro definition symbol * @param tparams The type parameters of the macro definition * @param vparamss The value parameters of the macro definition @@ -283,53 +358,22 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { macroTraceVerbose("macroImplSig is: ")(paramss, implRetTpe) } - /** Transforms parameters lists of a macro impl. - * The `transform` function is invoked only for AbsTypeTag evidence parameters. - * - * The transformer takes two arguments: a value parameter from the parameter list - * and a type parameter that is witnesses by the value parameter. - * - * If the transformer returns a NoSymbol, the value parameter is not included from the result. - * If the transformer returns something else, this something else is included in the result instead of the value parameter. - * - * Despite of being highly esoteric, this function significantly simplifies signature analysis. - * For example, it can be used to strip macroImpl.paramss from the evidences (necessary when checking def <-> impl correspondence) - * or to streamline creation of the list of macro arguments. - */ - private def transformTypeTagEvidenceParams(paramss: List[List[Symbol]], transform: (Symbol, Symbol) => Symbol): List[List[Symbol]] = { - if (paramss.isEmpty || paramss.last.isEmpty) return paramss // no implicit parameters in the signature => nothing to do - if (paramss.head.isEmpty || !(paramss.head.head.tpe <:< MacroContextClass.tpe)) return paramss // no context parameter in the signature => nothing to do - def transformTag(param: Symbol): Symbol = param.tpe.dealias match { - case TypeRef(SingleType(SingleType(NoPrefix, c), universe), AbsTypeTagClass, targ :: Nil) - if c == paramss.head.head && universe == MacroContextUniverse => - transform(param, targ.typeSymbol) - case _ => - param - } - val transformed = paramss.last map transformTag filter (_ ne NoSymbol) - if (transformed.isEmpty) paramss.init else paramss.init :+ transformed - } - - /** As specified above, body of a macro definition must reference its implementation. - * This function verifies that the body indeed refers to a method, and that - * the referenced macro implementation is compatible with the given macro definition. - * - * This means that macro implementation (fooBar in example above) must: - * 1) Refer to a statically accessible, non-overloaded method. - * 2) Have the right parameter lists as outlined in the SIP / in the doc comment of this class. + /** Verifies that the body of a macro def typechecks to a reference to a static public non-overloaded method, + * and that that method is signature-wise compatible with the given macro definition. * - * @return typechecked rhs of the given macro definition + * @return Typechecked rhs of the given macro definition if everything is okay. + * EmptyTree if an error occurs. */ def typedMacroBody(typer: Typer, macroDdef: DefDef): Tree = try new MacroTyper(typer, macroDdef).typed - catch { case MacroBodyTypecheckException() => EmptyTree } + catch { case MacroBodyTypecheckException => EmptyTree } class MacroTyper(val typer: Typer, val macroDdef: DefDef) extends MacroErrors { // Phase I: sanity checks val macroDef = macroDdef.symbol macroLogVerbose("typechecking macro def %s at %s".format(macroDef, macroDdef.pos)) assert(macroDef.isTermMacro, macroDdef) - if (fastTrack contains macroDef) MacroDefIsHardwired() + if (fastTrack contains macroDef) MacroDefIsFastTrack() if (!typer.checkFeature(macroDdef.pos, MacrosFeature, immediate = true)) MacroFeatureNotEnabled() // we use typed1 instead of typed, because otherwise adapt is going to mess us up @@ -377,15 +421,15 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { if (!meth.isMethod) MacroDefInvalidBodyError() if (!meth.isPublic) MacroImplNotPublicError() if (meth.isOverloaded) MacroImplOverloadedError() - if (meth.typeParams.nonEmpty && targs.isEmpty) MacroImplNeedsTypeArgumentsError() - if (meth.typeParams.isEmpty && targs.nonEmpty) MacroImplDoesntNeedTypeArgumentsError() if (!owner.isStaticOwner && !owner.moduleClass.isStaticOwner) MacroImplNotStaticError() + if (meth.typeParams.length != targs.length) MacroImplWrongNumberOfTypeArgumentsError(typed) bindMacroImpl(macroDef, typed) case _ => MacroDefInvalidBodyError() } // Phase III: check compatibility between the macro def and its macro impl + // this check ignores type tag evidence parameters, because type tag context bounds are optional // aXXX (e.g. aparamss) => characteristics of the macro impl ("a" stands for "actual") // rXXX (e.g. rparamss) => characteristics of a reference macro impl signature synthesized from the macro def ("r" stands for "reference") val macroImpl = typed.symbol @@ -432,74 +476,6 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { } } - def computeMacroDefTypeFromMacroImpl(macroDdef: DefDef, macroImpl: Symbol): Type = { - // downgrade from metalevel-0 to metalevel-1 - var runtimeType = macroImpl.tpe.finalResultType.dealias match { - case TypeRef(_, ExprClass, runtimeType :: Nil) => runtimeType - case _ => AnyTpe - } - - // transform type parameters of a macro implementation into type parameters of a macro definition - runtimeType = runtimeType map { - case TypeRef(pre, sym, args) => - // sym.paramPos is unreliable (see an example in `macroArgs`) - val tparams = macroImpl.typeParams map (_.deSkolemize) - val paramPos = tparams indexOf sym.deSkolemize - val sym1 = - if (paramPos == -1) sym - else loadMacroImplBinding(macroDdef.symbol).targs(paramPos).tpe.typeSymbol - TypeRef(pre, sym1, args) - case tpe => - tpe - } - - // as stated in the spec, before being matched to macroimpl, type and value parameters of macrodef - // undergo a special transformation, sigma, that adapts them to the different metalevel macroimpl lives in - // as a result, we need to reverse this transformation when inferring macrodef ret from macroimpl ret - def unsigma(tpe: Type): Type = { - // unfortunately, we cannot dereference ``paramss'', because we're in the middle of inferring a type for ``macroDdef'' -// val defParamss = macroDdef.symbol.paramss - val defParamss = mmap(macroDdef.vparamss)(_.symbol) - var implParamss = macroImpl.paramss - implParamss = transformTypeTagEvidenceParams(implParamss, (param, tparam) => NoSymbol) - - val implCtxParam = if (implParamss.nonEmpty && implParamss(0).nonEmpty) implParamss(0)(0) else null - def implParamToDefParam(implParam: Symbol): Symbol = { - val indices = (((implParamss drop 1).zipWithIndex) map { case (implParams, index) => (index, implParams indexOf implParam) } filter (_._2 != -1)).headOption - val defParam = indices flatMap { - case (plistIndex, pIndex) => - if (defParamss.length <= plistIndex) None - else if (defParamss(plistIndex).length <= pIndex) None - else Some(defParamss(plistIndex)(pIndex)) - } - defParam.orNull - } - - class UnsigmaTypeMap extends TypeMap { - def apply(tp: Type): Type = tp match { - case TypeRef(pre, sym, args) => - val pre1 = pre match { - case SingleType(SingleType(SingleType(NoPrefix, param), prefix), value) if param == implCtxParam && prefix == MacroContextPrefix && value == ExprValue => - ThisType(macroDdef.symbol.owner) - case SingleType(SingleType(NoPrefix, param), value) if implParamToDefParam(param) != null && value == ExprValue => - val macroDefParam = implParamToDefParam(param) - SingleType(NoPrefix, macroDefParam) - case _ => - pre - } - val args1 = args map mapOver - TypeRef(pre1, sym, args1) - case _ => - mapOver(tp) - } - } - - new UnsigmaTypeMap() apply tpe - } - - unsigma(runtimeType) - } - /** Macro classloader that is used to resolve and run macro implementations. * Loads classes from from -cp (aka the library classpath). * Is also capable of detecting REPL and reusing its classloader. @@ -530,7 +506,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { * 4) Resolves macro implementation within the loaded companion. * * @return Requested runtime if macro implementation can be loaded successfully from either of the mirrors, - * null otherwise. + * `null` otherwise. */ type MacroRuntime = List[Any] => Any private val macroRuntimesCache = perRunCaches.newWeakMap[Symbol, MacroRuntime] @@ -585,9 +561,9 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { /** Calculate the arguments to pass to a macro implementation when expanding the provided tree. * * This includes inferring the exact type and instance of the macro context to pass, and also - * allowing for missing parameter sections in macro implementation (see ``macroImplParamsss'' for more info). + * allowing for missing parameter sections in macro implementation (see `macroImplParamsss` for more info). * - * @return list of runtime objects to pass to the implementation obtained by ``macroRuntime'' + * @return list of runtime objects to pass to the implementation obtained by `macroRuntime` */ private def macroArgs(typer: Typer, expandee: Tree): Option[List[Any]] = { val macroDef = expandee.symbol @@ -643,8 +619,8 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { // val outer2 = new outer1.C[String] // outer2.foo[Boolean] // - // then T and U need to be inferred from the lexical scope of the call using ``asSeenFrom'' - // whereas V won't be resolved by asSeenFrom and need to be loaded directly from ``expandee'' which needs to contain a TypeApply node + // then T and U need to be inferred from the lexical scope of the call using `asSeenFrom` + // whereas V won't be resolved by asSeenFrom and need to be loaded directly from `expandee` which needs to contain a TypeApply node // also, macro implementation reference may contain a regular type as a type argument, then we pass it verbatim val tags = binding.signature filter (_ != -1) map (paramPos => { val targ = binding.targs(paramPos).tpe.typeSymbol @@ -688,14 +664,14 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { } /** Keeps track of macros in-flight. - * See more informations in comments to ``openMacros'' in ``scala.reflect.macros.Context''. + * See more informations in comments to `openMacros` in `scala.reflect.macros.Context`. */ var openMacros = List[MacroContext]() def enclosingMacroPosition = openMacros map (_.macroApplication.pos) find (_ ne NoPosition) getOrElse NoPosition /** Performs macro expansion: - * 1) Checks whether the expansion needs to be delayed (see ``mustDelayMacroExpansion'') - * 2) Loads macro implementation using ``macroMirror'' + * 1) Checks whether the expansion needs to be delayed (see `mustDelayMacroExpansion`) + * 2) Loads macro implementation using `macroMirror` * 3) Synthesizes invocation arguments for the macro implementation * 4) Checks that the result is a tree bound to this universe * 5) Typechecks the result against the return type of the macro definition @@ -789,7 +765,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { Failure(expandee) } - /** Does the same as ``macroExpand'', but without typechecking the expansion + /** Does the same as `macroExpand`, but without typechecking the expansion * Meant for internal use within the macro infrastructure, don't use it elsewhere. */ private def macroExpand1(typer: Typer, expandee: Tree): MacroExpansionResult = @@ -1047,7 +1023,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { /** Performs macro expansion on all subtrees of a given tree. * Innermost macros are expanded first, outermost macros are expanded last. - * See the documentation for ``macroExpand'' for more information. + * See the documentation for `macroExpand` for more information. */ def macroExpandAll(typer: Typer, expandee: Tree): Tree = new Transformer { diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 5ffb6504a5..a80194c3dd 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -381,7 +381,7 @@ trait Definitions extends api.StandardDefinitions { def isScalaRepeatedParamType(tp: Type) = tp.typeSymbol == RepeatedParamClass def isJavaRepeatedParamType(tp: Type) = tp.typeSymbol == JavaRepeatedParamClass def isRepeatedParamType(tp: Type) = isScalaRepeatedParamType(tp) || isJavaRepeatedParamType(tp) - def isRepeated(param: Symbol) = param.tpe.typeSymbol == RepeatedParamClass + def isRepeated(param: Symbol) = isRepeatedParamType(param.tpe) def isCastSymbol(sym: Symbol) = sym == Any_asInstanceOf || sym == Object_asInstanceOf def isJavaVarArgsMethod(m: Symbol) = m.isMethod && isJavaVarArgs(m.info.params) diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 521d7072dc..39539a113c 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -593,13 +593,16 @@ abstract class TreeInfo { object DynamicApplicationNamed extends DynamicApplicationExtractor(_ == nme.applyDynamicNamed) object MacroImplReference { - def unapply(tree: Tree): Option[(Symbol, Symbol, List[Tree])] = - tree match { - case TypeApply(fun, targs) => unapply(fun) map { case (owner, sym, _) => (owner, sym, targs) } - case Select(pre, _) => Some(pre.symbol, tree.symbol, Nil) - case Ident(_) => Some(NoSymbol, tree.symbol, Nil) - case _ => None - } + private def refPart(tree: Tree): Tree = tree match { + case TypeApply(fun, _) => refPart(fun) + case ref: RefTree => ref + case _ => EmptyTree + } + + def unapply(tree: Tree) = refPart(tree) match { + case ref: RefTree => Some((ref.qualifier.symbol, ref.symbol, typeArguments(tree))) + case _ => None + } } def stripOffPrefixTypeRefinement(tpe: Type): Type = diff --git a/test/files/neg/macro-invalidsig-context-bounds.check b/test/files/neg/macro-invalidsig-context-bounds.check index 6c9482e537..5d42ebc515 100644 --- a/test/files/neg/macro-invalidsig-context-bounds.check +++ b/test/files/neg/macro-invalidsig-context-bounds.check @@ -1,4 +1,7 @@ -Impls_1.scala:5: error: macro implementations cannot have implicit parameters other than AbsTypeTag evidences - def foo[U: c.AbsTypeTag: Numeric](c: Ctx) = { - ^ -one error found +Macros_Test_1.scala:2: error: macro implementation has wrong shape: + required: (c: scala.reflect.macros.Context): c.Expr[Any] + found : (c: scala.reflect.macros.Context)(implicit evidence$2: Numeric[U]): c.universe.Literal +macro implementations cannot have implicit parameters other than AbsTypeTag evidences + def foo[U] = macro Impls.foo[U] + ^ +one error found diff --git a/test/files/neg/macro-invalidsig-implicit-params.check b/test/files/neg/macro-invalidsig-implicit-params.check index 98b3167b7a..62156770e4 100644 --- a/test/files/neg/macro-invalidsig-implicit-params.check +++ b/test/files/neg/macro-invalidsig-implicit-params.check @@ -1,4 +1,7 @@ -Impls_Macros_1.scala:5: error: macro implementations cannot have implicit parameters other than AbsTypeTag evidences - def foo_targs[T, U: c.AbsTypeTag](c: Ctx)(implicit x: c.Expr[Int]) = { - ^ -one error found +Impls_Macros_1.scala:18: error: macro implementation has wrong shape: + required: (c: scala.reflect.macros.Context)(x: c.Expr[Int]): c.Expr[Unit] + found : (c: scala.reflect.macros.Context)(implicit x: c.Expr[Int]): c.Expr[Unit] +macro implementations cannot have implicit parameters other than AbsTypeTag evidences + def foo_targs[U](x: Int) = macro Impls.foo_targs[T, U] + ^ +one error found diff --git a/test/files/neg/macro-invalidsig-tparams-badtype.check b/test/files/neg/macro-invalidsig-tparams-badtype.check index e5e8366ba4..20c58ff2bb 100644 --- a/test/files/neg/macro-invalidsig-tparams-badtype.check +++ b/test/files/neg/macro-invalidsig-tparams-badtype.check @@ -3,5 +3,5 @@ Macros_Test_2.scala:2: error: macro implementation has wrong shape: found : (c: scala.reflect.macros.Context)(U: c.universe.Type): Nothing number of parameter sections differ def foo[U] = macro Impls.foo[U] - ^ + ^ one error found diff --git a/test/files/neg/macro-invalidsig-tparams-notparams-a.check b/test/files/neg/macro-invalidsig-tparams-notparams-a.check index 5b4ef42ea5..5aee62b9e5 100644 --- a/test/files/neg/macro-invalidsig-tparams-notparams-a.check +++ b/test/files/neg/macro-invalidsig-tparams-notparams-a.check @@ -1,4 +1,4 @@ -Macros_Test_2.scala:2: error: macro implementation reference needs type arguments +Macros_Test_2.scala:2: error: wrong number of type parameters for method foo: [U](c: scala.reflect.macros.Context)(implicit evidence$1: c.AbsTypeTag[U])Nothing def foo = macro Impls.foo ^ one error found diff --git a/test/files/neg/macro-invalidsig-tparams-notparams-b.check b/test/files/neg/macro-invalidsig-tparams-notparams-b.check index 261e3b8293..e8de8a4c6b 100644 --- a/test/files/neg/macro-invalidsig-tparams-notparams-b.check +++ b/test/files/neg/macro-invalidsig-tparams-notparams-b.check @@ -1,4 +1,4 @@ -Macros_Test_2.scala:3: error: macro implementation reference needs type arguments +Macros_Test_2.scala:3: error: wrong number of type parameters for method foo: [T, U, V](c: scala.reflect.macros.Context)(implicit evidence$1: c.AbsTypeTag[T], implicit evidence$2: c.AbsTypeTag[U], implicit V: c.AbsTypeTag[V])c.Expr[Unit] def foo[V] = macro Impls.foo ^ one error found diff --git a/test/files/run/macro-def-path-dependent-d.check b/test/files/run/macro-def-path-dependent-d.check deleted file mode 100644 index 1ea14b4e20..0000000000 --- a/test/files/run/macro-def-path-dependent-d.check +++ /dev/null @@ -1 +0,0 @@ -it works diff --git a/test/files/run/macro-def-path-dependent-d.flags b/test/files/run/macro-def-path-dependent-d.flags deleted file mode 100644 index cd66464f2f..0000000000 --- a/test/files/run/macro-def-path-dependent-d.flags +++ /dev/null @@ -1 +0,0 @@ --language:experimental.macros \ No newline at end of file diff --git a/test/files/run/macro-def-path-dependent-d/Impls_Macros_1.scala b/test/files/run/macro-def-path-dependent-d/Impls_Macros_1.scala deleted file mode 100644 index 2daf6fc3fb..0000000000 --- a/test/files/run/macro-def-path-dependent-d/Impls_Macros_1.scala +++ /dev/null @@ -1,9 +0,0 @@ -import scala.reflect.runtime.universe._ -import scala.reflect.macros.Context -import scala.reflect.api.Universe - -object Test { - def materializeTypeTag[T](u: Universe)(e: T) = macro materializeTypeTag_impl[T] - - def materializeTypeTag_impl[T: c.AbsTypeTag](c: Context)(u: c.Expr[Universe])(e: c.Expr[T]): c.Expr[u.value.TypeTag[T]] = ??? -} \ No newline at end of file diff --git a/test/files/run/macro-def-path-dependent-d/Test_2.scala b/test/files/run/macro-def-path-dependent-d/Test_2.scala deleted file mode 100644 index 7dffc5107d..0000000000 --- a/test/files/run/macro-def-path-dependent-d/Test_2.scala +++ /dev/null @@ -1,3 +0,0 @@ -object Test extends App { - println("it works") -} \ No newline at end of file diff --git a/test/files/run/macro-def-path-dependent-d1.check b/test/files/run/macro-def-path-dependent-d1.check new file mode 100644 index 0000000000..1ea14b4e20 --- /dev/null +++ b/test/files/run/macro-def-path-dependent-d1.check @@ -0,0 +1 @@ +it works diff --git a/test/files/run/macro-def-path-dependent-d1.flags b/test/files/run/macro-def-path-dependent-d1.flags new file mode 100644 index 0000000000..cd66464f2f --- /dev/null +++ b/test/files/run/macro-def-path-dependent-d1.flags @@ -0,0 +1 @@ +-language:experimental.macros \ No newline at end of file diff --git a/test/files/run/macro-def-path-dependent-d1/Impls_Macros_1.scala b/test/files/run/macro-def-path-dependent-d1/Impls_Macros_1.scala new file mode 100644 index 0000000000..2daf6fc3fb --- /dev/null +++ b/test/files/run/macro-def-path-dependent-d1/Impls_Macros_1.scala @@ -0,0 +1,9 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.macros.Context +import scala.reflect.api.Universe + +object Test { + def materializeTypeTag[T](u: Universe)(e: T) = macro materializeTypeTag_impl[T] + + def materializeTypeTag_impl[T: c.AbsTypeTag](c: Context)(u: c.Expr[Universe])(e: c.Expr[T]): c.Expr[u.value.TypeTag[T]] = ??? +} \ No newline at end of file diff --git a/test/files/run/macro-def-path-dependent-d1/Test_2.scala b/test/files/run/macro-def-path-dependent-d1/Test_2.scala new file mode 100644 index 0000000000..7dffc5107d --- /dev/null +++ b/test/files/run/macro-def-path-dependent-d1/Test_2.scala @@ -0,0 +1,3 @@ +object Test extends App { + println("it works") +} \ No newline at end of file diff --git a/test/files/run/macro-def-path-dependent-d2.check b/test/files/run/macro-def-path-dependent-d2.check new file mode 100644 index 0000000000..1ea14b4e20 --- /dev/null +++ b/test/files/run/macro-def-path-dependent-d2.check @@ -0,0 +1 @@ +it works diff --git a/test/files/run/macro-def-path-dependent-d2.flags b/test/files/run/macro-def-path-dependent-d2.flags new file mode 100644 index 0000000000..cd66464f2f --- /dev/null +++ b/test/files/run/macro-def-path-dependent-d2.flags @@ -0,0 +1 @@ +-language:experimental.macros \ No newline at end of file diff --git a/test/files/run/macro-def-path-dependent-d2/Impls_1.scala b/test/files/run/macro-def-path-dependent-d2/Impls_1.scala new file mode 100644 index 0000000000..1cda64e43e --- /dev/null +++ b/test/files/run/macro-def-path-dependent-d2/Impls_1.scala @@ -0,0 +1,7 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.macros.Context +import scala.reflect.api.Universe + +object Impls { + def materializeTypeTag_impl[T: c.AbsTypeTag](c: Context)(u: c.Expr[Universe])(e: c.Expr[T]): c.Expr[u.value.TypeTag[T]] = ??? +} \ No newline at end of file diff --git a/test/files/run/macro-def-path-dependent-d2/Macros_2.scala b/test/files/run/macro-def-path-dependent-d2/Macros_2.scala new file mode 100644 index 0000000000..65ce4d8bd2 --- /dev/null +++ b/test/files/run/macro-def-path-dependent-d2/Macros_2.scala @@ -0,0 +1,7 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.macros.Context +import scala.reflect.api.Universe + +object Macros { + def materializeTypeTag[T](u: Universe)(e: T) = macro Impls.materializeTypeTag_impl[T] +} \ No newline at end of file diff --git a/test/files/run/macro-def-path-dependent-d2/Test_3.scala b/test/files/run/macro-def-path-dependent-d2/Test_3.scala new file mode 100644 index 0000000000..7dffc5107d --- /dev/null +++ b/test/files/run/macro-def-path-dependent-d2/Test_3.scala @@ -0,0 +1,3 @@ +object Test extends App { + println("it works") +} \ No newline at end of file -- cgit v1.2.3