From 03e4c3d7b7b3cbe82ef0d16ad74a279c06fee2a2 Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Sun, 25 Feb 2024 03:42:15 +0100 Subject: [PATCH] Fix bug with normal map usecase --- media/test-project/test.spice | 52 +------------------ src/symboltablebuilder/SymbolType.h | 2 +- src/typechecker/StructManager.cpp | 4 ++ src/typechecker/TypeChecker.h | 5 ++ src/typechecker/TypeCheckerCheck.cpp | 16 ++++++ src/typechecker/TypeCheckerImplicit.cpp | 68 ++++++++++++++++++++++++- 6 files changed, 95 insertions(+), 52 deletions(-) diff --git a/media/test-project/test.spice b/media/test-project/test.spice index a52a22de2..8e3b7e268 100644 --- a/media/test-project/test.spice +++ b/media/test-project/test.spice @@ -1,55 +1,7 @@ -import "bootstrap/bindings/llvm/llvm" as llvm; -import "std/data/vector"; +import "std/data/map"; f 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 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 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 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 map; } /*import "bootstrap/util/block-allocator"; diff --git a/src/symboltablebuilder/SymbolType.h b/src/symboltablebuilder/SymbolType.h index 5f5e271ba..401562a33 100644 --- a/src/symboltablebuilder/SymbolType.h +++ b/src/symboltablebuilder/SymbolType.h @@ -208,7 +208,7 @@ class SymbolType { [[nodiscard]] const std::vector &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); diff --git a/src/typechecker/StructManager.cpp b/src/typechecker/StructManager.cpp index a2a96ac3b..8a119b6ac 100644 --- a/src/typechecker/StructManager.cpp +++ b/src/typechecker/StructManager.cpp @@ -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 diff --git a/src/typechecker/TypeChecker.h b/src/typechecker/TypeChecker.h index 9b90db0f9..b523b733a 100644 --- a/src/typechecker/TypeChecker.h +++ b/src/typechecker/TypeChecker.h @@ -146,9 +146,14 @@ class TypeChecker : private CompilerPass, public ASTVisitor { // Implicit code generation void createDefaultStructMethod(const Struct &spiceStruct, const std::string &methodName, const ParamList ¶ms); 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); diff --git a/src/typechecker/TypeCheckerCheck.cpp b/src/typechecker/TypeCheckerCheck.cpp index cdbde4db6..fec29e405 100644 --- a/src/typechecker/TypeCheckerCheck.cpp +++ b/src/typechecker/TypeCheckerCheck.cpp @@ -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); diff --git a/src/typechecker/TypeCheckerImplicit.cpp b/src/typechecker/TypeCheckerImplicit.cpp index 3a1fbbf5c..9a5da4227 100644 --- a/src/typechecker/TypeCheckerImplicit.cpp +++ b/src/typechecker/TypeCheckerImplicit.cpp @@ -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. * @@ -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. * @@ -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. @@ -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(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(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); @@ -235,7 +301,7 @@ void TypeChecker::createCtorBodyPreamble(Scope *bodyScope) { auto fieldNode = spice_pointer_cast(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); } } }