@@ -15,6 +15,7 @@ import util.SourcePosition
15
15
import config .Printers .init as printer
16
16
import reporting .StoreReporter
17
17
import reporting .trace as log
18
+ import typer .Applications .*
18
19
19
20
import Errors .*
20
21
import Trace .*
@@ -834,11 +835,10 @@ object Objects:
834
835
835
836
/** Handle local variable definition, `val x = e` or `var x = e`.
836
837
*
837
- * @param ref The value for `this` where the variable is defined.
838
838
* @param sym The symbol of the variable.
839
839
* @param value The value of the initializer.
840
840
*/
841
- def initLocal (ref : Ref , sym : Symbol , value : Value ): Contextual [Unit ] = log(" initialize local " + sym.show + " with " + value.show, printer) {
841
+ def initLocal (sym : Symbol , value : Value ): Contextual [Unit ] = log(" initialize local " + sym.show + " with " + value.show, printer) {
842
842
if sym.is(Flags .Mutable ) then
843
843
val addr = Heap .localVarAddr(summon[Regions .Data ], sym, State .currentObject)
844
844
Env .setLocalVar(sym, addr)
@@ -870,9 +870,6 @@ object Objects:
870
870
case _ =>
871
871
report.warning(" [Internal error] Variable not found " + sym.show + " \n env = " + env.show + " . Calling trace:\n " + Trace .show, Trace .position)
872
872
Bottom
873
- else if sym.isPatternBound then
874
- // TODO: handle patterns
875
- Cold
876
873
else
877
874
given Env .Data = env
878
875
// Assume forward reference check is doing a good job
@@ -1113,11 +1110,9 @@ object Objects:
1113
1110
else
1114
1111
eval(arg, thisV, klass)
1115
1112
1116
- case Match (selector, cases) =>
1117
- eval(selector, thisV, klass)
1118
- // TODO: handle pattern match properly
1119
- report.warning(" [initChecker] Pattern match is skipped. Trace:\n " + Trace .show, expr)
1120
- Bottom
1113
+ case Match (scrutinee, cases) =>
1114
+ val scrutineeValue = eval(scrutinee, thisV, klass)
1115
+ patternMatch(scrutineeValue, cases, thisV, klass)
1121
1116
1122
1117
case Return (expr, from) =>
1123
1118
Returns .handle(from.symbol, eval(expr, thisV, klass))
@@ -1151,7 +1146,7 @@ object Objects:
1151
1146
// local val definition
1152
1147
val rhs = eval(vdef.rhs, thisV, klass)
1153
1148
val sym = vdef.symbol
1154
- initLocal(thisV. asInstanceOf [ Ref ], vdef.symbol, rhs)
1149
+ initLocal(vdef.symbol, rhs)
1155
1150
Bottom
1156
1151
1157
1152
case ddef : DefDef =>
@@ -1173,6 +1168,95 @@ object Objects:
1173
1168
Bottom
1174
1169
}
1175
1170
1171
+ /** Evaluate the cases against the scrutinee value.
1172
+ *
1173
+ * @param scrutinee The abstract value of the scrutinee.
1174
+ * @param cases The cases to match.
1175
+ * @param thisV The value for `C.this` where `C` is represented by `klass`.
1176
+ * @param klass The enclosing class where the type `tp` is located.
1177
+ */
1178
+ def patternMatch (scrutinee : Value , cases : List [CaseDef ], thisV : Value , klass : ClassSymbol ): Contextual [Value ] =
1179
+ def evalCase (caseDef : CaseDef ): Value =
1180
+ evalPattern(scrutinee, caseDef.pat)
1181
+ eval(caseDef.guard, thisV, klass)
1182
+ eval(caseDef.body, thisV, klass)
1183
+
1184
+ /** Abstract evaluation of patterns.
1185
+ *
1186
+ * It augments the local environment for bound pattern variables. As symbols are globally
1187
+ * unique, we can put them in a single environment.
1188
+ *
1189
+ * Currently, we assume all cases are reachable, thus all patterns are assumed to match.
1190
+ */
1191
+ def evalPattern (scrutinee : Value , pat : Tree ): Value = log(" match " + scrutinee.show + " against " + pat.show, printer, (_ : Value ).show):
1192
+ pat match
1193
+ case Alternative (pats) =>
1194
+ for pat <- pats do evalPattern(scrutinee, pat)
1195
+ scrutinee
1196
+
1197
+ case bind @ Bind (_, pat) =>
1198
+ val value = evalPattern(scrutinee, pat)
1199
+ initLocal(bind.symbol, value)
1200
+ scrutinee
1201
+
1202
+ case SeqLiteral (pats, _) =>
1203
+ // TODO: handle unapplySeq
1204
+ Bottom
1205
+
1206
+ case UnApply (fun, _, pats) =>
1207
+ val fun1 = funPart(fun)
1208
+ val funRef = fun1.tpe.asInstanceOf [TermRef ]
1209
+ if fun.symbol.name == nme.unapplySeq then
1210
+ // TODO: handle unapplySeq
1211
+ ()
1212
+ else
1213
+ val receiver = evalType(funRef.prefix, thisV, klass)
1214
+ // TODO: apply implicits
1215
+ val unapplyRes = call(receiver, funRef.symbol, TraceValue (scrutinee, summon[Trace ]) :: Nil , funRef.prefix, superType = NoType , needResolve = true )
1216
+ // distribute unapply to patterns
1217
+ val unapplyResTp = funRef.widen.finalResultType
1218
+ if isProductMatch(unapplyResTp, pats.length) then
1219
+ // product match
1220
+ val selectors = productSelectors(unapplyResTp).take(pats.length)
1221
+ selectors.zip(pats).map { (sel, pat) =>
1222
+ val selectRes = call(unapplyRes, sel, Nil , unapplyResTp, superType = NoType , needResolve = true )
1223
+ evalPattern(selectRes, pat)
1224
+ }
1225
+ else if unapplyResTp <:< defn.BooleanType then
1226
+ // Boolean extractor, do nothing
1227
+ ()
1228
+ else
1229
+ // Get match
1230
+ val getMember = unapplyResTp.member(nme.get).suchThat(_.info.isParameterless)
1231
+ // TODO: call isEmpty as well
1232
+ val getRes = call(unapplyRes, getMember.symbol, Nil , unapplyResTp, superType = NoType , needResolve = true )
1233
+ if pats.length == 1 then
1234
+ // single match
1235
+ evalPattern(getRes, pats.head)
1236
+ else
1237
+ val getResTp = getMember.info.widen.finalResultType
1238
+ val selectors = productSelectors(getResTp).take(pats.length)
1239
+ selectors.zip(pats).map { (sel, pat) =>
1240
+ val selectRes = call(unapplyRes, sel, Nil , unapplyResTp, superType = NoType , needResolve = true )
1241
+ evalPattern(selectRes, pat)
1242
+ }
1243
+ end if
1244
+ end if
1245
+ end if
1246
+ scrutinee
1247
+
1248
+ case Typed (pat, _) =>
1249
+ evalPattern(scrutinee, pat)
1250
+
1251
+ case tree =>
1252
+ // For all other trees, the semantics is normal.
1253
+ eval(tree, thisV, klass)
1254
+
1255
+ end evalPattern
1256
+
1257
+ cases.map(evalCase).join
1258
+
1259
+
1176
1260
/** Handle semantics of leaf nodes
1177
1261
*
1178
1262
* For leaf nodes, their semantics is determined by their types.
0 commit comments