diff --git a/frontend/lib/resolution/Resolver.cpp b/frontend/lib/resolution/Resolver.cpp index fc64aae33826..84b2e8605054 100644 --- a/frontend/lib/resolution/Resolver.cpp +++ b/frontend/lib/resolution/Resolver.cpp @@ -2704,6 +2704,17 @@ QualifiedType Resolver::typeForId(const ID& id, bool localGenericToUnknown) { } } + if (auto tup = rt->toTupleType()) { + auto field = parsing::idToAst(context, id)->toNamedDecl(); + if (field && field->name() == USTR("size")) { + // Tuples don't store a 'size' in their substitutions map, so + // manually take care of things here. + auto intType = IntType::get(context, 0); + auto val = IntParam::get(context, tup->numElements()); + return QualifiedType(QualifiedType::PARAM, intType, val); + } + } + if (auto comprt = rt->getCompositeType()) { if (comprt->id() == parentId) { ct = comprt; // handle record, class with field diff --git a/frontend/lib/resolution/default-functions.cpp b/frontend/lib/resolution/default-functions.cpp index ffe3bd5a0534..bab6e729862d 100644 --- a/frontend/lib/resolution/default-functions.cpp +++ b/frontend/lib/resolution/default-functions.cpp @@ -135,6 +135,8 @@ needCompilerGeneratedMethod(Context* context, const Type* type, UniqueString name, bool parenless) { if (type == nullptr) return false; + if (type->isNothingType()) return false; + if (isNameOfCompilerGeneratedMethod(name) || (type->isRecordType() && !isBuiltinTypeOperator(name))) { if (!areOverloadsPresentInDefiningScope(context, type, QualifiedType::INIT_RECEIVER, name)) { @@ -161,55 +163,6 @@ needCompilerGeneratedMethod(Context* context, const Type* type, return false; } -// generates the untyped function signature and typed function -// signature formal entries for the 'this' method receiver for -// some kind of 'init' or 'init=' -static void -generateInitParts(Context* context, - const CompositeType* inCompType, - const CompositeType*& compType, - std::vector& ufsFormals, - std::vector& formalTypes, - bool useGeneric) { - // adjust to refer to fully generic signature if needed - auto genericCompType = inCompType->instantiatedFromCompositeType(); - if (useGeneric && genericCompType != nullptr) { - compType = genericCompType; - } else { - compType = inCompType; - } - - // start by adding a formal for the receiver - auto ufsReceiver = - UntypedFnSignature::FormalDetail(USTR("this"), - UntypedFnSignature::DK_NO_DEFAULT, - nullptr); - ufsFormals.push_back(std::move(ufsReceiver)); - - // Determine the receiver type and intent. - QualifiedType qtReceiver; - - // If the receiver is a record type, just give it the 'ref' intent. - if (compType->isRecordType() || compType->isUnionType()) { - qtReceiver = QualifiedType(QualifiedType::REF, compType); - - // If the receiver is a basic class C, use 'const in x: borrowed C'. - } else if (auto basic = compType->toBasicClassType()) { - const Type* manager = nullptr; - auto borrowedNonnilDecor = - ClassTypeDecorator(ClassTypeDecorator::BORROWED_NONNIL); - auto receiverType = - ClassType::get(context, basic, manager, borrowedNonnilDecor); - CHPL_ASSERT(receiverType); - qtReceiver = QualifiedType(QualifiedType::CONST_IN, receiverType); - - } else { - CHPL_ASSERT(false && "Not possible!"); - } - - formalTypes.push_back(std::move(qtReceiver)); -} - static void collectFields(const AstNode* ast, std::vector& fields) { if (auto var = ast->toVarLikeDecl()) { @@ -369,18 +322,8 @@ const BuilderResult& buildInitializer(Context* context, ID typeID) { return QUERY_END(result); } -static const TypedFnSignature* -generateInitSignature(Context* context, const CompositeType* inCompType) { - if (auto ct = inCompType->getCompositeType()->toBasicClassType()) { - if (ct->isObjectType()) { - return nullptr; - } - } - - auto& br = buildInitializer(context, inCompType->id()); - - auto initFn = br.topLevelExpression(0)->toFunction(); - +static std::vector +buildInitUfsFormals(const uast::Function* initFn) { // compute the FormalDetails manually so that we can set the default-kind // appropriately. // @@ -390,14 +333,19 @@ generateInitSignature(Context* context, const CompositeType* inCompType) { for (auto decl : initFn->formals()) { UniqueString name; bool hasDefault = false; + if (auto formal = decl->toFormal()) { name = formal->name(); - hasDefault = formal->initExpression() != nullptr; - if (decl != initFn->thisFormal()) { - if (formal->intent() != Formal::Intent::TYPE && - formal->intent() != Formal::Intent::PARAM) { - if (formal->typeExpression() != nullptr) { - hasDefault = true; + + // Check if formal should have a default, which is never true for init= + if (initFn->name() != USTR("init=")) { + hasDefault = formal->initExpression() != nullptr; + if (decl != initFn->thisFormal()) { + if (formal->intent() != Formal::Intent::TYPE && + formal->intent() != Formal::Intent::PARAM) { + if (formal->typeExpression() != nullptr) { + hasDefault = true; + } } } } @@ -410,6 +358,22 @@ generateInitSignature(Context* context, const CompositeType* inCompType) { formals.push_back(fd); } + return formals; +} + +static const TypedFnSignature* +generateInitSignature(Context* context, const CompositeType* inCompType) { + if (auto ct = inCompType->getCompositeType()->toBasicClassType()) { + if (ct->isObjectType()) { + return nullptr; + } + } + + auto& br = buildInitializer(context, inCompType->id()); + + auto initFn = br.topLevelExpression(0)->toFunction(); + auto formals = buildInitUfsFormals(initFn); + // find the unique-ified untyped signature auto uSig = UntypedFnSignature::get(context, initFn->id(), initFn->name(), true, @@ -425,89 +389,210 @@ generateInitSignature(Context* context, const CompositeType* inCompType) { return typedSignatureInitial(&rcval, uSig); } +const BuilderResult& buildInitEquals(Context* context, ID typeID) { + QUERY_BEGIN(buildInitEquals, context, typeID); + + auto typeDecl = parsing::idToAst(context, typeID)->toAggregateDecl(); + auto bld = Builder::createForGeneratedCode(context, typeID); + auto builder = bld.get(); + auto dummyLoc = parsing::locateId(context, typeID); + + auto thisType = Identifier::build(builder, dummyLoc, typeDecl->name()); + auto thisFormal = Formal::build(builder, dummyLoc, nullptr, + USTR("this"), Formal::DEFAULT_INTENT, + std::move(thisType), nullptr); + + // TODO: constrain type to be same as 'typeID', possibly through 'this.type'? + auto otherName = UniqueString::get(context, "other"); + auto otherFormal = Formal::build(builder, dummyLoc, nullptr, + otherName, Formal::DEFAULT_INTENT, + nullptr, nullptr); + AstList formals; + formals.push_back(std::move(otherFormal)); + + AstList stmts; + + std::vector fields; + for (auto d : typeDecl->decls()) { + collectFields(d, fields); + } + + for (auto field : fields) { + // Create 'this.field = other.field;' statement + owned lhs = Dot::build(builder, dummyLoc, + Identifier::build(builder, dummyLoc, USTR("this")), + field->name()); + owned rhs = Dot::build(builder, dummyLoc, + Identifier::build(builder, dummyLoc, otherName), + field->name()); + owned assign = OpCall::build(builder, dummyLoc, USTR("="), + std::move(lhs), std::move(rhs)); + stmts.push_back(std::move(assign)); + } + + auto body = Block::build(builder, dummyLoc, std::move(stmts)); + auto genFn = Function::build(builder, + dummyLoc, {}, + Decl::Visibility::PUBLIC, + Decl::Linkage::DEFAULT_LINKAGE, + /*linkageName=*/{}, + USTR("init="), + /*inline=*/false, /*override=*/false, + Function::Kind::PROC, + /*receiver=*/std::move(thisFormal), + Function::ReturnIntent::DEFAULT_RETURN_INTENT, + // throws, primaryMethod, parenless + false, false, false, + std::move(formals), + // returnType, where, lifetime, body + {}, {}, {}, std::move(body)); + + builder->noteChildrenLocations(genFn.get(), dummyLoc); + builder->addToplevelExpression(std::move(genFn)); + + auto result = builder->result(); + return QUERY_END(result); +} + static const TypedFnSignature* generateInitCopySignature(Context* context, const CompositeType* inCompType) { - const CompositeType* compType = nullptr; - std::vector ufsFormals; - std::vector formalTypes; + auto& br = buildInitEquals(context, inCompType->id()); + auto initFn = br.topLevelExpression(0)->toFunction(); + auto formals = buildInitUfsFormals(initFn); - generateInitParts(context, inCompType, compType, - ufsFormals, formalTypes, /*useGeneric*/ false); + // find the unique-ified untyped signature + auto uSig = UntypedFnSignature::get(context, initFn->id(), initFn->name(), + true, + /* isTypeConstructor */ false, + /* isCompilerGenerated */ true, + /* throws */ false, + /* idTag */ asttags::Function, + uast::Function::Kind::PROC, + std::move(formals), nullptr, + inCompType->id()); - // add a formal for the 'other' argument - auto name = UniqueString::get(context, "other"); - auto defaultKind = UntypedFnSignature::DK_NO_DEFAULT; - const uast::Decl* node = nullptr; + ResolutionContext rcval(context); + return typedSignatureInitial(&rcval, uSig); +} - auto fd = UntypedFnSignature::FormalDetail(name, defaultKind, node); - ufsFormals.push_back(std::move(fd)); +const BuilderResult& buildDeinit(Context* context, ID typeID) { + QUERY_BEGIN(buildDeinit, context, typeID); - CHPL_ASSERT(formalTypes.size() == 1); - auto otherType = QualifiedType(QualifiedType::CONST_REF, - formalTypes[0].type()); - formalTypes.push_back(std::move(otherType)); + auto bld = Builder::createForGeneratedCode(context, typeID); + auto builder = bld.get(); + auto dummyLoc = parsing::locateId(context, typeID); - // build the untyped signature - auto ufs = UntypedFnSignature::get(context, - /*id*/ compType->id(), - /*name*/ USTR("init="), - /*isMethod*/ true, - /*isTypeConstructor*/ false, - /*isCompilerGenerated*/ true, - /*throws*/ false, - /*idTag*/ parsing::idToTag(context, compType->id()), - /*kind*/ uast::Function::Kind::PROC, - /*formals*/ std::move(ufsFormals), - /*whereClause*/ nullptr); + auto thisType = Identifier::build(builder, dummyLoc, typeID.symbolName(context)); + auto thisFormal = Formal::build(builder, dummyLoc, nullptr, + USTR("this"), Formal::DEFAULT_INTENT, + std::move(thisType), nullptr); - // now build the other pieces of the typed signature - auto ret = TypedFnSignature::get(context, - ufs, - std::move(formalTypes), - TypedFnSignature::WHERE_NONE, - /*needsInstantiation*/ false, - /* instantiatedFrom */ nullptr, - /* parentFn */ nullptr, - /* formalsInstantiated */ Bitmap(), - /* outerVariables */ {}); + AstList formals; - return ret; + // Empty body. Easier to let other parts of resolution infer the contents. + // TODO: Insert call to parent deinit + AstList stmts; + auto body = Block::build(builder, dummyLoc, std::move(stmts)); + + auto genFn = Function::build(builder, + dummyLoc, {}, + Decl::Visibility::PUBLIC, + Decl::Linkage::DEFAULT_LINKAGE, + /*linkageName=*/{}, + USTR("deinit"), + /*inline=*/false, /*override=*/false, + Function::Kind::PROC, + /*receiver=*/std::move(thisFormal), + Function::ReturnIntent::DEFAULT_RETURN_INTENT, + // throws, primaryMethod, parenless + false, false, false, + std::move(formals), + // returnType, where, lifetime, body + {}, {}, {}, std::move(body)); + + builder->noteChildrenLocations(genFn.get(), dummyLoc); + builder->addToplevelExpression(std::move(genFn)); + + auto result = builder->result(); + return QUERY_END(result); } static const TypedFnSignature* generateDeinitSignature(Context* context, const CompositeType* inCompType) { - const CompositeType* compType = nullptr; std::vector ufsFormals; - std::vector formalTypes; + auto& br = buildDeinit(context, inCompType->id()); + auto deinitFn = br.topLevelExpression(0)->toFunction(); - generateInitParts(context, inCompType, compType, - ufsFormals, formalTypes, /*useGeneric*/ false); + auto fd = UntypedFnSignature::FormalDetail(USTR("this"), + UntypedFnSignature::DK_NO_DEFAULT, + deinitFn->thisFormal(), false); + ufsFormals.push_back(fd); // build the untyped signature auto ufs = UntypedFnSignature::get(context, - /*id*/ compType->id(), + /*id*/ deinitFn->id(), /*name*/ USTR("deinit"), /*isMethod*/ true, /*isTypeConstructor*/ false, /*isCompilerGenerated*/ true, /*throws*/ false, - /*idTag*/ parsing::idToTag(context, compType->id()), + /*idTag*/ asttags::Function, /*kind*/ uast::Function::Kind::PROC, /*formals*/ std::move(ufsFormals), /*whereClause*/ nullptr); - // now build the other pieces of the typed signature - auto ret = TypedFnSignature::get(context, - ufs, - std::move(formalTypes), - TypedFnSignature::WHERE_NONE, - /*needsInstantiation*/ false, - /* instantiatedFrom */ nullptr, - /* parentFn */ nullptr, - /* formalsInstantiated */ Bitmap(), - /* outerVariables */ {}); + ResolutionContext rcval(context); + return typedSignatureInitial(&rcval, ufs); +} - return ret; +const BuilderResult& buildDeSerialize(Context* context, ID typeID, bool isSerializer) { + QUERY_BEGIN(buildDeSerialize, context, typeID, isSerializer); + + // TODO: + // - use types for formals + // - add calls to (de)serializeDefaultImpl + + auto bld = Builder::createForGeneratedCode(context, typeID); + auto builder = bld.get(); + auto dummyLoc = parsing::locateId(context, typeID); + + auto thisType = Identifier::build(builder, dummyLoc, typeID.symbolName(context)); + auto thisFormal = Formal::build(builder, dummyLoc, nullptr, + USTR("this"), Formal::DEFAULT_INTENT, + std::move(thisType), nullptr); + + auto writerArg = Formal::build(builder, dummyLoc, nullptr, UniqueString::get(context, "writer"), + Formal::DEFAULT_INTENT, {}, nullptr); + auto serializerArg = Formal::build(builder, dummyLoc, nullptr, UniqueString::get(context, "serializer"), + Formal::DEFAULT_INTENT, {}, nullptr); + AstList formals; + formals.push_back(std::move(writerArg)); + formals.push_back(std::move(serializerArg)); + + AstList stmts; + auto body = Block::build(builder, dummyLoc, std::move(stmts)); + + auto genFn = Function::build(builder, + dummyLoc, {}, + Decl::Visibility::PUBLIC, + Decl::Linkage::DEFAULT_LINKAGE, + /*linkageName=*/{}, + USTR("serialize"), + /*inline=*/false, /*override=*/false, + Function::Kind::PROC, + /*receiver=*/std::move(thisFormal), + Function::ReturnIntent::DEFAULT_RETURN_INTENT, + // throws, primaryMethod, parenless + true, false, false, + std::move(formals), + // returnType, where, lifetime, body + {}, {}, {}, std::move(body)); + + builder->noteChildrenLocations(genFn.get(), dummyLoc); + builder->addToplevelExpression(std::move(genFn)); + + auto result = builder->result(); + return QUERY_END(result); } static const TypedFnSignature* @@ -517,62 +602,37 @@ generateDeSerialize(Context* context, const CompositeType* compType, std::vector ufsFormals; std::vector formalTypes; + auto& br = buildDeSerialize(context, compType->id(), name == USTR("serialize")); + auto genFn = br.topLevelExpression(0)->toFunction(); + ufsFormals.push_back( UntypedFnSignature::FormalDetail(USTR("this"), UntypedFnSignature::DK_NO_DEFAULT, - nullptr)); - - QualifiedType thisType; - if (compType->isBasicClassType()) { - const Type* manager = nullptr; - auto borrowedNonnilDecor = - ClassTypeDecorator(ClassTypeDecorator::BORROWED_NONNIL); - auto receiverType = - ClassType::get(context, compType->toBasicClassType(), manager, borrowedNonnilDecor); - thisType = QualifiedType(QualifiedType::CONST_IN, receiverType); - } else { - thisType =QualifiedType(QualifiedType::CONST_REF, compType); - } - formalTypes.push_back(thisType); - - // TODO: Add constraints to these arguments + genFn->thisFormal())); ufsFormals.push_back( UntypedFnSignature::FormalDetail(UniqueString::get(context, channel), UntypedFnSignature::DK_NO_DEFAULT, - nullptr)); - formalTypes.push_back(QualifiedType(QualifiedType::CONST_REF, AnyType::get(context))); - + genFn->formal(0))); ufsFormals.push_back( UntypedFnSignature::FormalDetail(UniqueString::get(context, deSerializer), UntypedFnSignature::DK_NO_DEFAULT, - nullptr)); - formalTypes.push_back(QualifiedType(QualifiedType::REF, AnyType::get(context))); + genFn->formal(1))); // build the untyped signature auto ufs = UntypedFnSignature::get(context, - /*id*/ compType->id(), + /*id*/ genFn->id(), /*name*/ name, /*isMethod*/ true, /*isTypeConstructor*/ false, /*isCompilerGenerated*/ true, /*throws*/ true, - /*idTag*/ parsing::idToTag(context, compType->id()), + /*idTag*/ asttags::Function, /*kind*/ uast::Function::Kind::PROC, /*formals*/ std::move(ufsFormals), /*whereClause*/ nullptr); - // now build the other pieces of the typed signature - auto ret = TypedFnSignature::get(context, - ufs, - std::move(formalTypes), - TypedFnSignature::WHERE_NONE, - /*needsInstantiation*/ false, - /* instantiatedFrom */ nullptr, - /* parentFn */ nullptr, - /* formalsInstantiated */ Bitmap(), - /* outerVariables */ {}); - - return ret; + ResolutionContext rcval(context); + return typedSignatureInitial(&rcval, ufs); } static const TypedFnSignature* @@ -1336,6 +1396,14 @@ builderResultForDefaultFunction(Context* context, if (name == USTR("init")) { return &buildInitializer(context, typeID); + } else if (name == USTR("init=")) { + return &buildInitEquals(context, typeID); + } else if (name == USTR("deinit")) { + return &buildDeinit(context, typeID); + } else if (name == USTR("serialize")) { + return &buildDeSerialize(context, typeID, true); + } else if (name == USTR("deserialize")) { + return &buildDeSerialize(context, typeID, false); } else if (typeID.symbolName(context) == name) { return &buildTypeConstructor(context, typeID); } diff --git a/frontend/lib/resolution/default-functions.h b/frontend/lib/resolution/default-functions.h index 2f5c79051b2d..24ab4d888232 100644 --- a/frontend/lib/resolution/default-functions.h +++ b/frontend/lib/resolution/default-functions.h @@ -84,7 +84,10 @@ getCompilerGeneratedBinaryOp(Context* context, UniqueString name); const uast::BuilderResult& buildInitializer(Context* context, ID typeID); +const uast::BuilderResult& buildInitEquals(Context* context, ID typeID); const uast::BuilderResult& buildTypeConstructor(Context* context, ID typeID); +const uast::BuilderResult& buildDeinit(Context* context, ID typeID); +const uast::BuilderResult& buildDeSerialize(Context* context, ID typeID, bool isSerializer); } // end namespace resolution } // end namespace chpl diff --git a/frontend/lib/resolution/resolution-queries.cpp b/frontend/lib/resolution/resolution-queries.cpp index 1aacfcb9f2f2..6750361ddf6c 100644 --- a/frontend/lib/resolution/resolution-queries.cpp +++ b/frontend/lib/resolution/resolution-queries.cpp @@ -5030,7 +5030,7 @@ resolveCallInMethod(ResolutionContext* rc, std::vector* rejected) { CallResolutionResult asFunction = resolveCall(rc,call,ci,inScopes,rejected); - + CallResolutionResult asMethod; if (shouldAttemptImplicitReceiver(ci, implicitReceiver)) { auto methodCi = CallInfo::createWithReceiver(ci, implicitReceiver); diff --git a/frontend/lib/types/Type.cpp b/frontend/lib/types/Type.cpp index 14d0a1eef22f..4e0149d9a5c3 100644 --- a/frontend/lib/types/Type.cpp +++ b/frontend/lib/types/Type.cpp @@ -242,6 +242,10 @@ static bool compositeTypeIsPod(Context* context, const Type* t) { using namespace resolution; + if (auto cls = t->toClassType()) { + return !cls->decorator().isManaged(); + } + auto ct = t->getCompositeType(); if (!ct) return false;