From 6ae44c4a3c6c9bd65086a5877ea7f463c6fdb531 Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Fri, 20 Jan 2023 02:25:30 +0100 Subject: [PATCH] Fix bug in struct substantiation --- media/specs/name-mangling.md | 2 +- media/test-project/os-test.spice | 83 ++----------------- src/irgenerator/GenTopLevelDefinitions.cpp | 12 ++- src/irgenerator/IRGenerator.cpp | 1 + src/model/Function.cpp | 28 ++++++- src/model/Function.h | 3 + src/model/Struct.cpp | 44 +++++----- src/model/Struct.h | 4 +- src/symboltablebuilder/Scope.cpp | 12 +-- src/symboltablebuilder/SymbolTableBuilder.cpp | 4 +- src/typechecker/FunctionManager.cpp | 12 +-- src/typechecker/StructManager.cpp | 15 ++-- src/typechecker/TypeChecker.cpp | 5 +- src/typechecker/TypeCheckerCheck.cpp | 4 +- src/typechecker/TypeCheckerPrepare.cpp | 6 +- .../std/data/combined-test-1-fq/cout.out | 1 + .../std/data/combined-test-1-fq/ir-code-O2.ll | 61 ++++++++++++++ .../std/data/combined-test-1-fq/source.spice | 11 +++ .../std/data/combined-test-1/source.spice | 12 +-- 19 files changed, 178 insertions(+), 142 deletions(-) create mode 100644 test/test-files/std/data/combined-test-1-fq/cout.out create mode 100644 test/test-files/std/data/combined-test-1-fq/ir-code-O2.ll create mode 100644 test/test-files/std/data/combined-test-1-fq/source.spice diff --git a/media/specs/name-mangling.md b/media/specs/name-mangling.md index 56038205d..da5296495 100644 --- a/media/specs/name-mangling.md +++ b/media/specs/name-mangling.md @@ -56,4 +56,4 @@ Here is the scheme, how Spice mangles struct names: ### Implementation To see the implementation for struct name mangling, have a look here: -[Struct::gerMangledName](../../src/model/Struct.cpp#:~:text=Struct::getMangledName) \ No newline at end of file +[Struct::getMangledName](../../src/model/Struct.cpp#:~:text=Struct::getMangledName) \ No newline at end of file diff --git a/media/test-project/os-test.spice b/media/test-project/os-test.spice index 96e78c86d..3ab57d1b4 100644 --- a/media/test-project/os-test.spice +++ b/media/test-project/os-test.spice @@ -1,78 +1,11 @@ -type T int|long; - -type TestStruct struct { - T f1 - unsigned long length -} - -p TestStruct.ctor(const unsigned long initialLength) { - this.length = initialLength; -} - -p TestStruct.printLength() { - printf("%d\n", this.length); -} - -type Alias alias TestStruct; - -f main() { - Alias a = Alias{12345l, 54321l}; - a.printLength(); - dyn b = Alias(12l); - b.printLength(); -} - -/*type T dyn; - -type Vector struct { - T data -} - -p Vector.ctor() { - this.data = 12; -} - -f main() { - Vector intVec = Vector(); -}*/ - -/*type T string|char; - -type TestStruct struct { - T base - int test -} - -f main() { - TestStruct s = TestStruct{ 'a', 1 }; - s.printTest(); -} - -p TestStruct.printTest() { - printf("Test: %d\n", this.getTest()); -} - -f TestStruct.getTest() { - if this.test == 1 { - this.test++; - this.printTest(); - } - return this.test; -}*/ - -/*ext malloc(long); -ext free(byte*); +import "std/data/vector" as vec; +import "std/data/pair" as pair; f main() { - byte* address = malloc(1l); - *address = (byte) 12; - free(address); -}*/ + Vector> pairVector = Vector>(); + pairVector.pushBack(Pair(0, "Hello")); + pairVector.pushBack(Pair(1, "World")); -/*f main() { - int[10] a; - for int i = 0; i < len(a); i++ { - a[i] = 1; - } - printf("Cell [3]: %d", a[3]); -}*/ \ No newline at end of file + Pair p1 = pairVector.get(1); + printf("Hello %s!\n", p1.getSecond()); +} \ No newline at end of file diff --git a/src/irgenerator/GenTopLevelDefinitions.cpp b/src/irgenerator/GenTopLevelDefinitions.cpp index cee5b8b55..b0ce6f81f 100644 --- a/src/irgenerator/GenTopLevelDefinitions.cpp +++ b/src/irgenerator/GenTopLevelDefinitions.cpp @@ -157,7 +157,7 @@ std::any IRGenerator::visitFctDef(const FctDefNode *node) { } // Change scope - currentScope = currentScope->getChildScope(manifestation->getSignature()); + currentScope = currentScope->getChildScope(manifestation->getSignature(false)); assert(currentScope != nullptr); // Get 'this' entry @@ -321,7 +321,7 @@ std::any IRGenerator::visitProcDef(const ProcDefNode *node) { } // Change scope - currentScope = currentScope->getChildScope(manifestation->getSignature()); + currentScope = currentScope->getChildScope(manifestation->getSignature(false)); assert(currentScope != nullptr); // Get 'this' entry @@ -462,10 +462,8 @@ std::any IRGenerator::visitStructDef(const StructDefNode *node) { llvm::StructType *structType = llvm::StructType::create(context, mangledName); // Set LLVM type to the struct entry - const std::string structSignature = spiceStruct.getSignature(); - SymbolTableEntry *structEntry = rootScope->lookupStrict(structSignature); - assert(structEntry != nullptr); - structEntry->setStructLLVMType(structType); + assert(spiceStruct.entry != nullptr); + spiceStruct.entry->setStructLLVMType(structType); // Collect concrete field types std::vector fieldTypes; @@ -501,7 +499,7 @@ std::any IRGenerator::visitGenericTypeDef(const GenericTypeDefNode *node) { } std::any IRGenerator::visitAliasDef(const AliasDefNode *node) { - return nullptr; // Noop (alias defs are high-level semantic-only structures) + return nullptr; // Noop (alias definitions are high-level semantic-only structures) } std::any IRGenerator::visitGlobalVarDef(const GlobalVarDefNode *node) { diff --git a/src/irgenerator/IRGenerator.cpp b/src/irgenerator/IRGenerator.cpp index 1e2718f3a..dd9927ba9 100644 --- a/src/irgenerator/IRGenerator.cpp +++ b/src/irgenerator/IRGenerator.cpp @@ -438,6 +438,7 @@ std::string IRGenerator::getIRString() const { void IRGenerator::changeToScope(Scope *scope, const ScopeType scopeType) { assert(scope != nullptr); assert(scope->type == scopeType); + assert(!scope->isGenericScope); // Adjust members of the new scope scope->parent = currentScope; scope->symbolTable.parent = ¤tScope->symbolTable; diff --git a/src/model/Function.cpp b/src/model/Function.cpp index 30a0b4f0a..21271d178 100644 --- a/src/model/Function.cpp +++ b/src/model/Function.cpp @@ -93,6 +93,28 @@ std::string Function::getMangledName() const { * @return String representation as function signature */ std::string Function::getSignature(bool withThisType /*=true*/) const { + std::vector templateSymbolTypes; + templateSymbolTypes.reserve(templateTypes.size()); + for (const GenericType &genericType : templateTypes) + templateSymbolTypes.push_back(genericType); + + return Function::getSignature(name, thisType, returnType, paramList, templateSymbolTypes, withThisType); +} + +/** + * Get a string representation of the current function. + * + * @param name Function name + * @param thisType This symbol type + * @param returnType Return symbol type + * @param paramList Param symbol types + * @param concreteTemplateTypes Concrete template symbol types + * @param withThisType Include 'this' type in signature + * @return Function signature + */ +std::string Function::getSignature(const std::string &name, const SymbolType &thisType, const SymbolType &returnType, + const ParamList ¶mList, const std::vector &concreteTemplateTypes, + bool withThisType /*=true*/) { // Build this type string std::stringstream thisTyStr; if (withThisType && !thisType.is(TY_DYN)) { @@ -128,12 +150,12 @@ std::string Function::getSignature(bool withThisType /*=true*/) const { // Build template type string std::stringstream templateTyStr; - if (!templateTypes.empty()) { + if (!concreteTemplateTypes.empty()) { templateTyStr << "<"; - for (size_t i = 0; i < templateTypes.size(); i++) { + for (size_t i = 0; i < concreteTemplateTypes.size(); i++) { if (i > 0) templateTyStr << ","; - templateTyStr << templateTypes.at(i).getName(); + templateTyStr << concreteTemplateTypes.at(i).getName(); } templateTyStr << ">"; } diff --git a/src/model/Function.h b/src/model/Function.h index f77ea5687..721f0be86 100644 --- a/src/model/Function.h +++ b/src/model/Function.h @@ -44,6 +44,9 @@ class Function { [[nodiscard]] std::vector getParamTypes() const; [[nodiscard]] std::string getMangledName() const; [[nodiscard]] std::string getSignature(bool withThisType = true) const; + [[nodiscard]] static std::string getSignature(const std::string &name, const SymbolType &thisType, const SymbolType &returnType, + const ParamList ¶mList, const std::vector &concreteTemplateTypes, + bool withThisType = true); [[nodiscard]] inline bool isMethod() const { return !thisType.is(TY_DYN); } [[nodiscard]] inline bool isFunction() const { return !isMethod() && !returnType.is(TY_DYN); } [[nodiscard]] inline bool isProcedure() const { return !isMethod() && returnType.is(TY_DYN); } diff --git a/src/model/Struct.cpp b/src/model/Struct.cpp index e8692db05..434bf4d6b 100644 --- a/src/model/Struct.cpp +++ b/src/model/Struct.cpp @@ -52,36 +52,17 @@ std::string Struct::getSignature() const { return getSignature(name, templateSymbolTypes); } -/** - * Checks if a struct contains template types. - * This would imply that the struct is not substantiated by its generic types yet. - * - * @return Substantiated generics or not - */ -bool Struct::hasSubstantiatedGenerics() const { - return std::none_of(templateTypes.begin(), templateTypes.end(), - [](const GenericType &genericType) { return genericType.isBaseType(TY_GENERIC); }); -} - -/** - * Checks if a struct has generic types present. - * This would imply that the struct is not fully substantiated yet. - * - * @return Fully substantiated or not - */ -bool Struct::isFullySubstantiated() const { return hasSubstantiatedGenerics(); } - /** * Get the signature from the struct name and the concrete template types * * Example: * Pair * - * @param structName Struct name + * @param name Struct name * @param concreteTemplateTypes Concrete template types * @return Signature */ -std::string Struct::getSignature(const std::string &structName, const std::vector &concreteTemplateTypes) { +std::string Struct::getSignature(const std::string &name, const std::vector &concreteTemplateTypes) { // Build template type string std::stringstream templateTyStr; if (!concreteTemplateTypes.empty()) { @@ -94,9 +75,28 @@ std::string Struct::getSignature(const std::string &structName, const std::vecto templateTyStr << ">"; } - return CommonUtil::getLastFragment(structName, SCOPE_ACCESS_TOKEN) + templateTyStr.str(); + return CommonUtil::getLastFragment(name, SCOPE_ACCESS_TOKEN) + templateTyStr.str(); } +/** + * Checks if a struct contains template types. + * This would imply that the struct is not substantiated by its generic types yet. + * + * @return Substantiated generics or not + */ +bool Struct::hasSubstantiatedGenerics() const { + return std::none_of(templateTypes.begin(), templateTypes.end(), + [](const GenericType &genericType) { return genericType.isBaseType(TY_GENERIC); }); +} + +/** + * Checks if a struct has generic types present. + * This would imply that the struct is not fully substantiated yet. + * + * @return Fully substantiated or not + */ +bool Struct::isFullySubstantiated() const { return hasSubstantiatedGenerics(); } + /** * Checks if the current struct is of infinite size. * diff --git a/src/model/Struct.h b/src/model/Struct.h index a0d72df12..8c9b08a6f 100644 --- a/src/model/Struct.h +++ b/src/model/Struct.h @@ -32,10 +32,10 @@ class Struct { // Public methods [[nodiscard]] std::string getMangledName() const; [[nodiscard]] std::string getSignature() const; + static std::string getSignature(const std::string &name, const std::vector &concreteTemplateTypes); [[nodiscard]] bool hasSubstantiatedGenerics() const; [[nodiscard]] bool isFullySubstantiated() const; - static std::string getSignature(const std::string &structName, const std::vector &concreteTemplateTypes); - //bool hasInfiniteSize(Scope *anchorScope = nullptr) const; + // bool hasInfiniteSize(Scope *anchorScope = nullptr) const; // Public members std::string name; diff --git a/src/symboltablebuilder/Scope.cpp b/src/symboltablebuilder/Scope.cpp index dfb99ff97..e06ae5816 100644 --- a/src/symboltablebuilder/Scope.cpp +++ b/src/symboltablebuilder/Scope.cpp @@ -226,7 +226,7 @@ void Scope::collectWarnings(std::vector &warnings) const { // N continue; warningType = UNUSED_FUNCTION; - warningMessage = "The function '" + key + "' is unused"; + warningMessage = "The function '" + entry.declNode->getFctManifestations()->front()->getSignature() + "' is unused"; break; } case TY_PROCEDURE: { @@ -235,15 +235,15 @@ void Scope::collectWarnings(std::vector &warnings) const { // N continue; warningType = UNUSED_PROCEDURE; - warningMessage = "The procedure '" + key + "' is unused"; + warningMessage = "The procedure '" + entry.declNode->getFctManifestations()->front()->getSignature() + "' is unused"; break; } case TY_STRUCT: { - // Skip generic struct entries - if (!entry.getType().getTemplateTypes().empty()) - continue; - if (entry.scope->type == SCOPE_GLOBAL) { + // Skip generic struct entries + if (!entry.getType().getTemplateTypes().empty()) + continue; + warningType = UNUSED_STRUCT; warningMessage = "The struct '" + entry.name + "' is unused"; } else { diff --git a/src/symboltablebuilder/SymbolTableBuilder.cpp b/src/symboltablebuilder/SymbolTableBuilder.cpp index 946e25590..a5ae7204f 100644 --- a/src/symboltablebuilder/SymbolTableBuilder.cpp +++ b/src/symboltablebuilder/SymbolTableBuilder.cpp @@ -81,7 +81,7 @@ std::any SymbolTableBuilder::visitFctDef(FctDefNode *node) { // Create scope for the function node->fctScope = currentScope = currentScope->createChildScope(node->getScopeId(), SCOPE_FUNC_PROC_BODY, &node->codeLoc); - currentScope->isGenericScope = node->hasTemplateTypes; + currentScope->isGenericScope = node->hasTemplateTypes || (node->structScope && node->structScope->isGenericScope); // Create symbol for 'this' variable if (node->isMethod) { @@ -143,7 +143,7 @@ std::any SymbolTableBuilder::visitProcDef(ProcDefNode *node) { // Create scope for the procedure node->procScope = currentScope = currentScope->createChildScope(node->getScopeId(), SCOPE_FUNC_PROC_BODY, &node->codeLoc); - currentScope->isGenericScope = node->hasTemplateTypes; + currentScope->isGenericScope = node->hasTemplateTypes || (node->structScope && node->structScope->isGenericScope); // Create symbol for 'this' variable if (node->isMethod) { diff --git a/src/typechecker/FunctionManager.cpp b/src/typechecker/FunctionManager.cpp index 63998b6b3..a19f3fba0 100644 --- a/src/typechecker/FunctionManager.cpp +++ b/src/typechecker/FunctionManager.cpp @@ -191,6 +191,7 @@ Function *FunctionManager::matchFunction(Scope *matchScope, const std::string &r if (presetFunction.templateTypes.empty()) { assert(matchScope->functions.contains(defCodeLocStr) && matchScope->functions.at(defCodeLocStr).contains(mangledName)); matches.push_back(&matchScope->functions.at(defCodeLocStr).at(mangledName)); + matches.back()->used = true; continue; // Match was successful -> match the next function } @@ -216,19 +217,20 @@ Function *FunctionManager::matchFunction(Scope *matchScope, const std::string &r substantiatedFunction->declNode->getFctManifestations()->push_back(substantiatedFunction); // Copy function entry - const std::string newSignature = substantiatedFunction->getSignature(); - matchScope->symbolTable.copySymbol(presetFunction.entry->name, newSignature); + const std::string newSignature = substantiatedFunction->getSignature(false); matchScope->lookupStrict(presetFunction.entry->name)->used = true; - candidate.entry = matchScope->lookupStrict(newSignature); - candidate.entry->used = true; + matchScope->symbolTable.copySymbol(presetFunction.entry->name, newSignature); + substantiatedFunction->entry = matchScope->lookupStrict(newSignature); + assert(substantiatedFunction->entry != nullptr); // Copy function scope matchScope->copyChildScope(presetFunction.getSignature(false), newSignature); Scope *childScope = matchScope->getChildScope(newSignature); + assert(childScope != nullptr); childScope->isGenericScope = false; // Insert symbols for generic type names with concrete types into the child block - for (const auto &[typeName, concreteType] : candidate.typeMapping) + for (const auto &[typeName, concreteType] : substantiatedFunction->typeMapping) childScope->insertGenericType(typeName, GenericType(concreteType)); // Substantiate the 'this' symbol table entry in the new function scope diff --git a/src/typechecker/StructManager.cpp b/src/typechecker/StructManager.cpp index 658599d7e..8efe57ac7 100644 --- a/src/typechecker/StructManager.cpp +++ b/src/typechecker/StructManager.cpp @@ -92,6 +92,7 @@ Struct *StructManager::matchStruct(Scope *matchScope, const std::string &request if (presetStruct.templateTypes.empty()) { assert(matchScope->structs.contains(defCodeLocStr) && matchScope->structs.at(defCodeLocStr).contains(mangledName)); matches.push_back(&matchScope->structs.at(defCodeLocStr).at(mangledName)); + matches.back()->used = true; continue; // Match was successful -> match the next struct } @@ -106,25 +107,27 @@ Struct *StructManager::matchStruct(Scope *matchScope, const std::string &request substantiatedStruct->genericSubstantiation = true; substantiatedStruct->declNode->getStructManifestations()->push_back(substantiatedStruct); - // Copy function entry + // Copy struct entry const std::string newSignature = substantiatedStruct->getSignature(); - matchScope->symbolTable.copySymbol(candidate.name, newSignature); - matchScope->lookupStrict(candidate.name)->used = true; - candidate.entry = matchScope->lookupStrict(newSignature); + matchScope->lookupStrict(substantiatedStruct->name)->used = true; + matchScope->symbolTable.copySymbol(substantiatedStruct->name, newSignature); + substantiatedStruct->entry = matchScope->lookupStrict(newSignature); + assert(substantiatedStruct->entry != nullptr); // Copy struct scope const std::string newScopeName = STRUCT_SCOPE_PREFIX + newSignature; matchScope->copyChildScope(STRUCT_SCOPE_PREFIX + presetStruct.name, newScopeName); substantiatedStruct->structScope = matchScope->getChildScope(newScopeName); + assert(substantiatedStruct->structScope != nullptr); substantiatedStruct->structScope->isGenericScope = false; // Replace field types with concrete template types assert(substantiatedStruct->structScope != nullptr); - for (size_t i = 0; i < candidate.fieldTypes.size(); i++) { + for (size_t i = 0; i < substantiatedStruct->fieldTypes.size(); i++) { // Replace field type with concrete template type SymbolTableEntry *fieldEntry = substantiatedStruct->structScope->symbolTable.lookupByIndex(i); assert(fieldEntry != nullptr); - fieldEntry->updateType(candidate.fieldTypes.at(i), /*overwriteExistingType=*/true); + fieldEntry->updateType(substantiatedStruct->fieldTypes.at(i), /*overwriteExistingType=*/true); } // Add to matched structs diff --git a/src/typechecker/TypeChecker.cpp b/src/typechecker/TypeChecker.cpp index 28961ef67..e788aabc0 100644 --- a/src/typechecker/TypeChecker.cpp +++ b/src/typechecker/TypeChecker.cpp @@ -1283,10 +1283,9 @@ std::any TypeChecker::visitFunctionCall(FunctionCallNode *node) { ParamList errArgTypes; for (const SymbolType &argType : data.argTypes) errArgTypes.push_back({argType, false}); - const SymbolType dynType(TY_DYN); - Function f(functionName, nullptr, thisType, returnType, errArgTypes, /*templateTypes=*/{}, node, /*external=*/false); + const std::string signature = Function::getSignature(functionName, thisType, returnType, errArgTypes, {}); // Throw error - throw SemanticError(node, REFERENCED_UNDEFINED_FUNCTION, "Function/procedure '" + f.getSignature() + "' could not be found"); + throw SemanticError(node, REFERENCED_UNDEFINED_FUNCTION, "Function/procedure '" + signature + "' could not be found"); } // Check if we need to request a re-visit, because the function body was not type-checked yet diff --git a/src/typechecker/TypeCheckerCheck.cpp b/src/typechecker/TypeCheckerCheck.cpp index ec0bb4acc..43430121f 100644 --- a/src/typechecker/TypeCheckerCheck.cpp +++ b/src/typechecker/TypeCheckerCheck.cpp @@ -50,7 +50,7 @@ std::any TypeChecker::visitFctDefCheck(FctDefNode *node) { } // Change to function scope - currentScope = currentScope->getChildScope(manifestation->getSignature()); + currentScope = currentScope->getChildScope(manifestation->getSignature(false)); assert(currentScope != nullptr && currentScope->type == SCOPE_FUNC_PROC_BODY); // Mount type mapping for this manifestation @@ -107,7 +107,7 @@ std::any TypeChecker::visitProcDefCheck(ProcDefNode *node) { } // Change to procedure scope - currentScope = currentScope->getChildScope(manifestation->getSignature()); + currentScope = currentScope->getChildScope(manifestation->getSignature(false)); assert(currentScope != nullptr && currentScope->type == SCOPE_FUNC_PROC_BODY); // Mount type mapping for this manifestation diff --git a/src/typechecker/TypeCheckerPrepare.cpp b/src/typechecker/TypeCheckerPrepare.cpp index ab940f95b..290ecf6a5 100644 --- a/src/typechecker/TypeCheckerPrepare.cpp +++ b/src/typechecker/TypeCheckerPrepare.cpp @@ -137,7 +137,8 @@ std::any TypeChecker::visitFctDefPrepare(FctDefNode *node) { FunctionManager::substantiateOptionalParams(spiceFunc, substantiatedFunctions); currentScope->renameChildScope(node->getScopeId(), substantiatedFunctions.front().getSignature(false)); for (size_t i = 1; i < substantiatedFunctions.size(); i++) - currentScope->copyChildScope(substantiatedFunctions.front().getSignature(), substantiatedFunctions[i].getSignature(false)); + currentScope->copyChildScope(substantiatedFunctions.front().getSignature(false), + substantiatedFunctions[i].getSignature(false)); // Change to the root scope currentScope = rootScope; @@ -241,7 +242,8 @@ std::any TypeChecker::visitProcDefPrepare(ProcDefNode *node) { FunctionManager::substantiateOptionalParams(spiceProc, substantiatedProcedures); currentScope->renameChildScope(node->getScopeId(), substantiatedProcedures.front().getSignature(false)); for (size_t i = 1; i < substantiatedProcedures.size(); i++) - currentScope->copyChildScope(substantiatedProcedures.front().getSignature(), substantiatedProcedures[i].getSignature(false)); + currentScope->copyChildScope(substantiatedProcedures.front().getSignature(false), + substantiatedProcedures[i].getSignature(false)); // Change to the root scope currentScope = rootScope; diff --git a/test/test-files/std/data/combined-test-1-fq/cout.out b/test/test-files/std/data/combined-test-1-fq/cout.out new file mode 100644 index 000000000..980a0d5f1 --- /dev/null +++ b/test/test-files/std/data/combined-test-1-fq/cout.out @@ -0,0 +1 @@ +Hello World! diff --git a/test/test-files/std/data/combined-test-1-fq/ir-code-O2.ll b/test/test-files/std/data/combined-test-1-fq/ir-code-O2.ll new file mode 100644 index 000000000..451deb110 --- /dev/null +++ b/test/test-files/std/data/combined-test-1-fq/ir-code-O2.ll @@ -0,0 +1,61 @@ +; ModuleID = 'source.spice' +source_filename = "source.spice" +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-w64-windows-gnu" + +%"_s__pair.Pair__Vector__pair.Pairptr_long_long_int" = type { ptr, i64, i64, i32 } +%_s__int_string__Pair__int_string = type { i32, ptr } + +@0 = private unnamed_addr constant [6 x i8] c"Hello\00", align 1 +@1 = private unnamed_addr constant [6 x i8] c"World\00", align 1 +@2 = private unnamed_addr constant [11 x i8] c"Hello %s!\0A\00", align 1 + +define i32 @main() local_unnamed_addr { +entry.l4: + %pairVector = alloca %"_s__pair.Pair__Vector__pair.Pairptr_long_long_int", align 8 + %0 = alloca %_s__int_string__Pair__int_string, align 8 + %1 = alloca %_s__int_string__Pair__int_string, align 8 + %2 = alloca %_s__int_string__Pair__int_string, align 8 + call void @"_mp__Vector_pair.Pair__void__ctor"(ptr nonnull %pairVector) + call void @_mp__Pair_int_string__void__ctor__int_string(ptr nonnull %0, i32 0, ptr nonnull @0) + %.fca.0.load7 = load i32, ptr %0, align 8 + %.fca.0.insert8 = insertvalue %_s__int_string__Pair__int_string poison, i32 %.fca.0.load7, 0 + %.fca.1.gep9 = getelementptr inbounds %_s__int_string__Pair__int_string, ptr %0, i64 0, i32 1 + %.fca.1.load10 = load ptr, ptr %.fca.1.gep9, align 8 + %.fca.1.insert11 = insertvalue %_s__int_string__Pair__int_string %.fca.0.insert8, ptr %.fca.1.load10, 1 + call void @"_mp__Vector_pair.Pair__void__pushBack__pair.Pair"(ptr nonnull %pairVector, %_s__int_string__Pair__int_string %.fca.1.insert11) + call void @_mp__Pair_int_string__void__ctor__int_string(ptr nonnull %1, i32 1, ptr nonnull @1) + %.fca.0.load = load i32, ptr %1, align 8 + %.fca.0.insert = insertvalue %_s__int_string__Pair__int_string poison, i32 %.fca.0.load, 0 + %.fca.1.gep3 = getelementptr inbounds %_s__int_string__Pair__int_string, ptr %1, i64 0, i32 1 + %.fca.1.load = load ptr, ptr %.fca.1.gep3, align 8 + %.fca.1.insert = insertvalue %_s__int_string__Pair__int_string %.fca.0.insert, ptr %.fca.1.load, 1 + call void @"_mp__Vector_pair.Pair__void__pushBack__pair.Pair"(ptr nonnull %pairVector, %_s__int_string__Pair__int_string %.fca.1.insert) + %3 = call %_s__int_string__Pair__int_string @"_mf__Vector_pair.Pair__pair.Pair__get__int"(ptr nonnull %pairVector, i32 1) + %.fca.0.extract = extractvalue %_s__int_string__Pair__int_string %3, 0 + store i32 %.fca.0.extract, ptr %2, align 8 + %.fca.1.extract = extractvalue %_s__int_string__Pair__int_string %3, 1 + %.fca.1.gep = getelementptr inbounds %_s__int_string__Pair__int_string, ptr %2, i64 0, i32 1 + store ptr %.fca.1.extract, ptr %.fca.1.gep, align 8 + %4 = call ptr @_mf__Pair_int_string__string__getSecond(ptr nonnull %2) + %5 = call i32 (ptr, ...) @printf(ptr nonnull @2, ptr %4) + call void @"_mp__Vector_pair.Pair__void__dtor"(ptr nonnull %pairVector) + ret i32 0 +} + +declare void @"_mp__Vector_pair.Pair__void__ctor"(ptr) local_unnamed_addr + +declare void @"_mp__Vector_pair.Pair__void__pushBack__pair.Pair"(ptr, %_s__int_string__Pair__int_string) local_unnamed_addr + +declare void @_mp__Pair_int_string__void__ctor__int_string(ptr, i32, ptr) local_unnamed_addr + +declare %_s__int_string__Pair__int_string @"_mf__Vector_pair.Pair__pair.Pair__get__int"(ptr, i32) local_unnamed_addr + +; Function Attrs: nofree nounwind +declare noundef i32 @printf(ptr nocapture noundef readonly, ...) local_unnamed_addr #0 + +declare ptr @_mf__Pair_int_string__string__getSecond(ptr) local_unnamed_addr + +declare void @"_mp__Vector_pair.Pair__void__dtor"(ptr) local_unnamed_addr + +attributes #0 = { nofree nounwind } diff --git a/test/test-files/std/data/combined-test-1-fq/source.spice b/test/test-files/std/data/combined-test-1-fq/source.spice new file mode 100644 index 000000000..c724b31fe --- /dev/null +++ b/test/test-files/std/data/combined-test-1-fq/source.spice @@ -0,0 +1,11 @@ +import "std/data/vector" as vec; +import "std/data/pair" as pair; + +f main() { + vec::Vector> pairVector = vec::Vector>(); + pairVector.pushBack(pair::Pair(0, "Hello")); + pairVector.pushBack(pair::Pair(1, "World")); + + pair::Pair p1 = pairVector.get(1); + printf("Hello %s!\n", p1.getSecond()); +} \ No newline at end of file diff --git a/test/test-files/std/data/combined-test-1/source.spice b/test/test-files/std/data/combined-test-1/source.spice index c724b31fe..1e90b5dfd 100644 --- a/test/test-files/std/data/combined-test-1/source.spice +++ b/test/test-files/std/data/combined-test-1/source.spice @@ -1,11 +1,11 @@ -import "std/data/vector" as vec; -import "std/data/pair" as pair; +import "std/data/vector"; +import "std/data/pair"; f main() { - vec::Vector> pairVector = vec::Vector>(); - pairVector.pushBack(pair::Pair(0, "Hello")); - pairVector.pushBack(pair::Pair(1, "World")); + Vector> pairVector = Vector>(); + pairVector.pushBack(Pair(0, "Hello")); + pairVector.pushBack(Pair(1, "World")); - pair::Pair p1 = pairVector.get(1); + Pair p1 = pairVector.get(1); printf("Hello %s!\n", p1.getSecond()); } \ No newline at end of file