compiler: match expr mir

This commit is contained in:
sfja 2025-03-24 00:40:40 +01:00 committed by SimonFJ20
parent f4fbda226a
commit 9a6d570a8a
7 changed files with 177 additions and 10 deletions

View File

@ -222,11 +222,13 @@ export type PatKind =
| { tag: "error" } | { tag: "error" }
| { tag: "bind" } & BindPat | { tag: "bind" } & BindPat
| { tag: "path" } & PathPat | { tag: "path" } & PathPat
| { tag: "bool" } & BoolPat
| { tag: "tuple" } & TuplePat | { tag: "tuple" } & TuplePat
| { tag: "struct" } & StructPat; | { tag: "struct" } & StructPat;
export type BindPat = { ident: Ident; mut: boolean }; export type BindPat = { ident: Ident; mut: boolean };
export type PathPat = { qty?: Ty; path: Path }; export type PathPat = { qty?: Ty; path: Path };
export type BoolPat = { value: boolean };
export type TuplePat = { path?: Path; elems: Pat[] }; export type TuplePat = { path?: Path; elems: Pat[] };
export type StructPat = { path?: Path; fields: PatField[] }; export type StructPat = { path?: Path; fields: PatField[] };

View File

@ -10,6 +10,7 @@ import {
Block, Block,
BlockExpr, BlockExpr,
BoolExpr, BoolExpr,
BoolPat,
BreakStmt, BreakStmt,
CallExpr, CallExpr,
CForExpr, CForExpr,
@ -132,6 +133,7 @@ export interface Visitor<
visitErrorPat?(pat: Pat, ...p: P): R; visitErrorPat?(pat: Pat, ...p: P): R;
visitBindPat?(pat: Pat, kind: BindPat, ...p: P): R; visitBindPat?(pat: Pat, kind: BindPat, ...p: P): R;
visitPathPat?(pat: Pat, kind: PathPat, ...p: P): R; visitPathPat?(pat: Pat, kind: PathPat, ...p: P): R;
visitBoolPat?(pat: Pat, kind: BoolPat, ...p: P): R;
visitTuplePat?(pat: Pat, kind: TuplePat, ...p: P): R; visitTuplePat?(pat: Pat, kind: TuplePat, ...p: P): R;
visitStructPat?(pat: Pat, kind: StructPat, ...p: P): R; visitStructPat?(pat: Pat, kind: StructPat, ...p: P): R;
@ -532,6 +534,9 @@ export function visitPat<
if (v.visitPathPat?.(pat, kind, ...p) === "stop") return; if (v.visitPathPat?.(pat, kind, ...p) === "stop") return;
visitPath(v, kind.path, ...p); visitPath(v, kind.path, ...p);
return; return;
case "bool":
if (v.visitBoolPat?.(pat, kind, ...p) === "stop") return;
return;
case "tuple": case "tuple":
if (v.visitTuplePat?.(pat, kind, ...p) === "stop") return; if (v.visitTuplePat?.(pat, kind, ...p) === "stop") return;
kind.path && visitPath(v, kind.path, ...p); kind.path && visitPath(v, kind.path, ...p);

View File

@ -91,6 +91,8 @@ export class Checker {
return Ok(undefined); return Ok(undefined);
case "path": case "path":
return todo(); return todo();
case "bool":
return Ok(undefined);
case "tuple": { case "tuple": {
if (k.path) { if (k.path) {
const re = this.re.pathRes(k.path.id); const re = this.re.pathRes(k.path.id);
@ -133,6 +135,35 @@ export class Checker {
} }
return Res.Ok(undefined); return Res.Ok(undefined);
} }
if (re.kind.tag === "struct") {
const data = re.kind.kind.data;
if (
data.kind.tag !== "tuple" ||
ty.kind.tag !== "struct" ||
ty.kind.data.tag !== "tuple"
) {
return Res.Err({
msg: "type/pattern mismatch",
span: pat.span,
});
}
if (k.elems.length !== data.kind.elems.length) {
return Res.Err({
msg: `incorrect amount of elements, expected ${data.kind.elems.length} got ${k.elems.length}`,
span: pat.span,
});
}
for (const i of data.kind.elems.keys()) {
const res = this.assignPatTy(
k.elems[i],
ty.kind.data.elems[i].ty,
);
if (!res.ok) {
return res;
}
}
return Res.Ok(undefined);
}
} }
return todo(); return todo();
} }
@ -995,6 +1026,7 @@ export class Checker {
case "int": case "int":
return Ty({ tag: "int" }); return Ty({ tag: "int" });
case "bool": case "bool":
return Ty({ tag: "bool" });
case "str": case "str":
return todo(k.tag); return todo(k.tag);
case "path": { case "path": {
@ -1073,6 +1105,10 @@ export class Checker {
return todo(); return todo();
} }
case "path": case "path":
return todo();
case "bool": {
return this.patTy(pat);
}
case "tuple": case "tuple":
case "struct": case "struct":
return todo(); return todo();

View File

@ -164,6 +164,9 @@ export class FnLowerer {
return; return;
} }
case "path": case "path":
return todo();
case "bool":
return;
case "tuple": case "tuple":
case "struct": case "struct":
return todo(); return todo();
@ -186,6 +189,9 @@ export class FnLowerer {
return; return;
} }
case "path": case "path":
return todo();
case "bool":
return;
case "tuple": case "tuple":
case "struct": case "struct":
return todo(); return todo();
@ -569,6 +575,7 @@ export class FnLowerer {
nextArmBlock, nextArmBlock,
); );
this.pushCreatedBlock(exprBlock); this.pushCreatedBlock(exprBlock);
this.lowerMatchArmPatternBindings(discr, arm.pat);
const rval = this.lowerExpr(arm.expr); const rval = this.lowerExpr(arm.expr);
this.addStmt({ this.addStmt({
tag: "assign", tag: "assign",
@ -588,6 +595,102 @@ export class FnLowerer {
pat: ast.Pat, pat: ast.Pat,
truthyBlock: Block, truthyBlock: Block,
falsyBlock: Block, falsyBlock: Block,
) {
const discrOperand = this.lowerMatchArmPatternCondition(discr, pat);
this.setTer({
tag: "switch",
discr: discrOperand,
targets: [{ value: 1, target: truthyBlock.id }],
otherwise: falsyBlock.id,
});
}
private lowerMatchArmPatternCondition(
discr: RVal,
pat: ast.Pat,
): Operand {
const k = pat.kind;
switch (k.tag) {
case "error":
return { tag: "error" };
case "bind": {
return { tag: "const", val: { tag: "int", value: 1 } };
}
case "path":
return todo();
case "bool": {
const ty = this.ch.patTy(pat);
if (ty.kind.tag !== "bool") {
throw new Error();
}
const discrLocal = this.local(ty);
this.addStmt({
tag: "assign",
place: { local: discrLocal, proj: [] },
rval: discr,
});
const local = this.local(ty);
this.addStmt({
tag: "assign",
place: { local, proj: [] },
rval: {
tag: "binary",
binaryType: "eq",
left: this.copyOrMoveLocal(discrLocal, ty),
right: { tag: "const", val: { tag: "int", value: 1 } },
},
});
return this.copyOrMoveLocal(local, ty);
}
case "tuple": {
const ty = this.ch.patTy(pat);
if (ty.kind.tag === "struct") {
const discrLocal = this.local(ty);
this.addStmt({
tag: "assign",
place: { local: discrLocal, proj: [] },
rval: discr,
});
const condLocals: LocalId[] = [];
for (const [fieldIdx, pat] of k.elems.entries()) {
if (ty.kind.data.tag !== "tuple") {
throw new Error();
}
const elemTy = ty.kind.data.elems[fieldIdx].ty;
const condOperand = this.lowerMatchArmPatternCondition({
tag: "use",
operand: {
tag: "move",
place: {
local: discrLocal,
proj: [{ tag: "field", fieldIdx }],
},
},
}, pat);
const condLocal = this.local(Ty({ tag: "int" }));
this.addStmt({
tag: "assign",
place: { local: condLocal, proj: [] },
rval: { tag: "use", operand: condOperand },
});
condLocals.push(condLocal);
}
const condRVal = condLocals
.reduce((condRVal, condLocal) => {
const local = this.local(Ty({ tag: "int" }));
});
}
return todo();
}
case "struct":
return todo();
}
exhausted(k);
}
private lowerMatchArmPatternBindings(
discr: RVal,
pat: ast.Pat,
) { ) {
const k = pat.kind; const k = pat.kind;
switch (k.tag) { switch (k.tag) {
@ -601,14 +704,14 @@ export class FnLowerer {
place: { local, proj: [] }, place: { local, proj: [] },
rval: discr, rval: discr,
}); });
this.setTer({ tag: "goto", target: truthyBlock.id });
return; return;
} }
case "path": case "path":
return;
case "bool":
return;
case "tuple":
return todo(); return todo();
case "tuple": {
return todo();
}
case "struct": case "struct":
return todo(); return todo();
} }

