diff --git a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala index 4eee4884f954..159f7e4bd451 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala @@ -964,7 +964,25 @@ class Inliner(val call: tpd.Tree)(using Context): case tree1 @ Splice(expr) if level == 0 && !hasInliningErrors && !ctx.usedBestEffortTasty => val expanded = expandMacro(expr, tree1.srcPos) transform.TreeChecker.checkMacroGeneratedTree(tree1, expanded) - typedExpr(expanded) // Inline calls and constant fold code generated by the macro + val res = typedExpr(expanded) // Inline calls and constant fold code generated by the macro + + // We dealias opaque types because their aliases might not be visible + // at the expansion site. See `tests/run-macros/opaque-inline`. + val dealiasOpaques = new TypeMap: + def apply(tp: Type): Type = tp match + case tp: TypeRef if tp.typeSymbol.isOpaqueAlias => + val sym = tp.typeSymbol + apply(sym.opaqueAlias.asSeenFrom(tp.prefix, sym.owner)) + case _ => + mapOver(tp) + + val actualTp = dealiasOpaques(res.tpe) + val expectedTp = dealiasOpaques(tree1.tpe) + if !ctx.settings.XcheckMacros.value || (actualTp frozen_<:< expectedTp) then + res + else + errorTree(tree1, em"""Macro expansion has type $actualTp, which does not conform to the expected type $expectedTp""") + case tree1 => tree1 override def typedMatch(tree: untpd.Match, pt: Type)(using Context): Tree = diff --git a/tests/neg-macros/expr-asInstanceOf/Macro_1.scala b/tests/neg-macros/expr-asInstanceOf/Macro_1.scala new file mode 100644 index 000000000000..98182a4cb2e7 --- /dev/null +++ b/tests/neg-macros/expr-asInstanceOf/Macro_1.scala @@ -0,0 +1,9 @@ +import scala.quoted.* + +object Macro: + inline def foo(): Int = + ${fooImpl()} + + def fooImpl()(using Quotes): Expr[Int] = + import quotes.reflect.* + Expr("hello").asInstanceOf[Expr[Int]] diff --git a/tests/neg-macros/expr-asInstanceOf/Test_2.scala b/tests/neg-macros/expr-asInstanceOf/Test_2.scala new file mode 100644 index 000000000000..3f4c8f02a902 --- /dev/null +++ b/tests/neg-macros/expr-asInstanceOf/Test_2.scala @@ -0,0 +1,2 @@ +@main def test = + println(Macro.foo()) // error diff --git a/tests/neg-macros/monocle-transparent-invariant-neg/Macro_1.scala b/tests/neg-macros/monocle-transparent-invariant-neg/Macro_1.scala new file mode 100644 index 000000000000..ec5d3eed3c0e --- /dev/null +++ b/tests/neg-macros/monocle-transparent-invariant-neg/Macro_1.scala @@ -0,0 +1,12 @@ +import scala.quoted.* + +// Invariant type constructor +final class Inv[A](val value: A) + +object Inv: + transparent inline def make: Inv[Tuple] = + ${ makeImpl } + + def makeImpl(using Quotes): Expr[Inv[Tuple]] = + val e: Expr[Inv[EmptyTuple]] = '{ new Inv[EmptyTuple](EmptyTuple) } + e.asInstanceOf[Expr[Inv[Tuple]]] diff --git a/tests/neg-macros/monocle-transparent-invariant-neg/Test_2.scala b/tests/neg-macros/monocle-transparent-invariant-neg/Test_2.scala new file mode 100644 index 000000000000..002c20d8efaa --- /dev/null +++ b/tests/neg-macros/monocle-transparent-invariant-neg/Test_2.scala @@ -0,0 +1 @@ +val inv: Inv[EmptyTuple] = Inv.make // error diff --git a/tests/pos-macros/i25690/Macro_1.scala b/tests/pos-macros/i25690/Macro_1.scala index 6867d5a9bcc8..146e3d97df22 100644 --- a/tests/pos-macros/i25690/Macro_1.scala +++ b/tests/pos-macros/i25690/Macro_1.scala @@ -11,4 +11,4 @@ object Tracer: def autoTraceImpl(using Quotes): Expr[Trace] = import quotes.reflect.* - Literal(StringConstant("loc")).asExprOf[String].asInstanceOf[Expr[Trace]] + '{ ${ Literal(StringConstant("loc")).asExprOf[String] }.asInstanceOf[Trace] } diff --git a/tests/pos-macros/i25692/Macro_1.scala b/tests/pos-macros/i25692/Macro_1.scala index 84a3d3bd9c52..0580cf043850 100644 --- a/tests/pos-macros/i25692/Macro_1.scala +++ b/tests/pos-macros/i25692/Macro_1.scala @@ -27,7 +27,7 @@ package internal.stacktracer: object Macros: def autoTraceImpl(using Quotes): Expr[Tracer.instance.Type] = - Expr("trace").asInstanceOf[Expr[Tracer.instance.Type]] + '{ "trace".asInstanceOf[Tracer.instance.Type] } package internal.macros: import zio.* diff --git a/tests/pos-macros/monocle-transparent-invariant-pos/Macro_1.scala b/tests/pos-macros/monocle-transparent-invariant-pos/Macro_1.scala new file mode 100644 index 000000000000..0ef9eda14f93 --- /dev/null +++ b/tests/pos-macros/monocle-transparent-invariant-pos/Macro_1.scala @@ -0,0 +1,11 @@ +import scala.quoted.* + +// Invariant type constructor +final class Inv[A](val value: A) + +object Inv: + transparent inline def make: Inv[? <: Tuple] = + ${ makeImpl } + + def makeImpl(using Quotes): Expr[Inv[? <: Tuple]] = + '{ new Inv[EmptyTuple](EmptyTuple) } diff --git a/tests/pos-macros/monocle-transparent-invariant-pos/Test_2.scala b/tests/pos-macros/monocle-transparent-invariant-pos/Test_2.scala new file mode 100644 index 000000000000..870de05f04f9 --- /dev/null +++ b/tests/pos-macros/monocle-transparent-invariant-pos/Test_2.scala @@ -0,0 +1 @@ +val inv: Inv[EmptyTuple] = Inv.make diff --git a/tests/run-macros/i7887/Macro_1.scala b/tests/run-macros/i7887/Macro_1.scala index 9ba02c41ab23..e6af538a9c79 100644 --- a/tests/run-macros/i7887/Macro_1.scala +++ b/tests/run-macros/i7887/Macro_1.scala @@ -1,4 +1,4 @@ -def myMacroImpl(a: quoted.Expr[_])(using qctx: quoted.Quotes) = { +def myMacroImpl[S](a: quoted.Expr[S])(using qctx: quoted.Quotes): quoted.Expr[S] = { import scala.quoted.quotes.reflect.* def typed[A] = { implicit val t: quoted.Type[A] = a.asTerm.tpe.widen.asType.asInstanceOf[quoted.Type[A]] diff --git a/tests/run-macros/i7887/Test_2.scala b/tests/run-macros/i7887/Test_2.scala index 565f6f019fe4..dddb31e4ad03 100644 --- a/tests/run-macros/i7887/Test_2.scala +++ b/tests/run-macros/i7887/Test_2.scala @@ -1,3 +1,2 @@ -object Test extends App { +@main def Test = assert(myMacro(42) == 42) -}