mirror of
https://github.com/Noratrieb/riverdelta.git
synced 2026-01-14 16:35:03 +01:00
make generics worse
This commit is contained in:
parent
1a0828bd32
commit
5fefc46402
7 changed files with 107 additions and 73 deletions
31
src/ast.ts
31
src/ast.ts
|
|
@ -538,7 +538,7 @@ export type TyStruct = {
|
|||
kind: "struct";
|
||||
itemId: ItemId;
|
||||
params: string[];
|
||||
args: Ty[];
|
||||
genericArgs: Ty[];
|
||||
_name: string;
|
||||
fields_no_subst: [string, Ty][];
|
||||
};
|
||||
|
|
@ -563,6 +563,13 @@ export type TyParam = {
|
|||
name: string;
|
||||
};
|
||||
|
||||
export type TyAlias = {
|
||||
kind: "alias";
|
||||
actual: Ty;
|
||||
genericArgs: Ty[];
|
||||
params: string[];
|
||||
};
|
||||
|
||||
export type TyError = {
|
||||
kind: "error";
|
||||
err: ErrorEmitted;
|
||||
|
|
@ -580,6 +587,7 @@ export type Ty =
|
|||
| TyRawPtr
|
||||
| TyNever
|
||||
| TyParam
|
||||
| TyAlias
|
||||
| TyError;
|
||||
|
||||
export function tyIsUnit(ty: Ty): ty is TyUnit {
|
||||
|
|
@ -598,7 +606,7 @@ export type TypeckResults = {
|
|||
};
|
||||
|
||||
export function structFieldsSubstituted(ty: TyStruct): [string, Ty][] {
|
||||
const args = ty.args;
|
||||
const args = ty.genericArgs;
|
||||
return ty.fields_no_subst.map(([name, type]) => [
|
||||
name,
|
||||
substituteTy(args, type),
|
||||
|
|
@ -607,12 +615,16 @@ export function structFieldsSubstituted(ty: TyStruct): [string, Ty][] {
|
|||
|
||||
// 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);
|
||||
|
||||
export function substituteTy(genericArgs: Ty[], ty: Ty): Ty {
|
||||
const subst = (ty: Ty) => substituteTy(genericArgs, ty);
|
||||
switch (ty.kind) {
|
||||
case "param":
|
||||
return params[ty.idx];
|
||||
if (ty.idx >= genericArgs.length) {
|
||||
throw new Error(
|
||||
`substitution out of range, param index ${ty.idx} of param ${ty.name} out of range for length ${genericArgs.length}`,
|
||||
);
|
||||
}
|
||||
return genericArgs[ty.idx];
|
||||
case "tuple":
|
||||
return { ...ty, elems: ty.elems.map(subst) };
|
||||
case "fn":
|
||||
|
|
@ -622,9 +634,10 @@ export function substituteTy(params: Ty[], ty: Ty): Ty {
|
|||
params: ty.params.map(subst),
|
||||
};
|
||||
case "struct":
|
||||
case "alias":
|
||||
return {
|
||||
...ty,
|
||||
args: ty.args.map(subst),
|
||||
genericArgs: ty.genericArgs.map(subst),
|
||||
};
|
||||
case "rawptr":
|
||||
return { ...ty, inner: subst(ty.inner) };
|
||||
|
|
@ -952,6 +965,6 @@ export function varUnreachable(): never {
|
|||
unreachable("Type variables must not occur after type checking");
|
||||
}
|
||||
|
||||
export function paramUnreachable(): never {
|
||||
unreachable("Type parameters must not occur after monomophization");
|
||||
export function paramUnreachable(ty: Ty): never {
|
||||
unreachable(`type ${ty.kind} should never occur in codegen`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ it("should compute struct layout correctly", () => {
|
|||
const ty: TyStruct = {
|
||||
kind: "struct",
|
||||
itemId: ItemId.dummy(),
|
||||
args: [],
|
||||
genericArgs: [],
|
||||
params: [],
|
||||
_name: "",
|
||||
fields_no_subst: [
|
||||
|
|
@ -52,7 +52,7 @@ it("should compute single field struct layout correctly", () => {
|
|||
const ty: TyStruct = {
|
||||
kind: "struct",
|
||||
itemId: ItemId.dummy(),
|
||||
args: [],
|
||||
genericArgs: [],
|
||||
params: [],
|
||||
_name: "",
|
||||
fields_no_subst: [["owo", TY_INT]],
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import {
|
|||
superFoldItem,
|
||||
varUnreachable,
|
||||
TyRawPtr,
|
||||
paramUnreachable,
|
||||
paramUnreachable as codegenUnreachableTy,
|
||||
structFieldsSubstituted,
|
||||
} from "./ast";
|
||||
import { GlobalContext } from "./context";
|
||||
|
|
@ -1256,11 +1256,10 @@ function argRetAbi(param: Ty): ArgRetAbi {
|
|||
case "never":
|
||||
return [];
|
||||
case "var":
|
||||
varUnreachable();
|
||||
case "param":
|
||||
paramUnreachable();
|
||||
case "alias":
|
||||
case "error":
|
||||
unreachable("codegen should not see errors");
|
||||
codegenUnreachableTy(param);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1313,11 +1312,10 @@ function wasmTypeForBody(ty: Ty): wasm.ValType[] {
|
|||
case "never":
|
||||
return [];
|
||||
case "var":
|
||||
varUnreachable();
|
||||
case "param":
|
||||
paramUnreachable();
|
||||
case "alias":
|
||||
case "error":
|
||||
unreachable("codegen should not see errors");
|
||||
codegenUnreachableTy(ty);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import {
|
|||
Type,
|
||||
ItemType,
|
||||
tyIsUnit,
|
||||
substituteTy,
|
||||
} from "./ast";
|
||||
|
||||
export function printAst(ast: Crate<AnyPhase>): string {
|
||||
|
|
@ -255,40 +256,32 @@ function printIdent(ident: IdentWithRes<AnyPhase>): string {
|
|||
|
||||
export function printTy(ty: Ty): string {
|
||||
switch (ty.kind) {
|
||||
case "string": {
|
||||
case "string":
|
||||
return "String";
|
||||
}
|
||||
case "int": {
|
||||
case "int":
|
||||
return "Int";
|
||||
}
|
||||
case "i32": {
|
||||
case "i32":
|
||||
return "I32";
|
||||
}
|
||||
case "bool": {
|
||||
case "bool":
|
||||
return "Bool";
|
||||
}
|
||||
case "tuple": {
|
||||
case "tuple":
|
||||
return `(${ty.elems.map(printTy).join(", ")})`;
|
||||
}
|
||||
case "fn": {
|
||||
const ret = tyIsUnit(ty.returnTy) ? "" : `: ${printTy(ty.returnTy)}`;
|
||||
return `fn(${ty.params.map(printTy).join(", ")})${ret}`;
|
||||
}
|
||||
case "var": {
|
||||
case "var":
|
||||
return `?${ty.index}`;
|
||||
}
|
||||
case "struct": {
|
||||
case "struct":
|
||||
return ty._name;
|
||||
}
|
||||
case "rawptr": {
|
||||
case "rawptr":
|
||||
return `*${printTy(ty.inner)}`;
|
||||
}
|
||||
case "never": {
|
||||
case "never":
|
||||
return "!";
|
||||
}
|
||||
case "param": {
|
||||
case "param":
|
||||
return ty.name;
|
||||
}
|
||||
case "alias":
|
||||
return printTy(substituteTy(ty.genericArgs, ty.actual));
|
||||
case "error":
|
||||
return "<ERROR>";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import {
|
|||
StructLiteralField,
|
||||
superFoldExpr,
|
||||
ExprCall,
|
||||
substituteTy,
|
||||
} from "./ast";
|
||||
import { GlobalContext } from "./context";
|
||||
import {
|
||||
|
|
@ -140,7 +141,7 @@ function lowerAstTy(cx: TypeckCtx, type: Type<Resolved>): Ty {
|
|||
throw new Error("Item type cannot refer to local variable");
|
||||
}
|
||||
case "item": {
|
||||
ty = typeOfItem(cx, res.id, type.span);
|
||||
ty = typeOfItem(cx, res.id, generics, type.span);
|
||||
break;
|
||||
}
|
||||
case "builtin": {
|
||||
|
|
@ -157,9 +158,12 @@ function lowerAstTy(cx: TypeckCtx, type: Type<Resolved>): Ty {
|
|||
}
|
||||
}
|
||||
|
||||
if (ty.kind === "struct") {
|
||||
if (ty.kind === "struct" || ty.kind === "alias") {
|
||||
if (generics.length === ty.params.length) {
|
||||
return { ...ty, args: generics };
|
||||
if (ty.kind === "alias") {
|
||||
return substituteTy(ty.genericArgs, ty.actual);
|
||||
}
|
||||
return { ...ty, genericArgs: generics };
|
||||
} else {
|
||||
return tyError(
|
||||
cx,
|
||||
|
|
@ -209,7 +213,12 @@ function lowerAstTy(cx: TypeckCtx, type: Type<Resolved>): Ty {
|
|||
}
|
||||
}
|
||||
|
||||
function typeOfItem(cx: TypeckCtx, itemId: ItemId, cause: Span): Ty {
|
||||
function typeOfItem(
|
||||
cx: TypeckCtx,
|
||||
itemId: ItemId,
|
||||
genericArgs: Ty[],
|
||||
cause: Span,
|
||||
): Ty {
|
||||
if (itemId.crateId !== cx.ast.id) {
|
||||
// Look up foreign items in the foreign crates, we don't need to lower those
|
||||
// ourselves.
|
||||
|
|
@ -220,7 +229,7 @@ function typeOfItem(cx: TypeckCtx, itemId: ItemId, cause: Span): Ty {
|
|||
case "import":
|
||||
case "type":
|
||||
case "global":
|
||||
return item.ty!;
|
||||
return substituteTy(genericArgs, item.ty!);
|
||||
case "mod": {
|
||||
return tyError(
|
||||
cx,
|
||||
|
|
@ -276,7 +285,13 @@ function typeOfItem(cx: TypeckCtx, itemId: ItemId, cause: Span): Ty {
|
|||
case "struct": {
|
||||
ty = {
|
||||
kind: "struct",
|
||||
args: [],
|
||||
genericArgs: item.generics.map(
|
||||
({ name }, idx): Ty => ({
|
||||
kind: "param",
|
||||
name,
|
||||
idx,
|
||||
}),
|
||||
),
|
||||
params: item.generics.map((ident) => ident.name),
|
||||
itemId: item.id,
|
||||
_name: item.name,
|
||||
|
|
@ -295,8 +310,20 @@ function typeOfItem(cx: TypeckCtx, itemId: ItemId, cause: Span): Ty {
|
|||
break;
|
||||
}
|
||||
case "alias": {
|
||||
// TODO: subst
|
||||
ty = lowerAstTy(cx, item.type.type);
|
||||
const actual = lowerAstTy(cx, item.type.type);
|
||||
|
||||
ty = {
|
||||
kind: "alias",
|
||||
actual,
|
||||
genericArgs: item.generics.map(
|
||||
({ name }, idx): Ty => ({
|
||||
kind: "param",
|
||||
name,
|
||||
idx,
|
||||
}),
|
||||
),
|
||||
params: item.generics.map((ident) => ident.name),
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -329,6 +356,8 @@ function typeOfItem(cx: TypeckCtx, itemId: ItemId, cause: Span): Ty {
|
|||
}
|
||||
}
|
||||
|
||||
ty = substituteTy(genericArgs, ty);
|
||||
|
||||
cx.itemTys.set(item.id, ty);
|
||||
return ty;
|
||||
}
|
||||
|
|
@ -348,7 +377,8 @@ export function typeck(
|
|||
itemInner(item: Item<Resolved>): Item<Typecked> {
|
||||
switch (item.kind) {
|
||||
case "function": {
|
||||
const fnTy = typeOfItem(cx, item.id, item.span) as TyFn;
|
||||
// Functions do not have generic arguments right now.
|
||||
const fnTy = typeOfItem(cx, item.id, [], item.span) as TyFn;
|
||||
const body = checkBody(cx, ast, item.body, fnTy);
|
||||
|
||||
return {
|
||||
|
|
@ -360,7 +390,7 @@ export function typeck(
|
|||
};
|
||||
}
|
||||
case "import": {
|
||||
const fnTy = typeOfItem(cx, item.id, item.span) as TyFn;
|
||||
const fnTy = typeOfItem(cx, item.id, [], item.span) as TyFn;
|
||||
|
||||
fnTy.params.forEach((param, i) => {
|
||||
switch (param.kind) {
|
||||
|
|
@ -404,7 +434,7 @@ export function typeck(
|
|||
};
|
||||
}
|
||||
case "type": {
|
||||
const ty = typeOfItem(cx, item.id, item.span);
|
||||
const ty = typeOfItem(cx, item.id, [], item.span);
|
||||
|
||||
switch (item.type.kind) {
|
||||
case "struct": {
|
||||
|
|
@ -452,7 +482,7 @@ export function typeck(
|
|||
return item;
|
||||
}
|
||||
case "global": {
|
||||
const ty = typeOfItem(cx, item.id, item.span);
|
||||
const ty = typeOfItem(cx, item.id, [], item.span);
|
||||
const { init } = item;
|
||||
|
||||
let initChecked: Expr<Typecked>;
|
||||
|
|
@ -720,7 +750,7 @@ function typeOfValue(fcx: FuncCtx, res: Resolution, span: Span): Ty {
|
|||
return fcx.localTys[idx];
|
||||
}
|
||||
case "item": {
|
||||
return typeOfItem(fcx.cx, res.id, span);
|
||||
return typeOfItem(fcx.cx, res.id, [], span);
|
||||
}
|
||||
case "builtin":
|
||||
return typeOfBuiltinValue(fcx, res.name, span);
|
||||
|
|
|
|||
40
std/list.nil
40
std/list.nil
|
|
@ -1,21 +1,21 @@
|
|||
type List[T] = struct {
|
||||
ptr: Int,
|
||||
len: Int,
|
||||
cap: Int,
|
||||
};
|
||||
|
||||
function new(): List[Int] = (
|
||||
List { ptr: 0, len: 0, cap: 0 }
|
||||
);
|
||||
|
||||
function push(list: List[Int], elem: Int) = (
|
||||
growIfNeeded(list, 1);
|
||||
);
|
||||
|
||||
//type List[T] = struct {
|
||||
// ptr: Int,
|
||||
// len: Int,
|
||||
// cap: Int,
|
||||
//};
|
||||
//
|
||||
//function new(): List[Int] = (
|
||||
// List { ptr: 0, len: 0, cap: 0 }
|
||||
//);
|
||||
//
|
||||
//function push(list: List[Int], elem: Int) = (
|
||||
// growIfNeeded(list, 1);
|
||||
//);
|
||||
//
|
||||
// PRIVATE:
|
||||
|
||||
function growIfNeeded(list: List[Int], elems: Int) = (
|
||||
if (list.len + elems) < list.cap then (
|
||||
let newMemory = std.rt.alloc.allocateItem(0_I32, 0_I32);
|
||||
);
|
||||
);
|
||||
//
|
||||
//function growIfNeeded(list: List[Int], elems: Int) = (
|
||||
// if (list.len + elems) < list.cap then (
|
||||
// let newMemory = std.rt.alloc.allocateItem(0_I32, 0_I32);
|
||||
// );
|
||||
//);
|
||||
|
|
|
|||
4
test.nil
4
test.nil
|
|
@ -1,6 +1,6 @@
|
|||
//@check-pass
|
||||
type A[T] = struct { a: T };
|
||||
type A[T] = T;
|
||||
|
||||
function main() = ;
|
||||
|
||||
function test(a: A[I32]) = ;
|
||||
function aaaaaaaaaaa(a: A[I32]) = ;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue