mirror of
https://github.com/Noratrieb/riverdelta.git
synced 2026-01-16 09:25:03 +01:00
Start typechecking generics
This commit is contained in:
parent
bf73203182
commit
01d4238269
15 changed files with 248 additions and 19 deletions
|
|
@ -1 +0,0 @@
|
||||||
mod b;
|
|
||||||
36
src/ast.ts
36
src/ast.ts
|
|
@ -139,8 +139,9 @@ export type FunctionArg<P extends Phase> = {
|
||||||
|
|
||||||
export type ItemKindType<P extends Phase> = {
|
export type ItemKindType<P extends Phase> = {
|
||||||
kind: "type";
|
kind: "type";
|
||||||
|
generics: Ident[];
|
||||||
type: TypeDefKind<P>;
|
type: TypeDefKind<P>;
|
||||||
ty?: TyStruct;
|
ty?: Ty;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TypeDefKind<P extends Phase> =
|
export type TypeDefKind<P extends Phase> =
|
||||||
|
|
@ -407,6 +408,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>[];
|
||||||
value: IdentWithRes<P>;
|
value: IdentWithRes<P>;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
|
|
@ -453,6 +455,19 @@ export type Resolution =
|
||||||
kind: "builtin";
|
kind: "builtin";
|
||||||
name: BuiltinName;
|
name: BuiltinName;
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
kind: "tyParam";
|
||||||
|
/**
|
||||||
|
* The index of the type parameter, from first to last.
|
||||||
|
* ```
|
||||||
|
* type A[T, U] = (T, U);
|
||||||
|
* ^ ^
|
||||||
|
* 0 1
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
index: number;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
| { kind: "error"; err: ErrorEmitted };
|
| { kind: "error"; err: ErrorEmitted };
|
||||||
|
|
||||||
export const BUILTINS = [
|
export const BUILTINS = [
|
||||||
|
|
@ -531,6 +546,8 @@ export type TyVar = {
|
||||||
export type TyStruct = {
|
export type TyStruct = {
|
||||||
kind: "struct";
|
kind: "struct";
|
||||||
itemId: ItemId;
|
itemId: ItemId;
|
||||||
|
params: string[];
|
||||||
|
args: Ty[];
|
||||||
_name: string;
|
_name: string;
|
||||||
fields: [string, Ty][];
|
fields: [string, Ty][];
|
||||||
};
|
};
|
||||||
|
|
@ -544,6 +561,17 @@ export type TyNever = {
|
||||||
kind: "never";
|
kind: "never";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TyParam = {
|
||||||
|
kind: "param";
|
||||||
|
/**
|
||||||
|
* The index of the type parameter of the parent.
|
||||||
|
* If the parent is `type A[T, U] = U;`
|
||||||
|
* then `U` will have index 1.
|
||||||
|
*/
|
||||||
|
idx: number;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type TyError = {
|
export type TyError = {
|
||||||
kind: "error";
|
kind: "error";
|
||||||
err: ErrorEmitted;
|
err: ErrorEmitted;
|
||||||
|
|
@ -561,6 +589,7 @@ export type Ty =
|
||||||
| TyStruct
|
| TyStruct
|
||||||
| TyRawPtr
|
| TyRawPtr
|
||||||
| TyNever
|
| TyNever
|
||||||
|
| TyParam
|
||||||
| TyError;
|
| TyError;
|
||||||
|
|
||||||
export function tyIsUnit(ty: Ty): ty is TyUnit {
|
export function tyIsUnit(ty: Ty): ty is TyUnit {
|
||||||
|
|
@ -860,6 +889,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)),
|
||||||
value: folder.ident(type.value),
|
value: folder.ident(type.value),
|
||||||
span,
|
span,
|
||||||
};
|
};
|
||||||
|
|
@ -895,3 +925,7 @@ export function superFoldType<From extends Phase, To extends Phase>(
|
||||||
export function varUnreachable(): never {
|
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 {
|
||||||
|
unreachable("Type parameters must not occur after monomophization");
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ it("should compute struct layout correctly", () => {
|
||||||
const ty: TyStruct = {
|
const ty: TyStruct = {
|
||||||
kind: "struct",
|
kind: "struct",
|
||||||
itemId: ItemId.dummy(),
|
itemId: ItemId.dummy(),
|
||||||
|
args: [],
|
||||||
|
params: [],
|
||||||
_name: "",
|
_name: "",
|
||||||
fields: [
|
fields: [
|
||||||
["uwu", TY_I32],
|
["uwu", TY_I32],
|
||||||
|
|
@ -50,6 +52,8 @@ 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: [],
|
||||||
|
params: [],
|
||||||
_name: "",
|
_name: "",
|
||||||
fields: [["owo", TY_INT]],
|
fields: [["owo", TY_INT]],
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import {
|
||||||
superFoldItem,
|
superFoldItem,
|
||||||
varUnreachable,
|
varUnreachable,
|
||||||
TyRawPtr,
|
TyRawPtr,
|
||||||
|
paramUnreachable,
|
||||||
} from "./ast";
|
} from "./ast";
|
||||||
import { GlobalContext } from "./context";
|
import { GlobalContext } from "./context";
|
||||||
import { unreachable } from "./error";
|
import { unreachable } from "./error";
|
||||||
|
|
@ -1257,6 +1258,8 @@ function argRetAbi(param: Ty): ArgRetAbi {
|
||||||
return [];
|
return [];
|
||||||
case "var":
|
case "var":
|
||||||
varUnreachable();
|
varUnreachable();
|
||||||
|
case "param":
|
||||||
|
paramUnreachable();
|
||||||
case "error":
|
case "error":
|
||||||
unreachable("codegen should not see errors");
|
unreachable("codegen should not see errors");
|
||||||
}
|
}
|
||||||
|
|
@ -1314,6 +1317,8 @@ function wasmTypeForBody(ty: Ty): wasm.ValType[] {
|
||||||
return [];
|
return [];
|
||||||
case "var":
|
case "var":
|
||||||
varUnreachable();
|
varUnreachable();
|
||||||
|
case "param":
|
||||||
|
paramUnreachable();
|
||||||
case "error":
|
case "error":
|
||||||
unreachable("codegen should not see errors");
|
unreachable("codegen should not see errors");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,10 @@ function parseItem(t: State): [State, Item<Parsed>] {
|
||||||
} else if (tok.kind === "type") {
|
} else if (tok.kind === "type") {
|
||||||
let name;
|
let name;
|
||||||
[t, name] = expectNext<TokenIdent>(t, "identifier");
|
[t, name] = expectNext<TokenIdent>(t, "identifier");
|
||||||
|
|
||||||
|
let generics;
|
||||||
|
[t, generics] = parseGenericsDef(t);
|
||||||
|
|
||||||
[t] = expectNext(t, "=");
|
[t] = expectNext(t, "=");
|
||||||
|
|
||||||
let type: TypeDefKind<Parsed>;
|
let type: TypeDefKind<Parsed>;
|
||||||
|
|
@ -169,6 +173,7 @@ function parseItem(t: State): [State, Item<Parsed>] {
|
||||||
{
|
{
|
||||||
kind: "type",
|
kind: "type",
|
||||||
name: name.ident,
|
name: name.ident,
|
||||||
|
generics,
|
||||||
type,
|
type,
|
||||||
span: name.span,
|
span: name.span,
|
||||||
id: ItemId.dummy(),
|
id: ItemId.dummy(),
|
||||||
|
|
@ -308,7 +313,7 @@ function parseFunctionSig(t: State): [State, FunctionSig] {
|
||||||
let params: FunctionArg<Parsed>[];
|
let params: FunctionArg<Parsed>[];
|
||||||
[t, params] = parseCommaSeparatedList(t, ")", (t) => {
|
[t, params] = parseCommaSeparatedList(t, ")", (t) => {
|
||||||
let name;
|
let name;
|
||||||
[t, name] = expectNext<TokenIdent & { span: Span }>(t, "identifier");
|
[t, name] = expectNext<TokenIdent>(t, "identifier");
|
||||||
[t] = expectNext(t, ":");
|
[t] = expectNext(t, ":");
|
||||||
let type;
|
let type;
|
||||||
[t, type] = parseType(t);
|
[t, type] = parseType(t);
|
||||||
|
|
@ -326,6 +331,33 @@ function parseFunctionSig(t: State): [State, FunctionSig] {
|
||||||
return [t, { name: name.ident, params, returnType }];
|
return [t, { name: name.ident, params, returnType }];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseGenericsDef(t: State): [State, Ident[]] {
|
||||||
|
let openBracket;
|
||||||
|
[t, openBracket] = eat(t, "[");
|
||||||
|
if (openBracket) {
|
||||||
|
let elems;
|
||||||
|
[t, elems] = parseCommaSeparatedList<Ident>(t, "]", (t) => {
|
||||||
|
let name;
|
||||||
|
[t, name] = expectNext<TokenIdent>(t, "identifier");
|
||||||
|
|
||||||
|
return [t, { name: name.ident, span: name.span }];
|
||||||
|
});
|
||||||
|
return [t, elems];
|
||||||
|
} else {
|
||||||
|
return [t, []];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseGenericsArgs(t: State): [State, Type<Parsed>[]] {
|
||||||
|
let openBracket;
|
||||||
|
[t, openBracket] = eat(t, "[");
|
||||||
|
if (openBracket) {
|
||||||
|
return parseCommaSeparatedList(t, "]", parseType);
|
||||||
|
} else {
|
||||||
|
return [t, []];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function parseExpr(t: State): [State, Expr<Parsed>] {
|
function parseExpr(t: State): [State, Expr<Parsed>] {
|
||||||
/*
|
/*
|
||||||
EXPR = ASSIGNMENT
|
EXPR = ASSIGNMENT
|
||||||
|
|
@ -656,10 +688,13 @@ function parseType(t: State): [State, Type<Parsed>] {
|
||||||
return [t, { kind: "never", span }];
|
return [t, { kind: "never", span }];
|
||||||
}
|
}
|
||||||
case "identifier": {
|
case "identifier": {
|
||||||
|
let generics;
|
||||||
|
[t, generics] = parseGenericsArgs(t);
|
||||||
return [
|
return [
|
||||||
t,
|
t,
|
||||||
{
|
{
|
||||||
kind: "ident",
|
kind: "ident",
|
||||||
|
generics,
|
||||||
value: { name: tok.ident, span },
|
value: { name: tok.ident, span },
|
||||||
span,
|
span,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,11 @@ function printFunction(func: ItemFunction<AnyPhase>): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
function printTypeDef(type: ItemType<AnyPhase>): string {
|
function printTypeDef(type: ItemType<AnyPhase>): string {
|
||||||
|
const head = `type ${type.name}${
|
||||||
|
type.generics.length === 0
|
||||||
|
? ""
|
||||||
|
: `[${type.generics.map((ident) => ident.name).join(", ")}]`
|
||||||
|
} = `;
|
||||||
switch (type.type.kind) {
|
switch (type.type.kind) {
|
||||||
case "struct": {
|
case "struct": {
|
||||||
const { fields } = type.type;
|
const { fields } = type.type;
|
||||||
|
|
@ -75,10 +80,10 @@ function printTypeDef(type: ItemType<AnyPhase>): string {
|
||||||
const fieldPart =
|
const fieldPart =
|
||||||
fields.length === 0 ? "{}" : `{\n${fieldStr.join("\n")}\n}`;
|
fields.length === 0 ? "{}" : `{\n${fieldStr.join("\n")}\n}`;
|
||||||
|
|
||||||
return `type ${type.name} = ${fieldPart};`;
|
return head + `${fieldPart};`;
|
||||||
}
|
}
|
||||||
case "alias": {
|
case "alias": {
|
||||||
return `type ${type.name} = ${printType(type.type.type)}`;
|
return head + `${printType(type.type.type)}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -236,6 +241,9 @@ function printRes(res: Resolution): string {
|
||||||
case "builtin": {
|
case "builtin": {
|
||||||
return `#B`;
|
return `#B`;
|
||||||
}
|
}
|
||||||
|
case "tyParam": {
|
||||||
|
return `#P${res.index}`;
|
||||||
|
}
|
||||||
case "error": {
|
case "error": {
|
||||||
return "#E";
|
return "#E";
|
||||||
}
|
}
|
||||||
|
|
@ -283,6 +291,9 @@ export function printTy(ty: Ty): string {
|
||||||
case "never": {
|
case "never": {
|
||||||
return "!";
|
return "!";
|
||||||
}
|
}
|
||||||
|
case "param": {
|
||||||
|
return ty.name;
|
||||||
|
}
|
||||||
case "error":
|
case "error":
|
||||||
return "<ERROR>";
|
return "<ERROR>";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,7 @@ function resolveModule(
|
||||||
});
|
});
|
||||||
|
|
||||||
const scopes: string[] = [];
|
const scopes: string[] = [];
|
||||||
|
let tyParamScopes: string[] = [];
|
||||||
|
|
||||||
const popScope = (expected: string) => {
|
const popScope = (expected: string) => {
|
||||||
const popped = scopes.pop();
|
const popped = scopes.pop();
|
||||||
|
|
@ -130,6 +131,18 @@ function resolveModule(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (let i = tyParamScopes.length - 1; i >= 0; i--) {
|
||||||
|
const candidate = tyParamScopes[i];
|
||||||
|
|
||||||
|
if (candidate === ident.name) {
|
||||||
|
return {
|
||||||
|
kind: "tyParam",
|
||||||
|
index: i,
|
||||||
|
name: ident.name,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const item = items.get(ident.name);
|
const item = items.get(ident.name);
|
||||||
if (item !== undefined) {
|
if (item !== undefined) {
|
||||||
return {
|
return {
|
||||||
|
|
@ -214,6 +227,13 @@ function resolveModule(
|
||||||
defPath,
|
defPath,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
case "type": {
|
||||||
|
tyParamScopes = item.generics.map(({name}) => name);
|
||||||
|
|
||||||
|
const type = { ...superFoldItem(item, this) };
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { ...superFoldItem(item, this), defPath };
|
return { ...superFoldItem(item, this), defPath };
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ import {
|
||||||
tyIsUnit,
|
tyIsUnit,
|
||||||
Type,
|
Type,
|
||||||
Typecked,
|
Typecked,
|
||||||
TyStruct,
|
|
||||||
Item,
|
Item,
|
||||||
StructLiteralField,
|
StructLiteralField,
|
||||||
superFoldExpr,
|
superFoldExpr,
|
||||||
|
|
@ -133,20 +132,56 @@ function lowerAstTy(cx: TypeckCtx, type: Type<Resolved>): Ty {
|
||||||
case "ident": {
|
case "ident": {
|
||||||
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));
|
||||||
|
let ty: Ty;
|
||||||
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": {
|
||||||
return typeOfItem(cx, res.id, type.span);
|
ty = typeOfItem(cx, res.id, type.span);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case "builtin": {
|
case "builtin": {
|
||||||
return builtinAsTy(cx, res.name, ident.span);
|
ty = builtinAsTy(cx, res.name, ident.span);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "tyParam": {
|
||||||
|
ty = { kind: "param", idx: res.index, name: res.name };
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case "error": {
|
case "error": {
|
||||||
return tyErrorFrom(res);
|
ty = tyErrorFrom(res);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ty.kind === "struct") {
|
||||||
|
if (generics.length === ty.params.length) {
|
||||||
|
return { ...ty, args: generics };
|
||||||
|
} else {
|
||||||
|
return tyError(
|
||||||
|
cx,
|
||||||
|
new CompilerError(
|
||||||
|
`expected ${ty.params.length} generic arguments, found ${generics.length}`,
|
||||||
|
type.span,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (ty.kind !== "error") {
|
||||||
|
if (generics.length > 0) {
|
||||||
|
return tyError(
|
||||||
|
cx,
|
||||||
|
new CompilerError(
|
||||||
|
`type ${printTy(ty)} does not take generic arguments`,
|
||||||
|
type.span,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ty;
|
||||||
}
|
}
|
||||||
case "list": {
|
case "list": {
|
||||||
return {
|
return {
|
||||||
|
|
@ -247,6 +282,8 @@ function typeOfItem(cx: TypeckCtx, itemId: ItemId, cause: Span): Ty {
|
||||||
case "struct": {
|
case "struct": {
|
||||||
ty = {
|
ty = {
|
||||||
kind: "struct",
|
kind: "struct",
|
||||||
|
args: [],
|
||||||
|
params: item.generics.map((ident) => ident.name),
|
||||||
itemId: item.id,
|
itemId: item.id,
|
||||||
_name: item.name,
|
_name: item.name,
|
||||||
fields: [
|
fields: [
|
||||||
|
|
@ -264,6 +301,7 @@ function typeOfItem(cx: TypeckCtx, itemId: ItemId, cause: Span): Ty {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "alias": {
|
case "alias": {
|
||||||
|
// TODO: subst
|
||||||
ty = lowerAstTy(cx, item.type.type);
|
ty = lowerAstTy(cx, item.type.type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -372,7 +410,7 @@ export function typeck(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case "type": {
|
case "type": {
|
||||||
const ty = typeOfItem(cx, item.id, item.span) as TyStruct;
|
const ty = typeOfItem(cx, item.id, item.span);
|
||||||
|
|
||||||
switch (item.type.kind) {
|
switch (item.type.kind) {
|
||||||
case "struct": {
|
case "struct": {
|
||||||
|
|
@ -699,6 +737,11 @@ function typeOfValue(fcx: FuncCtx, res: Resolution, span: Span): Ty {
|
||||||
}
|
}
|
||||||
case "builtin":
|
case "builtin":
|
||||||
return typeOfBuiltinValue(fcx, res.name, span);
|
return typeOfBuiltinValue(fcx, res.name, span);
|
||||||
|
case "tyParam":
|
||||||
|
return tyError(
|
||||||
|
fcx.cx,
|
||||||
|
new CompilerError(`type parameter cannot be used as value`, span),
|
||||||
|
);
|
||||||
case "error":
|
case "error":
|
||||||
return tyErrorFrom(res);
|
return tyErrorFrom(res);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
18
test.nil
18
test.nil
|
|
@ -1,11 +1,11 @@
|
||||||
type A = struct { a: Int };
|
//@check-pass
|
||||||
|
type A[T] = struct { a: T };
|
||||||
|
type B[T, U, V] = struct {
|
||||||
|
b: T,
|
||||||
|
d: V,
|
||||||
|
};
|
||||||
|
type C = ();
|
||||||
|
|
||||||
function main() = (
|
function main() = ;
|
||||||
let a: Int = "";
|
|
||||||
let b: Int = "";
|
|
||||||
c;
|
|
||||||
);
|
|
||||||
|
|
||||||
function rawr(a: *A) = (
|
function test(a: A[I32], b: B[I32, Int, I32], c: C) = ;
|
||||||
a.a = 1;
|
|
||||||
);
|
|
||||||
|
|
|
||||||
3
ui-tests/type/generics/generics_on_primitive.nil
Normal file
3
ui-tests/type/generics/generics_on_primitive.nil
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
function main() = (
|
||||||
|
let a: I32[I32] = 0;
|
||||||
|
);
|
||||||
4
ui-tests/type/generics/generics_on_primitive.stderr
Normal file
4
ui-tests/type/generics/generics_on_primitive.stderr
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
error: type I32 does not take generic arguments
|
||||||
|
--> $DIR/generics_on_primitive.nil:2
|
||||||
|
2 | let a: I32[I32] = 0;
|
||||||
|
^^^
|
||||||
8
ui-tests/type/generics/structs.nil
Normal file
8
ui-tests/type/generics/structs.nil
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
type A[T] = struct { a: T };
|
||||||
|
type B[T, U, V] = struct {
|
||||||
|
b: T,
|
||||||
|
d: V,
|
||||||
|
};
|
||||||
|
type C = ();
|
||||||
|
|
||||||
|
function test(a: A[I32], b: B[I32, Int, I32], c: C) = ;
|
||||||
4
ui-tests/type/generics/structs.stderr
Normal file
4
ui-tests/type/generics/structs.stderr
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
error: `main` function not found
|
||||||
|
--> $DIR/structs.nil:1
|
||||||
|
1 | type A[T] = struct { a: T };
|
||||||
|
^
|
||||||
23
ui-tests/type/generics/wrong_amount.nil
Normal file
23
ui-tests/type/generics/wrong_amount.nil
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
type A[T] = struct { a: T };
|
||||||
|
type B[T, U, V] = struct {
|
||||||
|
b: T,
|
||||||
|
d: V,
|
||||||
|
};
|
||||||
|
type C = ();
|
||||||
|
|
||||||
|
function test(
|
||||||
|
a1: A,
|
||||||
|
a2: A[],
|
||||||
|
a3: A[I32],
|
||||||
|
a4: A[I32, I32],
|
||||||
|
|
||||||
|
b1: B,
|
||||||
|
b2: B[],
|
||||||
|
b3: B[Int, Int],
|
||||||
|
b4: B[Int, I32, Int],
|
||||||
|
b5: B[Int, Int, Int, Int],
|
||||||
|
|
||||||
|
c1: C,
|
||||||
|
c2: C[],
|
||||||
|
c3: C[I32],
|
||||||
|
) = ;
|
||||||
36
ui-tests/type/generics/wrong_amount.stderr
Normal file
36
ui-tests/type/generics/wrong_amount.stderr
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
error: expected 1 generic arguments, found 0
|
||||||
|
--> $DIR/wrong_amount.nil:9
|
||||||
|
9 | a1: A,
|
||||||
|
^
|
||||||
|
error: expected 1 generic arguments, found 0
|
||||||
|
--> $DIR/wrong_amount.nil:10
|
||||||
|
10 | a2: A[],
|
||||||
|
^
|
||||||
|
error: expected 1 generic arguments, found 2
|
||||||
|
--> $DIR/wrong_amount.nil:12
|
||||||
|
12 | a4: A[I32, I32],
|
||||||
|
^
|
||||||
|
error: expected 3 generic arguments, found 0
|
||||||
|
--> $DIR/wrong_amount.nil:14
|
||||||
|
14 | b1: B,
|
||||||
|
^
|
||||||
|
error: expected 3 generic arguments, found 0
|
||||||
|
--> $DIR/wrong_amount.nil:15
|
||||||
|
15 | b2: B[],
|
||||||
|
^
|
||||||
|
error: expected 3 generic arguments, found 2
|
||||||
|
--> $DIR/wrong_amount.nil:16
|
||||||
|
16 | b3: B[Int, Int],
|
||||||
|
^
|
||||||
|
error: expected 3 generic arguments, found 4
|
||||||
|
--> $DIR/wrong_amount.nil:18
|
||||||
|
18 | b5: B[Int, Int, Int, Int],
|
||||||
|
^
|
||||||
|
error: type () does not take generic arguments
|
||||||
|
--> $DIR/wrong_amount.nil:22
|
||||||
|
22 | c3: C[I32],
|
||||||
|
^
|
||||||
|
error: `main` function not found
|
||||||
|
--> $DIR/wrong_amount.nil:1
|
||||||
|
1 | type A[T] = struct { a: T };
|
||||||
|
^
|
||||||
Loading…
Add table
Add a link
Reference in a new issue