Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix bug with normal map usecase #480

Merged
merged 1 commit into from
Feb 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 2 additions & 50 deletions media/test-project/test.spice
Original file line number Diff line number Diff line change
@@ -1,55 +1,7 @@
import "bootstrap/bindings/llvm/llvm" as llvm;
import "std/data/vector";
import "std/data/map";

f<int> main() {
llvm::initializeNativeTarget();
llvm::initializeNativeAsmPrinter();

heap string targetTriple = llvm::getDefaultTargetTriple();
string error;
llvm::Target target = llvm::getTargetFromTriple(targetTriple, &error);
llvm::TargetMachine targetMachine = target.createTargetMachine(targetTriple, "generic", "", llvm::LLVMCodeGenOptLevel::Default, llvm::LLVMRelocMode::Default, llvm::LLVMCodeModel::Default);

llvm::LLVMContext context;
llvm::Module module = llvm::Module("test", context);
module.setDataLayout(targetMachine.createDataLayout());
module.setTargetTriple(targetTriple);
llvm::Builder builder = llvm::Builder(context);

llvm::Type returnType = builder.getInt32Ty();
Vector<llvm::Type> argTypes;
llvm::Type funcType = llvm::getFunctionType(returnType, argTypes);
llvm::Function func = llvm::Function(module, "main", funcType);
func.setLinkage(llvm::LLVMLinkage::ExternalLinkage);

llvm::BasicBlock entry = llvm::BasicBlock(context, "");
func.pushBack(entry);
builder.setInsertPoint(entry);

llvm::Value calcResult = builder.createAdd(builder.getInt32(1), builder.getInt32(2), "calcResult");

llvm::Value helloWorldStr = builder.createGlobalStringPtr("Hello, world!\n", "helloWorldStr");
Vector<llvm::Type> printfArgTypes;
printfArgTypes.pushBack(builder.getPtrTy());
printfArgTypes.pushBack(builder.getInt32Ty());
llvm::Type printfFuncType = llvm::getFunctionType(builder.getInt32Ty(), printfArgTypes, true);
llvm::Function printfFunc = module.getOrInsertFunction("printf", printfFuncType);

Vector<llvm::Value> printfArgs;
printfArgs.pushBack(helloWorldStr);
printfArgs.pushBack(calcResult);
builder.createCall(printfFunc, printfArgs);

builder.createRet(builder.getInt32(0));

assert !llvm::verifyFunction(func);
string output;
assert !llvm::verifyModule(module, &output);

printf("%s", module.print());

llvm::PassBuilderOptions passBuilderOptions;

Map<int, string> map;
}

/*import "bootstrap/util/block-allocator";
Expand Down
2 changes: 1 addition & 1 deletion src/symboltablebuilder/SymbolType.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ class SymbolType {
[[nodiscard]] const std::vector<SymbolType> &getFunctionParamAndReturnTypes() const;
void setHasLambdaCaptures(bool hasCaptures);
[[nodiscard]] bool hasLambdaCaptures() const;
[[nodiscard]] Struct *getStruct(const ASTNode *node) const;
Struct *getStruct(const ASTNode *node) const;
[[nodiscard]] Interface *getInterface(const ASTNode *node) const;
friend bool operator==(const SymbolType &lhs, const SymbolType &rhs);
friend bool operator!=(const SymbolType &lhs, const SymbolType &rhs);
Expand Down
4 changes: 4 additions & 0 deletions src/typechecker/StructManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ Struct *StructManager::matchStruct(Scope *matchScope, const std::string &reqName
}

fieldEntry->updateType(fieldType, /*overwriteExistingType=*/true);

// Instantiate structs
if (baseType.is(TY_STRUCT))
baseType.getStruct(node);
}

// Instantiate implemented interfaces if required
Expand Down
5 changes: 5 additions & 0 deletions src/typechecker/TypeChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,14 @@ class TypeChecker : private CompilerPass, public ASTVisitor {
// Implicit code generation
void createDefaultStructMethod(const Struct &spiceStruct, const std::string &methodName, const ParamList &params);
void createDefaultCtorIfRequired(const Struct &spiceStruct, Scope *structScope);
void createDefaultCtorBody(const Function *ctorFunction);
void createDefaultCopyCtorIfRequired(const Struct &spiceStruct, Scope *structScope);
void createDefaultCopyCtorBody(const Function *copyCtorFunction);
void createDefaultDtorIfRequired(const Struct &spiceStruct, Scope *structScope);
void createDefaultDtorBody(const Function *dtorFunction);
void createCtorBodyPreamble(Scope *bodyScope);
void createCopyCtorBodyPreamble(Scope *bodyScope);
void createDtorBodyPreamble(Scope *bodyScope);
Function *implicitlyCallStructMethod(SymbolTableEntry *entry, const std::string &methodName, const ArgList &args,
const ASTNode *node);
void implicitlyCallStructCopyCtor(SymbolTableEntry *entry, const ASTNode *node);
Expand Down
16 changes: 16 additions & 0 deletions src/typechecker/TypeCheckerCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,22 @@ std::any TypeChecker::visitStructDefCheck(StructDefNode *node) {
}
}

// Generate default ctor body if required
const Function *ctorFunc = FunctionManager::lookupFunction(currentScope, CTOR_FUNCTION_NAME, structType, {}, true);
if (ctorFunc != nullptr && ctorFunc->implicitDefault)
createDefaultCtorBody(ctorFunc);

// Generate default copy ctor body if required
const ArgList args = {{structType.toConstReference(node), false /* always non-temporary */}};
const Function *copyCtorFunc = FunctionManager::lookupFunction(currentScope, CTOR_FUNCTION_NAME, structType, args, true);
if (copyCtorFunc != nullptr && copyCtorFunc->implicitDefault)
createDefaultCopyCtorBody(copyCtorFunc);

