diff --git a/include/swift/AST/ActorIsolation.h b/include/swift/AST/ActorIsolation.h index e78397d8e4b0a..ff65568756f23 100644 --- a/include/swift/AST/ActorIsolation.h +++ b/include/swift/AST/ActorIsolation.h @@ -39,9 +39,6 @@ class AbstractClosureExpr; /// to avoid having to include Types.h. bool areTypesEqual(Type type1, Type type2); -/// Determine whether the given type is suitable as a concurrent value type. -bool isSendableType(ModuleDecl *module, Type type); - /// Determines if the 'let' can be read from anywhere within the given module, /// regardless of the isolation or async-ness of the context in which /// the var is read. diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 869fbf3f61a65..e6d77cda21717 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -2829,6 +2829,25 @@ class TypeWitnessRequest void cacheResult(TypeWitnessAndDecl value) const; }; +class ReferencedAssociatedTypesRequest + : public SimpleRequest(ValueDecl *), + RequestFlags::Cached> { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + TinyPtrVector + evaluate(Evaluator &evaluator, ValueDecl *req) const; + +public: + // Caching. + bool isCached() const { return true; } +}; + class ValueWitnessRequest : public SimpleRequest(ValueDecl *), + Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, ValueWitnessRequest, Witness(NormalProtocolConformance *, ValueDecl *), SeparatelyCached, NoLocationInfo) diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 1666a230cccf9..19af7d5c529c9 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -925,11 +925,9 @@ class alignas(1 << TypeAlignInBits) TypeBase /// Determines whether this type is an any actor type. bool isAnyActorType(); - /// Returns true if this type is a Sendable type. - bool isSendableType(DeclContext *declContext); - - /// Returns true if this type is a Sendable type. - bool isSendableType(ModuleDecl *parentModule); + /// Returns true if this type conforms to Sendable, or if its a function type + /// that is @Sendable. + bool isSendableType(); /// Determines whether this type conforms or inherits (if it's a protocol /// type) from `DistributedActor`. diff --git a/include/swift/SIL/SILType.h b/include/swift/SIL/SILType.h index 1416620a0bdfe..fa3b9dbaf4b58 100644 --- a/include/swift/SIL/SILType.h +++ b/include/swift/SIL/SILType.h @@ -891,9 +891,6 @@ class SILType { /// Returns true if this function conforms to the Sendable protocol. bool isSendable(SILFunction *fn) const; - ProtocolConformanceRef conformsToProtocol(SILFunction *fn, - ProtocolDecl *protocol) const; - /// False if SILValues of this type cannot be used outside the scope of their /// lifetime dependence. bool isEscapable() const; diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 3f8b80eb5ebc0..105ac2438f9b3 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -580,12 +580,28 @@ bool TypeBase::isAnyActorType() { return false; } -bool TypeBase::isSendableType(DeclContext *ctx) { - return isSendableType(ctx->getParentModule()); -} +bool TypeBase::isSendableType() { + auto proto = getASTContext().getProtocol(KnownProtocolKind::Sendable); + if (!proto) + return true; + + // First check if we have a function type. If we do, check if it is + // Sendable. We do this since functions cannot conform to protocols. + if (auto *fas = getAs()) + return fas->isSendable(); + if (auto *fas = getAs()) + return fas->isSendable(); -bool TypeBase::isSendableType(ModuleDecl *parentModule) { - return ::isSendableType(parentModule, Type(this)); + auto conformance = proto->getParentModule()->checkConformance(this, proto); + if (conformance.isInvalid()) + return false; + + // Look for missing Sendable conformances. + return !conformance.forEachMissingConformance( + [](BuiltinProtocolConformance *missing) { + return missing->getProtocol()->isSpecificProtocol( + KnownProtocolKind::Sendable); + }); } bool TypeBase::isDistributedActor() { diff --git a/lib/IDE/CompletionLookup.cpp b/lib/IDE/CompletionLookup.cpp index 1fb40e3e41446..4ca0ec4779cb4 100644 --- a/lib/IDE/CompletionLookup.cpp +++ b/lib/IDE/CompletionLookup.cpp @@ -637,6 +637,8 @@ Type CompletionLookup::getTypeOfMember(const ValueDecl *VD, // τ_1_0(U) => U } auto subs = keyPathInfo.baseType->getMemberSubstitutions(SD); + // FIXME: The below should use substitution map substitution. + // If the keyPath result type has type parameters, that might affect the // subscript result type. auto keyPathResultTy = @@ -800,21 +802,20 @@ void CompletionLookup::analyzeActorIsolation( // If the reference is 'async', all types must be 'Sendable'. if (Ctx.LangOpts.StrictConcurrencyLevel >= StrictConcurrency::Complete && implicitlyAsync && T) { - auto *M = CurrDeclContext->getParentModule(); if (isa(VD)) { - if (!isSendableType(M, T)) { + if (!T->isSendableType()) { NotRecommended = ContextualNotRecommendedReason::CrossActorReference; } } else { assert(isa(VD) || isa(VD)); // Check if the result and the param types are all 'Sendable'. auto *AFT = T->castTo(); - if (!isSendableType(M, AFT->getResult())) { + if (!AFT->getResult()->isSendableType()) { NotRecommended = ContextualNotRecommendedReason::CrossActorReference; } else { for (auto ¶m : AFT->getParams()) { Type paramType = param.getPlainType(); - if (!isSendableType(M, paramType)) { + if (!paramType->isSendableType()) { NotRecommended = ContextualNotRecommendedReason::CrossActorReference; break; diff --git a/lib/IDE/IDETypeChecking.cpp b/lib/IDE/IDETypeChecking.cpp index 105a1f96bbef0..3b5c11df2a1d2 100644 --- a/lib/IDE/IDETypeChecking.cpp +++ b/lib/IDE/IDETypeChecking.cpp @@ -52,7 +52,9 @@ swift::getTopLevelDeclsForDisplay(ModuleDecl *M, !accessScope.isPublic() && !accessScope.isPackage()) continue; - (void)swift::isSendableType(M, NTD->getDeclaredInterfaceType()); + auto proto = M->getASTContext().getProtocol(KnownProtocolKind::Sendable); + if (proto) + (void) M->lookupConformance(NTD->getDeclaredInterfaceType(), proto); } } diff --git a/lib/SIL/IR/SILType.cpp b/lib/SIL/IR/SILType.cpp index be029f8424172..8b6bd7e0e60a5 100644 --- a/lib/SIL/IR/SILType.cpp +++ b/lib/SIL/IR/SILType.cpp @@ -1250,11 +1250,6 @@ SILType SILType::removingMoveOnlyWrapperToBoxedType(const SILFunction *fn) { return SILType::getPrimitiveObjectType(newBoxType); } -ProtocolConformanceRef -SILType::conformsToProtocol(SILFunction *fn, ProtocolDecl *protocol) const { - return fn->getParentModule()->checkConformance(getASTType(), protocol); -} - bool SILType::isSendable(SILFunction *fn) const { - return getASTType()->isSendableType(fn->getParentModule()); + return getASTType()->isSendableType(); } diff --git a/lib/SILOptimizer/Mandatory/FlowIsolation.cpp b/lib/SILOptimizer/Mandatory/FlowIsolation.cpp index 3fa995f941372..6c8d76000ab5b 100644 --- a/lib/SILOptimizer/Mandatory/FlowIsolation.cpp +++ b/lib/SILOptimizer/Mandatory/FlowIsolation.cpp @@ -499,7 +499,7 @@ static bool accessIsConcurrencySafe(ModuleDecl *module, // must be accessible from nonisolated and Sendable return isLetAccessibleAnywhere(module, var) - && isSendableType(module, var->getTypeInContext()); + && var->getTypeInContext()->isSendableType(); } /// \returns true iff the ref_element_addr instruction is only used @@ -517,11 +517,10 @@ static bool onlyDeinitAccess(RefElementAddrInst *inst) { /// diagnostic if it is not Sendable. The diagnostic assumes that the access /// is happening in a deinit that uses flow-isolation. /// \returns true iff a diagnostic was emitted for this reference. -static bool diagnoseNonSendableFromDeinit(ModuleDecl *module, - RefElementAddrInst *inst) { +static bool diagnoseNonSendableFromDeinit(RefElementAddrInst *inst) { VarDecl *var = inst->getField(); Type ty = var->getTypeInContext(); - DeclContext* dc = inst->getFunction()->getDeclContext(); + DeclContext *dc = inst->getFunction()->getDeclContext(); // FIXME: we should emit diagnostics in other modes using: // @@ -534,7 +533,7 @@ static bool diagnoseNonSendableFromDeinit(ModuleDecl *module, != StrictConcurrency::Complete) return false; - if (isSendableType(module, ty)) + if (ty->isSendableType()) return false; auto &diag = var->getASTContext().Diags; @@ -657,7 +656,7 @@ void AnalysisInfo::analyze(const SILArgument *selfParam) { continue; // emit a diagnostic and skip if it's non-sendable in a deinit - if (forDeinit && diagnoseNonSendableFromDeinit(module, refInst)) + if (forDeinit && diagnoseNonSendableFromDeinit(refInst)) continue; markPropertyUse(user); diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index 2cca26e6c0435..5a65c2c5c2f0d 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -361,7 +361,7 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl, auto type = var->getTypeInContext(); auto isolation = getActorIsolation(var); if (isolation.isGlobalActor()) { - if (!isSendableType(decl->getModuleContext(), type) || + if (!type->isSendableType() || var->getInitializerIsolation().isGlobalActor()) { // If different isolated stored properties require different // global actors, it is impossible to initialize this type. diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index a5dc2b3b8e597..d484513983007 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -2806,8 +2806,7 @@ ConstraintSystem::getTypeOfMemberReference( FunctionType::ExtInfo info; if (Context.LangOpts.hasFeature(Feature::InferSendableFromCaptures)) { - if (isPartialApplication(locator) && - isSendableType(DC->getParentModule(), baseOpenedTy)) { + if (isPartialApplication(locator) && baseOpenedTy->isSendableType()) { // Add @Sendable to functions without conditional conformances functionType = functionType diff --git a/lib/Sema/IDETypeCheckingRequests.cpp b/lib/Sema/IDETypeCheckingRequests.cpp index 88384cf4fb983..f13b6e853587c 100644 --- a/lib/Sema/IDETypeCheckingRequests.cpp +++ b/lib/Sema/IDETypeCheckingRequests.cpp @@ -161,20 +161,34 @@ static bool isMemberDeclAppliedInternal(const DeclContext *DC, Type BaseTy, const GenericContext *genericDecl = VD->getAsGenericContext(); if (!genericDecl) return true; + + // The declaration may introduce inner generic parameters and requirements, + // or it may be nested in an outer generic context. GenericSignature genericSig = genericDecl->getGenericSignature(); if (!genericSig) return true; + // The context substitution map for the base type fixes the declaration's + // outer generic parameters. auto *module = DC->getParentModule(); - SubstitutionMap substMap = BaseTy->getContextSubstitutionMap( + auto substMap = BaseTy->getContextSubstitutionMap( module, VD->getDeclContext()); - // Note: we treat substitution failure as success, to avoid tripping - // up over generic parameters introduced by the declaration itself. + // The innermost generic parameters are mapped to error types. + unsigned innerDepth = genericSig.getGenericParams().back()->getDepth(); + if (!genericDecl->isGeneric()) + ++innerDepth; + + // We treat substitution failure as success, to ignore requirements + // that involve innermost generic parameters. return checkRequirements(module, genericSig.getRequirements(), - QuerySubstitutionMap{substMap}) != - CheckRequirementsResult::RequirementFailure; + [&](SubstitutableType *type) -> Type { + auto *paramTy = cast(type); + if (paramTy->getDepth() == innerDepth) + return ErrorType::get(DC->getASTContext()); + return Type(paramTy).subst(substMap); + }) != CheckRequirementsResult::RequirementFailure; } bool diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 8063ecfcdf53b..135169d27691c 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -6825,9 +6825,6 @@ void AttributeChecker::visitKnownToBeLocalAttr(KnownToBeLocalAttr *attr) { } void AttributeChecker::visitSendableAttr(SendableAttr *attr) { - - auto dc = D->getDeclContext(); - if ((isa(D) || isa(D)) && !isAsyncDecl(cast(D))) { auto value = cast(D); @@ -6841,8 +6838,8 @@ void AttributeChecker::visitSendableAttr(SendableAttr *attr) { } // Prevent Sendable Attr from being added to methods of non-sendable types if (auto *funcDecl = dyn_cast(D)) { - if (auto selfdecl = funcDecl->getImplicitSelfDecl()) { - if (!isSendableType(dc->getParentModule(), selfdecl->getTypeInContext())) { + if (auto selfDecl = funcDecl->getImplicitSelfDecl()) { + if (!selfDecl->getTypeInContext()->isSendableType()) { diagnose(attr->getLocation(), diag::nonsendable_instance_method) .warnUntilSwiftVersion(6); } diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index 0b30d02c7d7da..a7728c0b1573d 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -683,31 +683,6 @@ static bool isSendableClosure( return false; } -/// Determine whether the given type is suitable as a concurrent value type. -bool swift::isSendableType(ModuleDecl *module, Type type) { - auto proto = module->getASTContext().getProtocol(KnownProtocolKind::Sendable); - if (!proto) - return true; - - // First check if we have a function type. If we do, check if it is - // Sendable. We do this since functions cannot conform to protocols. - if (auto *fas = type->getAs()) - return fas->isSendable(); - if (auto *fas = type->getAs()) - return fas->isSendable(); - - auto conformance = module->checkConformance(type, proto); - if (conformance.isInvalid()) - return false; - - // Look for missing Sendable conformances. - return !conformance.forEachMissingConformance( - [](BuiltinProtocolConformance *missing) { - return missing->getProtocol()->isSpecificProtocol( - KnownProtocolKind::Sendable); - }); -} - /// Add Fix-It text for the given nominal type to adopt Sendable. static void addSendableFixIt( const NominalTypeDecl *nominal, InFlightDiagnostic &diag, bool unchecked) { @@ -4741,8 +4716,7 @@ ActorIsolation ActorIsolationRequest::evaluate( diagVar = originalVar; } if (var->isLet()) { - if (!isSendableType(var->getModuleContext(), - var->getInterfaceType())) { + if (!var->getInterfaceType()->isSendableType()) { diagVar->diagnose(diag::shared_immutable_state_decl, diagVar) .warnUntilSwiftVersion(6); } @@ -6356,7 +6330,7 @@ ActorReferenceResult ActorReferenceResult::forReference( (!actorInstance || actorInstance->isSelf())) { auto type = fromDC->mapTypeIntoContext(declRef.getDecl()->getInterfaceType()); - if (!isSendableType(fromDC->getParentModule(), type)) { + if (!type->isSendableType()) { // Treat the decl isolation as 'preconcurrency' to downgrade violations // to warnings, because violating Sendable here is accepted by the // Swift 5.9 compiler. diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index a291fb572d1bb..ab41da9255e30 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -1653,7 +1653,7 @@ static void diagnoseRetroactiveConformances( proto->walkInheritedProtocols([&](ProtocolDecl *decl) { // Get the original conformance of the extended type to this protocol. - auto conformanceRef = ext->getParentModule()->checkConformance( + auto conformanceRef = ext->getParentModule()->lookupConformance( extendedType, decl); if (!conformanceRef.isConcrete()) { diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index f7b77c57c5829..a4d29c677d28a 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -1359,9 +1359,9 @@ WitnessChecker::WitnessChecker(ASTContext &ctx, ProtocolDecl *proto, Type adoptee, DeclContext *dc) : Context(ctx), Proto(proto), Adoptee(adoptee), DC(dc) {} -void -WitnessChecker::lookupValueWitnessesViaImplementsAttr( - ValueDecl *req, SmallVector &witnesses) { +static void +lookupValueWitnessesViaImplementsAttr( + DeclContext *DC, ValueDecl *req, SmallVector &witnesses) { auto name = req->createNameRef(); auto *nominal = DC->getSelfNominalTypeDecl(); @@ -1411,7 +1411,7 @@ static bool contextMayExpandOperator( } SmallVector -WitnessChecker::lookupValueWitnesses(ValueDecl *req, bool *ignoringNames) { +swift::lookupValueWitnesses(DeclContext *DC, ValueDecl *req, bool *ignoringNames) { assert(!isa(req) && "Not for lookup for type witnesses*"); assert(req->isProtocolRequirement()); @@ -1419,7 +1419,7 @@ WitnessChecker::lookupValueWitnesses(ValueDecl *req, bool *ignoringNames) { // Do an initial check to see if there are any @_implements remappings // for this requirement. - lookupValueWitnessesViaImplementsAttr(req, witnesses); + lookupValueWitnessesViaImplementsAttr(DC, req, witnesses); auto reqName = req->createNameRef(); auto reqBaseName = reqName.withoutArgumentLabels(); @@ -1441,7 +1441,7 @@ WitnessChecker::lookupValueWitnesses(ValueDecl *req, bool *ignoringNames) { for (auto candidate : lookup) { auto decl = candidate.getValueDecl(); if (!isa(decl->getDeclContext()) && - swift::isMemberOperator(cast(decl), Adoptee)) { + swift::isMemberOperator(cast(decl), DC->getSelfInterfaceType())) { witnesses.push_back(decl); } } @@ -1515,7 +1515,7 @@ bool WitnessChecker::findBestWitness( SmallVector witnesses; switch (attempt) { case Regular: - witnesses = lookupValueWitnesses(requirement, ignoringNames); + witnesses = lookupValueWitnesses(DC, requirement, ignoringNames); break; case OperatorsFromOverlay: { // If we have a Clang declaration, the matching operator might be in the @@ -2924,29 +2924,26 @@ ConformanceChecker::~ConformanceChecker() { !getASTContext().hasDelayedConformanceErrors(Conformance)); } -ArrayRef -ConformanceChecker::getReferencedAssociatedTypes(ValueDecl *req) { - // Check whether we've already cached this information. - auto known = ReferencedAssociatedTypes.find(req); - if (known != ReferencedAssociatedTypes.end()) - return known->second; +TinyPtrVector +ReferencedAssociatedTypesRequest::evaluate(Evaluator &eval, + ValueDecl *req) const { // Collect the set of associated types rooted on Self in the // signature. Note that for references to nested types, we only // want to consider the outermost dependent member type. // // For example, a requirement typed '(Iterator.Element) -> ()' // is not considered to reference the associated type 'Iterator'. - auto &assocTypes = ReferencedAssociatedTypes[req]; + TinyPtrVector assocTypes; class Walker : public TypeWalker { ProtocolDecl *Proto; - llvm::SmallVectorImpl &assocTypes; + llvm::TinyPtrVector &assocTypes; llvm::SmallPtrSet knownAssocTypes; public: Walker(ProtocolDecl *Proto, - llvm::SmallVectorImpl &assocTypes) + llvm::TinyPtrVector &assocTypes) : Proto(Proto), assocTypes(assocTypes) {} Action walkToTypePre(Type type) override { @@ -2963,7 +2960,7 @@ ConformanceChecker::getReferencedAssociatedTypes(ValueDecl *req) { } }; - Walker walker(Proto, assocTypes); + Walker walker(cast(req->getDeclContext()), assocTypes); // This dance below is to avoid calling getCanonicalType() on a // GenericFunctionType, which creates a GenericSignatureBuilder, which @@ -4301,7 +4298,10 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) { // If any of the type witnesses was erroneous, don't bother to check // this value witness: it will fail. - for (auto assocType : getReferencedAssociatedTypes(requirement)) { + auto referenced = evaluateOrDefault(getASTContext().evaluator, + ReferencedAssociatedTypesRequest{requirement}, + TinyPtrVector()); + for (auto assocType : referenced) { if (Conformance->getTypeWitness(assocType)->hasError()) { return ResolveWitnessResult::ExplicitFailed; } diff --git a/lib/Sema/TypeCheckProtocol.h b/lib/Sema/TypeCheckProtocol.h index be298e23f41bf..19cb6dbe54514 100644 --- a/lib/Sema/TypeCheckProtocol.h +++ b/lib/Sema/TypeCheckProtocol.h @@ -636,6 +636,19 @@ struct RequirementMatch { swift::Witness getWitness(ASTContext &ctx) const; }; +/// Gather the value witnesses for the given requirement. +/// +/// \param DC A nominal type or extension context where the conformance +/// was declared. +/// \param req A member of a protocol that DC conforms to. +/// \param ignoringNames If non-null and there are no value +/// witnesses with the correct full name, the results will reflect +/// lookup for just the base name and the pointee will be set to +/// \c true. +SmallVector lookupValueWitnesses(DeclContext *DC, + ValueDecl *req, + bool *ignoringNames); + struct RequirementCheck; class WitnessChecker { @@ -676,15 +689,6 @@ class WitnessChecker { return RequiredAccessScopeAndUsableFromInline.value().second; } - /// Gather the value witnesses for the given requirement. - /// - /// \param ignoringNames If non-null and there are no value - /// witnesses with the correct full name, the results will reflect - /// lookup for just the base name and the pointee will be set to - /// \c true. - SmallVector lookupValueWitnesses(ValueDecl *req, - bool *ignoringNames); - void lookupValueWitnessesViaImplementsAttr(ValueDecl *req, SmallVector &witnesses); @@ -774,11 +778,6 @@ class ConformanceChecker : public WitnessChecker { /// Witnesses that are currently being resolved. llvm::SmallPtrSet ResolvingWitnesses; - /// Caches the set of associated types that are referenced in each - /// requirement. - llvm::DenseMap> - ReferencedAssociatedTypes; - /// Keep track of missing witnesses, either type or value, for later /// diagnosis emits. This may contain witnesses that are external to the /// protocol under checking. @@ -804,10 +803,6 @@ class ConformanceChecker : public WitnessChecker { /// Whether objcMethodRequirements has been computed. bool computedObjCMethodRequirements = false; - /// Retrieve the associated types that are referenced by the given - /// requirement with a base of 'Self'. - ArrayRef getReferencedAssociatedTypes(ValueDecl *req); - /// Record a (non-type) witness for the given requirement. void recordWitness(ValueDecl *requirement, const RequirementMatch &match); @@ -1132,13 +1127,11 @@ class AssociatedTypeInference { /// Infer associated type witnesses for the given value requirement. InferredAssociatedTypesByWitnesses inferTypeWitnessesViaValueWitnesses( - ConformanceChecker &checker, const llvm::SetVector &allUnresolved, ValueDecl *req); /// Infer associated type witnesses for the given associated type. InferredAssociatedTypesByWitnesses inferTypeWitnessesViaAssociatedType( - ConformanceChecker &checker, const llvm::SetVector &allUnresolved, AssociatedTypeDecl *assocType); @@ -1147,7 +1140,6 @@ class AssociatedTypeInference { /// \param assocTypes The set of associated types we're interested in. InferredAssociatedTypes inferTypeWitnessesViaValueWitnesses( - ConformanceChecker &checker, const llvm::SetVector &assocTypes); /// Compute a "fixed" type witness for an associated type, e.g., @@ -1255,8 +1247,7 @@ class AssociatedTypeInference { /// involving multiple files/modules, and not in tests within the Swift /// project itself. bool canAttemptEagerTypeWitnessDerivation( - ConformanceChecker &checker, - AssociatedTypeDecl *assocType); + DeclContext *DC, AssociatedTypeDecl *assocType); public: /// Describes a mapping from associated type declarations to their diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp index 5ae57921e39e0..5b26b7b334742 100644 --- a/lib/Sema/TypeCheckProtocolInference.cpp +++ b/lib/Sema/TypeCheckProtocolInference.cpp @@ -25,6 +25,7 @@ #include "swift/AST/SubstitutionMap.h" #include "swift/AST/TypeMatcher.h" #include "swift/AST/Types.h" +#include "swift/AST/TypeCheckRequests.h" #include "swift/Basic/Defer.h" #include "swift/ClangImporter/ClangModule.h" #include "llvm/ADT/Statistic.h" @@ -374,7 +375,6 @@ static bool isExtensionUsableForInference(const ExtensionDecl *extension, InferredAssociatedTypesByWitnesses AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses( - ConformanceChecker &checker, const llvm::SetVector &allUnresolved, ValueDecl *req) { // Conformances constructed by the ClangImporter should have explicit type @@ -392,7 +392,7 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses( InferredAssociatedTypesByWitnesses result; for (auto witness : - checker.lookupValueWitnesses(req, /*ignoringNames=*/nullptr)) { + lookupValueWitnesses(dc, req, /*ignoringNames=*/nullptr)) { LLVM_DEBUG(llvm::dbgs() << "Inferring associated types from decl:\n"; witness->dump(llvm::dbgs())); @@ -582,9 +582,7 @@ next_witness:; InferredAssociatedTypes AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses( - ConformanceChecker &checker, - const llvm::SetVector &assocTypes) -{ + const llvm::SetVector &assocTypes) { InferredAssociatedTypes result; for (auto member : proto->getMembers()) { auto req = dyn_cast(member); @@ -598,8 +596,7 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses( if (assocTypes.count(assocType) == 0) continue; - auto reqInferred = inferTypeWitnessesViaAssociatedType(checker, - assocTypes, + auto reqInferred = inferTypeWitnessesViaAssociatedType(assocTypes, assocType); if (!reqInferred.empty()) result.push_back({req, std::move(reqInferred)}); @@ -623,7 +620,9 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses( // Check whether any of the associated types we care about are // referenced in this value requirement. { - const auto referenced = checker.getReferencedAssociatedTypes(req); + auto referenced = evaluateOrDefault(ctx.evaluator, + ReferencedAssociatedTypesRequest{req}, + TinyPtrVector()); if (llvm::find_if(referenced, [&](AssociatedTypeDecl *const assocType) { return assocTypes.count(assocType); }) == referenced.end()) @@ -633,7 +632,7 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses( // Infer associated types from the potential value witnesses for // this requirement. auto reqInferred = - inferTypeWitnessesViaValueWitnesses(checker, assocTypes, req); + inferTypeWitnessesViaValueWitnesses(assocTypes, req); if (reqInferred.empty()) continue; @@ -738,7 +737,6 @@ static Type removeSelfParam(ValueDecl *value, Type type) { InferredAssociatedTypesByWitnesses AssociatedTypeInference::inferTypeWitnessesViaAssociatedType( - ConformanceChecker &checker, const llvm::SetVector &allUnresolved, AssociatedTypeDecl *assocType) { // Form the default name _Default_Foo. @@ -2513,13 +2511,13 @@ bool AssociatedTypeInference::diagnoseAmbiguousSolutions( } bool AssociatedTypeInference::canAttemptEagerTypeWitnessDerivation( - ConformanceChecker &checker, - AssociatedTypeDecl *assocType) { + DeclContext *DC, AssociatedTypeDecl *assocType) { /// Rather than locating the TypeID via the default implementation of /// Identifiable, we need to find the type based on the associated ActorSystem - if (checker.Adoptee->isDistributedActor() && - assocType->getProtocol()->isSpecificProtocol(KnownProtocolKind::Identifiable)) { + if (auto *nominal = DC->getSelfNominalTypeDecl()) + if (nominal->isDistributedActor() && + assocType->getProtocol()->isSpecificProtocol(KnownProtocolKind::Identifiable)) { return true; } @@ -2550,7 +2548,7 @@ auto AssociatedTypeInference::solve(ConformanceChecker &checker) if (conformance->hasTypeWitness(assocType)) continue; - if (canAttemptEagerTypeWitnessDerivation(checker, assocType)) { + if (canAttemptEagerTypeWitnessDerivation(dc, assocType)) { auto derivedType = computeDerivedTypeWitness(assocType); if (derivedType.first) { checker.recordTypeWitness(assocType, @@ -2602,8 +2600,7 @@ auto AssociatedTypeInference::solve(ConformanceChecker &checker) return result; // Infer potential type witnesses from value witnesses. - inferred = inferTypeWitnessesViaValueWitnesses(checker, - unresolvedAssocTypes); + inferred = inferTypeWitnessesViaValueWitnesses(unresolvedAssocTypes); LLVM_DEBUG(llvm::dbgs() << "Candidates for inference:\n"; dumpInferredAssociatedTypes(inferred)); @@ -3036,7 +3033,11 @@ void ConformanceChecker::resolveSingleWitness(ValueDecl *requirement) { // If any of the type witnesses was erroneous, don't bother to check // this value witness: it will fail. - for (auto assocType : getReferencedAssociatedTypes(requirement)) { + auto assocTypes = evaluateOrDefault(getASTContext().evaluator, + ReferencedAssociatedTypesRequest{requirement}, + TinyPtrVector()); + + for (auto assocType : assocTypes) { if (Conformance->getTypeWitness(assocType)->hasError()) { Conformance->setInvalid(); return; diff --git a/test/IRGen/bitwise-copyable-derived-loadRaw.swift b/test/IRGen/bitwise-copyable-derived-loadRaw.swift index eb33ac7be6518..4e86e79e4f9fe 100644 --- a/test/IRGen/bitwise-copyable-derived-loadRaw.swift +++ b/test/IRGen/bitwise-copyable-derived-loadRaw.swift @@ -6,7 +6,7 @@ public protocol MyBitwiseCopyable : _BitwiseCopyable {} -extension SIMD16 : @retroactive MyBitwiseCopyable where Scalar.SIMD16Storage : MyBitwiseCopyable {} +extension SIMD16 : MyBitwiseCopyable where Scalar.SIMD16Storage : MyBitwiseCopyable {} extension UInt8.SIMD16Storage : MyBitwiseCopyable {} func doit() { diff --git a/test/Sema/extension_retroactive_conformances.swift b/test/Sema/extension_retroactive_conformances.swift index e2fcc14ce44b3..04f4fe7b415e7 100644 --- a/test/Sema/extension_retroactive_conformances.swift +++ b/test/Sema/extension_retroactive_conformances.swift @@ -15,6 +15,9 @@ public struct Sample5 {} public struct Sample6 {} public struct SampleAlreadyConforms: SampleProtocol1 {} + +public struct GenericSample1 {} + #else import Library @@ -81,4 +84,9 @@ extension OriginallyDefinedInLibrary: SampleProtocol1 {} // ok, @_originallyDefi #endif +// conditional conformances +extension GenericSample1: SampleProtocol1 where T: SampleProtocol1 {} +// expected-warning@-1 {{extension declares a conformance of imported type 'GenericSample1' to imported protocol 'SampleProtocol1'; this will not behave correctly if the owners of 'Library' introduce this conformance in the future}} +// expected-note@-2 {{add '@retroactive' to silence this warning}} + #endif diff --git a/test/stdlib/SIMD_as_AdditiveArithmetic.swift b/test/stdlib/SIMD_as_AdditiveArithmetic.swift index f2641a396c7ec..f4dac5deaf43c 100644 --- a/test/stdlib/SIMD_as_AdditiveArithmetic.swift +++ b/test/stdlib/SIMD_as_AdditiveArithmetic.swift @@ -1,5 +1,5 @@ // RUN: %target-typecheck-verify-swift -extension SIMD2: AdditiveArithmetic where Scalar: FloatingPoint { } -extension SIMD3: AdditiveArithmetic where Scalar: FloatingPoint { } -extension SIMD4: AdditiveArithmetic where Scalar: FloatingPoint { } -extension SIMD8: AdditiveArithmetic where Scalar: FloatingPoint { } +extension SIMD2: @retroactive AdditiveArithmetic where Scalar: FloatingPoint { } +extension SIMD3: @retroactive AdditiveArithmetic where Scalar: FloatingPoint { } +extension SIMD4: @retroactive AdditiveArithmetic where Scalar: FloatingPoint { } +extension SIMD8: @retroactive AdditiveArithmetic where Scalar: FloatingPoint { }