From dbd49d852f645d89fb18e96114bdb4378cc213f5 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sat, 16 Dec 2023 13:00:49 +0100 Subject: [PATCH] typeck refactors --- src/typeck/expr.ts | 182 ++++++++++++++++++++++++++------------------- src/typeck/item.ts | 3 +- test.nil | 15 ++-- 3 files changed, 113 insertions(+), 87 deletions(-) diff --git a/src/typeck/expr.ts b/src/typeck/expr.ts index 1d3817f..59cd660 100644 --- a/src/typeck/expr.ts +++ b/src/typeck/expr.ts @@ -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>( - ({ 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, + expr: ExprStructLiteral & Expr, +) { + const fields = expr.fields.map>( + ({ 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) { switch (expr.kind) { case "ident": diff --git a/src/typeck/item.ts b/src/typeck/item.ts index 856dd4a..b084d28 100644 --- a/src/typeck/item.ts +++ b/src/typeck/item.ts @@ -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): 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; diff --git a/test.nil b/test.nil index 9eff204..1a3619e 100644 --- a/test.nil +++ b/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;