// Generate default dtor body if required
const Function *dtorFunc = FunctionManager::lookupFunction(currentScope, DTOR_FUNCTION_NAME, structType, {}, true);
if (dtorFunc != nullptr && dtorFunc->implicitDefault)
createDefaultDtorBody(dtorFunc);

// Return to the root scope
currentScope = rootScope;
assert(currentScope != nullptr && currentScope->type == ScopeType::GLOBAL);
Expand Down
68 changes: 67 additions & 1 deletion src/typechecker/TypeCheckerImplicit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ void TypeChecker::createDefaultCtorIfRequired(const Struct &spiceStruct, Scope *
createDefaultStructMethod(spiceStruct, CTOR_FUNCTION_NAME, {});
}

void TypeChecker::createDefaultCtorBody(const Function *ctorFunction) { createCtorBodyPreamble(ctorFunction->bodyScope); }

/**
* Checks if the given struct scope already has an user-defined constructor and creates a default one if not.
*
Expand Down Expand Up @@ -156,6 +158,10 @@ void TypeChecker::createDefaultCopyCtorIfRequired(const Struct &spiceStruct, Sco
createDefaultStructMethod(spiceStruct, CTOR_FUNCTION_NAME, paramTypes);
}

void TypeChecker::createDefaultCopyCtorBody(const Function *copyCtorFunction) {
createCopyCtorBodyPreamble(copyCtorFunction->bodyScope);
}

/**
* Checks if the given struct scope already has an user-defined destructor and creates a default one if not.
*
Expand Down Expand Up @@ -214,6 +220,8 @@ void TypeChecker::createDefaultDtorIfRequired(const Struct &spiceStruct, Scope *
}
}

void TypeChecker::createDefaultDtorBody(const Function *dtorFunction) { createDtorBodyPreamble(dtorFunction->bodyScope); }

/**
* Prepare the generation of the ctor body preamble. This preamble is used to initialize the VTable, construct or initialize
* fields.
Expand All @@ -223,6 +231,64 @@ void TypeChecker::createCtorBodyPreamble(Scope *bodyScope) {
Scope *structScope = bodyScope->parent;
assert(structScope != nullptr);

const size_t fieldCount = structScope->getFieldCount();
for (size_t i = 0; i < fieldCount; i++) {
SymbolTableEntry *fieldSymbol = structScope->symbolTable.lookupStrictByIndex(i);
assert(fieldSymbol != nullptr && fieldSymbol->isField());
if (fieldSymbol->isImplicitField)
continue;
SymbolType fieldType = fieldSymbol->getType();

if (fieldType.is(TY_STRUCT)) {
auto fieldNode = spice_pointer_cast<FieldNode *>(fieldSymbol->declNode);
// Match ctor function, create the concrete manifestation and set it to used
Scope *matchScope = fieldType.getBodyScope();
Function *spiceFunc = FunctionManager::matchFunction(matchScope, CTOR_FUNCTION_NAME, fieldType, {}, {}, false, fieldNode);
if (spiceFunc != nullptr) {
fieldType.setBodyScope(spiceFunc->thisType.getBodyScope());
fieldSymbol->updateType(fieldType, true);
}
}
}
}

/**
* Prepare the generation of the copy ctor body preamble. This preamble is used to initialize the VTable, construct or initialize
* fields.
*/
void TypeChecker::createCopyCtorBodyPreamble(Scope *bodyScope) {
// Retrieve struct scope
Scope *structScope = bodyScope->parent;
assert(structScope != nullptr);

const size_t fieldCount = structScope->getFieldCount();
for (size_t i = 0; i < fieldCount; i++) {
SymbolTableEntry *fieldSymbol = structScope->symbolTable.lookupStrictByIndex(i);
assert(fieldSymbol != nullptr && fieldSymbol->isField());
if (fieldSymbol->isImplicitField)
continue;
SymbolType fieldType = fieldSymbol->getType();

if (fieldType.is(TY_STRUCT)) {
auto fieldNode = spice_pointer_cast<FieldNode *>(fieldSymbol->declNode);
// Match ctor function, create the concrete manifestation and set it to used
Scope *matchScope = fieldType.getBodyScope();
const ArgList args = {{fieldType.toConstReference(fieldNode), false /* we always have the field as storage */}};
Function *spiceFunc = FunctionManager::matchFunction(matchScope, CTOR_FUNCTION_NAME, fieldType, args, {}, false, fieldNode);
fieldType.setBodyScope(spiceFunc->thisType.getBodyScope());
fieldSymbol->updateType(fieldType, true);
}
}
}

/**
* Prepare the generation of the dtor body preamble. This preamble is used to destruct all fields and to free all heap fields.
*/
void TypeChecker::createDtorBodyPreamble(Scope *bodyScope) {
// Retrieve struct scope
Scope *structScope = bodyScope->parent;
assert(structScope != nullptr);

const size_t fieldCount = structScope->getFieldCount();
for (size_t i = 0; i < fieldCount; i++) {
SymbolTableEntry *fieldSymbol = structScope->symbolTable.lookupStrictByIndex(i);
Expand All @@ -235,7 +301,7 @@ void TypeChecker::createCtorBodyPreamble(Scope *bodyScope) {
auto fieldNode = spice_pointer_cast<FieldNode *>(fieldSymbol->declNode);
// Match ctor function, create the concrete manifestation and set it to used
Scope *matchScope = fieldType.getBodyScope();
FunctionManager::matchFunction(matchScope, CTOR_FUNCTION_NAME, fieldType, {}, {}, false, fieldNode);
FunctionManager::matchFunction(matchScope, DTOR_FUNCTION_NAME, fieldType, {}, {}, false, fieldNode);
}
}
}
Expand Down