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>[]; generics: Type<P>[];
value: IdentWithRes<P>; value: IdentWithRes<P>;
} }
| {
kind: "list";
elem: Type<P>;
}
| { | {
kind: "tuple"; kind: "tuple";
elems: Type<P>[]; elems: Type<P>[];
@ -517,11 +513,6 @@ export type TyBool = {
kind: "bool"; kind: "bool";
}; };
export type TyList = {
kind: "list";
elem: Ty;
};
export type TyTuple = { export type TyTuple = {
kind: "tuple"; kind: "tuple";
elems: Ty[]; elems: Ty[];
@ -549,7 +540,7 @@ export type TyStruct = {
params: string[]; params: string[];
args: Ty[]; args: Ty[];
_name: string; _name: string;
fields: [string, Ty][]; fields_no_subst: [string, Ty][];
}; };
export type TyRawPtr = { export type TyRawPtr = {
@ -582,7 +573,6 @@ export type Ty =
| TyInt | TyInt
| TyI32 | TyI32
| TyBool | TyBool
| TyList
| TyTuple | TyTuple
| TyFn | TyFn
| TyVar | TyVar
@ -607,6 +597,49 @@ export type TypeckResults = {
main: Resolution | undefined; 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 // folders
export type FoldFn<From, To> = (value: From) => To; export type FoldFn<From, To> = (value: From) => To;
@ -894,13 +927,6 @@ export function superFoldType<From extends Phase, To extends Phase>(
span, span,
}; };
} }
case "list": {
return {
kind: "list",
elem: folder.type(type.elem),
span,
};
}
case "tuple": { case "tuple": {
return { return {
kind: "tuple", kind: "tuple",

View file

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

View file

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

View file

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

View file

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

View file

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