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

Resolve basic associative domains with module code in Dyno #26077

Draft
wants to merge 16 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
5 changes: 3 additions & 2 deletions frontend/include/chpl/types/DomainType.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,9 @@ class DomainType final : public CompositeType {

/** Return an associative domain type */
static const DomainType* getAssociativeType(Context* context,
const QualifiedType& idxType,
const QualifiedType& parSafe);
const QualifiedType& instance,
const QualifiedType& idxType,
const QualifiedType& parSafe);

/** Get the default distribution type */
static const QualifiedType& getDefaultDistType(Context* context);
Expand Down
4 changes: 4 additions & 0 deletions frontend/include/chpl/types/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ class Type {
*/
bool isUserRecordType() const;

bool isRecordLike() const;

/** Returns true if the this type has the pragma 'p' attached to it. */
bool hasPragma(Context* context, uast::pragmatags::PragmaTag p) const;

Expand Down Expand Up @@ -316,6 +318,8 @@ class Type {
*/
static bool isPod(Context* context, const Type* t);

static bool needsInitDeinitCall(const Type* t);

/// \cond DO_NOT_DOCUMENT
DECLARE_DUMP;
/// \endcond DO_NOT_DOCUMENT
Expand Down
23 changes: 20 additions & 3 deletions frontend/lib/resolution/InitResolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,9 +295,9 @@ static const DomainType* domainTypeFromSubsHelper(
if (auto instanceBct = instanceCt->basicClassType()) {
// Get BaseRectangularDom parent subs for rectangular domain info
if (auto baseDom = instanceBct->parentClassType()) {
auto& rf = fieldsForTypeDecl(context, baseDom,
DefaultsPolicy::IGNORE_DEFAULTS);
if (baseDom->id().symbolPath() == "ChapelDistribution.BaseRectangularDom") {
auto& rf = fieldsForTypeDecl(context, baseDom,
DefaultsPolicy::IGNORE_DEFAULTS);
CHPL_ASSERT(rf.numFields() == 3);
QualifiedType rank;
QualifiedType idxType;
Expand All @@ -315,7 +315,24 @@ static const DomainType* domainTypeFromSubsHelper(
return DomainType::getRectangularType(context, instanceQt, rank,
idxType, strides);
} else if (baseDom->id().symbolPath() == "ChapelDistribution.BaseAssociativeDom") {
// TODO: support associative domains
// Currently the relevant associative domain fields are defined
// on all the children of BaseAssociativeDom, so get information
// from there.
auto& rf = fieldsForTypeDecl(context, instanceBct,
DefaultsPolicy::IGNORE_DEFAULTS);
CHPL_ASSERT(rf.numFields() >= 2);
QualifiedType idxType;
QualifiedType parSafe;
for (int i = 0; i < rf.numFields(); i++) {
if (rf.fieldName(i) == "idxType") {
idxType = rf.fieldType(i);
} else if (rf.fieldName(i) == "parSafe") {
parSafe = rf.fieldType(i);
}
}

return DomainType::getAssociativeType(context, instanceQt, idxType,
parSafe);
} else if (baseDom->id().symbolPath() == "ChapelDistribution.BaseSparseDom") {
// TODO: support sparse domains
} else {
Expand Down
52 changes: 6 additions & 46 deletions frontend/lib/resolution/call-init-deinit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -368,46 +368,6 @@ void CallInitDeinit::processDeinitsAndPropagate(VarFrame* frame,
}
}

static bool isRecordLike(const Type* t) {
if (auto ct = t->toClassType()) {
auto decorator = ct->decorator();
// no action needed for 'borrowed' or 'unmanaged'
// (these should just default initialized to 'nil',
// so nothing else needs to be resolved)
if (! (decorator.isBorrowed() || decorator.isUnmanaged() ||
decorator.isUnknownManagement())) {
return true;
}
} else if (t->isRecordType() || t->isUnionType()) {
return true;
}
// TODO: tuples?

return false;
}

static bool typeNeedsInitDeinitCall(const Type* t) {
if (t == nullptr || t->isUnknownType() || t->isErroneousType()) {
// can't do anything with these
return false;
} else if (t->isPrimitiveType() || t->isBuiltinType() || t->isCStringType() ||
t->isNilType() || t->isNothingType() || t->isVoidType()) {
// OK, we can always default initialize primitive numeric types,
// and as well we assume that for the non-generic builtin types
// e.g. TaskIdType.
// No need to resolve anything additional now.
return false;
} else if (t->isEnumType()) {
// OK, can default-initialize enums to first element
return false;
} else if (t->isFunctionType()) {
return false;
}

return isRecordLike(t);
}


void CallInitDeinit::resolveDefaultInit(const VarLikeDecl* ast, RV& rv) {
// Type variables do not need default init.
if (ast->storageKind() == Qualifier::TYPE) return;
Expand Down Expand Up @@ -446,7 +406,7 @@ void CallInitDeinit::resolveDefaultInit(const VarLikeDecl* ast, RV& rv) {
}
}

if (!typeNeedsInitDeinitCall(vt)) {
if (!Type::needsInitDeinitCall(vt)) {
// nothing to do here
} else if (vt->isTupleType()) {
// TODO: probably need to do something here, at least in some cases
Expand Down Expand Up @@ -563,7 +523,7 @@ void CallInitDeinit::resolveCopyInit(const AstNode* ast,
const QualifiedType& rhsType,
bool forMoveInit,
RV& rv) {
if (!typeNeedsInitDeinitCall(lhsType.type())) {
if (!Type::needsInitDeinitCall(lhsType.type())) {
// TODO: we could resolve it anyway
return;
}
Expand Down Expand Up @@ -672,7 +632,7 @@ void CallInitDeinit::processInit(VarFrame* frame,
const QualifiedType& rhsType,
RV& rv) {
if (lhsType.type() == rhsType.type() &&
!typeNeedsInitDeinitCall(lhsType.type())) {
!Type::needsInitDeinitCall(lhsType.type())) {
// TODO: we should resolve it anyway
return;
}
Expand Down Expand Up @@ -722,7 +682,7 @@ void CallInitDeinit::processInit(VarFrame* frame,
} else {
// it is copy initialization, so use init= for records
// and assign for other stuff
if (lhsType.type() != nullptr && isRecordLike(lhsType.type())) {
if (lhsType.type() != nullptr && lhsType.type()->isRecordLike()) {
resolveCopyInit(ast, rhsAst,
lhsType, rhsType,
/* forMoveInit */ false,
Expand All @@ -741,7 +701,7 @@ void CallInitDeinit::resolveDeinit(const AstNode* ast,
RV& rv) {

// nothing to do for 'int' etc
if (!typeNeedsInitDeinitCall(type.type())) {
if (!Type::needsInitDeinitCall(type.type())) {
return;
} else if (type.type()->isTupleType()) {
// TODO: probably need to do something here, at least in some cases
Expand Down Expand Up @@ -968,7 +928,7 @@ void CallInitDeinit::handleInFormal(const FnCall* ast, const AstNode* actual,
// is the copy for 'in' elided?
if (elidedCopyFromIds.count(actual->id()) > 0 &&
isValue(actualType.kind()) &&
typeNeedsInitDeinitCall(actualType.type())) {
Type::needsInitDeinitCall(actualType.type())) {
// it is move initialization
resolveMoveInit(actual, actual, formalType, actualType, rv);

Expand Down
32 changes: 29 additions & 3 deletions frontend/lib/resolution/prims.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ static QualifiedType computeDomainType(Context* context, const CallInfo& ci) {
return QualifiedType(QualifiedType::TYPE, type);
} else if (ci.numActuals() == 2) {
auto type = DomainType::getAssociativeType(context,
QualifiedType(),
ci.actual(0).type(),
ci.actual(1).type());
return QualifiedType(QualifiedType::TYPE, type);
Expand Down Expand Up @@ -389,6 +390,18 @@ static QualifiedType primTypeof(Context* context, PrimitiveTag prim, const CallI
return QualifiedType(QualifiedType::TYPE, typePtr);
}

static QualifiedType primPromotionType(Context* context, const CallInfo& ci) {
if (ci.numActuals() != 1) return QualifiedType();
auto actualQt = ci.actual(0).type();

auto promoTy = getPromotionType(context, actualQt).type();

// We want a type result, even if the prim was passed a value.
auto promoQt = QualifiedType(QualifiedType::TYPE, promoTy);

return promoQt;
}

static QualifiedType primGetSvecMember(Context* context, PrimitiveTag prim,
const CallInfo& ci) {
CHPL_ASSERT(prim == PRIM_GET_SVEC_MEMBER ||
Expand Down Expand Up @@ -985,6 +998,12 @@ static QualifiedType primIsPod(Context* context, const CallInfo& ci) {
});
}

static QualifiedType primNeedsAutoDestroy(Context* context, const CallInfo& ci) {
return actualTypeHasProperty(context, ci, [=](auto t) {
return Type::needsInitDeinitCall(t) && !Type::isPod(context, t);
});
}

static QualifiedType
primIsCoercible(Context* context, const CallInfo& ci) {
if (ci.numActuals() < 2) return QualifiedType();
Expand Down Expand Up @@ -1243,10 +1262,13 @@ CallResolutionResult resolvePrimCall(ResolutionContext* rc,
break;

case PRIM_HAS_DEFAULT_VALUE:
case PRIM_NEEDS_AUTO_DESTROY:
CHPL_UNIMPL("various primitives");
break;

case PRIM_NEEDS_AUTO_DESTROY:
type = primNeedsAutoDestroy(context, ci);
break;

case PRIM_CALL_RESOLVES:
case PRIM_CALL_AND_FN_RESOLVES:
case PRIM_METHOD_CALL_AND_FN_RESOLVES:
Expand Down Expand Up @@ -1687,7 +1709,7 @@ CallResolutionResult resolvePrimCall(ResolutionContext* rc,
break;

case PRIM_SCALAR_PROMOTION_TYPE:
CHPL_UNIMPL("misc primitives");
type = primPromotionType(context, ci);
break;
case PRIM_STATIC_FIELD_TYPE:
type = staticFieldType(context, ci);
Expand Down Expand Up @@ -1744,7 +1766,6 @@ CallResolutionResult resolvePrimCall(ResolutionContext* rc,
case PRIM_BLOCK_UNLOCAL:
case PRIM_LOGICAL_FOLDER:
case PRIM_WIDE_MAKE:
case PRIM_WIDE_GET_LOCALE:
case PRIM_REGISTER_GLOBAL_VAR:
case PRIM_BROADCAST_GLOBAL_VARS:
case PRIM_PRIVATE_BROADCAST:
Expand All @@ -1769,6 +1790,11 @@ CallResolutionResult resolvePrimCall(ResolutionContext* rc,
CHPL_UNIMPL("misc primitives");
break;

case PRIM_WIDE_GET_LOCALE:
type = QualifiedType(QualifiedType::CONST_VAR,
CompositeType::getLocaleIDType(context));
break;

case PRIM_GATHER_TESTS:
type = primGatherTests(context, ci);
break;
Expand Down
37 changes: 28 additions & 9 deletions frontend/lib/resolution/resolution-queries.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2735,9 +2735,11 @@ helpResolveFunction(ResolutionContext* rc, const TypedFnSignature* sig,
// same function twice when working with inferred 'out' formals)
sig = sig->inferredFrom();

if (!sig->isInitializer() && sig->needsInstantiation()) {
CHPL_ASSERT(false && "Should only be called on concrete or fully "
"instantiated functions");
if (!sig->isInitializer() && !sig->untyped()->isTypeConstructor() &&
sig->needsInstantiation()) {
CHPL_ASSERT(false &&
"Should only be called on concrete or fully "
"instantiated functions");
return nullptr;
}

Expand Down Expand Up @@ -3787,13 +3789,9 @@ static bool resolveFnCallSpecial(Context* context,
}

if ((ci.name() == USTR("==") || ci.name() == USTR("!="))) {
if (ci.numActuals() == 2 || ci.hasQuestionArg()) {
if (ci.numActuals() == 2) {
auto lhs = ci.actual(0).type();

// support comparisons with '?'
auto rhs = ci.hasQuestionArg() ?
QualifiedType(QualifiedType::TYPE, AnyType::get(context)) :
ci.actual(1).type();
auto rhs = ci.actual(1).type();

bool bothType = lhs.kind() == QualifiedType::TYPE &&
rhs.kind() == QualifiedType::TYPE;
Expand All @@ -3806,6 +3804,27 @@ static bool resolveFnCallSpecial(Context* context,
BoolParam::get(context, result));
return true;
}
} else if (ci.numActuals() == 1 && ci.hasQuestionArg()) {
// support type and param comparisons with '?'
// TODO: will likely need adjustment once we are able to compare a
// partially-instantiated type's fields with '?'
auto arg = ci.actual(0).type();
bool result = false;
bool haveResult = true;
if (arg.isType()) {
result = arg.type()->isAnyType();
} else if (arg.isParam()) {
result = arg.param() == nullptr;
} else {
haveResult = false;
}
result = ci.name() == USTR("==") ? result : !result;
if (haveResult) {
exprTypeOut =
QualifiedType(QualifiedType::PARAM, BoolType::get(context),
BoolParam::get(context, result));
return true;
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions frontend/lib/types/CompositeType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,8 @@ const RecordType* CompositeType::getLocaleType(Context* context) {
}

const RecordType* CompositeType::getLocaleIDType(Context* context) {
auto id = ID();
auto name = UniqueString::get(context, "chpl_localeID_t");
auto [id, name] = parsing::getSymbolFromTopLevelModule(
context, "LocaleModelHelpRuntime", "chpl_localeID_t");
return RecordType::get(context, id, name,
/* instantiatedFrom */ nullptr,
SubstitutionsMap());
Expand Down
26 changes: 22 additions & 4 deletions frontend/lib/types/DomainType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,17 +118,35 @@ DomainType::getRectangularType(Context* context,

const DomainType*
DomainType::getAssociativeType(Context* context,
const QualifiedType& instance,
const QualifiedType& idxType,
const QualifiedType& parSafe) {
auto genericDomain = getGenericDomainType(context);

SubstitutionsMap subs;
// TODO: assert validity of sub types
subs.emplace(ID(UniqueString(), 0, 0), idxType);
CHPL_ASSERT(idxType.isType());
subs.emplace(ID(UniqueString(), 1, 0), parSafe);
CHPL_ASSERT(parSafe.isParam() && parSafe.param() &&
parSafe.param()->isBoolParam());

// Add substitution for _instance field
auto& rf = fieldsForTypeDecl(context, genericDomain,
resolution::DefaultsPolicy::IGNORE_DEFAULTS,
/* syntaxOnly */ true);
ID instanceFieldId;
for (int i = 0; i < rf.numFields(); i++) {
if (rf.fieldName(i) == USTR("_instance")) {
instanceFieldId = rf.fieldDeclId(i);
break;
}
}
subs.emplace(instanceFieldId, instance);

auto name = UniqueString::get(context, "_domain");
auto id = getDomainID(context);
auto instantiatedFrom = getGenericDomainType(context);
return getDomainType(context, id, name, instantiatedFrom, subs,
DomainType::Kind::Associative).get();
return getDomainType(context, id, name, /* instantiatedFrom */ genericDomain,
subs, DomainType::Kind::Associative).get();
}

const QualifiedType& DomainType::getDefaultDistType(Context* context) {
Expand Down
Loading
Loading