From 99a9c021e2902fc902e8cfabc90cb0f91a67f8e6 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 24 Dec 2021 22:06:48 -0800 Subject: [PATCH] Carry through the ordinal for opaque type declarations. Generalize the implementation of opaque type declarations to maintain the "ordinal", which represents a particular "some" utterance in a structural opaque type, throughout more of the compiler. The ordinal value for a given "some" matches with the index of the corresponding generic parameter in the opaque type declaration's generic signature. To properly be able to determine the ordinal for a given "some" type representation, retain all of the "some" type representations in the `OpaqueTypeDecl` (using trailing storage), so we can map them to the proper generic parameter and ordinal later on. --- include/swift/AST/Decl.h | 68 ++++++++++++++++++++++----- include/swift/AST/Types.h | 5 +- lib/AST/ASTContext.cpp | 4 +- lib/AST/ASTDemangler.cpp | 5 -- lib/AST/Decl.cpp | 41 +++++++++++++--- lib/AST/Type.cpp | 4 ++ lib/Sema/TypeCheckGeneric.cpp | 8 ++-- lib/Serialization/Deserialization.cpp | 7 ++- 8 files changed, 101 insertions(+), 41 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index a9169a15ac8..b6fad83d12c 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -2699,22 +2699,26 @@ public: /// The declared type uses a special kind of archetype type to represent /// abstracted types, e.g. `(some P, some Q)` becomes `((opaque archetype 0), /// (opaque archetype 1))`. -class OpaqueTypeDecl : public GenericTypeDecl { +class OpaqueTypeDecl final : + public GenericTypeDecl, + private llvm::TrailingObjects { + friend TrailingObjects; + /// The original declaration that "names" the opaque type. Although a specific /// opaque type cannot be explicitly named, oapque types can propagate /// arbitrarily through expressions, so we need to know *which* opaque type is /// propagated. - ValueDecl *NamingDecl; + /// + /// The bit indicates whether there are any trailing + /// OpaqueReturnTypeReprs. + llvm::PointerIntPair + NamingDeclAndHasOpaqueReturnTypeRepr; /// The generic signature of the opaque interface to the type. This is the /// outer generic signature with added generic parameters representing the /// abstracted underlying types. GenericSignature OpaqueInterfaceGenericSignature; - /// The type repr of the underlying type. Might be null if no source location - /// is availble, e.g. if this decl was loaded from a serialized module. - OpaqueReturnTypeRepr *UnderlyingInterfaceRepr; - /// The generic parameter that represents the underlying type. GenericTypeParamType *UnderlyingInterfaceType; @@ -2725,19 +2729,47 @@ class OpaqueTypeDecl : public GenericTypeDecl { Optional UnderlyingTypeSubstitutions; mutable Identifier OpaqueReturnTypeIdentifier; - -public: + OpaqueTypeDecl(ValueDecl *NamingDecl, GenericParamList *GenericParams, DeclContext *DC, GenericSignature OpaqueInterfaceGenericSignature, - OpaqueReturnTypeRepr *UnderlyingInterfaceRepr, + ArrayRef OpaqueReturnTypeReprs, GenericTypeParamType *UnderlyingInterfaceType); - ValueDecl *getNamingDecl() const { return NamingDecl; } + unsigned getNumOpaqueReturnTypeReprs() const { + return NamingDeclAndHasOpaqueReturnTypeRepr.getInt() + ? getOpaqueGenericParams().size() + : 0; + } + + size_t numTrailingObjects(OverloadToken) const { + return getNumOpaqueReturnTypeReprs(); + } + + /// Retrieve the buffer containing the opaque return type + /// representations that correspond to the opaque generic parameters. + ArrayRef getOpaqueReturnTypeReprs() const { + return { + getTrailingObjects(), + getNumOpaqueReturnTypeReprs() + }; + } + +public: + static OpaqueTypeDecl *get( + ValueDecl *NamingDecl, GenericParamList *GenericParams, + DeclContext *DC, + GenericSignature OpaqueInterfaceGenericSignature, + ArrayRef OpaqueReturnTypeReprs, + GenericTypeParamType *UnderlyingInterfaceType); + + ValueDecl *getNamingDecl() const { + return NamingDeclAndHasOpaqueReturnTypeRepr.getPointer(); + } void setNamingDecl(ValueDecl *D) { - assert(!NamingDecl && "already have naming decl"); - NamingDecl = D; + assert(!getNamingDecl() && "already have naming decl"); + NamingDeclAndHasOpaqueReturnTypeRepr.setPointer(D); } /// Is this opaque type the opaque return type of the given function? @@ -2754,7 +2786,17 @@ public: GenericSignature getOpaqueInterfaceGenericSignature() const { return OpaqueInterfaceGenericSignature; } - + + /// Retrieve the generic parameters that represent the opaque types described by this opaque + /// type declaration. + TypeArrayView getOpaqueGenericParams() const { + return OpaqueInterfaceGenericSignature.getInnermostGenericParams(); + } + + /// The underlying interface type describing the whole opaque type. + /// + /// FIXME: Structured opaque types will generalize this to an + /// arbitrary type. GenericTypeParamType *getUnderlyingInterfaceType() const { return UnderlyingInterfaceType; } diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 45fb797fd18..a32f3918095 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -5601,10 +5601,7 @@ public: /// func foo() -> (some P, some Q) /// /// then the underlying type of `some P` would be ordinal 0, and `some Q` would be ordinal 1. - unsigned getOrdinal() const { - // TODO [OPAQUE SUPPORT]: multiple opaque types - return 0; - } + unsigned getOrdinal() const; static void Profile(llvm::FoldingSetNodeID &ID, OpaqueTypeDecl *OpaqueDecl, diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 48e47fb034b..06b4a20970c 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -4275,9 +4275,7 @@ DependentMemberType *DependentMemberType::get(Type base, OpaqueTypeArchetypeType * OpaqueTypeArchetypeType::get(OpaqueTypeDecl *Decl, unsigned ordinal, SubstitutionMap Substitutions) { - // TODO [OPAQUE SUPPORT]: multiple opaque types - assert(ordinal == 0 && "we only support one 'some' type per composite type"); - auto opaqueParamType = Decl->getUnderlyingInterfaceType(); + auto opaqueParamType = Decl->getOpaqueGenericParams()[ordinal]; // TODO: We could attempt to preserve type sugar in the substitution map. // Currently archetypes are assumed to be always canonical in many places, diff --git a/lib/AST/ASTDemangler.cpp b/lib/AST/ASTDemangler.cpp index ff46d1b8331..698da2641b7 100644 --- a/lib/AST/ASTDemangler.cpp +++ b/lib/AST/ASTDemangler.cpp @@ -265,11 +265,6 @@ Type ASTBuilder::resolveOpaqueType(NodePointer opaqueDescriptor, auto opaqueDecl = parentModule->lookupOpaqueResultType(mangledName); if (!opaqueDecl) return Type(); - // TODO [OPAQUE SUPPORT]: multiple opaque types - assert(ordinal == 0 && "not implemented"); - if (ordinal != 0) - return Type(); - SmallVector allArgs; for (auto argSet : args) { allArgs.append(argSet.begin(), argSet.end()); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 92c3f0127a8..7030b572f85 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -7780,16 +7780,41 @@ void AbstractFunctionDecl::setParameters(ParameterList *BodyParams) { OpaqueTypeDecl::OpaqueTypeDecl(ValueDecl *NamingDecl, GenericParamList *GenericParams, DeclContext *DC, GenericSignature OpaqueInterfaceGenericSignature, - OpaqueReturnTypeRepr *UnderlyingInterfaceRepr, + ArrayRef + OpaqueReturnTypeReprs, GenericTypeParamType *UnderlyingInterfaceType) : GenericTypeDecl(DeclKind::OpaqueType, DC, Identifier(), SourceLoc(), {}, GenericParams), - NamingDecl(NamingDecl), + NamingDeclAndHasOpaqueReturnTypeRepr( + NamingDecl, !OpaqueReturnTypeReprs.empty()), OpaqueInterfaceGenericSignature(OpaqueInterfaceGenericSignature), - UnderlyingInterfaceRepr(UnderlyingInterfaceRepr), UnderlyingInterfaceType(UnderlyingInterfaceType) { // Always implicit. setImplicit(); + + /// We either have no opaque return type representations ('some P'), or we + /// have one for each opaque generic parameter. + assert(OpaqueReturnTypeReprs.empty() || + OpaqueReturnTypeReprs.size() == + OpaqueInterfaceGenericSignature.getInnermostGenericParams().size()); + std::uninitialized_copy( + OpaqueReturnTypeReprs.begin(), OpaqueReturnTypeReprs.end(), + getTrailingObjects()); +} + +OpaqueTypeDecl *OpaqueTypeDecl::get( + ValueDecl *NamingDecl, GenericParamList *GenericParams, + DeclContext *DC, + GenericSignature OpaqueInterfaceGenericSignature, + ArrayRef OpaqueReturnTypeReprs, + GenericTypeParamType *UnderlyingInterfaceType) { + ASTContext &ctx = DC->getASTContext(); + auto size = totalSizeToAlloc( + OpaqueReturnTypeReprs.size()); + auto mem = ctx.Allocate(size, alignof(OpaqueTypeDecl)); + return new (mem) OpaqueTypeDecl( + NamingDecl, GenericParams, DC, OpaqueInterfaceGenericSignature, + OpaqueReturnTypeReprs, UnderlyingInterfaceType); } bool OpaqueTypeDecl::isOpaqueReturnTypeOfFunction( @@ -7809,11 +7834,13 @@ bool OpaqueTypeDecl::isOpaqueReturnTypeOfFunction( unsigned OpaqueTypeDecl::getAnonymousOpaqueParamOrdinal( OpaqueReturnTypeRepr *repr) const { - // TODO [OPAQUE SUPPORT]: we will need to generalize here when we allow - // multiple "some" types. - assert(UnderlyingInterfaceRepr && + assert(NamingDeclAndHasOpaqueReturnTypeRepr.getInt() && "can't do opaque param lookup without underlying interface repr"); - return repr == UnderlyingInterfaceRepr ? 0 : -1; + auto opaqueReprs = getOpaqueReturnTypeReprs(); + auto found = std::find(opaqueReprs.begin(), opaqueReprs.end(), repr); + if (found != opaqueReprs.end()) + return found - opaqueReprs.begin(); + return -1; } Identifier OpaqueTypeDecl::getOpaqueReturnTypeIdentifier() const { diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 66c1070a6d4..b59e5fb1fcc 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -3289,6 +3289,10 @@ OpaqueTypeArchetypeType::OpaqueTypeArchetypeType(OpaqueTypeDecl *OpaqueDecl, { } +unsigned OpaqueTypeArchetypeType::getOrdinal() const { + return getInterfaceType()->castTo()->getIndex(); +} + SequenceArchetypeType::SequenceArchetypeType( const ASTContext &Ctx, GenericEnvironment *GenericEnv, Type InterfaceType, ArrayRef ConformsTo, Type Superclass, diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index ce25b997d23..97e09127e8f 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -296,11 +296,9 @@ OpaqueResultTypeRequest::evaluate(Evaluator &evaluator, } // Create the OpaqueTypeDecl for the result type. - auto opaqueDecl = new (ctx) - OpaqueTypeDecl(originatingDecl, genericParams, parentDC, - interfaceSignature, - opaqueReprs.empty() ? 0 : opaqueReprs[0], - underlyingGenericParamType); + auto opaqueDecl = OpaqueTypeDecl::get( + originatingDecl, genericParams, parentDC, interfaceSignature, opaqueReprs, + underlyingGenericParamType); opaqueDecl->copyFormalAccessFrom(originatingDecl); if (auto originatingSig = originatingDC->getGenericSignatureOfContext()) { opaqueDecl->setGenericSignature(originatingSig); diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 1abaa7dce24..de5a1364b02 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -3464,10 +3464,9 @@ public: return cast(declOrOffset.get()); // Create the decl. - auto opaqueDecl = new (ctx) - OpaqueTypeDecl(/*NamingDecl*/ nullptr, - /*GenericParams*/ nullptr, declContext, interfaceSig, - /*UnderlyingInterfaceTypeRepr*/ nullptr, interfaceType); + auto opaqueDecl = OpaqueTypeDecl::get( + /*NamingDecl*/ nullptr, /*GenericParams*/ nullptr, declContext, + interfaceSig, /*OpaqueReturnTypeReprs*/ { }, interfaceType); declOrOffset = opaqueDecl; auto namingDecl = cast(MF.getDecl(namingDeclID));