@@ -19,6 +19,7 @@ import Util._
1919import scala .collection .mutable
2020
2121class Semantic {
22+ import Semantic ._
2223
2324// ----- Domain definitions --------------------------------
2425
@@ -410,6 +411,23 @@ class Semantic {
410411 def eval (exprs : List [Tree ], thisV : Value , klass : ClassSymbol )(using Context , Trace ): List [Result ] =
411412 exprs.map { expr => eval(expr, thisV, klass) }
412413
414+ /** Evaluate arguments of methods */
415+ def evalArgs (args : List [Arg ], thisV : Value , klass : ClassSymbol )(using Context , Trace ): List [Error ] =
416+ val ress = args.map { arg =>
417+ val res =
418+ if arg.isByName then
419+ thisV match
420+ case obj : (ThisRef | Warm ) =>
421+ val value = Fun (arg.tree, obj, klass)
422+ Result (value, Nil )
423+ case _ => ??? // impossible
424+ else
425+ eval(arg.tree, thisV, klass)
426+
427+ res.ensureHot(" May only use initialized value as arguments" , arg.tree)
428+ }
429+ ress.flatMap(_.errors)
430+
413431 /** Handles the evaluation of different expressions
414432 *
415433 * Note: Recursive call should go to `eval` instead of `cases`.
@@ -426,23 +444,15 @@ class Semantic {
426444
427445 case NewExpr (tref, New (tpt), ctor, argss) =>
428446 // check args
429- val args = argss.flatten
430- val ress = args.map { arg =>
431- eval(arg, thisV, klass).ensureHot(" May use initialized value as arguments" , arg)
432- }
433- val errors = ress.flatMap(_.errors)
447+ val errors = evalArgs(argss.flatten, thisV, klass)
434448
435449 val cls = tref.classSymbol.asClass
436450 val res = outerValue(tref, thisV, klass, tpt)
437451 (res ++ errors).instantiate(cls, ctor, expr)
438452
439453 case Call (ref, argss) =>
440454 // check args
441- val args = argss.flatten
442- val ress = args.map { arg =>
443- eval(arg, thisV, klass).ensureHot(" May use initialized value as arguments" , arg)
444- }
445- val errors = ress.flatMap(_.errors)
455+ val errors = evalArgs(argss.flatten, thisV, klass)
446456
447457 ref match
448458 case Select (supert : Super , _) =>
@@ -667,19 +677,11 @@ class Semantic {
667677 def initParent (parent : Tree ) = parent match {
668678 case tree @ Block (stats, NewExpr (tref, New (tpt), ctor, argss)) =>
669679 eval(stats, thisV, klass).foreach { res => errorBuffer ++= res.errors }
670- argss.flatten.foreach { arg =>
671- val res = eval(arg, thisV, klass)
672- res.ensureHot(" Argument must be an initialized value" , arg)
673- errorBuffer ++= res.errors
674- }
680+ errorBuffer ++= evalArgs(argss.flatten, thisV, klass)
675681 superCall(tref, ctor, tree)
676682
677683 case tree @ NewExpr (tref, New (tpt), ctor, argss) =>
678- argss.flatten.foreach { arg =>
679- val res = eval(arg, thisV, klass)
680- res.ensureHot(" Argument must be an initialized value" , arg)
681- errorBuffer ++= res.errors
682- }
684+ errorBuffer ++= evalArgs(argss.flatten, thisV, klass)
683685 superCall(tref, ctor, tree)
684686
685687 case _ =>
@@ -728,7 +730,7 @@ class Semantic {
728730 *
729731 * This is intended to avoid type soundness issues in Dotty.
730732 */
731- def checkTermUsage (tpt : Tree , thisV : Value , klass : ClassSymbol )(using Context , Trace ): List [Error ] =
733+ def checkTermUsage (tpt : Tree , thisV : Value , klass : ClassSymbol )(using Context , Trace ): List [Error ] =
732734 val buf = new mutable.ArrayBuffer [Error ]
733735 val traverser = new TypeTraverser {
734736 def traverse (tp : Type ): Unit = tp match {
@@ -741,19 +743,39 @@ class Semantic {
741743 traverser.traverse(tpt.tpe)
742744 buf.toList
743745
746+ }
747+
748+ object Semantic {
749+
744750// ----- Utility methods and extractors --------------------------------
745751
746752 def typeRefOf (tp : Type )(using Context ): TypeRef = tp.dealias.typeConstructor match {
747753 case tref : TypeRef => tref
748754 case hklambda : HKTypeLambda => typeRefOf(hklambda.resType)
749755 }
750756
757+ opaque type Arg = Tree | ByNameArg
758+ case class ByNameArg (tree : Tree )
759+
760+ extension (arg : Arg )
761+ def isByName = arg.isInstanceOf [ByNameArg ]
762+ def tree : Tree = arg match
763+ case t : Tree => t
764+ case ByNameArg (t) => t
765+
751766 object Call {
752- def unapply (tree : Tree )(using Context ): Option [(Tree , List [List [Tree ]])] =
767+
768+ def unapply (tree : Tree )(using Context ): Option [(Tree , List [List [Arg ]])] =
753769 tree match
754770 case Apply (fn, args) =>
771+ val argTps = fn.tpe.widen match
772+ case mt : MethodType => mt.paramInfos
773+ val normArgs : List [Arg ] = args.zip(argTps).map {
774+ case (arg, _ : ExprType ) => ByNameArg (arg)
775+ case (arg, _) => arg
776+ }
755777 unapply(fn) match
756- case Some ((ref, args0)) => Some ((ref, args0 :+ args ))
778+ case Some ((ref, args0)) => Some ((ref, args0 :+ normArgs ))
757779 case None => None
758780
759781 case TypeApply (fn, targs) =>
@@ -766,7 +788,7 @@ class Semantic {
766788 }
767789
768790 object NewExpr {
769- def unapply (tree : Tree )(using Context ): Option [(TypeRef , New , Symbol , List [List [Tree ]])] =
791+ def unapply (tree : Tree )(using Context ): Option [(TypeRef , New , Symbol , List [List [Arg ]])] =
770792 tree match
771793 case Call (fn @ Select (newTree : New , init), argss) if init == nme.CONSTRUCTOR =>
772794 val tref = typeRefOf(newTree.tpe)
0 commit comments