From 9a79c009b2b198f1eb2772ab49e8b19230274820 Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Thu, 9 May 2024 03:01:05 +0200 Subject: [PATCH] Move logic from Type to QualType where possible (#540) --- src/CompilerPass.h | 2 +- src/SourceFile.cpp | 3 +- src/ast/ASTNodes.h | 2 +- src/cmake/ExternalAntlr4Cpp.cmake | 12 +- src/driver/Driver.cpp | 15 +- src/global/TypeRegistry.cpp | 6 +- src/irgenerator/DebugInfoGenerator.cpp | 10 +- src/irgenerator/GenBuiltinFunctions.cpp | 14 +- src/irgenerator/GenControlStructures.cpp | 8 +- src/irgenerator/GenExpressions.cpp | 14 +- src/irgenerator/GenImplicit.cpp | 22 +- src/irgenerator/GenStatements.cpp | 4 +- src/irgenerator/GenTopLevelDefinitions.cpp | 24 +- src/irgenerator/GenVTable.cpp | 4 +- src/irgenerator/GenValues.cpp | 46 +- src/irgenerator/IRGenerator.cpp | 23 +- src/irgenerator/IRGenerator.h | 4 +- src/irgenerator/NameMangling.cpp | 2 +- src/irgenerator/OpRuleConversionManager.cpp | 6 +- src/irgenerator/StdFunctionManager.cpp | 6 +- src/model/Function.cpp | 10 +- src/model/Function.h | 4 +- src/model/GenericType.h | 4 +- src/model/Struct.h | 8 +- src/model/StructBase.cpp | 8 +- src/model/StructBase.h | 4 +- src/symboltablebuilder/QualType.cpp | 656 +++++++++++++++++--- src/symboltablebuilder/QualType.h | 101 ++- src/symboltablebuilder/Scope.cpp | 10 +- src/symboltablebuilder/SymbolTable.cpp | 2 +- src/symboltablebuilder/SymbolTableEntry.h | 6 +- src/symboltablebuilder/Type.cpp | 297 ++++----- src/symboltablebuilder/Type.h | 116 ++-- src/symboltablebuilder/TypeChain.cpp | 2 +- src/typechecker/FunctionManager.cpp | 16 +- src/typechecker/FunctionManager.h | 7 +- src/typechecker/InterfaceManager.cpp | 11 +- src/typechecker/InterfaceManager.h | 4 +- src/typechecker/MacroDefs.h | 2 +- src/typechecker/OpRuleManager.cpp | 2 +- src/typechecker/OpRuleManager.h | 6 +- src/typechecker/StructManager.cpp | 17 +- src/typechecker/StructManager.h | 7 +- src/typechecker/TypeChecker.cpp | 130 ++-- src/typechecker/TypeChecker.h | 4 +- src/typechecker/TypeCheckerCheck.cpp | 13 +- src/typechecker/TypeCheckerImplicit.cpp | 22 +- src/typechecker/TypeCheckerPrepare.cpp | 50 +- src/typechecker/TypeMatcher.cpp | 27 +- src/typechecker/TypeMatcher.h | 4 +- 50 files changed, 1107 insertions(+), 670 deletions(-) diff --git a/src/CompilerPass.h b/src/CompilerPass.h index 2b78dd144..83eac7ce5 100644 --- a/src/CompilerPass.h +++ b/src/CompilerPass.h @@ -2,8 +2,8 @@ #pragma once -#include #include +#include namespace spice::compiler { diff --git a/src/SourceFile.cpp b/src/SourceFile.cpp index fd22d3399..7780ce66f 100644 --- a/src/SourceFile.cpp +++ b/src/SourceFile.cpp @@ -458,8 +458,7 @@ void SourceFile::runObjectEmitter() { objectEmitter.emit(objectFilePath); // Save assembly string in the compiler output - if (cliOptions.isNativeTarget && - (cliOptions.dumpSettings.dumpAssembly || cliOptions.testMode)) + if (cliOptions.isNativeTarget && (cliOptions.dumpSettings.dumpAssembly || cliOptions.testMode)) objectEmitter.getASMString(compilerOutput.asmString); // Dump assembly code diff --git a/src/ast/ASTNodes.h b/src/ast/ASTNodes.h index 69b595dae..b6fa646ae 100644 --- a/src/ast/ASTNodes.h +++ b/src/ast/ASTNodes.h @@ -159,7 +159,7 @@ class ASTNode { ASTNode *parent = nullptr; std::vector children; const CodeLoc codeLoc; - std::vector symbolTypes; + QualTypeList symbolTypes; bool unreachable = false; }; diff --git a/src/cmake/ExternalAntlr4Cpp.cmake b/src/cmake/ExternalAntlr4Cpp.cmake index 825db2e19..7fe5d12d1 100644 --- a/src/cmake/ExternalAntlr4Cpp.cmake +++ b/src/cmake/ExternalAntlr4Cpp.cmake @@ -78,7 +78,7 @@ if (NOT DEFINED ANTLR4_WITH_STATIC_CRT) endif () if (ANTLR4_ZIP_REPOSITORY) - if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + if (CMAKE_SYSTEM_NAME STREQUAL "Linux") ExternalProject_Add( antlr4_runtime PREFIX antlr4_runtime @@ -100,7 +100,7 @@ if (ANTLR4_ZIP_REPOSITORY) INSTALL_COMMAND "" EXCLUDE_FROM_ALL 1 DOWNLOAD_EXTRACT_TIMESTAMP 0) - else() + else () ExternalProject_Add( antlr4_runtime PREFIX antlr4_runtime @@ -118,9 +118,9 @@ if (ANTLR4_ZIP_REPOSITORY) INSTALL_COMMAND "" EXCLUDE_FROM_ALL 1 DOWNLOAD_EXTRACT_TIMESTAMP 0) - endif() + endif () else () - if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + if (CMAKE_SYSTEM_NAME STREQUAL "Linux") ExternalProject_Add( antlr4_runtime PREFIX antlr4_runtime @@ -143,7 +143,7 @@ else () INSTALL_COMMAND "" EXCLUDE_FROM_ALL 1 DOWNLOAD_EXTRACT_TIMESTAMP 0) - else() + else () ExternalProject_Add( antlr4_runtime PREFIX antlr4_runtime @@ -162,7 +162,7 @@ else () INSTALL_COMMAND "" EXCLUDE_FROM_ALL 1 DOWNLOAD_EXTRACT_TIMESTAMP 0) - endif() + endif () endif () # Separate build step as rarely people want both diff --git a/src/driver/Driver.cpp b/src/driver/Driver.cpp index dc29aed51..10cb0264b 100644 --- a/src/driver/Driver.cpp +++ b/src/driver/Driver.cpp @@ -321,18 +321,13 @@ void Driver::addCompileSubcommandOptions(CLI::App *subCmd) { // Opt levels subCmd->add_flag_callback( "-O0", [&]() { cliOptions.optLevel = OptLevel::O0; }, "Disable optimization for the output executable."); - subCmd->add_flag_callback( - "-O1", [&]() { cliOptions.optLevel = OptLevel::O1; }, "Only basic optimization is executed."); - subCmd->add_flag_callback( - "-O2", [&]() { cliOptions.optLevel = OptLevel::O2; }, "More advanced optimization is applied."); + subCmd->add_flag_callback("-O1", [&]() { cliOptions.optLevel = OptLevel::O1; }, "Only basic optimization is executed."); + subCmd->add_flag_callback("-O2", [&]() { cliOptions.optLevel = OptLevel::O2; }, "More advanced optimization is applied."); subCmd->add_flag_callback( "-O3", [&]() { cliOptions.optLevel = OptLevel::O3; }, "Aggressive optimization for best performance."); - subCmd->add_flag_callback( - "-Os", [&]() { cliOptions.optLevel = OptLevel::Os; }, "Size optimization for output executable."); - subCmd->add_flag_callback( - "-Oz", [&]() { cliOptions.optLevel = OptLevel::Oz; }, "Aggressive optimization for best size."); - subCmd->add_flag_callback( - "-lto", [&]() { cliOptions.useLTO = true; }, "Enable link time optimization (LTO)"); + subCmd->add_flag_callback("-Os", [&]() { cliOptions.optLevel = OptLevel::Os; }, "Size optimization for output executable."); + subCmd->add_flag_callback("-Oz", [&]() { cliOptions.optLevel = OptLevel::Oz; }, "Aggressive optimization for best size."); + subCmd->add_flag_callback("-lto", [&]() { cliOptions.useLTO = true; }, "Enable link time optimization (LTO)"); // --debug-output subCmd->add_flag("--debug-output,-d", cliOptions.printDebugOutput, "Enable debug output"); diff --git a/src/global/TypeRegistry.cpp b/src/global/TypeRegistry.cpp index 8eb479027..6f7718fb0 100644 --- a/src/global/TypeRegistry.cpp +++ b/src/global/TypeRegistry.cpp @@ -7,7 +7,7 @@ namespace spice::compiler { // Static member initialization -std::unordered_map>TypeRegistry::types = {}; +std::unordered_map> TypeRegistry::types = {}; const Type *TypeRegistry::get(const std::string &name) { const auto it = types.find(name); @@ -27,8 +27,6 @@ const Type *TypeRegistry::getOrInsert(Type type) { return insertedElement.first->second.get(); } -const Type *TypeRegistry::getOrInsert(SuperType superType) { - return getOrInsert(Type(superType)); -} +const Type *TypeRegistry::getOrInsert(SuperType superType) { return getOrInsert(Type(superType)); } } // namespace spice::compiler diff --git a/src/irgenerator/DebugInfoGenerator.cpp b/src/irgenerator/DebugInfoGenerator.cpp index cd4a615a0..ff30e1541 100644 --- a/src/irgenerator/DebugInfoGenerator.cpp +++ b/src/irgenerator/DebugInfoGenerator.cpp @@ -176,7 +176,7 @@ llvm::DICompositeType *DebugInfoGenerator::generateCaptureStructDebugInfo(const // Get LLVM type for struct std::vector fieldTypes; std::vector fieldEntries; - std::vector fieldSymbolTypes; + QualTypeList fieldSymbolTypes; for (const auto &[_, capture] : captures) { QualType captureType = capture.capturedEntry->getQualType(); @@ -186,7 +186,7 @@ llvm::DICompositeType *DebugInfoGenerator::generateCaptureStructDebugInfo(const fieldEntries.push_back(capture.capturedEntry); fieldSymbolTypes.push_back(captureType); - fieldTypes.push_back(captureType.getType().toLLVMType(irGenerator->context, irGenerator->currentScope)); + fieldTypes.push_back(captureType.toLLVMType(irGenerator->context, irGenerator->currentScope)); } llvm::StructType *structType = llvm::StructType::get(irGenerator->context, fieldTypes, CAPTURES_PARAM_NAME); const llvm::StructLayout *structLayout = irGenerator->module->getDataLayout().getStructLayout(structType); @@ -291,7 +291,7 @@ llvm::DIType *DebugInfoGenerator::getDITypeForQualType(const ASTNode *node, cons // Array ty if (ty.isArray()) { llvm::DIType *itemTy = getDITypeForQualType(node, ty.getContained()); - const size_t size = ty.getType().getArraySize(); + const size_t size = ty.getArraySize(); llvm::DINodeArray subscripts = diBuilder->getOrCreateArray({}); return diBuilder->createArrayType(size, 0, itemTy, subscripts); } @@ -324,7 +324,7 @@ llvm::DIType *DebugInfoGenerator::getDITypeForQualType(const ASTNode *node, cons baseDiType = boolTy; break; case TY_STRUCT: { - Struct *spiceStruct = ty.getType().getStruct(node); + Struct *spiceStruct = ty.getStruct(node); assert(spiceStruct != nullptr); // Check if we already know the DI ty @@ -373,7 +373,7 @@ llvm::DIType *DebugInfoGenerator::getDITypeForQualType(const ASTNode *node, cons break; } case TY_INTERFACE: { - Interface *spiceInterface = ty.getType().getInterface(node); + Interface *spiceInterface = ty.getInterface(node); assert(spiceInterface != nullptr); // Check if we already know the DI ty diff --git a/src/irgenerator/GenBuiltinFunctions.cpp b/src/irgenerator/GenBuiltinFunctions.cpp index f5b0e1e92..405de78b0 100644 --- a/src/irgenerator/GenBuiltinFunctions.cpp +++ b/src/irgenerator/GenBuiltinFunctions.cpp @@ -25,11 +25,11 @@ std::any IRGenerator::visitPrintfCall(const PrintfCallNode *node) { if (argSymbolType.isArray()) { llvm::Value *argValPtr = resolveAddress(arg); llvm::Value *indices[2] = {builder.getInt32(0), builder.getInt32(0)}; - llvm::Type *argType = argSymbolType.getType().toLLVMType(context, currentScope); + llvm::Type *argType = argSymbolType.toLLVMType(context, currentScope); argVal = insertInBoundsGEP(argType, argValPtr, indices); - } else if (argSymbolType.getBase().getType().isStringObj()) { + } else if (argSymbolType.getBase().isStringObj()) { llvm::Value *argValPtr = resolveAddress(arg); - llvm::Type *argBaseType = argSymbolType.getBase().getType().toLLVMType(context, currentScope); + llvm::Type *argBaseType = argSymbolType.getBase().toLLVMType(context, currentScope); argValPtr = insertStructGEP(argBaseType, argValPtr, 0); argVal = insertLoad(builder.getPtrTy(), argValPtr); } else { @@ -61,7 +61,7 @@ std::any IRGenerator::visitSizeofCall(const SizeofCallNode *node) { if (node->isType) { // Size of type type = any_cast(visit(node->dataType())); } else { // Size of value - type = node->assignExpr()->getEvaluatedSymbolType(manIdx).getType().toLLVMType(context, currentScope); + type = node->assignExpr()->getEvaluatedSymbolType(manIdx).toLLVMType(context, currentScope); } // Calculate size at compile-time const llvm::TypeSize sizeInBits = module->getDataLayout().getTypeSizeInBits(type); @@ -76,7 +76,7 @@ std::any IRGenerator::visitAlignofCall(const AlignofCallNode *node) { if (node->isType) { // Align of type type = any_cast(visit(node->dataType())); } else { // Align of value - type = node->assignExpr()->getEvaluatedSymbolType(manIdx).getType().toLLVMType(context, currentScope); + type = node->assignExpr()->getEvaluatedSymbolType(manIdx).toLLVMType(context, currentScope); } // Calculate size at compile-time const llvm::Align align = module->getDataLayout().getABITypeAlign(type); @@ -96,9 +96,9 @@ std::any IRGenerator::visitLenCall(const LenCallNode *node) { llvm::Function *getRawLengthFct = stdFunctionManager.getStringGetRawLengthStringFct(); lengthValue = builder.CreateCall(getRawLengthFct, resolveValue(node->assignExpr())); } else { - assert(symbolType.isArray() && symbolType.getType().getArraySize() != ARRAY_SIZE_UNKNOWN); + assert(symbolType.isArray() && symbolType.getArraySize() != ARRAY_SIZE_UNKNOWN); // Return length value - lengthValue = builder.getInt64(symbolType.getType().getArraySize()); + lengthValue = builder.getInt64(symbolType.getArraySize()); } return LLVMExprResult{.value = lengthValue}; } diff --git a/src/irgenerator/GenControlStructures.cpp b/src/irgenerator/GenControlStructures.cpp index 98f390c9f..6cb027832 100644 --- a/src/irgenerator/GenControlStructures.cpp +++ b/src/irgenerator/GenControlStructures.cpp @@ -106,7 +106,7 @@ std::any IRGenerator::visitForeachLoop(const ForeachLoopNode *node) { if (!node->getIteratorFct->isMethod() && node->getIteratorFct->getParamTypes().front().isArray()) { // Array as iterable // Call iterate() function from std/iterator/array-iterator llvm::Function *iterateFct = stdFunctionManager.getIterateFct(node->getIteratorFct); - const size_t arraySize = iteratorAssignNode->getEvaluatedSymbolType(manIdx).getType().getArraySize(); + const size_t arraySize = iteratorAssignNode->getEvaluatedSymbolType(manIdx).getArraySize(); assert(arraySize > 0); iterator = builder.CreateCall(iterateFct, {iterablePtr, builder.getInt64(arraySize)}); } else { // Struct as iterable @@ -127,10 +127,10 @@ std::any IRGenerator::visitForeachLoop(const ForeachLoopNode *node) { iteratorPtr = resolveAddress(iteratorAssignNode); } - const QualType &itemSTy = iteratorType.getType().getTemplateTypes().front(); + const QualType &itemSTy = iteratorType.getTemplateTypes().front(); const QualType itemRefSTy = itemSTy.toRef(node); assert(!node->getFct || itemRefSTy == node->getFct->returnType); - assert(!node->getIdxFct || itemRefSTy == node->getIdxFct->returnType.getType().getTemplateTypes().back()); + assert(!node->getIdxFct || itemRefSTy == node->getIdxFct->returnType.getTemplateTypes().back()); // Visit idx variable declaration if required const DeclStmtNode *idxDeclNode = node->idxVarDecl(); @@ -170,7 +170,7 @@ std::any IRGenerator::visitForeachLoop(const ForeachLoopNode *node) { // Get the current iterator values if (hasIdx) { // Allocate space to save pair - llvm::Type *pairTy = node->getIdxFct->returnType.getType().toLLVMType(context, currentScope); + llvm::Type *pairTy = node->getIdxFct->returnType.toLLVMType(context, currentScope); llvm::Value *pairPtr = insertAlloca(pairTy, "pair_addr"); // Call .getIdx() on iterator assert(node->getIdxFct); diff --git a/src/irgenerator/GenExpressions.cpp b/src/irgenerator/GenExpressions.cpp index 05bd18d16..697c8722e 100644 --- a/src/irgenerator/GenExpressions.cpp +++ b/src/irgenerator/GenExpressions.cpp @@ -102,8 +102,8 @@ std::any IRGenerator::visitTernaryExpr(const TernaryExprNode *node) { } else { const QualType &op1Type = node->operands()[1]->getEvaluatedSymbolType(manIdx); const QualType &op2Type = node->operands()[2]->getEvaluatedSymbolType(manIdx); - llvm::Type *op1Ty = op1Type.getType().toLLVMType(context, currentScope); - llvm::Type *op2Ty = op2Type.getType().toLLVMType(context, currentScope); + llvm::Type *op1Ty = op1Type.toLLVMType(context, currentScope); + llvm::Type *op2Ty = op2Type.toLLVMType(context, currentScope); trueValue = resolveValue(node->operands()[1]); falseValue = resolveValue(node->operands()[2]); } @@ -664,13 +664,13 @@ std::any IRGenerator::visitPostfixUnaryExpr(const PostfixUnaryExprNode *node) { lhsSTy = lhsSTy.removeReferenceWrapper(); // Get the LLVM type of the operand - llvm::Type *lhsTy = lhsSTy.getType().toLLVMType(context, currentScope); + llvm::Type *lhsTy = lhsSTy.toLLVMType(context, currentScope); // Get the index value AssignExprNode *indexExpr = node->assignExpr(); llvm::Value *indexValue = resolveValue(indexExpr); // Come up with the address - if (lhsSTy.isArray() && lhsSTy.getType().getArraySize() != ARRAY_SIZE_UNKNOWN) { // Array + if (lhsSTy.isArray() && lhsSTy.getArraySize() != ARRAY_SIZE_UNKNOWN) { // Array // Make sure the address is present resolveAddress(lhs); @@ -706,7 +706,7 @@ std::any IRGenerator::visitPostfixUnaryExpr(const PostfixUnaryExprNode *node) { // Retrieve struct scope const std::string &fieldName = node->identifier; - Scope *structScope = lhsSTy.getType().getBodyScope(); + Scope *structScope = lhsSTy.getBodyScope(); // Retrieve field entry std::vector indexPath; @@ -719,7 +719,7 @@ std::any IRGenerator::visitPostfixUnaryExpr(const PostfixUnaryExprNode *node) { for (size_t index : indexPath) indices.push_back(builder.getInt32(index)); const std::string name = fieldName + "_addr"; - llvm::Value *memberAddr = insertInBoundsGEP(lhsSTy.getType().toLLVMType(context, structScope->parent), lhs.ptr, indices, name); + llvm::Value *memberAddr = insertInBoundsGEP(lhsSTy.toLLVMType(context, structScope->parent), lhs.ptr, indices, name); // Set as ptr or refPtr, depending on the type if (fieldSymbolType.isRef()) { @@ -826,7 +826,7 @@ std::any IRGenerator::visitAtomicExpr(const AtomicExprNode *node) { Scope *accessScope = data.accessScope; assert(accessScope != nullptr); QualType varSymbolType = varEntry->getQualType(); - llvm::Type *varType = varSymbolType.getType().toLLVMType(context, accessScope); + llvm::Type *varType = varSymbolType.toLLVMType(context, accessScope); // Check if external global variable if (varEntry->global && accessScope->isImportedBy(rootScope)) { diff --git a/src/irgenerator/GenImplicit.cpp b/src/irgenerator/GenImplicit.cpp index fe076574b..b08fd85a0 100644 --- a/src/irgenerator/GenImplicit.cpp +++ b/src/irgenerator/GenImplicit.cpp @@ -26,7 +26,7 @@ llvm::Value *IRGenerator::doImplicitCast(llvm::Value *src, QualType dstSTy, Qual // Unpack the pointers until a pointer of another type is met size_t loadCounter = 0; while (srcSTy.isPtr()) { - src = insertLoad(srcSTy.getType().toLLVMType(context, currentScope), src); + src = insertLoad(srcSTy.toLLVMType(context, currentScope), src); srcSTy = srcSTy.getContained(); dstSTy = dstSTy.getContained(); loadCounter++; @@ -34,10 +34,10 @@ llvm::Value *IRGenerator::doImplicitCast(llvm::Value *src, QualType dstSTy, Qual // GEP or bit-cast if (dstSTy.isArray() && srcSTy.isArray()) { // Special case that is used for passing arrays as pointer to functions llvm::Value *indices[2] = {builder.getInt32(0), builder.getInt32(0)}; - src = insertInBoundsGEP(srcSTy.getType().toLLVMType(context, currentScope), src, indices); + src = insertInBoundsGEP(srcSTy.toLLVMType(context, currentScope), src, indices); } else { - src = insertLoad(srcSTy.getType().toLLVMType(context, currentScope), src); - src = builder.CreateBitCast(src, dstSTy.getType().toLLVMType(context, currentScope)); + src = insertLoad(srcSTy.toLLVMType(context, currentScope), src); + src = builder.CreateBitCast(src, dstSTy.toLLVMType(context, currentScope)); } // Pack the pointers together again for (; loadCounter > 0; loadCounter--) { @@ -124,7 +124,7 @@ llvm::Function *IRGenerator::generateImplicitFunction(const std::functionreturnType.getType().toLLVMType(context, currentScope); + llvm::Type *returnType = spiceFunc->returnType.toLLVMType(context, currentScope); // Get 'this' entry std::vector> paramInfoList; @@ -140,7 +140,7 @@ llvm::Function *IRGenerator::generateImplicitFunction(const std::functionparamList) { assert(!param.isOptional); - paramTypes.push_back(param.type.getType().toLLVMType(context, currentScope)); + paramTypes.push_back(param.type.toLLVMType(context, currentScope)); } // Get function linkage @@ -231,7 +231,7 @@ llvm::Function *IRGenerator::generateImplicitProcedure(const std::functionparamList) { assert(!param.isOptional); - paramTypes.push_back(param.type.getType().toLLVMType(context, currentScope)); + paramTypes.push_back(param.type.toLLVMType(context, currentScope)); } // Get function linkage @@ -317,7 +317,7 @@ void IRGenerator::generateCtorBodyPreamble(Scope *bodyScope) { llvm::Type *structType = structSymbolType.toLLVMType(context, structScope); // Store VTable to first struct field if required - Struct *spiceStruct = structSymbolType.getType().getStruct(nullptr); + Struct *spiceStruct = structSymbolType.getStruct(nullptr); assert(spiceStruct != nullptr); if (spiceStruct->vTableData.vtable != nullptr) { assert(spiceStruct->vTableData.vtableType != nullptr); @@ -340,7 +340,7 @@ void IRGenerator::generateCtorBodyPreamble(Scope *bodyScope) { auto fieldNode = spice_pointer_cast(fieldSymbol->declNode); if (fieldType.is(TY_STRUCT)) { // Lookup ctor function and call if available - Scope *matchScope = fieldType.getType().getBodyScope(); + Scope *matchScope = fieldType.getBodyScope(); const Function *ctorFunction = FunctionManager::lookupFunction(matchScope, CTOR_FUNCTION_NAME, fieldType, {}, false); if (ctorFunction) generateCtorOrDtorCall(fieldSymbol, ctorFunction, {}); @@ -403,7 +403,7 @@ void IRGenerator::generateCopyCtorBodyPreamble(const Function *copyCtorFunction) const QualType &fieldType = fieldSymbol->getQualType(); if (fieldType.is(TY_STRUCT)) { // Lookup copy ctor function and call if available - Scope *matchScope = fieldType.getType().getBodyScope(); + Scope *matchScope = fieldType.getBodyScope(); const ArgList args = {{fieldType.toConstRef(nullptr), false /* we have the field as storage */}}; const Function *ctorFct = FunctionManager::lookupFunction(matchScope, CTOR_FUNCTION_NAME, fieldType, args, false); if (ctorFct) { @@ -449,7 +449,7 @@ void IRGenerator::generateDtorBodyPreamble(const Function *dtorFunction) { if (fieldType.is(TY_STRUCT)) { // Lookup dtor function and generate call if found const Function *dtorFct = - FunctionManager::lookupFunction(fieldType.getType().getBodyScope(), DTOR_FUNCTION_NAME, fieldType, {}, false); + FunctionManager::lookupFunction(fieldType.getBodyScope(), DTOR_FUNCTION_NAME, fieldType, {}, false); if (dtorFct) generateCtorOrDtorCall(fieldSymbol, dtorFct, {}); continue; diff --git a/src/irgenerator/GenStatements.cpp b/src/irgenerator/GenStatements.cpp index cc48fef4a..b53f75a87 100644 --- a/src/irgenerator/GenStatements.cpp +++ b/src/irgenerator/GenStatements.cpp @@ -41,8 +41,8 @@ std::any IRGenerator::visitDeclStmt(const DeclStmtNode *node) { // Get LLVM type of variable Scope *accessScope = currentScope; if (varSymbolType.is(TY_STRUCT)) - accessScope = varSymbolType.getType().getBodyScope()->parent; - llvm::Type *varTy = varSymbolType.getType().toLLVMType(context, accessScope); + accessScope = varSymbolType.getBodyScope()->parent; + llvm::Type *varTy = varSymbolType.toLLVMType(context, accessScope); // Check if right side is dyn array. If this is the case we have an empty array initializer and need the default value const bool rhsIsDynArray = node->hasAssignment && node->assignExpr()->getEvaluatedSymbolType(manIdx).isArrayOf(TY_DYN); diff --git a/src/irgenerator/GenTopLevelDefinitions.cpp b/src/irgenerator/GenTopLevelDefinitions.cpp index b2b9a759d..8593b5baa 100644 --- a/src/irgenerator/GenTopLevelDefinitions.cpp +++ b/src/irgenerator/GenTopLevelDefinitions.cpp @@ -25,7 +25,7 @@ std::any IRGenerator::visitMainFctDef(const MainFctDefNode *node) { // Visit parameters std::vector> paramInfoList; - std::vector paramSymbolTypes; + QualTypeList paramSymbolTypes; std::vector paramTypes; if (node->takesArgs) { const size_t numOfParams = node->paramLst()->params().size(); @@ -142,7 +142,7 @@ std::any IRGenerator::visitFctDef(const FctDefNode *node) { // Change to struct scope if (manifestation->isMethod()) { const QualType &thisType = manifestation->thisType; - const std::string signature = Struct::getSignature(thisType.getSubType(), thisType.getType().getTemplateTypes()); + const std::string signature = Struct::getSignature(thisType.getSubType(), thisType.getTemplateTypes()); currentScope = currentScope->getChildScope(STRUCT_SCOPE_PREFIX + signature); assert(currentScope != nullptr); } @@ -175,13 +175,13 @@ std::any IRGenerator::visitFctDef(const FctDefNode *node) { assert(paramSymbol != nullptr); const QualType paramSymbolType = manifestation->getParamTypes().at(argIdx); // Pass the information if captures are taken for function/procedure types - if (paramSymbolType.isOneOf({TY_FUNCTION, TY_PROCEDURE}) && paramSymbolType.getType().hasLambdaCaptures()) { + if (paramSymbolType.isOneOf({TY_FUNCTION, TY_PROCEDURE}) && paramSymbolType.hasLambdaCaptures()) { QualType paramSymbolSymbolType = paramSymbol->getQualType(); - paramSymbolSymbolType.getType().setHasLambdaCaptures(true); + paramSymbolSymbolType.setHasLambdaCaptures(true); paramSymbol->updateType(paramSymbolSymbolType, true); } // Retrieve type of param - llvm::Type *paramType = paramSymbolType.getType().toLLVMType(context, currentScope); + llvm::Type *paramType = paramSymbolType.toLLVMType(context, currentScope); // Add it to the lists paramInfoList.emplace_back(param->varName, paramSymbol); paramTypes.push_back(paramType); @@ -189,7 +189,7 @@ std::any IRGenerator::visitFctDef(const FctDefNode *node) { } // Get return type - llvm::Type *returnType = manifestation->returnType.getType().toLLVMType(context, currentScope); + llvm::Type *returnType = manifestation->returnType.toLLVMType(context, currentScope); // Check if function is explicitly inlined const bool explicitlyInlined = manifestation->entry->getQualType().isInline(); @@ -314,7 +314,7 @@ std::any IRGenerator::visitProcDef(const ProcDefNode *node) { // Change to struct scope if (manifestation->isMethod()) { const QualType &thisType = manifestation->thisType; - const std::string signature = Struct::getSignature(thisType.getSubType(), thisType.getType().getTemplateTypes()); + const std::string signature = Struct::getSignature(thisType.getSubType(), thisType.getTemplateTypes()); currentScope = currentScope->getChildScope(STRUCT_SCOPE_PREFIX + signature); assert(currentScope != nullptr); } @@ -347,13 +347,13 @@ std::any IRGenerator::visitProcDef(const ProcDefNode *node) { assert(paramSymbol != nullptr); const QualType paramSymbolType = manifestation->getParamTypes().at(argIdx); // Pass the information if captures are taken for function/procedure types - if (paramSymbolType.isOneOf({TY_FUNCTION, TY_PROCEDURE}) && paramSymbolType.getType().hasLambdaCaptures()) { + if (paramSymbolType.isOneOf({TY_FUNCTION, TY_PROCEDURE}) && paramSymbolType.hasLambdaCaptures()) { QualType paramSymbolSymbolType = paramSymbol->getQualType(); - paramSymbolSymbolType.getType().setHasLambdaCaptures(true); + paramSymbolSymbolType.setHasLambdaCaptures(true); paramSymbol->updateType(paramSymbolSymbolType, true); } // Retrieve type of param - llvm::Type *paramType = paramSymbolType.getType().toLLVMType(context, currentScope); + llvm::Type *paramType = paramSymbolType.toLLVMType(context, currentScope); // Add it to the lists paramInfoList.emplace_back(param->varName, paramSymbol); paramTypes.push_back(paramType); @@ -594,13 +594,13 @@ std::any IRGenerator::visitExtDecl(const ExtDeclNode *node) { assert(spiceFunc != nullptr); llvm::Type *returnType = builder.getVoidTy(); if (!spiceFunc->returnType.is(TY_DYN)) - returnType = spiceFunc->returnType.getType().toLLVMType(context, currentScope); + returnType = spiceFunc->returnType.toLLVMType(context, currentScope); // Get arg types std::vector argTypes; argTypes.reserve(spiceFunc->paramList.size()); for (const QualType ¶mType : spiceFunc->getParamTypes()) - argTypes.push_back(paramType.getType().toLLVMType(context, currentScope)); + argTypes.push_back(paramType.toLLVMType(context, currentScope)); // Declare function llvm::FunctionType *functionType = llvm::FunctionType::get(returnType, argTypes, node->isVarArg); diff --git a/src/irgenerator/GenVTable.cpp b/src/irgenerator/GenVTable.cpp index c0706d8f9..9d73b1c5e 100644 --- a/src/irgenerator/GenVTable.cpp +++ b/src/irgenerator/GenVTable.cpp @@ -33,7 +33,7 @@ llvm::Constant *IRGenerator::generateTypeInfo(StructBase *spiceStruct) { const std::string mangledName = NameMangling::mangleTypeInfo(spiceStruct); llvm::PointerType *ptrTy = builder.getPtrTy(); - std::vector interfaceTypes; + QualTypeList interfaceTypes; if (spiceStruct->entry->getQualType().is(TY_STRUCT)) { auto spiceStructEnsured = reinterpret_cast(spiceStruct); interfaceTypes = spiceStructEnsured->interfaceTypes; @@ -58,7 +58,7 @@ llvm::Constant *IRGenerator::generateTypeInfo(StructBase *spiceStruct) { fieldValues.push_back(typeInfoVTable); fieldValues.push_back(typeInfoName); for (const QualType &interfaceType : interfaceTypes) { - Interface *interface = interfaceType.getType().getInterface(nullptr); + Interface *interface = interfaceType.getInterface(nullptr); assert(interface != nullptr && interface->vTableData.typeInfo != nullptr); const std::string interfaceMangledName = NameMangling::mangleTypeInfo(interface); llvm::Constant *global = module->getOrInsertGlobal(interfaceMangledName, builder.getPtrTy()); diff --git a/src/irgenerator/GenValues.cpp b/src/irgenerator/GenValues.cpp index 0053fab34..2f3bb2028 100644 --- a/src/irgenerator/GenValues.cpp +++ b/src/irgenerator/GenValues.cpp @@ -75,7 +75,7 @@ std::any IRGenerator::visitFctCall(const FctCallNode *node) { // Retrieve entry of the first fragment const QualType baseType = firstFragEntry->getQualType().getBase(); assert(firstFragEntry != nullptr && baseType.isOneOf({TY_STRUCT, TY_INTERFACE})); - Scope *structScope = baseType.getType().getBodyScope(); + Scope *structScope = baseType.getBodyScope(); // Get address of the referenced variable / struct instance thisPtr = firstFragEntry->getAddress(); @@ -94,14 +94,14 @@ std::any IRGenerator::visitFctCall(const FctCallNode *node) { QualType fieldEntryType = fieldEntry->getQualType(); assert(fieldEntryType.getBase().isOneOf({TY_STRUCT, TY_INTERFACE})); // Get struct type and scope - structScope = fieldEntryType.getBase().getType().getBodyScope(); + structScope = fieldEntryType.getBase().getBodyScope(); assert(structScope != nullptr); // Get address of field llvm::Value *indices[2] = {builder.getInt32(0), builder.getInt32(fieldEntry->orderIndex)}; thisPtr = insertInBoundsGEP(structTy, thisPtr, indices); // Auto de-reference pointer and get new struct type autoDeReferencePtr(thisPtr, fieldEntryType, structScope->parent); - structTy = fieldEntryType.getBase().getType().toLLVMType(context, structScope->parent); + structTy = fieldEntryType.getBase().toLLVMType(context, structScope->parent); } // Add 'this' pointer to the front of the argument list @@ -111,7 +111,7 @@ std::any IRGenerator::visitFctCall(const FctCallNode *node) { if (data.isCtorCall()) { assert(!data.isMethodCall()); - llvm::Type *thisType = spiceFunc->thisType.getType().toLLVMType(context, spiceFunc->thisType.getType().getBodyScope()); + llvm::Type *thisType = spiceFunc->thisType.toLLVMType(context, spiceFunc->thisType.getBodyScope()); thisPtr = insertAlloca(thisType); // Add 'this' pointer to the front of the argument list @@ -125,7 +125,7 @@ std::any IRGenerator::visitFctCall(const FctCallNode *node) { // Load fctPtr llvm::StructType *fatStructType = llvm::StructType::get(context, {builder.getPtrTy(), builder.getPtrTy()}); fctPtr = insertStructGEP(fatStructType, fatPtr, 0); - if (firstFragEntry->getQualType().getType().hasLambdaCaptures()) { + if (firstFragEntry->getQualType().hasLambdaCaptures()) { // Load captures struct llvm::Value *capturesPtrPtr = insertStructGEP(fatStructType, fatPtr, 1); llvm::Value *capturesPtr = insertLoad(builder.getPtrTy(), capturesPtrPtr, false, CAPTURES_PARAM_NAME); @@ -138,8 +138,8 @@ std::any IRGenerator::visitFctCall(const FctCallNode *node) { if (node->hasArgs) { argValues.reserve(node->argLst()->args().size()); const std::vector args = node->argLst()->args(); - const std::vector paramSTypes = - data.isFctPtrCall() ? firstFragEntry->getQualType().getBase().getType().getFunctionParamTypes() : spiceFunc->getParamTypes(); + const QualTypeList paramSTypes = + data.isFctPtrCall() ? firstFragEntry->getQualType().getBase().getFunctionParamTypes() : spiceFunc->getParamTypes(); assert(paramSTypes.size() == args.size()); for (size_t i = 0; i < args.size(); i++) { AssignExprNode *argNode = args.at(i); @@ -147,7 +147,7 @@ std::any IRGenerator::visitFctCall(const FctCallNode *node) { const QualType &actualSTy = argNode->getEvaluatedSymbolType(manIdx); const auto matchFct = [](const QualType &lhsTy, const QualType &rhsTy) { - return lhsTy.matches(rhsTy, false, true, true) || lhsTy.getType().matchesInterfaceImplementedByStruct(rhsTy.getType()); + return lhsTy.matches(rhsTy, false, true, true) || lhsTy.matchesInterfaceImplementedByStruct(rhsTy); }; // If the arrays are both of size -1 or 0, they are both pointers and do not need to be cast implicitly @@ -170,11 +170,11 @@ std::any IRGenerator::visitFctCall(const FctCallNode *node) { // Retrieve return and param types QualType returnSType(TY_DYN); - std::vector paramSTypes; + QualTypeList paramSTypes; if (data.isFctPtrCall()) { if (firstFragEntry->getQualType().isBase(TY_FUNCTION)) - returnSType = firstFragEntry->getQualType().getBase().getType().getFunctionReturnType(); - paramSTypes = firstFragEntry->getQualType().getBase().getType().getFunctionParamTypes(); + returnSType = firstFragEntry->getQualType().getBase().getFunctionReturnType(); + paramSTypes = firstFragEntry->getQualType().getBase().getFunctionParamTypes(); } else { returnSType = spiceFunc->returnType; paramSTypes = spiceFunc->getParamTypes(); @@ -188,16 +188,16 @@ std::any IRGenerator::visitFctCall(const FctCallNode *node) { // Get returnType llvm::Type *returnType = builder.getVoidTy(); if (!returnSType.is(TY_DYN)) - returnType = returnSType.getType().toLLVMType(context, accessScope); + returnType = returnSType.toLLVMType(context, accessScope); // Get arg types std::vector argTypes; if (data.isMethodCall() || data.isCtorCall()) argTypes.push_back(builder.getPtrTy()); // This pointer - if (data.isFctPtrCall() && firstFragEntry->getQualType().getType().hasLambdaCaptures()) + if (data.isFctPtrCall() && firstFragEntry->getQualType().hasLambdaCaptures()) argTypes.push_back(builder.getPtrTy()); // Capture pointer for (const QualType ¶mType : paramSTypes) - argTypes.push_back(paramType.getType().toLLVMType(context, accessScope)); + argTypes.push_back(paramType.toLLVMType(context, accessScope)); fctType = llvm::FunctionType::get(returnType, argTypes, false); if (!data.isFctPtrCall() && !data.isVirtualMethodCall()) @@ -238,7 +238,7 @@ std::any IRGenerator::visitFctCall(const FctCallNode *node) { } if (data.isMethodCall() || data.isCtorCall() || data.isVirtualMethodCall()) { - llvm::Type *thisType = data.thisType.getType().toLLVMType(context, currentScope); + llvm::Type *thisType = data.thisType.toLLVMType(context, currentScope); result->addParamAttr(0, llvm::Attribute::NoUndef); result->addParamAttr(0, llvm::Attribute::NonNull); result->addDereferenceableParamAttr(0, module->getDataLayout().getTypeStoreSize(thisType)); @@ -292,7 +292,7 @@ std::any IRGenerator::visitArrayInitialization(const ArrayInitializationNode *no // Get LLVM type of item and array assert(!itemResults.empty()); const QualType &firstItemSTy = node->itemLst()->args().front()->getEvaluatedSymbolType(manIdx); - llvm::Type *itemType = firstItemSTy.getType().toLLVMType(context, currentScope); + llvm::Type *itemType = firstItemSTy.toLLVMType(context, currentScope); llvm::ArrayType *arrayType = llvm::ArrayType::get(itemType, node->actualSize); if (canBeConstant) { // All items are constants, so we can create a global constant array @@ -337,7 +337,7 @@ std::any IRGenerator::visitStructInstantiation(const StructInstantiationNode *no // Get struct object const Struct *spiceStruct = node->instantiatedStructs.at(manIdx); assert(spiceStruct != nullptr); - const std::vector &fieldTypes = spiceStruct->fieldTypes; + const QualTypeList &fieldTypes = spiceStruct->fieldTypes; // Can only be constant if none of the fields is of type reference bool canBeConstant = !spiceStruct->hasReferenceFields(); @@ -446,7 +446,7 @@ std::any IRGenerator::visitLambdaFunc(const LambdaFuncNode *node) { SymbolTableEntry *paramSymbol = currentScope->lookupStrict(param->varName); assert(paramSymbol != nullptr); // Retrieve type of param - llvm::Type *paramType = spiceFunc.getParamTypes().at(argIdx).getType().toLLVMType(context, currentScope); + llvm::Type *paramType = spiceFunc.getParamTypes().at(argIdx).toLLVMType(context, currentScope); // Add it to the lists paramInfoList.emplace_back(param->varName, paramSymbol); paramTypes.push_back(paramType); @@ -454,7 +454,7 @@ std::any IRGenerator::visitLambdaFunc(const LambdaFuncNode *node) { } // Get return type - llvm::Type *returnType = spiceFunc.returnType.getType().toLLVMType(context, currentScope); + llvm::Type *returnType = spiceFunc.returnType.toLLVMType(context, currentScope); // Create function or implement declared function spiceFunc.mangleSuffix = "." + std::to_string(manIdx); @@ -601,7 +601,7 @@ std::any IRGenerator::visitLambdaProc(const LambdaProcNode *node) { SymbolTableEntry *paramSymbol = currentScope->lookupStrict(param->varName); assert(paramSymbol != nullptr); // Retrieve type of param - llvm::Type *paramType = spiceFunc.getParamTypes().at(argIdx).getType().toLLVMType(context, currentScope); + llvm::Type *paramType = spiceFunc.getParamTypes().at(argIdx).toLLVMType(context, currentScope); // Add it to the lists paramInfoList.emplace_back(param->varName, paramSymbol); paramTypes.push_back(paramType); @@ -743,7 +743,7 @@ std::any IRGenerator::visitLambdaExpr(const LambdaExprNode *node) { SymbolTableEntry *paramSymbol = currentScope->lookupStrict(param->varName); assert(paramSymbol != nullptr); // Retrieve type of param - llvm::Type *paramType = spiceFunc.getParamTypes().at(argIdx).getType().toLLVMType(context, currentScope); + llvm::Type *paramType = spiceFunc.getParamTypes().at(argIdx).toLLVMType(context, currentScope); // Add it to the lists paramInfoList.emplace_back(param->varName, paramSymbol); paramTypes.push_back(paramType); @@ -753,7 +753,7 @@ std::any IRGenerator::visitLambdaExpr(const LambdaExprNode *node) { // Get return type llvm::Type *returnType = builder.getVoidTy(); if (spiceFunc.isFunction()) - returnType = spiceFunc.returnType.getType().toLLVMType(context, currentScope); + returnType = spiceFunc.returnType.toLLVMType(context, currentScope); // Create function or implement declared function const std::string mangledName = spiceFunc.getMangledName(); @@ -859,7 +859,7 @@ std::any IRGenerator::visitDataType(const DataTypeNode *node) { // Retrieve symbol type QualType symbolType = node->getEvaluatedSymbolType(manIdx); assert(!symbolType.is(TY_DYN)); // Symbol type should not be dyn anymore at this point - return symbolType.getType().toLLVMType(context, currentScope); + return symbolType.toLLVMType(context, currentScope); } llvm::Value *IRGenerator::buildFatFctPtr(Scope *bodyScope, llvm::Type *capturesStructType, llvm::Value *lambda) { diff --git a/src/irgenerator/IRGenerator.cpp b/src/irgenerator/IRGenerator.cpp index 1310f57c8..55bddb0e7 100644 --- a/src/irgenerator/IRGenerator.cpp +++ b/src/irgenerator/IRGenerator.cpp @@ -142,7 +142,7 @@ llvm::Value *IRGenerator::resolveValue(const QualType &qualType, LLVMExprResult exprResult.ptr = insertLoad(builder.getPtrTy(), exprResult.refPtr, exprResult.entry && exprResult.entry->isVolatile); // Load the value from the pointer - llvm::Type *valueTy = referencedType.getType().toLLVMType(context, accessScope); + llvm::Type *valueTy = referencedType.toLLVMType(context, accessScope); exprResult.value = insertLoad(valueTy, exprResult.ptr, exprResult.entry && exprResult.entry->isVolatile); return exprResult.value; @@ -210,7 +210,7 @@ llvm::Constant *IRGenerator::getDefaultValueForSymbolType(const QualType &symbol // Array if (symbolType.isArray()) { // Get array size - const size_t arraySize = symbolType.getType().getArraySize(); + const size_t arraySize = symbolType.getArraySize(); // Get default value for item llvm::Constant *defaultItemValue = getDefaultValueForSymbolType(symbolType.getContained()); @@ -236,10 +236,10 @@ llvm::Constant *IRGenerator::getDefaultValueForSymbolType(const QualType &symbol // Struct if (symbolType.is(TY_STRUCT)) { // Retrieve struct type - Scope *structScope = symbolType.getType().getBodyScope(); + Scope *structScope = symbolType.getBodyScope(); assert(structScope != nullptr); const size_t fieldCount = structScope->getFieldCount(); - auto structType = reinterpret_cast(symbolType.getType().toLLVMType(context, structScope)); + auto structType = reinterpret_cast(symbolType.toLLVMType(context, structScope)); // Get default values for all fields of the struct std::vector fieldConstants; @@ -266,9 +266,9 @@ llvm::Constant *IRGenerator::getDefaultValueForSymbolType(const QualType &symbol // Interface if (symbolType.is(TY_INTERFACE)) { // Retrieve struct type - Scope *interfaceScope = symbolType.getType().getBodyScope(); + Scope *interfaceScope = symbolType.getBodyScope(); assert(interfaceScope != nullptr); - auto structType = reinterpret_cast(symbolType.getType().toLLVMType(context, interfaceScope)); + auto structType = reinterpret_cast(symbolType.toLLVMType(context, interfaceScope)); return llvm::ConstantStruct::get(structType, llvm::Constant::getNullValue(builder.getPtrTy())); } @@ -429,7 +429,7 @@ LLVMExprResult IRGenerator::doAssignment(llvm::Value *lhsAddress, SymbolTableEnt assert(rhsAddress != nullptr); // Check if we have a copy ctor - Scope *structScope = rhsSType.getType().getBodyScope(); + Scope *structScope = rhsSType.getBodyScope(); const ArgList args = {{rhsSType.toConstRef(nullptr), rhs.isTemporary()}}; auto copyCtor = FunctionManager::matchFunction(structScope, CTOR_FUNCTION_NAME, rhsSType, args, {}, true, nullptr); if (copyCtor != nullptr) { @@ -438,7 +438,7 @@ LLVMExprResult IRGenerator::doAssignment(llvm::Value *lhsAddress, SymbolTableEnt return LLVMExprResult{.ptr = lhsAddress, .entry = lhsEntry}; } else { // Create shallow copy - llvm::Type *rhsType = rhsSType.getType().toLLVMType(context, currentScope); + llvm::Type *rhsType = rhsSType.toLLVMType(context, currentScope); const std::string copyName = lhsEntry ? lhsEntry->name : ""; llvm::Value *newAddress = createShallowCopy(rhsAddress, rhsType, lhsAddress, copyName, lhsEntry && lhsEntry->isVolatile); // Set address of lhs to the copy @@ -465,12 +465,11 @@ LLVMExprResult IRGenerator::doAssignment(llvm::Value *lhsAddress, SymbolTableEnt } // Check if we try to assign an array by value to a pointer. Here we have to store the address of the first element to the lhs - if (lhsEntry && lhsEntry->getQualType().isPtr() && rhsSType.isArray() && - rhsSType.getType().getArraySize() != ARRAY_SIZE_UNKNOWN) { + if (lhsEntry && lhsEntry->getQualType().isPtr() && rhsSType.isArray() && rhsSType.getArraySize() != ARRAY_SIZE_UNKNOWN) { // Get address of right side llvm::Value *rhsAddress = resolveAddress(rhs); assert(rhsAddress != nullptr); - llvm::Type *elementTy = rhsSType.getType().toLLVMType(context, currentScope); + llvm::Type *elementTy = rhsSType.toLLVMType(context, currentScope); llvm::Value *indices[2] = {builder.getInt32(0), builder.getInt32(0)}; llvm::Value *firstItemAddress = insertInBoundsGEP(elementTy, rhsAddress, indices); insertStore(firstItemAddress, lhsAddress); @@ -507,7 +506,7 @@ llvm::Value *IRGenerator::createShallowCopy(llvm::Value *oldAddress, llvm::Type void IRGenerator::autoDeReferencePtr(llvm::Value *&ptr, QualType &symbolType, Scope *accessScope) const { while (symbolType.isPtr() || symbolType.isRef()) { - ptr = insertLoad(symbolType.getType().toLLVMType(context, accessScope), ptr); + ptr = insertLoad(symbolType.toLLVMType(context, accessScope), ptr); symbolType = symbolType.getContained(); } } diff --git a/src/irgenerator/IRGenerator.h b/src/irgenerator/IRGenerator.h index 479d259b9..dbb4e41e2 100644 --- a/src/irgenerator/IRGenerator.h +++ b/src/irgenerator/IRGenerator.h @@ -138,8 +138,8 @@ class IRGenerator : private CompilerPass, public ParallelizableASTVisitor { void verifyModule(const CodeLoc &codeLoc) const; LLVMExprResult doAssignment(const ASTNode *lhsNode, const ASTNode *rhsNode); LLVMExprResult doAssignment(llvm::Value *lhsAddress, SymbolTableEntry *lhsEntry, const ASTNode *rhsNode, bool isDecl = false); - LLVMExprResult doAssignment(llvm::Value *lhsAddress, SymbolTableEntry *lhsEntry, LLVMExprResult &rhs, - const QualType &rhsSType, bool isDecl); + LLVMExprResult doAssignment(llvm::Value *lhsAddress, SymbolTableEntry *lhsEntry, LLVMExprResult &rhs, const QualType &rhsSType, + bool isDecl); llvm::Value *createShallowCopy(llvm::Value *oldAddress, llvm::Type *varType, llvm::Value *targetAddress, const std::string &name = "", bool isVolatile = false); void autoDeReferencePtr(llvm::Value *&ptr, QualType &symbolType, Scope *accessScope) const; diff --git a/src/irgenerator/NameMangling.cpp b/src/irgenerator/NameMangling.cpp index f15c95ea2..9d6535a1d 100644 --- a/src/irgenerator/NameMangling.cpp +++ b/src/irgenerator/NameMangling.cpp @@ -44,7 +44,7 @@ std::string NameMangling::mangleFunction(const Function &spiceFunc) { // Template types bool isSelfGeneric = !spiceFunc.templateTypes.empty(); if (spiceFunc.isMethod()) - isSelfGeneric = spiceFunc.templateTypes.size() > spiceFunc.thisType.getType().getTemplateTypes().size(); + isSelfGeneric = spiceFunc.templateTypes.size() > spiceFunc.thisType.getTemplateTypes().size(); if (isSelfGeneric) { mangledName << "I"; // Template types themselves diff --git a/src/irgenerator/OpRuleConversionManager.cpp b/src/irgenerator/OpRuleConversionManager.cpp index 78bf8aee9..cbd323612 100644 --- a/src/irgenerator/OpRuleConversionManager.cpp +++ b/src/irgenerator/OpRuleConversionManager.cpp @@ -1681,7 +1681,7 @@ LLVMExprResult OpRuleConversionManager::callOperatorOverloadFct(const ASTNode *n assert(accessScope != nullptr); // Get arg values - const std::vector ¶mTypes = opFct->getParamTypes(); + const QualTypeList ¶mTypes = opFct->getParamTypes(); assert(paramTypes.size() == N); llvm::Value *argValues[N]; argValues[0] = paramTypes[0].isRef() ? opV[1]() : opV[0](); @@ -1693,12 +1693,12 @@ LLVMExprResult OpRuleConversionManager::callOperatorOverloadFct(const ASTNode *n // Get returnType llvm::Type *returnType = builder.getVoidTy(); if (!opFct->returnType.is(TY_DYN)) - returnType = opFct->returnType.getType().toLLVMType(context, accessScope); + returnType = opFct->returnType.toLLVMType(context, accessScope); // Get arg types std::vector argTypes; for (const QualType ¶mType : opFct->getParamTypes()) - argTypes.push_back(paramType.getType().toLLVMType(context, accessScope)); + argTypes.push_back(paramType.toLLVMType(context, accessScope)); llvm::FunctionType *fctType = llvm::FunctionType::get(returnType, argTypes, false); irGenerator->module->getOrInsertFunction(mangledName, fctType); diff --git a/src/irgenerator/StdFunctionManager.cpp b/src/irgenerator/StdFunctionManager.cpp index a8c3d4a32..f96222bd0 100644 --- a/src/irgenerator/StdFunctionManager.cpp +++ b/src/irgenerator/StdFunctionManager.cpp @@ -80,13 +80,13 @@ llvm::Function *StdFunctionManager::getDeallocBytePtrRefFct() const { llvm::Function *StdFunctionManager::getIterateFct(const Function *spiceFunc) const { const std::string functionName = NameMangling::mangleFunction(*spiceFunc); - llvm::Type *iteratorType = spiceFunc->returnType.getType().toLLVMType(context, nullptr); + llvm::Type *iteratorType = spiceFunc->returnType.toLLVMType(context, nullptr); return getFunction(functionName.c_str(), iteratorType, {builder.getPtrTy(), builder.getInt64Ty()}); } llvm::Function *StdFunctionManager::getIteratorFct(const Function *spiceFunc) const { const std::string functionName = NameMangling::mangleFunction(*spiceFunc); - llvm::Type *iteratorType = spiceFunc->returnType.getType().toLLVMType(context, nullptr); + llvm::Type *iteratorType = spiceFunc->returnType.toLLVMType(context, nullptr); return getFunction(functionName.c_str(), iteratorType, builder.getPtrTy()); } @@ -97,7 +97,7 @@ llvm::Function *StdFunctionManager::getIteratorGetFct(const Function *spiceFunc) llvm::Function *StdFunctionManager::getIteratorGetIdxFct(const Function *spiceFunc, Scope *accessScope) const { const std::string functionName = NameMangling::mangleFunction(*spiceFunc); - llvm::Type *pairTy = spiceFunc->returnType.getType().toLLVMType(context, accessScope); + llvm::Type *pairTy = spiceFunc->returnType.toLLVMType(context, accessScope); return getFunction(functionName.c_str(), pairTy, builder.getPtrTy()); } diff --git a/src/model/Function.cpp b/src/model/Function.cpp index c0afb428c..60a57ac50 100644 --- a/src/model/Function.cpp +++ b/src/model/Function.cpp @@ -13,8 +13,8 @@ namespace spice::compiler { * * @return Vector of parameter types */ -std::vector Function::getParamTypes() const { - std::vector newParamTypes; +QualTypeList Function::getParamTypes() const { + QualTypeList newParamTypes; for (const Param ¶m : paramList) newParamTypes.push_back(param.type); return newParamTypes; @@ -31,7 +31,7 @@ std::vector Function::getParamTypes() const { * @return String representation as function signature */ std::string Function::getSignature(bool withThisType /*=true*/, bool ignorePublic /*=false*/) const { - std::vector concreteTemplateTypes; + QualTypeList concreteTemplateTypes; concreteTemplateTypes.reserve(templateTypes.size()); for (const GenericType &genericType : templateTypes) { if (genericType.is(TY_GENERIC) && !typeMapping.empty()) { @@ -58,7 +58,7 @@ std::string Function::getSignature(bool withThisType /*=true*/, bool ignorePubli * @return Function signature */ std::string Function::getSignature(const std::string &name, const QualType &thisType, const QualType &returnType, - const ParamList ¶mList, const std::vector &concreteTemplateTypes, + const ParamList ¶mList, const QualTypeList &concreteTemplateTypes, bool withThisType /*=true*/, bool ignorePublic /*=false*/) { std::stringstream signature; @@ -71,7 +71,7 @@ std::string Function::getSignature(const std::string &name, const QualType &this // Build this type string if (withThisType && !thisType.is(TY_DYN)) { signature << thisType.getBase().getSubType(); - const std::vector &thisTemplateTypes = thisType.getType().getTemplateTypes(); + const QualTypeList &thisTemplateTypes = thisType.getTemplateTypes(); if (!thisTemplateTypes.empty()) { signature << "<"; for (size_t i = 0; i < thisTemplateTypes.size(); i++) { diff --git a/src/model/Function.h b/src/model/Function.h index 2f005152b..920950605 100644 --- a/src/model/Function.h +++ b/src/model/Function.h @@ -39,10 +39,10 @@ class Function { Function() = default; // Public methods - [[nodiscard]] std::vector getParamTypes() const; + [[nodiscard]] QualTypeList getParamTypes() const; [[nodiscard]] std::string getSignature(bool withThisType = true, bool ignorePublic = true) const; [[nodiscard]] static std::string getSignature(const std::string &name, const QualType &thisType, const QualType &returnType, - const ParamList ¶mList, const std::vector &concreteTemplateTypes, + const ParamList ¶mList, const QualTypeList &concreteTemplateTypes, bool withThisType = true, bool ignorePublic = true); [[nodiscard]] std::string getMangledName() const; [[nodiscard]] static std::string getSymbolTableEntryName(const std::string &functionName, const CodeLoc &codeLoc); diff --git a/src/model/GenericType.h b/src/model/GenericType.h index cb5dc28cd..99a20bbea 100644 --- a/src/model/GenericType.h +++ b/src/model/GenericType.h @@ -20,7 +20,7 @@ class GenericType : public QualType { // Constructors explicit GenericType(const QualType &type) : QualType(type){}; explicit GenericType(const std::string &name) : QualType(TY_GENERIC, name) {} - GenericType(const std::string &name, const std::vector &typeConditions) + GenericType(const std::string &name, const QualTypeList &typeConditions) : QualType(TY_GENERIC, name), typeConditions(typeConditions) {} GenericType() = default; @@ -32,7 +32,7 @@ class GenericType : public QualType { private: // Members - std::vector typeConditions = {QualType(TY_DYN)}; + QualTypeList typeConditions = {QualType(TY_DYN)}; // Private methods [[nodiscard]] [[deprecated]] bool checkTypeConditionOf(const QualType &type, bool ignoreArraySize, bool ignoreSpecifiers) const; diff --git a/src/model/Struct.h b/src/model/Struct.h index d23802b5d..0601326c4 100644 --- a/src/model/Struct.h +++ b/src/model/Struct.h @@ -14,8 +14,8 @@ namespace spice::compiler { class Struct : public StructBase { public: // Constructors - Struct(std::string name, SymbolTableEntry *entry, Scope *scope, std::vector fieldTypes, - std::vector templateTypes, std::vector interfaceTypes, ASTNode *declNode) + Struct(std::string name, SymbolTableEntry *entry, Scope *scope, QualTypeList fieldTypes, std::vector templateTypes, + QualTypeList interfaceTypes, ASTNode *declNode) : StructBase(std::move(name), entry, scope, std::move(templateTypes), declNode), fieldTypes(std::move(fieldTypes)), interfaceTypes(std::move(interfaceTypes)) {} @@ -23,8 +23,8 @@ class Struct : public StructBase { [[nodiscard]] bool hasReferenceFields() const; // Public members - std::vector fieldTypes; - std::vector interfaceTypes; + QualTypeList fieldTypes; + QualTypeList interfaceTypes; }; } // namespace spice::compiler \ No newline at end of file diff --git a/src/model/StructBase.cpp b/src/model/StructBase.cpp index 195661953..032a1d563 100644 --- a/src/model/StructBase.cpp +++ b/src/model/StructBase.cpp @@ -15,7 +15,7 @@ namespace spice::compiler { * @return String representation as struct signature */ std::string StructBase::getSignature() const { - std::vector templateSymbolTypes; + QualTypeList templateSymbolTypes; templateSymbolTypes.reserve(templateTypes.size()); for (const GenericType &genericType : templateTypes) { if (genericType.is(TY_GENERIC) && !typeMapping.empty()) { @@ -39,7 +39,7 @@ std::string StructBase::getSignature() const { * @param concreteTemplateTypes Concrete template types * @return Signature */ -std::string StructBase::getSignature(const std::string &name, const std::vector &concreteTemplateTypes) { +std::string StructBase::getSignature(const std::string &name, const QualTypeList &concreteTemplateTypes) { // Build template type string std::stringstream templateTyStr; if (!concreteTemplateTypes.empty()) { @@ -79,8 +79,8 @@ bool StructBase::isFullySubstantiated() const { return hasSubstantiatedGenerics( * * @return Template types as vector of symbol types */ -std::vector StructBase::getTemplateTypes() const { - std::vector templateSymbolTypes; +QualTypeList StructBase::getTemplateTypes() const { + QualTypeList templateSymbolTypes; for (const GenericType &genericTemplateType : templateTypes) templateSymbolTypes.push_back(genericTemplateType); return templateSymbolTypes; diff --git a/src/model/StructBase.h b/src/model/StructBase.h index bee0aac6b..3d838776b 100644 --- a/src/model/StructBase.h +++ b/src/model/StructBase.h @@ -27,10 +27,10 @@ class StructBase { // Public methods [[nodiscard]] std::string getSignature() const; - static std::string getSignature(const std::string &name, const std::vector &concreteTemplateTypes); + static std::string getSignature(const std::string &name, const QualTypeList &concreteTemplateTypes); [[nodiscard]] bool hasSubstantiatedGenerics() const; [[nodiscard]] bool isFullySubstantiated() const; - [[nodiscard]] std::vector getTemplateTypes() const; + [[nodiscard]] QualTypeList getTemplateTypes() const; [[nodiscard]] const CodeLoc &getDeclCodeLoc() const; [[nodiscard]] bool isGenericSubstantiation() const; diff --git a/src/symboltablebuilder/QualType.cpp b/src/symboltablebuilder/QualType.cpp index 3c47ec45d..2a6ae8b2d 100644 --- a/src/symboltablebuilder/QualType.cpp +++ b/src/symboltablebuilder/QualType.cpp @@ -4,7 +4,12 @@ #include +#include +#include +#include #include +#include +#include namespace spice::compiler { @@ -24,127 +29,315 @@ QualType &QualType::operator=(const spice::compiler::QualType &other) { return *this; } -void QualType::getName(std::stringstream &name, bool withSize, bool ignorePublic) const { - // Append the specifiers - const TypeSpecifiers defaultForSuperType = TypeSpecifiers::of(getBase().getSuperType()); - if (!ignorePublic && specifiers.isPublic && !defaultForSuperType.isPublic) - name << "public "; - if (specifiers.isInline && !defaultForSuperType.isInline) - name << "inline "; - if (specifiers.isComposition && !defaultForSuperType.isComposition) - name << "compose "; - if (specifiers.isConst && !defaultForSuperType.isConst) - name << "const "; - if (specifiers.isHeap && !defaultForSuperType.isHeap) - name << "heap "; - if (specifiers.isSigned && !defaultForSuperType.isSigned) - name << "signed "; - if (!specifiers.isSigned && defaultForSuperType.isSigned) - name << "unsigned "; +/** + * Set the underlying type + * + * @return Type + */ +void QualType::setType(const Type &newType) { type = std::make_unique(newType); } - // Loop through all chain elements - type->getName(name, withSize); -} +/** + * Get the super type of the underlying type + * + * @return Super type + */ +SuperType QualType::getSuperType() const { return type->getSuperType(); } /** - * Get the name of the symbol type as a string + * Get the sub type of the underlying type * - * @param withSize Include the array size for sized types - * @param ignorePublic Ignore any potential public specifier - * @return Symbol type name + * @return Sub type */ -std::string QualType::getName(bool withSize, bool ignorePublic) const { - std::stringstream name; - getName(name, withSize, ignorePublic); - return name.str(); -} +const std::string &QualType::getSubType() const { return type->getSubType(); } -bool QualType::is(SuperType superType) const { return type->is(superType); } +/** + * Get the array size of the underlying type + * + * @return Array size + */ +unsigned int QualType::getArraySize() const { return type->getArraySize(); } -bool QualType::isOneOf(const std::initializer_list &superTypes) const { return type->isOneOf(superTypes); } +/** + * Get the body scope of the underlying type + * + * @return Body scope + */ +Scope *QualType::getBodyScope() const { return type->getBodyScope(); } -bool QualType::isBase(SuperType superType) const { return type->isBase(superType); } +/** + * Set the body scope of the underlying type + * + * @param newBodyScope New body scope + */ +void QualType::setBodyScope(Scope *newBodyScope) { type->setBodyScope(newBodyScope); } -QualType QualType::getBase() const { - QualType qualType = *this; - qualType.type = std::make_unique(type->getBase()); - return qualType; -} +/** + * Get the function parameter types of the underlying type + * + * @return Function parameter types + */ +const QualType &QualType::getFunctionReturnType() const { return type->getFunctionReturnType(); } -void QualType::setType(const Type &newType) { type = std::make_unique(newType); } +/** + * Set the function return type of the underlying type + * + * @param returnType New return type + */ +void QualType::setFunctionReturnType(const QualType &returnType) { type->setFunctionReturnType(returnType); } -bool QualType::isConst() const { return specifiers.isConst; } +/** + * Get the function parameter types of the underlying type + * + * @return Function parameter types + */ +QualTypeList QualType::getFunctionParamTypes() const { return type->getFunctionParamTypes(); } -void QualType::makeConst(bool isConst) { specifiers.isConst = isConst; } +/** + * Set the function parameter types of the underlying type + * + * @param paramTypes New parameter types + */ +void QualType::setFunctionParamTypes(const QualTypeList ¶mTypes) { type->setFunctionParamTypes(paramTypes); } -bool QualType::isSigned() const { - assert(isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_BOOL})); - return specifiers.isSigned; -} +/** + * Get the function parameter and return types of the underlying type + * + * @return Function parameter and return types + */ +const QualTypeList &QualType::getFunctionParamAndReturnTypes() const { return type->getFunctionParamAndReturnTypes(); } -void QualType::makeSigned(bool isSigned) { - assert(isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_BOOL})); - specifiers.isSigned = isSigned; +/** + * Set the function parameter and return types of the underlying type + * + * @param paramAndReturnTypes New parameter and return types + */ +void QualType::setFunctionParamAndReturnTypes(const QualTypeList ¶mAndReturnTypes) { + type->setFunctionParamAndReturnTypes(paramAndReturnTypes); } -bool QualType::isUnsigned() const { - assert(isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_BOOL})); - return specifiers.isUnsigned; -} +/** + * Check if the underlying type has lambda captures + * + * @return Has lambda captures or not + */ +bool QualType::hasLambdaCaptures() const { return type->hasLambdaCaptures(); } -void QualType::makeUnsigned(bool isUnsigned) { - assert(isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_BOOL})); - specifiers.isUnsigned = isUnsigned; -} +/** + * Set if the underlying type has lambda captures + * + * @param hasCaptures Has lambda captures or not + */ +void QualType::setHasLambdaCaptures(bool hasCaptures) { type->setHasLambdaCaptures(hasCaptures); } -bool QualType::isInline() const { - assert(isOneOf({TY_FUNCTION, TY_PROCEDURE})); - return specifiers.isInline; -} +/** + * Get the template types of the underlying type + * + * @return Template types + */ +const QualTypeList &QualType::getTemplateTypes() const { return type->getTemplateTypes(); } -void QualType::makeInline(bool isInline) { - assert(isOneOf({TY_FUNCTION, TY_PROCEDURE})); - specifiers.isInline = isInline; -} +/** + * Set the template types of the underlying type + * + * @param templateTypes New template types + */ +void QualType::setTemplateTypes(const QualTypeList &templateTypes) { type->setTemplateTypes(templateTypes); } -bool QualType::isPublic() const { - assert(type->isPrimitive() /* Global variables */ || isOneOf({TY_FUNCTION, TY_PROCEDURE, TY_ENUM, TY_STRUCT, TY_INTERFACE})); - return specifiers.isPublic; +/** + * Set the template types of the underlying base type + * + * @param templateTypes New template types + */ +void QualType::setBaseTemplateTypes(const QualTypeList &templateTypes) { type->setBaseTemplateTypes(templateTypes); } + +/** + * Get the struct instance for a struct type + * + * @param node Accessing AST node + * @return Struct instance + */ +Struct *QualType::getStruct(const ASTNode *node) const { + assert(is(TY_STRUCT)); + Scope *structDefScope = getBodyScope()->parent; + const std::string structName = getSubType(); + const QualTypeList &templateTypes = getTemplateTypes(); + return StructManager::matchStruct(structDefScope, structName, templateTypes, node); } -void QualType::makePublic(bool isPublic) { - assert(type->isPrimitive() /* Global variables */ || isOneOf({TY_FUNCTION, TY_PROCEDURE, TY_ENUM, TY_STRUCT, TY_INTERFACE})); - specifiers.isPublic = isPublic; +/** + * Get the interface instance for an interface type + * + * @param node Accessing AST node + * @return Interface instance + */ +Interface *QualType::getInterface(const ASTNode *node) const { + assert(is(TY_INTERFACE)); + Scope *interfaceDefScope = getBodyScope()->parent; + const std::string structName = getSubType(); + const QualTypeList &templateTypes = getTemplateTypes(); + return InterfaceManager::matchInterface(interfaceDefScope, structName, templateTypes, node); } -bool QualType::isHeap() const { return specifiers.isHeap; } +/** + * Check if the underlying type is of a certain super type + * + * @param superType Super type + * @return Is of super type or not + */ +bool QualType::is(SuperType superType) const { return type->is(superType); } -void QualType::makeHeap(bool isHeap) { specifiers.isHeap = isHeap; } +/** + * Check if the underlying type is one of a list of super types + * + * @param superTypes List of super types + * @return Is one of the super types or not + */ +bool QualType::isOneOf(const std::initializer_list &superTypes) const { return type->isOneOf(superTypes); } -bool QualType::isComposition() const { return specifiers.isComposition; } +/** + * Check if the base type of the underlying type is a certain super type + * + * @param superType Super type + * @return Is base type or not + */ +bool QualType::isBase(SuperType superType) const { return type->isBase(superType); } -void QualType::makeComposition(bool isComposition) { specifiers.isComposition = isComposition; } +/** + * Check if the underlying type is a primitive type + * + * @return Primitive or not + */ +bool QualType::isPrimitive() const { return type->isPrimitive(); } +/** + * Check if the underlying type is a pointer + * + * @return Pointer or not + */ bool QualType::isPtr() const { return type->isPtr(); } +/** + * Check if the underlying type is a pointer to a certain super type + * + * @param superType Super type + * @return Pointer to super type or not + */ bool QualType::isPtrTo(SuperType superType) const { return isPtr() && getContained().is(superType); } +/** + * Check if the underlying type is a reference + * + * @return Reference or not + */ bool QualType::isRef() const { return type->isRef(); } +/** + * Check if the underlying type is a reference to a certain super type + * + * @param superType Super type + * @return Reference to super type or not + */ bool QualType::isRefTo(SuperType superType) const { return isRef() && getContained().is(superType); } +/** + * Check if the underlying type is an array + * + * @return Array or not + */ bool QualType::isArray() const { return type->isArray(); } +/** + * Check if the underlying type is an array of a certain super type + * + * @param superType Super type + * @return Array of super type or not + */ bool QualType::isArrayOf(SuperType superType) const { return isArray() && getContained().is(superType); } +/** + * Check if the underlying type is a const reference + * + * @return Const reference or not + */ bool QualType::isConstRef() const { return isConst() && isRef(); } -SuperType QualType::getSuperType() const { return type->getSuperType(); } +/** + * Check if the current type is an iterator + * + * @param node ASTNode + * @return Iterator or not + */ +bool QualType::isIterator(const ASTNode *node) const { + // The type must be a struct that implements the iterator interface + if (!is(TY_STRUCT)) + return false; -const std::string &QualType::getSubType() const { return type->getSubType(); } + const QualType genericType(TY_GENERIC, "T"); + const Type iteratorType(TY_INTERFACE, IITERATOR_NAME, TYPE_ID_ITERATOR_INTERFACE, {.bodyScope = nullptr}, {genericType}); + const QualType iteratorQualType(iteratorType, TypeSpecifiers::of(TY_INTERFACE)); + return doesImplement(iteratorQualType, node); +} + +/** + * Check if the current type is an iterable + * - Arrays are always considered iterable + * - Otherwise the type must be a struct that implements the iterator interface + * + * @param node ASTNode + * @return Iterable or not + */ +bool QualType::isIterable(const ASTNode *node) const { + // Arrays are always considered iterable + if (isArray()) + return true; + // Otherwise the type must be a struct that implements the iterator interface + if (!is(TY_STRUCT)) + return false; + + const QualType genericType(TY_GENERIC, "T"); + const Type iteratorType(Type(TY_INTERFACE, IITERATOR_NAME, TYPE_ID_ITERABLE_INTERFACE, {.bodyScope = nullptr}, {genericType})); + const QualType iteratorQualType(iteratorType, TypeSpecifiers::of(TY_INTERFACE)); + return doesImplement(iteratorQualType, node); +} +/** + * Check if the current type is a string object + * + * @return String object or not + */ +bool QualType::isStringObj() const { return is(TY_STRUCT) && getSubType() == STROBJ_NAME && getBodyScope()->sourceFile->stdFile; } + +/** + * Check if the current type is a error object + * + * @return Error object or not + */ +bool QualType::isErrorObj() const { return is(TY_STRUCT) && getSubType() == ERROBJ_NAME && getBodyScope()->sourceFile->stdFile; } + +/** + * Check if the current type has any generic parts + * + * @return Generic parts or not + */ bool QualType::hasAnyGenericParts() const { return type->hasAnyGenericParts(); } +/** + * Check if the current type implements the given interface type + * + * @param symbolType Interface type + * @param node ASTNode + * @return Struct implements interface or not + */ +bool QualType::doesImplement(const QualType &symbolType, const ASTNode *node) const { + assert(is(TY_STRUCT) && symbolType.is(TY_INTERFACE)); + const Struct *spiceStruct = getStruct(node); + assert(spiceStruct != nullptr); + return std::ranges::any_of(spiceStruct->interfaceTypes, [&](const QualType &interfaceType) { + assert(interfaceType.is(TY_INTERFACE)); + return symbolType.matches(interfaceType, false, false, true); + }); +} + /** * Check if a certain input type can be bound (assigned) to the current type-> * @@ -168,15 +361,118 @@ bool QualType::canBind(const QualType &inputType, bool isTemporary) const { */ bool QualType::matches(const QualType &otherType, bool ignoreArraySize, bool ignoreSpecifiers, bool allowConstify) const { // Compare type - if (!type->matches(*otherType.type, ignoreArraySize, ignoreSpecifiers, allowConstify)) + if (!type->matches(*otherType.type, ignoreArraySize)) return false; // Ignore or compare specifiers return ignoreSpecifiers || specifiers.match(otherType.specifiers, allowConstify); } +/** + * Check for the matching compatibility of two types in terms of interface implementation. + * Useful for function matching as well as assignment type validation and function arg matching. + * + * @param otherType Type to compare against + * @return Matching or not + */ +bool QualType::matchesInterfaceImplementedByStruct(const QualType &otherType) const { + if (!is(TY_INTERFACE) || !otherType.is(TY_STRUCT)) + return false; + + // Check if the rhs is a struct type that implements the lhs interface type + const Struct *spiceStruct = otherType.getStruct(nullptr); + assert(spiceStruct != nullptr); + const auto pred = [&](const QualType &interfaceType) { return matches(interfaceType, false, false, true); }; + return std::ranges::any_of(spiceStruct->interfaceTypes, pred); +} + +/** + * Check if the current type is the same container type as another type. + * Container types include arrays, pointers, and references. + * + * @param other Other type + * @return Same container type or not + */ bool QualType::isSameContainerTypeAs(const QualType &other) const { return type->isSameContainerTypeAs(*other.type); } +/** + * Check if the given generic type list has a substantiation for the current (generic) type + * + * @param genericTypeList Generic type list + * @return Has substantiation or not + */ +bool QualType::isCoveredByGenericTypeList(std::vector &genericTypeList) const { + const QualType baseType = getBase(); + // Check if the symbol type itself is generic + if (baseType.is(TY_GENERIC)) { + return std::ranges::any_of(genericTypeList, [&](GenericType &t) { + if (baseType.matches(t, true, true, true)) { + t.used = true; + return true; + } + return false; + }); + } + + // If the type is non-generic check template types + bool covered = true; + // Check template types + const QualTypeList &baseTemplateTypes = baseType.getTemplateTypes(); + auto outerPred = [&](const QualType &templateType) { return templateType.isCoveredByGenericTypeList(genericTypeList); }; + covered &= std::ranges::all_of(baseTemplateTypes, outerPred); + + // If function/procedure, check param and return types + if (baseType.isOneOf({TY_FUNCTION, TY_PROCEDURE})) { + const QualTypeList ¶mAndReturnTypes = baseType.getFunctionParamAndReturnTypes(); + const auto innerPred = [&](const QualType ¶mType) { return paramType.isCoveredByGenericTypeList(genericTypeList); }; + covered &= std::ranges::all_of(paramAndReturnTypes, innerPred); + } + + return covered; +} + +/** + * Get the name of the symbol type as a string + * + * @param name Name stream + * @param withSize Include the array size for sized types + * @param ignorePublic Ignore any potential public specifier + */ +void QualType::getName(std::stringstream &name, bool withSize, bool ignorePublic) const { + // Append the specifiers + const TypeSpecifiers defaultForSuperType = TypeSpecifiers::of(getBase().getSuperType()); + if (!ignorePublic && specifiers.isPublic && !defaultForSuperType.isPublic) + name << "public "; + if (specifiers.isInline && !defaultForSuperType.isInline) + name << "inline "; + if (specifiers.isComposition && !defaultForSuperType.isComposition) + name << "compose "; + if (specifiers.isConst && !defaultForSuperType.isConst) + name << "const "; + if (specifiers.isHeap && !defaultForSuperType.isHeap) + name << "heap "; + if (specifiers.isSigned && !defaultForSuperType.isSigned) + name << "signed "; + if (!specifiers.isSigned && defaultForSuperType.isSigned) + name << "unsigned "; + + // Loop through all chain elements + type->getName(name, withSize); +} + +/** + * Get the name of the symbol type as a string + * + * @param withSize Include the array size for sized types + * @param ignorePublic Ignore any potential public specifier + * @return Symbol type name + */ +std::string QualType::getName(bool withSize, bool ignorePublic) const { + std::stringstream name; + getName(name, withSize, ignorePublic); + return name.str(); +} + /** * Convert the type to an LLVM type * @@ -188,46 +484,96 @@ llvm::Type *QualType::toLLVMType(llvm::LLVMContext &context, Scope *accessScope) return type->toLLVMType(context, accessScope); } +/** + * Retrieve the pointer type to this type + * + * @param node ASTNode + * @return New type + */ QualType QualType::toPtr(const ASTNode *node) const { QualType newType = *this; newType.type = std::make_unique(type->toPointer(node)); return newType; } +/** + * Retrieve the reference type to this type + * + * @param node ASTNode + * @return New type + */ QualType QualType::toRef(const ASTNode *node) const { QualType newType = *this; newType.type = std::make_unique(type->toReference(node)); return newType; } +/** + * Retrieve the const reference type of this type + * + * @param node ASTNode + * @return New type + */ +QualType QualType::toConstRef(const ASTNode *node) const { + QualType qualType = toRef(node); + qualType.specifiers.isConst = true; + return qualType; +} + +/** + * Retrieve the array type of this type + * + * @param node ASTNode + * @param size Array size + * @param skipDynCheck Skip dynamic check + * @return New type + */ QualType QualType::toArray(const ASTNode *node, size_t size, bool skipDynCheck /*=false*/) const { QualType newType = *this; newType.type = std::make_unique(type->toArray(node, size, skipDynCheck)); return newType; } +/** + * Retrieve the non-const type of this type + * + * @return New type + */ QualType QualType::toNonConst() const { QualType qualType = *this; qualType.specifiers.isConst = false; return qualType; } -QualType QualType::toConstRef(const ASTNode *node) const { - QualType qualType = toRef(node); - qualType.specifiers.isConst = true; - return qualType; -} - +/** + * Retrieve the contained type of this type + * This works on pointers, arrays, references and strings (which alias with char*) + * + * @return New type + */ QualType QualType::getContained() const { + assert(isOneOf({TY_PTR, TY_ARRAY, TY_REF, TY_STRING})); QualType qualType = *this; qualType.type = std::make_unique(type->getContainedTy()); return qualType; } -bool operator==(const QualType &lhs, const QualType &rhs) { return *lhs.type == *rhs.type; } - -bool operator!=(const QualType &lhs, const QualType &rhs) { return !(lhs == rhs); } +/** + * Retrieve the base type of this type + * + * @return New type + */ +QualType QualType::getBase() const { + QualType qualType = *this; + qualType.type = std::make_unique(type->getBase()); + return qualType; +} +/** + * Remove reference of this type, if it is a reference + * + * @return New type + */ QualType QualType::removeReferenceWrapper() const { return isRef() ? getContained() : *this; } /** @@ -245,6 +591,146 @@ QualType QualType::replaceBaseType(const QualType &newBaseType) const { return {newType, newSpecifiers}; } +/** + * Check if the current type is marked const + * + * @return Is const or not + */ +bool QualType::isConst() const { return specifiers.isConst; } + +/** + * Check if the current type is marked signed + * + * @return Is signed or not + */ +bool QualType::isSigned() const { + assert(isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_BOOL})); + return specifiers.isSigned; +} + +/** + * Check if the current type is marked unsigned + * + * @return Is unsigned or not + */ +bool QualType::isUnsigned() const { + assert(isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_BOOL})); + return specifiers.isUnsigned; +} + +/** + * Check if the current type is marked inline + * + * @return Is inline or not + */ +bool QualType::isInline() const { + assert(isOneOf({TY_FUNCTION, TY_PROCEDURE})); + return specifiers.isInline; +} + +/** + * Check if the current type is marked public + * + * @return Is public or not + */ +bool QualType::isPublic() const { + assert(type->isPrimitive() /* Global variables */ || isOneOf({TY_FUNCTION, TY_PROCEDURE, TY_ENUM, TY_STRUCT, TY_INTERFACE})); + return specifiers.isPublic; +} + +/** + * Check if the current type is marked heap + * + * @return Is heap or not + */ +bool QualType::isHeap() const { return specifiers.isHeap; } + +/** + * Check if the current type is marked as composition + * + * @return Is composition or not + */ +bool QualType::isComposition() const { return specifiers.isComposition; } + +/** + * Make the current type const + * + * @param isConst Is const or not + */ +void QualType::makeConst(bool isConst) { specifiers.isConst = isConst; } + +/** + * Make the current type signed + * + * @param isSigned Is signed or not + */ +void QualType::makeSigned(bool isSigned) { + assert(isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_BOOL})); + specifiers.isSigned = isSigned; +} + +/** + * Make the current type unsigned + * + * @param isUnsigned Is unsigned or not + */ +void QualType::makeUnsigned(bool isUnsigned) { + assert(isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_BOOL})); + specifiers.isUnsigned = isUnsigned; +} + +/** + * Make the current type inline + * + * @param isInline Is inline or not + */ +void QualType::makeInline(bool isInline) { + assert(isOneOf({TY_FUNCTION, TY_PROCEDURE})); + specifiers.isInline = isInline; +} + +/** + * Make the current type public + * + * @param isPublic Is public or not + */ +void QualType::makePublic(bool isPublic) { + assert(type->isPrimitive() /* Global variables */ || isOneOf({TY_FUNCTION, TY_PROCEDURE, TY_ENUM, TY_STRUCT, TY_INTERFACE})); + specifiers.isPublic = isPublic; +} + +/** + * Make the current type heap + * + * @param isHeap Is heap or not + */ +void QualType::makeHeap(bool isHeap) { specifiers.isHeap = isHeap; } + +/** + * Make the current type composition + * + * @param isComposition Is composition or not + */ +void QualType::makeComposition(bool isComposition) { specifiers.isComposition = isComposition; } + +/** + * Check if two types are equal + * + * @param lhs Left-hand side type + * @param rhs Right-hand side type + * @return Equal or not + */ +bool operator==(const QualType &lhs, const QualType &rhs) { return *lhs.type == *rhs.type; } + +/** + * Check if two types are not equal + * + * @param lhs Left-hand side type + * @param rhs Right-hand side type + * @return Not equal or not + */ +bool operator!=(const QualType &lhs, const QualType &rhs) { return !(lhs == rhs); } + /** * Remove pointers / arrays / references if both types have them as far as possible. * Furthermore, remove reference wrappers if possible. diff --git a/src/symboltablebuilder/QualType.h b/src/symboltablebuilder/QualType.h index c2c007142..dfa8b313d 100644 --- a/src/symboltablebuilder/QualType.h +++ b/src/symboltablebuilder/QualType.h @@ -17,8 +17,15 @@ namespace spice::compiler { class Type; class ASTNode; class Scope; +class Struct; +class Interface; +class GenericType; +class QualType; enum SuperType : uint8_t; +// Typedefs +using QualTypeList = std::vector; + class QualType { public: // Constructors @@ -31,38 +38,36 @@ class QualType { QualType(const QualType &other); QualType &operator=(const QualType &other); - // Public methods - void getName(std::stringstream &name, bool withSize = false, bool ignorePublic = false) const; - [[nodiscard]] std::string getName(bool withSize = false, bool ignorePublic = false) const; - [[nodiscard]] bool is(SuperType superType) const; - [[nodiscard]] bool isOneOf(const std::initializer_list &superTypes) const; - [[nodiscard]] bool isBase(SuperType superType) const; - [[nodiscard]] QualType getBase() const; - // Getters and setters on type [[nodiscard]] Type &getType() { return *type; } [[nodiscard]] const Type &getType() const { return *type; } void setType(const Type &newType); - // Getters and setters on specifiers - [[nodiscard]] TypeSpecifiers &getSpecifiers() { return specifiers; } - [[nodiscard]] const TypeSpecifiers &getSpecifiers() const { return specifiers; } - [[nodiscard]] bool isConst() const; - void makeConst(bool isConst = true); - [[nodiscard]] bool isSigned() const; - void makeSigned(bool isSigned = true); - [[nodiscard]] bool isUnsigned() const; - void makeUnsigned(bool isUnsigned = true); - [[nodiscard]] bool isInline() const; - void makeInline(bool isInline = true); - [[nodiscard]] bool isPublic() const; - void makePublic(bool isPublic = true); - [[nodiscard]] bool isHeap() const; - void makeHeap(bool isHeap = true); - [[nodiscard]] bool isComposition() const; - void makeComposition(bool isComposition = true); + // Getters on type parts + [[nodiscard]] SuperType getSuperType() const; + [[nodiscard]] const std::string &getSubType() const; + [[nodiscard]] unsigned int getArraySize() const; + [[nodiscard]] Scope *getBodyScope() const; + void setBodyScope(Scope *newBodyScope); + [[nodiscard]] const QualType &getFunctionReturnType() const; + void setFunctionReturnType(const QualType &returnType); + [[nodiscard]] QualTypeList getFunctionParamTypes() const; + void setFunctionParamTypes(const QualTypeList ¶mTypes); + [[nodiscard]] const QualTypeList &getFunctionParamAndReturnTypes() const; + void setFunctionParamAndReturnTypes(const QualTypeList ¶mAndReturnTypes); + [[nodiscard]] bool hasLambdaCaptures() const; + void setHasLambdaCaptures(bool hasCaptures); + [[nodiscard]] const QualTypeList &getTemplateTypes() const; + void setTemplateTypes(const QualTypeList &templateTypes); + void setBaseTemplateTypes(const QualTypeList &templateTypes); + [[nodiscard]] Struct *getStruct(const ASTNode *node) const; + [[nodiscard]] Interface *getInterface(const ASTNode *node) const; // Queries on the type + [[nodiscard]] bool is(SuperType superType) const; + [[nodiscard]] bool isOneOf(const std::initializer_list &superTypes) const; + [[nodiscard]] bool isBase(SuperType superType) const; + [[nodiscard]] bool isPrimitive() const; [[nodiscard]] bool isPtr() const; [[nodiscard]] bool isPtrTo(SuperType superType) const; [[nodiscard]] bool isRef() const; @@ -70,30 +75,62 @@ class QualType { [[nodiscard]] bool isArray() const; [[nodiscard]] bool isArrayOf(SuperType superType) const; [[nodiscard]] bool isConstRef() const; - [[nodiscard]] SuperType getSuperType() const; - [[nodiscard]] const std::string &getSubType() const; + [[nodiscard]] bool isIterator(const ASTNode *node) const; + [[nodiscard]] bool isIterable(const ASTNode *node) const; + [[nodiscard]] bool isStringObj() const; + [[nodiscard]] bool isErrorObj() const; [[nodiscard]] bool hasAnyGenericParts() const; + + // Complex queries on the type + [[nodiscard]] bool doesImplement(const QualType &symbolType, const ASTNode *node) const; [[nodiscard]] bool canBind(const QualType &otherType, bool isTemporary) const; [[nodiscard]] bool matches(const QualType &otherType, bool ignoreArraySize, bool ignoreSpecifiers, bool allowConstify) const; + [[nodiscard]] bool matchesInterfaceImplementedByStruct(const QualType &otherType) const; [[nodiscard]] bool isSameContainerTypeAs(const QualType &other) const; + [[nodiscard]] bool isCoveredByGenericTypeList(std::vector &genericTypeList) const; + + // Serialization + void getName(std::stringstream &name, bool withSize = false, bool ignorePublic = false) const; + [[nodiscard]] std::string getName(bool withSize = false, bool ignorePublic = false) const; + + // LLVM helpers [[nodiscard]] llvm::Type *toLLVMType(llvm::LLVMContext &context, Scope *accessScope) const; // Get new type, based on this one [[nodiscard]] QualType toPtr(const ASTNode *node) const; [[nodiscard]] QualType toRef(const ASTNode *node) const; + [[nodiscard]] QualType toConstRef(const ASTNode *node) const; [[nodiscard]] QualType toArray(const ASTNode *node, size_t size, bool skipDynCheck = false) const; [[nodiscard]] QualType toNonConst() const; - [[nodiscard]] QualType toConstRef(const ASTNode *node) const; [[nodiscard]] QualType getContained() const; + [[nodiscard]] QualType getBase() const; + [[nodiscard]] QualType removeReferenceWrapper() const; + [[nodiscard]] QualType replaceBaseType(const QualType &newBaseType) const; + + // Getters on specifiers + [[nodiscard]] TypeSpecifiers &getSpecifiers() { return specifiers; } + [[nodiscard]] const TypeSpecifiers &getSpecifiers() const { return specifiers; } + + // Getters and setters on specifier parts + [[nodiscard]] bool isConst() const; + [[nodiscard]] bool isSigned() const; + [[nodiscard]] bool isUnsigned() const; + [[nodiscard]] bool isInline() const; + [[nodiscard]] bool isPublic() const; + [[nodiscard]] bool isHeap() const; + [[nodiscard]] bool isComposition() const; + void makeConst(bool isConst = true); + void makeSigned(bool isSigned = true); + void makeUnsigned(bool isUnsigned = true); + void makeInline(bool isInline = true); + void makePublic(bool isPublic = true); + void makeHeap(bool isHeap = true); + void makeComposition(bool isComposition = true); // Overloaded operators friend bool operator==(const QualType &lhs, const QualType &rhs); friend bool operator!=(const QualType &lhs, const QualType &rhs); - // Modify the type - [[nodiscard]] QualType removeReferenceWrapper() const; - [[nodiscard]] QualType replaceBaseType(const QualType &newBaseType) const; - // Public static methods static void unwrapBoth(QualType &typeA, QualType &typeB); diff --git a/src/symboltablebuilder/Scope.cpp b/src/symboltablebuilder/Scope.cpp index 1b8b50b58..b25bf32bb 100644 --- a/src/symboltablebuilder/Scope.cpp +++ b/src/symboltablebuilder/Scope.cpp @@ -150,7 +150,7 @@ void Scope::collectWarnings(std::vector &warnings) const { // N switch (entry.getQualType().getSuperType()) { case TY_FUNCTION: { // Skip generic function entries - if (!entry.getQualType().getType().getTemplateTypes().empty()) + if (!entry.getQualType().getTemplateTypes().empty()) continue; if (type == ScopeType::GLOBAL) { @@ -170,7 +170,7 @@ void Scope::collectWarnings(std::vector &warnings) const { // N } case TY_PROCEDURE: { // Skip generic procedure entries - if (!entry.getQualType().getType().getTemplateTypes().empty()) + if (!entry.getQualType().getTemplateTypes().empty()) continue; if (type == ScopeType::GLOBAL) { @@ -195,7 +195,7 @@ void Scope::collectWarnings(std::vector &warnings) const { // N case TY_STRUCT: { if (entry.scope->type == ScopeType::GLOBAL) { // Skip generic struct entries - if (!entry.getQualType().getType().getTemplateTypes().empty()) + if (!entry.getQualType().getTemplateTypes().empty()) continue; warningType = UNUSED_STRUCT; @@ -209,7 +209,7 @@ void Scope::collectWarnings(std::vector &warnings) const { // N case TY_INTERFACE: { if (entry.scope->type == ScopeType::GLOBAL) { // Skip generic struct entries - if (!entry.getQualType().getType().getTemplateTypes().empty()) + if (!entry.getQualType().getTemplateTypes().empty()) continue; warningType = UNUSED_INTERFACE; @@ -276,7 +276,7 @@ void Scope::collectWarnings(std::vector &warnings) const { // N void Scope::ensureSuccessfulTypeInference() const { // NOLINT(misc-no-recursion) // Check symbols in this scope for (auto &[name, entry] : symbolTable.symbols) - if (entry.getQualType().getType().is(TY_DYN)) + if (entry.getQualType().is(TY_DYN)) throw SemanticError(entry.declNode, UNEXPECTED_DYN_TYPE, "For the variable '" + name + "' no type could be inferred"); // Check child scopes diff --git a/src/symboltablebuilder/SymbolTable.cpp b/src/symboltablebuilder/SymbolTable.cpp index 9c4457429..71ed5c405 100644 --- a/src/symboltablebuilder/SymbolTable.cpp +++ b/src/symboltablebuilder/SymbolTable.cpp @@ -157,7 +157,7 @@ SymbolTableEntry *SymbolTable::lookupInComposedFields(const std::string &name, / indexPath.push_back(fieldEntry->orderIndex); // Search in the composed field's body scope - Scope *searchScope = fieldEntry->getQualType().getType().getBodyScope(); + Scope *searchScope = fieldEntry->getQualType().getBodyScope(); assert(searchScope != nullptr); if (SymbolTableEntry *result = searchScope->symbolTable.lookupInComposedFields(name, indexPath)) return result; diff --git a/src/symboltablebuilder/SymbolTableEntry.h b/src/symboltablebuilder/SymbolTableEntry.h index beaf66fe6..36b416ee0 100644 --- a/src/symboltablebuilder/SymbolTableEntry.h +++ b/src/symboltablebuilder/SymbolTableEntry.h @@ -29,9 +29,9 @@ union CompileTimeValue; class SymbolTableEntry { public: // Constructors - SymbolTableEntry(std::string name, const QualType& qualType, Scope *scope, ASTNode *declNode, size_t orderIndex, const bool global) - : name(std::move(name)), scope(scope), declNode(declNode), orderIndex(orderIndex), global(global), - qualType(qualType){}; + SymbolTableEntry(std::string name, const QualType &qualType, Scope *scope, ASTNode *declNode, size_t orderIndex, + const bool global) + : name(std::move(name)), scope(scope), declNode(declNode), orderIndex(orderIndex), global(global), qualType(qualType){}; // Public methods [[nodiscard]] const QualType &getQualType() const; diff --git a/src/symboltablebuilder/Type.cpp b/src/symboltablebuilder/Type.cpp index b949a085f..006546805 100644 --- a/src/symboltablebuilder/Type.cpp +++ b/src/symboltablebuilder/Type.cpp @@ -23,11 +23,61 @@ Type::Type(SuperType superType) : typeChain({TypeChainElement{superType}}) {} Type::Type(SuperType superType, const std::string &subType) : typeChain({TypeChainElement{superType, subType}}) {} Type::Type(SuperType superType, const std::string &subType, uint64_t typeId, const Type::TypeChainElementData &data, - const std::vector &templateTypes) + const QualTypeList &templateTypes) : typeChain({TypeChainElement(superType, subType, typeId, data, templateTypes)}) {} Type::Type(TypeChain types) : typeChain(std::move(types)) {} +/** + * Get the super type of the current type + * + * @return Super type + */ +SuperType Type::getSuperType() const { + assert(!typeChain.empty()); + return typeChain.back().superType; +} + +/** + * Get the sub type of the current type + * + * @return Sub type + */ +const std::string &Type::getSubType() const { + assert(isOneOf({TY_STRUCT, TY_INTERFACE, TY_ENUM, TY_GENERIC})); + return typeChain.back().subType; +} + +/** + * Get the array size of the current type + * + * @return Array size + */ +unsigned int Type::getArraySize() const { + assert(getSuperType() == TY_ARRAY); + return typeChain.back().data.arraySize; +} + +/** + * Get the body scope of the current type + * + * @return Body scope + */ +Scope *Type::getBodyScope() const { + assert(isOneOf({TY_STRUCT, TY_INTERFACE})); + return typeChain.back().data.bodyScope; +} + +/** + * Set the body scope of the current type + * + * @param bodyScope Body scope + */ +void Type::setBodyScope(Scope *bodyScope) { + assert(isOneOf({TY_STRUCT, TY_INTERFACE})); + typeChain.back().data.bodyScope = bodyScope; +} + /** * Get the pointer type of the current type as a new type * @@ -217,6 +267,13 @@ const Type *Type::replaceBase(const Type &newBaseType) const { return TypeRegistry::getOrInsert(newType); } +/** + * Remove reference wrapper from the current type + * + * @return Type without reference wrapper + */ +Type Type::removeReferenceWrapper() const { return isRef() ? getContainedTy() : *this; } + /** * Return the LLVM type for this symbol type * @@ -261,7 +318,7 @@ llvm::Type *Type::toLLVMType(llvm::LLVMContext &context, Scope *accessScope) con std::vector fieldTypes; bool isPacked = false; if (is(TY_STRUCT)) { // Struct - Struct *spiceStruct = structSymbol->getQualType().getType().getStruct(structSymbol->declNode); + Struct *spiceStruct = structSymbol->getQualType().getStruct(structSymbol->declNode); assert(spiceStruct != nullptr); const std::string mangledName = NameMangling::mangleStruct(*spiceStruct); structType = llvm::StructType::create(context, mangledName); @@ -287,7 +344,7 @@ llvm::Type *Type::toLLVMType(llvm::LLVMContext &context, Scope *accessScope) con if (structDeclNode->attrs() && structDeclNode->attrs()->attrLst()->hasAttr(ATTR_CORE_COMPILER_PACKED)) isPacked = structDeclNode->attrs()->attrLst()->getAttrValueByName(ATTR_CORE_COMPILER_PACKED)->boolValue; } else { // Interface - Interface *spiceInterface = structSymbol->getQualType().getType().getInterface(structSymbol->declNode); + Interface *spiceInterface = structSymbol->getQualType().getInterface(structSymbol->declNode); assert(spiceInterface != nullptr); const std::string mangledName = NameMangling::mangleInterface(*spiceInterface); structType = llvm::StructType::create(context, mangledName); @@ -323,78 +380,43 @@ llvm::Type *Type::toLLVMType(llvm::LLVMContext &context, Scope *accessScope) con } /** - * Check if the current type is an iterator - * - * @param node ASTNode - * @return Iterator or not - */ -bool Type::isIterator(const ASTNode *node) const { - if (!is(TY_STRUCT)) - return false; - const QualType genericType(TY_GENERIC, "T"); - const Type iteratorType(TY_INTERFACE, IITERATOR_NAME, TYPE_ID_ITERATOR_INTERFACE, {.bodyScope = nullptr}, {genericType}); - return implements(iteratorType, node); -} - -/** - * Check if the current type is an iterable - * - Arrays are always considered iterable - * - Otherwise the type must be a struct that implements the iterator interface + * Check if the base type of the current type chain is of a certain super type * - * @param node ASTNode - * @return Iterable or not + * @param superType Super type to check for + * @return Applicable or not */ -bool Type::isIterable(const ASTNode *node) const { - if (isArray()) - return true; // Arrays are always considered iterable - if (!is(TY_STRUCT)) - return false; - const QualType genericType(TY_GENERIC, "T"); - const Type iteratorType(TY_INTERFACE, IITERATOR_NAME, TYPE_ID_ITERABLE_INTERFACE, {.bodyScope = nullptr}, {genericType}); - return implements(iteratorType, node); +bool Type::isBase(SuperType superType) const { + assert(!typeChain.empty()); + return typeChain.front().superType == superType; } /** - * Check if the current type is a string object + * Check if the current type is a primitive type * - * @return String object or not + * @return Primitive type or not */ -bool Type::isStringObj() const { return is(TY_STRUCT) && getSubType() == STROBJ_NAME && getBodyScope()->sourceFile->stdFile; } +bool Type::isPrimitive() const { return isOneOf({TY_DOUBLE, TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_STRING, TY_BOOL}); } /** - * Check if the current type is a error object + * Check if the current type is a pointer type * - * @return Error object or not + * @return Pointer type or not */ -bool Type::isErrorObj() const { return is(TY_STRUCT) && getSubType() == ERROBJ_NAME && getBodyScope()->sourceFile->stdFile; } +bool Type::isPtr() const { return getSuperType() == TY_PTR; } /** - * Check if the current type implements the given interface type + * Check if the current type is a reference type * - * @param symbolType Interface type - * @param node ASTNode - * @return Struct implements interface or not + * @return Reference type or not */ -bool Type::implements(const Type &symbolType, const ASTNode *node) const { - assert(is(TY_STRUCT) && symbolType.is(TY_INTERFACE)); - Struct *spiceStruct = getStruct(node); - assert(spiceStruct != nullptr); - return std::ranges::any_of(spiceStruct->interfaceTypes, [&](const QualType &interfaceType) { - assert(interfaceType.is(TY_INTERFACE)); - return symbolType.matches(interfaceType.getType(), false, false, true); - }); -} +bool Type::isRef() const { return getSuperType() == TY_REF; } /** - * Check if the base type of the current type chain is of a certain super type + * Check if the current type is an array type * - * @param superType Super type to check for - * @return Applicable or not + * @return Array type or not */ -bool Type::isBase(SuperType superType) const { - assert(!typeChain.empty()); - return typeChain.front().superType == superType; -} +bool Type::isArray() const { return getSuperType() == TY_ARRAY; } /** * Check if the current type is of the same container type like the other type. @@ -450,61 +472,40 @@ bool Type::hasAnyGenericParts() const { // NOLINT(misc-no-recursion) /** * Set the list of templates types */ -void Type::setTemplateTypes(const std::vector &templateTypes) { +void Type::setTemplateTypes(const QualTypeList &templateTypes) { assert(isOneOf({TY_STRUCT, TY_INTERFACE})); typeChain.back().templateTypes = templateTypes; } +/** + * Retrieve template types of the current type + * + * @return Vector of template types + */ +const QualTypeList &Type::getTemplateTypes() const { return typeChain.back().templateTypes; } + /** * Set the list of templates types of the base type */ -void Type::setBaseTemplateTypes(const std::vector &templateTypes) { +void Type::setBaseTemplateTypes(const QualTypeList &templateTypes) { assert(getBase().isOneOf({TY_STRUCT, TY_INTERFACE})); typeChain.front().templateTypes = templateTypes; } /** - * Retrieve template types of the current type + * Check if the current type is of a certain super type * - * @return Vector of template types + * @return Applicable or not */ -const std::vector &Type::getTemplateTypes() const { return typeChain.back().templateTypes; } +bool Type::is(SuperType superType) const { return getSuperType() == superType; } /** - * Check if the given generic type list has a substantiation for the current (generic) type + * Check if the current type is one of a list of super types * - * @param genericTypeList Generic type list - * @return Has substantiation or not + * @return Applicable or not */ -bool Type::isCoveredByGenericTypeList(std::vector &genericTypeList) const { - const Type baseType = getBase(); - // Check if the symbol type itself is generic - if (baseType.is(TY_GENERIC)) { - return std::ranges::any_of(genericTypeList, [&](GenericType &t) { - if (baseType.matches(t.getType(), true, true, true)) { - t.used = true; - return true; - } - return false; - }); - } - - // If the type is non-generic check template types - bool covered = true; - // Check template types - const std::vector &baseTemplateTypes = baseType.getTemplateTypes(); - auto lambda = [&](const QualType &templateType) { return templateType.getType().isCoveredByGenericTypeList(genericTypeList); }; - covered &= std::ranges::all_of(baseTemplateTypes, lambda); - - // If function/procedure, check param and return types - if (baseType.isOneOf({TY_FUNCTION, TY_PROCEDURE})) { - const std::vector ¶mAndReturnTypes = baseType.getFunctionParamAndReturnTypes(); - covered &= std::ranges::all_of(paramAndReturnTypes, [&](const QualType ¶mType) { - return paramType.getType().isCoveredByGenericTypeList(genericTypeList); - }); - } - - return covered; +bool Type::isOneOf(const std::initializer_list &superTypes) const { + return std::ranges::any_of(superTypes, [this](SuperType superType) { return is(superType); }); } /** @@ -532,19 +533,6 @@ std::string Type::getName(bool withSize) const { return name.str(); } -/** - * Set the return type of a function type - * - * @param returnType Function return type - */ -void Type::setFunctionReturnType(const QualType &returnType) { - assert(is(TY_FUNCTION)); - std::vector ¶mTypes = typeChain.back().paramTypes; - if (paramTypes.empty()) - paramTypes.resize(1); - paramTypes.at(0) = returnType; -} - /** * Get the return type of a function type * @@ -557,19 +545,16 @@ const QualType &Type::getFunctionReturnType() const { } /** - * Set the param types of a function or procedure type + * Set the return type of a function type * - * @param paramTypes Function param types + * @param returnType Function return type */ -void Type::setFunctionParamTypes(const std::vector &newParamTypes) { - assert(isOneOf({TY_FUNCTION, TY_PROCEDURE})); - std::vector ¶mTypes = typeChain.back().paramTypes; - // Resize param types if required - if (paramTypes.size() < newParamTypes.size() + 1) - paramTypes.resize(newParamTypes.size() + 1, QualType(TY_DYN)); - // Set the function param types - for (size_t i = 0; i < newParamTypes.size(); i++) - paramTypes.at(i + 1) = newParamTypes.at(i); +void Type::setFunctionReturnType(const QualType &returnType) { + assert(is(TY_FUNCTION)); + QualTypeList ¶mTypes = typeChain.back().paramTypes; + if (paramTypes.empty()) + paramTypes.resize(1); + paramTypes.at(0) = returnType; } /** @@ -577,7 +562,7 @@ void Type::setFunctionParamTypes(const std::vector &newParamTypes) { * * @return Function param types */ -std::vector Type::getFunctionParamTypes() const { +QualTypeList Type::getFunctionParamTypes() const { assert(isOneOf({TY_FUNCTION, TY_PROCEDURE})); if (typeChain.back().paramTypes.empty()) return {}; @@ -585,13 +570,19 @@ std::vector Type::getFunctionParamTypes() const { } /** - * Set has captures of a function or procedure type + * Set the param types of a function or procedure type * - * @param hasCaptures Has captures + * @param paramTypes Function param types */ -void Type::setHasLambdaCaptures(bool hasCaptures) { - assert(getBase().isOneOf({TY_FUNCTION, TY_PROCEDURE})); - typeChain.front().data.hasCaptures = hasCaptures; +void Type::setFunctionParamTypes(const QualTypeList &newParamTypes) { + assert(isOneOf({TY_FUNCTION, TY_PROCEDURE})); + QualTypeList ¶mTypes = typeChain.back().paramTypes; + // Resize param types if required + if (paramTypes.size() < newParamTypes.size() + 1) + paramTypes.resize(newParamTypes.size() + 1, QualType(TY_DYN)); + // Set the function param types + for (size_t i = 0; i < newParamTypes.size(); i++) + paramTypes.at(i + 1) = newParamTypes.at(i); } /** @@ -605,13 +596,13 @@ bool Type::hasLambdaCaptures() const { } /** - * Set the param and return types of a function or procedure base type + * Set has captures of a function or procedure type * - * @param newParamAndReturnTypes Function param and return types (first is return type, rest are param types) + * @param hasCaptures Has captures */ -void Type::setFunctionParamAndReturnTypes(const std::vector &newParamAndReturnTypes) { +void Type::setHasLambdaCaptures(bool hasCaptures) { assert(getBase().isOneOf({TY_FUNCTION, TY_PROCEDURE})); - typeChain.front().paramTypes = newParamAndReturnTypes; + typeChain.front().data.hasCaptures = hasCaptures; } /** @@ -619,37 +610,19 @@ void Type::setFunctionParamAndReturnTypes(const std::vector &newParamA * * @return Function param and return types (first is return type, rest are param types) */ -const std::vector &Type::getFunctionParamAndReturnTypes() const { +const QualTypeList &Type::getFunctionParamAndReturnTypes() const { assert(getBase().isOneOf({TY_FUNCTION, TY_PROCEDURE})); return typeChain.front().paramTypes; } /** - * Get the struct instance for a struct type - * - * @param node Accessing AST node - * @return Struct instance - */ -Struct *Type::getStruct(const ASTNode *node) const { - assert(is(TY_STRUCT)); - Scope *structDefScope = getBodyScope()->parent; - const std::string structName = getSubType(); - const std::vector &templateTypes = getTemplateTypes(); - return StructManager::matchStruct(structDefScope, structName, templateTypes, node); -} - -/** - * Get the interface instance for an interface type + * Set the param and return types of a function or procedure base type * - * @param node Accessing AST node - * @return Interface instance + * @param newParamAndReturnTypes Function param and return types (first is return type, rest are param types) */ -Interface *Type::getInterface(const ASTNode *node) const { - assert(is(TY_INTERFACE)); - Scope *interfaceDefScope = getBodyScope()->parent; - const std::string structName = getSubType(); - const std::vector &templateTypes = getTemplateTypes(); - return InterfaceManager::matchInterface(interfaceDefScope, structName, templateTypes, node); +void Type::setFunctionParamAndReturnTypes(const QualTypeList &newParamAndReturnTypes) { + assert(getBase().isOneOf({TY_FUNCTION, TY_PROCEDURE})); + typeChain.front().paramTypes = newParamAndReturnTypes; } bool operator==(const Type &lhs, const Type &rhs) { return lhs.typeChain == rhs.typeChain; } @@ -662,11 +635,9 @@ bool operator!=(const Type &lhs, const Type &rhs) { return !(lhs == rhs); } * * @param otherType Type to compare against * @param ignoreArraySize Ignore array sizes - * @param ignoreSpecifiers Ignore specifiers, except for pointer and reference types - * @param allowConstify Match when the types are the same, but the lhs type is more const restrictive than the rhs type * @return Matching or not */ -bool Type::matches(const Type &otherType, bool ignoreArraySize, bool ignoreSpecifiers, bool allowConstify) const { +bool Type::matches(const Type &otherType, bool ignoreArraySize) const { // If the size does not match, it is not equal if (typeChain.size() != otherType.typeChain.size()) return false; @@ -689,24 +660,6 @@ bool Type::matches(const Type &otherType, bool ignoreArraySize, bool ignoreSpeci return true; } -/** - * Check for the matching compatibility of two types in terms of interface implementation. - * Useful for function matching as well as assignment type validation and function arg matching. - * - * @param otherType Type to compare against - * @return Matching or not - */ -bool Type::matchesInterfaceImplementedByStruct(const Type &otherType) const { - if (!is(TY_INTERFACE) || !otherType.is(TY_STRUCT)) - return false; - - // Check if the rhs is a struct type that implements the lhs interface type - const Struct *spiceStruct = otherType.getStruct(nullptr); - assert(spiceStruct != nullptr); - const auto pred = [&](const QualType &interfaceType) { return matches(interfaceType.getType(), false, false, true); }; - return std::ranges::any_of(spiceStruct->interfaceTypes, pred); -} - /** * Remove pointers / arrays / references if both types have them as far as possible. * Furthermore, remove reference wrappers if possible. diff --git a/src/symboltablebuilder/Type.h b/src/symboltablebuilder/Type.h index ea2e84f5d..8c6f39db6 100644 --- a/src/symboltablebuilder/Type.h +++ b/src/symboltablebuilder/Type.h @@ -73,10 +73,9 @@ class Type { explicit TypeChainElement(SuperType superType) : superType(superType), typeId(superType){}; TypeChainElement(SuperType superType, std::string subType) : superType(superType), subType(std::move(subType)), typeId(superType){}; - TypeChainElement(SuperType superType, TypeChainElementData data) - : superType(superType), typeId(superType), data(data){}; + TypeChainElement(SuperType superType, TypeChainElementData data) : superType(superType), typeId(superType), data(data){}; TypeChainElement(SuperType superType, std::string subType, uint64_t typeId, TypeChainElementData data, - const std::vector &templateTypes) + const QualTypeList &templateTypes) : superType(superType), subType(std::move(subType)), typeId(typeId), data(data), templateTypes(templateTypes){}; // Overloaded operators @@ -90,8 +89,8 @@ class Type { std::string subType; uint64_t typeId = TY_INVALID; TypeChainElementData data = {.arraySize = 0}; - std::vector templateTypes; - std::vector paramTypes; // First type is the return type + QualTypeList templateTypes; + QualTypeList paramTypes; // First type is the return type }; // Make sure we have no unexpected increases in memory consumption @@ -105,9 +104,48 @@ class Type { explicit Type(TypeChain types); Type(SuperType superType, const std::string &subType); Type(SuperType superType, const std::string &subType, uint64_t typeId, const TypeChainElementData &data, - const std::vector &templateTypes); + const QualTypeList &templateTypes); + + // Getters and setters on type parts + [[nodiscard]] SuperType getSuperType() const; + [[nodiscard]] const std::string &getSubType() const; + [[nodiscard]] unsigned int getArraySize() const; + [[nodiscard]] Scope *getBodyScope() const; + void setBodyScope(Scope *bodyScope); + [[nodiscard]] const QualType &getFunctionReturnType() const; + void setFunctionReturnType(const QualType &returnType); + [[nodiscard]] QualTypeList getFunctionParamTypes() const; + void setFunctionParamTypes(const QualTypeList ¶mTypes); + [[nodiscard]] const QualTypeList &getFunctionParamAndReturnTypes() const; + void setFunctionParamAndReturnTypes(const QualTypeList ¶mAndReturnTypes); + [[nodiscard]] bool hasLambdaCaptures() const; + void setHasLambdaCaptures(bool hasCaptures); + [[nodiscard]] const QualTypeList &getTemplateTypes() const; + void setTemplateTypes(const QualTypeList &templateTypes); + void setBaseTemplateTypes(const QualTypeList &templateTypes); + + // Queries on the type + [[nodiscard]] bool is(SuperType superType) const; + [[nodiscard]] bool isOneOf(const std::initializer_list &superTypes) const; + [[nodiscard]] bool isBase(SuperType superType) const; + [[nodiscard]] bool isPrimitive() const; + [[nodiscard]] bool isPtr() const; + [[nodiscard]] bool isRef() const; + [[nodiscard]] bool isArray() const; + [[nodiscard]] bool hasAnyGenericParts() const; - // Public methods + // Complex queries on the type + [[nodiscard]] bool isSameContainerTypeAs(const Type &other) const; + [[nodiscard]] bool matches(const Type &otherType, bool ignoreArraySize) const; + + // Serialization + void getName(std::stringstream &name, bool withSize = false) const; + [[nodiscard]] std::string getName(bool withSize = false) const; + + // LLVM helpers + [[nodiscard]] llvm::Type *toLLVMType(llvm::LLVMContext &context, Scope *accessScope) const; + + // Get new type, based on this one [[nodiscard]] [[deprecated]] Type toPointer(const ASTNode *node) const; [[nodiscard]] const Type *toPtr(const ASTNode *node) const; [[nodiscard]] [[deprecated]] Type toReference(const ASTNode *node) const; @@ -118,70 +156,14 @@ class Type { [[nodiscard]] const Type *getContained() const; [[nodiscard]] [[deprecated]] Type replaceBaseType(const Type &newBaseType) const; [[nodiscard]] const Type *replaceBase(const Type &newBaseType) const; - [[nodiscard]] llvm::Type *toLLVMType(llvm::LLVMContext &context, Scope *accessScope) const; - [[nodiscard]] ALWAYS_INLINE bool isPtr() const { return getSuperType() == TY_PTR; } - [[nodiscard]] ALWAYS_INLINE bool isRef() const { return getSuperType() == TY_REF; } - [[nodiscard]] ALWAYS_INLINE bool isArray() const { return getSuperType() == TY_ARRAY; } - [[nodiscard]] ALWAYS_INLINE bool is(SuperType superType) const { return getSuperType() == superType; } - [[nodiscard]] ALWAYS_INLINE bool isPrimitive() const { - return isOneOf({TY_DOUBLE, TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_STRING, TY_BOOL}); - } - [[nodiscard]] bool isIterator(const ASTNode *node) const; - [[nodiscard]] bool isIterable(const ASTNode *node) const; - [[nodiscard]] bool isStringObj() const; - [[nodiscard]] bool isErrorObj() const; - [[nodiscard]] bool implements(const Type &symbolType, const ASTNode *node) const; - [[nodiscard]] bool isBase(SuperType superType) const; - [[nodiscard]] ALWAYS_INLINE bool isOneOf(const std::initializer_list &superTypes) const { - const SuperType superType = getSuperType(); - return std::ranges::any_of(superTypes, [&superType](SuperType type) { return type == superType; }); - } - [[nodiscard]] bool isSameContainerTypeAs(const Type &other) const; - [[nodiscard]] ALWAYS_INLINE SuperType getSuperType() const { - assert(!typeChain.empty()); - return typeChain.back().superType; - } - [[nodiscard]] ALWAYS_INLINE const std::string &getSubType() const { - assert(isOneOf({TY_STRUCT, TY_INTERFACE, TY_ENUM, TY_GENERIC})); - return typeChain.back().subType; - } - [[nodiscard]] ALWAYS_INLINE Type removeReferenceWrapper() const { return isRef() ? getContainedTy() : *this; } + [[nodiscard]] Type removeReferenceWrapper() const; [[nodiscard]] Type getBase() const; - [[nodiscard]] bool hasAnyGenericParts() const; - void setTemplateTypes(const std::vector &templateTypes); - void setBaseTemplateTypes(const std::vector &templateTypes); - [[nodiscard]] const std::vector &getTemplateTypes() const; - [[nodiscard]] bool isCoveredByGenericTypeList(std::vector &genericTypeList) const; - void getName(std::stringstream &name, bool withSize = false) const; - [[nodiscard]] std::string getName(bool withSize = false) const; - [[nodiscard]] ALWAYS_INLINE unsigned int getArraySize() const { - assert(getSuperType() == TY_ARRAY); - return typeChain.back().data.arraySize; - } - ALWAYS_INLINE void setBodyScope(Scope *bodyScope) { - assert(isOneOf({TY_STRUCT, TY_INTERFACE})); - typeChain.back().data.bodyScope = bodyScope; - } - [[nodiscard]] ALWAYS_INLINE Scope *getBodyScope() const { - assert(isOneOf({TY_STRUCT, TY_INTERFACE})); - return typeChain.back().data.bodyScope; - } - void setFunctionReturnType(const QualType &returnType); - [[nodiscard]] const QualType &getFunctionReturnType() const; - void setFunctionParamTypes(const std::vector ¶mTypes); - [[nodiscard]] std::vector getFunctionParamTypes() const; - void setFunctionParamAndReturnTypes(const std::vector ¶mAndReturnTypes); - [[nodiscard]] const std::vector &getFunctionParamAndReturnTypes() const; - void setHasLambdaCaptures(bool hasCaptures); - [[nodiscard]] bool hasLambdaCaptures() const; - Struct *getStruct(const ASTNode *node) const; - [[nodiscard]] Interface *getInterface(const ASTNode *node) const; + + // Overloaded operators friend bool operator==(const Type &lhs, const Type &rhs); friend bool operator!=(const Type &lhs, const Type &rhs); - [[nodiscard]] bool matches(const Type &otherType, bool ignoreArraySize, bool ignoreSpecifiers, bool allowConstify) const; - [[nodiscard]] bool matchesInterfaceImplementedByStruct(const Type &otherType) const; - // Static util methods + // Public static methods static void unwrapBoth(Type &typeA, Type &typeB); // Public members diff --git a/src/symboltablebuilder/TypeChain.cpp b/src/symboltablebuilder/TypeChain.cpp index e3714a13f..1baa9495e 100644 --- a/src/symboltablebuilder/TypeChain.cpp +++ b/src/symboltablebuilder/TypeChain.cpp @@ -132,7 +132,7 @@ void Type::TypeChainElement::getName(std::stringstream &name, bool withSize) con case TY_IMPORT: name << "import"; break; - case TY_INVALID: // GCOV_EXCL_LINE + case TY_INVALID: // GCOV_EXCL_LINE name << "invalid"; // GCOV_EXCL_LINE break; default: diff --git a/src/typechecker/FunctionManager.cpp b/src/typechecker/FunctionManager.cpp index 142432dac..febf0cc63 100644 --- a/src/typechecker/FunctionManager.cpp +++ b/src/typechecker/FunctionManager.cpp @@ -95,8 +95,7 @@ void FunctionManager::substantiateOptionalParams(const Function &baseFunction, s manifestations.push_back(baseFunction); } -Function FunctionManager::createMainFunction(SymbolTableEntry *entry, const std::vector ¶mTypes, - ASTNode *declNode) { +Function FunctionManager::createMainFunction(SymbolTableEntry *entry, const QualTypeList ¶mTypes, ASTNode *declNode) { ParamList paramList; for (const QualType ¶mType : paramTypes) paramList.push_back({paramType, false}); @@ -190,7 +189,7 @@ const Function *FunctionManager::lookupFunction(Scope *matchScope, const std::st * @return Matched function or nullptr */ Function *FunctionManager::matchFunction(Scope *matchScope, const std::string &reqName, const QualType &reqThisType, - const ArgList &reqArgs, const std::vector &templateTypeHints, + const ArgList &reqArgs, const QualTypeList &templateTypeHints, bool strictSpecifierMatching, const ASTNode *callNode) { assert(reqThisType.isOneOf({TY_DYN, TY_STRUCT, TY_INTERFACE})); @@ -325,13 +324,12 @@ MatchResult FunctionManager::matchManifestation(Function &candidate, Scope *&mat // If we only have the generic struct scope, lookup the concrete manifestation scope if (matchScope->isGenericScope) { const std::string structName = thisType.getSubType(); - Scope *scope = thisType.getType().getBodyScope()->parent; - Struct *spiceStruct = - StructManager::matchStruct(scope, structName, thisType.getType().getTemplateTypes(), candidate.declNode); + Scope *scope = thisType.getBodyScope()->parent; + Struct *spiceStruct = StructManager::matchStruct(scope, structName, thisType.getTemplateTypes(), candidate.declNode); assert(spiceStruct != nullptr); matchScope = spiceStruct->scope; } - candidate.thisType.getType().setBodyScope(matchScope); + candidate.thisType.setBodyScope(matchScope); } return MatchResult::MATCHED; @@ -429,8 +427,8 @@ bool FunctionManager::matchArgTypes(Function &candidate, const ArgList &reqArgs, } // If we have a function/procedure type we need to take care of the information, if it takes captures - if (requestedType.getBase().isOneOf({TY_FUNCTION, TY_PROCEDURE}) && requestedType.getType().hasLambdaCaptures()) { - candidateParamType.getType().setHasLambdaCaptures(true); + if (requestedType.getBase().isOneOf({TY_FUNCTION, TY_PROCEDURE}) && requestedType.hasLambdaCaptures()) { + candidateParamType.setHasLambdaCaptures(true); needsSubstantiation = true; } } diff --git a/src/typechecker/FunctionManager.h b/src/typechecker/FunctionManager.h index 0a123ebf6..4511682c9 100644 --- a/src/typechecker/FunctionManager.h +++ b/src/typechecker/FunctionManager.h @@ -42,12 +42,11 @@ class FunctionManager { static Function *insertFunction(Scope *insertScope, const Function &baseFunction, std::vector *nodeFunctionList = nullptr); static void substantiateOptionalParams(const Function &baseFunction, std::vector &manifestations); - [[nodiscard]] static Function createMainFunction(SymbolTableEntry *entry, const std::vector ¶mTypes, - ASTNode *declNode); + [[nodiscard]] static Function createMainFunction(SymbolTableEntry *entry, const QualTypeList ¶mTypes, ASTNode *declNode); [[nodiscard]] static const Function *lookupFunction(Scope *matchScope, const std::string &reqName, const QualType &reqThisType, const ArgList &reqArgs, bool strictSpecifierMatching); - static Function *matchFunction(Scope *matchScope, const std::string &reqName, const QualType &reqThisType, const ArgList &reqArgs, - const std::vector &templateTypeHints, bool strictSpecifierMatching, + static Function *matchFunction(Scope *matchScope, const std::string &reqName, const QualType &reqThisType, + const ArgList &reqArgs, const QualTypeList &templateTypeHints, bool strictSpecifierMatching, const ASTNode *callNode); private: diff --git a/src/typechecker/InterfaceManager.cpp b/src/typechecker/InterfaceManager.cpp index f28a7b79f..ef444f4e4 100644 --- a/src/typechecker/InterfaceManager.cpp +++ b/src/typechecker/InterfaceManager.cpp @@ -49,8 +49,8 @@ Interface *InterfaceManager::insertSubstantiation(Scope *insertScope, Interface * @param node Instantiation AST node for printing error messages * @return Matched interface or nullptr */ -Interface *InterfaceManager::matchInterface(Scope *matchScope, const std::string &reqName, - const std::vector &reqTemplateTypes, const ASTNode *node) { +Interface *InterfaceManager::matchInterface(Scope *matchScope, const std::string &reqName, const QualTypeList &reqTemplateTypes, + const ASTNode *node) { // Copy the registry to prevent iterating over items, that are created within the loop InterfaceRegistry interfaceRegistry = matchScope->interfaces; // Loop over interface registry to find interfaces, that match the requirements of the instantiation @@ -121,8 +121,8 @@ Interface *InterfaceManager::matchInterface(Scope *matchScope, const std::string // Attach the template types to the new interface entry QualType entryType = substantiatedInterface->entry->getQualType(); - entryType.getType().setTemplateTypes(substantiatedInterface->getTemplateTypes()); - entryType.getType().setBodyScope(substantiatedInterface->scope); + entryType.setTemplateTypes(substantiatedInterface->getTemplateTypes()); + entryType.setBodyScope(substantiatedInterface->scope); substantiatedInterface->entry->updateType(entryType, true); // Replace symbol types of method entries with concrete types @@ -166,8 +166,7 @@ bool InterfaceManager::matchName(const Interface &candidate, const std::string & * @param reqTemplateTypes Requested interface template types * @return Fulfilled or not */ -bool InterfaceManager::matchTemplateTypes(Interface &candidate, const std::vector &reqTemplateTypes, - TypeMapping &typeMapping) { +bool InterfaceManager::matchTemplateTypes(Interface &candidate, const QualTypeList &reqTemplateTypes, TypeMapping &typeMapping) { // Check if the number of types match const size_t typeCount = reqTemplateTypes.size(); if (typeCount != candidate.templateTypes.size()) diff --git a/src/typechecker/InterfaceManager.h b/src/typechecker/InterfaceManager.h index e260f55d8..b85e092eb 100644 --- a/src/typechecker/InterfaceManager.h +++ b/src/typechecker/InterfaceManager.h @@ -25,13 +25,13 @@ class InterfaceManager { // Public methods static Interface *insertInterface(Scope *insertScope, Interface &spiceInterface, std::vector *nodeInterfaceList); [[nodiscard]] static Interface *matchInterface(Scope *matchScope, const std::string &reqName, - const std::vector &reqTemplateTypes, const ASTNode *node); + const QualTypeList &reqTemplateTypes, const ASTNode *node); private: // Private methods [[nodiscard]] static Interface *insertSubstantiation(Scope *insertScope, Interface &newManifestation, const ASTNode *declNode); [[nodiscard]] static bool matchName(const Interface &candidate, const std::string &reqName); - [[nodiscard]] static bool matchTemplateTypes(Interface &candidate, const std::vector &reqTemplateTypes, + [[nodiscard]] static bool matchTemplateTypes(Interface &candidate, const QualTypeList &reqTemplateTypes, TypeMapping &typeMapping); static void substantiateSignatures(Interface &candidate, TypeMapping &typeMapping); [[nodiscard]] static const GenericType *getGenericTypeOfCandidateByName(const Interface &candidate, diff --git a/src/typechecker/MacroDefs.h b/src/typechecker/MacroDefs.h index 96da89320..068e1d2bb 100644 --- a/src/typechecker/MacroDefs.h +++ b/src/typechecker/MacroDefs.h @@ -7,7 +7,7 @@ #define SOFT_ERROR_ER(node, type, message) \ { \ resourceManager.errorManager.addSoftError(node, type, message); \ - return ExprResult{node->setEvaluatedSymbolType(QualType(TY_UNRESOLVED), manIdx)}; \ + return ExprResult{node->setEvaluatedSymbolType(QualType(TY_UNRESOLVED), manIdx)}; \ } #define SOFT_ERROR_QT(node, type, message) \ diff --git a/src/typechecker/OpRuleManager.cpp b/src/typechecker/OpRuleManager.cpp index 9108e1abc..33867033b 100644 --- a/src/typechecker/OpRuleManager.cpp +++ b/src/typechecker/OpRuleManager.cpp @@ -116,7 +116,7 @@ QualType OpRuleManager::getAssignResultTypeCommon(const ASTNode *node, const Exp QualType lhsTypeCopy = lhsType; QualType rhsTypeCopy = rhsType; QualType::unwrapBoth(lhsTypeCopy, rhsTypeCopy); - if (lhsTypeCopy.getType().matchesInterfaceImplementedByStruct(rhsTypeCopy.getType())) + if (lhsTypeCopy.matchesInterfaceImplementedByStruct(rhsTypeCopy)) return lhsType; } diff --git a/src/typechecker/OpRuleManager.h b/src/typechecker/OpRuleManager.h index 3d207bf17..9e6a94f10 100644 --- a/src/typechecker/OpRuleManager.h +++ b/src/typechecker/OpRuleManager.h @@ -669,10 +669,10 @@ class OpRuleManager { ExprResult isOperatorOverloadingFctAvailable(ASTNode *node, const char *fctName, const std::array &op, size_t opIdx); static QualType validateUnaryOperation(const ASTNode *node, const UnaryOpRule opRules[], size_t opRulesSize, const char *name, - const QualType &lhs); + const QualType &lhs); static QualType validateBinaryOperation(const ASTNode *node, const BinaryOpRule opRules[], size_t opRulesSize, const char *name, - const QualType &lhs, const QualType &rhs, bool preserveSpecifiersFromLhs = false, - const char *customMessagePrefix = ""); + const QualType &lhs, const QualType &rhs, bool preserveSpecifiersFromLhs = false, + const char *customMessagePrefix = ""); static SemanticError getExceptionUnary(const ASTNode *node, const char *name, const QualType &lhs); static SemanticError getExceptionBinary(const ASTNode *node, const char *name, const QualType &lhs, const QualType &rhs, const char *messagePrefix); diff --git a/src/typechecker/StructManager.cpp b/src/typechecker/StructManager.cpp index 69658ce78..dbdcaca3a 100644 --- a/src/typechecker/StructManager.cpp +++ b/src/typechecker/StructManager.cpp @@ -53,7 +53,7 @@ Struct *StructManager::insertSubstantiation(Scope *insertScope, Struct &newManif * @param node Instantiation AST node for printing error messages * @return Matched struct or nullptr */ -Struct *StructManager::matchStruct(Scope *matchScope, const std::string &reqName, const std::vector &reqTemplateTypes, +Struct *StructManager::matchStruct(Scope *matchScope, const std::string &reqName, const QualTypeList &reqTemplateTypes, const ASTNode *node) { // Copy the registry to prevent iterating over items, that are created within the loop StructRegistry structRegistry = matchScope->structs; @@ -125,8 +125,8 @@ Struct *StructManager::matchStruct(Scope *matchScope, const std::string &reqName // Attach the template types to the new struct entry QualType entryType = substantiatedStruct->entry->getQualType(); - entryType.getType().setTemplateTypes(substantiatedStruct->getTemplateTypes()); - entryType.getType().setBodyScope(substantiatedStruct->scope); + entryType.setTemplateTypes(substantiatedStruct->getTemplateTypes()); + entryType.setBodyScope(substantiatedStruct->scope); substantiatedStruct->entry->updateType(entryType, true); // Replace symbol types of field entries with concrete types @@ -142,7 +142,7 @@ Struct *StructManager::matchStruct(Scope *matchScope, const std::string &reqName // Set the body scope of fields that are of type * if (baseType.matches(substantiatedStruct->entry->getQualType(), false, true, true)) { - baseType.getType().setBodyScope(substantiatedStruct->scope); + baseType.setBodyScope(substantiatedStruct->scope); fieldType = fieldType.replaceBaseType(baseType); } @@ -150,7 +150,7 @@ Struct *StructManager::matchStruct(Scope *matchScope, const std::string &reqName // Instantiate structs if (baseType.is(TY_STRUCT)) - baseType.getType().getStruct(node); + baseType.getStruct(node); } // Instantiate implemented interfaces if required @@ -160,11 +160,11 @@ Struct *StructManager::matchStruct(Scope *matchScope, const std::string &reqName continue; // Build template types - std::vector templateTypes = interfaceType.getType().getTemplateTypes(); + QualTypeList templateTypes = interfaceType.getTemplateTypes(); TypeMatcher::substantiateTypesWithTypeMapping(templateTypes, typeMapping); // Instantiate interface - Scope *interfaceMatchScope = interfaceType.getType().getBodyScope()->parent; + Scope *interfaceMatchScope = interfaceType.getBodyScope()->parent; Interface *spiceInterface = InterfaceManager::matchInterface(interfaceMatchScope, interfaceType.getSubType(), templateTypes, node); assert(spiceInterface != nullptr); @@ -204,8 +204,7 @@ bool StructManager::matchName(const Struct &candidate, const std::string &reqNam * @param reqTemplateTypes Requested struct template types * @return Fulfilled or not */ -bool StructManager::matchTemplateTypes(Struct &candidate, const std::vector &reqTemplateTypes, - TypeMapping &typeMapping) { +bool StructManager::matchTemplateTypes(Struct &candidate, const QualTypeList &reqTemplateTypes, TypeMapping &typeMapping) { // Check if the number of types match const size_t typeCount = reqTemplateTypes.size(); if (typeCount != candidate.templateTypes.size()) diff --git a/src/typechecker/StructManager.h b/src/typechecker/StructManager.h index 3388258b2..4c4b36ce2 100644 --- a/src/typechecker/StructManager.h +++ b/src/typechecker/StructManager.h @@ -27,15 +27,14 @@ class StructManager { public: // Public methods static Struct *insertStruct(Scope *insertScope, Struct &spiceStruct, std::vector *nodeStructList); - [[nodiscard]] static Struct *matchStruct(Scope *matchScope, const std::string &reqName, - const std::vector &reqTemplateTypes, const ASTNode *node); + [[nodiscard]] static Struct *matchStruct(Scope *matchScope, const std::string &reqName, const QualTypeList &reqTemplateTypes, + const ASTNode *node); private: // Private methods [[nodiscard]] static Struct *insertSubstantiation(Scope *insertScope, Struct &newManifestation, const ASTNode *declNode); [[nodiscard]] static bool matchName(const Struct &candidate, const std::string &reqName); - [[nodiscard]] static bool matchTemplateTypes(Struct &candidate, const std::vector &reqTemplateTypes, - TypeMapping &typeMapping); + [[nodiscard]] static bool matchTemplateTypes(Struct &candidate, const QualTypeList &reqTemplateTypes, TypeMapping &typeMapping); static void substantiateFieldTypes(Struct &candidate, TypeMapping &typeMapping); [[nodiscard]] static const GenericType *getGenericTypeOfCandidateByName(const Struct &candidate, const std::string &templateTypeName); diff --git a/src/typechecker/TypeChecker.cpp b/src/typechecker/TypeChecker.cpp index 4ccc64ccd..534a84dfa 100644 --- a/src/typechecker/TypeChecker.cpp +++ b/src/typechecker/TypeChecker.cpp @@ -157,9 +157,9 @@ std::any TypeChecker::visitForeachLoop(ForeachLoopNode *node) { // Retrieve iterator type QualType iteratorType = iteratorOrIterableType; - if (iteratorOrIterableType.getType().isIterable(node)) { + if (iteratorOrIterableType.isIterable(node)) { const QualType &iterableType = iteratorOrIterableType; - if (iteratorOrIterableType.getType().isArray()) { // Array + if (iteratorOrIterableType.isArray()) { // Array const NameRegistryEntry *nameRegistryEntry = sourceFile->getNameRegistryEntry(ARRAY_ITERATOR_NAME); if (!nameRegistryEntry) { softError(node, UNKNOWN_DATATYPE, "Forgot to import of \"std/iterator/array-iterator\"?"); @@ -175,7 +175,7 @@ std::any TypeChecker::visitForeachLoop(ForeachLoopNode *node) { const QualType thisType(TY_DYN); node->getIteratorFct = FunctionManager::matchFunction(matchScope, "iterate", thisType, argTypes, {}, true, iteratorNode); } else { // Struct, implementing Iterator interface - Scope *matchScope = iterableType.getType().getBodyScope(); + Scope *matchScope = iterableType.getBodyScope(); node->getIteratorFct = FunctionManager::matchFunction(matchScope, "getIterator", iterableType, {}, {}, true, iteratorNode); } assert(node->getIteratorFct != nullptr); @@ -185,14 +185,14 @@ std::any TypeChecker::visitForeachLoop(ForeachLoopNode *node) { } // Check iterator type - if (!iteratorType.getType().isIterator(node)) { + if (!iteratorType.isIterator(node)) { const std::string errMsg = "Can only iterate over arrays or data structures, inheriting from IIterator or IIterable. You provided " + iteratorType.getName(false); softError(node->iteratorAssign(), OPERATOR_WRONG_DATA_TYPE, errMsg); return nullptr; } - const std::vector &iteratorTemplateTypes = iteratorType.getType().getTemplateTypes(); + const QualTypeList &iteratorTemplateTypes = iteratorType.getTemplateTypes(); if (iteratorTemplateTypes.empty()) SOFT_ERROR_ER(node->iteratorAssign(), INVALID_ITERATOR, "Iterator has no generic arguments so that the item type could not be inferred") @@ -209,12 +209,12 @@ std::any TypeChecker::visitForeachLoop(ForeachLoopNode *node) { } // Retrieve .get(), .getIdx(), .isValid() and .next() functions - Scope *matchScope = iteratorType.getType().getBodyScope(); + Scope *matchScope = iteratorType.getBodyScope(); QualType iteratorItemType; if (hasIdx) { node->getIdxFct = FunctionManager::matchFunction(matchScope, "getIdx", iteratorType, {}, {}, false, node); assert(node->getIdxFct != nullptr); - iteratorItemType = node->getIdxFct->returnType.getType().getTemplateTypes().back(); + iteratorItemType = node->getIdxFct->returnType.getTemplateTypes().back(); } else { node->getFct = FunctionManager::matchFunction(matchScope, "get", iteratorType, {}, {}, false, node); assert(node->getFct != nullptr); @@ -485,13 +485,13 @@ std::any TypeChecker::visitSignature(SignatureNode *node) { if (returnType.is(TY_UNRESOLVED)) return static_cast *>(nullptr); - if (!returnType.getType().isCoveredByGenericTypeList(usedGenericTypes)) + if (!returnType.isCoveredByGenericTypeList(usedGenericTypes)) softError(node->returnType(), GENERIC_TYPE_NOT_IN_TEMPLATE, "Generic return type not included in the template type list of the function"); } // Visit params - std::vector paramTypes; + QualTypeList paramTypes; ParamList paramList; if (node->hasParams) { paramList.reserve(node->paramTypeLst()->dataTypes().size()); @@ -501,7 +501,7 @@ std::any TypeChecker::visitSignature(SignatureNode *node) { return static_cast *>(nullptr); // Check if the type is present in the template for generic types - if (!paramType.getType().isCoveredByGenericTypeList(usedGenericTypes)) { + if (!paramType.isCoveredByGenericTypeList(usedGenericTypes)) { softError(node->paramTypeLst(), GENERIC_TYPE_NOT_IN_TEMPLATE, "Generic param type not included in the template type list of the function"); continue; @@ -524,8 +524,8 @@ std::any TypeChecker::visitSignature(SignatureNode *node) { QualType signatureType(isFunction ? TY_FUNCTION : TY_PROCEDURE); signatureType.getSpecifiers() = node->signatureSpecifiers; if (isFunction) - signatureType.getType().setFunctionReturnType(returnType); - signatureType.getType().setFunctionParamTypes(paramTypes); + signatureType.setFunctionReturnType(returnType); + signatureType.setFunctionParamTypes(paramTypes); // Set entry to signature type assert(node->entry != nullptr); @@ -566,7 +566,7 @@ std::any TypeChecker::visitDeclStmt(DeclStmtNode *node) { // Call copy ctor if required if (localVarType.is(TY_STRUCT) && !node->isParam && !rhs.isTemporary()) { - Scope *matchScope = localVarType.getType().getBodyScope(); + Scope *matchScope = localVarType.getBodyScope(); assert(matchScope != nullptr); // Check if we have a no-args ctor to call const QualType &thisType = localVarType; @@ -588,15 +588,15 @@ std::any TypeChecker::visitDeclStmt(DeclStmtNode *node) { localVarType = std::any_cast(visit(node->dataType())); // References with no initialization are illegal - if (localVarType.getType().isRef() && !node->isParam && !node->isForEachItem) + if (localVarType.isRef() && !node->isParam && !node->isForEachItem) softError(node, REFERENCE_WITHOUT_INITIALIZER, "References must always be initialized directly"); // If this is a struct, check for the default ctor if (localVarType.is(TY_STRUCT) && !node->isParam && !node->isForEachItem) { - Scope *matchScope = localVarType.getType().getBodyScope(); + Scope *matchScope = localVarType.getBodyScope(); assert(matchScope != nullptr); // Check if we are required to call a ctor - auto structDeclNode = spice_pointer_cast(localVarType.getType().getStruct(node)->declNode); + auto structDeclNode = spice_pointer_cast(localVarType.getStruct(node)->declNode); node->isCtorCallRequired = matchScope->hasRefFields() || structDeclNode->emitVTable; // Check if we have a no-args ctor to call const std::string &structName = localVarType.getSubType(); @@ -783,8 +783,7 @@ std::any TypeChecker::visitPrintfCall(PrintfCallNode *node) { break; } case 's': { - if (!argType.is(TY_STRING) && !argType.getType().isStringObj() && !argType.isPtrTo(TY_CHAR) && - !argType.isArrayOf(TY_CHAR)) + if (!argType.is(TY_STRING) && !argType.isStringObj() && !argType.isPtrTo(TY_CHAR) && !argType.isArrayOf(TY_CHAR)) SOFT_ERROR_ER(assignment, PRINTF_TYPE_ERROR, "The placeholder string expects string, String, char* or char[], but got " + argType.getName(false)) placeholderCount++; @@ -852,7 +851,7 @@ std::any TypeChecker::visitPanicCall(PanicCallNode *node) { argType = argType.removeReferenceWrapper(); // Check if arg is of type array - if (!argType.getType().isErrorObj()) + if (!argType.isErrorObj()) SOFT_ERROR_ER(node->assignExpr(), EXPECTED_ERROR_TYPE, "The panic builtin can only work with errors") return ExprResult{node->setEvaluatedSymbolType(QualType(TY_DYN), manIdx)}; @@ -1330,9 +1329,9 @@ std::any TypeChecker::visitPostfixUnaryExpr(PostfixUnaryExprNode *node) { "The subscript operator on pointers is an unsafe operation. Use unsafe blocks if you know what you are doing.") // Check if we have a hardcoded array index - if (lhsType.isArray() && lhsType.getType().getArraySize() != ARRAY_SIZE_UNKNOWN && indexAssignExpr->hasCompileTimeValue()) { + if (lhsType.isArray() && lhsType.getArraySize() != ARRAY_SIZE_UNKNOWN && indexAssignExpr->hasCompileTimeValue()) { const int32_t constIndex = indexAssignExpr->getCompileTimeValue().intValue; - const unsigned int constSize = lhsType.getType().getArraySize(); + const unsigned int constSize = lhsType.getArraySize(); // Check if we are accessing out-of-bounds memory if (constIndex >= static_cast(constSize)) { const std::string idxStr = std::to_string(constIndex); @@ -1361,12 +1360,12 @@ std::any TypeChecker::visitPostfixUnaryExpr(PostfixUnaryExprNode *node) { // Retrieve registry entry const std::string &structName = lhsBaseTy.getSubType(); - Scope *structScope = lhsBaseTy.getType().getBodyScope(); + Scope *structScope = lhsBaseTy.getBodyScope(); // If we only have the generic struct scope, lookup the concrete manifestation scope if (structScope->isGenericScope) { Scope *matchScope = structScope->parent; - Struct *spiceStruct = StructManager::matchStruct(matchScope, structName, lhsBaseTy.getType().getTemplateTypes(), node); + Struct *spiceStruct = StructManager::matchStruct(matchScope, structName, lhsBaseTy.getTemplateTypes(), node); assert(spiceStruct != nullptr); structScope = spiceStruct->scope; } @@ -1501,7 +1500,7 @@ std::any TypeChecker::visitAtomicExpr(AtomicExprNode *node) { // The base type should be a primitive, struct, interface, function or procedure const QualType baseType = varType.getBase(); - if (!baseType.getType().isPrimitive() && !baseType.isOneOf({TY_STRUCT, TY_INTERFACE, TY_FUNCTION, TY_PROCEDURE, TY_DYN})) + if (!baseType.isPrimitive() && !baseType.isOneOf({TY_STRUCT, TY_INTERFACE, TY_FUNCTION, TY_PROCEDURE, TY_DYN})) SOFT_ERROR_ER(node, INVALID_SYMBOL_ACCESS, "A symbol of type " + varType.getName(false) + " cannot be accessed here") // Check if is an imported variable @@ -1665,10 +1664,10 @@ std::any TypeChecker::visitFctCall(FctCallNode *node) { } // Get the concrete template types - std::vector concreteTemplateTypes; + QualTypeList concreteTemplateTypes; if (isAliasType) { // Retrieve concrete template types from type alias - concreteTemplateTypes = aliasedTypeContainerEntry->getQualType().getType().getTemplateTypes(); + concreteTemplateTypes = aliasedTypeContainerEntry->getQualType().getTemplateTypes(); // Check if the aliased type specified template types and the struct instantiation does if (!concreteTemplateTypes.empty() && node->hasTemplateTypes) SOFT_ERROR_BOOL(node->templateTypeLst(), ALIAS_WITH_TEMPLATE_LIST, "The aliased type already has a template list") @@ -1696,7 +1695,7 @@ std::any TypeChecker::visitFctCall(FctCallNode *node) { if (data.isMethodCall()) { // This is a method call data.thisType = firstFragEntry->getQualType(); - Scope *structBodyScope = data.thisType.getBase().getType().getBodyScope(); + Scope *structBodyScope = data.thisType.getBase().getBodyScope(); assert(structBodyScope != nullptr); bool success = visitMethodCall(node, structBodyScope, concreteTemplateTypes); if (!success) // Check if soft errors occurred @@ -1754,7 +1753,7 @@ std::any TypeChecker::visitFctCall(FctCallNode *node) { const bool isFct = data.isFctPtrCall() ? firstFragEntry->getQualType().getBase().is(TY_FUNCTION) : data.callee->isFunction(); QualType returnType; if (data.isFctPtrCall()) { - returnType = isFct ? firstFragEntry->getQualType().getBase().getType().getFunctionReturnType() : QualType(TY_BOOL); + returnType = isFct ? firstFragEntry->getQualType().getBase().getFunctionReturnType() : QualType(TY_BOOL); } else if (data.isCtorCall()) { // Set return type to 'this' type returnType = data.thisType; @@ -1770,14 +1769,14 @@ std::any TypeChecker::visitFctCall(FctCallNode *node) { if (returnType.isBase(TY_STRUCT)) { QualType returnBaseType = returnType.getBase(); const std::string structName = returnBaseType.getSubType(); - Scope *matchScope = returnBaseType.getType().getBodyScope()->parent; + Scope *matchScope = returnBaseType.getBodyScope()->parent; assert(matchScope != nullptr); - Struct *spiceStruct = StructManager::matchStruct(matchScope, structName, returnBaseType.getType().getTemplateTypes(), node); + Struct *spiceStruct = StructManager::matchStruct(matchScope, structName, returnBaseType.getTemplateTypes(), node); assert(spiceStruct != nullptr); - returnBaseType.getType().setBodyScope(spiceStruct->scope); + returnBaseType.setBodyScope(spiceStruct->scope); returnType = returnType.replaceBaseType(returnBaseType); - returnType = mapImportedScopeTypeToLocalType(returnType.getBase().getType().getBodyScope(), returnType); + returnType = mapImportedScopeTypeToLocalType(returnType.getBase().getBodyScope(), returnType); // Add anonymous symbol to keep track of de-allocation if (returnType.is(TY_STRUCT)) @@ -1794,8 +1793,7 @@ std::any TypeChecker::visitFctCall(FctCallNode *node) { return ExprResult{node->setEvaluatedSymbolType(returnType, manIdx), anonymousSymbol}; } -bool TypeChecker::visitOrdinaryFctCall(FctCallNode *node, std::vector &templateTypes, - const std::string &fqFunctionName) { +bool TypeChecker::visitOrdinaryFctCall(FctCallNode *node, QualTypeList &templateTypes, const std::string &fqFunctionName) { FctCallNode::FctCallData &data = node->data.at(manIdx); // Check if this is a ctor call to the String type @@ -1847,7 +1845,7 @@ bool TypeChecker::visitOrdinaryFctCall(FctCallNode *node, std::vector // Set the 'this' type of the function to the struct type data.thisType = structEntry->getQualType(); - data.thisType.getType().setBodyScope(thisStruct->scope); + data.thisType.setBodyScope(thisStruct->scope); // Get the fully qualified name, that can be used in the current source file to identify the struct knownStructName = structRegistryEntry->name; @@ -1855,7 +1853,7 @@ bool TypeChecker::visitOrdinaryFctCall(FctCallNode *node, std::vector // Attach the concrete template types to the 'this' type if (!data.thisType.is(TY_DYN) && !templateTypes.empty()) - data.thisType.getType().setTemplateTypes(templateTypes); + data.thisType.setTemplateTypes(templateTypes); // Map local arg types to imported types Scope *matchScope = data.calleeParentScope = functionRegistryEntry->targetScope; @@ -1878,7 +1876,7 @@ bool TypeChecker::visitFctPtrCall(FctCallNode *node, const QualType &functionTyp FctCallNode::FctCallData &data = node->data.at(manIdx); // Check if the given argument types match the type - const std::vector expectedArgTypes = functionType.getType().getFunctionParamTypes(); + const QualTypeList expectedArgTypes = functionType.getFunctionParamTypes(); if (data.argResults.size() != expectedArgTypes.size()) SOFT_ERROR_BOOL(node, REFERENCED_UNDEFINED_FUNCTION, "Expected and actual number of arguments do not match") @@ -1896,7 +1894,7 @@ bool TypeChecker::visitFctPtrCall(FctCallNode *node, const QualType &functionTyp return true; } -bool TypeChecker::visitMethodCall(FctCallNode *node, Scope *structScope, std::vector &templateTypes) const { +bool TypeChecker::visitMethodCall(FctCallNode *node, Scope *structScope, QualTypeList &templateTypes) const { FctCallNode::FctCallData &data = node->data.at(manIdx); // Traverse through structs - the first fragment is already looked up and the last one is the method name @@ -1916,7 +1914,7 @@ bool TypeChecker::visitMethodCall(FctCallNode *node, Scope *structScope, std::ve // Get struct type and scope data.thisType = fieldEntry->getQualType(); - structScope = data.thisType.getBase().getType().getBodyScope(); + structScope = data.thisType.getBase().getBodyScope(); assert(structScope != nullptr); } @@ -1996,10 +1994,10 @@ std::any TypeChecker::visitStructInstantiation(StructInstantiationNode *node) { QualType structType = structEntry->getQualType(); // Get the concrete template types - std::vector concreteTemplateTypes; + QualTypeList concreteTemplateTypes; if (isAliasType) { // Retrieve concrete template types from type alias - concreteTemplateTypes = aliasedTypeContainerEntry->getQualType().getType().getTemplateTypes(); + concreteTemplateTypes = aliasedTypeContainerEntry->getQualType().getTemplateTypes(); // Check if the aliased type specified template types and the struct instantiation does if (!concreteTemplateTypes.empty() && node->templateTypeLst()) SOFT_ERROR_ER(node->templateTypeLst(), ALIAS_WITH_TEMPLATE_LIST, "The aliased type already has a template list") @@ -2033,13 +2031,13 @@ std::any TypeChecker::visitStructInstantiation(StructInstantiationNode *node) { // Use scope of concrete substantiation and not the scope of the generic type structScope = spiceStruct->scope; - structType.getType().setBodyScope(structScope); + structType.setBodyScope(structScope); // Set template types to the struct - std::vector templateTypes; + QualTypeList templateTypes; for (const GenericType &genericType : spiceStruct->templateTypes) templateTypes.emplace_back(genericType); - structType.getType().setTemplateTypes(templateTypes); + structType.setTemplateTypes(templateTypes); // Check if the number of fields matches if (node->fieldLst()) { // Check if any fields are passed. Empty braces are also allowed @@ -2115,7 +2113,7 @@ std::any TypeChecker::visitLambdaFunc(LambdaFuncNode *node) { resultVarEntry->used = true; // Visit parameters - std::vector paramTypes; + QualTypeList paramTypes; ParamList paramList; if (node->hasParams) { // Visit param list to retrieve the param names @@ -2137,9 +2135,9 @@ std::any TypeChecker::visitLambdaFunc(LambdaFuncNode *node) { // Prepare type of function QualType functionType(TY_FUNCTION); - functionType.getType().setFunctionReturnType(returnType); - functionType.getType().setFunctionParamTypes(paramTypes); - functionType.getType().setHasLambdaCaptures(!bodyScope->symbolTable.captures.empty()); + functionType.setFunctionReturnType(returnType); + functionType.setFunctionParamTypes(paramTypes); + functionType.setHasLambdaCaptures(!bodyScope->symbolTable.captures.empty()); // Create function object const std::string fctName = "lambda." + node->codeLoc.toPrettyLineAndColumn(); @@ -2159,7 +2157,7 @@ std::any TypeChecker::visitLambdaProc(LambdaProcNode *node) { ScopeHandle scopeHandle(this, bodyScope, ScopeType::LAMBDA_BODY); // Visit parameters - std::vector paramTypes; + QualTypeList paramTypes; ParamList paramList; if (node->hasParams) { // Visit param list to retrieve the param names @@ -2181,8 +2179,8 @@ std::any TypeChecker::visitLambdaProc(LambdaProcNode *node) { // Prepare type of function QualType functionType(TY_PROCEDURE); - functionType.getType().setFunctionParamTypes(paramTypes); - functionType.getType().setHasLambdaCaptures(!bodyScope->symbolTable.captures.empty()); + functionType.setFunctionParamTypes(paramTypes); + functionType.setHasLambdaCaptures(!bodyScope->symbolTable.captures.empty()); // Create function object const std::string fctName = "lambda." + node->codeLoc.toPrettyLineAndColumn(); @@ -2202,7 +2200,7 @@ std::any TypeChecker::visitLambdaExpr(LambdaExprNode *node) { ScopeHandle scopeHandle(this, bodyScope, ScopeType::LAMBDA_BODY); // Visit parameters - std::vector paramTypes; + QualTypeList paramTypes; ParamList paramList; if (node->hasParams) { // Visit param list to retrieve the param names @@ -2229,9 +2227,9 @@ std::any TypeChecker::visitLambdaExpr(LambdaExprNode *node) { const bool isFunction = !returnType.is(TY_DYN); QualType functionType(isFunction ? TY_FUNCTION : TY_PROCEDURE); if (isFunction) - functionType.getType().setFunctionReturnType(returnType); - functionType.getType().setFunctionParamTypes(paramTypes); - functionType.getType().setHasLambdaCaptures(!bodyScope->symbolTable.captures.empty()); + functionType.setFunctionReturnType(returnType); + functionType.setFunctionParamTypes(paramTypes); + functionType.setHasLambdaCaptures(!bodyScope->symbolTable.captures.empty()); // Create function object const std::string fctName = "lambda." + node->codeLoc.toPrettyLineAndColumn(); @@ -2252,7 +2250,7 @@ std::any TypeChecker::visitDataType(DataTypeNode *node) { DataTypeNode::TypeModifier typeModifier = tmQueue.front(); // Only the outermost array can have an unknown size - if (type.getType().isArray() && type.getType().getArraySize() == ARRAY_SIZE_UNKNOWN) + if (type.isArray() && type.getArraySize() == ARRAY_SIZE_UNKNOWN) SOFT_ERROR_QT(node, ARRAY_SIZE_INVALID, "Usage of incomplete array type. Only the outermost array type may have unknown size") @@ -2393,7 +2391,7 @@ std::any TypeChecker::visitCustomDataType(CustomDataTypeNode *node) { symbolType = typeMapping.at(firstFragment); // Check if the replacement is a String type - if (!isImported && symbolType.getType().isStringObj() && !sourceFile->isStringRT()) + if (!isImported && symbolType.isStringObj() && !sourceFile->isStringRT()) sourceFile->requestRuntimeModule(STRING_RT); return node->setEvaluatedSymbolType(symbolType, manIdx); @@ -2432,7 +2430,7 @@ std::any TypeChecker::visitCustomDataType(CustomDataTypeNode *node) { // Collect the concrete template types bool allTemplateTypesConcrete = true; - std::vector templateTypes; + QualTypeList templateTypes; if (node->templateTypeLst()) { templateTypes.reserve(node->templateTypeLst()->dataTypes().size()); for (DataTypeNode *dataType : node->templateTypeLst()->dataTypes()) { @@ -2442,7 +2440,7 @@ std::any TypeChecker::visitCustomDataType(CustomDataTypeNode *node) { allTemplateTypesConcrete = false; templateTypes.push_back(templateType); } - entryType.getType().setTemplateTypes(templateTypes); + entryType.setTemplateTypes(templateTypes); } if (entryType.is(TY_STRUCT)) { @@ -2458,7 +2456,7 @@ std::any TypeChecker::visitCustomDataType(CustomDataTypeNode *node) { const std::string structName = node->typeNameFragments.back(); Struct *spiceStruct = StructManager::matchStruct(localAccessScope, structName, templateTypes, node); if (spiceStruct) - entryType.getType().setBodyScope(spiceStruct->scope); + entryType.setBodyScope(spiceStruct->scope); } } @@ -2468,7 +2466,7 @@ std::any TypeChecker::visitCustomDataType(CustomDataTypeNode *node) { Interface *spiceInterface = InterfaceManager::matchInterface(localAccessScope, interfaceName, templateTypes, node); if (!spiceInterface) SOFT_ERROR_QT(node, UNKNOWN_DATATYPE, "Unknown interface " + Interface::getSignature(interfaceName, templateTypes)) - entryType.getType().setBodyScope(spiceInterface->scope); + entryType.setBodyScope(spiceInterface->scope); } return node->setEvaluatedSymbolType(entryType, manIdx); @@ -2490,7 +2488,7 @@ std::any TypeChecker::visitFunctionDataType(FunctionDataTypeNode *node) { } // Visit param types - std::vector paramTypes; + QualTypeList paramTypes; if (const TypeLstNode *paramTypeListNode = node->paramTypeLst(); paramTypeListNode != nullptr) { for (DataTypeNode *paramTypeNode : paramTypeListNode->dataTypes()) { auto paramType = std::any_cast(visit(paramTypeNode)); @@ -2502,8 +2500,8 @@ std::any TypeChecker::visitFunctionDataType(FunctionDataTypeNode *node) { // Build function type QualType functionType(node->isFunction ? TY_FUNCTION : TY_PROCEDURE); if (node->isFunction) - functionType.getType().setFunctionReturnType(returnType); - functionType.getType().setFunctionParamTypes(paramTypes); + functionType.setFunctionReturnType(returnType); + functionType.setFunctionParamTypes(paramTypes); return node->setEvaluatedSymbolType(functionType, manIdx); } @@ -2555,7 +2553,7 @@ QualType TypeChecker::mapLocalTypeToImportedScopeType(const Scope *targetScope, for (const auto &[_, entry] : targetSourceFile->exportedNameRegistry) if (entry.targetEntry != nullptr && entry.targetEntry->getQualType().isBase(TY_STRUCT)) for (const Struct *manifestation : *entry.targetEntry->declNode->getStructManifestations()) - if (manifestation->scope == symbolType.getBase().getType().getBodyScope()) + if (manifestation->scope == symbolType.getBase().getBodyScope()) return symbolType; // The target source file does not know about the struct at all @@ -2585,7 +2583,7 @@ QualType TypeChecker::mapImportedScopeTypeToLocalType(const Scope *sourceScope, for (const auto &[_, entry] : sourceFile->exportedNameRegistry) if (entry.targetEntry != nullptr && entry.targetEntry->getQualType().isBase(TY_STRUCT)) for (const Struct *manifestation : *entry.targetEntry->declNode->getStructManifestations()) - if (manifestation->scope == baseType.getType().getBodyScope()) + if (manifestation->scope == baseType.getBodyScope()) return symbolType; // This source file does not know about the struct at all diff --git a/src/typechecker/TypeChecker.h b/src/typechecker/TypeChecker.h index 5093012e5..518a3ffae 100644 --- a/src/typechecker/TypeChecker.h +++ b/src/typechecker/TypeChecker.h @@ -132,9 +132,9 @@ class TypeChecker : private CompilerPass, public ASTVisitor { bool typeCheckedMainFct = false; // Private methods - bool visitOrdinaryFctCall(FctCallNode *node, std::vector &templateTypes, const std::string &fqFunctionName); + bool visitOrdinaryFctCall(FctCallNode *node, QualTypeList &templateTypes, const std::string &fqFunctionName); bool visitFctPtrCall(FctCallNode *node, const QualType &functionType) const; - bool visitMethodCall(FctCallNode *node, Scope *structScope, std::vector &templateTypes) const; + bool visitMethodCall(FctCallNode *node, Scope *structScope, QualTypeList &templateTypes) const; bool checkAsyncLambdaCaptureRules(LambdaBaseNode *node, const LambdaAttrNode *attrs) const; [[nodiscard]] QualType mapLocalTypeToImportedScopeType(const Scope *targetScope, const QualType &symbolType) const; [[nodiscard]] QualType mapImportedScopeTypeToLocalType(const Scope *sourceScope, const QualType &symbolType) const; diff --git a/src/typechecker/TypeCheckerCheck.cpp b/src/typechecker/TypeCheckerCheck.cpp index b1502c940..396cf8e45 100644 --- a/src/typechecker/TypeCheckerCheck.cpp +++ b/src/typechecker/TypeCheckerCheck.cpp @@ -43,8 +43,7 @@ std::any TypeChecker::visitFctDefCheck(FctDefNode *node) { // Change scope to concrete struct specialization scope if (node->isMethod) { - const auto structSignature = - Struct::getSignature(node->name->structName, manifestation->thisType.getType().getTemplateTypes()); + const auto structSignature = Struct::getSignature(node->name->structName, manifestation->thisType.getTemplateTypes()); changeToScope(STRUCT_SCOPE_PREFIX + structSignature, ScopeType::STRUCT); } @@ -100,8 +99,7 @@ std::any TypeChecker::visitProcDefCheck(ProcDefNode *node) { // Change scope to concrete struct specialization scope if (node->isMethod) { - const auto structSignature = - Struct::getSignature(node->name->structName, manifestation->thisType.getType().getTemplateTypes()); + const auto structSignature = Struct::getSignature(node->name->structName, manifestation->thisType.getTemplateTypes()); changeToScope(STRUCT_SCOPE_PREFIX + structSignature, ScopeType::STRUCT); } @@ -169,15 +167,14 @@ std::any TypeChecker::visitStructDefCheck(StructDefNode *node) { for (const QualType &interfaceType : manifestation->interfaceTypes) { // Retrieve interface instance const std::string interfaceName = interfaceType.getSubType(); - Scope *matchScope = interfaceType.getType().getBodyScope()->parent; - Interface *interface = - InterfaceManager::matchInterface(matchScope, interfaceName, interfaceType.getType().getTemplateTypes(), node); + Scope *matchScope = interfaceType.getBodyScope()->parent; + Interface *interface = InterfaceManager::matchInterface(matchScope, interfaceName, interfaceType.getTemplateTypes(), node); assert(interface != nullptr); // Check for all methods, that it is implemented by the struct for (const Function *expectedMethod : interface->methods) { const std::string methodName = expectedMethod->name; - std::vector params = expectedMethod->getParamTypes(); + QualTypeList params = expectedMethod->getParamTypes(); QualType returnType = expectedMethod->returnType; // Substantiate diff --git a/src/typechecker/TypeCheckerImplicit.cpp b/src/typechecker/TypeCheckerImplicit.cpp index a781c44bf..826638896 100644 --- a/src/typechecker/TypeCheckerImplicit.cpp +++ b/src/typechecker/TypeCheckerImplicit.cpp @@ -95,8 +95,8 @@ void TypeChecker::createDefaultCtorIfRequired(const Struct &spiceStruct, Scope * const QualType fieldType = fieldSymbol->getQualType(); if (fieldType.is(TY_STRUCT)) { - Scope *bodyScope = fieldType.getType().getBodyScope(); - Struct *fieldStruct = fieldType.getType().getStruct(node); + Scope *bodyScope = fieldType.getBodyScope(); + Struct *fieldStruct = fieldType.getStruct(node); // Check if we are required to call a ctor const auto structDeclNode = spice_pointer_cast(fieldStruct->declNode); const bool isCtorCallRequired = bodyScope->hasRefFields() || structDeclNode->emitVTable; @@ -150,8 +150,8 @@ void TypeChecker::createDefaultCopyCtorIfRequired(const Struct &spiceStruct, Sco const QualType fieldType = fieldSymbol->getQualType(); if (fieldType.is(TY_STRUCT)) { - Scope *bodyScope = fieldType.getType().getBodyScope(); - Struct *fieldStruct = fieldType.getType().getStruct(node); + Scope *bodyScope = fieldType.getBodyScope(); + Struct *fieldStruct = fieldType.getStruct(node); // Check if we are required to call a ctor const auto structDeclNode = spice_pointer_cast(fieldStruct->declNode); const bool isCtorCallRequired = bodyScope->hasRefFields() || structDeclNode->emitVTable; @@ -204,7 +204,7 @@ void TypeChecker::createDefaultDtorIfRequired(const Struct &spiceStruct, Scope * SymbolTableEntry *fieldSymbol = structScope->symbolTable.lookupStrictByIndex(i); hasHeapFields |= fieldSymbol->getQualType().isHeap(); if (fieldSymbol->getQualType().is(TY_STRUCT)) { - Scope *fieldScope = fieldSymbol->getQualType().getType().getBodyScope(); + Scope *fieldScope = fieldSymbol->getQualType().getBodyScope(); // Lookup dtor function const QualType &thisType = fieldSymbol->getQualType(); const Function *dtorFct = FunctionManager::matchFunction(fieldScope, DTOR_FUNCTION_NAME, thisType, {}, {}, true, node); @@ -261,10 +261,10 @@ void TypeChecker::createCtorBodyPreamble(Scope *bodyScope) { 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.getType().getBodyScope(); + Scope *matchScope = fieldType.getBodyScope(); Function *spiceFunc = FunctionManager::matchFunction(matchScope, CTOR_FUNCTION_NAME, fieldType, {}, {}, false, fieldNode); if (spiceFunc != nullptr) { - fieldType.getType().setBodyScope(spiceFunc->thisType.getType().getBodyScope()); + fieldType.setBodyScope(spiceFunc->thisType.getBodyScope()); fieldSymbol->updateType(fieldType, true); } } @@ -293,11 +293,11 @@ void TypeChecker::createCopyCtorBodyPreamble(Scope *bodyScope) { 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.getType().getBodyScope(); + Scope *matchScope = fieldType.getBodyScope(); const ArgList args = {{fieldType.toConstRef(fieldNode), false /* we always have the field as storage */}}; Function *spiceFunc = FunctionManager::matchFunction(matchScope, CTOR_FUNCTION_NAME, fieldType, args, {}, false, fieldNode); if (spiceFunc != nullptr) { - fieldType.getType().setBodyScope(spiceFunc->thisType.getType().getBodyScope()); + fieldType.setBodyScope(spiceFunc->thisType.getBodyScope()); fieldSymbol->updateType(fieldType, true); } } @@ -325,7 +325,7 @@ void TypeChecker::createDtorBodyPreamble(Scope *bodyScope) { 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.getType().getBodyScope(); + Scope *matchScope = fieldType.getBodyScope(); FunctionManager::matchFunction(matchScope, DTOR_FUNCTION_NAME, fieldType, {}, {}, false, fieldNode); } } @@ -343,7 +343,7 @@ Function *TypeChecker::implicitlyCallStructMethod(SymbolTableEntry *entry, const const ASTNode *node) { QualType thisType = entry->getQualType(); assert(thisType.is(TY_STRUCT)); - Scope *matchScope = thisType.getType().getBodyScope(); + Scope *matchScope = thisType.getBodyScope(); assert(matchScope->type == ScopeType::STRUCT); // Search for dtor diff --git a/src/typechecker/TypeCheckerPrepare.cpp b/src/typechecker/TypeCheckerPrepare.cpp index 9dceb8266..25c355dd4 100644 --- a/src/typechecker/TypeCheckerPrepare.cpp +++ b/src/typechecker/TypeCheckerPrepare.cpp @@ -25,7 +25,7 @@ std::any TypeChecker::visitMainFctDefPrepare(MainFctDefNode *node) { resultEntry->used = true; // Retrieve param types - std::vector paramTypes; + QualTypeList paramTypes; if (node->takesArgs) { auto namedParamList = std::any_cast(visit(node->paramLst())); for (const NamedParam ¶m : namedParamList) @@ -34,8 +34,8 @@ std::any TypeChecker::visitMainFctDefPrepare(MainFctDefNode *node) { // Prepare type of function QualType functionType(TY_FUNCTION); - functionType.getType().setFunctionReturnType(returnType); - functionType.getType().setFunctionParamTypes(paramTypes); + functionType.setFunctionReturnType(returnType); + functionType.setFunctionParamTypes(paramTypes); // Update main function symbol type SymbolTableEntry *functionEntry = rootScope->lookupStrict(node->getSignature()); @@ -93,7 +93,7 @@ std::any TypeChecker::visitFctDefPrepare(FctDefNode *node) { thisType = structEntry->getQualType(); thisPtrType = thisType.toPtr(node); // Collect template types of 'this' type - for (const QualType &templateType : thisType.getType().getTemplateTypes()) { + for (const QualType &templateType : thisType.getTemplateTypes()) { const auto lambda = [&](const GenericType &genericType) { return genericType == templateType; }; if (std::ranges::none_of(usedGenericTypes, lambda)) usedGenericTypes.emplace_back(templateType); @@ -110,7 +110,7 @@ std::any TypeChecker::visitFctDefPrepare(FctDefNode *node) { // Visit parameters std::vector paramNames; - std::vector paramTypes; + QualTypeList paramTypes; ParamList paramList; if (node->hasParams) { // Visit param list to retrieve the param names @@ -120,7 +120,7 @@ std::any TypeChecker::visitFctDefPrepare(FctDefNode *node) { paramTypes.push_back(param.type); paramList.push_back({param.type, param.isOptional}); // Check if the type is present in the template for generic types - if (!param.type.getType().isCoveredByGenericTypeList(usedGenericTypes)) + if (!param.type.isCoveredByGenericTypeList(usedGenericTypes)) throw SemanticError(node->paramLst(), GENERIC_TYPE_NOT_IN_TEMPLATE, "Generic param type not included in the template type list of the function"); } @@ -131,7 +131,7 @@ std::any TypeChecker::visitFctDefPrepare(FctDefNode *node) { HANDLE_UNRESOLVED_TYPE_PTR(returnType) if (returnType.is(TY_DYN)) SOFT_ERROR_BOOL(node, UNEXPECTED_DYN_TYPE, "Dyn return types are not allowed") - if (!returnType.getType().isCoveredByGenericTypeList(usedGenericTypes)) + if (!returnType.isCoveredByGenericTypeList(usedGenericTypes)) SOFT_ERROR_BOOL(node->returnType(), GENERIC_TYPE_NOT_IN_TEMPLATE, "Generic return type not included in the template type list of the function") @@ -142,8 +142,8 @@ std::any TypeChecker::visitFctDefPrepare(FctDefNode *node) { // Prepare type of function QualType functionType(TY_FUNCTION); functionType.getSpecifiers() = node->specifiers; - functionType.getType().setFunctionReturnType(returnType); - functionType.getType().setFunctionParamTypes(paramTypes); + functionType.setFunctionReturnType(returnType); + functionType.setFunctionParamTypes(paramTypes); // Update type of function entry SymbolTableEntry *functionEntry = currentScope->lookupStrict(node->getSymbolTableEntryName()); @@ -235,7 +235,7 @@ std::any TypeChecker::visitProcDefPrepare(ProcDefNode *node) { thisType = structEntry->getQualType(); thisPtrType = thisType.toPtr(node); // Collect template types of 'this' type - for (const QualType &templateType : thisType.getType().getTemplateTypes()) { + for (const QualType &templateType : thisType.getTemplateTypes()) { const auto lambda = [&](const GenericType &genericType) { return genericType == templateType; }; if (std::ranges::none_of(usedGenericTypes, lambda)) usedGenericTypes.emplace_back(templateType); @@ -252,7 +252,7 @@ std::any TypeChecker::visitProcDefPrepare(ProcDefNode *node) { // Visit parameters std::vector paramNames; - std::vector paramTypes; + QualTypeList paramTypes; ParamList paramList; if (node->hasParams) { // Visit param list to retrieve the param names @@ -262,7 +262,7 @@ std::any TypeChecker::visitProcDefPrepare(ProcDefNode *node) { paramTypes.push_back(param.type); paramList.push_back({param.type, param.isOptional}); // Check if the type is present in the template for generic types - if (!param.type.getType().isCoveredByGenericTypeList(usedGenericTypes)) + if (!param.type.isCoveredByGenericTypeList(usedGenericTypes)) throw SemanticError(node->paramLst(), GENERIC_TYPE_NOT_IN_TEMPLATE, "Generic param type not included in the template type list of the procedure"); } @@ -275,7 +275,7 @@ std::any TypeChecker::visitProcDefPrepare(ProcDefNode *node) { // Prepare type of procedure QualType procedureType(TY_PROCEDURE); procedureType.getSpecifiers() = node->specifiers; - procedureType.getType().setFunctionParamTypes(paramTypes); + procedureType.setFunctionParamTypes(paramTypes); // Update type of procedure entry SymbolTableEntry *procedureEntry = currentScope->lookupStrict(node->getSymbolTableEntryName()); @@ -313,7 +313,7 @@ std::any TypeChecker::visitProcDefPrepare(ProcDefNode *node) { } std::any TypeChecker::visitStructDefPrepare(StructDefNode *node) { - std::vector usedTemplateTypes; + QualTypeList usedTemplateTypes; std::vector templateTypesGeneric; // Retrieve struct template types @@ -337,7 +337,7 @@ std::any TypeChecker::visitStructDefPrepare(StructDefNode *node) { } // Retrieve implemented interfaces - std::vector interfaceTypes; + QualTypeList interfaceTypes; if (node->hasInterfaces) { interfaceTypes.reserve(node->interfaceTypeLst()->dataTypes().size()); for (DataTypeNode *interfaceNode : node->interfaceTypeLst()->dataTypes()) { @@ -350,7 +350,7 @@ std::any TypeChecker::visitStructDefPrepare(StructDefNode *node) { throw SemanticError(interfaceNode, EXPECTED_INTERFACE_TYPE, "Expected interface type, got " + interfaceType.getName(false)); // Check for visibility - if (interfaceType.getType().getBodyScope()->isImportedBy(rootScope) && !interfaceType.isPublic()) + if (interfaceType.getBodyScope()->isImportedBy(rootScope) && !interfaceType.isPublic()) throw SemanticError(node, INSUFFICIENT_VISIBILITY, "Cannot access interface '" + interfaceType.getSubType() + "' due to its private visibility"); // Add to interface types @@ -375,7 +375,7 @@ std::any TypeChecker::visitStructDefPrepare(StructDefNode *node) { assert(currentScope->type == ScopeType::STRUCT); // Retrieve field types - std::vector fieldTypes; + QualTypeList fieldTypes; fieldTypes.reserve(node->fields().size()); for (FieldNode *field : node->fields()) { // Visit field type @@ -385,7 +385,7 @@ std::any TypeChecker::visitStructDefPrepare(StructDefNode *node) { // Check for struct with infinite size. // This can happen if the struct A has a field with type A - if (fieldType.is(TY_STRUCT) && fieldType.getType().getBodyScope() == node->structScope) + if (fieldType.is(TY_STRUCT) && fieldType.getBodyScope() == node->structScope) throw SemanticError(field, STRUCT_INFINITE_SIZE, "Struct with infinite size detected"); // Add to field types @@ -397,7 +397,7 @@ std::any TypeChecker::visitStructDefPrepare(StructDefNode *node) { fieldEntry->updateType(fieldType, false); // Check if the template type list contains this type - if (!fieldType.getType().isCoveredByGenericTypeList(templateTypesGeneric)) + if (!fieldType.isCoveredByGenericTypeList(templateTypesGeneric)) throw SemanticError(field->dataType(), GENERIC_TYPE_NOT_IN_TEMPLATE, "Generic field type not included in struct template"); } @@ -421,7 +421,7 @@ std::any TypeChecker::visitStructDefPrepare(StructDefNode *node) { } std::any TypeChecker::visitInterfaceDefPrepare(InterfaceDefNode *node) { - std::vector usedTemplateTypes; + QualTypeList usedTemplateTypes; std::vector templateTypesGeneric; // Retrieve interface template types @@ -546,7 +546,7 @@ std::any TypeChecker::visitEnumDefPrepare(EnumDefNode *node) { std::any TypeChecker::visitGenericTypeDefPrepare(GenericTypeDefNode *node) { // Retrieve type conditions - std::vector typeConditions; + QualTypeList typeConditions; typeConditions.reserve(node->typeAltsLst()->dataTypes().size()); for (const auto &typeAlt : node->typeAltsLst()->dataTypes()) { auto typeCondition = std::any_cast(visit(typeAlt)); @@ -605,7 +605,7 @@ std::any TypeChecker::visitGlobalVarDefPrepare(GlobalVarDefNode *node) { SOFT_ERROR_BOOL(node->dataType(), GLOBAL_OF_TYPE_DYN, "Global variables must have an explicit data type") // Check if we would need to insert instructions in the global scope to initialize the variable - if (!globalVarType.getType().isPrimitive()) + if (!globalVarType.isPrimitive()) SOFT_ERROR_BOOL(node->dataType(), GLOBAL_OF_INVALID_TYPE, "Spice does only support global variables of primitive type") // Update type of global var entry @@ -621,7 +621,7 @@ std::any TypeChecker::visitGlobalVarDefPrepare(GlobalVarDefNode *node) { std::any TypeChecker::visitExtDeclPrepare(ExtDeclNode *node) { // Collect argument types - std::vector argTypes; + QualTypeList argTypes; ParamList argList; if (node->hasArgs) { argList.reserve(node->argTypeLst()->dataTypes().size()); @@ -670,8 +670,8 @@ std::any TypeChecker::visitExtDeclPrepare(ExtDeclNode *node) { // Prepare ext function type QualType extFunctionType(isFunction ? TY_FUNCTION : TY_PROCEDURE); if (isFunction) - extFunctionType.getType().setFunctionReturnType(returnType); - extFunctionType.getType().setFunctionParamTypes(argTypes); + extFunctionType.setFunctionReturnType(returnType); + extFunctionType.setFunctionParamTypes(argTypes); // Set type of external function node->entry->updateType(extFunctionType, false); diff --git a/src/typechecker/TypeMatcher.cpp b/src/typechecker/TypeMatcher.cpp index b6a2ee3ea..8cb87be7f 100644 --- a/src/typechecker/TypeMatcher.cpp +++ b/src/typechecker/TypeMatcher.cpp @@ -6,9 +6,8 @@ namespace spice::compiler { -bool TypeMatcher::matchRequestedToCandidateTypes(const std::vector &candidateTypes, - const std::vector &reqTypes, TypeMapping &typeMapping, - ResolverFct &resolverFct, bool strictSpecifiers) { +bool TypeMatcher::matchRequestedToCandidateTypes(const QualTypeList &candidateTypes, const QualTypeList &reqTypes, + TypeMapping &typeMapping, ResolverFct &resolverFct, bool strictSpecifiers) { // Check if the size of template types matches if (reqTypes.size() != candidateTypes.size()) return false; @@ -33,7 +32,7 @@ bool TypeMatcher::matchRequestedToCandidateType(QualType candidateType, QualType // If the candidate does not contain any generic parts, we can simply check for type equality if (!candidateType.hasAnyGenericParts()) { // Check if the right one is a struct that implements the interface on the left - if (candidateType.getType().matchesInterfaceImplementedByStruct(requestedType.getType())) + if (candidateType.matchesInterfaceImplementedByStruct(requestedType)) return true; // Normal equality check return candidateType.matches(requestedType, true, !strictSpecifierMatching, true); @@ -85,19 +84,19 @@ bool TypeMatcher::matchRequestedToCandidateType(QualType candidateType, QualType // If we have a function/procedure type, check the param and return types. Otherwise, check the template types if (candidateType.isOneOf({TY_FUNCTION, TY_PROCEDURE})) { // Check param and return types - const std::vector &candidatePRTypes = candidateType.getType().getFunctionParamAndReturnTypes(); - const std::vector &requestedPRTypes = requestedType.getType().getFunctionParamAndReturnTypes(); + const QualTypeList &candidatePRTypes = candidateType.getFunctionParamAndReturnTypes(); + const QualTypeList &requestedPRTypes = requestedType.getFunctionParamAndReturnTypes(); if (!matchRequestedToCandidateTypes(candidatePRTypes, requestedPRTypes, typeMapping, resolverFct, strictSpecifierMatching)) return false; } else { if (requestedType.getSubType() != candidateType.getSubType()) return false; - if (requestedType.getType().getBodyScope()->parent != candidateType.getType().getBodyScope()->parent) + if (requestedType.getBodyScope()->parent != candidateType.getBodyScope()->parent) return false; // Check template types - const std::vector &candidateTTypes = candidateType.getType().getTemplateTypes(); - const std::vector &requestedTTypes = requestedType.getType().getTemplateTypes(); + const QualTypeList &candidateTTypes = candidateType.getTemplateTypes(); + const QualTypeList &requestedTTypes = requestedType.getTemplateTypes(); if (!matchRequestedToCandidateTypes(candidateTTypes, requestedTTypes, typeMapping, resolverFct, strictSpecifierMatching)) return false; } @@ -106,7 +105,7 @@ bool TypeMatcher::matchRequestedToCandidateType(QualType candidateType, QualType } } -void TypeMatcher::substantiateTypesWithTypeMapping(std::vector &qualTypes, const TypeMapping &typeMapping) { +void TypeMatcher::substantiateTypesWithTypeMapping(QualTypeList &qualTypes, const TypeMapping &typeMapping) { for (QualType &qualType : qualTypes) if (qualType.hasAnyGenericParts()) substantiateTypeWithTypeMapping(qualType, typeMapping); @@ -124,20 +123,20 @@ void TypeMatcher::substantiateTypeWithTypeMapping(QualType &type, const TypeMapp } else { // The symbol type itself is non-generic, but one or several template or param types are if (type.getBase().isOneOf({TY_FUNCTION, TY_PROCEDURE})) { // Substantiate each param type - std::vector paramTypes = type.getType().getFunctionParamAndReturnTypes(); + QualTypeList paramTypes = type.getFunctionParamAndReturnTypes(); for (QualType ¶mType : paramTypes) if (paramType.hasAnyGenericParts()) substantiateTypeWithTypeMapping(paramType, typeMapping); // Attach the list of concrete param types to the symbol type - type.getType().setFunctionParamAndReturnTypes(paramTypes); + type.setFunctionParamAndReturnTypes(paramTypes); } else { // Substantiate each template type - std::vector templateTypes = type.getBase().getType().getTemplateTypes(); + QualTypeList templateTypes = type.getBase().getTemplateTypes(); for (QualType &templateType : templateTypes) if (templateType.hasAnyGenericParts()) substantiateTypeWithTypeMapping(templateType, typeMapping); // Attach the list of concrete template types to the symbol type - type.getType().setBaseTemplateTypes(templateTypes); + type.setBaseTemplateTypes(templateTypes); } } } diff --git a/src/typechecker/TypeMatcher.h b/src/typechecker/TypeMatcher.h index fd07e61c6..099f4a0fe 100644 --- a/src/typechecker/TypeMatcher.h +++ b/src/typechecker/TypeMatcher.h @@ -17,11 +17,11 @@ class TypeMatcher { using ResolverFct = std::function; // Public methods - static bool matchRequestedToCandidateTypes(const std::vector &candidateTypes, const std::vector &reqTypes, + static bool matchRequestedToCandidateTypes(const QualTypeList &candidateTypes, const QualTypeList &reqTypes, TypeMapping &typeMapping, ResolverFct &resolverFct, bool strictSpecifiers); static bool matchRequestedToCandidateType(QualType candidateType, QualType requestedType, TypeMapping &typeMapping, ResolverFct &resolverFct, bool strictSpecifierMatching); - static void substantiateTypesWithTypeMapping(std::vector &qualTypes, const TypeMapping &typeMapping); + static void substantiateTypesWithTypeMapping(QualTypeList &qualTypes, const TypeMapping &typeMapping); static void substantiateTypeWithTypeMapping(QualType &type, const TypeMapping &typeMapping); };