diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index b313d264736df..4a3ccf95535a2 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -519,7 +519,7 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated { IsComputingSemanticMembers : 1 ); - SWIFT_INLINE_BITFIELD_FULL(ProtocolDecl, NominalTypeDecl, 1+1+1+1+1+1+1+1+1+8+16, + SWIFT_INLINE_BITFIELD_FULL(ProtocolDecl, NominalTypeDecl, 1+1+1+1+1+1+1+1+1+1+1+8+16, /// Whether the \c RequiresClass bit is valid. RequiresClassValid : 1, @@ -532,6 +532,12 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated { /// Whether the existential of this protocol conforms to itself. ExistentialConformsToSelf : 1, + /// Whether the \c ExistentialRequiresAny bit is valid. + ExistentialRequiresAnyValid : 1, + + /// Whether the existential of this protocol must be spelled with \c any. + ExistentialRequiresAny : 1, + /// True if the protocol has requirements that cannot be satisfied (e.g. /// because they could not be imported from Objective-C). HasMissingRequirements : 1, @@ -4224,6 +4230,21 @@ class ProtocolDecl final : public NominalTypeDecl { Bits.ProtocolDecl.ExistentialConformsToSelf = result; } + /// Returns the cached result of \c existentialRequiresAny or \c None if it + /// hasn't yet been computed. + Optional getCachedExistentialRequiresAny() { + if (Bits.ProtocolDecl.ExistentialRequiresAnyValid) + return Bits.ProtocolDecl.ExistentialRequiresAny; + + return None; + } + + /// Caches the result of \c existentialRequiresAny + void setCachedExistentialRequiresAny(bool requiresAny) { + Bits.ProtocolDecl.ExistentialRequiresAnyValid = true; + Bits.ProtocolDecl.ExistentialRequiresAny = requiresAny; + } + bool hasLazyRequirementSignature() const { return Bits.ProtocolDecl.HasLazyRequirementSignature; } @@ -4237,6 +4258,7 @@ class ProtocolDecl final : public NominalTypeDecl { friend class RequirementSignatureRequestRQM; friend class ProtocolRequiresClassRequest; friend class ExistentialConformsToSelfRequest; + friend class ExistentialRequiresAnyRequest; friend class InheritedProtocolsRequest; public: @@ -4325,6 +4347,11 @@ class ProtocolDecl final : public NominalTypeDecl { /// contain 'Self' in 'parameter' or 'other' position. bool isAvailableInExistential(const ValueDecl *decl) const; + /// Determine whether an existential type must be explicitly prefixed + /// with \c any. \c any is required if any of the members contain + /// an associated type, or if \c Self appears in non-covariant position. + bool existentialRequiresAny() const; + /// Returns a list of protocol requirements that must be assessed to /// determine a concrete's conformance effect polymorphism kind. PolymorphicEffectRequirementList getPolymorphicEffectRequirements( diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index e95b5d378addd..0ea07eaf3a4e2 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -873,7 +873,8 @@ ERROR(sil_function_subs_without_generics,none, // Opaque types ERROR(opaque_mid_composition,none, - "'some' should appear at the beginning of a composition", ()) + "'%0' should appear at the beginning of a composition", + (StringRef)) //------------------------------------------------------------------------------ // MARK: Layout constraint diagnostics diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index ac805477ad203..9ea910c55aabe 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -4618,6 +4618,19 @@ ERROR(unchecked_not_inheritance_clause,none, ERROR(unchecked_not_existential,none, "'unchecked' attribute cannot apply to non-protocol type %0", (Type)) +WARNING(unnecessary_any,none, + "'any' is redundant on type %0", (Type)) +ERROR(any_not_existential,none, + "'any' has no effect on %select{concrete type|type parameter}0 %1", + (bool, Type)) +ERROR(existential_requires_any,none, + "protocol %0 as a type must be explicitly marked as 'any'", + (Identifier)) +ERROR(explicit_existential_not_supported,none, + "explicit 'any' not supported; use frontend flag " + "-enable-explicit-existential-types to enable this feature", + ()) + ERROR(nonisolated_let,none, "'nonisolated' is meaningless on 'let' declarations because " "they are immutable", diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 87642adedd562..07f4c78a76304 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -287,6 +287,32 @@ class ExistentialConformsToSelfRequest : void cacheResult(bool value) const; }; +/// Determine whether an existential type conforming to this protocol +/// requires the \c any syntax. +class ExistentialRequiresAnyRequest : + public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + bool evaluate(Evaluator &evaluator, ProtocolDecl *decl) const; + +public: + // Cycle handling. + void diagnoseCycle(DiagnosticEngine &diags) const; + void noteCycleStep(DiagnosticEngine &diags) const; + + // Separate caching. + bool isCached() const { return true; } + Optional getCachedResult() const; + void cacheResult(bool value) const; +}; + class PolymorphicEffectRequirementsRequest : public SimpleRequest { type1->getMembers(), type2->getMembers()); } + bool visitExistentialType(CanExistentialType type1, + CanExistentialType type2) { + return asImpl().visit(type1.getConstraintType(), + type2.getConstraintType()); + } + bool visitLValueType(CanLValueType type1, CanLValueType type2) { return asImpl().visit(type1.getObjectType(), type2.getObjectType()); } diff --git a/include/swift/AST/TypeMatcher.h b/include/swift/AST/TypeMatcher.h index c0da030791ab5..4323e3ab720eb 100644 --- a/include/swift/AST/TypeMatcher.h +++ b/include/swift/AST/TypeMatcher.h @@ -269,6 +269,20 @@ class TypeMatcher { TRIVIAL_CASE(SILBoxType) TRIVIAL_CASE(ProtocolCompositionType) + bool visitExistentialType(CanExistentialType firstExistential, + Type secondType, + Type sugaredFirstType) { + if (auto secondExistential = secondType->getAs()) { + return this->visit(firstExistential.getConstraintType(), + secondExistential->getConstraintType(), + sugaredFirstType->castTo() + ->getConstraintType()); + } + + return mismatch(firstExistential.getPointer(), secondType, + sugaredFirstType); + } + bool visitLValueType(CanLValueType firstLValue, Type secondType, Type sugaredFirstType) { if (auto secondLValue = secondType->getAs()) { diff --git a/include/swift/AST/TypeNodes.def b/include/swift/AST/TypeNodes.def index 23c668e90b675..23b0696c2fcf1 100644 --- a/include/swift/AST/TypeNodes.def +++ b/include/swift/AST/TypeNodes.def @@ -162,6 +162,7 @@ ARTIFICIAL_TYPE(SILBlockStorage, Type) ARTIFICIAL_TYPE(SILBox, Type) ARTIFICIAL_TYPE(SILToken, Type) TYPE(ProtocolComposition, Type) +TYPE(Existential, Type) TYPE(LValue, Type) TYPE(InOut, Type) UNCHECKED_TYPE(TypeVariable, Type) diff --git a/include/swift/AST/TypeRepr.h b/include/swift/AST/TypeRepr.h index 448df94a353f1..94b27ae1a1c06 100644 --- a/include/swift/AST/TypeRepr.h +++ b/include/swift/AST/TypeRepr.h @@ -1158,6 +1158,35 @@ class NamedOpaqueReturnTypeRepr : public TypeRepr { friend class TypeRepr; }; +/// A TypeRepr for an existential type spelled with \c any +/// +/// Can appear anywhere a normal existential type would. This is +/// purely a more explicit spelling for existential types. +class ExistentialTypeRepr: public TypeRepr { + TypeRepr *Constraint; + SourceLoc AnyLoc; + +public: + ExistentialTypeRepr(SourceLoc anyLoc, TypeRepr *constraint) + : TypeRepr(TypeReprKind::Existential), Constraint(constraint), + AnyLoc(anyLoc) {} + + TypeRepr *getConstraint() const { return Constraint; } + SourceLoc getAnyLoc() const { return AnyLoc; } + + static bool classof(const TypeRepr *T) { + return T->getKind() == TypeReprKind::Existential; + } + static bool classof(const ExistentialTypeRepr *T) { return true; } + +private: + SourceLoc getStartLocImpl() const { return AnyLoc; } + SourceLoc getEndLocImpl() const { return Constraint->getEndLoc(); } + SourceLoc getLocImpl() const { return AnyLoc; } + void printImpl(ASTPrinter &Printer, const PrintOptions &Opts) const; + friend class TypeRepr; +}; + /// TypeRepr for a user-specified placeholder (essentially, a user-facing /// representation of an anonymous type variable. /// @@ -1285,6 +1314,7 @@ inline bool TypeRepr::isSimple() const { case TypeReprKind::Composition: case TypeReprKind::OpaqueReturn: case TypeReprKind::NamedOpaqueReturn: + case TypeReprKind::Existential: return false; case TypeReprKind::SimpleIdent: case TypeReprKind::GenericIdent: diff --git a/include/swift/AST/TypeReprNodes.def b/include/swift/AST/TypeReprNodes.def index fee3fd287fcc8..3bb74cf05f77a 100644 --- a/include/swift/AST/TypeReprNodes.def +++ b/include/swift/AST/TypeReprNodes.def @@ -55,6 +55,7 @@ TYPEREPR(Metatype, TypeRepr) TYPEREPR(Protocol, TypeRepr) TYPEREPR(OpaqueReturn, TypeRepr) TYPEREPR(NamedOpaqueReturn, TypeRepr) +TYPEREPR(Existential, TypeRepr) TYPEREPR(Placeholder, TypeRepr) ABSTRACT_TYPEREPR(Specifier, TypeRepr) TYPEREPR(InOut, SpecifierTypeRepr) diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index b8f337344569c..28d8da6a620ef 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -5199,6 +5199,42 @@ class ProtocolCompositionType final : public TypeBase, BEGIN_CAN_TYPE_WRAPPER(ProtocolCompositionType, Type) END_CAN_TYPE_WRAPPER(ProtocolCompositionType, Type) +/// An existential type, spelled with \c any . +/// +/// In Swift 5 mode, a plain protocol name in type +/// context is an implicit existential type. +class ExistentialType final : public TypeBase { + Type ConstraintType; + + ExistentialType(Type constraintType, + const ASTContext *canonicalContext, + RecursiveTypeProperties properties) + : TypeBase(TypeKind::Existential, canonicalContext, properties), + ConstraintType(constraintType) {} + +public: + static ExistentialType *get(Type constraint); + + Type getConstraintType() const { return ConstraintType; } + + bool requiresClass() const { + if (auto protocol = ConstraintType->getAs()) + return protocol->requiresClass(); + + if (auto composition = ConstraintType->getAs()) + return composition->requiresClass(); + + return false; + } + + static bool classof(const TypeBase *type) { + return type->getKind() == TypeKind::Existential; + } +}; +BEGIN_CAN_TYPE_WRAPPER(ExistentialType, Type) + PROXY_CAN_TYPE_SIMPLE_GETTER(getConstraintType) +END_CAN_TYPE_WRAPPER(ExistentialType, Type) + /// LValueType - An l-value is a handle to a physical object. The /// type of that object uniquely determines the type of an l-value /// for it. @@ -6154,7 +6190,9 @@ inline bool TypeBase::isAnyExistentialType() { } inline bool CanType::isExistentialTypeImpl(CanType type) { - return isa(type) || isa(type); + return (isa(type) || + isa(type) || + isa(type)); } inline bool CanType::isAnyExistentialTypeImpl(CanType type) { @@ -6167,6 +6205,8 @@ inline bool TypeBase::isClassExistentialType() { return pt->requiresClass(); if (auto pct = dyn_cast(T)) return pct->requiresClass(); + if (auto existential = dyn_cast(T)) + return existential->requiresClass(); return false; } @@ -6427,6 +6467,9 @@ inline bool TypeBase::hasSimpleTypeRepr() const { case TypeKind::ExistentialMetatype: return !cast(this)->hasRepresentation(); + case TypeKind::Existential: + return false; + case TypeKind::NestedArchetype: return cast(this)->getParent()->hasSimpleTypeRepr(); diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 9e8f1ecfc6f38..a1421fd5d97f8 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -310,6 +310,10 @@ namespace swift { /// `func f() -> T`. bool EnableExperimentalNamedOpaqueTypes = false; + /// Enable support for explicit existential types via the \c any + /// keyword. + bool EnableExplicitExistentialTypes = false; + /// Enable experimental flow-sensitive concurrent captures. bool EnableExperimentalFlowSensitiveConcurrentCaptures = false; diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 6c53cbc492fc0..f4b744bad0101 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -472,6 +472,10 @@ def enable_experimental_structural_opaque_types : Flag<["-"], "enable-experimental-structural-opaque-types">, HelpText<"Enable experimental support for structural opaque result types">; +def enable_explicit_existential_types : + Flag<["-"], "enable-explicit-existential-types">, + HelpText<"Enable experimental support for explicit existential types">; + def enable_deserialization_recovery : Flag<["-"], "enable-deserialization-recovery">, HelpText<"Attempt to recover from missing xrefs (etc) in swiftmodules">; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 314885b458f1b..36e82a10f8b7c 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -408,6 +408,7 @@ struct ASTContext::Implementation { llvm::DenseMap, StructType*> StructTypes; llvm::DenseMap, ClassType*> ClassTypes; llvm::DenseMap, ProtocolType*> ProtocolTypes; + llvm::DenseMap ExistentialTypes; llvm::FoldingSet UnboundGenericTypes; llvm::FoldingSet BoundGenericTypes; llvm::FoldingSet ProtocolCompositionTypes; @@ -4093,6 +4094,21 @@ ProtocolType::ProtocolType(ProtocolDecl *TheDecl, Type Parent, RecursiveTypeProperties properties) : NominalType(TypeKind::Protocol, &Ctx, TheDecl, Parent, properties) { } +ExistentialType *ExistentialType::get(Type constraint) { + auto properties = constraint->getRecursiveProperties(); + auto arena = getArena(properties); + + auto &C = constraint->getASTContext(); + auto &entry = C.getImpl().getArena(arena).ExistentialTypes[constraint]; + if (entry) + return entry; + + const ASTContext *canonicalContext = constraint->isCanonical() ? &C : nullptr; + return entry = new (C, arena) ExistentialType(constraint, + canonicalContext, + properties); +} + LValueType *LValueType::get(Type objectTy) { assert(!objectTy->is() && !objectTy->is() && "cannot have 'inout' or @lvalue wrapped inside an @lvalue"); diff --git a/lib/AST/ASTDemangler.cpp b/lib/AST/ASTDemangler.cpp index 31b5af311c3ff..ff46d1b83314f 100644 --- a/lib/AST/ASTDemangler.cpp +++ b/lib/AST/ASTDemangler.cpp @@ -589,7 +589,12 @@ Type ASTBuilder::createProtocolCompositionType( members.push_back(protocol->getDeclaredInterfaceType()); if (superclass && superclass->getClassOrBoundGenericClass()) members.push_back(superclass); - return ProtocolCompositionType::get(Ctx, members, isClassBound); + Type composition = ProtocolCompositionType::get(Ctx, members, isClassBound); + if (Ctx.LangOpts.EnableExplicitExistentialTypes && + !(composition->isAny() || composition->isAnyObject())) { + composition = ExistentialType::get(composition); + } + return composition; } static MetatypeRepresentation @@ -607,6 +612,8 @@ getMetatypeRepresentation(ImplMetatypeRepresentation repr) { Type ASTBuilder::createExistentialMetatypeType(Type instance, Optional repr) { + if (auto existential = instance->getAs()) + instance = existential->getConstraintType(); if (!instance->isAnyExistentialType()) return Type(); if (!repr) diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 9b01939674728..5ae1f26910657 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -3095,6 +3095,12 @@ class PrintTypeRepr : public TypeReprVisitor { PrintWithColorRAII(OS, ParenthesisColor) << ')'; } + void visitExistentialTypeRepr(ExistentialTypeRepr *T) { + printCommon("type_existential"); + printRec(T->getConstraint()); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } + void visitPlaceholderTypeRepr(PlaceholderTypeRepr *T) { printCommon("type_placeholder"); PrintWithColorRAII(OS, ParenthesisColor) << ')'; @@ -3927,6 +3933,13 @@ namespace { PrintWithColorRAII(OS, ParenthesisColor) << ')'; } + void visitExistentialType(ExistentialType *T, + StringRef label) { + printCommon(label, "existential_type"); + printRec(T->getConstraintType()); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } + void visitLValueType(LValueType *T, StringRef label) { printCommon(label, "lvalue_type"); printRec(T->getObjectType()); diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 318bcf7bb4a90..3bdbdc7af9e19 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -1251,6 +1251,11 @@ void ASTMangler::appendType(Type type, GenericSignature sig, return appendExistentialLayout(layout, sig, forDecl); } + case TypeKind::Existential: { + auto constraint = cast(tybase)->getConstraintType(); + return appendType(constraint, sig, forDecl); + } + case TypeKind::UnboundGeneric: case TypeKind::Class: case TypeKind::Enum: diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 0ed06e34fdc2b..08d4b5defa58a 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -4739,11 +4739,18 @@ class TypePrinter : public TypeVisitor { case MetatypeRepresentation::ObjC: Printer << "@objc_metatype "; break; } } + + auto &ctx = T->getASTContext(); + if (T->is() && + ctx.LangOpts.EnableExplicitExistentialTypes) + Printer << "any "; + printWithParensIfNotSimple(T->getInstanceType()); // We spell normal metatypes of existential types as .Protocol. if (isa(T) && - T->getInstanceType()->isAnyExistentialType()) { + T->getInstanceType()->isAnyExistentialType() && + !ctx.LangOpts.EnableExplicitExistentialTypes) { Printer << ".Protocol"; } else { Printer << ".Type"; @@ -5329,6 +5336,11 @@ class TypePrinter : public TypeVisitor { } } + void visitExistentialType(ExistentialType *T) { + Printer << "any "; + visit(T->getConstraintType()); + } + void visitLValueType(LValueType *T) { Printer << "@lvalue "; visit(T->getObjectType()); diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index d010c6dd2e8f9..59a4ef7888c7b 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -1863,6 +1863,10 @@ bool Traversal::visitNamedOpaqueReturnTypeRepr(NamedOpaqueReturnTypeRepr *T) { return doIt(T->getBase()); } +bool Traversal::visitExistentialTypeRepr(ExistentialTypeRepr *T) { + return doIt(T->getConstraint()); +} + bool Traversal::visitPlaceholderTypeRepr(PlaceholderTypeRepr *T) { return false; } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 0279f72789134..de5a453c0c620 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -5258,6 +5258,11 @@ bool ProtocolDecl::isAvailableInExistential(const ValueDecl *decl) const { return true; } +bool ProtocolDecl::existentialRequiresAny() const { + return evaluateOrDefault(getASTContext().evaluator, + ExistentialRequiresAnyRequest{const_cast(this)}, true); +} + StringRef ProtocolDecl::getObjCRuntimeName( llvm::SmallVectorImpl &buffer) const { // If there is an 'objc' attribute with a name, use that name. diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index 0c5f2fd44ba7b..ba88285db7df2 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -1660,6 +1660,12 @@ static void extractDirectlyReferencedNominalTypes( return; } + if (auto existential = type->getAs()) { + extractDirectlyReferencedNominalTypes( + existential->getConstraintType(), decls); + return; + } + llvm_unreachable("Not a type containing nominal types?"); } @@ -2319,6 +2325,7 @@ directReferencesForTypeRepr(Evaluator &evaluator, case TypeReprKind::OpaqueReturn: case TypeReprKind::NamedOpaqueReturn: + case TypeReprKind::Existential: return { }; case TypeReprKind::Fixed: diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index e27df1cc49c70..689129f8002a5 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -190,6 +190,9 @@ bool CanType::isReferenceTypeImpl(CanType type, const GenericSignatureImpl *sig, return cast(type)->requiresClass(); case TypeKind::ProtocolComposition: return cast(type)->requiresClass(); + case TypeKind::Existential: + return isReferenceTypeImpl(cast(type).getConstraintType(), + sig, functionsCount); case TypeKind::UnboundGeneric: return isa(cast(type)->getDecl()); @@ -293,6 +296,12 @@ ExistentialLayout TypeBase::getExistentialLayout() { } ExistentialLayout CanType::getExistentialLayout() { + if (auto existential = dyn_cast(*this)) + return existential->getConstraintType()->getExistentialLayout(); + + if (auto metatype = dyn_cast(*this)) + return metatype->getInstanceType()->getExistentialLayout(); + if (auto proto = dyn_cast(*this)) return ExistentialLayout(proto); @@ -1443,6 +1452,12 @@ CanType TypeBase::computeCanonicalType() { Result = Composition.getPointer(); break; } + case TypeKind::Existential: { + auto *existential = cast(this); + auto constraint = existential->getConstraintType()->getCanonicalType(); + Result = ExistentialType::get(constraint); + break; + } case TypeKind::ExistentialMetatype: { auto metatype = cast(this); auto instanceType = metatype->getInstanceType()->getCanonicalType(); @@ -5236,6 +5251,19 @@ case TypeKind::Id: *this : InOutType::get(objectTy); } + case TypeKind::Existential: { + auto *existential = cast(base); + auto constraint = existential->getConstraintType().transformRec(fn); + if (!constraint || constraint->hasError()) + return constraint; + + if (constraint.getPointer() == + existential->getConstraintType().getPointer()) + return *this; + + return ExistentialType::get(constraint); + } + case TypeKind::ProtocolComposition: { auto pc = cast(base); SmallVector substMembers; @@ -5429,6 +5457,10 @@ ReferenceCounting TypeBase::getReferenceCounting() { return ReferenceCounting::Unknown; } + case TypeKind::Existential: + return cast(type)->getConstraintType() + ->getReferenceCounting(); + case TypeKind::Function: case TypeKind::GenericFunction: case TypeKind::SILFunction: diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index 2471e9ddc675b..b1dd853686ab9 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -249,6 +249,31 @@ void ExistentialConformsToSelfRequest::cacheResult(bool value) const { decl->setCachedExistentialConformsToSelf(value); } +//----------------------------------------------------------------------------// +// existentialRequiresAny computation. +//----------------------------------------------------------------------------// + +void ExistentialRequiresAnyRequest::diagnoseCycle(DiagnosticEngine &diags) const { + auto decl = std::get<0>(getStorage()); + diags.diagnose(decl, diag::circular_protocol_def, decl->getName()); +} + +void ExistentialRequiresAnyRequest::noteCycleStep(DiagnosticEngine &diags) const { + auto requirement = std::get<0>(getStorage()); + diags.diagnose(requirement, diag::kind_declname_declared_here, + DescriptiveDeclKind::Protocol, requirement->getName()); +} + +Optional ExistentialRequiresAnyRequest::getCachedResult() const { + auto decl = std::get<0>(getStorage()); + return decl->getCachedExistentialRequiresAny(); +} + +void ExistentialRequiresAnyRequest::cacheResult(bool value) const { + auto decl = std::get<0>(getStorage()); + decl->setCachedExistentialRequiresAny(value); +} + //----------------------------------------------------------------------------// // isFinal computation. //----------------------------------------------------------------------------// diff --git a/lib/AST/TypeRepr.cpp b/lib/AST/TypeRepr.cpp index 99f853b9eb203..4062e1fa66fc2 100644 --- a/lib/AST/TypeRepr.cpp +++ b/lib/AST/TypeRepr.cpp @@ -479,6 +479,12 @@ void OpaqueReturnTypeRepr::printImpl(ASTPrinter &Printer, printTypeRepr(Constraint, Printer, Opts); } +void ExistentialTypeRepr::printImpl(ASTPrinter &Printer, + const PrintOptions &Opts) const { + Printer.printKeyword("any", Opts, /*Suffix=*/" "); + printTypeRepr(Constraint, Printer, Opts); +} + SourceLoc NamedOpaqueReturnTypeRepr::getStartLocImpl() const { return GenericParams->getLAngleLoc(); } diff --git a/lib/AST/TypeWalker.cpp b/lib/AST/TypeWalker.cpp index a6ce37ffdf317..966458f12f24e 100644 --- a/lib/AST/TypeWalker.cpp +++ b/lib/AST/TypeWalker.cpp @@ -163,6 +163,10 @@ class Traversal : public TypeVisitor return false; } + bool visitExistentialType(ExistentialType *ty) { + return doIt(ty->getConstraintType()); + } + bool visitLValueType(LValueType *ty) { return doIt(ty->getObjectType()); } diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index cc60ba016612a..16933aee3faa6 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -438,6 +438,9 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.EnableExperimentalNamedOpaqueTypes |= Args.hasArg(OPT_enable_experimental_named_opaque_types); + Opts.EnableExplicitExistentialTypes |= + Args.hasArg(OPT_enable_explicit_existential_types); + Opts.EnableExperimentalDistributed |= Args.hasArg(OPT_enable_experimental_distributed); diff --git a/lib/IRGen/Fulfillment.cpp b/lib/IRGen/Fulfillment.cpp index 6ea58a82bf26f..c6077a0666339 100644 --- a/lib/IRGen/Fulfillment.cpp +++ b/lib/IRGen/Fulfillment.cpp @@ -99,6 +99,10 @@ static bool isLeafTypeMetadata(CanType type) { case TypeKind::ProtocolComposition: return false; + // Existential types have constraint types. + case TypeKind::Existential: + return false; + // Metatypes have instance types. case TypeKind::Metatype: case TypeKind::ExistentialMetatype: diff --git a/lib/IRGen/GenExistential.cpp b/lib/IRGen/GenExistential.cpp index 730ea78693f59..516eb9913685b 100644 --- a/lib/IRGen/GenExistential.cpp +++ b/lib/IRGen/GenExistential.cpp @@ -1441,6 +1441,9 @@ static const TypeInfo *createExistentialTypeInfo(IRGenModule &IGM, CanType T) { } // Note: Protocol composition types are not nominal, but we name them anyway. + if (auto existential = T->getAs()) { + T = existential->getConstraintType()->getCanonicalType(); + } llvm::StructType *type; if (isa(T)) type = IGM.createNominalType(T); @@ -1553,6 +1556,11 @@ TypeConverter::convertProtocolCompositionType(ProtocolCompositionType *T) { return createExistentialTypeInfo(IGM, CanType(T)); } +const TypeInfo * +TypeConverter::convertExistentialType(ExistentialType *T) { + return createExistentialTypeInfo(IGM, CanType(T)); +} + const TypeInfo * TypeConverter::convertExistentialMetatypeType(ExistentialMetatypeType *T) { assert(T->hasRepresentation() && diff --git a/lib/IRGen/GenType.cpp b/lib/IRGen/GenType.cpp index cdf6a3a75c040..eecdaa442cfb1 100644 --- a/lib/IRGen/GenType.cpp +++ b/lib/IRGen/GenType.cpp @@ -2182,6 +2182,8 @@ const TypeInfo *TypeConverter::convertType(CanType ty) { return convertProtocolType(cast(ty)); case TypeKind::ProtocolComposition: return convertProtocolCompositionType(cast(ty)); + case TypeKind::Existential: + return convertExistentialType(cast(ty)); case TypeKind::GenericTypeParam: case TypeKind::DependentMember: llvm_unreachable("can't convert dependent type"); diff --git a/lib/IRGen/GenType.h b/lib/IRGen/GenType.h index e070dcef0b432..284c74598dc6a 100644 --- a/lib/IRGen/GenType.h +++ b/lib/IRGen/GenType.h @@ -163,6 +163,7 @@ class TypeConverter { const TypeInfo *convertModuleType(ModuleType *T); const TypeInfo *convertProtocolType(ProtocolType *T); const TypeInfo *convertProtocolCompositionType(ProtocolCompositionType *T); + const TypeInfo *convertExistentialType(ExistentialType *T); const LoadableTypeInfo *convertBuiltinNativeObject(); const LoadableTypeInfo *convertBuiltinUnknownObject(); const LoadableTypeInfo *convertBuiltinBridgeObject(); diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp index aa2d8e6b22263..e5998782e9451 100644 --- a/lib/IRGen/IRGenDebugInfo.cpp +++ b/lib/IRGen/IRGenDebugInfo.cpp @@ -1458,6 +1458,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { Flags, MangledName); } + case TypeKind::Existential: case TypeKind::ProtocolComposition: { auto *Decl = DbgTy.getDecl(); auto L = getFilenameAndLocation(*this, Decl); diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index 21ff16f54e6c4..9d56f89581dbd 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -1729,6 +1729,12 @@ namespace { return emitExistentialTypeMetadata(type, request); } + MetadataResponse + visitExistentialType(CanExistentialType type, + DynamicMetadataRequest request) { + return emitExistentialTypeMetadata(type, request); + } + MetadataResponse visitReferenceStorageType(CanReferenceStorageType type, DynamicMetadataRequest request) { llvm_unreachable("reference storage type should have been converted by " diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp index 93fe717537164..162eb5aa82fcc 100644 --- a/lib/Parse/ParsePattern.cpp +++ b/lib/Parse/ParsePattern.cpp @@ -165,7 +165,8 @@ bool Parser::startsParameterName(bool isClosure) { if (nextTok.canBeArgumentLabel()) { // If the first name wasn't "isolated", we're done. if (!Tok.isContextualKeyword("isolated") && - !Tok.isContextualKeyword("some")) + !Tok.isContextualKeyword("some") && + !Tok.isContextualKeyword("any")) return true; // "isolated" can be an argument label, but it's also a contextual keyword, diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 1fadcc4de2fbd..f7b406ef5d9a6 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -804,10 +804,15 @@ Parser::parseTypeSimpleOrComposition(Diag<> MessageID, ParseTypeReason reason) { // This is only semantically allowed in certain contexts, but we parse it // generally for diagnostics and recovery. SourceLoc opaqueLoc; + SourceLoc anyLoc; if (Tok.isContextualKeyword("some")) { // Treat some as a keyword. TokReceiver->registerTokenKindChange(Tok.getLoc(), tok::contextual_keyword); opaqueLoc = consumeToken(); + } else if (Tok.isContextualKeyword("any")) { + // Treat any as a keyword. + TokReceiver->registerTokenKindChange(Tok.getLoc(), tok::contextual_keyword); + anyLoc = consumeToken(); } else { // This isn't a some type. SomeTypeContext.setTransparent(); @@ -816,6 +821,8 @@ Parser::parseTypeSimpleOrComposition(Diag<> MessageID, ParseTypeReason reason) { auto applyOpaque = [&](TypeRepr *type) -> TypeRepr* { if (opaqueLoc.isValid()) { type = new (Context) OpaqueReturnTypeRepr(opaqueLoc, type); + } else if (anyLoc.isValid()) { + type = new (Context) ExistentialTypeRepr(anyLoc, type); } return type; }; @@ -866,16 +873,21 @@ Parser::parseTypeSimpleOrComposition(Diag<> MessageID, ParseTypeReason reason) { consumeToken(); // consume '&' } - // Diagnose invalid `some` after an ampersand. - if (Tok.isContextualKeyword("some")) { + // Diagnose invalid `some` or `any` after an ampersand. + if (Tok.isContextualKeyword("some") || + Tok.isContextualKeyword("any")) { + auto keyword = Tok.getText(); auto badLoc = consumeToken(); - diagnose(badLoc, diag::opaque_mid_composition) + diagnose(badLoc, diag::opaque_mid_composition, keyword) .fixItRemove(badLoc) - .fixItInsert(FirstTypeLoc, "some "); + .fixItInsert(FirstTypeLoc, keyword.str() + " "); - if (opaqueLoc.isInvalid()) + if (opaqueLoc.isInvalid()) { opaqueLoc = badLoc; + } else if (anyLoc.isInvalid()) { + anyLoc = badLoc; + } } // Parse next type. @@ -1441,8 +1453,11 @@ bool Parser::canParseType() { // Accept 'inout' at for better recovery. consumeIf(tok::kw_inout); - if (Tok.isContextualKeyword("some")) + if (Tok.isContextualKeyword("some")) { consumeToken(); + } else if (Tok.isContextualKeyword("any")) { + consumeToken(); + } switch (Tok.getKind()) { case tok::kw_Self: diff --git a/lib/PrintAsObjC/DeclAndTypePrinter.cpp b/lib/PrintAsObjC/DeclAndTypePrinter.cpp index 98803ea8e88a8..a122c289eb305 100644 --- a/lib/PrintAsObjC/DeclAndTypePrinter.cpp +++ b/lib/PrintAsObjC/DeclAndTypePrinter.cpp @@ -1830,6 +1830,12 @@ class DeclAndTypePrinter::Implementation visitExistentialType(PCT, optionalKind, /*isMetatype=*/false); } + void visitExistentialType(ExistentialType *ET, + Optional optionalKind) { + visitExistentialType(ET, optionalKind, + /*isMetatype=*/ET->getConstraintType()->is()); + } + void visitExistentialMetatypeType(ExistentialMetatypeType *MT, Optional optionalKind) { Type instanceTy = MT->getInstanceType(); diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 189d94061f2a7..1edc8ff1e4742 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -6942,6 +6942,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, case TypeKind::Struct: case TypeKind::Protocol: case TypeKind::ProtocolComposition: + case TypeKind::Existential: case TypeKind::BoundGenericEnum: case TypeKind::BoundGenericStruct: case TypeKind::GenericFunction: @@ -6954,6 +6955,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, auto desugaredToType = toType->getDesugaredType(); switch (desugaredToType->getKind()) { // Coercions from a type to an existential type. + case TypeKind::Existential: case TypeKind::ExistentialMetatype: case TypeKind::ProtocolComposition: case TypeKind::Protocol: diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index a1a386738a51a..f028980c1c386 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -2920,7 +2920,13 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2, // Handle existential metatypes. if (auto meta1 = type1->getAs()) { - if (auto meta2 = type2->getAs()) { + ExistentialMetatypeType *meta2; + if (auto existential = type2->getAs()) { + meta2 = existential->getConstraintType()->getAs(); + } else { + meta2 = type2->getAs(); + } + if (meta2) { return matchExistentialTypes(meta1->getInstanceType(), meta2->getInstanceType(), kind, subflags, locator.withPathElement( @@ -5674,6 +5680,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, case TypeKind::GenericFunction: llvm_unreachable("Polymorphic function type should have been opened"); + case TypeKind::Existential: case TypeKind::ProtocolComposition: switch (kind) { case ConstraintKind::Equal: @@ -6314,6 +6321,7 @@ ConstraintSystem::simplifyConstructionConstraint( case TypeKind::DynamicSelf: case TypeKind::ProtocolComposition: case TypeKind::Protocol: + case TypeKind::Existential: // Break out to handle the actual construction below. break; @@ -10690,6 +10698,11 @@ getDynamicCallableMethods(Type type, ConstraintSystem &CS, if (auto protocolComp = dyn_cast(canType)) return calculateForComponentTypes(protocolComp->getMembers()); + if (auto existential = dyn_cast(canType)) { + auto constraint = existential->getConstraintType(); + return getDynamicCallableMethods(constraint, CS, locator); + } + // Otherwise, this must be a nominal type. // Dynamic calling doesn't work for tuples, etc. auto nominal = canType->getAnyNominal(); diff --git a/lib/Sema/LookupVisibleDecls.cpp b/lib/Sema/LookupVisibleDecls.cpp index f4a91fd6f20b7..a67ee4c78640e 100644 --- a/lib/Sema/LookupVisibleDecls.cpp +++ b/lib/Sema/LookupVisibleDecls.cpp @@ -669,6 +669,13 @@ static void lookupVisibleMemberDeclsImpl( return; } + if (auto *existential = BaseTy->getAs()) { + auto constraint = existential->getConstraintType(); + lookupVisibleMemberDeclsImpl(constraint, Consumer, CurrDC, LS, Reason, + Sig, Visited); + return; + } + // Enumerate members of archetype's requirements. if (ArchetypeType *Archetype = BaseTy->getAs()) { for (auto Proto : Archetype->getConformsTo()) diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index dc3ef7e334c36..2569bde8c4a6a 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -3361,6 +3361,8 @@ static void checkSwitch(ASTContext &ctx, const SwitchStmt *stmt) { // We want to warn about "case .Foo, .Bar where 1 != 100:" since the where // clause only applies to the second case, and this is surprising. for (auto cs : stmt->getCases()) { + TypeChecker::checkExistentialTypes(ctx, cs); + // The case statement can have multiple case items, each can have a where. // If we find a "where", and there is a preceding item without a where, and // if they are on the same source line, then warn. @@ -4839,6 +4841,8 @@ void swift::performSyntacticExprDiagnostics(const Expr *E, void swift::performStmtDiagnostics(const Stmt *S, DeclContext *DC) { auto &ctx = DC->getASTContext(); + TypeChecker::checkExistentialTypes(ctx, const_cast(S)); + if (auto switchStmt = dyn_cast(S)) checkSwitch(ctx, switchStmt); diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 5d1de0900a6db..48cf3f8520e0b 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -666,6 +666,34 @@ ExistentialConformsToSelfRequest::evaluate(Evaluator &evaluator, return true; } +bool +ExistentialRequiresAnyRequest::evaluate(Evaluator &evaluator, + ProtocolDecl *decl) const { + // ObjC protocols do not require `any`. + if (decl->isObjC()) + return false; + + for (auto member : decl->getMembers()) { + // Existential types require `any` if the protocol has an associated type. + if (isa(member)) + return true; + + // For value members, look at their type signatures. + if (auto valueMember = dyn_cast(member)) { + if (!decl->isAvailableInExistential(valueMember)) + return true; + } + } + + // Check whether any of the inherited protocols require `any`. + for (auto proto : decl->getInheritedProtocols()) { + if (proto->existentialRequiresAny()) + return true; + } + + return false; +} + bool IsFinalRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const { if (isa(decl)) diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index 4c9556bf724fa..1910948b0b156 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -1696,6 +1696,8 @@ class DeclChecker : public DeclVisitor { DeclVisitor::visit(decl); + TypeChecker::checkExistentialTypes(decl); + if (auto VD = dyn_cast(decl)) { auto &Context = getASTContext(); TypeChecker::checkForForbiddenPrefix(Context, VD->getBaseName()); diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index 3d514c7bc04a9..9ed28d5532039 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -962,8 +962,16 @@ RequirementRequest::evaluate(Evaluator &evaluator, WhereClauseOwner owner, unsigned index, TypeResolutionStage stage) const { + auto &reqRepr = getRequirement(); + // Figure out the type resolution. - auto options = TypeResolutionOptions(TypeResolverContext::GenericRequirement); + TypeResolverContext context; + if (reqRepr.getKind() == RequirementReprKind::SameType) { + context = TypeResolverContext::SameTypeRequirement; + } else { + context = TypeResolverContext::GenericRequirement; + } + auto options = TypeResolutionOptions(context); if (owner.dc->isInSpecializeExtensionContext()) options |= TypeResolutionFlags::AllowUsableFromInline; Optional resolution; @@ -981,7 +989,6 @@ RequirementRequest::evaluate(Evaluator &evaluator, break; } - auto &reqRepr = getRequirement(); switch (reqRepr.getKind()) { case RequirementReprKind::TypeConstraint: { Type subject = resolution->resolveType(reqRepr.getSubjectRepr()); diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 8bc5cb92d1755..0fe8b0966e481 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1852,6 +1852,8 @@ namespace { TypeResolutionOptions options); NeverNullType resolveCompositionType(CompositionTypeRepr *repr, TypeResolutionOptions options); + NeverNullType resolveExistentialType(ExistentialTypeRepr *repr, + TypeResolutionOptions options); NeverNullType resolveMetatypeType(MetatypeTypeRepr *repr, TypeResolutionOptions options); NeverNullType resolveProtocolType(ProtocolTypeRepr *repr, @@ -1947,7 +1949,8 @@ NeverNullType TypeResolver::resolveType(TypeRepr *repr, // Strip the "is function input" bits unless this is a type that knows about // them. - if (!isa(repr) && !isa(repr) && + if (options.is(TypeResolverContext::FunctionInput) && + !isa(repr) && !isa(repr) && !isa(repr) && !isa(repr) && !isa(repr) && !isa(repr)) { @@ -2058,6 +2061,16 @@ NeverNullType TypeResolver::resolveType(TypeRepr *repr, : ErrorType::get(getASTContext()); } + case TypeReprKind::Existential: { + if (!getASTContext().LangOpts.EnableExplicitExistentialTypes && + !(options & TypeResolutionFlags::SilenceErrors)) { + diagnose(repr->getLoc(), diag::explicit_existential_not_supported); + } + + auto *existential = cast(repr); + return resolveExistentialType(existential, options); + } + case TypeReprKind::NamedOpaqueReturn: return resolveType(cast(repr)->getBase(), options); @@ -3369,6 +3382,15 @@ TypeResolver::resolveIdentifierType(IdentTypeRepr *IdType, return ErrorType::get(getASTContext()); } + // FIXME: Don't use ExistentialType for AnyObject for now. + bool isConstraintType = (result->is() && + !result->isAnyObject()); + if (isConstraintType && + getASTContext().LangOpts.EnableExplicitExistentialTypes && + options.isConstraintImplicitExistential()) { + return ExistentialType::get(result); + } + // Hack to apply context-specific @escaping to a typealias with an underlying // function type. if (result->is()) @@ -3548,6 +3570,9 @@ NeverNullType TypeResolver::resolveImplicitlyUnwrappedOptionalType( case TypeResolverContext::TypeAliasDecl: case TypeResolverContext::GenericTypeAliasDecl: case TypeResolverContext::GenericRequirement: + case TypeResolverContext::SameTypeRequirement: + case TypeResolverContext::ProtocolMetatypeBase: + case TypeResolverContext::MetatypeBase: case TypeResolverContext::ImmediateOptionalTypeArgument: case TypeResolverContext::InExpression: case TypeResolverContext::EditorPlaceholderExpr: @@ -3690,7 +3715,8 @@ TypeResolver::resolveCompositionType(CompositionTypeRepr *repr, }; for (auto tyR : repr->getTypes()) { - auto ty = resolveType(tyR, options.withoutContext()); + auto ty = resolveType(tyR, + options.withContext(TypeResolverContext::GenericRequirement)); if (ty->hasError()) return ty; auto nominalDecl = ty->getAnyNominal(); @@ -3727,14 +3753,51 @@ TypeResolver::resolveCompositionType(CompositionTypeRepr *repr, // In user-written types, AnyObject constraints always refer to the // AnyObject type in the standard library. - return ProtocolCompositionType::get(getASTContext(), Members, - /*HasExplicitAnyObject=*/false); + auto composition = + ProtocolCompositionType::get(getASTContext(), Members, + /*HasExplicitAnyObject=*/false); + if (getASTContext().LangOpts.EnableExplicitExistentialTypes && + options.isConstraintImplicitExistential() && + !composition->isAny()) { + composition = ExistentialType::get(composition); + } + return composition; +} + +NeverNullType +TypeResolver::resolveExistentialType(ExistentialTypeRepr *repr, + TypeResolutionOptions options) { + auto constraintType = resolveType(repr->getConstraint(), + options.withContext(TypeResolverContext::GenericRequirement)); + if (constraintType->is()) + return constraintType; + + auto anyStart = repr->getAnyLoc(); + auto anyEnd = Lexer::getLocForEndOfToken(getASTContext().SourceMgr, anyStart); + if (!constraintType->isExistentialType()) { + diagnose(repr->getLoc(), diag::any_not_existential, + constraintType->isTypeParameter(), + constraintType) + .fixItRemove({anyStart, anyEnd}); + return constraintType; + } + + // Warn about `any Any` and `any AnyObject`. + if (constraintType->isAny() || constraintType->isAnyObject()) { + diagnose(repr->getLoc(), diag::unnecessary_any, + constraintType) + .fixItRemove({anyStart, anyEnd}); + return constraintType; + } + + return ExistentialType::get(constraintType); } NeverNullType TypeResolver::resolveMetatypeType(MetatypeTypeRepr *repr, TypeResolutionOptions options) { // The instance type of a metatype is always abstract, not SIL-lowered. - auto ty = resolveType(repr->getBase(), options.withoutContext()); + auto ty = resolveType(repr->getBase(), + options.withContext(TypeResolverContext::MetatypeBase)); if (ty->hasError()) { return ErrorType::get(getASTContext()); } @@ -3755,7 +3818,8 @@ NeverNullType TypeResolver::resolveMetatypeType(MetatypeTypeRepr *repr, NeverNullType TypeResolver::buildMetatypeType(MetatypeTypeRepr *repr, Type instanceType, Optional storedRepr) { - if (instanceType->isAnyExistentialType()) { + if (instanceType->isAnyExistentialType() && + !instanceType->is()) { // TODO: diagnose invalid representations? return ExistentialMetatypeType::get(instanceType, storedRepr); } else { @@ -3766,7 +3830,8 @@ TypeResolver::buildMetatypeType(MetatypeTypeRepr *repr, Type instanceType, NeverNullType TypeResolver::resolveProtocolType(ProtocolTypeRepr *repr, TypeResolutionOptions options) { // The instance type of a metatype is always abstract, not SIL-lowered. - auto ty = resolveType(repr->getBase(), options.withoutContext()); + auto ty = resolveType(repr->getBase(), + options.withContext(TypeResolverContext::ProtocolMetatypeBase)); if (ty->hasError()) { return ErrorType::get(getASTContext()); } @@ -3881,6 +3946,161 @@ Type TypeChecker::substMemberTypeWithBase(ModuleDecl *module, return resultType; } +namespace { + +class ExistentialTypeVisitor + : public TypeReprVisitor, public ASTWalker +{ + ASTContext &Ctx; + bool checkStatements; + bool hitTopStmt; + +public: + ExistentialTypeVisitor(ASTContext &ctx, bool checkStatements) + : Ctx(ctx), checkStatements(checkStatements), hitTopStmt(false) { } + + bool walkToTypeReprPre(TypeRepr *T) override { + if (T->isInvalid()) + return false; + if (auto compound = dyn_cast(T)) { + // Only visit the last component to check, because nested typealiases in + // existentials are okay. + visit(compound->getComponentRange().back()); + return false; + } + // Arbitrary protocol constraints are OK on opaque types. + if (isa(T)) + return false; + + // Arbitrary protocol constraints are okay for 'any' types. + if (isa(T)) + return false; + + visit(T); + return true; + } + + std::pair walkToStmtPre(Stmt *S) override { + if (checkStatements && !hitTopStmt) { + hitTopStmt = true; + return { true, S }; + } + + return { false, S }; + } + + bool walkToDeclPre(Decl *D) override { + return !checkStatements; + } + + void visitTypeRepr(TypeRepr *T) { + // Do nothing for all TypeReprs except the ones listed below. + } + + void visitIdentTypeRepr(IdentTypeRepr *T) { + if (T->isInvalid() || !Ctx.LangOpts.EnableExplicitExistentialTypes) + return; + + auto comp = T->getComponentRange().back(); + if (auto *proto = dyn_cast_or_null(comp->getBoundDecl())) { + if (proto->existentialRequiresAny()) { + Ctx.Diags.diagnose(comp->getNameLoc(), + diag::existential_requires_any, + proto->getName()); + } + } else if (auto *alias = dyn_cast_or_null(comp->getBoundDecl())) { + auto type = Type(alias->getDeclaredInterfaceType()->getDesugaredType()); + type.findIf([&](Type type) -> bool { + if (T->isInvalid()) + return false; + if (type->isExistentialType()) { + auto layout = type->getExistentialLayout(); + for (auto *proto : layout.getProtocols()) { + auto *protoDecl = proto->getDecl(); + if (!protoDecl->existentialRequiresAny()) + continue; + + Ctx.Diags.diagnose(comp->getNameLoc(), + diag::existential_requires_any, + protoDecl->getName()); + } + } + return false; + }); + } + } + + void visitRequirements(ArrayRef reqts) { + for (auto reqt : reqts) { + if (reqt.getKind() == RequirementReprKind::SameType) { + if (auto *repr = reqt.getFirstTypeRepr()) + repr->walk(*this); + if (auto *repr = reqt.getSecondTypeRepr()) + repr->walk(*this); + } + } + } +}; + +} // end anonymous namespace + +void TypeChecker::checkExistentialTypes(Decl *decl) { + if (!decl || decl->isInvalid()) + return; + + auto &ctx = decl->getASTContext(); + if (auto *protocolDecl = dyn_cast(decl)) { + checkExistentialTypes(ctx, protocolDecl->getTrailingWhereClause()); + } else if (auto *genericDecl = dyn_cast(decl)) { + checkExistentialTypes(ctx, genericDecl->getGenericParams()); + checkExistentialTypes(ctx, genericDecl->getTrailingWhereClause()); + } else if (auto *assocType = dyn_cast(decl)) { + checkExistentialTypes(ctx, assocType->getTrailingWhereClause()); + } else if (auto *extDecl = dyn_cast(decl)) { + checkExistentialTypes(ctx, extDecl->getTrailingWhereClause()); + } else if (auto *subscriptDecl = dyn_cast(decl)) { + checkExistentialTypes(ctx, subscriptDecl->getGenericParams()); + checkExistentialTypes(ctx, subscriptDecl->getTrailingWhereClause()); + } else if (auto *funcDecl = dyn_cast(decl)) { + if (!isa(funcDecl)) { + checkExistentialTypes(ctx, funcDecl->getGenericParams()); + checkExistentialTypes(ctx, funcDecl->getTrailingWhereClause()); + } + } + + if (isa(decl) || isa(decl)) + return; + + ExistentialTypeVisitor visitor(ctx, /*checkStatements=*/false); + decl->walk(visitor); +} + +void TypeChecker::checkExistentialTypes(ASTContext &ctx, Stmt *stmt) { + if (!stmt) + return; + + ExistentialTypeVisitor visitor(ctx, /*checkStatements=*/true); + stmt->walk(visitor); +} + +void TypeChecker::checkExistentialTypes( + ASTContext &ctx, TrailingWhereClause *whereClause) { + if (whereClause == nullptr) + return; + + ExistentialTypeVisitor visitor(ctx, /*checkStatements=*/false); + visitor.visitRequirements(whereClause->getRequirements()); +} + +void TypeChecker::checkExistentialTypes( + ASTContext &ctx, GenericParamList *genericParams) { + if (genericParams == nullptr) + return; + + ExistentialTypeVisitor visitor(ctx, /*checkStatements=*/false); + visitor.visitRequirements(genericParams->getRequirements()); +} + Type CustomAttrTypeRequest::evaluate(Evaluator &eval, CustomAttr *attr, DeclContext *dc, CustomAttrTypeKind typeKind) const { diff --git a/lib/Sema/TypeCheckType.h b/lib/Sema/TypeCheckType.h index f5c9ea23a1709..a34aecf381db1 100644 --- a/lib/Sema/TypeCheckType.h +++ b/lib/Sema/TypeCheckType.h @@ -125,6 +125,16 @@ enum class TypeResolverContext : uint8_t { /// Whether we are in a requirement of a generic declaration GenericRequirement, + /// Whether we are in a same-type requirement of a generic + /// declaration. + SameTypeRequirement, + + /// Whether this is the base type of .Protocol + ProtocolMetatypeBase, + + /// Whether this is the base type of .Type + MetatypeBase, + /// Whether we are in a type argument for an optional ImmediateOptionalTypeArgument, @@ -215,6 +225,9 @@ class TypeResolutionOptions { case Context::TypeAliasDecl: case Context::GenericTypeAliasDecl: case Context::GenericRequirement: + case Context::SameTypeRequirement: + case Context::ProtocolMetatypeBase: + case Context::MetatypeBase: case Context::ImmediateOptionalTypeArgument: case Context::AbstractFunctionDecl: case Context::Inherited: @@ -224,6 +237,40 @@ class TypeResolutionOptions { llvm_unreachable("unhandled kind"); } + /// Whether a generic constraint type is implicitly an + /// existential type in this context. + bool isConstraintImplicitExistential() const { + switch (context) { + case Context::Inherited: + case Context::ExtensionBinding: + case Context::TypeAliasDecl: + case Context::GenericTypeAliasDecl: + case Context::GenericRequirement: + case Context::MetatypeBase: + return false; + case Context::None: + case Context::InExpression: + case Context::ExplicitCastExpr: + case Context::ForEachStmt: + case Context::PatternBindingDecl: + case Context::EditorPlaceholderExpr: + case Context::ClosureExpr: + case Context::FunctionInput: + case Context::VariadicFunctionInput: + case Context::InoutFunctionInput: + case Context::FunctionResult: + case Context::SubscriptDecl: + case Context::EnumElementDecl: + case Context::EnumPatternPayload: + case Context::SameTypeRequirement: + case Context::ProtocolMetatypeBase: + case Context::ImmediateOptionalTypeArgument: + case Context::AbstractFunctionDecl: + case Context::CustomAttr: + return true; + } + } + /// Determine whether all of the given options are set. bool contains(TypeResolutionFlags set) const { return !static_cast(unsigned(set) & ~unsigned(flags)); @@ -276,6 +323,13 @@ class TypeResolutionOptions { if (!preserveSIL) copy -= TypeResolutionFlags::SILType; return copy; } + + inline + TypeResolutionOptions withContext(TypeResolverContext context) const { + auto copy = *this; + copy.setContext(context); + return copy; + } }; /// A function reference used to "open" the given unbound generic type diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 057a2f859f032..7b0cc926cff71 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -245,6 +245,22 @@ Type getOptionalType(SourceLoc loc, Type elementType); Expr *resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *Context, bool replaceInvalidRefsWithErrors); +/// Check for invalid existential types in the given declaration. +void checkExistentialTypes(Decl *decl); + +/// Check for invalid existential types in the given statement. +void checkExistentialTypes(ASTContext &ctx, Stmt *stmt); + +/// Check for invalid existential types in the given generic requirement +/// list. +void checkExistentialTypes(ASTContext &ctx, + TrailingWhereClause *whereClause); + +/// Check for invalid existential types in the given generic requirement +/// list. +void checkExistentialTypes(ASTContext &ctx, + GenericParamList *genericParams); + /// Substitute the given base type into the type of the given nested type, /// producing the effective type that the nested type will have. /// diff --git a/lib/Serialization/DeclTypeRecordNodes.def b/lib/Serialization/DeclTypeRecordNodes.def index 52744dbc6944e..911b31048f13c 100644 --- a/lib/Serialization/DeclTypeRecordNodes.def +++ b/lib/Serialization/DeclTypeRecordNodes.def @@ -94,6 +94,7 @@ TYPE(OPAQUE_ARCHETYPE) TYPE(NESTED_ARCHETYPE) TYPE(SEQUENCE_ARCHETYPE) TYPE(PROTOCOL_COMPOSITION) +TYPE(EXISTENTIAL) TYPE(BOUND_GENERIC) TYPE(GENERIC_FUNCTION) diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index f2c70d45267f6..2dbc332c86c2f 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -3564,13 +3564,14 @@ class DeclDeserializer { StringRef blobData) { IdentifierID nameID; DeclContextID contextID; - bool isImplicit, isClassBounded, isObjC; + bool isImplicit, isClassBounded, isObjC, existentialRequiresAny; uint8_t rawAccessLevel; unsigned numInheritedTypes; ArrayRef rawInheritedAndDependencyIDs; decls_block::ProtocolLayout::readRecord(scratch, nameID, contextID, isImplicit, isClassBounded, isObjC, + existentialRequiresAny, rawAccessLevel, numInheritedTypes, rawInheritedAndDependencyIDs); @@ -3596,6 +3597,8 @@ class DeclDeserializer { ctx.evaluator.cacheOutput(ProtocolRequiresClassRequest{proto}, std::move(isClassBounded)); + ctx.evaluator.cacheOutput(ExistentialRequiresAnyRequest{proto}, + std::move(existentialRequiresAny)); if (auto accessLevel = getActualAccessLevel(rawAccessLevel)) proto->setAccess(*accessLevel); @@ -5606,6 +5609,18 @@ class TypeDeserializer { return ProtocolCompositionType::get(ctx, protocols, hasExplicitAnyObject); } + Expected deserializeExistentialType(ArrayRef scratch, + StringRef blobData) { + TypeID constraintID; + decls_block::ExistentialTypeLayout::readRecord(scratch, constraintID); + + auto constraintType = MF.getTypeChecked(constraintID); + if (!constraintType) + return constraintType.takeError(); + + return ExistentialType::get(constraintType.get()); + } + Expected deserializeDependentMemberType(ArrayRef scratch, StringRef blobData) { TypeID baseID; diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 4a03d407dd11c..451cc8f30a68e 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -56,7 +56,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 649; // _unavailableFromAsync message +const uint16_t SWIFTMODULE_VERSION_MINOR = 651; // existential requires any /// A standard hash seed used for all string hashes in a serialized module. /// @@ -1184,6 +1184,8 @@ namespace decls_block { using ArraySliceTypeLayout = SyntaxSugarTypeLayout; using OptionalTypeLayout = SyntaxSugarTypeLayout; using VariadicSequenceTypeLayout = SyntaxSugarTypeLayout; + using ExistentialTypeLayout = + SyntaxSugarTypeLayout; using DictionaryTypeLayout = BCRecordLayout< DICTIONARY_TYPE, @@ -1290,6 +1292,7 @@ namespace decls_block { BCFixed<1>, // implicit flag BCFixed<1>, // class-bounded? BCFixed<1>, // objc? + BCFixed<1>, // existential-type-supported? AccessLevelField, // access level BCVBR<4>, // number of inherited types BCArray // inherited types, followed by dependency types diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 22fb26c451eb2..01506ff042718 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3630,6 +3630,7 @@ class Serializer::DeclSerializer : public DeclVisitor { const_cast(proto) ->requiresClass(), proto->isObjC(), + proto->existentialRequiresAny(), rawAccessLevel, numInherited, inheritedAndDependencyTypes); @@ -4706,6 +4707,12 @@ class Serializer::TypeSerializer : public TypeVisitor { protocols); } + void + visitExistentialType(const ExistentialType *existential) { + using namespace decls_block; + serializeSimpleWrapper(existential->getConstraintType()); + } + void visitReferenceStorageType(const ReferenceStorageType *refTy) { using namespace decls_block; unsigned abbrCode = S.DeclTypeAbbrCodes[ReferenceStorageTypeLayout::Code]; @@ -4882,6 +4889,7 @@ void Serializer::writeAllDeclsAndTypes() { registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); + registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); diff --git a/test/TypeDecoder/explicit_existentials.swift b/test/TypeDecoder/explicit_existentials.swift new file mode 100644 index 0000000000000..8fd42ae67bdd4 --- /dev/null +++ b/test/TypeDecoder/explicit_existentials.swift @@ -0,0 +1,112 @@ +// RUN: %empty-directory(%t) + +// RUN: %target-build-swift -Xfrontend -enable-explicit-existential-types -emit-executable %s -g -o %t/existentials -emit-module +// RUN: sed -ne '/\/\/ *DEMANGLE: /s/\/\/ *DEMANGLE: *//p' < %s > %t/input +// RUN: %lldb-moduleimport-test %t/existentials -type-from-mangled=%t/input | %FileCheck %s + +func blackHole(_: Any...) {} + +protocol P {} +protocol Q {} +class C {} + +class D : C, P, Q {} + +do { + let e0: Any = D() + let e1: AnyObject = D() + + let e2: P = D() + let e4: P & C = D() + let e3: P & AnyObject = D() + + let e5: P & Q = D() + let e6: P & Q & C = D() + let e7: P & Q & AnyObject = D() + + blackHole(e0, e1, e2, e3, e4, e5, e6, e7) +} + +do { + let e0: Any.Type = D.self + let e1: AnyObject.Type = D.self + + let e2: P.Type = D.self + let e4: (P & C).Type = D.self + let e3: (P & AnyObject).Type = D.self + + let e5: (P & Q).Type = D.self + let e6: (P & Q & C).Type = D.self + let e7: (P & Q & AnyObject).Type = D.self + + blackHole(e0, e1, e2, e3, e4, e5, e6, e7) +} + +do { + let e0: Any.Protocol = Any.self + let e1: AnyObject.Protocol = AnyObject.self + + let e2: P.Protocol = P.self + let e4: (P & C).Protocol = (P & C).self + let e3: (P & AnyObject).Protocol = (P & AnyObject).self + + let e5: (P & Q).Protocol = (P & Q).self + let e6: (P & Q & C).Protocol = (P & Q & C).self + let e7: (P & Q & AnyObject).Protocol = (P & Q & AnyObject).self + + blackHole(e0, e1, e2, e3, e4, e5, e6, e7) +} + +// DEMANGLE: $sypD +// DEMANGLE: $syXlD +// DEMANGLE: $s12existentials1P_pD +// DEMANGLE: $s12existentials1P_AA1CCXcD +// DEMANGLE: $s12existentials1P_XlD +// DEMANGLE: $s12existentials1P_AA1QpD +// DEMANGLE: $s12existentials1P_AA1QAA1CCXcD +// DEMANGLE: $s12existentials1P_AA1QXlD + +// CHECK: Any +// CHECK: AnyObject +// CHECK: P +// CHECK: C & P +// CHECK: P & AnyObject +// CHECK: P & Q +// CHECK: C & P & Q +// CHECK: P & Q & AnyObject + +// DEMANGLE: $sypXpD +// DEMANGLE: $syXlXpD +// DEMANGLE: $s12existentials1P_pXpD +// DEMANGLE: $s12existentials1P_XlXpD +// DEMANGLE: $s12existentials1P_AA1CCXcXpD +// DEMANGLE: $s12existentials1P_AA1QpXpD +// DEMANGLE: $s12existentials1P_AA1QAA1CCXcXpD +// DEMANGLE: $s12existentials1P_AA1QXlXpD + +// CHECK: Any.Type +// CHECK: AnyObject.Type +// CHECK: P.Type +// CHECK: (P & AnyObject).Type +// CHECK: (C & P).Type +// CHECK: (P & Q).Type +// CHECK: (C & P & Q).Type +// CHECK: (P & Q & AnyObject).Type + +// DEMANGLE: $sypmD +// DEMANGLE: $syXlmD +// DEMANGLE: $s12existentials1P_pmD +// DEMANGLE: $s12existentials1P_AA1CCXcmD +// DEMANGLE: $s12existentials1P_XlmD +// DEMANGLE: $s12existentials1P_AA1QpmD +// DEMANGLE: $s12existentials1P_AA1QAA1CCXcmD +// DEMANGLE: $s12existentials1P_AA1QXlmD + +// CHECK: Any.Protocol +// CHECK: AnyObject.Protocol +// CHECK: P.Protocol +// CHECK: (C & P).Protocol +// CHECK: (P & AnyObject).Protocol +// CHECK: (P & Q).Protocol +// CHECK: (C & P & Q).Protocol +// CHECK: (P & Q & AnyObject).Protocol diff --git a/test/type/explicit_existential.swift b/test/type/explicit_existential.swift new file mode 100644 index 0000000000000..b19a802007686 --- /dev/null +++ b/test/type/explicit_existential.swift @@ -0,0 +1,164 @@ +// RUN: %target-typecheck-verify-swift -enable-explicit-existential-types + +protocol HasSelfRequirements { + func foo(_ x: Self) + + func returnsOwnProtocol() -> any HasSelfRequirements +} +protocol Bar { + init() + + func bar() -> any Bar +} + +func useBarAsType(_ x: any Bar) {} + +protocol Pub : Bar { } + +func refinementErasure(_ p: any Pub) { + useBarAsType(p) +} + +typealias Compo = HasSelfRequirements & Bar + +struct CompoAssocType { + typealias Compo = HasSelfRequirements & Bar +} + +func useAsRequirement(_ x: T) { } +func useCompoAsRequirement(_ x: T) { } +func useCompoAliasAsRequirement(_ x: T) { } +func useNestedCompoAliasAsRequirement(_ x: T) { } + +func useAsWhereRequirement(_ x: T) where T: HasSelfRequirements {} +func useCompoAsWhereRequirement(_ x: T) where T: HasSelfRequirements & Bar {} +func useCompoAliasAsWhereRequirement(_ x: T) where T: Compo {} +func useNestedCompoAliasAsWhereRequirement(_ x: T) where T: CompoAssocType.Compo {} + +func useAsType(_: any HasSelfRequirements, + _: any HasSelfRequirements & Bar, + _: any Compo, + _: any CompoAssocType.Compo) { } + +struct TypeRequirement {} +struct CompoTypeRequirement {} +struct CompoAliasTypeRequirement {} +struct NestedCompoAliasTypeRequirement {} + +struct CompoTypeWhereRequirement where T: HasSelfRequirements & Bar {} +struct CompoAliasTypeWhereRequirement where T: Compo {} +struct NestedCompoAliasTypeWhereRequirement where T: CompoAssocType.Compo {} + +struct Struct1 { } + +typealias T1 = Pub & Bar +typealias T2 = any Pub & Bar + +protocol HasAssoc { + associatedtype Assoc + func foo() +} + +do { + enum MyError: Error { + case bad(Any) + } + + func checkIt(_ js: Any) throws { + switch js { + case let dbl as any HasAssoc: + throw MyError.bad(dbl) + + default: + fatalError("wrong") + } + } +} + +func testHasAssoc(_ x: Any, _: any HasAssoc) { + if let p = x as? any HasAssoc { + p.foo() + } + + struct ConformingType : HasAssoc { + typealias Assoc = Int + func foo() {} + + func method() -> any HasAssoc {} + } +} + +var b: any HasAssoc + +protocol P {} +typealias MoreHasAssoc = HasAssoc & P +func testHasMoreAssoc(_ x: Any) { + if let p = x as? any MoreHasAssoc { + p.foo() + } +} + +typealias X = Struct1 +_ = Struct1.self + +typealias AliasWhere = T +where T: HasAssoc, T.Assoc == any HasAssoc + +struct StructWhere +where T: HasAssoc, + T.Assoc == any HasAssoc {} + +protocol ProtocolWhere where T == any HasAssoc { + associatedtype T + + associatedtype U: HasAssoc + where U.Assoc == any HasAssoc +} + +extension HasAssoc where Assoc == any HasAssoc {} + +func FunctionWhere(_: T) +where T : HasAssoc, + T.Assoc == any HasAssoc {} + +struct SubscriptWhere { + subscript(_: T) -> Int + where T : HasAssoc, + T.Assoc == any HasAssoc { + get {} + set {} + } +} + +struct OuterGeneric { + func contextuallyGenericMethod() where T == any HasAssoc {} +} + +func testInvalidAny() { + struct S: HasAssoc { + typealias Assoc = Int + func foo() {} + } + let _: any S = S() // expected-error{{'any' has no effect on concrete type 'S'}} + + func generic(t: T) { + let _: any T = t // expected-error{{'any' has no effect on type parameter 'T'}} + let _: any T.Assoc // expected-error {{'any' has no effect on type parameter 'T.Assoc'}} + } + + let _: any ((S) -> Void) = generic // expected-error{{'any' has no effect on concrete type '(S) -> Void'}} +} + +func testRedundantAnyWarning() { + let _: any Any // expected-warning {{'any' is redundant on type 'Any'}} + let _: any AnyObject // expected-warning {{'any' is redundant on type 'AnyObject'}} +} + +protocol P1 {} +protocol P2 {} +struct ConcreteComposition: P1, P2 {} + +func testMetatypes() { + let _: any P1.Type = ConcreteComposition.self + let _: any (P1 & P2).Type = ConcreteComposition.self +}