fix generics and stuff

This commit is contained in:
nora 2023-12-15 17:47:16 +01:00
parent 537c924a68
commit 1a0828bd32
8 changed files with 63 additions and 63 deletions

View file

@ -411,10 +411,6 @@ export type TypeKind<P extends Phase> =
generics: Type<P>[];
value: IdentWithRes<P>;
}
| {
kind: "list";
elem: Type<P>;
}
| {
kind: "tuple";
elems: Type<P>[];
@ -517,11 +513,6 @@ export type TyBool = {
kind: "bool";
};
export type TyList = {
kind: "list";
elem: Ty;
};
export type TyTuple = {
kind: "tuple";
elems: Ty[];
@ -549,7 +540,7 @@ export type TyStruct = {
params: string[];
args: Ty[];
_name: string;
fields: [string, Ty][];
fields_no_subst: [string, Ty][];
};
export type TyRawPtr = {
@ -582,7 +573,6 @@ export type Ty =
| TyInt
| TyI32
| TyBool
| TyList
| TyTuple
| TyFn
| TyVar
@ -607,6 +597,49 @@ export type TypeckResults = {
main: Resolution | undefined;
};
export function structFieldsSubstituted(ty: TyStruct): [string, Ty][] {
const args = ty.args;
return ty.fields_no_subst.map(([name, type]) => [
name,
substituteTy(args, type),
]);
}
// Substitute the parameter of a type. We are only able to handle one
// level of generic definitions, for example for fields the struct def or for exprs the function generics.
export function substituteTy(params: Ty[], ty: Ty): Ty {
const subst = (ty: Ty) => substituteTy(params, ty);
switch (ty.kind) {
case "param":
return params[ty.idx];
case "tuple":
return { ...ty, elems: ty.elems.map(subst) };
case "fn":
return {
...ty,
returnTy: subst(ty.returnTy),
params: ty.params.map(subst),
};
case "struct":
return {
...ty,
args: ty.args.map(subst),
};
case "rawptr":
return { ...ty, inner: subst(ty.inner) };
// Primitives
case "var":
case "string":
case "int":
case "i32":
case "bool":
case "never":
case "error":
return ty;
}
}
// folders
export type FoldFn<From, To> = (value: From) => To;
@ -894,13 +927,6 @@ export function superFoldType<From extends Phase, To extends Phase>(
span,
};
}
case "list": {
return {
kind: "list",
elem: folder.type(type.elem),
span,
};
}
case "tuple": {
return {
kind: "tuple",

View file

@ -8,7 +8,7 @@ it("should compute struct layout correctly", () => {
args: [],
params: [],
_name: "",
fields: [
fields_no_subst: [
["uwu", TY_I32],
["owo", TY_INT],
],
@ -55,7 +55,7 @@ it("should compute single field struct layout correctly", () => {
args: [],
params: [],
_name: "",
fields: [["owo", TY_INT]],
fields_no_subst: [["owo", TY_INT]],
};
const layout = layoutOfStruct(ty);

View file

@ -21,6 +21,7 @@ import {
varUnreachable,
TyRawPtr,
paramUnreachable,
structFieldsSubstituted,
} from "./ast";
import { GlobalContext } from "./context";
import { unreachable } from "./error";
@ -1247,8 +1248,6 @@ function argRetAbi(param: Ty): ArgRetAbi {
return ["i32"];
case "bool":
return ["i32"];
case "list":
todo("list abi");
case "tuple":
return param.elems.flatMap(argRetAbi);
case "struct":
@ -1304,8 +1303,6 @@ function wasmTypeForBody(ty: Ty): wasm.ValType[] {
return ["i32"];
case "bool":
return ["i32"];
case "list":
todo("list types");
case "tuple":
return ty.elems.flatMap(wasmTypeForBody);
case "fn":
@ -1344,7 +1341,8 @@ export function layoutOfStruct(ty_: TyStruct | TyRawPtr): StructLayout {
if (ty.kind !== "struct") {
unreachable("must be struct");
}
const fieldWasmTys = ty.fields.map(([, field]) => wasmTypeForBody(field));
const fieldTys = structFieldsSubstituted(ty).map(([_, ty]) => ty);
const fieldWasmTys = fieldTys.map((field) => wasmTypeForBody(field));
// TODO: Use the max alignment instead.
const align = fieldWasmTys.some((field) =>
@ -1359,7 +1357,7 @@ export function layoutOfStruct(ty_: TyStruct | TyRawPtr): StructLayout {
const fields: StructFieldLayout[] = fieldWasmTys.map((field, i) => {
const value: StructFieldLayout = {
types: [],
ty: ty.fields[i][1],
ty: fieldTys[i],
};
const types = field.map((type) => {
@ -1457,8 +1455,6 @@ function needsRefcount(ty: Ty): StructLayout | "string" | undefined {
return undefined;
case "struct":
return layoutOfStruct(ty);
case "list":
todo("no lists yet");
case "var":
varUnreachable();
default:

View file

@ -700,12 +700,6 @@ function parseType(t: State): [State, Type<Parsed>] {
},
];
}
case "[": {
let elem;
[t, elem] = parseType(t);
[t] = expectNext(t, "]");
return [t, { kind: "list", elem, span }];
}
case "(": {
// `()` is a the unit type, an empty tuple.
// `(T)` is just `T`

View file

@ -219,8 +219,6 @@ function printType(type: Type<AnyPhase>): string {
switch (type.kind) {
case "ident":
return printIdent(type.value);
case "list":
return `[${printType(type.elem)}]`;
case "tuple":
return `(${type.elems.map(printType).join(", ")})`;
case "rawptr":
@ -269,9 +267,6 @@ export function printTy(ty: Ty): string {
case "bool": {
return "Bool";
}
case "list": {
return `[${printTy(ty.elem)}]`;
}
case "tuple": {
return `(${ty.elems.map(printTy).join(", ")})`;
}

View file

@ -183,12 +183,6 @@ function lowerAstTy(cx: TypeckCtx, type: Type<Resolved>): Ty {
return ty;
}
case "list": {
return {
kind: "list",
elem: lowerAstTy(cx, type.elem),
};
}
case "tuple": {
return {
kind: "tuple",
@ -286,7 +280,7 @@ function typeOfItem(cx: TypeckCtx, itemId: ItemId, cause: Span): Ty {
params: item.generics.map((ident) => ident.name),
itemId: item.id,
_name: item.name,
fields: [
fields_no_subst: [
/*dummy*/
],
};
@ -297,7 +291,7 @@ function typeOfItem(cx: TypeckCtx, itemId: ItemId, cause: Span): Ty {
({ name, type }) => [name.name, lowerAstTy(cx, type)],
);
ty.fields = fields;
ty.fields_no_subst = fields;
break;
}
case "alias": {
@ -667,13 +661,6 @@ export class InferContext {
if (rhs.kind === "bool") return;
break;
}
case "list": {
if (rhs.kind === "list") {
this.assign(lhs.elem, rhs.elem, span);
return;
}
break;
}
case "tuple": {
if (rhs.kind === "tuple" && lhs.elems.length === rhs.elems.length) {
lhs.elems.forEach((lhs, i) => this.assign(lhs, rhs.elems[i], span));
@ -953,7 +940,7 @@ export function checkBody(
case "rawptr": {
let fields: [string, Ty][];
if (lhs.ty.kind === "struct") {
fields = lhs.ty.fields;
fields = lhs.ty.fields_no_subst;
} else if (lhs.ty.kind === "rawptr") {
let inner = fcx.infcx.resolveIfPossible(lhs.ty.inner);
if (inner.kind !== "struct") {
@ -967,7 +954,7 @@ export function checkBody(
ty = inner;
break;
} else {
fields = inner.fields;
fields = inner.fields_no_subst;
}
} else {
fields = [];
@ -1100,7 +1087,7 @@ export function checkBody(
const assignedFields = new Set();
fields.forEach(({ name, expr: field }, i) => {
const fieldIdx = structTy.fields.findIndex(
const fieldIdx = structTy.fields_no_subst.findIndex(
(def) => def[0] === name.name,
);
if (fieldIdx == -1) {
@ -1112,14 +1099,14 @@ export function checkBody(
),
);
}
const fieldTy = structTy.fields[fieldIdx];
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.forEach(([name]) => {
structTy.fields_no_subst.forEach(([name]) => {
if (!assignedFields.has(name)) {
missing.push(name);
}

View file

@ -1,4 +1,6 @@
function main() = (
let list = std.list.new();
std.list.push(list, 0);
);
//@check-pass
type A[T] = struct { a: T };
function main() = ;
function test(a: A[I32]) = ;