@@ -5,7 +5,7 @@ import core._
55import  Decorators ._ , Flags ._ , Types ._ , Contexts ._ , Symbols ._ , Constants ._ 
66import  Flags ._ 
77import  ast .Trees ._ 
8- import  ast .{TreeTypeMap , untpd }
8+ import  ast .{TreeTypeMap , tpd ,  untpd }
99import  util .Positions ._ 
1010import  tasty .TreePickler .Hole 
1111import  SymUtils ._ 
@@ -16,6 +16,7 @@ import typer.Implicits.SearchFailureType
1616import  scala .collection .mutable 
1717import  dotty .tools .dotc .core .StdNames ._ 
1818import  dotty .tools .dotc .core .quoted ._ 
19+ import  dotty .tools .dotc .util .SourcePosition 
1920
2021
2122/**  Translates quoted terms and types to `unpickle` method calls.
@@ -78,7 +79,7 @@ class ReifyQuotes extends MacroTransformWithImplicits {
7879    if  (ctx.compilationUnit.containsQuotesOrSplices) super .run
7980
8081  protected  def  newTransformer (implicit  ctx : Context ):  Transformer  = 
81-     new  Reifier (inQuote =  false , null , 0 , new  LevelInfo , new  mutable.ListBuffer [Tree ])
82+     new  Reifier (inQuote =  false , null , 0 , new  LevelInfo , new  mutable.ListBuffer [Tree ],  null )
8283
8384  private  class  LevelInfo  {
8485    /**  A map from locally defined symbols to the staging levels of their definitions */  
@@ -108,16 +109,22 @@ class ReifyQuotes extends MacroTransformWithImplicits {
108109   *                     and `l == -1` is code inside a top level splice (in an transparent method). 
109110   *  @param   levels      a stacked map from symbols to the levels in which they were defined 
110111   *  @param   embedded    a list of embedded quotes (if `inSplice = true`) or splices (if `inQuote = true` 
112+    *  @param   inlinedAtPos   if non null, the reifier is inside an inlined call with position `inlinedAtPos` 
111113   */  
112114  private  class  Reifier (inQuote : Boolean , val  outer :  Reifier , val  level :  Int , levels : LevelInfo ,
113-       val  embedded :  mutable.ListBuffer [Tree ]) extends  ImplicitsTransformer  {
115+       val  embedded :  mutable.ListBuffer [Tree ],  inlinedAtPos :  SourcePosition ) extends  ImplicitsTransformer  {
114116    import  levels ._ 
115117    assert(level >=  - 1 )
116118
117119    /**  A nested reifier for a quote (if `isQuote = true`) or a splice (if not) */  
118120    def  nested (isQuote : Boolean ):  Reifier  =  {
119121      val  nestedEmbedded  =  if  (level >  1  ||  (level ==  1  &&  isQuote)) embedded else  new  mutable.ListBuffer [Tree ]
120-       new  Reifier (isQuote, this , if  (isQuote) level +  1  else  level -  1 , levels, nestedEmbedded)
122+       new  Reifier (isQuote, this , if  (isQuote) level +  1  else  level -  1 , levels, nestedEmbedded, inlinedAtPos)
123+     }
124+ 
125+     def  inlined (inlinedAt : SourcePosition ):  Reifier  =  {
126+       assert(level ==  0 )
127+       new  Reifier (true , this , 0 , levels, embedded, inlinedAt)
121128    }
122129
123130    /**  We are in a `~(...)` context that is not shadowed by a nested `'(...)` */  
@@ -126,6 +133,8 @@ class ReifyQuotes extends MacroTransformWithImplicits {
126133    /**  We are not in a `~(...)` or a `'(...)` */  
127134    def  isRoot :  Boolean  =  outer ==  null 
128135
136+     def  isInlined :  Boolean  =  inlinedAtPos !=  null 
137+ 
129138    /**  A map from type ref T to expressions of type `quoted.Type[T]`". 
130139     *  These will be turned into splices using `addTags` and represent type variables 
131140     *  that can be possibly healed. 
@@ -230,10 +239,6 @@ class ReifyQuotes extends MacroTransformWithImplicits {
230239        ! sym.is(Param ) ||  levelOK(sym.owner)
231240    }
232241
233-     /**  Issue a "splice outside quote" error unless we are in the body of a transparent method */  
234-     def  spliceOutsideQuotes (pos : Position )(implicit  ctx : Context ):  Unit  = 
235-       ctx.error(i " splice outside quotes " , pos)
236- 
237242    /**  Try to heal phase-inconsistent reference to type `T` using a local type definition. 
238243     *  @return  None      if successful 
239244     *  @return  Some(msg) if unsuccessful where `msg` is a potentially empty error message 
@@ -292,7 +297,7 @@ class ReifyQuotes extends MacroTransformWithImplicits {
292297              outer.checkType(pos).foldOver(acc, tp)
293298            }
294299            else  {
295-               if  (tp.isTerm) spliceOutsideQuotes( pos)
300+               if  (tp.isTerm) ctx.error( i " splice outside quotes " ,  pos)
296301              tp
297302            }
298303          case  tp : NamedType  => 
@@ -418,14 +423,34 @@ class ReifyQuotes extends MacroTransformWithImplicits {
418423        val  body1  =  nested(isQuote =  false ).transform(splice.qualifier)
419424        body1.select(splice.name)
420425      }
421-       else  if  (! inQuote &&  level ==  0  &&  ! ctx.owner.is(Transparent )) {
422-         spliceOutsideQuotes(splice.pos)
423-         splice
424-       }
425-       else  {
426+       else  if  (level ==  1 ) {
426427        val  (body1, quotes) =  nested(isQuote =  false ).split(splice.qualifier)
427428        makeHole(body1, quotes, splice.tpe).withPos(splice.pos)
428429      }
430+       else  if  (level ==  - 1 ) {
431+         //  TODO add test
432+         ctx.error(" Cannot splice inside a top-level splice" 
433+         splice
434+       }
435+       else  if  (isInlined) { //  level 0 in an inline call
436+         val  evaluatedSplice  =  Splicer .splice(splice.qualifier, inlinedAtPos, macroClassLoader).withPos(splice.pos)
437+         if  (ctx.reporter.hasErrors) splice else  transform(evaluatedSplice)
438+       } else  if  (ctx.owner.is(Transparent )) { //  level 0 in an inline definition
439+         if  (! Splicer .canBeSpliced(splice.qualifier))
440+           ctx.error( //  TODO adapt error message
441+             """ Malformed inline macro.
442+               | 
443+               |Expected the ~ to be at the top of the RHS: 
444+               |  inline def foo(x: X, ..., y: Y): Int = ~impl(x, ... '(y)) 
445+               | 
446+               |The contents of the splice must call a static method. Arguments must be quoted or inlined. 
447+             """  .stripMargin, splice.pos)
448+         splice
449+       }
450+       else  { //  level 0
451+         ctx.error(i " splice outside quotes or inline method " , splice.pos)
452+         splice
453+       }
429454    }
430455
431456    /**  Transforms the contents of a nested splice 
@@ -550,39 +575,12 @@ class ReifyQuotes extends MacroTransformWithImplicits {
550575            val  last  =  enteredSyms
551576            stats.foreach(markDef)
552577            mapOverTree(last)
553-           case  Inlined (call, bindings, InlineSplice (spliced)) if  ! call.isEmpty => 
554-             val  tree2  = 
555-               if  (level ==  0 ) {
556-                 val  evaluatedSplice  =  Splicer .splice(spliced, tree.pos, macroClassLoader).withPos(tree.pos)
557-                 if  (ctx.reporter.hasErrors) EmptyTree 
558-                 else  transform(cpy.Inlined (tree)(call, bindings, evaluatedSplice))
559-               }
560-               else  super .transform(tree)
561- 
562-             //  due to value-discarding which converts an { e } into { e; () })
563-             if  (tree.tpe =:=  defn.UnitType ) Block (tree2 ::  Nil , Literal (Constant (())))
564-             else  tree2
578+           case  tree : Inlined  if  ! isInlined &&  level ==  0  => 
579+             inlined(tree.pos).transform(tree)
565580          case  _ : Import  => 
566581            tree
567-           case  tree : DefDef  if  tree.symbol.is(Macro ) &&  level ==  0  => 
568-             if  (enclosingInlineds.nonEmpty)
569-               return  EmptyTree  //  Already checked at definition site and already inlined
570-             markDef(tree)
571-             tree.rhs match  {
572-               case  InlineSplice (_) => 
573-                 mapOverTree(enteredSyms) //  Ignore output, only check PCP
574-                 cpy.DefDef (tree)(rhs =  defaultValue(tree.rhs.tpe))
575-               case  _ => 
576-                 ctx.error(
577-                   """ Malformed transparent macro.
578-                     | 
579-                     |Expected the ~ to be at the top of the RHS: 
580-                     |  transparent def foo(x: X, ..., y: Y): Int = ~impl(x, ... '(y)) 
581-                     | 
582-                     |The contents of the splice must call a static method. Arguments must be quoted or inlined. 
583-                   """  .stripMargin, tree.rhs.pos)
584-                 EmptyTree 
585-             }
582+           case  tree : DefDef  if  tree.symbol.is(Macro ) &&  level ==  0  &&  enclosingInlineds.nonEmpty => 
583+             EmptyTree  //  Already checked at definition site and already inlined
586584          case  _ => 
587585            markDef(tree)
588586            checkLevel(mapOverTree(enteredSyms))
@@ -616,18 +614,6 @@ class ReifyQuotes extends MacroTransformWithImplicits {
616614        acc.select(" ::" 
617615      }
618616    }
619- 
620-     /**  InlineSplice is used to detect cases where the expansion 
621-      *  consists of a (possibly multiple & nested) block or a sole expression. 
622-      */  
623-     object  InlineSplice  {
624-       def  unapply (tree : Tree )(implicit  ctx : Context ):  Option [Tree ] =  tree match  {
625-         case  Select (qual, _) if  tree.symbol.isSplice &&  Splicer .canBeSpliced(qual) =>  Some (qual)
626-         case  Block (List (stat), Literal (Constant (()))) =>  unapply(stat)
627-         case  Block (Nil , expr) =>  unapply(expr)
628-         case  _ =>  None 
629-       }
630-     }
631617  }
632618}
633619
0 commit comments