diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index dfcaadeac7533..459e878fefabd 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -1609,6 +1609,10 @@ class ASTContext final { OutputBackend = std::move(OutBackend); } +private: + friend class BuiltinGenericType; + GenericSignature &getCachedBuiltinGenericTypeSignature(TypeKind kind); + private: friend Decl; diff --git a/include/swift/AST/TypeDifferenceVisitor.h b/include/swift/AST/TypeDifferenceVisitor.h index 5dde346477d7e..04aade617a043 100644 --- a/include/swift/AST/TypeDifferenceVisitor.h +++ b/include/swift/AST/TypeDifferenceVisitor.h @@ -134,13 +134,28 @@ class CanTypeDifferenceVisitor : public CanTypePairVisitor { CanBuiltinUnboundGenericType type2) { return asImpl().visitDifferentTypeStructure(type1, type2); } - - bool visitBuiltinFixedArrayType(CanBuiltinFixedArrayType type1, - CanBuiltinFixedArrayType type2) { - if (asImpl().visit(type1->getSize(), type2->getSize())) { + + bool visitBuiltinGenericType(CanBuiltinGenericType type1, + CanBuiltinGenericType type2) { + if (type1->getBuiltinTypeKind() != type2->getBuiltinTypeKind()) { return true; } - return asImpl().visit(type1->getElementType(), type2->getElementType()); + + auto subs1 = type1->getSubstitutions(); + auto subs2 = type2->getSubstitutions(); + + for (unsigned i : indices(subs1.getReplacementTypes())) { + if (asImpl().visit(CanType(subs1.getReplacementTypes()[i]), + CanType(subs2.getReplacementTypes()[i]))) { + return true; + } + } + for (unsigned i : indices(subs1.getConformances())) { + if (subs1.getConformances()[i] != subs2.getConformances()[i]) { + return true; + } + } + return false; } bool visitPackType(CanPackType type1, CanPackType type2) { diff --git a/include/swift/AST/TypeMatcher.h b/include/swift/AST/TypeMatcher.h index 31ac8e6ab299d..5bf1b37bbb363 100644 --- a/include/swift/AST/TypeMatcher.h +++ b/include/swift/AST/TypeMatcher.h @@ -112,7 +112,7 @@ class TypeMatcher { TRIVIAL_CASE(BuiltinFloatType) TRIVIAL_CASE(BuiltinVectorType) TRIVIAL_CASE(BuiltinUnboundGenericType) - TRIVIAL_CASE(BuiltinFixedArrayType) + TRIVIAL_CASE(BuiltinGenericType) TRIVIAL_CASE(IntegerType) #define SINGLETON_TYPE(SHORT_ID, ID) TRIVIAL_CASE(ID##Type) #include "swift/AST/TypeNodes.def" diff --git a/include/swift/AST/TypeNodes.def b/include/swift/AST/TypeNodes.def index a43d7d1642a14..b49e9958dd86e 100644 --- a/include/swift/AST/TypeNodes.def +++ b/include/swift/AST/TypeNodes.def @@ -141,7 +141,9 @@ ABSTRACT_TYPE(Builtin, Type) BUILTIN_CONCRETE_TYPE(BuiltinDefaultActorStorage, BuiltinType) BUILTIN_CONCRETE_TYPE(BuiltinNonDefaultDistributedActorStorage, BuiltinType) BUILTIN_CONCRETE_TYPE(BuiltinVector, BuiltinType) - BUILTIN_GENERIC_TYPE(BuiltinFixedArray, BuiltinType) + ABSTRACT_TYPE(BuiltinGeneric, BuiltinType) + BUILTIN_GENERIC_TYPE(BuiltinFixedArray, BuiltinGenericType) + TYPE_RANGE(BuiltinGeneric, BuiltinFixedArray, BuiltinFixedArray) BUILTIN_CONCRETE_TYPE(BuiltinUnboundGeneric, BuiltinType) BUILTIN_CONCRETE_TYPE(BuiltinImplicitActor, BuiltinType) TYPE_RANGE(Builtin, BuiltinInteger, BuiltinImplicitActor) diff --git a/include/swift/AST/TypeTransform.h b/include/swift/AST/TypeTransform.h index 1305c2695901e..a1558d15a54c3 100644 --- a/include/swift/AST/TypeTransform.h +++ b/include/swift/AST/TypeTransform.h @@ -21,6 +21,8 @@ #include "swift/AST/GenericEnvironment.h" #include "swift/AST/SILLayout.h" #include "swift/AST/LifetimeDependence.h" +#include "swift/AST/SubstitutionMap.h" +#include "llvm/ADT/SmallVector.h" namespace swift { @@ -117,29 +119,26 @@ case TypeKind::Id: case TypeKind::Integer: return t; + // BuiltinGenericType subclasses case TypeKind::BuiltinFixedArray: { - auto bfaTy = cast(base); - - Type transSize = doIt(bfaTy->getSize(), - TypePosition::Invariant); - if (!transSize) { - return Type(); - } - - Type transElement = doIt(bfaTy->getElementType(), - TypePosition::Invariant); - if (!transElement) { - return Type(); - } - - CanType canTransSize = transSize->getCanonicalType(); - CanType canTransElement = transElement->getCanonicalType(); - if (canTransSize != bfaTy->getSize() - || canTransElement != bfaTy->getElementType()) { - return BuiltinFixedArrayType::get(canTransSize, canTransElement); + auto bgaTy = cast(base); + + llvm::SmallVector transReplacements; + + for (auto t : bgaTy->getSubstitutions().getReplacementTypes()) { + Type transTy = doIt(t, TypePosition::Invariant); + if (!transTy) { + return Type(); + } + transReplacements.push_back(transTy); } - - return bfaTy; + + // TODO: translate conformances. No builtin types yet have conformance + // requirements in their generic signatures. + auto transSubs = SubstitutionMap::get(bgaTy->getGenericSignature(), + transReplacements, + ArrayRef{}); + return bgaTy->getWithSubstitutions(transSubs); } case TypeKind::PrimaryArchetype: diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index d3ebaa77a243d..c608e0032d245 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -1780,12 +1780,45 @@ class BuiltinUnboundGenericType : public BuiltinType { }; DEFINE_EMPTY_CAN_TYPE_WRAPPER(BuiltinUnboundGenericType, BuiltinType) +/// BuiltinGenericType - Base class for builtins that are parameterized by +/// a generic signature. +class BuiltinGenericType : public BuiltinType { +protected: + + BuiltinGenericType(TypeKind kind, ASTContext &context, + RecursiveTypeProperties properties) + : BuiltinType(kind, context, properties) + {} + + /// The substitution map is cached here once requested. + mutable std::optional CachedSubstitutionMap = std::nullopt; + +public: + static bool classof(const TypeBase *T) { + return T->getKind() >= TypeKind::First_BuiltinGenericType + && T->getKind() <= TypeKind::Last_BuiltinGenericType; + } + + // Get the generic signature describing the parameterization of types of + // this class. + GenericSignature getGenericSignature() const; + + // Get the substitution map for this particular type. + SubstitutionMap getSubstitutions() const; + + // Produce another type of the same class but with different arguments. + CanTypeWrapper + getWithSubstitutions(SubstitutionMap newSubs) const; +}; +DEFINE_EMPTY_CAN_TYPE_WRAPPER(BuiltinGenericType, BuiltinType) + /// BuiltinFixedArrayType - The builtin type representing N values stored /// inline contiguously. /// /// All elements of a value of this type must be fully initialized any time the /// value may be copied, moved, or destroyed. -class BuiltinFixedArrayType : public BuiltinType, public llvm::FoldingSetNode { +class BuiltinFixedArrayType : public BuiltinGenericType, + public llvm::FoldingSetNode { friend class ASTContext; CanType Size; @@ -1793,12 +1826,17 @@ class BuiltinFixedArrayType : public BuiltinType, public llvm::FoldingSetNode { BuiltinFixedArrayType(CanType Size, CanType ElementType, RecursiveTypeProperties properties) - : BuiltinType(TypeKind::BuiltinFixedArray, ElementType->getASTContext(), - properties), + : BuiltinGenericType(TypeKind::BuiltinFixedArray, + ElementType->getASTContext(), + properties), Size(Size), ElementType(ElementType) {} + friend BuiltinGenericType; + /// Get the generic arguments as a substitution map. + SubstitutionMap buildSubstitutions() const; + public: /// Arrays with more elements than this are always treated as in-memory values. /// @@ -1826,7 +1864,7 @@ class BuiltinFixedArrayType : public BuiltinType, public llvm::FoldingSetNode { /// Get the element type. CanType getElementType() const { return ElementType; } - + void Profile(llvm::FoldingSetNodeID &ID) const { Profile(ID, getSize(), getElementType()); } @@ -1836,7 +1874,7 @@ class BuiltinFixedArrayType : public BuiltinType, public llvm::FoldingSetNode { ID.AddPointer(ElementType.getPointer()); } }; -DEFINE_EMPTY_CAN_TYPE_WRAPPER(BuiltinFixedArrayType, BuiltinType) +DEFINE_EMPTY_CAN_TYPE_WRAPPER(BuiltinFixedArrayType, BuiltinGenericType) /// BuiltinRawPointerType - The builtin raw (and dangling) pointer type. This /// pointer is completely unmanaged and is equivalent to i8* in LLVM IR. diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 0acc541f5eff9..6709dd305b06f 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -533,6 +533,13 @@ struct ASTContext::Implementation { /// Local and closure discriminators per context. llvm::DenseMap NextDiscriminator; + /// Cached generic signatures for generic builtin types. + static const unsigned NumBuiltinGenericTypes + = unsigned(TypeKind::Last_BuiltinGenericType) + - unsigned(TypeKind::First_BuiltinGenericType) + 1; + std::array + BuiltinGenericTypeSignatures = {}; + /// Structure that captures data that is segregated into different /// arenas. struct Arena { @@ -7309,3 +7316,13 @@ AvailabilityDomain ASTContext::getTargetAvailabilityDomain() const { // Fall back to the universal domain for triples without a platform. return AvailabilityDomain::forUniversal(); } + +GenericSignature & +ASTContext::getCachedBuiltinGenericTypeSignature(TypeKind kind) { + ASSERT(kind >= TypeKind::First_BuiltinGenericType + && kind <= TypeKind::Last_BuiltinGenericType + && "not a builtin generic type kind"); + + return getImpl().BuiltinGenericTypeSignatures + [unsigned(kind) - unsigned(TypeKind::First_BuiltinGenericType)]; +} diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index b6d4da3f073e8..adff78c1d9477 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -21,6 +21,7 @@ #include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" +#include "swift/AST/SubstitutionMap.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/AST/Types.h" #include "swift/Basic/Assertions.h" @@ -30,6 +31,7 @@ #include "llvm/IR/Attributes.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" #include @@ -3649,11 +3651,10 @@ BuiltinUnboundGenericType::getBuiltinTypeNameString() const { return getBuiltinTypeName(); } -GenericSignature -BuiltinUnboundGenericType::getGenericSignature() const { - auto &C = getASTContext(); - - switch (BoundGenericTypeKind) { +static GenericSignature +getBuiltinGenericSignature(ASTContext &C, + TypeKind kind) { + switch (kind) { case TypeKind::BuiltinFixedArray: { auto Count = GenericTypeParamType::get(C.getIdentifier("Count"), GenericTypeParamKind::Value, @@ -3663,35 +3664,48 @@ BuiltinUnboundGenericType::getGenericSignature() const { 0, 1, Type(), C); return GenericSignature::get({Count, Element}, {}); } - + case TypeKind::BuiltinInteger: { auto bits = GenericTypeParamType::get(C.getIdentifier("Bits"), GenericTypeParamKind::Type, 0, 0, C.getIntType(), C); return GenericSignature::get(bits, {}); + } default: - llvm_unreachable("not a generic builtin"); + llvm_unreachable("not a generic builtin type"); } } -Type -BuiltinUnboundGenericType::getBound(SubstitutionMap subs) const { - if (!subs.getGenericSignature()->isEqual(getGenericSignature())) { - return ErrorType::get(const_cast(this)); +GenericSignature +BuiltinUnboundGenericType::getGenericSignature() const { + return getBuiltinGenericSignature(getASTContext(), BoundGenericTypeKind); +} + +static Type +getBuiltinBoundGenericType(ASTContext &C, + TypeKind kind, + SubstitutionMap subs, + bool validate) { + if (!subs.getGenericSignature()->isEqual(getBuiltinGenericSignature(C, kind))) { + return ErrorType::get(BuiltinUnboundGenericType::get(kind, C)); } - switch (BoundGenericTypeKind) { + switch (kind) { case TypeKind::BuiltinFixedArray: { auto types = subs.getReplacementTypes(); auto size = types[0]->getCanonicalType(); - if (size->getMatchingParamKind() != GenericTypeParamKind::Value) { - return ErrorType::get(const_cast(this)); + if (validate + && size->getMatchingParamKind() != GenericTypeParamKind::Value + && !size->hasTypeVariableOrPlaceholder()) { + return ErrorType::get(BuiltinUnboundGenericType::get(kind, C)); } auto element = types[1]->getCanonicalType(); - if (element->getMatchingParamKind() != GenericTypeParamKind::Type) { - return ErrorType::get(const_cast(this)); + if (validate + && element->getMatchingParamKind() != GenericTypeParamKind::Type + && !element->hasTypeVariableOrPlaceholder()) { + return ErrorType::get(BuiltinUnboundGenericType::get(kind, C)); } return BuiltinFixedArrayType::get(size, element); @@ -3699,19 +3713,20 @@ BuiltinUnboundGenericType::getBound(SubstitutionMap subs) const { case TypeKind::BuiltinInteger: { auto size = subs.getReplacementTypes()[0]; - if (size->getMatchingParamKind() != GenericTypeParamKind::Value) { - return ErrorType::get(const_cast(this)); + if (validate + && size->getMatchingParamKind() != GenericTypeParamKind::Value) { + return ErrorType::get(BuiltinUnboundGenericType::get(kind, C)); } // TODO: support actual generic parameters auto literalSize = size->getAs(); if (!literalSize) { - return ErrorType::get(const_cast(this)); + assert(validate && "can't represent an unbound generic sized integer yet"); + return ErrorType::get(BuiltinUnboundGenericType::get(kind, C)); } - return BuiltinIntegerType::get(literalSize->getValue().getLimitedValue(), - getASTContext()); + return BuiltinIntegerType::get(literalSize->getValue().getLimitedValue(),C); } default: @@ -3719,6 +3734,59 @@ BuiltinUnboundGenericType::getBound(SubstitutionMap subs) const { } } +Type +BuiltinUnboundGenericType::getBound(SubstitutionMap subs) const { + return getBuiltinBoundGenericType(getASTContext(), BoundGenericTypeKind, + subs, /*validate*/ true); +} + +CanBuiltinGenericType +BuiltinGenericType::getWithSubstitutions(SubstitutionMap subs) const { + auto t = getBuiltinBoundGenericType(getASTContext(), getKind(), subs, + /*validate*/ false); + return CanBuiltinGenericType(t->castTo()); +} + +GenericSignature +BuiltinGenericType::getGenericSignature() const { + auto &cached = getASTContext() + .getCachedBuiltinGenericTypeSignature(getKind()); + + if (!cached) { + cached = getBuiltinGenericSignature(getASTContext(), getKind()); + } + + return cached; +} + +SubstitutionMap +BuiltinGenericType::getSubstitutions() const { + if (auto cached = CachedSubstitutionMap) { + return *cached; + } + + auto buildSubstitutions = [&]() -> SubstitutionMap { +#define BUILTIN_GENERIC_SUBCLASS(c) \ + if (auto t = dyn_cast(this)) { \ + return t->c::buildSubstitutions(); \ + } + + BUILTIN_GENERIC_SUBCLASS(BuiltinFixedArrayType) + llvm_unreachable("unhandled BuiltinGenericType subclass"); + }; + + auto subs = buildSubstitutions(); + CachedSubstitutionMap = subs; + return subs; +} + +SubstitutionMap +BuiltinFixedArrayType::buildSubstitutions() const { + return SubstitutionMap::get(getGenericSignature(), + {getSize(), getElementType()}, + ArrayRef{}); +} + std::optional BuiltinFixedArrayType::getFixedInhabitedSize() const { if (auto intSize = getSize()->getAs()) { diff --git a/lib/AST/TypeWalker.cpp b/lib/AST/TypeWalker.cpp index b14330d807a2c..e236dece27527 100644 --- a/lib/AST/TypeWalker.cpp +++ b/lib/AST/TypeWalker.cpp @@ -17,6 +17,7 @@ #include "swift/AST/TypeWalker.h" #include "swift/AST/TypeVisitor.h" #include "swift/AST/GenericEnvironment.h" +#include "swift/AST/Types.h" #include "swift/Basic/Assertions.h" using namespace swift; @@ -301,17 +302,16 @@ class Traversal : public TypeVisitor } return false; } - - bool visitBuiltinFixedArrayType(BuiltinFixedArrayType *ty) { - if (ty->getSize() && doIt(ty->getSize())) { - return true; - } - if (ty->getElementType() && doIt(ty->getElementType())) { - return true; + + bool visitBuiltinGenericType(BuiltinGenericType *ty) { + for (auto replacement : ty->getSubstitutions().getReplacementTypes()) { + if (replacement && doIt(replacement)) { + return true; + } } return false; } - + public: explicit Traversal(TypeWalker &walker) : Walker(walker) {} diff --git a/lib/SIL/IR/AbstractionPattern.cpp b/lib/SIL/IR/AbstractionPattern.cpp index e7913e3b735ca..61b9309e2ce39 100644 --- a/lib/SIL/IR/AbstractionPattern.cpp +++ b/lib/SIL/IR/AbstractionPattern.cpp @@ -15,6 +15,8 @@ // //===----------------------------------------------------------------------===// +#include "swift/AST/Types.h" +#include "llvm/ADT/SmallVector.h" #define DEBUG_TYPE "libsil" #include "swift/AST/ASTContext.h" #include "swift/AST/ConformanceLookup.h" @@ -2673,32 +2675,38 @@ class SubstFunctionTypePatternVisitor // Otherwise, there are no structural type parameters to visit. return nom; } - - CanType visitBuiltinFixedArrayType(CanBuiltinFixedArrayType bfa, - AbstractionPattern pattern) { - auto orig = pattern.getAs(); + + CanType visitBuiltinGenericType(CanBuiltinGenericType bga, + AbstractionPattern pattern) { + auto orig = pattern.getAs(); // If there are no loose type parameters in the pattern here, we don't need // to do a recursive visit at all. if (!orig->hasTypeParameter() && !orig->hasArchetype() && !orig->hasOpaqueArchetype()) { - return bfa; + return bga; } - - CanType newSize = visit(bfa->getSize(), - AbstractionPattern(pattern.getGenericSubstitutions(), - pattern.getGenericSignatureOrNull(), - orig->getSize())); - CanType newElement = visit(bfa->getElementType(), - AbstractionPattern(pattern.getGenericSubstitutions(), - pattern.getGenericSignatureOrNull(), - orig->getElementType())); - - return BuiltinFixedArrayType::get(newSize, newElement) - ->getCanonicalType(); + + SmallVector newReplacements; + + for (unsigned i : indices(bga->getSubstitutions().getReplacementTypes())) { + CanType newReplacement + = visit(CanType(bga->getSubstitutions().getReplacementTypes()[i]), + AbstractionPattern(pattern.getGenericSubstitutions(), + pattern.getGenericSignatureOrNull(), + CanType(orig->getSubstitutions().getReplacementTypes()[i]))); + newReplacements.push_back(newReplacement); + } + + // TODO: handle conformances. no generic builtins currently have protocol + // requirements. + auto newSubs = SubstitutionMap::get(bga->getGenericSignature(), + newReplacements, + ArrayRef{}); + return bga->getWithSubstitutions(newSubs); } - + CanType visitBoundGenericType(CanBoundGenericType bgt, AbstractionPattern pattern) { return handleGenericNominalType(pattern, bgt); diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 7badd961f9776..c5365d11cd32a 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -7471,21 +7471,28 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, case TypeKind::Error: return getTypeMatchFailure(locator); + // BuiltinGenericType subclasses case TypeKind::BuiltinFixedArray: { - auto *fixed1 = cast(desugar1); - auto *fixed2 = cast(desugar2); + auto *fixed1 = cast(desugar1); + auto *fixed2 = cast(desugar2); + if (fixed1->getBuiltinTypeKind() != fixed2->getBuiltinTypeKind()) { + return getTypeMatchFailure(locator); + } - auto result = matchTypes(fixed1->getSize(), fixed2->getSize(), - ConstraintKind::Bind, subflags, - locator.withPathElement( - LocatorPathElt::GenericArgument(0))); - if (result.isFailure()) - return result; + auto result = ConstraintSystem::TypeMatchResult::success(); + for (unsigned i + : indices(fixed1->getSubstitutions().getReplacementTypes())) { + result = matchTypes(fixed1->getSubstitutions().getReplacementTypes()[i], + fixed2->getSubstitutions().getReplacementTypes()[i], + ConstraintKind::Bind, subflags, + locator.withPathElement( + LocatorPathElt::GenericArgument(i))); + if (result.isFailure()) { + return result; + } + } - return matchTypes(fixed1->getElementType(), fixed2->getElementType(), - ConstraintKind::Bind, subflags, - locator.withPathElement( - LocatorPathElt::GenericArgument(0))); + return result; } case TypeKind::Placeholder: {