Skip to content

Commit

Permalink
Detect duplicate field initializers (#416)
Browse files Browse the repository at this point in the history
  • Loading branch information
vtereshkov committed Jul 3, 2024
1 parent e7bb46b commit 821921e
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 17 deletions.
2 changes: 1 addition & 1 deletion playground/umka.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/umka_decl.c
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,7 @@ static void parseFnDecl(Compiler *comp)
{
Type *rcvBaseType = fnType->sig.param[0]->type->base;

if (rcvBaseType->kind == TYPE_STRUCT && typeFindField(rcvBaseType, name))
if (rcvBaseType->kind == TYPE_STRUCT && typeFindField(rcvBaseType, name, NULL))
comp->error.handler(comp->error.context, "Structure already has field %s", name);
}

Expand Down
34 changes: 25 additions & 9 deletions src/umka_expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ static void doPtrToInterfaceConv(Compiler *comp, Type *dest, Type **src, Const *
genSwapAssign(&comp->gen, TYPE_PTR, 0); // Assign to dest.__self

// Assign to __selftype (RTTI)
Field *selfType = typeAssertFindField(&comp->types, dest, "__selftype");
Field *selfType = typeAssertFindField(&comp->types, dest, "__selftype", NULL);

genPushGlobalPtr(&comp->gen, *src); // Push src type
genPushLocalPtr(&comp->gen, destOffset + selfType->offset); // Push dest.__selftype pointer
Expand Down Expand Up @@ -440,7 +440,7 @@ static void doInterfaceToInterfaceConv(Compiler *comp, Type *dest, Type **src, C
genSwapAssign(&comp->gen, TYPE_PTR, 0); // Assign to dest.__self (NULL means a dynamic type)

// Assign to __selftype (RTTI)
Field *selfType = typeAssertFindField(&comp->types, dest, "__selftype");
Field *selfType = typeAssertFindField(&comp->types, dest, "__selftype", NULL);

genDup(&comp->gen); // Duplicate src pointer
genGetFieldPtr(&comp->gen, selfType->offset); // Get src.__selftype pointer
Expand All @@ -452,7 +452,7 @@ static void doInterfaceToInterfaceConv(Compiler *comp, Type *dest, Type **src, C
for (int i = 2; i < dest->numItems; i++)
{
const char *name = dest->field[i]->name;
Field *srcMethod = typeFindField(*src, name);
Field *srcMethod = typeFindField(*src, name, NULL);
if (!srcMethod)
comp->error.handler(comp->error.context, "Method %s is not implemented", name);

Expand Down Expand Up @@ -1557,7 +1557,7 @@ static void parseCall(Compiler *comp, Type **type, Const *constant)
if ((*type)->kind == TYPE_CLOSURE)
{
// Closure upvalue
Field *fn = typeAssertFindField(&comp->types, *type, "__fn");
Field *fn = typeAssertFindField(&comp->types, *type, "__fn", NULL);
*type = fn->type;

genPushUpvalue(&comp->gen);
Expand Down Expand Up @@ -1768,6 +1768,8 @@ static void parseArrayOrStructLiteral(Compiler *comp, Type **type, Const *consta
lexEat(&comp->lex, TOK_LBRACE);

bool namedFields = false;
bool *fieldInitialized = NULL;

if ((*type)->kind == TYPE_STRUCT)
{
if (comp->lex.tok.kind == TOK_RBRACE)
Expand All @@ -1780,6 +1782,9 @@ static void parseArrayOrStructLiteral(Compiler *comp, Type **type, Const *consta
}
}

if (namedFields)
fieldInitialized = calloc((*type)->numItems + 1, sizeof(bool));

const int size = typeSize(&comp->types, *type);
Ident *arrayOrStruct = NULL;

Expand Down Expand Up @@ -1808,7 +1813,14 @@ static void parseArrayOrStructLiteral(Compiler *comp, Type **type, Const *consta
if (namedFields)
{
lexCheck(&comp->lex, TOK_IDENT);
field = typeAssertFindField(&comp->types, *type, comp->lex.tok.name);

int fieldIndex = 0;
field = typeAssertFindField(&comp->types, *type, comp->lex.tok.name, &fieldIndex);

if (field && fieldInitialized[fieldIndex])
comp->error.handler(comp->error.context, "Duplicate field %s", field->name);

fieldInitialized[fieldIndex] = true;
itemOffset = field->offset;

lexNext(&comp->lex);
Expand Down Expand Up @@ -1846,9 +1858,13 @@ static void parseArrayOrStructLiteral(Compiler *comp, Type **type, Const *consta
lexNext(&comp->lex);
}
}

if (!namedFields && numItems < (*type)->numItems)
comp->error.handler(comp->error.context, "Too few elements in literal");

if (fieldInitialized)
free(fieldInitialized);

if (!constant)
doPushVarPtr(comp, arrayOrStruct);

Expand Down Expand Up @@ -2028,7 +2044,7 @@ static void parseClosureLiteral(Compiler *comp, Type **type, Const *constant)
if (comp->blocks.top != 0)
genNop(&comp->gen); // Jump over the nested function block (stub)

Field *fn = typeAssertFindField(&comp->types, *type, "__fn");
Field *fn = typeAssertFindField(&comp->types, *type, "__fn", NULL);

Const fnConstant = {.intVal = comp->gen.ip};
Ident *fnConstantIdent = identAddTempConst(&comp->idents, &comp->modules, &comp->blocks, fn->type, fnConstant);
Expand Down Expand Up @@ -2095,7 +2111,7 @@ static void parseClosureLiteral(Compiler *comp, Type **type, Const *constant)
}

// Assign closure upvalues
Field *upvalues = typeAssertFindField(&comp->types, closureIdent->type, "__upvalues");
Field *upvalues = typeAssertFindField(&comp->types, closureIdent->type, "__upvalues", NULL);
Type *upvaluesType = upvaluesStructIdent->type;

doPushVarPtr(comp, closureIdent);
Expand All @@ -2113,7 +2129,7 @@ static void parseClosureLiteral(Compiler *comp, Type **type, Const *constant)

genNop(&comp->gen); // Jump over the nested function block (stub)

Field *fn = typeAssertFindField(&comp->types, closureIdent->type, "__fn");
Field *fn = typeAssertFindField(&comp->types, closureIdent->type, "__fn", NULL);

Const fnConstant = {.intVal = comp->gen.ip};
Ident *fnConstantIdent = identAddTempConst(&comp->idents, &comp->modules, &comp->blocks, fn->type, fnConstant);
Expand Down Expand Up @@ -2365,7 +2381,7 @@ static void parseFieldSelector(Compiler *comp, Type **type, Const *constant, boo
comp->error.handler(comp->error.context, "Method %s is not defined for %s", comp->lex.tok.name, typeSpelling(*type, typeBuf));
}

Field *field = typeAssertFindField(&comp->types, *type, comp->lex.tok.name);
Field *field = typeAssertFindField(&comp->types, *type, comp->lex.tok.name, NULL);
lexNext(&comp->lex);

genGetFieldPtr(&comp->gen, field->offset);
Expand Down
12 changes: 8 additions & 4 deletions src/umka_types.c
Original file line number Diff line number Diff line change
Expand Up @@ -574,22 +574,26 @@ void typeEnableForward(Types *types, bool enable)
}


Field *typeFindField(Type *structType, const char *name)
Field *typeFindField(Type *structType, const char *name, int *index)
{
if (structType->kind == TYPE_STRUCT || structType->kind == TYPE_INTERFACE || structType->kind == TYPE_CLOSURE)
{
unsigned int nameHash = hash(name);
for (int i = 0; i < structType->numItems; i++)
if (structType->field[i]->hash == nameHash && strcmp(structType->field[i]->name, name) == 0)
{
if (index)
*index = i;
return structType->field[i];
}
}
return NULL;
}


Field *typeAssertFindField(Types *types, Type *structType, const char *name)
Field *typeAssertFindField(Types *types, Type *structType, const char *name, int *index)
{
Field *res = typeFindField(structType, name);
Field *res = typeFindField(structType, name, index);
if (!res)
types->error->handler(types->error->context, "Unknown field %s", name);
return res;
Expand All @@ -610,7 +614,7 @@ Field *typeAddField(Types *types, Type *structType, Type *fieldType, const char
name = fieldNameBuf;
}

Field *field = typeFindField(structType, name);
Field *field = typeFindField(structType, name, NULL);
if (field)
types->error->handler(types->error->context, "Duplicate field %s", name);

Expand Down
4 changes: 2 additions & 2 deletions src/umka_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,8 @@ static inline bool typeOverflow(TypeKind typeKind, Const val)
}


Field *typeFindField (Type *structType, const char *name);
Field *typeAssertFindField (Types *types, Type *structType, const char *name);
Field *typeFindField (Type *structType, const char *name, int *index);
Field *typeAssertFindField (Types *types, Type *structType, const char *name, int *index);
Field *typeAddField (Types *types, Type *structType, Type *fieldType, const char *fieldName);

EnumConst *typeFindEnumConst (Type *enumType, const char *name);
Expand Down

0 comments on commit 821921e

Please sign in to comment.