From 19f0031dfa806e20a3df63a90f49bcb638362fdf Mon Sep 17 00:00:00 2001 From: ASDAlexander77 Date: Mon, 13 Jul 2026 12:06:51 +0100 Subject: [PATCH] Move access/call family out-of-line into MLIRGenAccessCall.cpp (review doc 1) 33 property/element-access and call/new methods (property access overloads + logic + base logic, class members/accessor/index/generic- method/base-class access, interface members, extension functions, element access, call expression/builtin/this-method/constructor, iterator next, spread operands, class instantiation family) move from MLIRGenImpl.h into a new MLIRGenAccessCall.cpp TU; header keeps declarations. mlirGenElementAccessTuple and mlirGenCallFunction templates stay inline. 1500 lines out of the header (13402 -> 11902). Extractor: K&R-brace signatures now handled (decl gets ");", def gets ")" plus a normalized brace line). Co-Authored-By: Claude Fable 5 --- tslang/lib/TypeScript/CMakeLists.txt | 1 + tslang/lib/TypeScript/MLIRGenAccessCall.cpp | 1606 ++++++++++++++++++ tslang/lib/TypeScript/MLIRGenImpl.h | 1677 ++----------------- 3 files changed, 1703 insertions(+), 1581 deletions(-) create mode 100644 tslang/lib/TypeScript/MLIRGenAccessCall.cpp diff --git a/tslang/lib/TypeScript/CMakeLists.txt b/tslang/lib/TypeScript/CMakeLists.txt index db27e58a..163fddcc 100644 --- a/tslang/lib/TypeScript/CMakeLists.txt +++ b/tslang/lib/TypeScript/CMakeLists.txt @@ -17,6 +17,7 @@ add_mlir_dialect_library(MLIRTypeScript AsyncDialectTranslation.cpp DiagnosticHelper.cpp MLIRGen.cpp + MLIRGenAccessCall.cpp MLIRGenCast.cpp MLIRGenClasses.cpp MLIRGenExpressions.cpp diff --git a/tslang/lib/TypeScript/MLIRGenAccessCall.cpp b/tslang/lib/TypeScript/MLIRGenAccessCall.cpp new file mode 100644 index 00000000..7976c84e --- /dev/null +++ b/tslang/lib/TypeScript/MLIRGenAccessCall.cpp @@ -0,0 +1,1606 @@ +// Property/element access and call/new code generation methods of MLIRGenImpl (see MLIRGenImpl.h). + +#include "MLIRGenImpl.h" + +namespace typescript +{ +namespace mlirgen +{ + + ValueOrLogicalResult MLIRGenImpl::mlirGenCallThisMethod(mlir::Location location, mlir::Value thisValue, StringRef methodName, + NodeArray typeArguments, NodeArray arguments, + const GenContext &genContext) + { + // to remove temp var after call + SymbolTableScopeT varScope(symbolTable); + + auto varDecl = std::make_shared(THIS_TEMPVAR_NAME, thisValue.getType(), location); + DECLARE(varDecl, thisValue); + + NodeFactory nf(NodeFactoryFlags::None); + + auto thisToken = nf.createIdentifier(S(THIS_TEMPVAR_NAME)); + auto callLogic = nf.createCallExpression( + nf.createPropertyAccessExpression(thisToken, nf.createIdentifier(stows(methodName.str()))), typeArguments, + arguments); + + return mlirGen(callLogic, genContext); + } + + ValueOrLogicalResult MLIRGenImpl::mlirGenPropertyAccessExpression(mlir::Location location, mlir::Value objectValue, + mlir::StringRef name, const GenContext &genContext) + { + assert(objectValue); + MLIRPropertyAccessCodeLogic cl(compileOptions, builder, location, objectValue, name); + return mlirGenPropertyAccessExpressionLogic(location, objectValue, false, cl, genContext); + } + + ValueOrLogicalResult MLIRGenImpl::mlirGenPropertyAccessExpression(mlir::Location location, mlir::Value objectValue, + mlir::StringRef name, bool isConditional, + const GenContext &genContext) + { + assert(objectValue); + MLIRPropertyAccessCodeLogic cl(compileOptions, builder, location, objectValue, name); + return mlirGenPropertyAccessExpressionLogic(location, objectValue, isConditional, cl, genContext); + } + + ValueOrLogicalResult MLIRGenImpl::mlirGenPropertyAccessExpression(mlir::Location location, mlir::Value objectValue, + mlir::Attribute id, const GenContext &genContext) + { + MLIRPropertyAccessCodeLogic cl(compileOptions, builder, location, objectValue, id); + return mlirGenPropertyAccessExpressionLogic(location, objectValue, false, cl, genContext); + } + + ValueOrLogicalResult MLIRGenImpl::mlirGenPropertyAccessExpression(mlir::Location location, mlir::Value objectValue, + mlir::Attribute id, bool isConditional, + const GenContext &genContext) + { + MLIRPropertyAccessCodeLogic cl(compileOptions, builder, location, objectValue, id); + return mlirGenPropertyAccessExpressionLogic(location, objectValue, isConditional, cl, genContext); + } + + ValueOrLogicalResult MLIRGenImpl::mlirGenPropertyAccessExpression(mlir::Location location, mlir::Value objectValue, + mlir::Attribute id, bool isConditional, + mlir::Value argument/*for index access*/, + const GenContext &genContext) + { + MLIRPropertyAccessCodeLogic cl(compileOptions, builder, location, objectValue, id, argument); + return mlirGenPropertyAccessExpressionLogic(location, objectValue, isConditional, cl, genContext); + } + + ValueOrLogicalResult MLIRGenImpl::mlirGenPropertyAccessExpressionLogic(mlir::Location location, mlir::Value objectValue, + bool isConditional, MLIRPropertyAccessCodeLogic &cl, + const GenContext &genContext) + { + if (isConditional && MLIRTypeCore::isNullableOrOptionalType(objectValue.getType())) + { + // TODO: replace with one op "Optional , " + CAST_A(condValue, location, getBooleanType(), objectValue, genContext); + + auto propType = evaluateProperty(location, objectValue, cl.getName().str(), genContext); + if (!propType) + { + emitError(location, "Can't resolve property '") << cl.getName() << "' of type " << to_print(objectValue.getType()); + return mlir::failure(); + } + + auto ifOp = builder.create(location, getOptionalType(propType), condValue, true); + + builder.setInsertionPointToStart(&ifOp.getThenRegion().front()); + + // value if true + auto result = mlirGenPropertyAccessExpressionBaseLogic(location, objectValue, cl, genContext); + auto value = V(result); + + // special case: conditional extension function ?.(); + if (auto createExtentionFunction = value.getDefiningOp()) + { + // we need to convert into CreateBoundFunction, so it should be reference type for this, do I need to case value type into reference type? + value = createBoundMethodFromExtensionMethod(location, createExtentionFunction); + ifOp.getResults().front().setType(getOptionalType(value.getType())); + } + + auto optValue = isa(value.getType()) + ? value : builder.create(location, getOptionalType(value.getType()), value); + builder.create(location, mlir::ValueRange{optValue}); + + // else + builder.setInsertionPointToStart(&ifOp.getElseRegion().front()); + + auto optUndefValue = builder.create(location, getOptionalType(value.getType())); + builder.create(location, mlir::ValueRange{optUndefValue}); + + builder.setInsertionPointAfter(ifOp); + + return ifOp.getResults().front(); + } + else + { + return mlirGenPropertyAccessExpressionBaseLogic(location, objectValue, cl, genContext); + } + } + + ValueOrLogicalResult MLIRGenImpl::mlirGenPropertyAccessExpressionBaseLogic(mlir::Location location, mlir::Value objectValue, + MLIRPropertyAccessCodeLogic &cl, + const GenContext &genContext) + { + auto name = cl.getName(); + auto argument = cl.getArgument(); + auto actualType = objectValue.getType(); + + LLVM_DEBUG(llvm::dbgs() << "\n\tResolving property '" << name << "' of type " << objectValue.getType();); + + // load reference if needed, except TupleTuple, ConstTupleType + if (auto refType = dyn_cast(actualType)) + { + auto elementType = refType.getElementType(); + if (!isa(elementType) && !isa(elementType)) + { + objectValue = builder.create(location, elementType, objectValue); + actualType = objectValue.getType(); + } + } + + // collapse union type + if (auto unionType = dyn_cast(actualType)) + { + mlir::Type baseType; + if (!mth.isUnionTypeNeedsTag(location, unionType, baseType)) + { + LLVM_DEBUG(llvm::dbgs() << "\n!! mlirGenPropertyAccessExpressionBaseLogic: union type " << baseType << "\n";); + actualType = baseType; + } + } + + // class member access + auto classAccessWithObject = [&](mlir_ts::ClassType classType, mlir::Value objectValue) { + + LLVM_DEBUG(llvm::dbgs() << "\n\t...field: \t" << cl.getName();); + auto accessingFromLevel = detectAccessLevel(classType, genContext); + LLVM_DEBUG(llvm::dbgs() << "\n\t = Accessing from level '" << accessingFromLevel << "'\n\n";); + + if (auto value = cl.Class(classType, accessingFromLevel)) + { + return value; + } + + return ClassMembersAccess(location, objectValue, classType.getName().getValue(), name, + false, argument, accessingFromLevel, genContext); + }; + + auto classAccess = [&](mlir_ts::ClassType classType) { + return classAccessWithObject(classType, objectValue); + }; + + auto castFn = [this](mlir::Location location, mlir::Type type, mlir::Value value, const GenContext &genContext, bool disableStrictNullCheck) { return cast(location, type, value, genContext, disableStrictNullCheck); }; + + mlir::Value value = + mlir::TypeSwitch(actualType) + .Case([&](auto enumType) { return cl.Enum(enumType); }) + .Case([&](auto constTupleType) { return cl.Tuple(constTupleType); }) + .Case([&](auto tupleType) { return cl.Tuple(tupleType); }) + .Case([&](auto stringType) { + if (auto value = cl.String(stringType)) + { + return value; + } + + return mlir::Value(); + }) + .Case([&](auto arrayType) { +#ifdef ARRAY_TYPE_AS_ARRAY_CLASS + if (auto genericClassTypeInfo = getGenericClassInfoByFullName("Array")) + { + auto classType = genericClassTypeInfo->classType; + SmallVector typeArg{arrayType.getElementType()}; + auto [result, specType] = instantiateSpecializedClassType(location, classType, + typeArg, genContext, true); + auto accessFailed = false; + if (mlir::succeeded(result)) + { + auto arrayNonConst = cast(location, mlir_ts::ArrayType::get(arrayType.getElementType()), objectValue, genContext); + if (arrayNonConst.failed()) + { + return mlir::Value(); + } + + if (auto value = classAccessWithObject(mlir::cast(specType), arrayNonConst)) + { + return value; + } + + accessFailed = true; + } + + if (mlir::failed(result) && !accessFailed) + { + genContext.stop(); + return mlir::Value(); + } + + genContext.postponedMessages->clear(); + } +#endif + + // find Array type + // TODO: should I mix use of Array and Array? + // if (auto classInfo = getClassInfoByFullName("Array")) + // { + // return classAccess(classInfo->classType); + // } + + if (auto value = cl.Array(arrayType, compileOptions, castFn, genContext)) + { + return value; + } + + return mlir::Value(); + }) + .Case([&](auto arrayType) { +#ifdef ARRAY_TYPE_AS_ARRAY_CLASS + if (auto genericClassTypeInfo = getGenericClassInfoByFullName("Array")) + { + auto classType = genericClassTypeInfo->classType; + SmallVector typeArg{arrayType.getElementType()}; + auto [result, specType] = instantiateSpecializedClassType(location, classType, + typeArg, genContext, true); + auto accessFailed = false; + if (mlir::succeeded(result)) + { + if (auto value = classAccess(mlir::cast(specType))) + { + return value; + } + + accessFailed = true; + } + + if (mlir::failed(result) && !accessFailed) + { + genContext.stop(); + return mlir::Value(); + } + + genContext.postponedMessages->clear(); + } +#endif + // find Array type + // TODO: should I mix use of Array and Array? + // if (auto classInfo = getClassInfoByFullName("Array")) + // { + // return classAccess(classInfo->classType); + // } + + if (auto value = cl.Array(arrayType, compileOptions, castFn, genContext)) + { + return value; + } + + return mlir::Value(); + }) + .Case([&](auto refType) { return cl.Ref(refType); }) + .Case([&](auto objectType) { + if (auto value = cl.Object(objectType)) + { + return value; + } + + return mlir::Value(); + }) + .Case([&](auto objectStorageType) { + if (auto value = cl.RefLogic(objectStorageType)) + { + return value; + } + + return mlir::Value(); + }) + .Case([&](auto symbolType) { return cl.Symbol(symbolType); }) + .Case([&](auto namespaceType) { + auto namespaceInfo = getNamespaceByFullName(namespaceType.getName().getValue()); + assert(namespaceInfo); + + MLIRNamespaceGuard ng(currentNamespace); + currentNamespace = namespaceInfo; + + return mlirGen(location, name, genContext); + }) + .Case([&](auto classStorageType) { + LLVM_DEBUG(llvm::dbgs() << "\n\t...field: \t" << cl.getName();); + auto accessingFromLevel = detectAccessLevel(classStorageType, genContext); + LLVM_DEBUG(llvm::dbgs() << "\n\t = Accessing from level '" << accessingFromLevel << "'\n\n";); + + if (auto value = cl.TupleNoError(classStorageType, accessingFromLevel)) + { + return value; + } + + return ClassMembersAccess(location, objectValue, + classStorageType.getName().getValue(), name, true, argument, accessingFromLevel, genContext); + }) + .Case(classAccess) + .Case([&](auto interfaceType) { + return InterfaceMembers( + location, objectValue, interfaceType.getName().getValue(), cl.getAttribute(), + argument, genContext); + }) + .Case([&](auto optionalType) { + // this is needed for conditional access to properties + auto elementType = optionalType.getElementType(); + auto loadedValue = builder.create(location, elementType, objectValue); + return mlirGenPropertyAccessExpression(location, loadedValue, name, false, genContext); + }) + .Case([&](auto unionType) { + // TODO: when access of property in union is finished use it instead of using first type + // all union types must have the same property + // 1) cast to first type + auto frontType = mth.getFirstNonNullUnionType(unionType); + //auto casted = cast(location, frontType, objectValue, genContext); + auto casted = builder.create(location, frontType, objectValue); + + return mlirGenPropertyAccessExpression(location, casted, name, false, genContext); + }) + .Case([&](auto literalType) { + auto elementType = literalType.getElementType(); + auto castedValue = builder.create(location, elementType, objectValue); + return mlirGenPropertyAccessExpression(location, castedValue, name, false, genContext); + }) + .Default([&](auto type) { + LLVM_DEBUG(llvm::dbgs() << "\n\tCan't resolve property '" << name << "' of type " << objectValue.getType();); + return mlir::Value(); + }); + + // extention logic: .(this) + if (!value) + { + if (auto funcRef = extensionFunction(location, objectValue, name, genContext)) + { + return funcRef; + } + } + + if (!value) + { + emitError(location, "Can't resolve property '") << name << "' of type " << to_print(objectValue.getType()); + return mlir::failure(); + } + + return value; + } + + mlir::Value MLIRGenImpl::extensionFunctionLogic(mlir::Location location, mlir::Value funcRef, mlir::Value thisValue, StringRef name, + const GenContext &genContext) + { + if (!mth.isAnyFunctionType(funcRef.getType())) + { + return mlir::Value(); + } + + LLVM_DEBUG(llvm::dbgs() << "!! found extension by name for type: " << thisValue.getType() + << " function: " << name << ", value: " << funcRef << "\n";); + + auto thisTypeFromFunc = mth.getFirstParamFromFuncRef(funcRef.getType()); + + LLVM_DEBUG(llvm::dbgs() << "!! this type of function is : " << thisTypeFromFunc << "\n";); + + if (auto symbolOp = funcRef.getDefiningOp()) + { + // if (!isa(symbolOp.getType())) + if (!symbolOp->hasAttrOfType(GENERIC_ATTR_NAME)) + { + auto funcType = mlir::cast(funcRef.getType()); + if (thisTypeFromFunc == thisValue.getType()) + { + // return funcRef; + auto thisRef = thisValue; + auto extensFuncVal = builder.create( + location, getExtensionFunctionType(funcType), thisRef, funcRef); + return extensFuncVal; + } + } + else + { + // TODO: add checking constraint + auto funcName = symbolOp.getIdentifierAttr().getValue(); + auto functionGenericTypeInfo = getGenericFunctionInfoByFullName(funcName); + auto first = functionGenericTypeInfo->typeParams.front(); + if (first->hasConstraint()) + { + if (auto constraintType = getType(first->getConstraint(), genContext)) + { + llvm::StringMap> pairs{}; + auto extendsResult = mth.extendsType(location, thisValue.getType(), constraintType, pairs); + if (extendsResult == ExtendsResult::False || extendsResult == ExtendsResult::Never) + { + // failed due to generic type constraints + return mlir::Value(); + } + } + } + + // TODO: finish it + // it is generic function + StringMap inferredTypes; + inferType(location, thisTypeFromFunc, thisValue.getType(), inferredTypes, genContext); + if (inferredTypes.size() > 0) + { + // we found needed function + // return funcRef; + auto thisRef = thisValue; + + LLVM_DEBUG(llvm::dbgs() << "\n!! recreate ExtensionFunctionOp (generic interface): '" << name << "'\n this ref: '" << thisRef << "'\n func ref: '" << funcRef + << "'\n";); + + auto funcType = mlir::cast(funcRef.getType()); + auto extensFuncVal = builder.create( + location, getExtensionFunctionType(funcType), thisRef, funcRef); + return extensFuncVal; + } + } + } + + return mlir::Value(); + } + + mlir::Value MLIRGenImpl::ClassMembersAccess(mlir::Location location, mlir::Value thisValue, mlir::StringRef classFullName, + mlir::StringRef name, bool baseClass, mlir::Value argument, mlir_ts::AccessLevel accessingFromLevel, const GenContext &genContext) + { + auto classInfo = getClassInfoByFullName(classFullName); + if (!classInfo) + { + auto genericClassInfo = getGenericClassInfoByFullName(classFullName); + if (genericClassInfo) + { + // we can't discover anything in generic class + return mlir::Value(); + } + + emitError(location, "Class can't be found ") << classFullName; + return mlir::Value(); + } + + // static field access + auto value = ClassMembersAccess(location, thisValue, classInfo, name, baseClass, argument, accessingFromLevel, genContext); + if (!value) + { + emitError(location, "Class member '") << name << "' can't be found"; + } + + return value; + } + + mlir::Value MLIRGenImpl::ClassGenericMethodAccess(ClassInfo::TypePtr classInfo, + mlir::Location location, mlir::Value thisValue, int genericMethodIndex, + bool isSuperClass, mlir_ts::AccessLevel accessingFromLevel, const GenContext &genContext) + { + auto genericMethodInfo = classInfo->staticGenericMethods[genericMethodIndex]; + if (accessingFromLevel < genericMethodInfo.accessLevel) { + emitError(location, "Class member '") << genericMethodInfo.name << "' is not accessable"; + return mlir::Value(); + } + + auto paramsArray = genericMethodInfo.funcProto->getParams(); + auto explicitThis = paramsArray.size() > 0 && paramsArray.front()->getName() == THIS_NAME; + if (genericMethodInfo.isStatic && !explicitThis) + { + auto funcSymbolOp = builder.create( + location, genericMethodInfo.funcType, + mlir::FlatSymbolRefAttr::get(builder.getContext(), genericMethodInfo.funcProto->getName())); + funcSymbolOp->setAttr(GENERIC_ATTR_NAME, mlir::BoolAttr::get(builder.getContext(), true)); + return funcSymbolOp; + } + else + { + auto effectiveThisValue = getThisRefOfClass(location, classInfo->classType, thisValue, isSuperClass, genContext); + auto effectiveFuncType = genericMethodInfo.funcProto->getFuncType(); + + auto thisSymbOp = builder.create( + location, getBoundFunctionType(effectiveFuncType), effectiveThisValue, + mlir::FlatSymbolRefAttr::get(builder.getContext(), genericMethodInfo.funcProto->getName())); + thisSymbOp->setAttr(GENERIC_ATTR_NAME, mlir::BoolAttr::get(builder.getContext(), true)); + return thisSymbOp; + } + } + + mlir::Value MLIRGenImpl::ClassAccessorAccess(ClassInfo::TypePtr classInfo, + mlir::Location location, mlir::Value thisValue, int accessorIndex, mlir_ts::AccessLevel accessingFromLevel, const GenContext &genContext) + { + + auto accessorInfo = classInfo->accessors[accessorIndex]; + + // TODO: finish access check for get/set methods + + auto getFunc = accessorInfo.get; + auto setFunc = accessorInfo.set; + mlir::Type accessorResultType; + if (getFunc) + { + auto funcType = getFunc.funcType; + if (funcType.getNumResults() > 0) + { + accessorResultType = funcType.getResult(0); + } + } + + if (!accessorResultType && setFunc) + { + accessorResultType = setFunc.funcType.getInput(accessorInfo.isStatic ? 0 : 1); + } + + if (!accessorResultType) + { + emitError(location) << "can't resolve type of property"; + return mlir::Value(); + } + + // remove funcs if access level is not high + if (getFunc && accessingFromLevel < accessorInfo.getAccessLevel) { + getFunc = {}; + } + if (setFunc && accessingFromLevel < accessorInfo.setAccessLevel) { + setFunc = {}; + } + + if (accessorInfo.isStatic) + { + auto accessorOp = builder.create( + location, accessorResultType, + getFunc ? mlir::FlatSymbolRefAttr::get(builder.getContext(), getFunc.name) + : mlir::FlatSymbolRefAttr{}, + setFunc ? mlir::FlatSymbolRefAttr::get(builder.getContext(), setFunc.name) + : mlir::FlatSymbolRefAttr{}, + mlir::Value()); + return accessorOp.getResult(0); + } + else + { + auto thisAccessorOp = builder.create( + location, accessorResultType, thisValue, + getFunc ? mlir::FlatSymbolRefAttr::get(builder.getContext(), getFunc.name) + : mlir::FlatSymbolRefAttr{}, + setFunc ? mlir::FlatSymbolRefAttr::get(builder.getContext(), setFunc.name) + : mlir::FlatSymbolRefAttr{}, + mlir::Value()); + return thisAccessorOp.getResult(0); + } + + } + + mlir::Value MLIRGenImpl::ClassIndexAccess(ClassInfo::TypePtr classInfo, + mlir::Location location, mlir::Value thisValue, mlir::Value argument, mlir_ts::AccessLevel accessingFromLevel, const GenContext &genContext) + { + + if (classInfo->indexes.size() == 0) + { + emitError(location) << "indexer is not declared"; + return mlir::Value(); + } + + auto indexInfo = classInfo->indexes.front(); + auto getFunc = indexInfo.get; + auto setFunc = indexInfo.set; + + if (!indexInfo.indexSignature || indexInfo.indexSignature.getNumResults() == 0) + { + emitError(location) << "can't resolve type of indexer"; + return mlir::Value(); + } + + // remove funcs if access level is not high + if (getFunc && accessingFromLevel < indexInfo.getAccessLevel) { + getFunc = {}; + } + if (setFunc && accessingFromLevel < indexInfo.setAccessLevel) { + setFunc = {}; + } + + auto indexResultType = indexInfo.indexSignature.getResult(0); + auto argumentType = indexInfo.indexSignature.getInput(0); + + // sync index + CAST_A(result, location, argumentType, argument, genContext); + + auto thisIndexAccessorOp = builder.create( + location, indexResultType, thisValue, V(result), + getFunc ? mlir::FlatSymbolRefAttr::get(builder.getContext(), getFunc.name) + : mlir::FlatSymbolRefAttr{}, + setFunc ? mlir::FlatSymbolRefAttr::get(builder.getContext(), setFunc.name) + : mlir::FlatSymbolRefAttr{}, + mlir::Value()); + return thisIndexAccessorOp.getResult(0); + } + + mlir::Value MLIRGenImpl::ClassBaseClassAccess(ClassInfo::TypePtr classInfo, ClassInfo::TypePtr baseClass, int index, + mlir::Location location, mlir::Value thisValue, StringRef name, mlir::Value argument, mlir_ts::AccessLevel accessingFromLevel, const GenContext &genContext) + { + + // first base is "super." + if (index == 0 && name == SUPER_NAME) + { + auto result = mlirGenPropertyAccessExpression(location, thisValue, baseClass->fullName, genContext); + auto value = V(result); + return value; + } + + auto value = ClassMembersAccess(location, thisValue, baseClass, name, true, argument, accessingFromLevel, genContext); + if (value) + { + return value; + } + + SmallVector fieldPath; + if (classHasField(baseClass, name, fieldPath)) + { + // load value from path + auto currentObject = thisValue; + for (auto &chain : fieldPath) + { + auto fieldValue = + mlirGenPropertyAccessExpression(location, currentObject, chain->fullName, genContext); + if (!fieldValue) + { + emitError(location) << "Can't resolve field/property/base '" << chain->fullName + << "' of class '" << classInfo->fullName << "'\n"; + return fieldValue; + } + + assert(fieldValue); + currentObject = fieldValue; + } + + // last value + auto result = mlirGenPropertyAccessExpression(location, currentObject, name, genContext); + auto value = V(result); + if (value) + { + return value; + } + } + + return mlir::Value(); + } + + mlir::Value MLIRGenImpl::ClassMembersAccess(mlir::Location location, mlir::Value thisValue, ClassInfo::TypePtr classInfo, + mlir::StringRef name, bool isSuperClass, mlir::Value argument, mlir_ts::AccessLevel accessingFromLevel, const GenContext &genContext) + { + assert(classInfo); + + LLVM_DEBUG(llvm::dbgs() << "\n\t looking for member: " << name << " in class '" << classInfo->fullName << "'\n";); + + // indexer access + if (name == INDEX_ACCESS_FIELD_NAME) + { + if (!classInfo->indexes.empty()) + { + return ClassIndexAccess(classInfo, location, thisValue, argument, accessingFromLevel, genContext); + } + } + + auto staticFieldIndex = classInfo->getStaticFieldIndex( + MLIRHelper::TupleFieldName(name, builder.getContext())); + if (staticFieldIndex >= 0) + { + return ClassStaticFieldAccess(classInfo, location, thisValue, staticFieldIndex, accessingFromLevel, genContext); + } + + // check method access + auto methodIndex = classInfo->getMethodIndex(name); + if (methodIndex >= 0) + { + return ClassMethodAccess(classInfo, location, thisValue, methodIndex, isSuperClass, accessingFromLevel, genContext); + } + + // static generic methods + auto genericMethodIndex = classInfo->getGenericMethodIndex(name); + if (genericMethodIndex >= 0) + { + return ClassGenericMethodAccess(classInfo, location, thisValue, genericMethodIndex, isSuperClass, accessingFromLevel, genContext); + } + + // check accessor + auto accessorIndex = classInfo->getAccessorIndex(name); + if (accessorIndex >= 0) + { + return ClassAccessorAccess(classInfo, location, thisValue, accessorIndex, accessingFromLevel, genContext); + } + + for (auto [index, baseClass] : enumerate(classInfo->baseClasses)) + { + auto effectiveAccessingFromLevel = accessingFromLevel == mlir_ts::AccessLevel::Private + ? mlir_ts::AccessLevel::Protected : accessingFromLevel; + auto value = ClassBaseClassAccess(classInfo, baseClass, index, location, + thisValue, name, argument, effectiveAccessingFromLevel, genContext); + if (value) + { + return value; + } + } + + if (isSuperClass || genContext.allowPartialResolve) + { + return mlir::Value(); + } + + emitError(location) << "can't resolve property/field/base '" << name << "' of class '" << classInfo->fullName + << "'\n"; + + return mlir::Value(); + } + + mlir::Value MLIRGenImpl::InterfaceMembers(mlir::Location location, mlir::Value interfaceValue, mlir::StringRef interfaceFullName, + mlir::Attribute id, mlir::Value argument, const GenContext &genContext) + { + auto interfaceInfo = getInterfaceInfoByFullName(interfaceFullName); + if (!interfaceInfo) + { + auto genericInterfaceInfo = getGenericInterfaceInfoByFullName(interfaceFullName); + if (genericInterfaceInfo) + { + // we can't detect value of generic interface (we can only if it is specialization) + emitError(location, "Interface can't be found ") << interfaceFullName; + return mlir::Value(); + } + + return mlir::Value(); + } + + assert(interfaceInfo); + + // static field access + auto value = InterfaceMembers(location, interfaceValue, interfaceInfo, id, argument, genContext); + if (!value) + { + emitError(location, "Interface member ") << id << " can't be found in interface '" << interfaceInfo->name << "'"; + } + + return value; + } + + mlir::Value MLIRGenImpl::InterfaceMembers(mlir::Location location, mlir::Value interfaceValue, InterfaceInfo::TypePtr interfaceInfo, + mlir::Attribute id, mlir::Value argument, const GenContext &genContext) + { + assert(interfaceInfo); + + // indexer access + auto nameAttr = mlir::dyn_cast(id); + if (nameAttr && nameAttr.getValue() == INDEX_ACCESS_FIELD_NAME) + { + return InterfaceIndexAccess(interfaceInfo, location, interfaceValue, argument, genContext); + } + + // check field access + if (auto fieldInfo = interfaceInfo->findField(id)) + { + return InterfaceFieldAccess(location, interfaceValue, fieldInfo); + } + + // check method access + if (nameAttr) + { + if (auto methodInfo = interfaceInfo->findMethod(nameAttr.getValue())) + { + return InterfaceMethodAccess(location, interfaceValue, methodInfo); + } + + if (auto accessorInfo = interfaceInfo->findAccessor(nameAttr.getValue())) + { + return InterfaceAccessorAccess(location, interfaceInfo, interfaceValue, accessorInfo, genContext); + } + + } + + return mlir::Value(); + } + + ValueOrLogicalResult MLIRGenImpl::mlirGenElementAccess(mlir::Location location, mlir::Value expression, mlir::Value argumentExpression, bool isConditionalAccess, const GenContext &genContext) + { + auto arrayType = expression.getType(); + + // collapse union type + if (auto unionType = dyn_cast(expression.getType())) + { + mlir::Type baseType; + if (!mth.isUnionTypeNeedsTag(location, unionType, baseType)) + { + LLVM_DEBUG(llvm::dbgs() << "\n!! ElementAccessExpression: union type " << baseType << "\n";); + arrayType = baseType; + } + } + + if (isa(arrayType)) + { + arrayType = mth.stripLiteralType(arrayType); + CAST(expression, location, arrayType, expression, genContext); + } + + if (auto optType = dyn_cast(arrayType)) + { + arrayType = optType.getElementType(); + // loading value from opt value + expression = builder.create(location, arrayType, expression); + } + + mlir::Type elementType; + if (auto arrayTyped = dyn_cast(arrayType)) + { + if (auto fieldName = argumentExpression.getDefiningOp()) + { + auto attr = fieldName.getValue(); + if (isa(attr)) + { + return mlirGenPropertyAccessExpression(location, expression, attr, isConditionalAccess, genContext); + } + } + + elementType = arrayTyped.getElementType(); + } + else if (auto vectorType = dyn_cast(arrayType)) + { + if (auto fieldName = argumentExpression.getDefiningOp()) + { + auto attr = fieldName.getValue(); + if (isa(attr)) + { + return mlirGenPropertyAccessExpression(location, expression, attr, isConditionalAccess, genContext); + } + } + + elementType = vectorType.getElementType(); + } + else if (isa(arrayType)) + { + elementType = getCharType(); + } + else if (auto tupleType = dyn_cast(arrayType)) + { + return mlirGenElementAccessTuple(location, expression, argumentExpression, tupleType); + } + else if (auto constTupleType = dyn_cast(arrayType)) + { + return mlirGenElementAccessTuple(location, expression, argumentExpression, constTupleType); + } + else if (auto classType = dyn_cast(arrayType)) + { + if (auto fieldName = argumentExpression.getDefiningOp()) + { + auto attr = fieldName.getValue(); + if (isa(attr)) + { + // TODO: implement '[string]' access here + return mlirGenPropertyAccessExpression(location, expression, attr, isConditionalAccess, genContext); + } + } + + // else access of index + auto indexAccessor = builder.getStringAttr(INDEX_ACCESS_FIELD_NAME); + return mlirGenPropertyAccessExpression(location, expression, indexAccessor, isConditionalAccess, argumentExpression, genContext); + } + else if (auto classStorageType = dyn_cast(arrayType)) + { + // seems we are calling "super" + if (auto fieldName = argumentExpression.getDefiningOp()) + { + auto attr = fieldName.getValue(); + return mlirGenPropertyAccessExpression(location, expression, attr, isConditionalAccess, genContext); + } + + llvm_unreachable("not implemented (ElementAccessExpression)"); + } + else if (auto interfaceType = dyn_cast(arrayType)) + { + if (auto fieldName = argumentExpression.getDefiningOp()) + { + auto attr = fieldName.getValue(); + if (isa(attr)) + { + return mlirGenPropertyAccessExpression(location, expression, attr, isConditionalAccess, genContext); + } + } + + // else access of index + auto indexAccessor = builder.getStringAttr(INDEX_ACCESS_FIELD_NAME); + return mlirGenPropertyAccessExpression(location, expression, indexAccessor, isConditionalAccess, argumentExpression, genContext); + } + else if (auto enumType = dyn_cast(arrayType)) + { + if (auto fieldName = argumentExpression.getDefiningOp()) + { + auto attr = fieldName.getValue(); + return mlirGenPropertyAccessExpression(location, expression, attr, isConditionalAccess, genContext); + } + + llvm_unreachable("not implemented (ElementAccessExpression)"); + } + else if (auto refType = dyn_cast(arrayType)) + { + CAST_A(index, location, mth.getIndexType(), argumentExpression, genContext); + + LLVM_DEBUG(llvm::dbgs() << "\n!! ref type: " << refType << " index value: " << index << "\n";); + + auto elemRef = builder.create( + location, refType, expression, index); + + return V(elemRef); + } + else if (auto anyType = dyn_cast(arrayType)) + { + emitError(location, "not supported"); + return mlir::failure(); + } + else + { + LLVM_DEBUG(llvm::dbgs() << "\n!! ElementAccessExpression: " << arrayType + << "\n";); + + emitError(location) << "access expression is not applicable to " << to_print(arrayType); + return mlir::failure(); + } + + auto indexType = argumentExpression.getType(); + CAST(argumentExpression, location, mth.getStructIndexType(), argumentExpression, genContext); + + auto elemRef = builder.create(location, mlir_ts::RefType::get(elementType), expression, + argumentExpression); + return V(builder.create(location, elementType, elemRef)); + } + + ValueOrLogicalResult MLIRGenImpl::mlirGenArrayReduce(mlir::Location location, SmallVector &operands, + const GenContext &genContext) + { + // info, we add "_" extra as scanner append "_" in front of "__"; + auto funcName = "___array_reduce"; + + if (!existGenericFunctionMap(funcName)) + { + auto src = S("function __array_reduce(arr: T[], f: (s: R, v: T) => R, init: R) \ + { \ + let r = init; \ + for (const v of arr) r = f(r, v); \ + return r; \ + }"); + + { + MLIRLocationGuard vgLoc(overwriteLoc); + overwriteLoc = location; + if (mlir::failed(parsePartialStatements(src))) + { + assert(false); + return mlir::failure(); + } + } + } + + auto funcResult = resolveIdentifier(location, funcName, genContext); + + assert(funcResult); + + return mlirGenCallExpression(location, funcResult, {}, operands, genContext); + } + + ValueOrLogicalResult MLIRGenImpl::mlirGenCallBuiltInFunction( + mlir::Location location, mlir::Value actualFuncRefValue, NodeArray typeArguments, + SmallVector &operands, const GenContext &genContext) + { + // TODO: when you resolve names such as "print", "parseInt" should return names in mlirGen(Identifier) + auto calleeName = actualFuncRefValue.getDefiningOp()->getAttrOfType(StringRef(IDENTIFIER_ATTR_NAME)); + auto functionName = calleeName.getValue(); + + if (auto thisSymbolRefOp = actualFuncRefValue.getDefiningOp()) + { + // do not remove it, it is needed for custom methods to be called correctly + operands.insert(operands.begin(), thisSymbolRefOp.getThisVal()); + } + + // temp hack + if (functionName == "__array_foreach") + { + mlirGenArrayForEach(location, operands, genContext); + return mlir::success(); + } + + if (functionName == "__array_every") + { + return mlirGenArrayEvery(location, operands, genContext); + } + + if (functionName == "__array_some") + { + return mlirGenArraySome(location, operands, genContext); + } + + if (functionName == "__array_map") + { + return mlirGenArrayMap(location, operands, genContext); + } + + if (functionName == "__array_filter") + { + return mlirGenArrayFilter(location, operands, genContext); + } + + if (functionName == "__array_reduce") + { + return mlirGenArrayReduce(location, operands, genContext); + } + + // resolve function + MLIRCustomMethods cm(builder, location, compileOptions); + mlir::SmallVector typeArgs; + for (auto typeArgNode : typeArguments) + { + auto typeArg = getType(typeArgNode, genContext); + if (!typeArg) + { + return mlir::failure(); + } + + typeArgs.push_back(typeArg); + } + + return cm.callMethod( + functionName, + typeArgs, + operands, + [this](mlir::Location location, mlir::Type type, mlir::Value value, const GenContext &genContext, bool disableStrictNullCheck) { return cast(location, type, value, genContext, disableStrictNullCheck); }, + genContext); + } + + ValueOrLogicalResult MLIRGenImpl::mlirGenCallExpression(mlir::Location location, mlir::Value funcResult, + NodeArray typeArguments, SmallVector &operands, + const GenContext &genContext) + { + GenContext specGenContext(genContext); + specGenContext.callOperands = operands; + + // get function ref. + auto result = mlirGenSpecialized(location, funcResult, typeArguments, operands, specGenContext); + EXIT_IF_FAILED(result) + auto actualFuncRefValue = V(result); + + if (!result.value && genContext.allowPartialResolve) + { + return mlir::success(); + } + + // special case when TypePredicateType is used in generic function and failed constraints + if (auto symbolRefOp = actualFuncRefValue.getDefiningOp()) + { + if (symbolRefOp.getIdentifier() == "") + { + if (auto funcType = mlir::dyn_cast(symbolRefOp.getType())) + { + if (funcType.getNumInputs() == 0 && funcType.getNumResults() == 1) + { + if (auto litType = dyn_cast(funcType.getResult(0))) + { + return V(builder.create(location, litType, litType.getValue())); + } + } + } + } + } + + if (mth.isBuiltinFunctionType(actualFuncRefValue)) + { + return mlirGenCallBuiltInFunction(location, + actualFuncRefValue, typeArguments, operands, genContext); + } + + if (auto optFuncRef = dyn_cast(actualFuncRefValue.getType())) + { + CAST_A(condValue, location, getBooleanType(), actualFuncRefValue, genContext); + + auto resultType = mth.getReturnTypeFromFuncRef(optFuncRef.getElementType()); + + LLVM_DEBUG(llvm::dbgs() << "\n!! Conditional call, return type: " << resultType << "\n";); + + auto hasReturn = !mth.isNoneType(resultType) && resultType != getVoidType(); + auto ifOp = hasReturn + ? builder.create(location, getOptionalType(resultType), condValue, true) + : builder.create(location, condValue, false); + + builder.setInsertionPointToStart(&ifOp.getThenRegion().front()); + + // value if true + + auto innerFuncRef = + builder.create(location, optFuncRef.getElementType(), actualFuncRefValue); + + auto result = mlirGenCallExpression(location, innerFuncRef, typeArguments, operands, genContext); + auto value = V(result); + if (value) + { + auto optValue = + builder.create(location, getOptionalType(value.getType()), value); + builder.create(location, mlir::ValueRange{optValue}); + + // else + builder.setInsertionPointToStart(&ifOp.getElseRegion().front()); + + auto optUndefValue = builder.create(location, getOptionalType(resultType)); + builder.create(location, mlir::ValueRange{optUndefValue}); + } + + builder.setInsertionPointAfter(ifOp); + + if (hasReturn) + { + return ifOp.getResults().front(); + } + + return mlir::success(); + } + + return mlirGenCall(location, actualFuncRefValue, operands, genContext); + } + + ValueOrLogicalResult MLIRGenImpl::NewClassInstanceOnStack(mlir::Location location, mlir_ts::ClassType classType, + SmallVector &operands, const GenContext &genContext) + { + // seems we are calling type constructor + // TODO: review it, really u should forbid to use "a = Class1();" to allocate in stack, or finish it + // using Class..new(true) method + + return NewClassInstance(location, classType, operands, genContext, true /*on stack*/); + } + + ValueOrLogicalResult MLIRGenImpl::NewClassInstance(mlir::Location location, mlir_ts::ClassType classType, + SmallVector &operands, const GenContext &genContext, bool onStack) + { + auto classInfo = getClassInfoByFullName(classType.getName().getValue()); + if (onStack && classInfo->hasVirtualTable) + { + emitError(location, "") << "can't instantiate new instance of " << to_print(classType) << " which has 'virtual table' on stack"; + return mlir::failure(); + } + + auto newOp = onStack + ? NewClassInstanceLogicAsOp(location, classType, onStack, genContext) + : ValueOrLogicalResult(NewClassInstanceAsMethodCallOp(location, classInfo, true, genContext)); + EXIT_IF_FAILED_OR_NO_VALUE(newOp) + if (mlir::failed(mlirGenCallConstructor(location, classInfo, V(newOp), operands, false, genContext))) + { + return mlir::failure(); + } + + return V(newOp); + } + + ValueOrLogicalResult MLIRGenImpl::mlirGenCall(mlir::Location location, mlir::Value funcRefValue, + SmallVector &operands, const GenContext &genContext) + { + ValueOrLogicalResult value(mlir::failure()); + mlir::TypeSwitch(funcRefValue.getType()) + .Case([&](auto calledFuncType) { + value = mlirGenCallFunction(location, calledFuncType, funcRefValue, operands, genContext); + }) + .Case([&](auto calledFuncType) { + value = mlirGenCallFunction(location, calledFuncType, funcRefValue, operands, genContext); + }) + .Case([&](auto calledBoundFuncType) { + auto calledFuncType = + getFunctionType(calledBoundFuncType.getInputs(), calledBoundFuncType.getResults(), calledBoundFuncType.isVarArg()); + auto thisValue = builder.create(location, calledFuncType.getInput(0), funcRefValue); + auto unboundFuncRefValue = builder.create(location, calledFuncType, funcRefValue); + value = mlirGenCallFunction(location, calledFuncType, unboundFuncRefValue, thisValue, operands, genContext); + }) + .Case([&](auto calledExtentFuncType) { + auto calledFuncType = + getFunctionType(calledExtentFuncType.getInputs(), calledExtentFuncType.getResults(), calledExtentFuncType.isVarArg()); + if (auto createExtensionFunctionOp = funcRefValue.getDefiningOp()) + { + auto thisValue = createExtensionFunctionOp.getThisVal(); + auto funcRefValue = createExtensionFunctionOp.getFunc(); + value = mlirGenCallFunction(location, calledFuncType, funcRefValue, thisValue, operands, genContext); + } + else + { + emitError(location, "not supported"); + value = mlir::Value(); + } + }) + .Case([&](auto classType) { + value = NewClassInstanceOnStack(location, classType, operands, genContext); + }) + .Case([&](auto classStorageType) { + MLIRCodeLogic mcl(builder, compileOptions); + auto refValue = mcl.GetReferenceFromValue(location, funcRefValue); + if (refValue) + { + // seems we are calling type constructor for super() + auto classInfo = getClassInfoByFullName(classStorageType.getName().getValue()); + // to track result call + value = mlirGenCallConstructor(location, classInfo, refValue, operands, true, genContext); + } + else + { + llvm_unreachable("not implemented"); + } + }) + .Default([&](auto type) { + emitError(location, "not supported function type"); + value = mlir::Value(); + }); + + return value; + } + + ValueOrLogicalResult MLIRGenImpl::callIteratorNext(mlir::Location location, mlir::Value nextProperty, + OperandsProcessingInfo* operandsProcessingInfo, const GenContext &genContext) + { + // call nextProperty + SmallVector callOperands; + auto callResult = mlirGenCall(location, nextProperty, callOperands, genContext); + EXIT_IF_FAILED_OR_NO_VALUE(callResult) + + // load property "value" + auto doneProperty = mlirGenPropertyAccessExpression(location, callResult, "done", false, genContext); + EXIT_IF_FAILED_OR_NO_VALUE(doneProperty) + + auto valueProperty = mlirGenPropertyAccessExpression(location, callResult, "value", false, genContext); + EXIT_IF_FAILED_OR_NO_VALUE(valueProperty) + + auto valueProp = V(valueProperty); + + if (operandsProcessingInfo != nullptr) + { + if (auto receiverType = operandsProcessingInfo->isCastNeededWithOptionalUnwrap(valueProp.getType())) + { + CAST(valueProp, location, receiverType, valueProp, genContext); + } + } + + // conditional expr: done ? undefined : value + auto doneInvValue = V(builder.create(location, getBooleanType(), + builder.getI32IntegerAttr((int)SyntaxKind::ExclamationToken), doneProperty)); + + mlir::Value condValue = builder.create( + location, getOptionalType(valueProp.getType()), valueProp, doneInvValue); + + return condValue; + } + + mlir::LogicalResult MLIRGenImpl::processOperandSpreadElement(mlir::Location location, mlir::Value source, OperandsProcessingInfo &operandsProcessingInfo, const GenContext &genContext) + { + auto count = operandsProcessingInfo.restCount(); + + if (hasIterator(location, source, genContext)) + { + // treat it as .next().value structure + // property + auto nextProperty = mlirGenPropertyAccessExpression( + location, source, ITERATOR_NEXT, false, genContext); + + for (auto spreadIndex = 0; spreadIndex < count; spreadIndex++) + { + auto result = callIteratorNext(location, nextProperty, &operandsProcessingInfo, genContext); + EXIT_IF_FAILED_OR_NO_VALUE(result) + operandsProcessingInfo.addOperandAndMoveToNextParameter(V(result)); + } + + return mlir::success(); + } + + if (isArrayLike(location, source, genContext)) + { + // treat it as [index] structure + auto lengthValue = mlirGenPropertyAccessExpression(location, source, LENGTH_FIELD_NAME, false, genContext); + EXIT_IF_FAILED_OR_NO_VALUE(lengthValue) + CAST(lengthValue, location, builder.getIndexType(), lengthValue, genContext); + + auto elementType = evaluateElementAccess(location, source, false, genContext); + if (genContext.receiverType && genContext.receiverType != elementType) + { + elementType = genContext.receiverType; + } + + auto valueFactory = + (isa(elementType)) + ? &MLIRGenImpl::anyOrUndefined + : &MLIRGenImpl::optionalValueOrUndefined; + + for (auto spreadIndex = 0; spreadIndex < count; spreadIndex++) + { + auto indexVal = builder.create(location, mth.getIndexType(), + mth.getIndexAttrValue(spreadIndex)); + + // conditional expr: length > "spreadIndex" ? value[index] : undefined + auto inBoundsValue = V(builder.create(location, getBooleanType(), + builder.getI32IntegerAttr((int)SyntaxKind::GreaterThanToken), + lengthValue, + indexVal)); + + auto spreadValue = (this->*valueFactory)(location, inBoundsValue, + [&](auto genContext) { + auto result = mlirGenElementAccess(location, source, indexVal, false, genContext); + EXIT_IF_FAILED_OR_NO_VALUE(result) + auto value = V(result); + + if (auto receiverType = operandsProcessingInfo.isCastNeeded(value.getType())) + { + CAST(value, location, receiverType, value, genContext); + } + + return ValueOrLogicalResult(value); + }, genContext); + EXIT_IF_FAILED_OR_NO_VALUE(spreadValue) + + operandsProcessingInfo.addOperandAndMoveToNextParameter(spreadValue); + } + + return mlir::success(); + } + + // this is defualt behavior for tuple + // treat it as [index] structure + for (auto spreadIndex = 0; spreadIndex < count; spreadIndex++) + { + auto indexVal = builder.create(location, mth.getStructIndexType(), + mth.getStructIndexAttrValue(spreadIndex)); + + auto result = mlirGenElementAccess(location, source, indexVal, false, genContext); + EXIT_IF_FAILED_OR_NO_VALUE(result) + auto value = V(result); + + operandsProcessingInfo.addOperandAndMoveToNextParameter(value); + } + + return mlir::success(); + } + + mlir::LogicalResult MLIRGenImpl::mlirGenCallConstructor(mlir::Location location, ClassInfo::TypePtr classInfo, + mlir::Value thisValue, SmallVector &operands, + bool castThisValueToClass, const GenContext &genContext) + { + assert(classInfo); + + auto virtualTable = classInfo->getHasVirtualTable(); + auto hasConstructor = classInfo->getHasConstructor(); + if (!hasConstructor && !virtualTable) + { + return mlir::success(); + } + + auto effectiveThisValue = thisValue; + if (castThisValueToClass) + { + CAST(effectiveThisValue, location, classInfo->classType, thisValue, genContext); + } + + if (classInfo->getHasConstructor()) + { + auto accessingFromLevel = detectAccessLevel(mlir::cast(effectiveThisValue.getType()), genContext); + if (accessingFromLevel < classInfo->constructorAccessLevel) { + emitError(location, "Class constructor is not accessable"); + return mlir::failure(); + } + + auto propAccess = + mlirGenPropertyAccessExpression(location, effectiveThisValue, CONSTRUCTOR_NAME, false, genContext); + + if (!propAccess && !genContext.allowPartialResolve) + { + emitError(location) << "Call Constructor: can't find constructor"; + } + + EXIT_IF_FAILED_OR_NO_VALUE(propAccess) + return mlirGenCall(location, propAccess, operands, genContext); + } + + return mlir::success(); + } + + ValueOrLogicalResult MLIRGenImpl::NewClassInstance(mlir::Location location, mlir::Value value, NodeArray arguments, + NodeArray typeArguments, bool suppressConstructorCall, + const GenContext &genContext) + { + + auto type = value.getType(); + type = mth.convertConstTupleTypeToTupleType(type); + + assert(type); + + auto resultType = type; + if (mth.isValueType(type)) + { + resultType = getValueRefType(type); + } + + // if true, will call Class..new method, otheriwise ts::NewOp which we need to implement Class..new method + auto methodCallWay = !suppressConstructorCall; + + mlir::Value newOp; + if (auto classType = dyn_cast(resultType)) + { + auto classInfo = getClassInfoByFullName(classType.getName().getValue()); + if (!classInfo) + { + auto genericClassInfo = getGenericClassInfoByFullName(classType.getName().getValue()); + if (genericClassInfo) + { + emitError(location) << "Generic class '"<< to_print(classType) << "' is missing type arguments "; + return mlir::failure(); + } + + emitError(location) << "Can't find class " << to_print(classType); + return mlir::failure(); + } + + if (genContext.dummyRun) + { + // just to cut a lot of calls + newOp = builder.create(location, classInfo->classType, builder.getBoolAttr(false)); + return newOp; + } + + auto newOp = NewClassInstanceAsMethodCallOp(location, classInfo, methodCallWay, genContext); + if (!newOp) + { + return mlir::failure(); + } + + if (methodCallWay) + { + // evaluate constructor + mlir::Type tupleParamsType; + + // we need context with correct thisType to get access to contructor + GenContext thisTypeGenContext(genContext); + thisTypeGenContext.thisType = mlir::cast(newOp.getType()); + + auto funcValueRef = evaluateProperty(location, newOp, CONSTRUCTOR_NAME, thisTypeGenContext); + if (funcValueRef) + { + SmallVector operands; + if (mlir::failed(mlirGenOperands(arguments, operands, funcValueRef, genContext, 1/*this params shift*/))) + { + emitError(location) << "Call constructor: can't resolve values of all parameters"; + return mlir::failure(); + } + + assert(newOp); + auto result = mlirGenCallConstructor(location, classInfo, newOp, operands, false, genContext); + EXIT_IF_FAILED(result) + } + } + + return newOp; + } + + return NewClassInstanceLogicAsOp(location, resultType, false, genContext); + } + + ValueOrLogicalResult MLIRGenImpl::NewClassInstanceLogicAsOp(mlir::Location location, mlir::Type typeOfInstance, bool stackAlloc, + const GenContext &genContext) + { + if (auto classType = dyn_cast(typeOfInstance)) + { + // set virtual table + auto classInfo = getClassInfoByFullName(classType.getName().getValue()); + if (!classInfo) + { + auto genericClassInfo = getGenericClassInfoByFullName(classType.getName().getValue()); + if (genericClassInfo) + { + emitError(location) << "Generic class '"<< to_print(classType) << "' is missing type arguments "; + return mlir::failure(); + } + + emitError(location) << "Can't find class " << to_print(classType); + return mlir::Value(); + } + + return NewClassInstanceLogicAsOp(location, classInfo, stackAlloc, genContext); + } + + LLVM_DEBUG(llvm::dbgs() << "\n!! new op (no method): " << typeOfInstance << "\n";); + + auto newOp = builder.create(location, typeOfInstance, builder.getBoolAttr(stackAlloc)); + return V(newOp); + } + + mlir::Value MLIRGenImpl::NewClassInstanceLogicAsOp(mlir::Location location, ClassInfo::TypePtr classInfo, bool stackAlloc, + const GenContext &genContext) + { + mlir::Value newOp; +#if ENABLE_TYPED_GC + auto enabledGC = !compileOptions.disableGC; + if (enabledGC && !stackAlloc) + { + auto typeDescrType = builder.getI64Type(); + auto typeDescGlobalName = getTypeDescriptorFieldName(classInfo); + auto typeDescRef = resolveFullNameIdentifier(location, typeDescGlobalName, true, genContext); + auto typeDescCurrentValue = builder.create(location, typeDescrType, typeDescRef); + + CAST_A(condVal, location, getBooleanType(), typeDescCurrentValue, genContext); + + auto ifOp = builder.create( + location, mlir::TypeRange{typeDescrType}, condVal, + [&](mlir::OpBuilder &opBuilder, mlir::Location loc) { + builder.create(loc, mlir::ValueRange{typeDescCurrentValue}); + }, + [&](mlir::OpBuilder &opBuilder, mlir::Location loc) { + // call typr bitmap + auto fullClassStaticFieldName = getTypeBitmapMethodName(classInfo); + + auto funcType = getFunctionType({}, {typeDescrType}, false); + + auto funcSymbolOp = builder.create( + location, funcType, + mlir::FlatSymbolRefAttr::get(builder.getContext(), fullClassStaticFieldName)); + + auto callIndirectOp = + builder.create( + MLIRHelper::getCallSiteLocation(funcSymbolOp->getLoc(), location), + funcSymbolOp, mlir::ValueRange{}); + auto typeDescr = callIndirectOp.getResult(0); + + // save value + builder.create(location, typeDescr, typeDescRef); + + builder.create(loc, mlir::ValueRange{typeDescr}); + }); + + auto typeDescrValue = ifOp.getResult(0); + + assert(!stackAlloc); + newOp = builder.create(location, classInfo->classType, typeDescrValue); + } + else + { + newOp = builder.create(location, classInfo->classType, builder.getBoolAttr(stackAlloc)); + } +#else + newOp = builder.create(location, classInfo->classType, builder.getBoolAttr(stackAlloc)); +#endif + mlirGenSetVTableToInstance(location, classInfo, newOp, genContext); + return newOp; + } + + mlir::Value MLIRGenImpl::NewClassInstanceAsMethodCallOp(mlir::Location location, ClassInfo::TypePtr classInfo, bool asMethodCall, + const GenContext &genContext) + { +#ifdef USE_NEW_AS_METHOD + if (asMethodCall) + { + auto classRefVal = builder.create( + location, classInfo->classType, + mlir::FlatSymbolRefAttr::get(builder.getContext(), classInfo->classType.getName().getValue())); + + // call ..new to create new instance + auto result = mlirGenPropertyAccessExpression(location, classRefVal, NEW_METHOD_NAME, false, genContext); + EXIT_IF_FAILED_OR_NO_VALUE(result) + auto newFuncRef = V(result); + + assert(newFuncRef); + + SmallVector emptyOperands; + auto resultCall = mlirGenCallExpression(location, newFuncRef, {}, emptyOperands, genContext); + EXIT_IF_FAILED_OR_NO_VALUE(resultCall) + auto newOp = V(resultCall); + return newOp; + } +#endif + + return NewClassInstanceLogicAsOp(location, classInfo, false, genContext); + } + + ValueOrLogicalResult MLIRGenImpl::NewClassInstanceByCallingNewCtor(mlir::Location location, mlir::Value value, NodeArray arguments, + NodeArray typeArguments, const GenContext &genContext) + { + auto result = mlirGenPropertyAccessExpression(location, value, NEW_CTOR_METHOD_NAME, genContext); + EXIT_IF_FAILED_OR_NO_VALUE(result) + auto newCtorMethod = V(result); + + SmallVector operands; + if (mlir::failed(mlirGenOperands(arguments, operands, newCtorMethod.getType(), genContext))) + { + emitError(location) << "Call new instance: can't resolve values of all parameters"; + return mlir::failure(); + } + + return mlirGenCallExpression(location, newCtorMethod, typeArguments, operands, genContext); + } + +} // namespace mlirgen +} // namespace typescript diff --git a/tslang/lib/TypeScript/MLIRGenImpl.h b/tslang/lib/TypeScript/MLIRGenImpl.h index d488d739..3cc1f3fc 100644 --- a/tslang/lib/TypeScript/MLIRGenImpl.h +++ b/tslang/lib/TypeScript/MLIRGenImpl.h @@ -4506,23 +4506,7 @@ class MLIRGenImpl ValueOrLogicalResult mlirGenCallThisMethod(mlir::Location location, mlir::Value thisValue, StringRef methodName, NodeArray typeArguments, NodeArray arguments, - const GenContext &genContext) - { - // to remove temp var after call - SymbolTableScopeT varScope(symbolTable); - - auto varDecl = std::make_shared(THIS_TEMPVAR_NAME, thisValue.getType(), location); - DECLARE(varDecl, thisValue); - - NodeFactory nf(NodeFactoryFlags::None); - - auto thisToken = nf.createIdentifier(S(THIS_TEMPVAR_NAME)); - auto callLogic = nf.createCallExpression( - nf.createPropertyAccessExpression(thisToken, nf.createIdentifier(stows(methodName.str()))), typeArguments, - arguments); - - return mlirGen(callLogic, genContext); - } + const GenContext &genContext); mlir::Value mlirGenInstanceOfOpaque(mlir::Location location, mlir::Value thisPtrValue, mlir::Value classRefVal, const GenContext &genContext) { @@ -5822,97 +5806,27 @@ class MLIRGenImpl ValueOrLogicalResult mlirGen(PropertyAccessExpression propertyAccessExpression, const GenContext &genContext); ValueOrLogicalResult mlirGenPropertyAccessExpression(mlir::Location location, mlir::Value objectValue, - mlir::StringRef name, const GenContext &genContext) - { - assert(objectValue); - MLIRPropertyAccessCodeLogic cl(compileOptions, builder, location, objectValue, name); - return mlirGenPropertyAccessExpressionLogic(location, objectValue, false, cl, genContext); - } + mlir::StringRef name, const GenContext &genContext); ValueOrLogicalResult mlirGenPropertyAccessExpression(mlir::Location location, mlir::Value objectValue, mlir::StringRef name, bool isConditional, - const GenContext &genContext) - { - assert(objectValue); - MLIRPropertyAccessCodeLogic cl(compileOptions, builder, location, objectValue, name); - return mlirGenPropertyAccessExpressionLogic(location, objectValue, isConditional, cl, genContext); - } + const GenContext &genContext); ValueOrLogicalResult mlirGenPropertyAccessExpression(mlir::Location location, mlir::Value objectValue, - mlir::Attribute id, const GenContext &genContext) - { - MLIRPropertyAccessCodeLogic cl(compileOptions, builder, location, objectValue, id); - return mlirGenPropertyAccessExpressionLogic(location, objectValue, false, cl, genContext); - } + mlir::Attribute id, const GenContext &genContext); ValueOrLogicalResult mlirGenPropertyAccessExpression(mlir::Location location, mlir::Value objectValue, mlir::Attribute id, bool isConditional, - const GenContext &genContext) - { - MLIRPropertyAccessCodeLogic cl(compileOptions, builder, location, objectValue, id); - return mlirGenPropertyAccessExpressionLogic(location, objectValue, isConditional, cl, genContext); - } + const GenContext &genContext); ValueOrLogicalResult mlirGenPropertyAccessExpression(mlir::Location location, mlir::Value objectValue, mlir::Attribute id, bool isConditional, mlir::Value argument/*for index access*/, - const GenContext &genContext) - { - MLIRPropertyAccessCodeLogic cl(compileOptions, builder, location, objectValue, id, argument); - return mlirGenPropertyAccessExpressionLogic(location, objectValue, isConditional, cl, genContext); - } + const GenContext &genContext); ValueOrLogicalResult mlirGenPropertyAccessExpressionLogic(mlir::Location location, mlir::Value objectValue, bool isConditional, MLIRPropertyAccessCodeLogic &cl, - const GenContext &genContext) - { - if (isConditional && MLIRTypeCore::isNullableOrOptionalType(objectValue.getType())) - { - // TODO: replace with one op "Optional , " - CAST_A(condValue, location, getBooleanType(), objectValue, genContext); - - auto propType = evaluateProperty(location, objectValue, cl.getName().str(), genContext); - if (!propType) - { - emitError(location, "Can't resolve property '") << cl.getName() << "' of type " << to_print(objectValue.getType()); - return mlir::failure(); - } - - auto ifOp = builder.create(location, getOptionalType(propType), condValue, true); - - builder.setInsertionPointToStart(&ifOp.getThenRegion().front()); - - // value if true - auto result = mlirGenPropertyAccessExpressionBaseLogic(location, objectValue, cl, genContext); - auto value = V(result); - - // special case: conditional extension function ?.(); - if (auto createExtentionFunction = value.getDefiningOp()) - { - // we need to convert into CreateBoundFunction, so it should be reference type for this, do I need to case value type into reference type? - value = createBoundMethodFromExtensionMethod(location, createExtentionFunction); - ifOp.getResults().front().setType(getOptionalType(value.getType())); - } - - auto optValue = isa(value.getType()) - ? value : builder.create(location, getOptionalType(value.getType()), value); - builder.create(location, mlir::ValueRange{optValue}); - - // else - builder.setInsertionPointToStart(&ifOp.getElseRegion().front()); - - auto optUndefValue = builder.create(location, getOptionalType(value.getType())); - builder.create(location, mlir::ValueRange{optUndefValue}); - - builder.setInsertionPointAfter(ifOp); - - return ifOp.getResults().front(); - } - else - { - return mlirGenPropertyAccessExpressionBaseLogic(location, objectValue, cl, genContext); - } - } + const GenContext &genContext); mlir_ts::AccessLevel detectAccessLevel(mlir_ts::ClassStorageType classStorageType, const GenContext &genContext) { @@ -5948,325 +5862,10 @@ class MLIRGenImpl ValueOrLogicalResult mlirGenPropertyAccessExpressionBaseLogic(mlir::Location location, mlir::Value objectValue, MLIRPropertyAccessCodeLogic &cl, - const GenContext &genContext) - { - auto name = cl.getName(); - auto argument = cl.getArgument(); - auto actualType = objectValue.getType(); - - LLVM_DEBUG(llvm::dbgs() << "\n\tResolving property '" << name << "' of type " << objectValue.getType();); - - // load reference if needed, except TupleTuple, ConstTupleType - if (auto refType = dyn_cast(actualType)) - { - auto elementType = refType.getElementType(); - if (!isa(elementType) && !isa(elementType)) - { - objectValue = builder.create(location, elementType, objectValue); - actualType = objectValue.getType(); - } - } - - // collapse union type - if (auto unionType = dyn_cast(actualType)) - { - mlir::Type baseType; - if (!mth.isUnionTypeNeedsTag(location, unionType, baseType)) - { - LLVM_DEBUG(llvm::dbgs() << "\n!! mlirGenPropertyAccessExpressionBaseLogic: union type " << baseType << "\n";); - actualType = baseType; - } - } - - // class member access - auto classAccessWithObject = [&](mlir_ts::ClassType classType, mlir::Value objectValue) { - - LLVM_DEBUG(llvm::dbgs() << "\n\t...field: \t" << cl.getName();); - auto accessingFromLevel = detectAccessLevel(classType, genContext); - LLVM_DEBUG(llvm::dbgs() << "\n\t = Accessing from level '" << accessingFromLevel << "'\n\n";); - - if (auto value = cl.Class(classType, accessingFromLevel)) - { - return value; - } - - return ClassMembersAccess(location, objectValue, classType.getName().getValue(), name, - false, argument, accessingFromLevel, genContext); - }; - - auto classAccess = [&](mlir_ts::ClassType classType) { - return classAccessWithObject(classType, objectValue); - }; - - auto castFn = [this](mlir::Location location, mlir::Type type, mlir::Value value, const GenContext &genContext, bool disableStrictNullCheck) { return cast(location, type, value, genContext, disableStrictNullCheck); }; - - mlir::Value value = - mlir::TypeSwitch(actualType) - .Case([&](auto enumType) { return cl.Enum(enumType); }) - .Case([&](auto constTupleType) { return cl.Tuple(constTupleType); }) - .Case([&](auto tupleType) { return cl.Tuple(tupleType); }) - .Case([&](auto stringType) { - if (auto value = cl.String(stringType)) - { - return value; - } - - return mlir::Value(); - }) - .Case([&](auto arrayType) { -#ifdef ARRAY_TYPE_AS_ARRAY_CLASS - if (auto genericClassTypeInfo = getGenericClassInfoByFullName("Array")) - { - auto classType = genericClassTypeInfo->classType; - SmallVector typeArg{arrayType.getElementType()}; - auto [result, specType] = instantiateSpecializedClassType(location, classType, - typeArg, genContext, true); - auto accessFailed = false; - if (mlir::succeeded(result)) - { - auto arrayNonConst = cast(location, mlir_ts::ArrayType::get(arrayType.getElementType()), objectValue, genContext); - if (arrayNonConst.failed()) - { - return mlir::Value(); - } - - if (auto value = classAccessWithObject(mlir::cast(specType), arrayNonConst)) - { - return value; - } - - accessFailed = true; - } - - if (mlir::failed(result) && !accessFailed) - { - genContext.stop(); - return mlir::Value(); - } - - genContext.postponedMessages->clear(); - } -#endif - - // find Array type - // TODO: should I mix use of Array and Array? - // if (auto classInfo = getClassInfoByFullName("Array")) - // { - // return classAccess(classInfo->classType); - // } - - if (auto value = cl.Array(arrayType, compileOptions, castFn, genContext)) - { - return value; - } - - return mlir::Value(); - }) - .Case([&](auto arrayType) { -#ifdef ARRAY_TYPE_AS_ARRAY_CLASS - if (auto genericClassTypeInfo = getGenericClassInfoByFullName("Array")) - { - auto classType = genericClassTypeInfo->classType; - SmallVector typeArg{arrayType.getElementType()}; - auto [result, specType] = instantiateSpecializedClassType(location, classType, - typeArg, genContext, true); - auto accessFailed = false; - if (mlir::succeeded(result)) - { - if (auto value = classAccess(mlir::cast(specType))) - { - return value; - } - - accessFailed = true; - } - - if (mlir::failed(result) && !accessFailed) - { - genContext.stop(); - return mlir::Value(); - } - - genContext.postponedMessages->clear(); - } -#endif - // find Array type - // TODO: should I mix use of Array and Array? - // if (auto classInfo = getClassInfoByFullName("Array")) - // { - // return classAccess(classInfo->classType); - // } - - if (auto value = cl.Array(arrayType, compileOptions, castFn, genContext)) - { - return value; - } - - return mlir::Value(); - }) - .Case([&](auto refType) { return cl.Ref(refType); }) - .Case([&](auto objectType) { - if (auto value = cl.Object(objectType)) - { - return value; - } - - return mlir::Value(); - }) - .Case([&](auto objectStorageType) { - if (auto value = cl.RefLogic(objectStorageType)) - { - return value; - } - - return mlir::Value(); - }) - .Case([&](auto symbolType) { return cl.Symbol(symbolType); }) - .Case([&](auto namespaceType) { - auto namespaceInfo = getNamespaceByFullName(namespaceType.getName().getValue()); - assert(namespaceInfo); - - MLIRNamespaceGuard ng(currentNamespace); - currentNamespace = namespaceInfo; - - return mlirGen(location, name, genContext); - }) - .Case([&](auto classStorageType) { - LLVM_DEBUG(llvm::dbgs() << "\n\t...field: \t" << cl.getName();); - auto accessingFromLevel = detectAccessLevel(classStorageType, genContext); - LLVM_DEBUG(llvm::dbgs() << "\n\t = Accessing from level '" << accessingFromLevel << "'\n\n";); - - if (auto value = cl.TupleNoError(classStorageType, accessingFromLevel)) - { - return value; - } - - return ClassMembersAccess(location, objectValue, - classStorageType.getName().getValue(), name, true, argument, accessingFromLevel, genContext); - }) - .Case(classAccess) - .Case([&](auto interfaceType) { - return InterfaceMembers( - location, objectValue, interfaceType.getName().getValue(), cl.getAttribute(), - argument, genContext); - }) - .Case([&](auto optionalType) { - // this is needed for conditional access to properties - auto elementType = optionalType.getElementType(); - auto loadedValue = builder.create(location, elementType, objectValue); - return mlirGenPropertyAccessExpression(location, loadedValue, name, false, genContext); - }) - .Case([&](auto unionType) { - // TODO: when access of property in union is finished use it instead of using first type - // all union types must have the same property - // 1) cast to first type - auto frontType = mth.getFirstNonNullUnionType(unionType); - //auto casted = cast(location, frontType, objectValue, genContext); - auto casted = builder.create(location, frontType, objectValue); - - return mlirGenPropertyAccessExpression(location, casted, name, false, genContext); - }) - .Case([&](auto literalType) { - auto elementType = literalType.getElementType(); - auto castedValue = builder.create(location, elementType, objectValue); - return mlirGenPropertyAccessExpression(location, castedValue, name, false, genContext); - }) - .Default([&](auto type) { - LLVM_DEBUG(llvm::dbgs() << "\n\tCan't resolve property '" << name << "' of type " << objectValue.getType();); - return mlir::Value(); - }); - - // extention logic: .(this) - if (!value) - { - if (auto funcRef = extensionFunction(location, objectValue, name, genContext)) - { - return funcRef; - } - } - - if (!value) - { - emitError(location, "Can't resolve property '") << name << "' of type " << to_print(objectValue.getType()); - return mlir::failure(); - } - - return value; - } + const GenContext &genContext); mlir::Value extensionFunctionLogic(mlir::Location location, mlir::Value funcRef, mlir::Value thisValue, StringRef name, - const GenContext &genContext) - { - if (!mth.isAnyFunctionType(funcRef.getType())) - { - return mlir::Value(); - } - - LLVM_DEBUG(llvm::dbgs() << "!! found extension by name for type: " << thisValue.getType() - << " function: " << name << ", value: " << funcRef << "\n";); - - auto thisTypeFromFunc = mth.getFirstParamFromFuncRef(funcRef.getType()); - - LLVM_DEBUG(llvm::dbgs() << "!! this type of function is : " << thisTypeFromFunc << "\n";); - - if (auto symbolOp = funcRef.getDefiningOp()) - { - // if (!isa(symbolOp.getType())) - if (!symbolOp->hasAttrOfType(GENERIC_ATTR_NAME)) - { - auto funcType = mlir::cast(funcRef.getType()); - if (thisTypeFromFunc == thisValue.getType()) - { - // return funcRef; - auto thisRef = thisValue; - auto extensFuncVal = builder.create( - location, getExtensionFunctionType(funcType), thisRef, funcRef); - return extensFuncVal; - } - } - else - { - // TODO: add checking constraint - auto funcName = symbolOp.getIdentifierAttr().getValue(); - auto functionGenericTypeInfo = getGenericFunctionInfoByFullName(funcName); - auto first = functionGenericTypeInfo->typeParams.front(); - if (first->hasConstraint()) - { - if (auto constraintType = getType(first->getConstraint(), genContext)) - { - llvm::StringMap> pairs{}; - auto extendsResult = mth.extendsType(location, thisValue.getType(), constraintType, pairs); - if (extendsResult == ExtendsResult::False || extendsResult == ExtendsResult::Never) - { - // failed due to generic type constraints - return mlir::Value(); - } - } - } - - // TODO: finish it - // it is generic function - StringMap inferredTypes; - inferType(location, thisTypeFromFunc, thisValue.getType(), inferredTypes, genContext); - if (inferredTypes.size() > 0) - { - // we found needed function - // return funcRef; - auto thisRef = thisValue; - - LLVM_DEBUG(llvm::dbgs() << "\n!! recreate ExtensionFunctionOp (generic interface): '" << name << "'\n this ref: '" << thisRef << "'\n func ref: '" << funcRef - << "'\n";); - - auto funcType = mlir::cast(funcRef.getType()); - auto extensFuncVal = builder.create( - location, getExtensionFunctionType(funcType), thisRef, funcRef); - return extensFuncVal; - } - } - } - - return mlir::Value(); - } + const GenContext &genContext); mlir::Value extensionFunction(mlir::Location location, mlir::Value thisValue, StringRef name, const GenContext &genContext) @@ -6320,31 +5919,7 @@ class MLIRGenImpl } mlir::Value ClassMembersAccess(mlir::Location location, mlir::Value thisValue, mlir::StringRef classFullName, - mlir::StringRef name, bool baseClass, mlir::Value argument, mlir_ts::AccessLevel accessingFromLevel, const GenContext &genContext) - { - auto classInfo = getClassInfoByFullName(classFullName); - if (!classInfo) - { - auto genericClassInfo = getGenericClassInfoByFullName(classFullName); - if (genericClassInfo) - { - // we can't discover anything in generic class - return mlir::Value(); - } - - emitError(location, "Class can't be found ") << classFullName; - return mlir::Value(); - } - - // static field access - auto value = ClassMembersAccess(location, thisValue, classInfo, name, baseClass, argument, accessingFromLevel, genContext); - if (!value) - { - emitError(location, "Class member '") << name << "' can't be found"; - } - - return value; - } + mlir::StringRef name, bool baseClass, mlir::Value argument, mlir_ts::AccessLevel accessingFromLevel, const GenContext &genContext); mlir::Value getThisRefOfClass(mlir::Location location, mlir_ts::ClassType classType, mlir::Value thisValue, bool isSuperClass, const GenContext &genContext) { @@ -6553,311 +6128,47 @@ class MLIRGenImpl mlir::Value ClassGenericMethodAccess(ClassInfo::TypePtr classInfo, mlir::Location location, mlir::Value thisValue, int genericMethodIndex, - bool isSuperClass, mlir_ts::AccessLevel accessingFromLevel, const GenContext &genContext) { - auto genericMethodInfo = classInfo->staticGenericMethods[genericMethodIndex]; - if (accessingFromLevel < genericMethodInfo.accessLevel) { - emitError(location, "Class member '") << genericMethodInfo.name << "' is not accessable"; - return mlir::Value(); - } - - auto paramsArray = genericMethodInfo.funcProto->getParams(); - auto explicitThis = paramsArray.size() > 0 && paramsArray.front()->getName() == THIS_NAME; - if (genericMethodInfo.isStatic && !explicitThis) - { - auto funcSymbolOp = builder.create( - location, genericMethodInfo.funcType, - mlir::FlatSymbolRefAttr::get(builder.getContext(), genericMethodInfo.funcProto->getName())); - funcSymbolOp->setAttr(GENERIC_ATTR_NAME, mlir::BoolAttr::get(builder.getContext(), true)); - return funcSymbolOp; - } - else - { - auto effectiveThisValue = getThisRefOfClass(location, classInfo->classType, thisValue, isSuperClass, genContext); - auto effectiveFuncType = genericMethodInfo.funcProto->getFuncType(); - - auto thisSymbOp = builder.create( - location, getBoundFunctionType(effectiveFuncType), effectiveThisValue, - mlir::FlatSymbolRefAttr::get(builder.getContext(), genericMethodInfo.funcProto->getName())); - thisSymbOp->setAttr(GENERIC_ATTR_NAME, mlir::BoolAttr::get(builder.getContext(), true)); - return thisSymbOp; - } - } + bool isSuperClass, mlir_ts::AccessLevel accessingFromLevel, const GenContext &genContext); mlir::Value ClassAccessorAccess(ClassInfo::TypePtr classInfo, - mlir::Location location, mlir::Value thisValue, int accessorIndex, mlir_ts::AccessLevel accessingFromLevel, const GenContext &genContext) { + mlir::Location location, mlir::Value thisValue, int accessorIndex, mlir_ts::AccessLevel accessingFromLevel, const GenContext &genContext); - auto accessorInfo = classInfo->accessors[accessorIndex]; - - // TODO: finish access check for get/set methods + // TODO: why isSuperClass is not used here? + mlir::Value ClassIndexAccess(ClassInfo::TypePtr classInfo, + mlir::Location location, mlir::Value thisValue, mlir::Value argument, mlir_ts::AccessLevel accessingFromLevel, const GenContext &genContext); - auto getFunc = accessorInfo.get; - auto setFunc = accessorInfo.set; - mlir::Type accessorResultType; - if (getFunc) - { - auto funcType = getFunc.funcType; - if (funcType.getNumResults() > 0) - { - accessorResultType = funcType.getResult(0); - } - } + mlir::Value ClassBaseClassAccess(ClassInfo::TypePtr classInfo, ClassInfo::TypePtr baseClass, int index, + mlir::Location location, mlir::Value thisValue, StringRef name, mlir::Value argument, mlir_ts::AccessLevel accessingFromLevel, const GenContext &genContext); - if (!accessorResultType && setFunc) - { - accessorResultType = setFunc.funcType.getInput(accessorInfo.isStatic ? 0 : 1); - } + mlir::Value ClassMembersAccess(mlir::Location location, mlir::Value thisValue, ClassInfo::TypePtr classInfo, + mlir::StringRef name, bool isSuperClass, mlir::Value argument, mlir_ts::AccessLevel accessingFromLevel, const GenContext &genContext); - if (!accessorResultType) + bool classHasField(ClassInfo::TypePtr classInfo, mlir::StringRef name, SmallVector &fieldPath) + { + auto fieldId = MLIRHelper::TupleFieldName(name, builder.getContext()); + auto classStorageType = mlir::cast(classInfo->classType.getStorageType()); + auto fieldIndex = classStorageType.getIndex(fieldId); + auto missingField = fieldIndex < 0 || fieldIndex >= classStorageType.size(); + if (!missingField) { - emitError(location) << "can't resolve type of property"; - return mlir::Value(); - } - - // remove funcs if access level is not high - if (getFunc && accessingFromLevel < accessorInfo.getAccessLevel) { - getFunc = {}; - } - if (setFunc && accessingFromLevel < accessorInfo.setAccessLevel) { - setFunc = {}; + fieldPath.insert(fieldPath.begin(), classInfo); + return true; } - if (accessorInfo.isStatic) - { - auto accessorOp = builder.create( - location, accessorResultType, - getFunc ? mlir::FlatSymbolRefAttr::get(builder.getContext(), getFunc.name) - : mlir::FlatSymbolRefAttr{}, - setFunc ? mlir::FlatSymbolRefAttr::get(builder.getContext(), setFunc.name) - : mlir::FlatSymbolRefAttr{}, - mlir::Value()); - return accessorOp.getResult(0); - } - else + for (auto baseClass : classInfo->baseClasses) { - auto thisAccessorOp = builder.create( - location, accessorResultType, thisValue, - getFunc ? mlir::FlatSymbolRefAttr::get(builder.getContext(), getFunc.name) - : mlir::FlatSymbolRefAttr{}, - setFunc ? mlir::FlatSymbolRefAttr::get(builder.getContext(), setFunc.name) - : mlir::FlatSymbolRefAttr{}, - mlir::Value()); - return thisAccessorOp.getResult(0); + if (classHasField(baseClass, name, fieldPath)) + { + fieldPath.insert(fieldPath.begin(), classInfo); + return true; + } } + return false; } - // TODO: why isSuperClass is not used here? - mlir::Value ClassIndexAccess(ClassInfo::TypePtr classInfo, - mlir::Location location, mlir::Value thisValue, mlir::Value argument, mlir_ts::AccessLevel accessingFromLevel, const GenContext &genContext) { - - if (classInfo->indexes.size() == 0) - { - emitError(location) << "indexer is not declared"; - return mlir::Value(); - } - - auto indexInfo = classInfo->indexes.front(); - auto getFunc = indexInfo.get; - auto setFunc = indexInfo.set; - - if (!indexInfo.indexSignature || indexInfo.indexSignature.getNumResults() == 0) - { - emitError(location) << "can't resolve type of indexer"; - return mlir::Value(); - } - - // remove funcs if access level is not high - if (getFunc && accessingFromLevel < indexInfo.getAccessLevel) { - getFunc = {}; - } - if (setFunc && accessingFromLevel < indexInfo.setAccessLevel) { - setFunc = {}; - } - - auto indexResultType = indexInfo.indexSignature.getResult(0); - auto argumentType = indexInfo.indexSignature.getInput(0); - - // sync index - CAST_A(result, location, argumentType, argument, genContext); - - auto thisIndexAccessorOp = builder.create( - location, indexResultType, thisValue, V(result), - getFunc ? mlir::FlatSymbolRefAttr::get(builder.getContext(), getFunc.name) - : mlir::FlatSymbolRefAttr{}, - setFunc ? mlir::FlatSymbolRefAttr::get(builder.getContext(), setFunc.name) - : mlir::FlatSymbolRefAttr{}, - mlir::Value()); - return thisIndexAccessorOp.getResult(0); - } - - mlir::Value ClassBaseClassAccess(ClassInfo::TypePtr classInfo, ClassInfo::TypePtr baseClass, int index, - mlir::Location location, mlir::Value thisValue, StringRef name, mlir::Value argument, mlir_ts::AccessLevel accessingFromLevel, const GenContext &genContext) { - - // first base is "super." - if (index == 0 && name == SUPER_NAME) - { - auto result = mlirGenPropertyAccessExpression(location, thisValue, baseClass->fullName, genContext); - auto value = V(result); - return value; - } - - auto value = ClassMembersAccess(location, thisValue, baseClass, name, true, argument, accessingFromLevel, genContext); - if (value) - { - return value; - } - - SmallVector fieldPath; - if (classHasField(baseClass, name, fieldPath)) - { - // load value from path - auto currentObject = thisValue; - for (auto &chain : fieldPath) - { - auto fieldValue = - mlirGenPropertyAccessExpression(location, currentObject, chain->fullName, genContext); - if (!fieldValue) - { - emitError(location) << "Can't resolve field/property/base '" << chain->fullName - << "' of class '" << classInfo->fullName << "'\n"; - return fieldValue; - } - - assert(fieldValue); - currentObject = fieldValue; - } - - // last value - auto result = mlirGenPropertyAccessExpression(location, currentObject, name, genContext); - auto value = V(result); - if (value) - { - return value; - } - } - - return mlir::Value(); - } - - mlir::Value ClassMembersAccess(mlir::Location location, mlir::Value thisValue, ClassInfo::TypePtr classInfo, - mlir::StringRef name, bool isSuperClass, mlir::Value argument, mlir_ts::AccessLevel accessingFromLevel, const GenContext &genContext) - { - assert(classInfo); - - LLVM_DEBUG(llvm::dbgs() << "\n\t looking for member: " << name << " in class '" << classInfo->fullName << "'\n";); - - // indexer access - if (name == INDEX_ACCESS_FIELD_NAME) - { - if (!classInfo->indexes.empty()) - { - return ClassIndexAccess(classInfo, location, thisValue, argument, accessingFromLevel, genContext); - } - } - - auto staticFieldIndex = classInfo->getStaticFieldIndex( - MLIRHelper::TupleFieldName(name, builder.getContext())); - if (staticFieldIndex >= 0) - { - return ClassStaticFieldAccess(classInfo, location, thisValue, staticFieldIndex, accessingFromLevel, genContext); - } - - // check method access - auto methodIndex = classInfo->getMethodIndex(name); - if (methodIndex >= 0) - { - return ClassMethodAccess(classInfo, location, thisValue, methodIndex, isSuperClass, accessingFromLevel, genContext); - } - - // static generic methods - auto genericMethodIndex = classInfo->getGenericMethodIndex(name); - if (genericMethodIndex >= 0) - { - return ClassGenericMethodAccess(classInfo, location, thisValue, genericMethodIndex, isSuperClass, accessingFromLevel, genContext); - } - - // check accessor - auto accessorIndex = classInfo->getAccessorIndex(name); - if (accessorIndex >= 0) - { - return ClassAccessorAccess(classInfo, location, thisValue, accessorIndex, accessingFromLevel, genContext); - } - - for (auto [index, baseClass] : enumerate(classInfo->baseClasses)) - { - auto effectiveAccessingFromLevel = accessingFromLevel == mlir_ts::AccessLevel::Private - ? mlir_ts::AccessLevel::Protected : accessingFromLevel; - auto value = ClassBaseClassAccess(classInfo, baseClass, index, location, - thisValue, name, argument, effectiveAccessingFromLevel, genContext); - if (value) - { - return value; - } - } - - if (isSuperClass || genContext.allowPartialResolve) - { - return mlir::Value(); - } - - emitError(location) << "can't resolve property/field/base '" << name << "' of class '" << classInfo->fullName - << "'\n"; - - return mlir::Value(); - } - - bool classHasField(ClassInfo::TypePtr classInfo, mlir::StringRef name, SmallVector &fieldPath) - { - auto fieldId = MLIRHelper::TupleFieldName(name, builder.getContext()); - auto classStorageType = mlir::cast(classInfo->classType.getStorageType()); - auto fieldIndex = classStorageType.getIndex(fieldId); - auto missingField = fieldIndex < 0 || fieldIndex >= classStorageType.size(); - if (!missingField) - { - fieldPath.insert(fieldPath.begin(), classInfo); - return true; - } - - for (auto baseClass : classInfo->baseClasses) - { - if (classHasField(baseClass, name, fieldPath)) - { - fieldPath.insert(fieldPath.begin(), classInfo); - return true; - } - } - - return false; - } - - mlir::Value InterfaceMembers(mlir::Location location, mlir::Value interfaceValue, mlir::StringRef interfaceFullName, - mlir::Attribute id, mlir::Value argument, const GenContext &genContext) - { - auto interfaceInfo = getInterfaceInfoByFullName(interfaceFullName); - if (!interfaceInfo) - { - auto genericInterfaceInfo = getGenericInterfaceInfoByFullName(interfaceFullName); - if (genericInterfaceInfo) - { - // we can't detect value of generic interface (we can only if it is specialization) - emitError(location, "Interface can't be found ") << interfaceFullName; - return mlir::Value(); - } - - return mlir::Value(); - } - - assert(interfaceInfo); - - // static field access - auto value = InterfaceMembers(location, interfaceValue, interfaceInfo, id, argument, genContext); - if (!value) - { - emitError(location, "Interface member ") << id << " can't be found in interface '" << interfaceInfo->name << "'"; - } - - return value; - } + mlir::Value InterfaceMembers(mlir::Location location, mlir::Value interfaceValue, mlir::StringRef interfaceFullName, + mlir::Attribute id, mlir::Value argument, const GenContext &genContext); mlir::Value InterfaceFieldAccess(mlir::Location location, mlir::Value interfaceValue, InterfaceFieldInfo *fieldInfo) { @@ -7041,40 +6352,7 @@ class MLIRGenImpl } mlir::Value InterfaceMembers(mlir::Location location, mlir::Value interfaceValue, InterfaceInfo::TypePtr interfaceInfo, - mlir::Attribute id, mlir::Value argument, const GenContext &genContext) - { - assert(interfaceInfo); - - // indexer access - auto nameAttr = mlir::dyn_cast(id); - if (nameAttr && nameAttr.getValue() == INDEX_ACCESS_FIELD_NAME) - { - return InterfaceIndexAccess(interfaceInfo, location, interfaceValue, argument, genContext); - } - - // check field access - if (auto fieldInfo = interfaceInfo->findField(id)) - { - return InterfaceFieldAccess(location, interfaceValue, fieldInfo); - } - - // check method access - if (nameAttr) - { - if (auto methodInfo = interfaceInfo->findMethod(nameAttr.getValue())) - { - return InterfaceMethodAccess(location, interfaceValue, methodInfo); - } - - if (auto accessorInfo = interfaceInfo->findAccessor(nameAttr.getValue())) - { - return InterfaceAccessorAccess(location, interfaceInfo, interfaceValue, accessorInfo, genContext); - } - - } - - return mlir::Value(); - } + mlir::Attribute id, mlir::Value argument, const GenContext &genContext); template ValueOrLogicalResult mlirGenElementAccessTuple(mlir::Location location, mlir::Value expression, @@ -7097,157 +6375,7 @@ class MLIRGenImpl ValueOrLogicalResult mlirGen(ElementAccessExpression elementAccessExpression, const GenContext &genContext); - ValueOrLogicalResult mlirGenElementAccess(mlir::Location location, mlir::Value expression, mlir::Value argumentExpression, bool isConditionalAccess, const GenContext &genContext) - { - auto arrayType = expression.getType(); - - // collapse union type - if (auto unionType = dyn_cast(expression.getType())) - { - mlir::Type baseType; - if (!mth.isUnionTypeNeedsTag(location, unionType, baseType)) - { - LLVM_DEBUG(llvm::dbgs() << "\n!! ElementAccessExpression: union type " << baseType << "\n";); - arrayType = baseType; - } - } - - if (isa(arrayType)) - { - arrayType = mth.stripLiteralType(arrayType); - CAST(expression, location, arrayType, expression, genContext); - } - - if (auto optType = dyn_cast(arrayType)) - { - arrayType = optType.getElementType(); - // loading value from opt value - expression = builder.create(location, arrayType, expression); - } - - mlir::Type elementType; - if (auto arrayTyped = dyn_cast(arrayType)) - { - if (auto fieldName = argumentExpression.getDefiningOp()) - { - auto attr = fieldName.getValue(); - if (isa(attr)) - { - return mlirGenPropertyAccessExpression(location, expression, attr, isConditionalAccess, genContext); - } - } - - elementType = arrayTyped.getElementType(); - } - else if (auto vectorType = dyn_cast(arrayType)) - { - if (auto fieldName = argumentExpression.getDefiningOp()) - { - auto attr = fieldName.getValue(); - if (isa(attr)) - { - return mlirGenPropertyAccessExpression(location, expression, attr, isConditionalAccess, genContext); - } - } - - elementType = vectorType.getElementType(); - } - else if (isa(arrayType)) - { - elementType = getCharType(); - } - else if (auto tupleType = dyn_cast(arrayType)) - { - return mlirGenElementAccessTuple(location, expression, argumentExpression, tupleType); - } - else if (auto constTupleType = dyn_cast(arrayType)) - { - return mlirGenElementAccessTuple(location, expression, argumentExpression, constTupleType); - } - else if (auto classType = dyn_cast(arrayType)) - { - if (auto fieldName = argumentExpression.getDefiningOp()) - { - auto attr = fieldName.getValue(); - if (isa(attr)) - { - // TODO: implement '[string]' access here - return mlirGenPropertyAccessExpression(location, expression, attr, isConditionalAccess, genContext); - } - } - - // else access of index - auto indexAccessor = builder.getStringAttr(INDEX_ACCESS_FIELD_NAME); - return mlirGenPropertyAccessExpression(location, expression, indexAccessor, isConditionalAccess, argumentExpression, genContext); - } - else if (auto classStorageType = dyn_cast(arrayType)) - { - // seems we are calling "super" - if (auto fieldName = argumentExpression.getDefiningOp()) - { - auto attr = fieldName.getValue(); - return mlirGenPropertyAccessExpression(location, expression, attr, isConditionalAccess, genContext); - } - - llvm_unreachable("not implemented (ElementAccessExpression)"); - } - else if (auto interfaceType = dyn_cast(arrayType)) - { - if (auto fieldName = argumentExpression.getDefiningOp()) - { - auto attr = fieldName.getValue(); - if (isa(attr)) - { - return mlirGenPropertyAccessExpression(location, expression, attr, isConditionalAccess, genContext); - } - } - - // else access of index - auto indexAccessor = builder.getStringAttr(INDEX_ACCESS_FIELD_NAME); - return mlirGenPropertyAccessExpression(location, expression, indexAccessor, isConditionalAccess, argumentExpression, genContext); - } - else if (auto enumType = dyn_cast(arrayType)) - { - if (auto fieldName = argumentExpression.getDefiningOp()) - { - auto attr = fieldName.getValue(); - return mlirGenPropertyAccessExpression(location, expression, attr, isConditionalAccess, genContext); - } - - llvm_unreachable("not implemented (ElementAccessExpression)"); - } - else if (auto refType = dyn_cast(arrayType)) - { - CAST_A(index, location, mth.getIndexType(), argumentExpression, genContext); - - LLVM_DEBUG(llvm::dbgs() << "\n!! ref type: " << refType << " index value: " << index << "\n";); - - auto elemRef = builder.create( - location, refType, expression, index); - - return V(elemRef); - } - else if (auto anyType = dyn_cast(arrayType)) - { - emitError(location, "not supported"); - return mlir::failure(); - } - else - { - LLVM_DEBUG(llvm::dbgs() << "\n!! ElementAccessExpression: " << arrayType - << "\n";); - - emitError(location) << "access expression is not applicable to " << to_print(arrayType); - return mlir::failure(); - } - - auto indexType = argumentExpression.getType(); - CAST(argumentExpression, location, mth.getStructIndexType(), argumentExpression, genContext); - - auto elemRef = builder.create(location, mlir_ts::RefType::get(elementType), expression, - argumentExpression); - return V(builder.create(location, elementType, elemRef)); - } + ValueOrLogicalResult mlirGenElementAccess(mlir::Location location, mlir::Value expression, mlir::Value argumentExpression, bool isConditionalAccess, const GenContext &genContext); ValueOrLogicalResult mlirGen(CallExpression callExpression, const GenContext &genContext); @@ -7462,337 +6590,76 @@ class MLIRGenImpl auto funcSrc = operands[1]; // register vals - auto srcArrayVarDecl = std::make_shared(".src_array", arraySrc.getType(), location); - DECLARE(srcArrayVarDecl, arraySrc); - - auto funcVarDecl = std::make_shared(".func", funcSrc.getType(), location); - DECLARE(funcVarDecl, funcSrc); - - NodeFactory nf(NodeFactoryFlags::None); - - auto _src_array_ident = nf.createIdentifier(S(".src_array")); - auto _func_ident = nf.createIdentifier(S(".func")); - - auto _v_ident = nf.createIdentifier(S(".v")); - - NodeArray declarations; - declarations.push_back(nf.createVariableDeclaration(_v_ident)); - auto declList = nf.createVariableDeclarationList(declarations, NodeFlags::Const); - - NodeArray argumentsArray; - argumentsArray.push_back(_v_ident); - - auto [pos, _end] = LocationHelper::getSpan(location); - - auto _yield_expr = nf.createYieldExpression(undefined, _v_ident); - _yield_expr->pos.pos = pos; - _yield_expr->_end = _end; - - auto forOfStat = nf.createForOfStatement( - undefined, declList, _src_array_ident, - nf.createIfStatement(nf.createCallExpression(_func_ident, undefined, argumentsArray), - nf.createExpressionStatement(_yield_expr), - undefined)); - - // iterator - auto iterName = MLIRHelper::getAnonymousName(location, ".iter", getFullNamespaceName()); - - NodeArray statements; - statements.push_back(forOfStat); - auto block = nf.createBlock(statements, false); - auto funcIter = - nf.createFunctionExpression(undefined, nf.createToken(SyntaxKind::AsteriskToken), - nf.createIdentifier(convertUTF8toWide(iterName)), undefined, undefined, undefined, block); - funcIter->pos.pos = pos; - funcIter->_end = _end; - - // call - NodeArray emptyArguments; - auto callOfIter = nf.createCallExpression(funcIter, undefined, emptyArguments); - - return mlirGen(callOfIter, genContext); - } - - ValueOrLogicalResult mlirGenArrayReduce(mlir::Location location, SmallVector &operands, - const GenContext &genContext) - { - // info, we add "_" extra as scanner append "_" in front of "__"; - auto funcName = "___array_reduce"; - - if (!existGenericFunctionMap(funcName)) - { - auto src = S("function __array_reduce(arr: T[], f: (s: R, v: T) => R, init: R) \ - { \ - let r = init; \ - for (const v of arr) r = f(r, v); \ - return r; \ - }"); - - { - MLIRLocationGuard vgLoc(overwriteLoc); - overwriteLoc = location; - if (mlir::failed(parsePartialStatements(src))) - { - assert(false); - return mlir::failure(); - } - } - } - - auto funcResult = resolveIdentifier(location, funcName, genContext); - - assert(funcResult); - - return mlirGenCallExpression(location, funcResult, {}, operands, genContext); - } - - ValueOrLogicalResult mlirGenCallBuiltInFunction( - mlir::Location location, mlir::Value actualFuncRefValue, NodeArray typeArguments, - SmallVector &operands, const GenContext &genContext) - { - // TODO: when you resolve names such as "print", "parseInt" should return names in mlirGen(Identifier) - auto calleeName = actualFuncRefValue.getDefiningOp()->getAttrOfType(StringRef(IDENTIFIER_ATTR_NAME)); - auto functionName = calleeName.getValue(); - - if (auto thisSymbolRefOp = actualFuncRefValue.getDefiningOp()) - { - // do not remove it, it is needed for custom methods to be called correctly - operands.insert(operands.begin(), thisSymbolRefOp.getThisVal()); - } - - // temp hack - if (functionName == "__array_foreach") - { - mlirGenArrayForEach(location, operands, genContext); - return mlir::success(); - } - - if (functionName == "__array_every") - { - return mlirGenArrayEvery(location, operands, genContext); - } - - if (functionName == "__array_some") - { - return mlirGenArraySome(location, operands, genContext); - } - - if (functionName == "__array_map") - { - return mlirGenArrayMap(location, operands, genContext); - } - - if (functionName == "__array_filter") - { - return mlirGenArrayFilter(location, operands, genContext); - } - - if (functionName == "__array_reduce") - { - return mlirGenArrayReduce(location, operands, genContext); - } - - // resolve function - MLIRCustomMethods cm(builder, location, compileOptions); - mlir::SmallVector typeArgs; - for (auto typeArgNode : typeArguments) - { - auto typeArg = getType(typeArgNode, genContext); - if (!typeArg) - { - return mlir::failure(); - } - - typeArgs.push_back(typeArg); - } - - return cm.callMethod( - functionName, - typeArgs, - operands, - [this](mlir::Location location, mlir::Type type, mlir::Value value, const GenContext &genContext, bool disableStrictNullCheck) { return cast(location, type, value, genContext, disableStrictNullCheck); }, - genContext); - } - - ValueOrLogicalResult mlirGenCallExpression(mlir::Location location, mlir::Value funcResult, - NodeArray typeArguments, SmallVector &operands, - const GenContext &genContext) - { - GenContext specGenContext(genContext); - specGenContext.callOperands = operands; - - // get function ref. - auto result = mlirGenSpecialized(location, funcResult, typeArguments, operands, specGenContext); - EXIT_IF_FAILED(result) - auto actualFuncRefValue = V(result); - - if (!result.value && genContext.allowPartialResolve) - { - return mlir::success(); - } - - // special case when TypePredicateType is used in generic function and failed constraints - if (auto symbolRefOp = actualFuncRefValue.getDefiningOp()) - { - if (symbolRefOp.getIdentifier() == "") - { - if (auto funcType = mlir::dyn_cast(symbolRefOp.getType())) - { - if (funcType.getNumInputs() == 0 && funcType.getNumResults() == 1) - { - if (auto litType = dyn_cast(funcType.getResult(0))) - { - return V(builder.create(location, litType, litType.getValue())); - } - } - } - } - } - - if (mth.isBuiltinFunctionType(actualFuncRefValue)) - { - return mlirGenCallBuiltInFunction(location, - actualFuncRefValue, typeArguments, operands, genContext); - } - - if (auto optFuncRef = dyn_cast(actualFuncRefValue.getType())) - { - CAST_A(condValue, location, getBooleanType(), actualFuncRefValue, genContext); + auto srcArrayVarDecl = std::make_shared(".src_array", arraySrc.getType(), location); + DECLARE(srcArrayVarDecl, arraySrc); - auto resultType = mth.getReturnTypeFromFuncRef(optFuncRef.getElementType()); + auto funcVarDecl = std::make_shared(".func", funcSrc.getType(), location); + DECLARE(funcVarDecl, funcSrc); - LLVM_DEBUG(llvm::dbgs() << "\n!! Conditional call, return type: " << resultType << "\n";); + NodeFactory nf(NodeFactoryFlags::None); - auto hasReturn = !mth.isNoneType(resultType) && resultType != getVoidType(); - auto ifOp = hasReturn - ? builder.create(location, getOptionalType(resultType), condValue, true) - : builder.create(location, condValue, false); + auto _src_array_ident = nf.createIdentifier(S(".src_array")); + auto _func_ident = nf.createIdentifier(S(".func")); - builder.setInsertionPointToStart(&ifOp.getThenRegion().front()); + auto _v_ident = nf.createIdentifier(S(".v")); - // value if true + NodeArray declarations; + declarations.push_back(nf.createVariableDeclaration(_v_ident)); + auto declList = nf.createVariableDeclarationList(declarations, NodeFlags::Const); - auto innerFuncRef = - builder.create(location, optFuncRef.getElementType(), actualFuncRefValue); + NodeArray argumentsArray; + argumentsArray.push_back(_v_ident); - auto result = mlirGenCallExpression(location, innerFuncRef, typeArguments, operands, genContext); - auto value = V(result); - if (value) - { - auto optValue = - builder.create(location, getOptionalType(value.getType()), value); - builder.create(location, mlir::ValueRange{optValue}); + auto [pos, _end] = LocationHelper::getSpan(location); - // else - builder.setInsertionPointToStart(&ifOp.getElseRegion().front()); + auto _yield_expr = nf.createYieldExpression(undefined, _v_ident); + _yield_expr->pos.pos = pos; + _yield_expr->_end = _end; - auto optUndefValue = builder.create(location, getOptionalType(resultType)); - builder.create(location, mlir::ValueRange{optUndefValue}); - } + auto forOfStat = nf.createForOfStatement( + undefined, declList, _src_array_ident, + nf.createIfStatement(nf.createCallExpression(_func_ident, undefined, argumentsArray), + nf.createExpressionStatement(_yield_expr), + undefined)); - builder.setInsertionPointAfter(ifOp); + // iterator + auto iterName = MLIRHelper::getAnonymousName(location, ".iter", getFullNamespaceName()); - if (hasReturn) - { - return ifOp.getResults().front(); - } + NodeArray statements; + statements.push_back(forOfStat); + auto block = nf.createBlock(statements, false); + auto funcIter = + nf.createFunctionExpression(undefined, nf.createToken(SyntaxKind::AsteriskToken), + nf.createIdentifier(convertUTF8toWide(iterName)), undefined, undefined, undefined, block); + funcIter->pos.pos = pos; + funcIter->_end = _end; - return mlir::success(); - } + // call + NodeArray emptyArguments; + auto callOfIter = nf.createCallExpression(funcIter, undefined, emptyArguments); - return mlirGenCall(location, actualFuncRefValue, operands, genContext); + return mlirGen(callOfIter, genContext); } - ValueOrLogicalResult NewClassInstanceOnStack(mlir::Location location, mlir_ts::ClassType classType, - SmallVector &operands, const GenContext &genContext) - { - // seems we are calling type constructor - // TODO: review it, really u should forbid to use "a = Class1();" to allocate in stack, or finish it - // using Class..new(true) method + ValueOrLogicalResult mlirGenArrayReduce(mlir::Location location, SmallVector &operands, + const GenContext &genContext); - return NewClassInstance(location, classType, operands, genContext, true /*on stack*/); - } + ValueOrLogicalResult mlirGenCallBuiltInFunction( + mlir::Location location, mlir::Value actualFuncRefValue, NodeArray typeArguments, + SmallVector &operands, const GenContext &genContext); - ValueOrLogicalResult NewClassInstance(mlir::Location location, mlir_ts::ClassType classType, - SmallVector &operands, const GenContext &genContext, bool onStack = false) - { - auto classInfo = getClassInfoByFullName(classType.getName().getValue()); - if (onStack && classInfo->hasVirtualTable) - { - emitError(location, "") << "can't instantiate new instance of " << to_print(classType) << " which has 'virtual table' on stack"; - return mlir::failure(); - } + ValueOrLogicalResult mlirGenCallExpression(mlir::Location location, mlir::Value funcResult, + NodeArray typeArguments, SmallVector &operands, + const GenContext &genContext); - auto newOp = onStack - ? NewClassInstanceLogicAsOp(location, classType, onStack, genContext) - : ValueOrLogicalResult(NewClassInstanceAsMethodCallOp(location, classInfo, true, genContext)); - EXIT_IF_FAILED_OR_NO_VALUE(newOp) - if (mlir::failed(mlirGenCallConstructor(location, classInfo, V(newOp), operands, false, genContext))) - { - return mlir::failure(); - } + ValueOrLogicalResult NewClassInstanceOnStack(mlir::Location location, mlir_ts::ClassType classType, + SmallVector &operands, const GenContext &genContext); - return V(newOp); - } + ValueOrLogicalResult NewClassInstance(mlir::Location location, mlir_ts::ClassType classType, + SmallVector &operands, const GenContext &genContext, bool onStack = false); ValueOrLogicalResult mlirGenCall(mlir::Location location, mlir::Value funcRefValue, - SmallVector &operands, const GenContext &genContext) - { - ValueOrLogicalResult value(mlir::failure()); - mlir::TypeSwitch(funcRefValue.getType()) - .Case([&](auto calledFuncType) { - value = mlirGenCallFunction(location, calledFuncType, funcRefValue, operands, genContext); - }) - .Case([&](auto calledFuncType) { - value = mlirGenCallFunction(location, calledFuncType, funcRefValue, operands, genContext); - }) - .Case([&](auto calledBoundFuncType) { - auto calledFuncType = - getFunctionType(calledBoundFuncType.getInputs(), calledBoundFuncType.getResults(), calledBoundFuncType.isVarArg()); - auto thisValue = builder.create(location, calledFuncType.getInput(0), funcRefValue); - auto unboundFuncRefValue = builder.create(location, calledFuncType, funcRefValue); - value = mlirGenCallFunction(location, calledFuncType, unboundFuncRefValue, thisValue, operands, genContext); - }) - .Case([&](auto calledExtentFuncType) { - auto calledFuncType = - getFunctionType(calledExtentFuncType.getInputs(), calledExtentFuncType.getResults(), calledExtentFuncType.isVarArg()); - if (auto createExtensionFunctionOp = funcRefValue.getDefiningOp()) - { - auto thisValue = createExtensionFunctionOp.getThisVal(); - auto funcRefValue = createExtensionFunctionOp.getFunc(); - value = mlirGenCallFunction(location, calledFuncType, funcRefValue, thisValue, operands, genContext); - } - else - { - emitError(location, "not supported"); - value = mlir::Value(); - } - }) - .Case([&](auto classType) { - value = NewClassInstanceOnStack(location, classType, operands, genContext); - }) - .Case([&](auto classStorageType) { - MLIRCodeLogic mcl(builder, compileOptions); - auto refValue = mcl.GetReferenceFromValue(location, funcRefValue); - if (refValue) - { - // seems we are calling type constructor for super() - auto classInfo = getClassInfoByFullName(classStorageType.getName().getValue()); - // to track result call - value = mlirGenCallConstructor(location, classInfo, refValue, operands, true, genContext); - } - else - { - llvm_unreachable("not implemented"); - } - }) - .Default([&](auto type) { - emitError(location, "not supported function type"); - value = mlir::Value(); - }); - - return value; - } + SmallVector &operands, const GenContext &genContext); template ValueOrLogicalResult mlirGenCallFunction(mlir::Location location, T calledFuncType, mlir::Value funcRefValue, @@ -8063,39 +6930,7 @@ class MLIRGenImpl }; ValueOrLogicalResult callIteratorNext(mlir::Location location, mlir::Value nextProperty, - OperandsProcessingInfo* operandsProcessingInfo, const GenContext &genContext) - { - // call nextProperty - SmallVector callOperands; - auto callResult = mlirGenCall(location, nextProperty, callOperands, genContext); - EXIT_IF_FAILED_OR_NO_VALUE(callResult) - - // load property "value" - auto doneProperty = mlirGenPropertyAccessExpression(location, callResult, "done", false, genContext); - EXIT_IF_FAILED_OR_NO_VALUE(doneProperty) - - auto valueProperty = mlirGenPropertyAccessExpression(location, callResult, "value", false, genContext); - EXIT_IF_FAILED_OR_NO_VALUE(valueProperty) - - auto valueProp = V(valueProperty); - - if (operandsProcessingInfo != nullptr) - { - if (auto receiverType = operandsProcessingInfo->isCastNeededWithOptionalUnwrap(valueProp.getType())) - { - CAST(valueProp, location, receiverType, valueProp, genContext); - } - } - - // conditional expr: done ? undefined : value - auto doneInvValue = V(builder.create(location, getBooleanType(), - builder.getI32IntegerAttr((int)SyntaxKind::ExclamationToken), doneProperty)); - - mlir::Value condValue = builder.create( - location, getOptionalType(valueProp.getType()), valueProp, doneInvValue); - - return condValue; - } + OperandsProcessingInfo* operandsProcessingInfo, const GenContext &genContext); bool hasIterator(mlir::Location location, mlir::Value source, const GenContext &genContext) { @@ -8139,93 +6974,7 @@ class MLIRGenImpl return false; } - mlir::LogicalResult processOperandSpreadElement(mlir::Location location, mlir::Value source, OperandsProcessingInfo &operandsProcessingInfo, const GenContext &genContext) - { - auto count = operandsProcessingInfo.restCount(); - - if (hasIterator(location, source, genContext)) - { - // treat it as .next().value structure - // property - auto nextProperty = mlirGenPropertyAccessExpression( - location, source, ITERATOR_NEXT, false, genContext); - - for (auto spreadIndex = 0; spreadIndex < count; spreadIndex++) - { - auto result = callIteratorNext(location, nextProperty, &operandsProcessingInfo, genContext); - EXIT_IF_FAILED_OR_NO_VALUE(result) - operandsProcessingInfo.addOperandAndMoveToNextParameter(V(result)); - } - - return mlir::success(); - } - - if (isArrayLike(location, source, genContext)) - { - // treat it as [index] structure - auto lengthValue = mlirGenPropertyAccessExpression(location, source, LENGTH_FIELD_NAME, false, genContext); - EXIT_IF_FAILED_OR_NO_VALUE(lengthValue) - CAST(lengthValue, location, builder.getIndexType(), lengthValue, genContext); - - auto elementType = evaluateElementAccess(location, source, false, genContext); - if (genContext.receiverType && genContext.receiverType != elementType) - { - elementType = genContext.receiverType; - } - - auto valueFactory = - (isa(elementType)) - ? &MLIRGenImpl::anyOrUndefined - : &MLIRGenImpl::optionalValueOrUndefined; - - for (auto spreadIndex = 0; spreadIndex < count; spreadIndex++) - { - auto indexVal = builder.create(location, mth.getIndexType(), - mth.getIndexAttrValue(spreadIndex)); - - // conditional expr: length > "spreadIndex" ? value[index] : undefined - auto inBoundsValue = V(builder.create(location, getBooleanType(), - builder.getI32IntegerAttr((int)SyntaxKind::GreaterThanToken), - lengthValue, - indexVal)); - - auto spreadValue = (this->*valueFactory)(location, inBoundsValue, - [&](auto genContext) { - auto result = mlirGenElementAccess(location, source, indexVal, false, genContext); - EXIT_IF_FAILED_OR_NO_VALUE(result) - auto value = V(result); - - if (auto receiverType = operandsProcessingInfo.isCastNeeded(value.getType())) - { - CAST(value, location, receiverType, value, genContext); - } - - return ValueOrLogicalResult(value); - }, genContext); - EXIT_IF_FAILED_OR_NO_VALUE(spreadValue) - - operandsProcessingInfo.addOperandAndMoveToNextParameter(spreadValue); - } - - return mlir::success(); - } - - // this is defualt behavior for tuple - // treat it as [index] structure - for (auto spreadIndex = 0; spreadIndex < count; spreadIndex++) - { - auto indexVal = builder.create(location, mth.getStructIndexType(), - mth.getStructIndexAttrValue(spreadIndex)); - - auto result = mlirGenElementAccess(location, source, indexVal, false, genContext); - EXIT_IF_FAILED_OR_NO_VALUE(result) - auto value = V(result); - - operandsProcessingInfo.addOperandAndMoveToNextParameter(value); - } - - return mlir::success(); - } + mlir::LogicalResult processOperandSpreadElement(mlir::Location location, mlir::Value source, OperandsProcessingInfo &operandsProcessingInfo, const GenContext &genContext); mlir::LogicalResult mlirGenOperand(Expression expression, OperandsProcessingInfo &operandsProcessingInfo, const GenContext &genContext) { @@ -8427,241 +7176,21 @@ class MLIRGenImpl mlir::LogicalResult mlirGenCallConstructor(mlir::Location location, ClassInfo::TypePtr classInfo, mlir::Value thisValue, SmallVector &operands, - bool castThisValueToClass, const GenContext &genContext) - { - assert(classInfo); - - auto virtualTable = classInfo->getHasVirtualTable(); - auto hasConstructor = classInfo->getHasConstructor(); - if (!hasConstructor && !virtualTable) - { - return mlir::success(); - } - - auto effectiveThisValue = thisValue; - if (castThisValueToClass) - { - CAST(effectiveThisValue, location, classInfo->classType, thisValue, genContext); - } - - if (classInfo->getHasConstructor()) - { - auto accessingFromLevel = detectAccessLevel(mlir::cast(effectiveThisValue.getType()), genContext); - if (accessingFromLevel < classInfo->constructorAccessLevel) { - emitError(location, "Class constructor is not accessable"); - return mlir::failure(); - } - - auto propAccess = - mlirGenPropertyAccessExpression(location, effectiveThisValue, CONSTRUCTOR_NAME, false, genContext); - - if (!propAccess && !genContext.allowPartialResolve) - { - emitError(location) << "Call Constructor: can't find constructor"; - } - - EXIT_IF_FAILED_OR_NO_VALUE(propAccess) - return mlirGenCall(location, propAccess, operands, genContext); - } - - return mlir::success(); - } + bool castThisValueToClass, const GenContext &genContext); // TODO: refactor it, somehow when NewClassInstanceAsMethodCallOp calling Ctor and NewClassInstanceLogicAsOp is not ValueOrLogicalResult NewClassInstance(mlir::Location location, mlir::Value value, NodeArray arguments, NodeArray typeArguments, bool suppressConstructorCall, - const GenContext &genContext) - { - - auto type = value.getType(); - type = mth.convertConstTupleTypeToTupleType(type); - - assert(type); - - auto resultType = type; - if (mth.isValueType(type)) - { - resultType = getValueRefType(type); - } - - // if true, will call Class..new method, otheriwise ts::NewOp which we need to implement Class..new method - auto methodCallWay = !suppressConstructorCall; - - mlir::Value newOp; - if (auto classType = dyn_cast(resultType)) - { - auto classInfo = getClassInfoByFullName(classType.getName().getValue()); - if (!classInfo) - { - auto genericClassInfo = getGenericClassInfoByFullName(classType.getName().getValue()); - if (genericClassInfo) - { - emitError(location) << "Generic class '"<< to_print(classType) << "' is missing type arguments "; - return mlir::failure(); - } - - emitError(location) << "Can't find class " << to_print(classType); - return mlir::failure(); - } - - if (genContext.dummyRun) - { - // just to cut a lot of calls - newOp = builder.create(location, classInfo->classType, builder.getBoolAttr(false)); - return newOp; - } - - auto newOp = NewClassInstanceAsMethodCallOp(location, classInfo, methodCallWay, genContext); - if (!newOp) - { - return mlir::failure(); - } - - if (methodCallWay) - { - // evaluate constructor - mlir::Type tupleParamsType; - - // we need context with correct thisType to get access to contructor - GenContext thisTypeGenContext(genContext); - thisTypeGenContext.thisType = mlir::cast(newOp.getType()); - - auto funcValueRef = evaluateProperty(location, newOp, CONSTRUCTOR_NAME, thisTypeGenContext); - if (funcValueRef) - { - SmallVector operands; - if (mlir::failed(mlirGenOperands(arguments, operands, funcValueRef, genContext, 1/*this params shift*/))) - { - emitError(location) << "Call constructor: can't resolve values of all parameters"; - return mlir::failure(); - } - - assert(newOp); - auto result = mlirGenCallConstructor(location, classInfo, newOp, operands, false, genContext); - EXIT_IF_FAILED(result) - } - } - - return newOp; - } - - return NewClassInstanceLogicAsOp(location, resultType, false, genContext); - } + const GenContext &genContext); ValueOrLogicalResult NewClassInstanceLogicAsOp(mlir::Location location, mlir::Type typeOfInstance, bool stackAlloc, - const GenContext &genContext) - { - if (auto classType = dyn_cast(typeOfInstance)) - { - // set virtual table - auto classInfo = getClassInfoByFullName(classType.getName().getValue()); - if (!classInfo) - { - auto genericClassInfo = getGenericClassInfoByFullName(classType.getName().getValue()); - if (genericClassInfo) - { - emitError(location) << "Generic class '"<< to_print(classType) << "' is missing type arguments "; - return mlir::failure(); - } - - emitError(location) << "Can't find class " << to_print(classType); - return mlir::Value(); - } - - return NewClassInstanceLogicAsOp(location, classInfo, stackAlloc, genContext); - } - - LLVM_DEBUG(llvm::dbgs() << "\n!! new op (no method): " << typeOfInstance << "\n";); - - auto newOp = builder.create(location, typeOfInstance, builder.getBoolAttr(stackAlloc)); - return V(newOp); - } + const GenContext &genContext); mlir::Value NewClassInstanceLogicAsOp(mlir::Location location, ClassInfo::TypePtr classInfo, bool stackAlloc, - const GenContext &genContext) - { - mlir::Value newOp; -#if ENABLE_TYPED_GC - auto enabledGC = !compileOptions.disableGC; - if (enabledGC && !stackAlloc) - { - auto typeDescrType = builder.getI64Type(); - auto typeDescGlobalName = getTypeDescriptorFieldName(classInfo); - auto typeDescRef = resolveFullNameIdentifier(location, typeDescGlobalName, true, genContext); - auto typeDescCurrentValue = builder.create(location, typeDescrType, typeDescRef); - - CAST_A(condVal, location, getBooleanType(), typeDescCurrentValue, genContext); - - auto ifOp = builder.create( - location, mlir::TypeRange{typeDescrType}, condVal, - [&](mlir::OpBuilder &opBuilder, mlir::Location loc) { - builder.create(loc, mlir::ValueRange{typeDescCurrentValue}); - }, - [&](mlir::OpBuilder &opBuilder, mlir::Location loc) { - // call typr bitmap - auto fullClassStaticFieldName = getTypeBitmapMethodName(classInfo); - - auto funcType = getFunctionType({}, {typeDescrType}, false); - - auto funcSymbolOp = builder.create( - location, funcType, - mlir::FlatSymbolRefAttr::get(builder.getContext(), fullClassStaticFieldName)); - - auto callIndirectOp = - builder.create( - MLIRHelper::getCallSiteLocation(funcSymbolOp->getLoc(), location), - funcSymbolOp, mlir::ValueRange{}); - auto typeDescr = callIndirectOp.getResult(0); - - // save value - builder.create(location, typeDescr, typeDescRef); - - builder.create(loc, mlir::ValueRange{typeDescr}); - }); - - auto typeDescrValue = ifOp.getResult(0); - - assert(!stackAlloc); - newOp = builder.create(location, classInfo->classType, typeDescrValue); - } - else - { - newOp = builder.create(location, classInfo->classType, builder.getBoolAttr(stackAlloc)); - } -#else - newOp = builder.create(location, classInfo->classType, builder.getBoolAttr(stackAlloc)); -#endif - mlirGenSetVTableToInstance(location, classInfo, newOp, genContext); - return newOp; - } + const GenContext &genContext); mlir::Value NewClassInstanceAsMethodCallOp(mlir::Location location, ClassInfo::TypePtr classInfo, bool asMethodCall, - const GenContext &genContext) - { -#ifdef USE_NEW_AS_METHOD - if (asMethodCall) - { - auto classRefVal = builder.create( - location, classInfo->classType, - mlir::FlatSymbolRefAttr::get(builder.getContext(), classInfo->classType.getName().getValue())); - - // call ..new to create new instance - auto result = mlirGenPropertyAccessExpression(location, classRefVal, NEW_METHOD_NAME, false, genContext); - EXIT_IF_FAILED_OR_NO_VALUE(result) - auto newFuncRef = V(result); - - assert(newFuncRef); - - SmallVector emptyOperands; - auto resultCall = mlirGenCallExpression(location, newFuncRef, {}, emptyOperands, genContext); - EXIT_IF_FAILED_OR_NO_VALUE(resultCall) - auto newOp = V(resultCall); - return newOp; - } -#endif - - return NewClassInstanceLogicAsOp(location, classInfo, false, genContext); - } + const GenContext &genContext); ValueOrLogicalResult NewArray(mlir::Location location, mlir::Type type, NodeArray arguments, const GenContext &genContext) { @@ -8717,21 +7246,7 @@ class MLIRGenImpl } ValueOrLogicalResult NewClassInstanceByCallingNewCtor(mlir::Location location, mlir::Value value, NodeArray arguments, - NodeArray typeArguments, const GenContext &genContext) - { - auto result = mlirGenPropertyAccessExpression(location, value, NEW_CTOR_METHOD_NAME, genContext); - EXIT_IF_FAILED_OR_NO_VALUE(result) - auto newCtorMethod = V(result); - - SmallVector operands; - if (mlir::failed(mlirGenOperands(arguments, operands, newCtorMethod.getType(), genContext))) - { - emitError(location) << "Call new instance: can't resolve values of all parameters"; - return mlir::failure(); - } - - return mlirGenCallExpression(location, newCtorMethod, typeArguments, operands, genContext); - } + NodeArray typeArguments, const GenContext &genContext); ValueOrLogicalResult mlirGen(NewExpression newExpression, const GenContext &genContext);