mirror of
https://github.com/Noratrieb/riverdelta.git
synced 2026-01-14 08:25:02 +01:00
typeck refactors
This commit is contained in:
parent
b4fb837efe
commit
dbd49d852f
3 changed files with 113 additions and 87 deletions
|
|
@ -17,6 +17,7 @@ import {
|
|||
Typecked,
|
||||
mkDefaultFolder,
|
||||
superFoldExpr,
|
||||
ExprStructLiteral,
|
||||
} from "../ast";
|
||||
import { CompilerError, ErrorEmitted, Span, unreachable } from "../error";
|
||||
import { printTy } from "../printer";
|
||||
|
|
@ -45,27 +46,6 @@ type FuncCtx = {
|
|||
|
||||
type LoopState = { hasBreak: boolean; loopId: LoopId };
|
||||
|
||||
function typeOfValue(fcx: FuncCtx, res: Resolution, span: Span): Ty {
|
||||
switch (res.kind) {
|
||||
case "local": {
|
||||
const idx = fcx.localTys.length - 1 - res.index;
|
||||
return fcx.localTys[idx];
|
||||
}
|
||||
case "item": {
|
||||
return typeOfItem(fcx.cx, res.id, [], span);
|
||||
}
|
||||
case "builtin":
|
||||
return typeOfBuiltinValue(fcx, res.name, span);
|
||||
case "tyParam":
|
||||
return tyError(
|
||||
fcx.cx,
|
||||
new CompilerError(`type parameter cannot be used as value`, span),
|
||||
);
|
||||
case "error":
|
||||
return tyErrorFrom(res);
|
||||
}
|
||||
}
|
||||
|
||||
export function typeOfBuiltinValue(
|
||||
fcx: FuncCtx,
|
||||
name: BuiltinName,
|
||||
|
|
@ -257,7 +237,34 @@ export function checkBody(
|
|||
}
|
||||
case "ident":
|
||||
case "path": {
|
||||
const ty = typeOfValue(fcx, expr.value.res, expr.value.span);
|
||||
const { res, span } = expr.value;
|
||||
let ty: Ty;
|
||||
switch (res.kind) {
|
||||
case "local": {
|
||||
const idx = fcx.localTys.length - 1 - res.index;
|
||||
ty = fcx.localTys[idx];
|
||||
break;
|
||||
}
|
||||
case "item": {
|
||||
ty = typeOfItem(fcx.cx, res.id, [], span);
|
||||
break;
|
||||
}
|
||||
case "builtin":
|
||||
ty = typeOfBuiltinValue(fcx, res.name, span);
|
||||
break;
|
||||
case "tyParam":
|
||||
ty = tyError(
|
||||
fcx.cx,
|
||||
new CompilerError(
|
||||
`type parameter cannot be used as value`,
|
||||
span,
|
||||
),
|
||||
);
|
||||
break;
|
||||
case "error":
|
||||
ty = tyErrorFrom(res);
|
||||
break;
|
||||
}
|
||||
|
||||
return { ...expr, ty };
|
||||
}
|
||||
|
|
@ -437,61 +444,7 @@ export function checkBody(
|
|||
};
|
||||
}
|
||||
case "structLiteral": {
|
||||
const fields = expr.fields.map<StructLiteralField<Typecked>>(
|
||||
({ name, expr }) => ({ name, expr: this.expr(expr) }),
|
||||
);
|
||||
|
||||
const structTy = typeOfValue(fcx, expr.name.res, expr.name.span);
|
||||
|
||||
if (structTy.kind !== "struct") {
|
||||
const err: ErrorEmitted = emitError(
|
||||
fcx.cx,
|
||||
new CompilerError(
|
||||
`struct literal is only allowed for struct types`,
|
||||
expr.span,
|
||||
),
|
||||
);
|
||||
return exprError(err, expr.span);
|
||||
}
|
||||
|
||||
const assignedFields = new Set();
|
||||
|
||||
fields.forEach(({ name, expr: field }, i) => {
|
||||
const fieldIdx = structTy.fields_no_subst.findIndex(
|
||||
(def) => def[0] === name.name,
|
||||
);
|
||||
if (fieldIdx == -1) {
|
||||
emitError(
|
||||
fcx.cx,
|
||||
new CompilerError(
|
||||
`field ${name.name} doesn't exist on type ${expr.name.name}`,
|
||||
name.span,
|
||||
),
|
||||
);
|
||||
}
|
||||
const fieldTy = structTy.fields_no_subst[fieldIdx];
|
||||
infcx.assign(fieldTy[1], field.ty, field.span);
|
||||
assignedFields.add(name.name);
|
||||
fields[i].fieldIdx = fieldIdx;
|
||||
});
|
||||
|
||||
const missing: string[] = [];
|
||||
structTy.fields_no_subst.forEach(([name]) => {
|
||||
if (!assignedFields.has(name)) {
|
||||
missing.push(name);
|
||||
}
|
||||
});
|
||||
if (missing.length > 0) {
|
||||
emitError(
|
||||
fcx.cx,
|
||||
new CompilerError(
|
||||
`missing fields in literal: ${missing.join(", ")}`,
|
||||
expr.span,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return { ...expr, fields, ty: structTy };
|
||||
return checkStructLiteral(fcx, this, expr);
|
||||
}
|
||||
case "tupleLiteral": {
|
||||
const fields = expr.fields.map((expr) => this.expr(expr));
|
||||
|
|
@ -617,6 +570,81 @@ function checkInlineAsm(
|
|||
return { kind: "asm", locals, ty: retTy, instructions, span: body.span };
|
||||
}
|
||||
|
||||
function checkStructLiteral(
|
||||
fcx: FuncCtx,
|
||||
self: Folder<Resolved, Typecked>,
|
||||
expr: ExprStructLiteral<Resolved> & Expr<Resolved>,
|
||||
) {
|
||||
const fields = expr.fields.map<StructLiteralField<Typecked>>(
|
||||
({ name, expr }) => ({ name, expr: self.expr(expr) }),
|
||||
);
|
||||
|
||||
const { name } = expr;
|
||||
|
||||
if (name.res.kind !== "item") {
|
||||
return exprError(
|
||||
emitError(
|
||||
fcx.cx,
|
||||
new CompilerError("struct literal must be struct type", name.span),
|
||||
),
|
||||
name.span,
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Handle generic arugments
|
||||
const structTy = typeOfItem(fcx.cx, name.res.id, [], name.span);
|
||||
|
||||
if (structTy.kind !== "struct") {
|
||||
const err: ErrorEmitted = emitError(
|
||||
fcx.cx,
|
||||
new CompilerError(
|
||||
`struct literal is only allowed for struct types`,
|
||||
expr.span,
|
||||
),
|
||||
);
|
||||
return exprError(err, expr.span);
|
||||
}
|
||||
|
||||
const assignedFields = new Set();
|
||||
|
||||
fields.forEach(({ name, expr: field }, i) => {
|
||||
const fieldIdx = structTy.fields_no_subst.findIndex(
|
||||
(def) => def[0] === name.name,
|
||||
);
|
||||
if (fieldIdx == -1) {
|
||||
emitError(
|
||||
fcx.cx,
|
||||
new CompilerError(
|
||||
`field ${name.name} doesn't exist on type ${name.name}`,
|
||||
name.span,
|
||||
),
|
||||
);
|
||||
}
|
||||
const fieldTy = structTy.fields_no_subst[fieldIdx];
|
||||
fcx.infcx.assign(fieldTy[1], field.ty, field.span);
|
||||
assignedFields.add(name.name);
|
||||
fields[i].fieldIdx = fieldIdx;
|
||||
});
|
||||
|
||||
const missing: string[] = [];
|
||||
structTy.fields_no_subst.forEach(([name]) => {
|
||||
if (!assignedFields.has(name)) {
|
||||
missing.push(name);
|
||||
}
|
||||
});
|
||||
if (missing.length > 0) {
|
||||
emitError(
|
||||
fcx.cx,
|
||||
new CompilerError(
|
||||
`missing fields in literal: ${missing.join(", ")}`,
|
||||
expr.span,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return { ...expr, fields, ty: structTy };
|
||||
}
|
||||
|
||||
function checkLValue(cx: TypeckCtx, expr: Expr<Typecked>) {
|
||||
switch (expr.kind) {
|
||||
case "ident":
|
||||
|
|
|
|||
|
|
@ -28,8 +28,9 @@ function builtinAsTy(cx: TypeckCtx, name: string, span: Span): Ty {
|
|||
* Lowers the AST representation of a type into its resolved Ty representation.
|
||||
* Will also validate the type, for example ensuring that generic arguments match up.
|
||||
*/
|
||||
// TODO: Cleanup, maybe get the ident switch into this function because typeOfItem is unused.
|
||||
export function lowerAstTy(cx: TypeckCtx, type: Type<Resolved>): Ty {
|
||||
// This function is called for every syntactical type in the program.
|
||||
// Could be a function argument, but also a struct field or a local variable annotation.
|
||||
switch (type.kind) {
|
||||
case "ident": {
|
||||
const ident = type.value;
|
||||
|
|
|
|||
15
test.nil
15
test.nil
|
|
@ -1,11 +1,8 @@
|
|||
function main() = ;
|
||||
|
||||
function memcpy(dst: I32, src: I32, n: I32) =
|
||||
___asm(
|
||||
__locals(),
|
||||
"local.get 2",
|
||||
"local.get 1",
|
||||
"local.get 0",
|
||||
"memory.copy",
|
||||
)
|
||||
;
|
||||
type A[T] = T;
|
||||
type B[T] = struct { a: T };
|
||||
|
||||
//function ohno(x: A[A[A[I32]]]): I32 = x;
|
||||
|
||||
function generic(a: B[I32]): B[I32] = a;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue