From e40dbf206c4829edcb8505398d717df0ad2a25d0 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 9 Jan 2023 14:55:01 +0100 Subject: [PATCH 1/4] Fix unbound type variables after implicit search The issue was that an uninstantiated type variable escaped the implicit search and was then affected by the quote pattern match. Fixes #15779 Fixes #16636 --- .../quoted/runtime/impl/QuotesImpl.scala | 8 ++++- tests/pos-macros/i15779/Macro_1.scala | 30 +++++++++++++++++++ tests/pos-macros/i15779/Test_2.scala | 3 ++ tests/pos-macros/i16636/Macro_1.scala | 30 +++++++++++++++++++ tests/pos-macros/i16636/Test_2.scala | 9 ++++++ 5 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 tests/pos-macros/i15779/Macro_1.scala create mode 100644 tests/pos-macros/i15779/Test_2.scala create mode 100644 tests/pos-macros/i16636/Macro_1.scala create mode 100644 tests/pos-macros/i16636/Test_2.scala diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index b2e0eba36ebc..d2f4d154e85c 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -2404,7 +2404,13 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler object Implicits extends ImplicitsModule: def search(tpe: TypeRepr): ImplicitSearchResult = - ctx.typer.inferImplicitArg(tpe, Position.ofMacroExpansion.span) + import tpd.TreeOps + val implicitTree = ctx.typer.inferImplicitArg(tpe, Position.ofMacroExpansion.span) + // Make sure that we do not have any uninstantiated type variables. + // See tests/pos-macros/i16636. + // See tests/pos-macros/exprSummonWithTypeVar with -Xcheck-macros. + dotc.typer.Inferencing.fullyDefinedType(implicitTree.tpe, "", implicitTree) + implicitTree end Implicits type ImplicitSearchResult = Tree diff --git a/tests/pos-macros/i15779/Macro_1.scala b/tests/pos-macros/i15779/Macro_1.scala new file mode 100644 index 000000000000..8bb98ab31553 --- /dev/null +++ b/tests/pos-macros/i15779/Macro_1.scala @@ -0,0 +1,30 @@ +import scala.quoted._ +import scala.deriving.Mirror + +trait Encoder[-A] + +trait PrimitiveEncoder[A] extends Encoder[A] + +given intOpt: PrimitiveEncoder[Option[Int]] with {} + +given primitiveNotNull[T](using e: Encoder[Option[T]]): PrimitiveEncoder[T] = + new PrimitiveEncoder[T] {} + +transparent inline given fromMirror[A]: Any = ${ fromMirrorImpl[A] } + +def fromMirrorImpl[A : Type](using q: Quotes): Expr[Any] = + Expr.summon[Mirror.Of[A]].get match + case '{ ${mirror}: Mirror.ProductOf[A] { type MirroredElemTypes = elementTypes } } => + val encoder = Type.of[elementTypes] match + case '[tpe *: EmptyTuple] => + Expr.summon[Encoder[tpe]].get + + encoder match + case '{ ${encoder}: Encoder[tpe] } => // ok + case _ => ??? + + encoder match + case '{ ${encoder}: Encoder[tpe] } => // ok + case _ => ??? + + encoder diff --git a/tests/pos-macros/i15779/Test_2.scala b/tests/pos-macros/i15779/Test_2.scala new file mode 100644 index 000000000000..c7223d849a86 --- /dev/null +++ b/tests/pos-macros/i15779/Test_2.scala @@ -0,0 +1,3 @@ +case class JustInt(i: Int) + +val x = fromMirror[JustInt] diff --git a/tests/pos-macros/i16636/Macro_1.scala b/tests/pos-macros/i16636/Macro_1.scala new file mode 100644 index 000000000000..78a3f6ef7b9b --- /dev/null +++ b/tests/pos-macros/i16636/Macro_1.scala @@ -0,0 +1,30 @@ +import scala.quoted.* + +trait ReproTransformer[A, B] { + def transform(from: A): B +} + +object ReproTransformer { + final class Identity[A, B >: A] extends ReproTransformer[A, B] { + def transform(from: A): B = from + } + + given identity[A, B >: A]: Identity[A, B] = Identity[A, B] + + inline def getTransformer[A, B]: ReproTransformer[A, B] = ${ getTransformerMacro[A, B] } + + def getTransformerMacro[A, B](using quotes: Quotes, A: Type[A], B: Type[B]) = { + import quotes.reflect.* + + val transformer = (A -> B) match { + case '[a] -> '[b] => + val summoned = Expr.summon[ReproTransformer[a, b]].get +// ----------- INTERESTING STUFF STARTS HERE + summoned match { + case '{ $t: ReproTransformer[src, dest] } => t + } +// ----------- INTERESTING STUFF ENDS HERE + } + transformer.asExprOf[ReproTransformer[A, B]] + } +} diff --git a/tests/pos-macros/i16636/Test_2.scala b/tests/pos-macros/i16636/Test_2.scala new file mode 100644 index 000000000000..eb8891ea7bf8 --- /dev/null +++ b/tests/pos-macros/i16636/Test_2.scala @@ -0,0 +1,9 @@ +object A { + case class AnotherCaseClass(name: String) + + val errorsOut1 = ReproTransformer.getTransformer[A.AnotherCaseClass, AnotherCaseClass] + val errorsOu2 = ReproTransformer.getTransformer[AnotherCaseClass, A.AnotherCaseClass] + + val works1 = ReproTransformer.getTransformer[A.AnotherCaseClass, A.AnotherCaseClass] + val works2 = ReproTransformer.getTransformer[AnotherCaseClass, AnotherCaseClass] +} From 83ded211da39ce007d45ddf0b848a18b63e6034e Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 21 Dec 2022 16:51:25 +0100 Subject: [PATCH 2/4] Move `Checker` from `class TreeChecker` to `object TreeChecker` --- .../tools/dotc/transform/TreeChecker.scala | 140 +++++++++--------- 1 file changed, 71 insertions(+), 69 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index f11c8f5313dc..9280016b04c4 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -42,10 +42,6 @@ class TreeChecker extends Phase with SymTransformer { private val seenClasses = collection.mutable.HashMap[String, Symbol]() private val seenModuleVals = collection.mutable.HashMap[String, Symbol]() - def isValidJVMName(name: Name): Boolean = name.toString.forall(isValidJVMChar) - - def isValidJVMMethodName(name: Name): Boolean = name.toString.forall(isValidJVMMethodChar) - val NoSuperClassFlags: FlagSet = Trait | Package def testDuplicate(sym: Symbol, registry: mutable.Map[String, Symbol], typ: String)(using Context): Unit = { @@ -150,7 +146,78 @@ class TreeChecker extends Phase with SymTransformer { } } + /** + * Checks that `New` nodes are always wrapped inside `Select` nodes. + */ + def assertSelectWrapsNew(tree: Tree)(using Context): Unit = + (new TreeAccumulator[tpd.Tree] { + override def apply(parent: Tree, tree: Tree)(using Context): Tree = { + tree match { + case tree: New if !parent.isInstanceOf[tpd.Select] => + assert(assertion = false, i"`New` node must be wrapped in a `Select`:\n parent = ${parent.show}\n child = ${tree.show}") + case _: Annotated => + // Don't check inside annotations, since they're allowed to contain + // somewhat invalid trees. + case _ => + foldOver(tree, tree) // replace the parent when folding over the children + } + parent // return the old parent so that my siblings see it + } + })(tpd.EmptyTree, tree) +} + +object TreeChecker { + /** - Check that TypeParamRefs and MethodParams refer to an enclosing type. + * - Check that all type variables are instantiated. + */ + def checkNoOrphans(tp0: Type, tree: untpd.Tree = untpd.EmptyTree)(using Context): Type = new TypeMap() { + val definedBinders = new java.util.IdentityHashMap[Type, Any] + def apply(tp: Type): Type = { + tp match { + case tp: BindingType => + definedBinders.put(tp, tp) + mapOver(tp) + definedBinders.remove(tp) + case tp: ParamRef => + assert(definedBinders.get(tp.binder) != null, s"orphan param: ${tp.show}, hash of binder = ${System.identityHashCode(tp.binder)}, tree = ${tree.show}, type = $tp0") + case tp: TypeVar => + assert(tp.isInstantiated, s"Uninstantiated type variable: ${tp.show}, tree = ${tree.show}") + apply(tp.underlying) + case _ => + mapOver(tp) + } + tp + } + }.apply(tp0) + + /** Run some additional checks on the nodes of the trees. Specifically: + * + * - TypeTree can only appear in TypeApply args, New, Typed tpt, Closure + * tpt, SeqLiteral elemtpt, ValDef tpt, DefDef tpt, and TypeDef rhs. + */ + object TreeNodeChecker extends untpd.TreeTraverser: + import untpd._ + def traverse(tree: Tree)(using Context) = tree match + case t: TypeTree => assert(assertion = false, i"TypeTree not expected: $t") + case t @ TypeApply(fun, _targs) => traverse(fun) + case t @ New(_tpt) => + case t @ Typed(expr, _tpt) => traverse(expr) + case t @ Closure(env, meth, _tpt) => traverse(env); traverse(meth) + case t @ SeqLiteral(elems, _elemtpt) => traverse(elems) + case t @ ValDef(_, _tpt, _) => traverse(t.rhs) + case t @ DefDef(_, paramss, _tpt, _) => for params <- paramss do traverse(params); traverse(t.rhs) + case t @ TypeDef(_, _rhs) => + case t @ Template(constr, parents, self, _) => traverse(constr); traverse(parents); traverse(self); traverse(t.body) + case t => traverseChildren(t) + end traverse + + private[TreeChecker] def isValidJVMName(name: Name): Boolean = name.toString.forall(isValidJVMChar) + + private[TreeChecker] def isValidJVMMethodName(name: Name): Boolean = name.toString.forall(isValidJVMMethodChar) + + class Checker(phasesToCheck: Seq[Phase]) extends ReTyper with Checking { + import ast.tpd._ private val nowDefinedSyms = util.HashSet[Symbol]() private val patBoundSyms = util.HashSet[Symbol]() @@ -657,69 +724,4 @@ class TreeChecker extends Phase with SymTransformer { override def simplify(tree: Tree, pt: Type, locked: TypeVars)(using Context): tree.type = tree } - - /** - * Checks that `New` nodes are always wrapped inside `Select` nodes. - */ - def assertSelectWrapsNew(tree: Tree)(using Context): Unit = - (new TreeAccumulator[tpd.Tree] { - override def apply(parent: Tree, tree: Tree)(using Context): Tree = { - tree match { - case tree: New if !parent.isInstanceOf[tpd.Select] => - assert(assertion = false, i"`New` node must be wrapped in a `Select`:\n parent = ${parent.show}\n child = ${tree.show}") - case _: Annotated => - // Don't check inside annotations, since they're allowed to contain - // somewhat invalid trees. - case _ => - foldOver(tree, tree) // replace the parent when folding over the children - } - parent // return the old parent so that my siblings see it - } - })(tpd.EmptyTree, tree) -} - -object TreeChecker { - /** - Check that TypeParamRefs and MethodParams refer to an enclosing type. - * - Check that all type variables are instantiated. - */ - def checkNoOrphans(tp0: Type, tree: untpd.Tree = untpd.EmptyTree)(using Context): Type = new TypeMap() { - val definedBinders = new java.util.IdentityHashMap[Type, Any] - def apply(tp: Type): Type = { - tp match { - case tp: BindingType => - definedBinders.put(tp, tp) - mapOver(tp) - definedBinders.remove(tp) - case tp: ParamRef => - assert(definedBinders.get(tp.binder) != null, s"orphan param: ${tp.show}, hash of binder = ${System.identityHashCode(tp.binder)}, tree = ${tree.show}, type = $tp0") - case tp: TypeVar => - assert(tp.isInstantiated, s"Uninstantiated type variable: ${tp.show}, tree = ${tree.show}") - apply(tp.underlying) - case _ => - mapOver(tp) - } - tp - } - }.apply(tp0) - - /** Run some additional checks on the nodes of the trees. Specifically: - * - * - TypeTree can only appear in TypeApply args, New, Typed tpt, Closure - * tpt, SeqLiteral elemtpt, ValDef tpt, DefDef tpt, and TypeDef rhs. - */ - object TreeNodeChecker extends untpd.TreeTraverser: - import untpd._ - def traverse(tree: Tree)(using Context) = tree match - case t: TypeTree => assert(assertion = false, i"TypeTree not expected: $t") - case t @ TypeApply(fun, _targs) => traverse(fun) - case t @ New(_tpt) => - case t @ Typed(expr, _tpt) => traverse(expr) - case t @ Closure(env, meth, _tpt) => traverse(env); traverse(meth) - case t @ SeqLiteral(elems, _elemtpt) => traverse(elems) - case t @ ValDef(_, _tpt, _) => traverse(t.rhs) - case t @ DefDef(_, paramss, _tpt, _) => for params <- paramss do traverse(params); traverse(t.rhs) - case t @ TypeDef(_, _rhs) => - case t @ Template(constr, parents, self, _) => traverse(constr); traverse(parents); traverse(self); traverse(t.body) - case t => traverseChildren(t) - end traverse } From 49df37931f3780012f09049060cb7669f5c23366 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 16 Jan 2023 10:08:35 +0100 Subject: [PATCH 3/4] Use tree checker for macro expanded trees Trees are only checked if -Xcheck-macros is enabled. Fixes: - Add missing positions to {ValDef,Bind}.apply - Inline by-name ascribed param - Buggy test (tests/neg-macros/annot-mod-top-method-add-top-method) --- .../dotty/tools/dotc/inlines/Inliner.scala | 3 +- .../dotc/transform/MacroAnnotations.scala | 9 ++- .../tools/dotc/transform/TreeChecker.scala | 62 +++++++++++++++---- .../quoted/runtime/impl/QuotesImpl.scala | 4 +- .../Macro_1.scala | 2 +- .../exprSummonWithTypeVar/Macro_1.scala | 13 ++++ .../exprSummonWithTypeVar/Test_2.scala | 1 + .../macro-inline-by-name-cast/Macro_1.scala | 7 +++ .../macro-inline-by-name-cast/Test_2.scala | 1 + 9 files changed, 82 insertions(+), 20 deletions(-) create mode 100644 tests/pos-macros/exprSummonWithTypeVar/Macro_1.scala create mode 100644 tests/pos-macros/exprSummonWithTypeVar/Test_2.scala create mode 100644 tests/pos-macros/macro-inline-by-name-cast/Macro_1.scala create mode 100644 tests/pos-macros/macro-inline-by-name-cast/Test_2.scala diff --git a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala index c71648984664..76494c1bf405 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala @@ -227,7 +227,7 @@ class Inliner(val call: tpd.Tree)(using Context): val binding = { var newArg = arg.changeOwner(ctx.owner, boundSym) if bindingFlags.is(Inline) && argIsBottom then - newArg = Typed(newArg, TypeTree(formal)) // type ascribe RHS to avoid type errors in expansion. See i8612.scala + newArg = Typed(newArg, TypeTree(formal.widenExpr)) // type ascribe RHS to avoid type errors in expansion. See i8612.scala if isByName then DefDef(boundSym, newArg) else ValDef(boundSym, newArg) }.withSpan(boundSym.span) @@ -816,6 +816,7 @@ class Inliner(val call: tpd.Tree)(using Context): && StagingContext.level == 0 && !hasInliningErrors => val expanded = expandMacro(res.args.head, tree.srcPos) + transform.TreeChecker.checkMacroGeneratedTree(res, expanded) typedExpr(expanded) // Inline calls and constant fold code generated by the macro case res => specializeEq(inlineIfNeeded(res, pt, locked)) diff --git a/compiler/src/dotty/tools/dotc/transform/MacroAnnotations.scala b/compiler/src/dotty/tools/dotc/transform/MacroAnnotations.scala index 701a6772743e..cc2e6118d1fa 100644 --- a/compiler/src/dotty/tools/dotc/transform/MacroAnnotations.scala +++ b/compiler/src/dotty/tools/dotc/transform/MacroAnnotations.scala @@ -82,8 +82,9 @@ class MacroAnnotations: case (prefixed, newTree :: suffixed) => allTrees ++= prefixed insertedAfter = suffixed :: insertedAfter - prefixed.foreach(checkMacroDef(_, tree.symbol, annot)) - suffixed.foreach(checkMacroDef(_, tree.symbol, annot)) + prefixed.foreach(checkMacroDef(_, tree, annot)) + suffixed.foreach(checkMacroDef(_, tree, annot)) + transform.TreeChecker.checkMacroGeneratedTree(tree, newTree) newTree case (Nil, Nil) => report.error(i"Unexpected `Nil` returned by `(${annot.tree}).transform(..)` during macro expansion", annot.tree.srcPos) @@ -119,8 +120,10 @@ class MacroAnnotations: annotInstance.transform(using quotes)(tree.asInstanceOf[quotes.reflect.Definition]) /** Check that this tree can be added by the macro annotation */ - private def checkMacroDef(newTree: DefTree, annotated: Symbol, annot: Annotation)(using Context) = + private def checkMacroDef(newTree: DefTree, annotatedTree: Tree, annot: Annotation)(using Context) = + transform.TreeChecker.checkMacroGeneratedTree(annotatedTree, newTree) val sym = newTree.symbol + val annotated = annotatedTree.symbol if sym.isType && !sym.isClass then report.error(i"macro annotation cannot return a `type`. $annot tried to add $sym", annot.tree) else if sym.owner != annotated.owner && !(annotated.owner.isPackageObject && (sym.isClass || sym.is(Module)) && sym.owner == annotated.owner.owner) then diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index 9280016b04c4..804c3d1a2dda 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -105,18 +105,6 @@ class TreeChecker extends Phase with SymTransformer { else if (ctx.phase.prev.isCheckable) check(ctx.base.allPhases.toIndexedSeq, ctx) - private def previousPhases(phases: List[Phase])(using Context): List[Phase] = phases match { - case (phase: MegaPhase) :: phases1 => - val subPhases = phase.miniPhases - val previousSubPhases = previousPhases(subPhases.toList) - if (previousSubPhases.length == subPhases.length) previousSubPhases ::: previousPhases(phases1) - else previousSubPhases - case phase :: phases1 if phase ne ctx.phase => - phase :: previousPhases(phases1) - case _ => - Nil - } - def check(phasesToRun: Seq[Phase], ctx: Context): Tree = { val fusedPhase = ctx.phase.prevMega(using ctx) report.echo(s"checking ${ctx.compilationUnit} after phase ${fusedPhase}")(using ctx) @@ -219,7 +207,7 @@ object TreeChecker { class Checker(phasesToCheck: Seq[Phase]) extends ReTyper with Checking { import ast.tpd._ - private val nowDefinedSyms = util.HashSet[Symbol]() + protected val nowDefinedSyms = util.HashSet[Symbol]() private val patBoundSyms = util.HashSet[Symbol]() private val everDefinedSyms = MutableSymbolMap[untpd.Tree]() @@ -724,4 +712,52 @@ object TreeChecker { override def simplify(tree: Tree, pt: Type, locked: TypeVars)(using Context): tree.type = tree } + + /** Tree checker that can be applied to a local tree. */ + class LocalChecker(phasesToCheck: Seq[Phase]) extends Checker(phasesToCheck: Seq[Phase]): + override def assertDefined(tree: untpd.Tree)(using Context): Unit = + // Only check definitions nested in the local tree + if nowDefinedSyms.contains(tree.symbol.maybeOwner) then + super.assertDefined(tree) + + def checkMacroGeneratedTree(original: tpd.Tree, expansion: tpd.Tree)(using Context): Unit = + if ctx.settings.XcheckMacros.value then + val checkingCtx = ctx + .fresh + .addMode(Mode.ImplicitsEnabled) + .setReporter(new ThrowingReporter(ctx.reporter)) + val phases = ctx.base.allPhases.toList + val treeChecker = new LocalChecker(previousPhases(phases)) + + try treeChecker.typed(expansion)(using checkingCtx) + catch + case err: java.lang.AssertionError => + report.error( + s"""Malformed tree was found while expanding macro with -Xcheck-macros. + |The tree does not conform to the compiler's tree invariants. + | + |Macro was: + |${scala.quoted.runtime.impl.QuotesImpl.showDecompiledTree(original)} + | + |The macro returned: + |${scala.quoted.runtime.impl.QuotesImpl.showDecompiledTree(expansion)} + | + |Error: + |${err.getMessage} + | + |""", + original + ) + + private[TreeChecker] def previousPhases(phases: List[Phase])(using Context): List[Phase] = phases match { + case (phase: MegaPhase) :: phases1 => + val subPhases = phase.miniPhases + val previousSubPhases = previousPhases(subPhases.toList) + if (previousSubPhases.length == subPhases.length) previousSubPhases ::: previousPhases(phases1) + else previousSubPhases + case phase :: phases1 if phase ne ctx.phase => + phase :: previousPhases(phases1) + case _ => + Nil + } } diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index d2f4d154e85c..dd6471a882bd 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -307,7 +307,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler object ValDef extends ValDefModule: def apply(symbol: Symbol, rhs: Option[Term]): ValDef = - tpd.ValDef(symbol.asTerm, xCheckMacroedOwners(xCheckMacroValidExpr(rhs), symbol).getOrElse(tpd.EmptyTree)) + withDefaultPos(tpd.ValDef(symbol.asTerm, xCheckMacroedOwners(xCheckMacroValidExpr(rhs), symbol).getOrElse(tpd.EmptyTree))) def copy(original: Tree)(name: String, tpt: TypeTree, rhs: Option[Term]): ValDef = tpd.cpy.ValDef(original)(name.toTermName, tpt, xCheckMacroedOwners(xCheckMacroValidExpr(rhs), original.symbol).getOrElse(tpd.EmptyTree)) def unapply(vdef: ValDef): (String, TypeTree, Option[Term]) = @@ -1483,7 +1483,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler object Bind extends BindModule: def apply(sym: Symbol, pattern: Tree): Bind = - tpd.Bind(sym, pattern) + withDefaultPos(tpd.Bind(sym, pattern)) def copy(original: Tree)(name: String, pattern: Tree): Bind = withDefaultPos(tpd.cpy.Bind(original)(name.toTermName, pattern)) def unapply(pattern: Bind): (String, Tree) = diff --git a/tests/neg-macros/annot-mod-top-method-add-top-method/Macro_1.scala b/tests/neg-macros/annot-mod-top-method-add-top-method/Macro_1.scala index e2a257ca716b..45679b65c03b 100644 --- a/tests/neg-macros/annot-mod-top-method-add-top-method/Macro_1.scala +++ b/tests/neg-macros/annot-mod-top-method-add-top-method/Macro_1.scala @@ -9,5 +9,5 @@ class addTopLevelMethodOutsidePackageObject extends MacroAnnotation: import quotes.reflect._ val methType = MethodType(Nil)(_ => Nil, _ => TypeRepr.of[Int]) val methSym = Symbol.newMethod(Symbol.spliceOwner.owner, Symbol.freshName("toLevelMethod"), methType, Flags.EmptyFlags, Symbol.noSymbol) - val methDef = ValDef(methSym, Some(Literal(IntConstant(1)))) + val methDef = DefDef(methSym, _ => Some(Literal(IntConstant(1)))) List(methDef, tree) diff --git a/tests/pos-macros/exprSummonWithTypeVar/Macro_1.scala b/tests/pos-macros/exprSummonWithTypeVar/Macro_1.scala new file mode 100644 index 000000000000..72bcbe8b6515 --- /dev/null +++ b/tests/pos-macros/exprSummonWithTypeVar/Macro_1.scala @@ -0,0 +1,13 @@ +import scala.compiletime.{erasedValue, summonFrom} + +import scala.quoted._ + +inline given summonAfterTypeMatch[T]: Any = + ${ summonAfterTypeMatchExpr[T] } + +private def summonAfterTypeMatchExpr[T: Type](using Quotes): Expr[Any] = + Expr.summon[Foo[T]].get + +trait Foo[T] + +given IntFoo[T <: Int]: Foo[T] = ??? diff --git a/tests/pos-macros/exprSummonWithTypeVar/Test_2.scala b/tests/pos-macros/exprSummonWithTypeVar/Test_2.scala new file mode 100644 index 000000000000..dbf2fd88fe24 --- /dev/null +++ b/tests/pos-macros/exprSummonWithTypeVar/Test_2.scala @@ -0,0 +1 @@ +def test: Unit = summonAfterTypeMatch[Int] diff --git a/tests/pos-macros/macro-inline-by-name-cast/Macro_1.scala b/tests/pos-macros/macro-inline-by-name-cast/Macro_1.scala new file mode 100644 index 000000000000..7d9e186ed94f --- /dev/null +++ b/tests/pos-macros/macro-inline-by-name-cast/Macro_1.scala @@ -0,0 +1,7 @@ +import scala.quoted.* + +inline def f[T](inline code: =>T): Any = + ${ create[T]('{ () => code }) } + +def create[T: Type](code: Expr[() => T])(using Quotes): Expr[Any] = + '{ identity($code) } diff --git a/tests/pos-macros/macro-inline-by-name-cast/Test_2.scala b/tests/pos-macros/macro-inline-by-name-cast/Test_2.scala new file mode 100644 index 000000000000..161f58748342 --- /dev/null +++ b/tests/pos-macros/macro-inline-by-name-cast/Test_2.scala @@ -0,0 +1 @@ +def test: Unit = f[Unit](???) From aaf86b3ea1ff2e409b35775b36ed85271b538ef6 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 5 Jan 2023 11:39:41 +0000 Subject: [PATCH 4/4] Remove Mode.ImplicitsEnabled from TreeChecker --- compiler/src/dotty/tools/dotc/transform/TreeChecker.scala | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index 804c3d1a2dda..4041f620db56 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -118,7 +118,6 @@ class TreeChecker extends Phase with SymTransformer { val checkingCtx = ctx .fresh - .addMode(Mode.ImplicitsEnabled) .setReporter(new ThrowingReporter(ctx.reporter)) val checker = inContext(ctx) { @@ -724,7 +723,6 @@ object TreeChecker { if ctx.settings.XcheckMacros.value then val checkingCtx = ctx .fresh - .addMode(Mode.ImplicitsEnabled) .setReporter(new ThrowingReporter(ctx.reporter)) val phases = ctx.base.allPhases.toList val treeChecker = new LocalChecker(previousPhases(phases))