View File

@ -1222,6 +1222,14 @@ export class Parser {
const ident = this.parseIdent(); const ident = this.parseIdent();
return this.pat({ tag: "bind", ident, mut: true }, begin); return this.pat({ tag: "bind", ident, mut: true }, begin);
} }
if (this.test("false")) {
this.step();
return this.pat({ tag: "bool", value: false }, begin);
}
if (this.test("true")) {
this.step();
return this.pat({ tag: "bool", value: true }, begin);
}
this.report(`expected pattern, got '${this.current().type}'`, begin); this.report(`expected pattern, got '${this.current().type}'`, begin);
this.step(); this.step();
return this.pat({ tag: "error" }, begin); return this.pat({ tag: "error" }, begin);

View File

@ -2,14 +2,25 @@
// #[builtin(Hello)] // #[builtin(Hello)]
// fn c_hello() -> int {} // fn c_hello() -> int {}
fn main() { struct A(bool, bool);
let mut a = 2;
if true {
a = 3;
} else {
fn main() {
//let mut a = 2;
//if true {
// a = 3;
//} else {
//
//}
//let b = a;
let a = A(true, false);
match a {
A(false, false) => {}
A(false, true) => {}
A(true, false) => {}
A(true, true) => {}
} }
let b = a;
} }

View File

@ -180,6 +180,8 @@ export class HirStringifyer {
}`; }`;
case "path": case "path":
return this.path(k.path); return this.path(k.path);
case "bool":
return k.value ? "true" : "false";
case "tuple": case "tuple":
return `${k.path && this.path(k.path) || ""}(${ return `${k.path && this.path(k.path) || ""}(${
k.elems.map((pat) => this.pat(pat, d)).join(", ") k.elems.map((pat) => this.pat(pat, d)).join(", ")