move constant tys

This commit is contained in:
nora 2023-12-16 12:44:30 +01:00
parent d18ab34e9f
commit b4fb837efe
10 changed files with 71 additions and 75 deletions

View file

@ -508,7 +508,6 @@ export type LocalInfo = {
// types // types
// folders // folders
export type FoldFn<From, To> = (value: From) => To; export type FoldFn<From, To> = (value: From) => To;

View file

@ -1,6 +1,6 @@
import { ItemId } from "./ast"; import { ItemId } from "./ast";
import { layoutOfStruct } from "./codegen"; import { layoutOfStruct } from "./codegen";
import { TY_I32, TY_INT, TyStruct } from "./types"; import { TYS, TyStruct } from "./types";
it("should compute struct layout correctly", () => { it("should compute struct layout correctly", () => {
const ty: TyStruct = { const ty: TyStruct = {
@ -10,8 +10,8 @@ it("should compute struct layout correctly", () => {
params: [], params: [],
_name: "", _name: "",
fields_no_subst: [ fields_no_subst: [
["uwu", TY_I32], ["uwu", TYS.I32],
["owo", TY_INT], ["owo", TYS.INT],
], ],
}; };
@ -56,7 +56,7 @@ it("should compute single field struct layout correctly", () => {
genericArgs: [], genericArgs: [],
params: [], params: [],
_name: "", _name: "",
fields_no_subst: [["owo", TY_INT]], fields_no_subst: [["owo", TYS.INT]],
}; };
const layout = layoutOfStruct(ty); const layout = layoutOfStruct(ty);

View file

@ -20,7 +20,14 @@ import {
import { GlobalContext } from "./context"; import { GlobalContext } from "./context";
import { unreachable } from "./error"; import { unreachable } from "./error";
import { printTy } from "./printer"; import { printTy } from "./printer";
import { Ty, TyFn, TyRawPtr, TyStruct, TyTuple, structFieldsSubstituted } from "./types"; import {
Ty,
TyFn,
TyRawPtr,
TyStruct,
TyTuple,
structFieldsSubstituted,
} from "./types";
import { ComplexMap, encodeUtf8, unwrap } from "./utils"; import { ComplexMap, encodeUtf8, unwrap } from "./utils";
import * as wasm from "./wasm/defs"; import * as wasm from "./wasm/defs";

View file

@ -91,9 +91,7 @@ export const loadPkg: PkgLoader = (
span: Span, span: Span,
): DepPkg => { ): DepPkg => {
// If we've loaded the pkg already, great. // If we've loaded the pkg already, great.
const existing = gcx.finalizedPkgs.find( const existing = gcx.finalizedPkgs.find((pkg) => pkg.packageName === name);
(pkg) => pkg.packageName === name,
);
if (existing) { if (existing) {
return existing; return existing;
} }

View file

@ -63,10 +63,7 @@ function resolveModItem(
return contents.get(name); return contents.get(name);
} }
export function resolve( export function resolve(gcx: GlobalContext, ast: Pkg<Built>): Pkg<Resolved> {
gcx: GlobalContext,
ast: Pkg<Built>,
): Pkg<Resolved> {
const cx: Context = { const cx: Context = {
ast, ast,
gcx, gcx,

View file

@ -20,7 +20,7 @@ import {
} from "../ast"; } from "../ast";
import { CompilerError, ErrorEmitted, Span, unreachable } from "../error"; import { CompilerError, ErrorEmitted, Span, unreachable } from "../error";
import { printTy } from "../printer"; import { printTy } from "../printer";
import { TY_BOOL, TY_I32, TY_INT, TY_NEVER, TY_STRING, TY_UNIT, Ty, TyFn } from "../types"; import { TYS, Ty, TyFn } from "../types";
import { INSTRS, Instr, VALTYPES, ValType } from "../wasm/defs"; import { INSTRS, Instr, VALTYPES, ValType } from "../wasm/defs";
import { TypeckCtx, emitError, mkTyFn, tyError, tyErrorFrom } from "./base"; import { TypeckCtx, emitError, mkTyFn, tyError, tyErrorFrom } from "./base";
import { InferContext } from "./infer"; import { InferContext } from "./infer";
@ -74,27 +74,27 @@ export function typeOfBuiltinValue(
switch (name) { switch (name) {
case "false": case "false":
case "true": case "true":
return TY_BOOL; return TYS.BOOL;
case "print": case "print":
return mkTyFn([TY_STRING], TY_UNIT); return mkTyFn([TYS.STRING], TYS.UNIT);
case "trap": case "trap":
return mkTyFn([], TY_NEVER); return mkTyFn([], TYS.NEVER);
case "__NULL": case "__NULL":
return { kind: "rawptr", inner: fcx.infcx.newVar() }; return { kind: "rawptr", inner: fcx.infcx.newVar() };
case "__i32_store": case "__i32_store":
return mkTyFn([TY_I32, TY_I32], TY_UNIT); return mkTyFn([TYS.I32, TYS.I32], TYS.UNIT);
case "__i64_store": case "__i64_store":
return mkTyFn([TY_I32, TY_INT], TY_UNIT); return mkTyFn([TYS.I32, TYS.INT], TYS.UNIT);
case "__i32_load": case "__i32_load":
return mkTyFn([TY_I32], TY_I32); return mkTyFn([TYS.I32], TYS.I32);
case "__i64_load": case "__i64_load":
return mkTyFn([TY_I32], TY_INT); return mkTyFn([TYS.I32], TYS.INT);
case "__memory_size": case "__memory_size":
return mkTyFn([], TY_I32); return mkTyFn([], TYS.I32);
case "__memory_grow": case "__memory_grow":
return mkTyFn([TY_I32], TY_I32); return mkTyFn([TYS.I32], TYS.I32);
case "__i32_extend_to_i64_u": case "__i32_extend_to_i64_u":
return mkTyFn([TY_I32], TY_INT); return mkTyFn([TYS.I32], TYS.INT);
default: { default: {
return tyError( return tyError(
fcx.cx, fcx.cx,
@ -134,7 +134,7 @@ export function checkBody(
expr(expr): Expr<Typecked> { expr(expr): Expr<Typecked> {
switch (expr.kind) { switch (expr.kind) {
case "empty": { case "empty": {
return { ...expr, ty: TY_UNIT }; return { ...expr, ty: TYS.UNIT };
} }
case "let": { case "let": {
const loweredBindingTy = expr.type && lowerAstTy(cx, expr.type); const loweredBindingTy = expr.type && lowerAstTy(cx, expr.type);
@ -160,7 +160,7 @@ export function checkBody(
name: expr.name, name: expr.name,
type, type,
rhs, rhs,
ty: TY_UNIT, ty: TYS.UNIT,
span: expr.span, span: expr.span,
}; };
} }
@ -215,7 +215,7 @@ export function checkBody(
kind: "assign", kind: "assign",
lhs, lhs,
rhs, rhs,
ty: TY_UNIT, ty: TYS.UNIT,
}; };
} }
case "block": { case "block": {
@ -223,7 +223,7 @@ export function checkBody(
const exprs = expr.exprs.map((expr) => this.expr(expr)); const exprs = expr.exprs.map((expr) => this.expr(expr));
const ty = exprs.length > 0 ? exprs[exprs.length - 1].ty : TY_UNIT; const ty = exprs.length > 0 ? exprs[exprs.length - 1].ty : TYS.UNIT;
fcx.localTys.length = prevLocalTysLen; fcx.localTys.length = prevLocalTysLen;
@ -237,16 +237,16 @@ export function checkBody(
let ty; let ty;
switch (expr.value.kind) { switch (expr.value.kind) {
case "str": { case "str": {
ty = TY_STRING; ty = TYS.STRING;
break; break;
} }
case "int": { case "int": {
switch (expr.value.type) { switch (expr.value.type) {
case "Int": case "Int":
ty = TY_INT; ty = TYS.INT;
break; break;
case "I32": case "I32":
ty = TY_I32; ty = TYS.I32;
break; break;
} }
break; break;
@ -387,15 +387,15 @@ export function checkBody(
const then = this.expr(expr.then); const then = this.expr(expr.then);
const elsePart = expr.else && this.expr(expr.else); const elsePart = expr.else && this.expr(expr.else);
infcx.assign(TY_BOOL, cond.ty, cond.span); infcx.assign(TYS.BOOL, cond.ty, cond.span);
let ty: Ty; let ty: Ty;
if (elsePart) { if (elsePart) {
infcx.assign(then.ty, elsePart.ty, elsePart.span); infcx.assign(then.ty, elsePart.ty, elsePart.span);
ty = then.ty!; ty = then.ty!;
} else { } else {
infcx.assign(TY_UNIT, then.ty, then.span); infcx.assign(TYS.UNIT, then.ty, then.span);
ty = TY_UNIT; ty = TYS.UNIT;
} }
return { ...expr, cond, then, else: elsePart, ty }; return { ...expr, cond, then, else: elsePart, ty };
@ -407,10 +407,10 @@ export function checkBody(
}); });
const body = this.expr(expr.body); const body = this.expr(expr.body);
infcx.assign(TY_UNIT, body.ty, body.span); infcx.assign(TYS.UNIT, body.ty, body.span);
const hadBreak = fcx.loopState.pop(); const hadBreak = fcx.loopState.pop();
const ty = hadBreak ? TY_UNIT : TY_NEVER; const ty = hadBreak ? TYS.UNIT : TYS.NEVER;
return { return {
...expr, ...expr,
@ -432,7 +432,7 @@ export function checkBody(
return { return {
...expr, ...expr,
ty: TY_NEVER, ty: TYS.NEVER,
target, target,
}; };
} }
@ -648,39 +648,39 @@ function checkBinary(
if (COMPARISON_KINDS.includes(expr.binaryKind)) { if (COMPARISON_KINDS.includes(expr.binaryKind)) {
if (lhsTy.kind === "int" && rhsTy.kind === "int") { if (lhsTy.kind === "int" && rhsTy.kind === "int") {
return { ...expr, lhs, rhs, ty: TY_BOOL }; return { ...expr, lhs, rhs, ty: TYS.BOOL };
} }
if (lhsTy.kind === "i32" && rhsTy.kind === "i32") { if (lhsTy.kind === "i32" && rhsTy.kind === "i32") {
return { ...expr, lhs, rhs, ty: TY_BOOL }; return { ...expr, lhs, rhs, ty: TYS.BOOL };
} }
if (lhsTy.kind === "string" && rhsTy.kind === "string") { if (lhsTy.kind === "string" && rhsTy.kind === "string") {
return { ...expr, lhs, rhs, ty: TY_BOOL }; return { ...expr, lhs, rhs, ty: TYS.BOOL };
} }
if (lhsTy.kind === "rawptr" && rhsTy.kind === "rawptr") { if (lhsTy.kind === "rawptr" && rhsTy.kind === "rawptr") {
fcx.infcx.assign(lhsTy.inner, rhsTy.inner, expr.span); fcx.infcx.assign(lhsTy.inner, rhsTy.inner, expr.span);
return { ...expr, lhs, rhs, ty: TY_BOOL }; return { ...expr, lhs, rhs, ty: TYS.BOOL };
} }
if (EQUALITY_KINDS.includes(expr.binaryKind)) { if (EQUALITY_KINDS.includes(expr.binaryKind)) {
if (lhsTy.kind === "bool" && rhsTy.kind === "bool") { if (lhsTy.kind === "bool" && rhsTy.kind === "bool") {
return { ...expr, lhs, rhs, ty: TY_BOOL }; return { ...expr, lhs, rhs, ty: TYS.BOOL };
} }
} }
} }
if (lhsTy.kind === "int" && rhsTy.kind === "int") { if (lhsTy.kind === "int" && rhsTy.kind === "int") {
return { ...expr, lhs, rhs, ty: TY_INT }; return { ...expr, lhs, rhs, ty: TYS.INT };
} }
if (lhsTy.kind === "i32" && rhsTy.kind === "i32") { if (lhsTy.kind === "i32" && rhsTy.kind === "i32") {
return { ...expr, lhs, rhs, ty: TY_I32 }; return { ...expr, lhs, rhs, ty: TYS.I32 };
} }
if (LOGICAL_KINDS.includes(expr.binaryKind)) { if (LOGICAL_KINDS.includes(expr.binaryKind)) {
if (lhsTy.kind === "bool" && rhsTy.kind === "bool") { if (lhsTy.kind === "bool" && rhsTy.kind === "bool") {
return { ...expr, lhs, rhs, ty: TY_BOOL }; return { ...expr, lhs, rhs, ty: TYS.BOOL };
} }
} }
@ -734,7 +734,7 @@ function checkCall(
const args = expr.args.map((arg) => fcx.checkExpr(arg)); const args = expr.args.map((arg) => fcx.checkExpr(arg));
const ret: Expr<Typecked> = { const ret: Expr<Typecked> = {
...expr, ...expr,
lhs: { ...expr.lhs, ty: TY_UNIT }, lhs: { ...expr.lhs, ty: TYS.UNIT },
args, args,
ty, ty,
}; };

View file

@ -11,17 +11,14 @@ import {
} from "../ast"; } from "../ast";
import { GlobalContext } from "../context"; import { GlobalContext } from "../context";
import { CompilerError, ErrorEmitted, Span } from "../error"; import { CompilerError, ErrorEmitted, Span } from "../error";
import { TY_I32, TY_INT, Ty, TyFn, tyIsUnit } from "../types"; import { TYS, Ty, TyFn, tyIsUnit } from "../types";
import { ComplexMap } from "../utils"; import { ComplexMap } from "../utils";
import { emitError } from "./base"; import { emitError } from "./base";
import { checkBody, exprError } from "./expr"; import { checkBody, exprError } from "./expr";
import { InferContext } from "./infer"; import { InferContext } from "./infer";
import { typeOfItem } from "./item"; import { typeOfItem } from "./item";
export function typeck( export function typeck(gcx: GlobalContext, ast: Pkg<Resolved>): Pkg<Typecked> {
gcx: GlobalContext,
ast: Pkg<Resolved>,
): Pkg<Typecked> {
const cx = { const cx = {
gcx, gcx,
itemTys: new ComplexMap<ItemId, Ty | null>(), itemTys: new ComplexMap<ItemId, Ty | null>(),
@ -152,7 +149,7 @@ export function typeck(
); );
initChecked = exprError(err, init.span); initChecked = exprError(err, init.span);
} else { } else {
const initTy = init.value.type === "I32" ? TY_I32 : TY_INT; const initTy = init.value.type === "I32" ? TYS.I32 : TYS.INT;
const infcx = new InferContext(cx.gcx.error); const infcx = new InferContext(cx.gcx.error);
infcx.assign(ty, initTy, init.span); infcx.assign(ty, initTy, init.span);
initChecked = { ...init, ty }; initChecked = { ...init, ty };

View file

@ -1,5 +1,5 @@
import { Emitter, ErrorHandler, Span } from "../error"; import { Emitter, ErrorHandler, Span } from "../error";
import { TY_INT, TY_STRING, TY_UNIT } from "../types"; import { TYS } from "../types";
import { InferContext } from "./infer"; import { InferContext } from "./infer";
const SPAN: Span = Span.startOfFile({ content: "" }); const SPAN: Span = Span.startOfFile({ content: "" });
@ -16,7 +16,7 @@ it("should infer types across assignments", () => {
infcx.assign(a, b, SPAN); infcx.assign(a, b, SPAN);
infcx.assign(b, c, SPAN); infcx.assign(b, c, SPAN);
infcx.assign(a, TY_INT, SPAN); infcx.assign(a, TYS.INT, SPAN);
const aTy = infcx.resolveIfPossible(c); const aTy = infcx.resolveIfPossible(c);
const bTy = infcx.resolveIfPossible(c); const bTy = infcx.resolveIfPossible(c);
@ -36,11 +36,11 @@ it("should conflict assignments to resolvable type vars", () => {
const b = infcx.newVar(); const b = infcx.newVar();
infcx.assign(a, b, SPAN); infcx.assign(a, b, SPAN);
infcx.assign(b, TY_INT, SPAN); infcx.assign(b, TYS.INT, SPAN);
expect(errorLines).toEqual(0); expect(errorLines).toEqual(0);
infcx.assign(a, TY_STRING, SPAN); infcx.assign(a, TYS.STRING, SPAN);
expect(errorLines).toBeGreaterThan(0); expect(errorLines).toBeGreaterThan(0);
}); });
@ -57,7 +57,7 @@ it("should not cycle", () => {
const aType = infcx.resolveIfPossible(a); const aType = infcx.resolveIfPossible(a);
expect(aType.kind).toEqual("var"); expect(aType.kind).toEqual("var");
infcx.assign(a, TY_UNIT, SPAN); infcx.assign(a, TYS.UNIT, SPAN);
const bType = infcx.resolveIfPossible(b); const bType = infcx.resolveIfPossible(b);
expect(bType.kind).toEqual("tuple"); expect(bType.kind).toEqual("tuple");

View file

@ -1,26 +1,22 @@
import { import { ItemId, Resolved, Type } from "../ast";
ItemId,
Resolved,
Type,
} from "../ast";
import { CompilerError, Span } from "../error"; import { CompilerError, Span } from "../error";
import { printTy } from "../printer"; import { printTy } from "../printer";
import { TY_BOOL, TY_I32, TY_INT, TY_NEVER, TY_STRING, TY_UNIT, Ty, substituteTy } from "../types"; import { TYS, Ty, substituteTy } from "../types";
import { TypeckCtx, tyError, tyErrorFrom } from "./base"; import { TypeckCtx, tyError, tyErrorFrom } from "./base";
function builtinAsTy(cx: TypeckCtx, name: string, span: Span): Ty { function builtinAsTy(cx: TypeckCtx, name: string, span: Span): Ty {
switch (name) { switch (name) {
case "String": { case "String": {
return TY_STRING; return TYS.STRING;
} }
case "Int": { case "Int": {
return TY_INT; return TYS.INT;
} }
case "I32": { case "I32": {
return TY_I32; return TYS.I32;
} }
case "Bool": { case "Bool": {
return TY_BOOL; return TYS.BOOL;
} }
default: { default: {
return tyError(cx, new CompilerError(`\`${name}\` is not a type`, span)); return tyError(cx, new CompilerError(`\`${name}\` is not a type`, span));
@ -110,7 +106,7 @@ export function lowerAstTy(cx: TypeckCtx, type: Type<Resolved>): Ty {
return { kind: "rawptr", inner }; return { kind: "rawptr", inner };
} }
case "never": { case "never": {
return TY_NEVER; return TYS.NEVER;
} }
case "error": { case "error": {
return tyErrorFrom(type); return tyErrorFrom(type);
@ -180,7 +176,7 @@ export function typeOfItem(
const args = item.params.map((arg) => lowerAstTy(cx, arg.type)); const args = item.params.map((arg) => lowerAstTy(cx, arg.type));
const returnTy: Ty = item.returnType const returnTy: Ty = item.returnType
? lowerAstTy(cx, item.returnType) ? lowerAstTy(cx, item.returnType)
: TY_UNIT; : TYS.UNIT;
ty = { kind: "fn", params: args, returnTy }; ty = { kind: "fn", params: args, returnTy };
break; break;

View file

@ -98,12 +98,14 @@ export function tyIsUnit(ty: Ty): ty is TyUnit {
return ty.kind === "tuple" && ty.elems.length === 0; return ty.kind === "tuple" && ty.elems.length === 0;
} }
export const TY_UNIT: Ty = { kind: "tuple", elems: [] }; export const TYS = {
export const TY_STRING: Ty = { kind: "string" }; UNIT: { kind: "tuple", elems: [] } as Ty,
export const TY_BOOL: Ty = { kind: "bool" }; STRING: { kind: "string" } as Ty,
export const TY_INT: Ty = { kind: "int" }; BOOL: { kind: "bool" } as Ty,
export const TY_I32: Ty = { kind: "i32" }; INT: { kind: "int" } as Ty,
export const TY_NEVER: Ty = { kind: "never" }; I32: { kind: "i32" } as Ty,
NEVER: { kind: "never" } as Ty,
} as const;
export type TypeckResults = { export type TypeckResults = {
main: Resolution | undefined; main: Resolution | undefined;