Compare commits

..

5 Commits

8 changed files with 435 additions and 117 deletions

View File

@ -14,6 +14,7 @@
"bool" return BOOL;
"MemoryAddress" return MEMORYADDRESS;
"struct" return STRUCT;
"interface" return INTERFACE;
"return" return RETURN;
"static" return STATIC;
"Reference" return REFERENCE;

View File

@ -27,6 +27,7 @@ extern FILE *yyin;
%token BOOL
%token MEMORYADDRESS
%token STRUCT
%token INTERFACE
%token RETURN
%token STATIC
%token REFERENCE
@ -150,6 +151,11 @@ AccessExpression : Identifier POINT AccessExpression
{
$$ = $1;
}
| BaseType POINT AccessExpression
{
$$ = MakeAccessExpressionNode($1, $3);
}
;
SystemCallExpression : AT Identifier
{
@ -355,6 +361,10 @@ GenericDeclaration : Identifier
{
$$ = MakeGenericDeclarationNode($1, NULL);
}
| Identifier COLON Type
{
$$ = MakeGenericDeclarationNode($1, $3);
}
GenericDeclarations : GenericDeclaration
{
@ -433,7 +443,28 @@ Declarations : Declaration
$$ = AddDeclarationNode($1, $2);
}
TopLevelDeclaration : StructDeclaration;
InterfaceMember : FunctionSignature SEMICOLON
{
$$ = $1;
}
InterfaceMembers : InterfaceMember
{
$$ = StartInterfaceMembersNode($1);
}
| InterfaceMembers InterfaceMember
{
$$ = AddInterfaceMemberNode($1, $2);
}
InterfaceDeclaration : INTERFACE Identifier GenericDeclarationClause LEFT_BRACE InterfaceMembers RIGHT_BRACE
{
$$ = MakeInterfaceDeclarationNode($2, $5, $3);
}
TopLevelDeclaration : StructDeclaration
| InterfaceDeclaration
;
TopLevelDeclarations : TopLevelDeclaration
{

View File

@ -14,6 +14,15 @@ struct MemoryBlock<T>
start: MemoryAddress;
capacity: uint;
static Init(capacity: uint): MemoryBlock<T>
{
return MemoryBlock<T>
{
capacity: capacity,
start: @malloc(capacity * @sizeof<T>())
};
}
AddressOf(index: uint): MemoryAddress
{
return start + (index * @sizeof<T>());
@ -35,25 +44,40 @@ struct MemoryBlock<T>
}
}
struct Array<T>
{
memoryBlock: MemoryBlock<T>;
static Init(capacity: uint): Array<T>
{
return Array<T>
{
memoryBlock: MemoryBlock<T>.Init(capacity)
};
}
Get(index: uint): T
{
return memoryBlock.Get(index);
}
Set(index: uint, value: T): void
{
memoryBlock.Set(index, value);
}
}
struct Program {
static Main(): int {
array: Array<int> = Array<int>.Init(4);
x: int = 4;
y: int = Foo.Func(x);
block: MemoryBlock<int> = MemoryBlock<int>
{
capacity: y,
start: @malloc(y * @sizeof<int>())
};
block.Set(0, 5);
block.Set(1, 3);
block.Set(2, 9);
block.Set(3, 100);
Console.PrintLine("%p", block.start);
Console.PrintLine("%i", block.Get(0));
Console.PrintLine("%i", block.Get(1));
Console.PrintLine("%i", block.Get(2));
Console.PrintLine("%i", block.Get(3));
block.Free();
array.Set(0, 2);
array.Set(1, 0);
array.Set(2, 5);
array.Set(3, 9);
Console.PrintLine("%i", array.Get(0));
Console.PrintLine("%i", array.Get(3));
return 0;
}
}

30
interface.w Normal file
View File

@ -0,0 +1,30 @@
struct Ass
{
Fart(): void
{
Console.PrintLine("Poot!");
}
}
interface Farter
{
Fart(): void;
}
struct FartDispatcher
{
static Fart<T : Farter>(farter: T): void
{
farter.Fart();
}
}
struct Program {
static Main(): int {
ass: Ass;
FartDispatcher.Fart(ass);
return 0;
}
}

View File

@ -612,6 +612,43 @@ Node *MakeStructInitExpressionNode(Node *typeNode, Node *structInitFieldsNode)
return node;
}
Node *MakeInterfaceDeclarationNode(
Node *identifierNode,
Node *interfaceMembersNode,
Node *genericDeclarationsNode)
{
Node *node = (Node *)malloc(sizeof(Node));
node->syntaxKind = Interface;
node->interface.identifier = identifierNode;
node->interface.interfaceMembers = interfaceMembersNode;
node->interface.genericDeclarations = genericDeclarationsNode;
return node;
}
Node *StartInterfaceMembersNode(Node *interfaceMemberNode)
{
Node *node = (Node *)malloc(sizeof(Node));
node->syntaxKind = InterfaceMembers;
node->interfaceMembers.members = (Node **)malloc(sizeof(Node *));
node->interfaceMembers.members[0] = interfaceMemberNode;
node->interfaceMembers.count = 1;
return node;
}
Node *AddInterfaceMemberNode(
Node *interfaceMembersNode,
Node *interfaceMemberNode)
{
interfaceMembersNode->interfaceMembers.members = realloc(
interfaceMembersNode->interfaceMembers.members,
sizeof(Node *) * (interfaceMembersNode->interfaceMembers.count + 1));
interfaceMembersNode->interfaceMembers
.members[interfaceMembersNode->interfaceMembers.count] =
interfaceMemberNode;
interfaceMembersNode->interfaceMembers.count += 1;
return interfaceMembersNode;
}
static const char *PrimitiveTypeToString(PrimitiveType type)
{
switch (type)
@ -1349,6 +1386,10 @@ void LinkParentPointers(Node *node, Node *prev)
case Comment:
return;
case ConcreteGenericTypeNode:
LinkParentPointers(node->concreteGenericType.genericArguments, node);
return;
case CustomTypeNode:
return;
@ -1388,6 +1429,7 @@ void LinkParentPointers(Node *node, Node *prev)
case FunctionCallExpression:
LinkParentPointers(node->functionCallExpression.identifier, node);
LinkParentPointers(node->functionCallExpression.argumentSequence, node);
LinkParentPointers(node->functionCallExpression.genericArguments, node);
return;
case FunctionDeclaration:
@ -1458,6 +1500,11 @@ void LinkParentPointers(Node *node, Node *prev)
LinkParentPointers(node->ifElseStatement.elseStatement, node);
return;
case Interface:
LinkParentPointers(node->interface.genericDeclarations, node);
LinkParentPointers(node->interface.interfaceMembers, node);
return;
case Number:
return;
@ -1512,6 +1559,7 @@ void LinkParentPointers(Node *node, Node *prev)
return;
case Type:
LinkParentPointers(node->type.typeNode, node);
return;
case UnaryExpression:

View File

@ -39,6 +39,8 @@ typedef enum
Identifier,
IfStatement,
IfElseStatement,
Interface,
InterfaceMembers,
Number,
PrimitiveTypeNode,
ReferenceTypeNode,
@ -284,6 +286,19 @@ struct Node
Node *elseStatement;
} ifElseStatement;
struct
{
Node *identifier;
Node *interfaceMembers;
Node *genericDeclarations;
} interface;
struct
{
Node **members;
uint32_t count;
} interfaceMembers;
struct
{
uint64_t value;
@ -445,6 +460,14 @@ Node *StartStructInitFieldsNode(Node *fieldInitNode);
Node *AddFieldInitNode(Node *structInitFieldsNode, Node *fieldInitNode);
Node *MakeEmptyFieldInitNode();
Node *MakeStructInitExpressionNode(Node *typeNode, Node *structInitFieldsNode);
Node *MakeInterfaceDeclarationNode(
Node *identifierNode,
Node *interfaceMembersNode,
Node *genericDeclarationsNode);
Node *StartInterfaceMembersNode(Node *interfaceMemberNode);
Node *AddInterfaceMemberNode(
Node *interfaceMembersNode,
Node *interfaceMemberNode);
void PrintNode(Node *node, uint32_t tabCount);
const char *SyntaxKindString(SyntaxKind syntaxKind);

View File

@ -111,7 +111,7 @@ struct StructTypeDeclaration
uint32_t genericFunctionCount;
};
StructTypeDeclaration *structTypeDeclarations;
StructTypeDeclaration **structTypeDeclarations;
uint32_t structTypeDeclarationCount;
typedef struct MonomorphizedGenericStructHashEntry
@ -401,9 +401,9 @@ static LLVMTypeRef LookupCustomType(char *name)
for (i = 0; i < structTypeDeclarationCount; i += 1)
{
if (strcmp(structTypeDeclarations[i].name, name) == 0)
if (strcmp(structTypeDeclarations[i]->name, name) == 0)
{
return structTypeDeclarations[i].structType;
return structTypeDeclarations[i]->structType;
}
}
@ -420,27 +420,30 @@ static StructTypeDeclaration *AddStructDeclaration(
uint32_t index = structTypeDeclarationCount;
structTypeDeclarations = realloc(
structTypeDeclarations,
sizeof(StructTypeDeclaration) * (structTypeDeclarationCount + 1));
structTypeDeclarations[index].module = module;
structTypeDeclarations[index].structType = wStructType;
structTypeDeclarations[index].structPointerType = wStructPointerType;
structTypeDeclarations[index].name = strdup(name);
structTypeDeclarations[index].fields = NULL;
structTypeDeclarations[index].fieldCount = 0;
structTypeDeclarations[index].functions = NULL;
structTypeDeclarations[index].functionCount = 0;
structTypeDeclarations[index].genericFunctions = NULL;
structTypeDeclarations[index].genericFunctionCount = 0;
sizeof(StructTypeDeclaration*) * (structTypeDeclarationCount + 1));
structTypeDeclarations[index] = malloc(sizeof(StructTypeDeclaration));
structTypeDeclarations[index]->module = module;
structTypeDeclarations[index]->structType = wStructType;
structTypeDeclarations[index]->structPointerType = wStructPointerType;
structTypeDeclarations[index]->name = strdup(name);
structTypeDeclarations[index]->fields = NULL;
structTypeDeclarations[index]->fieldCount = 0;
structTypeDeclarations[index]->functions = NULL;
structTypeDeclarations[index]->functionCount = 0;
structTypeDeclarations[index]->genericFunctions = NULL;
structTypeDeclarations[index]->genericFunctionCount = 0;
structTypeDeclarationCount += 1;
return &structTypeDeclarations[index];
return structTypeDeclarations[index];
}
static StructTypeDeclaration *CompileMonomorphizedGenericStruct(
static MonomorphizedGenericStructHashEntry *CompileMonomorphizedGenericStruct(
GenericStructTypeDeclaration *genericStructTypeDeclaration,
TypeTag **genericArgumentTypes,
uint32_t genericArgumentTypeCount)
uint32_t genericArgumentTypeCount,
MonomorphizedGenericStructHashArray *hashArray,
uint64_t typeHash)
{
uint32_t i = 0;
uint32_t fieldCount = 0;
@ -486,6 +489,25 @@ static StructTypeDeclaration *CompileMonomorphizedGenericStruct(
free(structName);
/* add entry to the hash array here in case of recursion */
hashArray->elements = realloc(
hashArray->elements,
sizeof(MonomorphizedGenericStructHashEntry) *
(hashArray->count + 1));
hashArray->elements[hashArray->count].key = typeHash;
hashArray->elements[hashArray->count].types =
malloc(sizeof(TypeTag *) * genericArgumentTypeCount);
hashArray->elements[hashArray->count].typeCount =
genericArgumentTypeCount;
hashArray->elements[hashArray->count].structDeclaration =
declaration;
for (uint32_t j = 0; j < genericArgumentTypeCount; j += 1)
{
hashArray->elements[hashArray->count].types[j] =
genericArgumentTypes[j];
}
hashArray->count += 1;
/* first build the structure def */
for (i = 0; i < declarationCount; i += 1)
{
@ -528,7 +550,7 @@ static StructTypeDeclaration *CompileMonomorphizedGenericStruct(
PopScopeFrame(scope);
return declaration;
return &hashArray->elements[hashArray->count - 1];;
}
static StructTypeDeclaration *LookupGenericStructType(
@ -578,38 +600,20 @@ static StructTypeDeclaration *LookupGenericStructType(
if (match)
{
hashEntry = &hashArray->elements[i];
hashEntry = &hashArray->elements[j];
break;
}
}
if (hashEntry == NULL)
{
StructTypeDeclaration *structTypeDeclaration =
hashEntry =
CompileMonomorphizedGenericStruct(
&genericStructTypeDeclarations[i],
genericTypeTags,
typeTag->genericArgumentCount);
hashArray->elements = realloc(
hashArray->elements,
sizeof(MonomorphizedGenericStructHashEntry) *
(hashArray->count + 1));
hashArray->elements[hashArray->count].key = typeHash;
hashArray->elements[hashArray->count].types =
malloc(sizeof(TypeTag *) * typeTag->genericArgumentCount);
hashArray->elements[hashArray->count].typeCount =
typeTag->genericArgumentCount;
hashArray->elements[hashArray->count].structDeclaration =
structTypeDeclaration;
for (j = 0; j < typeTag->genericArgumentCount; j += 1)
{
hashArray->elements[hashArray->count].types[j] =
genericTypeTags[j];
}
hashArray->count += 1;
hashEntry = &hashArray->elements[hashArray->count - 1];
typeTag->genericArgumentCount,
hashArray,
typeHash);
}
return hashEntry->structDeclaration;
@ -688,9 +692,9 @@ static LLVMTypeRef LookupStructTypeByName(char *name)
for (i = 0; i < structTypeDeclarationCount; i += 1)
{
if (strcmp(structTypeDeclarations[i].name, name) == 0)
if (strcmp(structTypeDeclarations[i]->name, name) == 0)
{
return structTypeDeclarations[i].structType;
return structTypeDeclarations[i]->structType;
}
}
@ -703,9 +707,9 @@ static StructTypeDeclaration *LookupStructDeclaration(LLVMTypeRef structType)
for (i = 0; i < structTypeDeclarationCount; i += 1)
{
if (structTypeDeclarations[i].structType == structType)
if (structTypeDeclarations[i]->structType == structType)
{
return &structTypeDeclarations[i];
return structTypeDeclarations[i];
}
}
@ -724,18 +728,18 @@ static LLVMValueRef FindStructFieldPointer(
for (i = 0; i < structTypeDeclarationCount; i += 1)
{
if (structTypeDeclarations[i].structPointerType == structPointerType)
if (structTypeDeclarations[i]->structPointerType == structPointerType)
{
for (j = 0; j < structTypeDeclarations[i].fieldCount; j += 1)
for (j = 0; j < structTypeDeclarations[i]->fieldCount; j += 1)
{
if (strcmp(structTypeDeclarations[i].fields[j].name, name) == 0)
if (strcmp(structTypeDeclarations[i]->fields[j].name, name) == 0)
{
char *ptrName = strdup(name);
ptrName = w_strcat(ptrName, "_ptr");
return LLVMBuildStructGEP(
builder,
structPointer,
structTypeDeclarations[i].fields[j].index,
structTypeDeclarations[i]->fields[j].index,
ptrName);
free(ptrName);
}
@ -1175,29 +1179,29 @@ static LLVMValueRef LookupFunctionByType(
for (i = 0; i < structTypeDeclarationCount; i += 1)
{
if (structTypeDeclarations[i].structType == structType)
if (structTypeDeclarations[i]->structType == structType)
{
for (j = 0; j < structTypeDeclarations[i].functionCount; j += 1)
for (j = 0; j < structTypeDeclarations[i]->functionCount; j += 1)
{
if (strcmp(structTypeDeclarations[i].functions[j].name, name) ==
if (strcmp(structTypeDeclarations[i]->functions[j].name, name) ==
0)
{
*pReturnType =
structTypeDeclarations[i].functions[j].returnType;
*pStatic = structTypeDeclarations[i].functions[j].isStatic;
return structTypeDeclarations[i].functions[j].function;
structTypeDeclarations[i]->functions[j].returnType;
*pStatic = structTypeDeclarations[i]->functions[j].isStatic;
return structTypeDeclarations[i]->functions[j].function;
}
}
for (j = 0; j < structTypeDeclarations[i].genericFunctionCount;
for (j = 0; j < structTypeDeclarations[i]->genericFunctionCount;
j += 1)
{
if (strcmp(
structTypeDeclarations[i].genericFunctions[j].name,
structTypeDeclarations[i]->genericFunctions[j].name,
name) == 0)
{
return LookupGenericFunction(
&structTypeDeclarations[i].genericFunctions[j],
&structTypeDeclarations[i]->genericFunctions[j],
functionCallExpression,
pReturnType,
pStatic);
@ -1221,29 +1225,29 @@ static LLVMValueRef LookupFunctionByPointerType(
for (i = 0; i < structTypeDeclarationCount; i += 1)
{
if (structTypeDeclarations[i].structPointerType == structPointerType)
if (structTypeDeclarations[i]->structPointerType == structPointerType)
{
for (j = 0; j < structTypeDeclarations[i].functionCount; j += 1)
for (j = 0; j < structTypeDeclarations[i]->functionCount; j += 1)
{
if (strcmp(structTypeDeclarations[i].functions[j].name, name) ==
if (strcmp(structTypeDeclarations[i]->functions[j].name, name) ==
0)
{
*pReturnType =
structTypeDeclarations[i].functions[j].returnType;
*pStatic = structTypeDeclarations[i].functions[j].isStatic;
return structTypeDeclarations[i].functions[j].function;
structTypeDeclarations[i]->functions[j].returnType;
*pStatic = structTypeDeclarations[i]->functions[j].isStatic;
return structTypeDeclarations[i]->functions[j].function;
}
}
for (j = 0; j < structTypeDeclarations[i].genericFunctionCount;
for (j = 0; j < structTypeDeclarations[i]->genericFunctionCount;
j += 1)
{
if (strcmp(
structTypeDeclarations[i].genericFunctions[j].name,
structTypeDeclarations[i]->genericFunctions[j].name,
name) == 0)
{
return LookupGenericFunction(
&structTypeDeclarations[i].genericFunctions[j],
&structTypeDeclarations[i]->genericFunctions[j],
functionCallExpression,
pReturnType,
pStatic);
@ -1369,6 +1373,31 @@ static LLVMValueRef CompileFunctionCallExpression(
*/
if (functionCallExpression->functionCallExpression.identifier->syntaxKind ==
AccessExpression)
{
if (functionCallExpression->functionCallExpression.identifier->accessExpression.accessee->syntaxKind ==
ConcreteGenericTypeNode)
{
TypeTag *typeTag =
MakeTypeTag(
functionCallExpression->functionCallExpression.identifier->accessExpression.accessee
);
LLVMTypeRef typeReference = ResolveType(typeTag);
char *functionName =
functionCallExpression->functionCallExpression.identifier
->accessExpression.accessor->identifier.name;
function = LookupFunctionByType(
typeReference,
functionName,
functionCallExpression,
&functionReturnType,
&isStatic
);
free(typeTag);
}
else
{
LLVMTypeRef typeReference = LookupStructTypeByName(
functionCallExpression->functionCallExpression.identifier
@ -1401,6 +1430,7 @@ static LLVMValueRef CompileFunctionCallExpression(
&isStatic);
}
}
}
else if (
functionCallExpression->functionCallExpression.identifier->syntaxKind ==
Identifier)
@ -1613,6 +1643,7 @@ static LLVMValueRef CompileStructInitExpression(
LLVMTypeRef structType = ResolveType(
ConcretizeType(structInitExpression->structInit.type->typeTag));
/* FIXME: this can be given by struct instead of allocated */
LLVMValueRef structPointer =
LLVMBuildAlloca(builder, structType, "structInit");
@ -1628,19 +1659,40 @@ static LLVMValueRef CompileStructInitExpression(
.fieldInits[i]
->fieldInit.identifier->identifier.name);
LLVMBuildStore(
builder,
CompileExpression(
LLVMValueRef fieldExpressionResult = CompileExpression(
structTypeDeclaration,
selfParam,
builder,
structInitExpression->structInit.initFields->structInitFields
.fieldInits[i]
->fieldInit.expression),
->fieldInit.expression);
LLVMTypeKind fieldExpressionTypeKind = LLVMGetTypeKind(LLVMTypeOf(fieldExpressionResult));
if (fieldExpressionTypeKind == LLVMPointerTypeKind)
{
LLVMBuildMemCpy(
builder,
structPointer,
LLVMGetAlignment(structPointer),
fieldExpressionResult,
LLVMGetAlignment(fieldExpressionResult),
LLVMSizeOf(LLVMTypeOf(fieldExpressionResult))
);
}
else
{
LLVMBuildStore(
builder,
fieldExpressionResult,
structFieldPointer);
}
}
return structPointer;
return LLVMBuildLoad(
builder,
structPointer,
"struct"
);
}
static LLVMValueRef CompileExpression(
@ -2334,11 +2386,17 @@ static void Compile(
context,
declarationSequenceNode->declarationSequence.sequence[i]);
}
else if (
declarationSequenceNode->declarationSequence.sequence[i]
->syntaxKind == Interface)
{
/* Interfaces don't need to compile! */
}
else
{
fprintf(
stderr,
"top level declarations that are not structs are "
"top level declarations that are not structs or interfaces are "
"forbidden!\n");
}
}

View File

@ -432,6 +432,41 @@ void ConvertCustomsToGenerics(Node *node)
switch (node->syntaxKind)
{
case Type:
{
Node *type = node->type.typeNode;
if (type->syntaxKind == CustomTypeNode)
{
char *target = type->customType.name;
Node *typeLookup = LookupType(node, target);
if (typeLookup != NULL &&
typeLookup->syntaxKind == GenericDeclaration)
{
node->typeTag->type = Generic;
free(node->declaration.type);
node->declaration.type =
MakeGenericTypeNode(node->typeTag->value.genericType);
}
}
else if (type->syntaxKind == ConcreteGenericTypeNode)
{
for (int32_t i = 0; i < node->typeTag->value.concreteGenericType.genericArgumentCount; i += 1)
{
if (node->typeTag->value.concreteGenericType.genericArguments[i]->type == Custom)
{
char *target = node->typeTag->value.concreteGenericType.genericArguments[i]->value.customType;
Node *typeLookup = LookupType(node, target);
if (typeLookup != NULL &&
typeLookup->syntaxKind == GenericDeclaration)
{
node->typeTag->value.concreteGenericType.genericArguments[i]->type = Generic;
}
}
}
}
break;
}
case Declaration:
{
Node *id = node->declaration.identifier;
@ -449,6 +484,22 @@ void ConvertCustomsToGenerics(Node *node)
MakeGenericTypeNode(id->typeTag->value.genericType);
}
}
else if (type->syntaxKind == ConcreteGenericTypeNode)
{
for (int32_t i = 0; i < id->typeTag->value.concreteGenericType.genericArgumentCount; i += 1)
{
if (id->typeTag->value.concreteGenericType.genericArguments[i]->type == Custom)
{
char *target = id->typeTag->value.concreteGenericType.genericArguments[i]->value.customType;
Node *typeLookup = LookupType(node, target);
if (typeLookup != NULL &&
typeLookup->syntaxKind == GenericDeclaration)
{
id->typeTag->value.concreteGenericType.genericArguments[i]->type = Generic;
}
}
}
}
break;
}
@ -468,6 +519,58 @@ void ConvertCustomsToGenerics(Node *node)
node->functionSignature.type =
MakeGenericTypeNode(id->typeTag->value.genericType);
}
}
else if (type->syntaxKind == ConcreteGenericTypeNode)
{
for (int32_t i = 0; i < id->typeTag->value.concreteGenericType.genericArgumentCount; i += 1)
{
if (id->typeTag->value.concreteGenericType.genericArguments[i]->type == Custom)
{
char *target = id->typeTag->value.concreteGenericType.genericArguments[i]->value.customType;
Node *typeLookup = LookupType(node, target);
if (typeLookup != NULL &&
typeLookup->syntaxKind == GenericDeclaration)
{
id->typeTag->value.concreteGenericType.genericArguments[i]->type = Generic;
}
}
}
}
break;
}
case StructInit:
{
Node *type = node->structInit.type->type.typeNode;
TypeTag *typeTag = node->structInit.type->typeTag;
if (type->syntaxKind == CustomTypeNode)
{
char *target = typeTag->value.customType;
Node *typeLookup = LookupType(node, target);
if (typeLookup != NULL &&
typeLookup->syntaxKind == GenericDeclaration)
{
typeTag->type = Generic;
free(node->functionSignature.type);
node->functionSignature.type =
MakeGenericTypeNode(typeTag->value.genericType);
}
}
else if (type->syntaxKind == ConcreteGenericTypeNode)
{
for (int32_t i = 0; i < typeTag->value.concreteGenericType.genericArgumentCount; i += 1)
{
if (typeTag->value.concreteGenericType.genericArguments[i]->type == Custom)
{
char *target = typeTag->value.concreteGenericType.genericArguments[i]->value.customType;
Node *typeLookup = LookupType(node, target);
if (typeLookup != NULL &&
typeLookup->syntaxKind == GenericDeclaration)
{
typeTag->value.concreteGenericType.genericArguments[i]->type = Generic;
}
}
}
}
break;
}