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