From 1ee791c42103979e3009abb335b911a2b3b75fbe Mon Sep 17 00:00:00 2001 From: Ben Harshbarger Date: Sun, 17 Mar 2024 17:55:39 -0700 Subject: [PATCH 01/14] Ignore c_ptr/Const module definitions in dyno We are managing the implementation of c_ptr/Const directly in the frontend as opposed to using some hacky module definition, so to avoid duplicate results when resolving identifiers, skip the c_ptr and c_ptrConst classes during scope resolution. Signed-off-by: Ben Harshbarger --- frontend/lib/resolution/scope-queries.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontend/lib/resolution/scope-queries.cpp b/frontend/lib/resolution/scope-queries.cpp index cddca4df3036..f16c563f74b1 100644 --- a/frontend/lib/resolution/scope-queries.cpp +++ b/frontend/lib/resolution/scope-queries.cpp @@ -160,6 +160,11 @@ struct GatherDecls { // since dyno handles tuple types directly rather // than through a record. skip = true; + } else if (d->isClass() && + d->attributeGroup() != nullptr && + d->attributeGroup()->hasPragma(uast::pragmatags::PRAGMA_C_PTR_CLASS) && + (d->name() == "c_ptr" || d->name() == "c_ptrConst")) { + skip = true; } if (skip == false) { From 85d87831f956898e49d162344429b6978cc26380 Mon Sep 17 00:00:00 2001 From: Ben Harshbarger Date: Sun, 17 Mar 2024 17:57:38 -0700 Subject: [PATCH 02/14] Refactor default function helpers to take a QualifiedType This refactoring allows for the creation of both type and value methods depending on the way in which the default function was called. With this functionality available, this commit also allows for calling ``eltType`` on either a c_ptr/Const type or value. Also adds ``CPtrType::id(Context*)`` to more easily grab the correct ID, instead of checking ``isConst()`` and using ``getId`` or ``getConstId``. Signed-off-by: Ben Harshbarger --- frontend/include/chpl/types/CPtrType.h | 4 +++ frontend/lib/resolution/default-functions.cpp | 25 +++++++++++-------- frontend/lib/resolution/default-functions.h | 3 ++- .../lib/resolution/resolution-queries.cpp | 2 +- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/frontend/include/chpl/types/CPtrType.h b/frontend/include/chpl/types/CPtrType.h index 35c236dfcf45..7d9b9532021b 100644 --- a/frontend/include/chpl/types/CPtrType.h +++ b/frontend/include/chpl/types/CPtrType.h @@ -82,6 +82,10 @@ class CPtrType final : public Type { static const ID& getId(Context* context); static const ID& getConstId(Context* context); + const ID& id(Context* context) const { + return isConst() ? getConstId(context) : getId(context); + } + const Type* eltType() const { return eltType_; } diff --git a/frontend/lib/resolution/default-functions.cpp b/frontend/lib/resolution/default-functions.cpp index 127ae7f4abf5..31818f7804a3 100644 --- a/frontend/lib/resolution/default-functions.cpp +++ b/frontend/lib/resolution/default-functions.cpp @@ -685,24 +685,27 @@ generateRecordComparison(Context* context, const CompositeType* lhsType) { } static const TypedFnSignature* -generateCPtrMethod(Context* context, const CPtrType * cpt, UniqueString name) { +generateCPtrMethod(Context* context, QualifiedType receiverType, + UniqueString name) { // Build a basic function signature for methods on a cptr // TODO: we should really have a way to just set the return type here + const CPtrType* cpt = receiverType.type()->toCPtrType(); const TypedFnSignature* result = nullptr; std::vector formals; std::vector formalTypes; formals.push_back(UntypedFnSignature::FormalDetail(USTR("this"), false, nullptr)); - formalTypes.push_back(QualifiedType(QualifiedType::CONST_REF, cpt)); + auto qual = receiverType.isType() ? QualifiedType::TYPE : QualifiedType::CONST_REF; + formalTypes.push_back(QualifiedType(qual, cpt)); auto ufs = UntypedFnSignature::get(context, - /*id*/ cpt->getId(context), + /*id*/ cpt->id(context), /*name*/ name, /*isMethod*/ true, /*isTypeConstructor*/ false, /*isCompilerGenerated*/ true, /*throws*/ false, - /*idTag*/ parsing::idToTag(context, cpt->getId(context)), + /*idTag*/ asttags::Record, /*parsing::idToTag(context, cpt->getId(context)),*/ /*kind*/ uast::Function::Kind::PROC, /*formals*/ std::move(formals), /*whereClause*/ nullptr); @@ -719,9 +722,11 @@ generateCPtrMethod(Context* context, const CPtrType * cpt, UniqueString name) { } static const TypedFnSignature* const& -getCompilerGeneratedMethodQuery(Context* context, const Type* type, +getCompilerGeneratedMethodQuery(Context* context, QualifiedType receiverType, UniqueString name, bool parenless) { - QUERY_BEGIN(getCompilerGeneratedMethodQuery, context, type, name, parenless); + QUERY_BEGIN(getCompilerGeneratedMethodQuery, context, receiverType, name, parenless); + + const Type* type = receiverType.type(); const TypedFnSignature* result = nullptr; @@ -749,8 +754,8 @@ getCompilerGeneratedMethodQuery(Context* context, const Type* type, } else { CHPL_UNIMPL("record method not implemented yet!"); } - } else if (auto cPtrType = type->toCPtrType()) { - result = generateCPtrMethod(context, cPtrType, name); + } else if (type->isCPtrType()) { + result = generateCPtrMethod(context, receiverType, name); } else { CHPL_UNIMPL("should not be reachable"); } @@ -855,9 +860,9 @@ generateCastToEnum(Context* context, If no method was generated, returns nullptr. */ const TypedFnSignature* -getCompilerGeneratedMethod(Context* context, const Type* type, +getCompilerGeneratedMethod(Context* context, const QualifiedType receiverType, UniqueString name, bool parenless) { - return getCompilerGeneratedMethodQuery(context, type, name, parenless); + return getCompilerGeneratedMethodQuery(context, receiverType, name, parenless); } static const TypedFnSignature* const& diff --git a/frontend/lib/resolution/default-functions.h b/frontend/lib/resolution/default-functions.h index 414b8719691f..52d0d0f905b3 100644 --- a/frontend/lib/resolution/default-functions.h +++ b/frontend/lib/resolution/default-functions.h @@ -54,7 +54,8 @@ bool needCompilerGeneratedMethod(Context* context, const types::Type* type, If no method was generated, returns nullptr. */ const TypedFnSignature* -getCompilerGeneratedMethod(Context* context, const types::Type* type, +getCompilerGeneratedMethod(Context* context, + const types::QualifiedType receiverType, UniqueString name, bool parenless); /** diff --git a/frontend/lib/resolution/resolution-queries.cpp b/frontend/lib/resolution/resolution-queries.cpp index 304b0c21dd28..4266a9cfd922 100644 --- a/frontend/lib/resolution/resolution-queries.cpp +++ b/frontend/lib/resolution/resolution-queries.cpp @@ -3413,7 +3413,7 @@ considerCompilerGeneratedMethods(Context* context, } // get the compiler-generated function, may be generic - auto tfs = getCompilerGeneratedMethod(context, receiverType, ci.name(), + auto tfs = getCompilerGeneratedMethod(context, receiver.type(), ci.name(), ci.isParenless()); return tfs; } From 18646025202fdd7da7367abdab5f4ac5231cf4fd Mon Sep 17 00:00:00 2001 From: Ben Harshbarger Date: Sun, 17 Mar 2024 17:59:55 -0700 Subject: [PATCH 03/14] Avoid segfault while accumulating POIs The 'call' might be null if we're resolving a generated call. Signed-off-by: Ben Harshbarger --- frontend/lib/resolution/resolution-queries.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/lib/resolution/resolution-queries.cpp b/frontend/lib/resolution/resolution-queries.cpp index 4266a9cfd922..0a0b77fac82f 100644 --- a/frontend/lib/resolution/resolution-queries.cpp +++ b/frontend/lib/resolution/resolution-queries.cpp @@ -4066,7 +4066,9 @@ findMostSpecificAndCheck(Context* context, } // note any most-specific candidates from POI in poiInfo. - { + // TODO: This can be the case for generated calls, but is skipping the POI + // accumulation safe? + if (call != nullptr) { size_t n = candidates.size(); for (size_t i = firstPoiCandidate; i < n; i++) { for (const MostSpecificCandidate& candidate : mostSpecific) { From a159ec10f8dea324b68020e5d85438dbc156bda0 Mon Sep 17 00:00:00 2001 From: Ben Harshbarger Date: Sun, 17 Mar 2024 18:00:42 -0700 Subject: [PATCH 04/14] Allow for c_ptr/Const usage with STRING_LENGTH_BYTES Signed-off-by: Ben Harshbarger --- frontend/lib/resolution/prims.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/lib/resolution/prims.cpp b/frontend/lib/resolution/prims.cpp index 58f996b86006..69037bf77ac8 100644 --- a/frontend/lib/resolution/prims.cpp +++ b/frontend/lib/resolution/prims.cpp @@ -1332,7 +1332,8 @@ CallResolutionResult resolvePrimCall(Context* context, break; } else if (actualType.type()->isStringType() || actualType.type()->isBytesType() || - actualType.type()->isCStringType()) { + actualType.type()->isCStringType() || + actualType.type()->isCPtrType()) { // for non-param string/bytes, the return type is just a default int type = QualifiedType(QualifiedType::CONST_VAR, IntType::get(context, 0)); From dd3aef0986491faaa86b5acda2b9d881fd7712b6 Mon Sep 17 00:00:00 2001 From: Ben Harshbarger Date: Sun, 17 Mar 2024 18:00:59 -0700 Subject: [PATCH 05/14] Update isMissingBundledClassType to include c_ptrConst Signed-off-by: Ben Harshbarger --- frontend/lib/types/CompositeType.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/lib/types/CompositeType.cpp b/frontend/lib/types/CompositeType.cpp index 808d19c530e5..798ec025f2ea 100644 --- a/frontend/lib/types/CompositeType.cpp +++ b/frontend/lib/types/CompositeType.cpp @@ -201,7 +201,8 @@ bool CompositeType::isMissingBundledClassType(Context* context, ID id) { auto path = id.symbolPath(); return path == "ChapelReduce.ReduceScanOp" || path == "Errors.Error" || - path == "CTypes.c_ptr"; + path == "CTypes.c_ptr" || + path == "CTypes.c_ptrConst"; } return false; From 692ca15ccc83f9d3b3af645ac1f36574ec29724b Mon Sep 17 00:00:00 2001 From: Ben Harshbarger Date: Fri, 29 Mar 2024 16:54:56 -0700 Subject: [PATCH 06/14] c_ptr is no longer considered a builtin type With c_ptr no longer being a builtin type, we can more directly rely on the fake "c_ptr" class in CTypes.chpl as an "anchor" for the type's ID. A few changes to resolution-queries are required to handle some CPtrType special cases. The main change is to lookupCalledExpr, which allows for the resolution of methods on c_ptr even when CTypes is no longer in scope. Signed-off-by: Ben Harshbarger --- .../lib/resolution/resolution-queries.cpp | 17 ++++++++++ frontend/lib/resolution/scope-queries.cpp | 5 --- frontend/lib/types/Type.cpp | 4 --- frontend/test/resolution/testCPtr.cpp | 31 ++++++++++++++++--- frontend/test/resolution/testReturnTypes.cpp | 17 ++++++++-- 5 files changed, 58 insertions(+), 16 deletions(-) diff --git a/frontend/lib/resolution/resolution-queries.cpp b/frontend/lib/resolution/resolution-queries.cpp index 0a0b77fac82f..0acabcb67d11 100644 --- a/frontend/lib/resolution/resolution-queries.cpp +++ b/frontend/lib/resolution/resolution-queries.cpp @@ -2676,6 +2676,15 @@ doIsCandidateApplicableInitial(Context* context, return ApplicabilityResult::failure(candidateId, /* TODO */ FAIL_CANDIDATE_OTHER); } + // Ignore the 'eltType' declaration in the fake c_ptr[Const] classes. A + // compiler-generated function will handle it since we're representing the + // type entirely within the frontend. + if ((candidateId.symbolPath() == CPtrType::getId(context).symbolPath() || + candidateId.symbolPath() == CPtrType::getConstId(context).symbolPath()) && + ci.name() == "eltType") { + return ApplicabilityResult::failure(candidateId, /* TODO */ FAIL_CANDIDATE_OTHER); + } + if (isVariable(tag)) { if (ci.isParenless() && ci.isMethodCall() && ci.numActuals() == 1) { // calling a field accessor @@ -3036,6 +3045,12 @@ static const Type* getCPtrType(Context* context, UniqueString name = ci.name(); bool isConst; + // 'typeForId' should have prepared this for us if 'CTypes' was in scope. + auto called = ci.calledType(); + if (!(called.hasTypePtr() && called.type()->isCPtrType())) { + return nullptr; + } + if (name == USTR("c_ptr")) { isConst = false; } else if (name == USTR("c_ptrConst")) { @@ -3502,6 +3517,8 @@ lookupCalledExpr(Context* context, if (auto compType = t->getCompositeType()) { receiverScopes = Resolver::gatherReceiverAndParentScopesForType(context, compType); + } else if (auto cptr = t->toCPtrType()) { + receiverScopes.push_back(scopeForId(context, cptr->id(context))); } } } diff --git a/frontend/lib/resolution/scope-queries.cpp b/frontend/lib/resolution/scope-queries.cpp index f16c563f74b1..cddca4df3036 100644 --- a/frontend/lib/resolution/scope-queries.cpp +++ b/frontend/lib/resolution/scope-queries.cpp @@ -160,11 +160,6 @@ struct GatherDecls { // since dyno handles tuple types directly rather // than through a record. skip = true; - } else if (d->isClass() && - d->attributeGroup() != nullptr && - d->attributeGroup()->hasPragma(uast::pragmatags::PRAGMA_C_PTR_CLASS) && - (d->name() == "c_ptr" || d->name() == "c_ptrConst")) { - skip = true; } if (skip == false) { diff --git a/frontend/lib/types/Type.cpp b/frontend/lib/types/Type.cpp index 8f4f432c2ba2..1110db8a6d2c 100644 --- a/frontend/lib/types/Type.cpp +++ b/frontend/lib/types/Type.cpp @@ -135,10 +135,6 @@ void Type::gatherBuiltins(Context* context, auto genericUnmanaged = ClassType::get(context, AnyClassType::get(context), nullptr, ClassTypeDecorator(ClassTypeDecorator::UNMANAGED)); gatherType(context, map, "unmanaged", genericUnmanaged); - gatherType(context, map, "c_ptr", CPtrType::get(context)); - - gatherType(context, map, "c_ptrConst", CPtrType::getConst(context)); - BuiltinType::gatherBuiltins(context, map); } diff --git a/frontend/test/resolution/testCPtr.cpp b/frontend/test/resolution/testCPtr.cpp index 23804f609651..6ba138c97252 100644 --- a/frontend/test/resolution/testCPtr.cpp +++ b/frontend/test/resolution/testCPtr.cpp @@ -32,14 +32,31 @@ #include +static Context* context; + +// Use a single context with revisions to get this test running faster. +static void setupContext() { + std::string chpl_home; + if (const char* chpl_home_env = getenv("CHPL_HOME")) { + chpl_home = chpl_home_env; + } else { + printf("CHPL_HOME must be set"); + exit(1); + } + Context::Configuration config; + config.chplHome = chpl_home; + context = new Context(config); +} + template void testCPtrArg(const char* formalType, const char* actualType, F&& test) { - Context ctx; - Context* context = &ctx; + context->advanceToNextRevision(false); + setupModuleSearchPaths(context, false, false, {}, {}); ErrorGuard guard(context); std::stringstream ss; + ss << "use CTypes;" << std::endl; ss << "record rec { type someType; }" << std::endl; ss << "proc f(x: " << formalType << ") {}" << std::endl; ss << "var arg: " << actualType << ";" << std::endl; @@ -53,14 +70,14 @@ void testCPtrArg(const char* formalType, const char* actualType, F&& test) { assert(modules.size() == 1); auto mainMod = modules[0]; - assert(mainMod->numStmts() == 4); + assert(mainMod->numStmts() == 5); - auto fChild = mainMod->child(1); + auto fChild = mainMod->child(2); assert(fChild->isFunction()); auto fFn = fChild->toFunction(); assert(fFn->name() == "f"); - auto fCallVar = mainMod->child(3); + auto fCallVar = mainMod->child(4); assert(fCallVar->isVariable()); auto& modResResult = resolveModule(context, mainMod->id()); @@ -294,6 +311,8 @@ static void test22() { } int main() { + setupContext(); + test1(); test2(); test3(); @@ -317,5 +336,7 @@ int main() { test21(); test22(); + delete context; + return 0; } diff --git a/frontend/test/resolution/testReturnTypes.cpp b/frontend/test/resolution/testReturnTypes.cpp index 6ed5a4c61910..96d7bf5de154 100644 --- a/frontend/test/resolution/testReturnTypes.cpp +++ b/frontend/test/resolution/testReturnTypes.cpp @@ -1095,15 +1095,26 @@ static void testSelectParams() { } static void testCPtrEltType() { + std::string chpl_home; + if (const char* chpl_home_env = getenv("CHPL_HOME")) { + chpl_home = chpl_home_env; + } else { + printf("CHPL_HOME must be set"); + exit(1); + } + Context::Configuration config; + config.chplHome = chpl_home; { //works for c_ptr std::string program = ops + R"""( + use CTypes; var y: c_ptr(uint(8)); type x = y.eltType; )"""; - Context ctx; + Context ctx(config); Context* context = &ctx; + setupModuleSearchPaths(context, false, false, {}, {}); ErrorGuard guard(context); auto qt = resolveTypeOfXInit(context, program); assert(qt.type()->isUintType()); @@ -1113,6 +1124,7 @@ static void testCPtrEltType() { { //works for user-defined class std::string program = ops + R"""( + use CTypes; class c_ptr2 { type eltType; } @@ -1120,8 +1132,9 @@ static void testCPtrEltType() { type x = y.eltType; )"""; - Context ctx; + Context ctx(config); Context* context = &ctx; + setupModuleSearchPaths(context, false, false, {}, {}); ErrorGuard guard(context); auto qt = resolveTypeOfXInit(context, program); assert(qt.type()->isUintType()); From 83942f221ee9fb585cd27f72e4a605e88edaf63a Mon Sep 17 00:00:00 2001 From: Ben Harshbarger Date: Fri, 29 Mar 2024 17:45:43 -0700 Subject: [PATCH 07/14] Implement PRIM_ARRAY_GET for CPtrType Signed-off-by: Ben Harshbarger --- frontend/lib/resolution/prims.cpp | 17 +++++++++++++++- frontend/test/resolution/testCPtr.cpp | 28 +++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/frontend/lib/resolution/prims.cpp b/frontend/lib/resolution/prims.cpp index 69037bf77ac8..36044e2c0690 100644 --- a/frontend/lib/resolution/prims.cpp +++ b/frontend/lib/resolution/prims.cpp @@ -1641,10 +1641,25 @@ CallResolutionResult resolvePrimCall(Context* context, type = QualifiedType(QualifiedType::CONST_VAR, CompositeType::getLocaleIDType(context)); break; + + case PRIM_ARRAY_GET: { + if (ci.numActuals() == 2 && ci.actual(0).type().hasTypePtr()) { + auto index = ci.actual(1).type(); + if (index.hasTypePtr() && index.type()->isIntegralType()) { + auto act = ci.actual(0).type(); + if (auto ptr = act.type()->toCPtrType()) { + type = QualifiedType(QualifiedType::REF, ptr->eltType()); + } + } else { + context->error(call, "bad call to primitive \"%s\": second argument must be an integral type", primTagToName(prim)); + } + } + } + break; + case PRIM_USED_MODULES_LIST: case PRIM_REFERENCED_MODULES_LIST: case PRIM_TUPLE_EXPAND: - case PRIM_ARRAY_GET: case PRIM_MAYBE_LOCAL_THIS: case PRIM_MAYBE_LOCAL_ARR_ELEM: case PRIM_MAYBE_AGGREGATE_ASSIGN: diff --git a/frontend/test/resolution/testCPtr.cpp b/frontend/test/resolution/testCPtr.cpp index 6ba138c97252..7a2e99c4c544 100644 --- a/frontend/test/resolution/testCPtr.cpp +++ b/frontend/test/resolution/testCPtr.cpp @@ -310,6 +310,32 @@ static void test22() { }); } +static void test23() { + ErrorGuard guard(context); + + std::string program = R"""( + module M{ + module X { + proc foo() { + use CTypes; + + var ret : c_ptr(int); + return ret; + } + } + + use X; + + var ptr = foo(); + var x = ptr[0]; + } + )"""; + + auto vars = resolveTypesOfVariables(context, program, {"ptr", "x"}); + assert(vars["ptr"].type()->isCPtrType()); + assert(vars["x"].type()->isIntType()); +} + int main() { setupContext(); @@ -336,6 +362,8 @@ int main() { test21(); test22(); + test23(); + delete context; return 0; From 12244c92f80cb5ec80f455cd836f6c287c09d4d7 Mon Sep 17 00:00:00 2001 From: Ben Harshbarger Date: Mon, 1 Apr 2024 17:20:46 -0700 Subject: [PATCH 08/14] Move eltType hack to scope-queries Signed-off-by: Ben Harshbarger --- frontend/lib/resolution/resolution-queries.cpp | 9 --------- frontend/lib/resolution/scope-queries.cpp | 9 +++++++++ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/frontend/lib/resolution/resolution-queries.cpp b/frontend/lib/resolution/resolution-queries.cpp index 0acabcb67d11..a614362238ac 100644 --- a/frontend/lib/resolution/resolution-queries.cpp +++ b/frontend/lib/resolution/resolution-queries.cpp @@ -2676,15 +2676,6 @@ doIsCandidateApplicableInitial(Context* context, return ApplicabilityResult::failure(candidateId, /* TODO */ FAIL_CANDIDATE_OTHER); } - // Ignore the 'eltType' declaration in the fake c_ptr[Const] classes. A - // compiler-generated function will handle it since we're representing the - // type entirely within the frontend. - if ((candidateId.symbolPath() == CPtrType::getId(context).symbolPath() || - candidateId.symbolPath() == CPtrType::getConstId(context).symbolPath()) && - ci.name() == "eltType") { - return ApplicabilityResult::failure(candidateId, /* TODO */ FAIL_CANDIDATE_OTHER); - } - if (isVariable(tag)) { if (ci.isParenless() && ci.isMethodCall() && ci.numActuals() == 1) { // calling a field accessor diff --git a/frontend/lib/resolution/scope-queries.cpp b/frontend/lib/resolution/scope-queries.cpp index cddca4df3036..38b02bc59d3e 100644 --- a/frontend/lib/resolution/scope-queries.cpp +++ b/frontend/lib/resolution/scope-queries.cpp @@ -160,6 +160,15 @@ struct GatherDecls { // since dyno handles tuple types directly rather // than through a record. skip = true; + } else if (d->name() == "eltType" && + atFieldLevel && tagParent == asttags::Class && + (d->id().symbolPath().startsWith("CTypes.c_ptr") || + d->id().symbolPath().startsWith("Ctypes.c_ptrConst"))) { + // skip gathering the 'eltType' field of the dummy c_ptr[Const] classes, + // since we're representing those types entirely within the frontend. + // + // TODO: Remove this once we have replaced those classes. + skip = true; } if (skip == false) { From 68072fb0ee7de14e7155f4ac26d40bd90fbb424d Mon Sep 17 00:00:00 2001 From: Ben Harshbarger Date: Tue, 2 Apr 2024 12:00:32 -0700 Subject: [PATCH 09/14] Improve comments related to c_ptr changes Signed-off-by: Ben Harshbarger --- frontend/lib/resolution/default-functions.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/lib/resolution/default-functions.cpp b/frontend/lib/resolution/default-functions.cpp index 31818f7804a3..5b8763631bbc 100644 --- a/frontend/lib/resolution/default-functions.cpp +++ b/frontend/lib/resolution/default-functions.cpp @@ -695,6 +695,8 @@ generateCPtrMethod(Context* context, QualifiedType receiverType, std::vector formalTypes; formals.push_back(UntypedFnSignature::FormalDetail(USTR("this"), false, nullptr)); + + // Allow calling 'eltType' on either a type or value auto qual = receiverType.isType() ? QualifiedType::TYPE : QualifiedType::CONST_REF; formalTypes.push_back(QualifiedType(qual, cpt)); @@ -705,7 +707,7 @@ generateCPtrMethod(Context* context, QualifiedType receiverType, /*isTypeConstructor*/ false, /*isCompilerGenerated*/ true, /*throws*/ false, - /*idTag*/ asttags::Record, /*parsing::idToTag(context, cpt->getId(context)),*/ + /*idTag*/ asttags::Record, /*kind*/ uast::Function::Kind::PROC, /*formals*/ std::move(formals), /*whereClause*/ nullptr); @@ -721,6 +723,8 @@ generateCPtrMethod(Context* context, QualifiedType receiverType, return result; } +// TODO: Is the use of a QualifiedType for 'receiverType' going to result in +// too many queries differentiated by the kind? static const TypedFnSignature* const& getCompilerGeneratedMethodQuery(Context* context, QualifiedType receiverType, UniqueString name, bool parenless) { From f3b3b5f070ab79a3eba683a0d1da765c271ad241 Mon Sep 17 00:00:00 2001 From: Ben Harshbarger Date: Tue, 2 Apr 2024 16:05:46 -0700 Subject: [PATCH 10/14] Add 'make modules' to frontend CI Signed-off-by: Ben Harshbarger --- .github/workflows/CI.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index bbb1e6dd918a..a432e3414828 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -78,8 +78,9 @@ jobs: steps: - uses: actions/checkout@v4 - name: make test-dyno-with-asserts + # 'make modules' so the ChapelSysCTypes module is available run: | - CHPL_HOME=$PWD make DYNO_ENABLE_ASSERTIONS=1 test-dyno -j`util/buildRelease/chpl-make-cpu_count` + CHPL_HOME=$PWD make modules && make DYNO_ENABLE_ASSERTIONS=1 test-dyno -j`util/buildRelease/chpl-make-cpu_count` - name: run dyno linters run: | CHPL_HOME=$PWD CHPL_HOST_CC=clang-13 CHPL_HOST_CXX=clang++-13 make run-dyno-linters From 1f177100c4b803aa6cdf707e4af8222103a2dee8 Mon Sep 17 00:00:00 2001 From: Ben Harshbarger Date: Wed, 3 Apr 2024 11:29:07 -0700 Subject: [PATCH 11/14] Split CI command onto multiple lines, and set CHPL_HOME for each command Signed-off-by: Ben Harshbarger --- .github/workflows/CI.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index a432e3414828..f39e94f6baa6 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -80,7 +80,8 @@ jobs: - name: make test-dyno-with-asserts # 'make modules' so the ChapelSysCTypes module is available run: | - CHPL_HOME=$PWD make modules && make DYNO_ENABLE_ASSERTIONS=1 test-dyno -j`util/buildRelease/chpl-make-cpu_count` + CHPL_HOME=$PWD make modules + CHPL_HOME=$PWD make DYNO_ENABLE_ASSERTIONS=1 test-dyno -j`util/buildRelease/chpl-make-cpu_count` - name: run dyno linters run: | CHPL_HOME=$PWD CHPL_HOST_CC=clang-13 CHPL_HOST_CXX=clang++-13 make run-dyno-linters From 06fa962ab25726749ce33147b06c87a15acb97ed Mon Sep 17 00:00:00 2001 From: Ben Harshbarger Date: Wed, 3 Apr 2024 11:56:25 -0700 Subject: [PATCH 12/14] Use 'Class' instead of 'Record' tag for c_ptr compiler-generated methods Signed-off-by: Ben Harshbarger --- frontend/lib/resolution/default-functions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/lib/resolution/default-functions.cpp b/frontend/lib/resolution/default-functions.cpp index 5b8763631bbc..8bb8922bed9a 100644 --- a/frontend/lib/resolution/default-functions.cpp +++ b/frontend/lib/resolution/default-functions.cpp @@ -707,7 +707,7 @@ generateCPtrMethod(Context* context, QualifiedType receiverType, /*isTypeConstructor*/ false, /*isCompilerGenerated*/ true, /*throws*/ false, - /*idTag*/ asttags::Record, + /*idTag*/ asttags::Class, /*kind*/ uast::Function::Kind::PROC, /*formals*/ std::move(formals), /*whereClause*/ nullptr); From 29189df6efe85363c8570997233c11b605fc5187 Mon Sep 17 00:00:00 2001 From: Ben Harshbarger Date: Wed, 3 Apr 2024 12:00:12 -0700 Subject: [PATCH 13/14] Normalize receiverType before getCompilerGeneratedMethodQuery Signed-off-by: Ben Harshbarger --- frontend/lib/resolution/default-functions.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/frontend/lib/resolution/default-functions.cpp b/frontend/lib/resolution/default-functions.cpp index 8bb8922bed9a..9bd4bd08aa31 100644 --- a/frontend/lib/resolution/default-functions.cpp +++ b/frontend/lib/resolution/default-functions.cpp @@ -723,8 +723,6 @@ generateCPtrMethod(Context* context, QualifiedType receiverType, return result; } -// TODO: Is the use of a QualifiedType for 'receiverType' going to result in -// too many queries differentiated by the kind? static const TypedFnSignature* const& getCompilerGeneratedMethodQuery(Context* context, QualifiedType receiverType, UniqueString name, bool parenless) { @@ -866,7 +864,15 @@ generateCastToEnum(Context* context, const TypedFnSignature* getCompilerGeneratedMethod(Context* context, const QualifiedType receiverType, UniqueString name, bool parenless) { - return getCompilerGeneratedMethodQuery(context, receiverType, name, parenless); + // Normalize recieverType to allow TYPE methods on c_ptr, and to otherwise + // use the VAR Kind. The Param* value is also stripped away to reduce + // queries. + auto qt = receiverType; + bool isCPtr = qt.hasTypePtr() ? qt.type()->isCPtrType() : false; + if (!(qt.isType() && isCPtr)) { + qt = QualifiedType(QualifiedType::VAR, qt.type()); + } + return getCompilerGeneratedMethodQuery(context, qt, name, parenless); } static const TypedFnSignature* const& From 71aa824c2794d496d8caa32785b0f398e8496cf7 Mon Sep 17 00:00:00 2001 From: Ben Harshbarger Date: Wed, 3 Apr 2024 13:18:48 -0700 Subject: [PATCH 14/14] Minor cleanup to considerCompilerGeneratedMethods Signed-off-by: Ben Harshbarger --- frontend/lib/resolution/resolution-queries.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/frontend/lib/resolution/resolution-queries.cpp b/frontend/lib/resolution/resolution-queries.cpp index a614362238ac..b3f62d453b95 100644 --- a/frontend/lib/resolution/resolution-queries.cpp +++ b/frontend/lib/resolution/resolution-queries.cpp @@ -3409,17 +3409,16 @@ considerCompilerGeneratedMethods(Context* context, // fetch the receiver type info CHPL_ASSERT(ci.numActuals() >= 1); auto& receiver = ci.actual(0); - // TODO: This should be the QualifiedType in case of type methods - auto receiverType = receiver.type().type(); + auto receiverType = receiver.type(); // if not compiler-generated, then nothing to do - if (!needCompilerGeneratedMethod(context, receiverType, ci.name(), + if (!needCompilerGeneratedMethod(context, receiverType.type(), ci.name(), ci.isParenless())) { return nullptr; } // get the compiler-generated function, may be generic - auto tfs = getCompilerGeneratedMethod(context, receiver.type(), ci.name(), + auto tfs = getCompilerGeneratedMethod(context, receiverType, ci.name(), ci.isParenless()); return tfs; }