mirror of
https://github.com/Noratrieb/riverdelta.git
synced 2026-01-14 16:35:03 +01:00
fix generics
This commit is contained in:
parent
dbd49d852f
commit
66d95dfeeb
18 changed files with 154 additions and 158 deletions
|
|
@ -141,7 +141,7 @@ export type FunctionArg<P extends Phase> = {
|
||||||
|
|
||||||
export type ItemKindType<P extends Phase> = {
|
export type ItemKindType<P extends Phase> = {
|
||||||
kind: "type";
|
kind: "type";
|
||||||
generics: Ident[];
|
genericParams: Ident[];
|
||||||
type: TypeDefKind<P>;
|
type: TypeDefKind<P>;
|
||||||
ty?: Ty;
|
ty?: Ty;
|
||||||
};
|
};
|
||||||
|
|
@ -417,7 +417,7 @@ export const UNARY_KINDS: UnaryKind[] = ["!", "-"];
|
||||||
export type TypeKind<P extends Phase> =
|
export type TypeKind<P extends Phase> =
|
||||||
| {
|
| {
|
||||||
kind: "ident";
|
kind: "ident";
|
||||||
generics: Type<P>[];
|
genericArgs: Type<P>[];
|
||||||
value: IdentWithRes<P>;
|
value: IdentWithRes<P>;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
|
|
@ -793,7 +793,7 @@ export function superFoldType<From extends Phase, To extends Phase>(
|
||||||
case "ident": {
|
case "ident": {
|
||||||
return {
|
return {
|
||||||
kind: "ident",
|
kind: "ident",
|
||||||
generics: type.generics.map((type) => folder.type(type)),
|
genericArgs: type.genericArgs.map((type) => folder.type(type)),
|
||||||
value: folder.ident(type.value),
|
value: folder.ident(type.value),
|
||||||
span,
|
span,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ it("should compute struct layout correctly", () => {
|
||||||
kind: "struct",
|
kind: "struct",
|
||||||
itemId: ItemId.dummy(),
|
itemId: ItemId.dummy(),
|
||||||
genericArgs: [],
|
genericArgs: [],
|
||||||
params: [],
|
|
||||||
_name: "",
|
_name: "",
|
||||||
fields_no_subst: [
|
fields_no_subst: [
|
||||||
["uwu", TYS.I32],
|
["uwu", TYS.I32],
|
||||||
|
|
@ -54,7 +53,6 @@ it("should compute single field struct layout correctly", () => {
|
||||||
kind: "struct",
|
kind: "struct",
|
||||||
itemId: ItemId.dummy(),
|
itemId: ItemId.dummy(),
|
||||||
genericArgs: [],
|
genericArgs: [],
|
||||||
params: [],
|
|
||||||
_name: "",
|
_name: "",
|
||||||
fields_no_subst: [["owo", TYS.INT]],
|
fields_no_subst: [["owo", TYS.INT]],
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -384,7 +384,6 @@ function lowerFunc(cx: Context, func: ItemFunction<Typecked>) {
|
||||||
fcx.wasm.body = body.instructions;
|
fcx.wasm.body = body.instructions;
|
||||||
} else {
|
} else {
|
||||||
lowerExpr(fcx, wasmFunc.body, body);
|
lowerExpr(fcx, wasmFunc.body, body);
|
||||||
|
|
||||||
paramLocations.forEach((local) => {
|
paramLocations.forEach((local) => {
|
||||||
const refcount = needsRefcount(local.ty);
|
const refcount = needsRefcount(local.ty);
|
||||||
if (refcount !== undefined) {
|
if (refcount !== undefined) {
|
||||||
|
|
@ -1264,7 +1263,6 @@ function argRetAbi(param: Ty): ArgRetAbi {
|
||||||
return [];
|
return [];
|
||||||
case "var":
|
case "var":
|
||||||
case "param":
|
case "param":
|
||||||
case "alias":
|
|
||||||
case "error":
|
case "error":
|
||||||
codegenUnreachableTy(param);
|
codegenUnreachableTy(param);
|
||||||
}
|
}
|
||||||
|
|
@ -1320,7 +1318,6 @@ function wasmTypeForBody(ty: Ty): wasm.ValType[] {
|
||||||
return [];
|
return [];
|
||||||
case "var":
|
case "var":
|
||||||
case "param":
|
case "param":
|
||||||
case "alias":
|
|
||||||
case "error":
|
case "error":
|
||||||
codegenUnreachableTy(ty);
|
codegenUnreachableTy(ty);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -173,7 +173,7 @@ function parseItem(t: State): [State, Item<Parsed>] {
|
||||||
{
|
{
|
||||||
kind: "type",
|
kind: "type",
|
||||||
name: name.ident,
|
name: name.ident,
|
||||||
generics,
|
genericParams: generics,
|
||||||
type,
|
type,
|
||||||
span: name.span,
|
span: name.span,
|
||||||
id: ItemId.dummy(),
|
id: ItemId.dummy(),
|
||||||
|
|
@ -694,7 +694,7 @@ function parseType(t: State): [State, Type<Parsed>] {
|
||||||
t,
|
t,
|
||||||
{
|
{
|
||||||
kind: "ident",
|
kind: "ident",
|
||||||
generics,
|
genericArgs: generics,
|
||||||
value: { name: tok.ident, span },
|
value: { name: tok.ident, span },
|
||||||
span,
|
span,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -65,9 +65,9 @@ function printFunction(func: ItemFunction<AnyPhase>): string {
|
||||||
|
|
||||||
function printTypeDef(type: ItemType<AnyPhase>): string {
|
function printTypeDef(type: ItemType<AnyPhase>): string {
|
||||||
const head = `type ${type.name}${
|
const head = `type ${type.name}${
|
||||||
type.generics.length === 0
|
type.genericParams.length === 0
|
||||||
? ""
|
? ""
|
||||||
: `[${type.generics.map((ident) => ident.name).join(", ")}]`
|
: `[${type.genericParams.map((ident) => ident.name).join(", ")}]`
|
||||||
} = `;
|
} = `;
|
||||||
switch (type.type.kind) {
|
switch (type.type.kind) {
|
||||||
case "struct": {
|
case "struct": {
|
||||||
|
|
@ -284,8 +284,6 @@ export function printTy(ty: Ty): string {
|
||||||
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>";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -225,7 +225,7 @@ function resolveModule(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case "type": {
|
case "type": {
|
||||||
tyParamScopes = item.generics.map(({ name }) => name);
|
tyParamScopes = item.genericParams.map(({ name }) => name);
|
||||||
|
|
||||||
const type = { ...superFoldItem(item, this) };
|
const type = { ...superFoldItem(item, this) };
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ import {
|
||||||
Folder,
|
Folder,
|
||||||
LOGICAL_KINDS,
|
LOGICAL_KINDS,
|
||||||
LoopId,
|
LoopId,
|
||||||
Resolution,
|
|
||||||
Resolved,
|
Resolved,
|
||||||
StructLiteralField,
|
StructLiteralField,
|
||||||
Type,
|
Type,
|
||||||
|
|
@ -91,7 +90,6 @@ export function checkBody(
|
||||||
fnTy: TyFn,
|
fnTy: TyFn,
|
||||||
): Expr<Typecked> {
|
): Expr<Typecked> {
|
||||||
const infcx = new InferContext(cx.gcx.error);
|
const infcx = new InferContext(cx.gcx.error);
|
||||||
|
|
||||||
const fcx: FuncCtx = {
|
const fcx: FuncCtx = {
|
||||||
cx,
|
cx,
|
||||||
infcx,
|
infcx,
|
||||||
|
|
@ -246,7 +244,8 @@ export function checkBody(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "item": {
|
case "item": {
|
||||||
ty = typeOfItem(fcx.cx, res.id, [], span);
|
// TODO: what do we do about generis here?
|
||||||
|
ty = typeOfItem(fcx.cx, res.id, span);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "builtin":
|
case "builtin":
|
||||||
|
|
@ -592,7 +591,7 @@ function checkStructLiteral(
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Handle generic arugments
|
// TODO: Handle generic arugments
|
||||||
const structTy = typeOfItem(fcx.cx, name.res.id, [], name.span);
|
const structTy = typeOfItem(fcx.cx, name.res.id, name.span);
|
||||||
|
|
||||||
if (structTy.kind !== "struct") {
|
if (structTy.kind !== "struct") {
|
||||||
const err: ErrorEmitted = emitError(
|
const err: ErrorEmitted = emitError(
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ export function typeck(gcx: GlobalContext, ast: Pkg<Resolved>): Pkg<Typecked> {
|
||||||
switch (item.kind) {
|
switch (item.kind) {
|
||||||
case "function": {
|
case "function": {
|
||||||
// Functions do not have generic arguments right now.
|
// Functions do not have generic arguments right now.
|
||||||
const fnTy = typeOfItem(cx, item.id, [], item.span) as TyFn;
|
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 {
|
||||||
|
|
@ -43,7 +43,7 @@ export function typeck(gcx: GlobalContext, ast: Pkg<Resolved>): Pkg<Typecked> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
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) {
|
||||||
|
|
@ -87,7 +87,7 @@ export function typeck(gcx: GlobalContext, ast: Pkg<Resolved>): Pkg<Typecked> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
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": {
|
||||||
|
|
@ -135,7 +135,7 @@ export function typeck(gcx: GlobalContext, ast: Pkg<Resolved>): Pkg<Typecked> {
|
||||||
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>;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { ItemId, Resolved, Type } from "../ast";
|
import { Ident, Item, ItemId, Resolved, Type, Typecked } from "../ast";
|
||||||
import { CompilerError, Span } from "../error";
|
import { CompilerError, Span } from "../error";
|
||||||
import { printTy } from "../printer";
|
import { printTy } from "../printer";
|
||||||
import { TYS, Ty, substituteTy } from "../types";
|
import { TYS, Ty, createIdentityGenericArgs, 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 {
|
||||||
|
|
@ -36,58 +36,77 @@ export function lowerAstTy(cx: TypeckCtx, type: Type<Resolved>): Ty {
|
||||||
const ident = type.value;
|
const ident = type.value;
|
||||||
const res = ident.res;
|
const res = ident.res;
|
||||||
|
|
||||||
const generics = type.generics.map((type) => lowerAstTy(cx, type));
|
const genericArgs = type.genericArgs.map((type) => lowerAstTy(cx, type));
|
||||||
let ty: Ty;
|
let ty: Ty;
|
||||||
|
let generics: Generics;
|
||||||
|
// We only actually substitute anything when "peeking" behind a type into its
|
||||||
|
// internals, where the params are used. This is only the case for aliases today.
|
||||||
|
let isAlias = false;
|
||||||
switch (res.kind) {
|
switch (res.kind) {
|
||||||
case "local": {
|
case "local": {
|
||||||
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, generics, type.span);
|
ty = typeOfItem(cx, res.id, type.span);
|
||||||
|
const item = cx.gcx.findItem<Resolved>(res.id, cx.ast);
|
||||||
|
if (item.kind === "type" && item.type.kind === "alias") {
|
||||||
|
isAlias = true;
|
||||||
|
}
|
||||||
|
generics = itemGenerics(item);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "builtin": {
|
case "builtin": {
|
||||||
ty = builtinAsTy(cx, res.name, ident.span);
|
ty = builtinAsTy(cx, res.name, ident.span);
|
||||||
|
generics = { kind: "none" };
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "tyParam": {
|
case "tyParam": {
|
||||||
ty = { kind: "param", idx: res.index, name: res.name };
|
ty = { kind: "param", idx: res.index, name: res.name };
|
||||||
|
generics = { kind: "none" };
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "error": {
|
case "error": {
|
||||||
ty = tyErrorFrom(res);
|
// Skip generics validation, it's fine!
|
||||||
break;
|
return tyErrorFrom(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ty.kind === "struct" || ty.kind === "alias") {
|
if (
|
||||||
if (generics.length === ty.params.length) {
|
(generics.kind === "none" || generics.params.length === 0) &&
|
||||||
if (ty.kind === "alias") {
|
genericArgs.length > 0
|
||||||
return substituteTy(ty.genericArgs, ty.actual);
|
) {
|
||||||
}
|
return tyError(
|
||||||
return { ...ty, genericArgs: generics };
|
cx,
|
||||||
} else {
|
new CompilerError(
|
||||||
return tyError(
|
`type ${printTy(ty)} does not take any generic arguments but ${
|
||||||
cx,
|
genericArgs.length
|
||||||
new CompilerError(
|
} were passed`,
|
||||||
`expected ${ty.params.length} generic arguments, found ${generics.length}`,
|
type.span,
|
||||||
type.span,
|
),
|
||||||
),
|
);
|
||||||
);
|
}
|
||||||
}
|
if (
|
||||||
} else if (ty.kind !== "error") {
|
generics.kind === "some" &&
|
||||||
if (generics.length > 0) {
|
generics.params.length > genericArgs.length
|
||||||
return tyError(
|
) {
|
||||||
cx,
|
return tyError(
|
||||||
new CompilerError(
|
cx,
|
||||||
`type ${printTy(ty)} does not take generic arguments`,
|
new CompilerError(
|
||||||
type.span,
|
`missing generics for type ${printTy(ty)}, expected ${
|
||||||
),
|
generics.params.length
|
||||||
);
|
}, but only ${genericArgs.length} were passed`,
|
||||||
}
|
type.span,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (isAlias) {
|
||||||
|
return substituteTy(genericArgs, ty);
|
||||||
|
} else {
|
||||||
|
if (ty.kind === "struct") {
|
||||||
|
return { ...ty, genericArgs };
|
||||||
|
}
|
||||||
|
return ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ty;
|
|
||||||
}
|
}
|
||||||
case "tuple": {
|
case "tuple": {
|
||||||
return {
|
return {
|
||||||
|
|
@ -115,12 +134,31 @@ export function lowerAstTy(cx: TypeckCtx, type: Type<Resolved>): Ty {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function typeOfItem(
|
type Generics =
|
||||||
cx: TypeckCtx,
|
| {
|
||||||
itemId: ItemId,
|
kind: "none";
|
||||||
genericArgs: Ty[],
|
}
|
||||||
cause: Span,
|
| {
|
||||||
): Ty {
|
kind: "some";
|
||||||
|
params: Ident[];
|
||||||
|
};
|
||||||
|
|
||||||
|
function itemGenerics(item: Item<Typecked> | Item<Resolved>): Generics {
|
||||||
|
const none: Generics = { kind: "none" };
|
||||||
|
switch (item.kind) {
|
||||||
|
case "function":
|
||||||
|
case "extern":
|
||||||
|
case "error":
|
||||||
|
case "global":
|
||||||
|
case "mod":
|
||||||
|
case "import":
|
||||||
|
return none;
|
||||||
|
case "type":
|
||||||
|
return { kind: "some", params: item.genericParams };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function typeOfItem(cx: TypeckCtx, itemId: ItemId, cause: Span): Ty {
|
||||||
if (itemId.pkgId !== cx.ast.id) {
|
if (itemId.pkgId !== cx.ast.id) {
|
||||||
// Look up foreign items in the foreign pkgs, we don't need to lower those
|
// Look up foreign items in the foreign pkgs, we don't need to lower those
|
||||||
// ourselves.
|
// ourselves.
|
||||||
|
|
@ -131,7 +169,7 @@ export function typeOfItem(
|
||||||
case "import":
|
case "import":
|
||||||
case "type":
|
case "type":
|
||||||
case "global":
|
case "global":
|
||||||
return substituteTy(genericArgs, item.ty!);
|
return item.ty!;
|
||||||
case "mod": {
|
case "mod": {
|
||||||
return tyError(
|
return tyError(
|
||||||
cx,
|
cx,
|
||||||
|
|
@ -187,14 +225,7 @@ export function typeOfItem(
|
||||||
case "struct": {
|
case "struct": {
|
||||||
ty = {
|
ty = {
|
||||||
kind: "struct",
|
kind: "struct",
|
||||||
genericArgs: item.generics.map(
|
genericArgs: createIdentityGenericArgs(item.genericParams),
|
||||||
({ name }, idx): Ty => ({
|
|
||||||
kind: "param",
|
|
||||||
name,
|
|
||||||
idx,
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
params: item.generics.map((ident) => ident.name),
|
|
||||||
itemId: item.id,
|
itemId: item.id,
|
||||||
_name: item.name,
|
_name: item.name,
|
||||||
fields_no_subst: [
|
fields_no_subst: [
|
||||||
|
|
@ -214,52 +245,41 @@ export function typeOfItem(
|
||||||
case "alias": {
|
case "alias": {
|
||||||
const actual = lowerAstTy(cx, item.type.type);
|
const actual = lowerAstTy(cx, item.type.type);
|
||||||
|
|
||||||
ty = {
|
ty = actual;
|
||||||
kind: "alias",
|
|
||||||
actual,
|
|
||||||
genericArgs: item.generics.map(
|
|
||||||
({ name }, idx): Ty => ({
|
|
||||||
kind: "param",
|
|
||||||
name,
|
|
||||||
idx,
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
params: item.generics.map((ident) => ident.name),
|
|
||||||
};
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "mod": {
|
case "mod": {
|
||||||
return tyError(
|
ty = tyError(
|
||||||
cx,
|
cx,
|
||||||
new CompilerError(
|
new CompilerError(
|
||||||
`module ${item.name} cannot be used as a type or value`,
|
`module ${item.name} cannot be used as a type or value`,
|
||||||
cause,
|
cause,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case "extern": {
|
case "extern": {
|
||||||
return tyError(
|
ty = tyError(
|
||||||
cx,
|
cx,
|
||||||
new CompilerError(
|
new CompilerError(
|
||||||
`extern declaration ${item.name} cannot be used as a type or value`,
|
`extern declaration ${item.name} cannot be used as a type or value`,
|
||||||
cause,
|
cause,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case "global": {
|
case "global": {
|
||||||
ty = lowerAstTy(cx, item.type);
|
ty = lowerAstTy(cx, item.type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "error": {
|
case "error": {
|
||||||
return tyErrorFrom(item);
|
ty = tyErrorFrom(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ty = substituteTy(genericArgs, ty);
|
|
||||||
|
|
||||||
cx.itemTys.set(item.id, ty);
|
cx.itemTys.set(item.id, ty);
|
||||||
return ty;
|
return ty;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
22
src/types.ts
22
src/types.ts
|
|
@ -1,4 +1,4 @@
|
||||||
import { ItemId, Resolution } from "./ast";
|
import { Ident, ItemId, Resolution } from "./ast";
|
||||||
import { ErrorEmitted } from "./error";
|
import { ErrorEmitted } from "./error";
|
||||||
|
|
||||||
export type TyString = {
|
export type TyString = {
|
||||||
|
|
@ -41,7 +41,6 @@ export type TyVar = {
|
||||||
export type TyStruct = {
|
export type TyStruct = {
|
||||||
kind: "struct";
|
kind: "struct";
|
||||||
itemId: ItemId;
|
itemId: ItemId;
|
||||||
params: string[];
|
|
||||||
genericArgs: Ty[];
|
genericArgs: Ty[];
|
||||||
_name: string;
|
_name: string;
|
||||||
fields_no_subst: [string, Ty][];
|
fields_no_subst: [string, Ty][];
|
||||||
|
|
@ -67,13 +66,6 @@ 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;
|
||||||
|
|
@ -91,7 +83,6 @@ 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 {
|
||||||
|
|
@ -140,7 +131,6 @@ export function substituteTy(genericArgs: Ty[], ty: Ty): Ty {
|
||||||
params: ty.params.map(subst),
|
params: ty.params.map(subst),
|
||||||
};
|
};
|
||||||
case "struct":
|
case "struct":
|
||||||
case "alias":
|
|
||||||
return {
|
return {
|
||||||
...ty,
|
...ty,
|
||||||
genericArgs: ty.genericArgs.map(subst),
|
genericArgs: ty.genericArgs.map(subst),
|
||||||
|
|
@ -158,3 +148,13 @@ export function substituteTy(genericArgs: Ty[], ty: Ty): Ty {
|
||||||
return ty;
|
return ty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createIdentityGenericArgs(params: Ident[]): Ty[] {
|
||||||
|
return params.map(
|
||||||
|
(name, idx): Ty => ({
|
||||||
|
kind: "param",
|
||||||
|
name: name.name,
|
||||||
|
idx,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
||||||
12
test.nil
12
test.nil
|
|
@ -1,8 +1,8 @@
|
||||||
|
type A[T] = struct { a: T };
|
||||||
|
type B[T] = struct {
|
||||||
|
b: T,
|
||||||
|
};
|
||||||
|
|
||||||
function main() = ;
|
function main() = ;
|
||||||
|
|
||||||
type A[T] = T;
|
function test(b: B[I32]) = ;
|
||||||
type B[T] = struct { a: T };
|
|
||||||
|
|
||||||
//function ohno(x: A[A[A[I32]]]): I32 = x;
|
|
||||||
|
|
||||||
function generic(a: B[I32]): B[I32] = a;
|
|
||||||
|
|
|
||||||
6
ui-tests/type/generics/aliases_nested.nil
Normal file
6
ui-tests/type/generics/aliases_nested.nil
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
//@check-pass
|
||||||
|
type A[T] = T;
|
||||||
|
|
||||||
|
function ohno(x: A[A[A[I32]]]): I32 = x;
|
||||||
|
|
||||||
|
function main() = ;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
error: type I32 does not take generic arguments
|
error: type I32 does not take any generic arguments but 1 were passed
|
||||||
--> $DIR/generics_on_primitive.nil:2
|
--> $DIR/generics_on_primitive.nil:2
|
||||||
2 | let a: I32[I32] = 0;
|
2 | let a: I32[I32] = 0;
|
||||||
^^^
|
^^^
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
/home/nils/projects/riverdelta/target/ast.js:110
|
|
||||||
throw new Error(`substitution out of range, param index ${ty.idx} of param ${ty.name} out of range for length ${genericArgs.length}`);
|
|
||||||
^
|
|
||||||
|
|
||||||
Error: substitution out of range, param index 0 of param T out of range for length 0
|
|
||||||
at substituteTy (/home/nils/projects/riverdelta/target/ast.js:110:23)
|
|
||||||
at subst (/home/nils/projects/riverdelta/target/ast.js:106:27)
|
|
||||||
at Array.map (<anonymous>)
|
|
||||||
at substituteTy (/home/nils/projects/riverdelta/target/ast.js:125:45)
|
|
||||||
at typeOfItem (/home/nils/projects/riverdelta/target/typeck/item.js:193:33)
|
|
||||||
at Object.itemInner (/home/nils/projects/riverdelta/target/typeck/index.js:63:54)
|
|
||||||
at Object.item (/home/nils/projects/riverdelta/target/ast.js:146:34)
|
|
||||||
at /home/nils/projects/riverdelta/target/ast.js:164:55
|
|
||||||
at Array.map (<anonymous>)
|
|
||||||
at foldAst (/home/nils/projects/riverdelta/target/ast.js:164:34)
|
|
||||||
|
|
||||||
Node.js v20.10.0
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//@check-pass
|
||||||
type A[T] = struct { a: T };
|
type A[T] = struct { a: T };
|
||||||
type B[T, U, V] = struct {
|
type B[T, U, V] = struct {
|
||||||
b: T,
|
b: T,
|
||||||
|
|
@ -6,3 +7,5 @@ type B[T, U, V] = struct {
|
||||||
type C = ();
|
type C = ();
|
||||||
|
|
||||||
function test(a: A[I32], b: B[I32, Int, I32], c: C) = ;
|
function test(a: A[I32], b: B[I32, Int, I32], c: C) = ;
|
||||||
|
|
||||||
|
function main() = ;
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
/home/nils/projects/riverdelta/target/ast.js:110
|
|
||||||
throw new Error(`substitution out of range, param index ${ty.idx} of param ${ty.name} out of range for length ${genericArgs.length}`);
|
|
||||||
^
|
|
||||||
|
|
||||||
Error: substitution out of range, param index 0 of param T out of range for length 0
|
|
||||||
at substituteTy (/home/nils/projects/riverdelta/target/ast.js:110:23)
|
|
||||||
at subst (/home/nils/projects/riverdelta/target/ast.js:106:27)
|
|
||||||
at Array.map (<anonymous>)
|
|
||||||
at substituteTy (/home/nils/projects/riverdelta/target/ast.js:125:45)
|
|
||||||
at typeOfItem (/home/nils/projects/riverdelta/target/typeck/item.js:193:33)
|
|
||||||
at Object.itemInner (/home/nils/projects/riverdelta/target/typeck/index.js:63:54)
|
|
||||||
at Object.item (/home/nils/projects/riverdelta/target/ast.js:146:34)
|
|
||||||
at /home/nils/projects/riverdelta/target/ast.js:164:55
|
|
||||||
at Array.map (<anonymous>)
|
|
||||||
at foldAst (/home/nils/projects/riverdelta/target/ast.js:164:34)
|
|
||||||
|
|
||||||
Node.js v20.10.0
|
|
||||||
|
|
@ -21,3 +21,5 @@ function test(
|
||||||
c2: C[],
|
c2: C[],
|
||||||
c3: C[I32],
|
c3: C[I32],
|
||||||
) = ;
|
) = ;
|
||||||
|
|
||||||
|
function main() = ;
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,24 @@
|
||||||
/home/nils/projects/riverdelta/target/ast.js:110
|
error: missing generics for type A, expected 1, but only 0 were passed
|
||||||
throw new Error(`substitution out of range, param index ${ty.idx} of param ${ty.name} out of range for length ${genericArgs.length}`);
|
--> $DIR/wrong_amount.nil:9
|
||||||
^
|
9 | a1: A,
|
||||||
|
^
|
||||||
Error: substitution out of range, param index 0 of param T out of range for length 0
|
error: missing generics for type A, expected 1, but only 0 were passed
|
||||||
at substituteTy (/home/nils/projects/riverdelta/target/ast.js:110:23)
|
--> $DIR/wrong_amount.nil:10
|
||||||
at subst (/home/nils/projects/riverdelta/target/ast.js:106:27)
|
10 | a2: A[],
|
||||||
at Array.map (<anonymous>)
|
^
|
||||||
at substituteTy (/home/nils/projects/riverdelta/target/ast.js:125:45)
|
error: missing generics for type B, expected 3, but only 0 were passed
|
||||||
at typeOfItem (/home/nils/projects/riverdelta/target/typeck/item.js:193:33)
|
--> $DIR/wrong_amount.nil:14
|
||||||
at Object.itemInner (/home/nils/projects/riverdelta/target/typeck/index.js:63:54)
|
14 | b1: B,
|
||||||
at Object.item (/home/nils/projects/riverdelta/target/ast.js:146:34)
|
^
|
||||||
at /home/nils/projects/riverdelta/target/ast.js:164:55
|
error: missing generics for type B, expected 3, but only 0 were passed
|
||||||
at Array.map (<anonymous>)
|
--> $DIR/wrong_amount.nil:15
|
||||||
at foldAst (/home/nils/projects/riverdelta/target/ast.js:164:34)
|
15 | b2: B[],
|
||||||
|
^
|
||||||
Node.js v20.10.0
|
error: missing generics for type B, expected 3, but only 2 were passed
|
||||||
|
--> $DIR/wrong_amount.nil:16
|
||||||
|
16 | b3: B[Int, Int],
|
||||||
|
^
|
||||||
|
error: type () does not take any generic arguments but 1 were passed
|
||||||
|
--> $DIR/wrong_amount.nil:22
|
||||||
|
22 | c3: C[I32],
|
||||||
|
^
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue