Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[dyno] map owned to _owned module code #25617

Merged
merged 17 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions frontend/include/chpl/framework/all-global-strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ X(none , "none")
X(nothing , "nothing")
X(object_ , "object")
X(owned , "owned")
X(owned_ , "_owned")
X(postinit , "postinit")
X(real_ , "real")
X(reduce , "reduce")
Expand All @@ -90,6 +91,7 @@ X(RootClass , "RootClass")
X(scan , "scan")
X(serialize , "serialize")
X(shared , "shared")
X(shared_ , "_shared")
X(single , "single")
X(size , "size")
X(sparse , "sparse")
Expand Down
4 changes: 4 additions & 0 deletions frontend/include/chpl/types/ClassType.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ class ClassType final : public Type {
/** Returns the version of this ClassType with the passed decorator */
const ClassType* withDecorator(Context* context,
ClassTypeDecorator decorator) const;

/** Returns the recordType for the manager */
const RecordType* managerRecordType(Context* context) const;

};


Expand Down
6 changes: 6 additions & 0 deletions frontend/include/chpl/types/CompositeType.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,12 @@ class CompositeType : public Type {
/** Get the chpl_localeID_t type */
static const RecordType* getLocaleIDType(Context* context);

/** Get the record _owned implementing owned */
static const RecordType* getOwnedRecordType(Context* context, const BasicClassType* bct);

/** Get the record _shared implementing shared */
static const RecordType* getSharedRecordType(Context* context, const BasicClassType* bct);

/** When compiling without a standard library (for testing purposes),
the compiler code needs to work around the fact that there
is no definition available for the bundled types needed
Expand Down
33 changes: 30 additions & 3 deletions frontend/lib/resolution/Resolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -920,6 +920,7 @@ static bool isCallToClassManager(const FnCall* call) {
if (!ident) return false;
auto name = ident->name();
return name == USTR("owned") || name == USTR("shared") ||
name == USTR("_owned") || name == USTR("_shared") ||
name == USTR("unmanaged") || name == USTR("borrowed");
}

Expand Down Expand Up @@ -2132,8 +2133,9 @@ bool Resolver::resolveSpecialNewCall(const Call* call) {
// will not resolve because the receiver formal is 'nonnil borrowed').
const Type* initReceiverType = qtNewExpr.type();
if (auto clsType = qtNewExpr.type()->toClassType()) {
auto oldDecor = clsType->decorator();
auto newDecor = oldDecor.addNonNil();
// always set the receiver to be borrowed non-nil b/c we don't want to
// call initializers for '_owned' when the receiver is 'owned(MyClass)'
auto newDecor = ClassTypeDecorator(ClassTypeDecorator::BORROWED_NONNIL);
arezaii marked this conversation as resolved.
Show resolved Hide resolved
initReceiverType = clsType->withDecorator(context, newDecor);
CHPL_ASSERT(initReceiverType);
}
Expand Down Expand Up @@ -2482,7 +2484,18 @@ QualifiedType Resolver::typeForId(const ID& id, bool localGenericToUnknown) {
// TODO: this needs to consider the possibility
// that we are working with a nested method
if (auto rt = methodReceiverType().type()) {
if (auto comprt = rt->getCompositeType()) {
// get the new class type if the receiver is a class
auto nct = rt->toClassType();
// get the manager record using ClassType method managerRecordType()
if (auto mr = checkIfReceiverIsManagerRecord(context, nct, parentId)) {
ct = mr;
auto fieldName = parsing::fieldIdToName(context, id);
// TODO: shared has additional fields that are not generic
CHPL_ASSERT(fieldName == "chpl_t" || fieldName == "chpl_p");
auto intent = fieldName == "chpl_t" ? QualifiedType::TYPE : QualifiedType::VAR;
auto borrowed = nct->withDecorator(context, nct->decorator().toBorrowed());
return QualifiedType(intent, borrowed);
} else if (auto comprt = rt->getCompositeType()) {
if (comprt->id() == parentId) {
ct = comprt; // handle record, class with field
} else if (auto bct = comprt->toBasicClassType()) {
Expand Down Expand Up @@ -2511,6 +2524,20 @@ QualifiedType Resolver::typeForId(const ID& id, bool localGenericToUnknown) {
return QualifiedType(QualifiedType::UNKNOWN, unknownType);
}

const types::CompositeType*
Resolver::checkIfReceiverIsManagerRecord(Context* context,
const types::ClassType* ct,
ID& parentId) {
if (ct) {
if (auto mr = ct->managerRecordType(context)) {
if (mr->id() == parentId) {
return mr;
}
}
}
return nullptr;
}

void Resolver::enterScope(const AstNode* ast) {
if (createsScope(ast->tag())) {
scopeStack.push_back(scopeForId(context, ast->id()));
Expand Down
8 changes: 8 additions & 0 deletions frontend/lib/resolution/Resolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,14 @@ struct Resolver {
*/
types::QualifiedType typeForId(const ID& id, bool localGenericToUnknown);

/* If the receiver is a manager record (owned/shared) returns the manager
class type, otherwise returns nullptr
*/
const types::CompositeType*
checkIfReceiverIsManagerRecord(Context* context,
const types::ClassType* nct,
ID& parentId);

// prepare the CallInfoActuals by inspecting the actuals of a call
// includes special handling for operators and tuple literals
void prepareCallInfoActuals(const uast::Call* call,
Expand Down
81 changes: 79 additions & 2 deletions frontend/lib/resolution/can-pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "chpl/resolution/can-pass.h"

#include "chpl/resolution/resolution-queries.h"
#include "chpl/parsing/parsing-queries.h"
#include "chpl/types/all-types.h"

#include <cmath>
Expand Down Expand Up @@ -811,6 +812,61 @@ bool CanPassResult::canInstantiateBuiltin(Context* context,
return false;
}

static bool classTypeIsManagedAndDecorated(Context* context,
const ClassType* ct) {
if (ct && ct->manager() && ct->decorator().isManaged()) {
return true;
}
return false;
}

static bool
tryConvertClassTypeIntoManagerRecordIfNeeded(Context* context,
const Type*& mightBeManagerRecord,
const Type*& mightBeClass) {
if (!mightBeManagerRecord || !mightBeClass) return false;

auto mr = mightBeManagerRecord->toRecordType();
auto ct = mightBeClass->toClassType();
auto aot = mightBeClass->toAnyOwnedType();
arezaii marked this conversation as resolved.
Show resolved Hide resolved

bool isCtManagedAndDecorated = classTypeIsManagedAndDecorated(context, ct);
// if mightBeManagerRecord is a record type and (mightBeClass is a class type
// that is managed and decorated or mightBeClass is an AnyOwnedType) we can continue
if (!mr || (!isCtManagedAndDecorated && !aot )) return false;

if (!parsing::idIsInBundledModule(context, mr->id())) return false;

auto ag = parsing::idToAttributeGroup(context, mr->id());
if (!ag || !ag->hasPragma(pragmatags::PragmaTag::PRAGMA_MANAGED_POINTER)) {
return false;
}

// Override the class type to the manager record type
// mightBeClass used to be `owned` of type ClassType,
// now it's `_owned` of type RecordType
if (aot) {
mightBeClass = CompositeType::getOwnedRecordType(context, /*bct*/ nullptr);
} else {
mightBeClass = ct->managerRecordType(context);
}

return true;
}

static optional<std::pair<const RecordType*, const RecordType*>>
shouldConvertClassTypeIntoManagerRecord(Context* context,
const Type* actualT,
const Type* formalT) {
if (tryConvertClassTypeIntoManagerRecordIfNeeded(context, formalT, actualT) ||
tryConvertClassTypeIntoManagerRecordIfNeeded(context, actualT, formalT)) {
CHPL_ASSERT(formalT->isRecordType() && actualT->isRecordType());
return std::make_pair(actualT->toRecordType(), formalT->toRecordType());
}

return empty;
}

CanPassResult CanPassResult::canInstantiate(Context* context,
const QualifiedType& actualQT,
const QualifiedType& formalQT) {
Expand All @@ -832,6 +888,18 @@ CanPassResult CanPassResult::canInstantiate(Context* context,
return instantiate();
}

// TODO: Should we move this to the section below and have it call canPassSubtypeOrBorrowing?
// TODO: There may be cases for nilType that are not covered
// this is to allow instantiating 'class?' type with nil
if (auto cls = formalT->toClassType()) {
if (auto mt = cls->manageableType()) {
if (mt->isAnyClassType()) {
if (cls->decorator().isNilable() && actualT->isNilType())
return instantiate();
}
}
}

DanilaFe marked this conversation as resolved.
Show resolved Hide resolved
// TODO: check for constrained generic types

if (auto actualCt = actualT->toClassType()) {
Expand Down Expand Up @@ -895,12 +963,21 @@ CanPassResult CanPassResult::canInstantiate(Context* context,
}

CanPassResult CanPassResult::canPass(Context* context,
const QualifiedType& actualQT,
const QualifiedType& formalQT) {
const QualifiedType& actualQtIn,
const QualifiedType& formalQtIn) {
auto actualQT = actualQtIn;
auto formalQT = formalQtIn;

const Type* actualT = actualQT.type();
const Type* formalT = formalQT.type();
CHPL_ASSERT(actualT && formalT);
if (auto managerRecordPair =
shouldConvertClassTypeIntoManagerRecord(context, actualT, formalT)) {
actualT = managerRecordPair->first;
formalT = managerRecordPair->second;
actualQT = QualifiedType(actualQT.kind(), actualT, actualQT.param());
formalQT = QualifiedType(formalQT.kind(), formalT, formalQT.param());
}

// if the formal type is unknown, allow passing
// this can come up with e.g.
Expand Down
14 changes: 13 additions & 1 deletion frontend/lib/resolution/resolution-queries.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3086,11 +3086,23 @@ doIsCandidateApplicableInitial(ResolutionContext* rc,
//
// TODO: This doesn't have anything to do with this candidate. Shouldn't
// we be handling this somewhere else?
if (auto ct = ci.actual(0).type().type()->getCompositeType()) {
auto t = ci.actual(0).type().type();
if (auto ct = t->getCompositeType()) {
if (auto containingType = isNameOfField(context, ci.name(), ct)) {
auto ret = fieldAccessor(context, containingType, ci.name());
return ApplicabilityResult::success(ret);
}
// help handle the case where we're calling a field accessor on a manger.
// while resolving the body of a method on owned to evaluate the applicability,
// we need to be able to resolve the field accessor on the manager.
if (auto classType = t->toClassType()) {
if (auto managerType = classType->managerRecordType(context)) {
if (auto containingType = isNameOfField(context, ci.name(), managerType)) {
auto ret = fieldAccessor(context, containingType, ci.name());
return ApplicabilityResult::success(ret);
}
}
}
}
}
// not a candidate
Expand Down
6 changes: 6 additions & 0 deletions frontend/lib/resolution/resolution-types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1388,6 +1388,12 @@ gatherReceiverAndParentScopesForType(Context* context,
scopes.push_back(scopeForId(context, ct->id()));

if (auto bct = ct->toBasicClassType()) {
// add the scope for the manager type
if (auto classType = thisType->toClassType()) {
if (auto managerType = classType->managerRecordType(context)) {
scopes.push_back(scopeForId(context, managerType->id()));
}
}
// also add scopes for all superclass types
auto cur = bct->parentClassType();
while (cur != nullptr) {
Expand Down
15 changes: 15 additions & 0 deletions frontend/lib/types/ClassType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,21 @@ const ClassType* ClassType::withDecorator(Context* context,
return ClassType::get(context, manageableType(), manager(), decorator);
}

const RecordType* ClassType::managerRecordType(Context* context) const {
// for owned and shared, manager is the builtin AnyClassType
// e.g. for `owned C`, produce `_owned(C)`
// for `shared C`, produce `_shared(C)`
if (auto myManager = manager()) {
if (myManager->isAnyOwnedType()) {
return CompositeType::getOwnedRecordType(context, basicClassType());
} else if (myManager->isAnySharedType()) {
return CompositeType::getSharedRecordType(context, basicClassType());
} else if (auto mgr = myManager->toRecordType()) {
return mgr;
}
}
return nullptr;
}

} // end namespace types
} // end namespace chpl
55 changes: 53 additions & 2 deletions frontend/lib/types/CompositeType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@
#include "chpl/parsing/parsing-queries.h"
#include "chpl/resolution/can-pass.h"
#include "chpl/resolution/resolution-queries.h"
#include "chpl/resolution/resolution-types.h"
#include "chpl/types/BasicClassType.h"
#include "chpl/types/ClassType.h"
#include "chpl/types/ClassTypeDecorator.h"
#include "chpl/types/RecordType.h"
#include "chpl/uast/Decl.h"
#include "chpl/uast/NamedDecl.h"
Expand Down Expand Up @@ -184,6 +186,53 @@ const RecordType* CompositeType::getLocaleIDType(Context* context) {
SubstitutionsMap());
}

static const RecordType* tryCreateManagerRecord(Context* context,
const char* moduleName,
const char* recordName,
const BasicClassType* bct) {
const RecordType* instantiatedFrom = nullptr;
SubstitutionsMap subs;
if (bct != nullptr) {
instantiatedFrom = tryCreateManagerRecord(context,
moduleName,
recordName,
/*bct*/ nullptr);

auto fields = fieldsForTypeDecl(context,
instantiatedFrom,
DefaultsPolicy::IGNORE_DEFAULTS);
for (int i = 0; i < fields.numFields(); i++) {
if (fields.fieldName(i) != "chpl_t") continue;
auto ctd = ClassTypeDecorator(ClassTypeDecorator::BORROWED_NONNIL);
auto ct = ClassType::get(context, bct, /* manager */ nullptr, ctd);

subs[fields.fieldDeclId(i)] = QualifiedType(QualifiedType::TYPE, ct);
break;
}
if (fields.numFields() == 0) {
CHPL_ASSERT(CompositeType::isMissingBundledRecordType(context,
instantiatedFrom->id()));
return nullptr;
}
}

auto name = UniqueString::get(context, recordName);
auto id = parsing::getSymbolFromTopLevelModule(context, moduleName, recordName);
return RecordType::get(context, id, name,
instantiatedFrom,
std::move(subs));
}

const RecordType*
CompositeType::getOwnedRecordType(Context* context, const BasicClassType* bct) {
return tryCreateManagerRecord(context, "OwnedObject", "_owned", bct);
}

const RecordType*
CompositeType::getSharedRecordType(Context* context, const BasicClassType* bct) {
return tryCreateManagerRecord(context, "SharedObject", "_shared", bct);
}

bool CompositeType::isMissingBundledType(Context* context, ID id) {
return isMissingBundledClassType(context, id) ||
isMissingBundledRecordType(context, id);
Expand All @@ -196,7 +245,9 @@ bool CompositeType::isMissingBundledRecordType(Context* context, ID id) {
return path == "String._string" ||
path == "ChapelRange._range" ||
path == "ChapelTuple._tuple" ||
path == "Bytes._bytes";
path == "Bytes._bytes" ||
path == "OwnedObject._owned" ||
path == "SharedObject._shared";
}

return false;
Expand All @@ -207,7 +258,7 @@ bool CompositeType::isMissingBundledClassType(Context* context, ID id) {
if (noLibrary) {
auto path = id.symbolPath();
return path == "ChapelReduce.ReduceScanOp" ||
path == "Errors.Error" ||
path == "Errors.Error" ||
path == "CTypes.c_ptr" ||
path == "CTypes.c_ptrConst";
}
Expand Down
Loading