size_t getLvalCount(const SEM::Type* type) { type = getDerefType(type); size_t count = 0; while (type->isLval()) { count++; type = getDerefType(type->lvalTarget()); } return count; }
AST::Value CallValue(Context& context, AST::Value rawValue, HeapArray<AST::Value> args, const Debug::SourceLocation& location) { auto value = derefValue(std::move(rawValue)); if (getDerefType(value.type())->isTypename()) { return CallValue(context, GetStaticMethod(context, std::move(value), context.getCString("create"), location), std::move(args), location); } if (!value.type()->isCallable()) { // Try to use 'call' method. if (TypeCapabilities(context).hasCallMethod(getDerefType(value.type()))) { return CallValue(context, GetMethod(context, std::move(value), context.getCString("call"), location), std::move(args), location); } else { context.issueDiag(TypeNotCallableDiag(getDerefType(value.type())), location); return AST::Value::Constant(Constant::Integer(0), context.typeBuilder().getIntType()); } } const auto functionType = value.type()->asFunctionType(); const auto& typeList = functionType.parameterTypes(); if (functionType.attributes().isVarArg()) { if (args.size() < typeList.size()) { context.issueDiag(VarArgTooFewArgsDiag(value.toDiagString(), args.size(), typeList.size()), location); } } else { if (args.size() != typeList.size()) { context.issueDiag(CallIncorrectArgCountDiag(value.toDiagString(), args.size(), typeList.size()), location); } } if (!TypeCapabilities(context).isSized(functionType.returnType())) { // TODO: also check that the type is not abstract. context.issueDiag(CallReturnTypeIsUnsizedDiag(functionType.returnType()), location); } if (functionType.returnType()->hasConst()) { context.issueDiag(CallReturnTypeIsConstDiag(functionType.returnType()), location); } return addDebugInfo(AST::Value::Call(std::move(value), CastFunctionArguments(context, std::move(args), typeList, location), functionType.returnType()->stripConst()), location); }
const SEM::Type* makeLvalType(Context& context, const bool isFinal, const SEM::Type* const valueType) { if (getDerefType(valueType)->isLval()) { return valueType; } if (isFinal) { return makeFinalLvalType(context, valueType); } else { return makeValueLvalType(context, valueType); } }
SEM::Value GetTemplatedMethod(Context& context, SEM::Value rawValue, const String& methodName, SEM::ValueArray templateArguments, const Debug::SourceLocation& location) { auto value = derefOrBindValue(context, tryDissolveValue(context, derefOrBindValue(context, std::move(rawValue)), location)); const auto type = getDerefType(value.type())->resolveAliases(); return GetTemplatedMethodWithoutResolution(context, std::move(value), type, methodName, std::move(templateArguments), location); }