Skip to content

Commit

Permalink
Pattern symbols should not be selected from globalThis
Browse files Browse the repository at this point in the history
  • Loading branch information
chengluyu committed Dec 2, 2024
1 parent 0a09baa commit f305fe0
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ class Desugarer(tl: TraceLogger, val elaborator: Elaborator)
Branch(ref, Pattern.ClassLike(cls, clsTrm, N, false)(ctor), sequel(ctx)) ~: fallback
case S(cls: ModuleSymbol) =>
Branch(ref, Pattern.ClassLike(cls, clsTrm, N, false)(ctor), sequel(ctx)) ~: fallback
case S(psym: PatternSymbol) => makeUnapplyBranch(ref, psym, sequel(ctx))(fallback)
case S(psym: PatternSymbol) => makeUnapplyBranch(ref, clsTrm, sequel(ctx))(fallback)
case N =>
// Raise an error and discard `sequel`. Use `fallback` instead.
raise(ErrorReport(msg"Cannot use this ${ctor.describe} as a pattern" -> ctor.toLoc :: Nil))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,24 +89,22 @@ trait DesugaringBase(using state: Elaborator.State):
/** Make a `Branch` that calls `Pattern` symbols' `unapply` functions. */
def makeUnapplyBranch(
scrut: => Term.Ref,
psym: PatternSymbol,
clsTerm: Term,
inner: => Split,
method: Str = "unapply"
)(fallback: Split): Ctxl[Split] =
val func = sel(sel(globalThisSymbol.ref(), psym.nme, psym), method)
val call = app(func, tup(fld(scrut)), FlowSymbol(s"result of $method"))
val call = app(sel(clsTerm, method), tup(fld(scrut)), FlowSymbol(s"result of $method"))
tempLet("matchResult", call): resultSymbol =>
Branch(resultSymbol.ref(), matchResultPattern(N), inner) ~: fallback

/** Make a `Branch` that calls `Pattern` symbols' `unapplyStringPrefix` functions. */
def makeUnapplyStringPrefixBranch(
scrut: => Term.Ref,
psym: PatternSymbol,
clsTerm: Term,
inner: TempSymbol => Split,
method: Str = "unapplyStringPrefix"
)(fallback: Split): Ctxl[Split] =
val func = sel(sel(globalThisSymbol.ref(), psym.nme, psym), method)
val call = app(func, tup(fld(scrut)), FlowSymbol(s"result of $method"))
val call = app(sel(clsTerm, method), tup(fld(scrut)), FlowSymbol(s"result of $method"))
tempLet("matchResult", call): resultSymbol =>
val argSym = TempSymbol(N, "arg")
Branch(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ class Translator(val elaborator: Elaborator)
case S(cls: (ClassSymbol | ModuleSymbol)) =>
Branch(scrut(), Pattern.ClassLike(cls, clsTrm, N, false)(ctor), inner(Map.empty)) ~: Split.End
case S(psym: PatternSymbol) =>
makeUnapplyBranch(scrut(), psym, inner(Map.empty))(Split.End)
makeUnapplyBranch(scrut(), clsTrm, inner(Map.empty))(Split.End)
case _ =>
error(msg"Cannot use this ${ctor.describe} as an extractor" -> ctor.toLoc)
errorSplit
Expand Down Expand Up @@ -146,13 +146,14 @@ class Translator(val elaborator: Elaborator)
stringPrefix(postfixScrut1, postfix, (captures2, postfixScrut2) =>
inner(captures2 ++ captures1, postfixScrut2)))
case ctor @ (_: Ident | _: Sel) =>
elaborator.cls(ctor, inAppPrefix = false).symbol.flatMap(_.asClsLike) match
val clsTrm = elaborator.cls(ctor, inAppPrefix = false)
clsTrm.symbol.flatMap(_.asClsLike) match
case S(cls: (ClassSymbol | ModuleSymbol)) =>
val kind = cls match { case _: ClassSymbol => "class" case _ => "module" }
error(msg"Cannot treat this $kind as a string prefix" -> ctor.toLoc)
errorSplit
case S(psym: PatternSymbol) =>
makeUnapplyStringPrefixBranch(scrut(), psym, postfixSym =>
makeUnapplyStringPrefixBranch(scrut(), clsTrm, postfixSym =>
inner(Map.empty, () => postfixSym.ref())
)(Split.End)
case _ =>
Expand Down
74 changes: 74 additions & 0 deletions hkmc2/shared/src/test/mlscript/rp/LocalPatterns.mls
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
:js

pattern One = "1"

module Playground with
pattern Zero = "0"
pattern DoubleZero = Zero ~ Zero
pattern ZeroOne = Zero ~ One

Playground
//│ > Playground {
//│ > Zero: Zero { class: [class Zero] },
//│ > DoubleZero: DoubleZero { class: [class DoubleZero] },
//│ > ZeroOne: ZeroOne { class: [class ZeroOne] },
//│ > class: [class Playground]
//│ = }

// Pattern defined in a module can be used with qualified name.
// ============================================================

Playground.Zero
//│ = Zero { class: [class Zero] }

Playground.Zero.unapply("0")
//│ = MatchResult { captures: [] }

:expect true
"0" is Playground.Zero
//│ = true

// Patterns defined in a module can refer to other patterns in the same module.
// ============================================================================

Playground.DoubleZero
//│ = DoubleZero { class: [class DoubleZero] }

Playground.DoubleZero.unapply("00")
//│ = MatchResult { captures: [] }

:expect true
"00" is Playground.DoubleZero
//│ = true

// Patterns defined in a module can refer to patterns in the global scope.
// =======================================================================

Playground.ZeroOne
//│ = ZeroOne { class: [class ZeroOne] }

Playground.ZeroOne.unapply("01")
//│ = MatchResult { captures: [] }

:expect true
"01" is Playground.ZeroOne
//│ = true

// Patterns defined in the global scope can refer to patterns in a module.
// =======================================================================

pattern TripleZero = Playground.DoubleZero ~ Playground.Zero

TripleZero
//│ = TripleZero { class: [class TripleZero] }

TripleZero.unapply("000")
//│ = MatchResult { captures: [] }

:expect true
"000" is TripleZero
//│ = true

:expect false
"001" is TripleZero
//│ = false

0 comments on commit f305fe0

Please sign in to comment.