From 19be3b2a1d2ff4d31beedbbce0b0ae0183e5ef4d Mon Sep 17 00:00:00 2001 From: Ben Harshbarger Date: Thu, 30 Jan 2025 20:10:29 -0800 Subject: [PATCH] Dyno: Add support for file-related reflection routines Signed-off-by: Ben Harshbarger --- .../lib/resolution/resolution-queries.cpp | 57 ++++++++++++++++++- frontend/test/resolution/testReflection.cpp | 31 ++++++++++ 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/frontend/lib/resolution/resolution-queries.cpp b/frontend/lib/resolution/resolution-queries.cpp index c6402cf44b6e..fcd8ff95bfb1 100644 --- a/frontend/lib/resolution/resolution-queries.cpp +++ b/frontend/lib/resolution/resolution-queries.cpp @@ -5092,6 +5092,49 @@ resolutionResultFromMostSpecificCandidate(ResolutionContext* rc, exprType, yieldedType, poiInfo); } +static bool handleReflectionFunction(ResolutionContext* rc, + const TypedFnSignature* sig, + const Call* call, + QualifiedType& result) { + if (sig->isCompilerGenerated()) return false; + + auto context = rc->context(); + auto fn = parsing::idToAst(context, sig->id())->toFunction(); + if (fn && fn->attributeGroup()) { + auto attr = fn->attributeGroup(); + if (attr->hasPragma(pragmatags::PRAGMA_GET_LINE_NUMBER)) { + auto loc = parsing::locateId(context, call->id()); + result = QualifiedType::makeParamInt(context, loc.firstLine()); + return true; + } else if (attr->hasPragma(pragmatags::PRAGMA_GET_FILE_NAME)) { + auto loc = parsing::locateId(context, call->id()); + result = QualifiedType::makeParamString(context, loc.path()); + return true; + } else if (attr->hasPragma(pragmatags::PRAGMA_GET_FUNCTION_NAME)) { + auto func = parsing::idToParentFunctionId(context, call->id()); + if (!func.isEmpty()) { + auto name = func.symbolName(context); + result = QualifiedType::makeParamString(context, name); + } else { + // For compatibility with production + // TODO: What *should* happen here? + auto mod = parsing::idToParentModule(context, call->id()); + auto name = mod.symbolName(context); + auto initFn = UniqueString::get(context, "chpl__init_" + name.str()); + result = QualifiedType::makeParamString(context, initFn); + } + return true; + } else if (attr->hasPragma(pragmatags::PRAGMA_GET_MODULE_NAME)) { + auto mod = parsing::idToParentModule(context, call->id()); + auto name = mod.symbolName(context); + result = QualifiedType::makeParamString(context, name); + return true; + } + } + + return false; +} + // call can be nullptr. in that event ci.name() will be used to find // what is called. static CallResolutionResult @@ -5166,8 +5209,18 @@ resolveFnCall(ResolutionContext* rc, for (const MostSpecificCandidate& candidate : mostSpecific) { if (candidate.fn() != nullptr) { bool isIterator = candidate.fn()->isIterator(); - QualifiedType rt = returnType(rc, candidate.fn(), - instantiationPoiScope); + + QualifiedType rt; + // TODO: Ideally we'd refactor things such that we instantiate some kind + // of hidden argument to these functions that is then returned. Alas, we + // still need this stuff to work with production, so we create this hack. + if (handleReflectionFunction(rc, candidate.fn(), call, rt)) { + CHPL_ASSERT(rt.isParam() && rt.hasParamPtr()); + } else { + rt = returnType(rc, candidate.fn(), + instantiationPoiScope); + } + QualifiedType yt; if (!candidate.promotedFormals().empty()) { diff --git a/frontend/test/resolution/testReflection.cpp b/frontend/test/resolution/testReflection.cpp index c58719ea975b..908bcba9cbc9 100644 --- a/frontend/test/resolution/testReflection.cpp +++ b/frontend/test/resolution/testReflection.cpp @@ -312,6 +312,36 @@ static void test9() { ensureParamBool(variables.at("r7"), false); } +static void test10() { + auto context = buildStdContext(); + ErrorGuard guard(context); + + auto variables = resolveTypesOfVariables(context, + R"""( + module M { + use Reflection; + + param lineno = getLineNumber(); + + param toplevelFn = getRoutineName(); + + proc bar() param { + return getRoutineName(); + } + param fn = bar(); + + param filename = getFileName(); + + param modname = getModuleName(); + } + )""", {"lineno", "filename", "toplevelFn", "fn", "modname"}); + ensureParamInt(variables["lineno"], 5); + ensureParamString(variables["filename"], "input.chpl"); + ensureParamString(variables["toplevelFn"], "chpl__init_M"); + ensureParamString(variables["fn"], "bar"); + ensureParamString(variables["modname"], "M"); +} + int main() { test1(); test2(); @@ -322,5 +352,6 @@ int main() { test7(); test8(); test9(); + test10(); return 0; }