@@ -220,7 +220,7 @@ class Lowering()(using Config, TL, Raise, State, Ctx):
220
220
args(fs)(args => k(Value .Arr (args)))
221
221
case ref @ st.Ref (sym) =>
222
222
sym match
223
- case ctx.builtins.source.bms | ctx.builtins.js.bms | ctx.builtins.debug.bms =>
223
+ case ctx.builtins.source.bms | ctx.builtins.js.bms | ctx.builtins.debug.bms | ctx.builtins.annotations.bms =>
224
224
raise :
225
225
ErrorReport (
226
226
msg " Module ' ${sym.nme}' is virtual (i.e., \" compiler fiction \" ); cannot be used directly " -> t.toLoc ::
@@ -466,30 +466,48 @@ class Lowering()(using Config, TL, Raise, State, Ctx):
466
466
)
467
467
pat match
468
468
case Pattern .Lit (lit) => mkMatch(Case .Lit (lit) -> go(tail, topLevel = false ))
469
- case Pattern .ClassLike (cls : ClassSymbol , _trm, _args0, _refined)
470
- // Do not elaborate `_trm` when the `cls` is virtual.
471
- if Elaborator .ctx.builtins.virtualClasses contains cls =>
472
- // [invariant:0] Some classes (e.g., `Int`) from `Prelude` do
473
- // not exist at runtime. If we do lowering on `trm`, backends
474
- // (e.g., `JSBuilder`) will not be able to handle the corresponding selections.
475
- // In this case the second parameter of `Case.Cls` will not be used.
476
- // So we make it `Predef.unreachable` here.
477
- mkMatch(Case .Cls (cls, unreachableFn) -> go(tail, topLevel = false ))
478
- case Pattern .ClassLike (cls, trm, args0, _refined) =>
479
- subTerm_nonTail(trm): st =>
480
- val args = args0.getOrElse(Nil )
481
- val clsParams = cls match
482
- case cls : ClassSymbol => cls.tree.clsParams
483
- case _ : ModuleSymbol => Nil
484
- assert(args0.isEmpty || clsParams.length === args.length)
469
+ case Pattern .ClassLike (ctor, argsOpt, _mode, _refined) =>
470
+ /** Make a continuation that creates the match. */
471
+ def k (ctorSym : ClassLikeSymbol , clsParams : Ls [TermSymbol ])(st : Path ): Block =
472
+ val args = argsOpt.map(_.map(_.scrutinee)).getOrElse(Nil )
473
+ // Normalization should reject cases where the user provides
474
+ // more sub-patterns than there are actual class parameters.
475
+ assert(argsOpt.isEmpty || args.length <= clsParams.length)
485
476
def mkArgs (args : Ls [TermSymbol -> BlockLocalSymbol ])(using Subst ): Case -> Block = args match
486
477
case Nil =>
487
- Case .Cls (cls , st) -> go(tail, topLevel = false )
478
+ Case .Cls (ctorSym , st) -> go(tail, topLevel = false )
488
479
case (param, arg) :: args =>
489
480
val (cse, blk) = mkArgs(args)
490
481
(cse, Assign (arg, Select (sr, param.id/* FIXME incorrect Ident?*/ )(S (param)), blk))
491
- mkMatch(mkArgs(clsParams.iterator.zip(args).collect { case (s1, S (s2)) => (s1, s2) }.toList))
482
+ mkMatch(mkArgs(clsParams.iterator.zip(args).toList))
483
+ ctor.symbol.flatMap(_.asClsOrMod) match
484
+ case S (cls : ClassSymbol ) if ctx.builtins.virtualClasses contains cls =>
485
+ // [invariant:0] Some classes (e.g., `Int`) from `Prelude` do
486
+ // not exist at runtime. If we do lowering on `trm`, backends
487
+ // (e.g., `JSBuilder`) will not be able to handle the corresponding selections.
488
+ // In this case the second parameter of `Case.Cls` will not be used.
489
+ // So we do not elaborate `ctor` when the `cls` is virtual
490
+ // and use it `Predef.unreachable` here.
491
+ k(cls, Nil )(unreachableFn)
492
+ case S (cls : ClassSymbol ) => subTerm_nonTail(ctor)(k(cls, cls.tree.clsParams))
493
+ case S (mod : ModuleSymbol ) => subTerm_nonTail(ctor)(k(mod, Nil ))
494
+ case N =>
495
+ // Normalization have already checked the constructor
496
+ // resolves to a class or module. Branches with unresolved
497
+ // constructors should have been removed.
498
+ lastWords(" Pattern.ClassLike: constructor is neither a class nor a module" )
492
499
case Pattern .Tuple (len, inf) => mkMatch(Case .Tup (len, inf) -> go(tail, topLevel = false ))
500
+ case Pattern .Record (entries) =>
501
+ val objectSym = ctx.builtins.Object
502
+ mkMatch( // checking that we have an object
503
+ Case .Cls (objectSym, Value .Ref (BuiltinSymbol (objectSym.nme, false , false , true , false ))),
504
+ entries.foldRight(go(tail, topLevel = false )):
505
+ case ((fieldName, fieldSymbol), blk) =>
506
+ mkMatch(
507
+ Case .Field (fieldName, safe = true ), // we know we have an object, no need to check again
508
+ Assign (fieldSymbol, Select (sr, fieldName)(N ), blk)
509
+ )
510
+ )
493
511
case Split .Else (els) =>
494
512
if k.isInstanceOf [TailOp ] && isIf then term_nonTail(els)(k)
495
513
else
@@ -502,11 +520,17 @@ class Lowering()(using Config, TL, Raise, State, Ctx):
502
520
Throw (Instantiate (Select (Value .Ref (State .globalThisSymbol), Tree .Ident (" Error" ))(N ),
503
521
Value .Lit (syntax.Tree .StrLit (" match error" )) :: Nil )) // TODO add failed-match scrutinee info
504
522
505
- if k.isInstanceOf [TailOp ] && isIf then go(iftrm.normalized, topLevel = true )
523
+ val normalize = ucs.Normalization ()
524
+ val normalized = tl.scoped(" ucs:normalize" ):
525
+ normalize(iftrm.desugared)
526
+ tl.scoped(" ucs:normalized" ):
527
+ tl.log(s " Normalized: \n ${Split .display(normalized)}" )
528
+
529
+ if k.isInstanceOf [TailOp ] && isIf then go(normalized, topLevel = true )
506
530
else
507
531
val body = if isWhile
508
- then Label (lbl, go(iftrm. normalized, topLevel = true ), End ())
509
- else go(iftrm. normalized, topLevel = true )
532
+ then Label (lbl, go(normalized, topLevel = true ), End ())
533
+ else go(normalized, topLevel = true )
510
534
Begin (
511
535
body,
512
536
if usesResTmp then k(Value .Ref (l))
0 commit comments