diff --git a/include/swift/AST/AnyFunctionRef.h b/include/swift/AST/AnyFunctionRef.h index 415309374130f..8a3baf78fe7e8 100644 --- a/include/swift/AST/AnyFunctionRef.h +++ b/include/swift/AST/AnyFunctionRef.h @@ -75,13 +75,6 @@ class AnyFunctionRef { return TheFunction.get()->getCaptureInfo(); } - - bool hasType() const { - if (auto *AFD = TheFunction.dyn_cast()) - return AFD->hasInterfaceType(); - return !TheFunction.get()->getType().isNull(); - } - ParameterList *getParameters() const { if (auto *AFD = TheFunction.dyn_cast()) return AFD->getParameters(); @@ -174,20 +167,8 @@ class AnyFunctionRef { return TheFunction.dyn_cast(); } - /// Return true if this closure is passed as an argument to a function and is - /// known not to escape from that function. In this case, captures can be - /// more efficient. - bool isKnownNoEscape() const { - if (hasType() && !getType()->hasError()) - return getType()->castTo()->isNoEscape(); - return false; - } - /// Whether this function is @Sendable. bool isSendable() const { - if (!hasType()) - return false; - if (auto *fnType = getType()->getAs()) return fnType->isSendable(); diff --git a/include/swift/AST/CaptureInfo.h b/include/swift/AST/CaptureInfo.h index 656ba48637f28..d3448515906c4 100644 --- a/include/swift/AST/CaptureInfo.h +++ b/include/swift/AST/CaptureInfo.h @@ -43,6 +43,7 @@ class ValueDecl; class FuncDecl; class OpaqueValueExpr; class VarDecl; +class GenericEnvironment; /// CapturedValue includes both the declaration being captured, along with flags /// that indicate how it is captured. @@ -140,19 +141,27 @@ class DynamicSelfType; /// Stores information about captured variables. class CaptureInfo { class CaptureInfoStorage final - : public llvm::TrailingObjects { + : public llvm::TrailingObjects { DynamicSelfType *DynamicSelf; OpaqueValueExpr *OpaqueValue; - unsigned Count; + unsigned NumCapturedValues; + unsigned NumGenericEnvironments; + public: - explicit CaptureInfoStorage(unsigned count, DynamicSelfType *dynamicSelf, - OpaqueValueExpr *opaqueValue) - : DynamicSelf(dynamicSelf), OpaqueValue(opaqueValue), Count(count) { } + explicit CaptureInfoStorage(DynamicSelfType *dynamicSelf, + OpaqueValueExpr *opaqueValue, + unsigned numCapturedValues, + unsigned numGenericEnvironments) + : DynamicSelf(dynamicSelf), OpaqueValue(opaqueValue), + NumCapturedValues(numCapturedValues), + NumGenericEnvironments(numGenericEnvironments) { } - ArrayRef getCaptures() const { - return llvm::ArrayRef(this->getTrailingObjects(), Count); - } + ArrayRef getCaptures() const; + + ArrayRef getGenericEnvironments() const; DynamicSelfType *getDynamicSelfType() const { return DynamicSelf; @@ -161,6 +170,10 @@ class CaptureInfo { OpaqueValueExpr *getOpaqueValue() const { return OpaqueValue; } + + unsigned numTrailingObjects(OverloadToken) const { + return NumCapturedValues; + } }; enum class Flags : unsigned { @@ -173,9 +186,11 @@ class CaptureInfo { public: /// The default-constructed CaptureInfo is "not yet computed". CaptureInfo() = default; - CaptureInfo(ASTContext &ctx, ArrayRef captures, + CaptureInfo(ASTContext &ctx, + ArrayRef captures, DynamicSelfType *dynamicSelf, OpaqueValueExpr *opaqueValue, - bool genericParamCaptures); + bool genericParamCaptures, + ArrayRef genericEnv=ArrayRef()); /// A CaptureInfo representing no captures at all. static CaptureInfo empty(); @@ -190,12 +205,20 @@ class CaptureInfo { !hasDynamicSelfCapture() && !hasOpaqueValueCapture(); } + /// Returns all captured values and opaque expressions. ArrayRef getCaptures() const { assert(hasBeenComputed()); return StorageAndFlags.getPointer()->getCaptures(); } - /// \returns true if the function captures any generic type parameters. + /// Returns all captured pack element environments. + ArrayRef getGenericEnvironments() const { + assert(hasBeenComputed()); + return StorageAndFlags.getPointer()->getGenericEnvironments(); + } + + /// \returns true if the function captures the primary generic environment + /// from its innermost declaration context. bool hasGenericParamCaptures() const { assert(hasBeenComputed()); return StorageAndFlags.getInt().contains(Flags::HasGenericParamCaptures); diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index d298668ebc8e9..a61ba19caaabb 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -2229,6 +2229,10 @@ class ConstraintSystem { /// from declared parameters/result and body. llvm::MapVector ClosureTypes; + /// Maps closures and local functions to the pack expansion expressions they + /// capture. + llvm::MapVector> CapturedExpansions; + /// Maps expressions for implied results (e.g implicit 'then' statements, /// implicit 'return' statements in single expression body closures) to their /// result kind. @@ -3164,6 +3168,19 @@ class ConstraintSystem { return nullptr; } + SmallVector getCapturedExpansions(AnyFunctionRef func) const { + auto result = CapturedExpansions.find(func); + if (result == CapturedExpansions.end()) + return {}; + + return result->second; + } + + void setCapturedExpansions(AnyFunctionRef func, SmallVector exprs) { + assert(CapturedExpansions.count(func) == 0 && "Cannot reset captured expansions"); + CapturedExpansions.insert({func, exprs}); + } + TypeVariableType *getKeyPathValueType(const KeyPathExpr *keyPath) const { auto result = getKeyPathValueTypeIfAvailable(keyPath); assert(result); diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp index 9f213aa28f7c0..20ae24c40eb87 100644 --- a/lib/AST/ASTVerifier.cpp +++ b/lib/AST/ASTVerifier.cpp @@ -198,9 +198,17 @@ class Verifier : public ASTWalker { using ScopeLike = llvm::PointerUnion; SmallVector Scopes; - /// The stack of generic contexts. - using GenericLike = llvm::PointerUnion; - SmallVector Generics; + /// The stack of declaration contexts we're visiting. The primary + /// archetypes from the innermost generic environment are in scope. + SmallVector Generics; + + /// The set of all opened existential and opened pack element generic + /// environments that are currently in scope. + llvm::DenseSet LocalGenerics; + + /// We track the pack expansion expressions in ForEachStmts, because + /// their local generics remain in scope until the end of the statement. + llvm::DenseSet ForEachPatternSequences; /// The stack of optional evaluations active at this point. SmallVector OptionalEvaluations; @@ -208,10 +216,6 @@ class Verifier : public ASTWalker { /// The set of opaque value expressions active at this point. llvm::DenseMap OpaqueValues; - /// The set of opened existential archetypes that are currently - /// active. - llvm::DenseSet OpenedExistentialArchetypes; - /// The set of inout to pointer expr that match the following pattern: /// /// (call-expr @@ -632,11 +636,10 @@ class Verifier : public ASTWalker { bool foundError = type->getCanonicalType().findIf([&](Type type) -> bool { if (auto archetype = type->getAs()) { - auto root = archetype->getRoot(); // Opaque archetypes are globally available. We don't need to check // them here. - if (isa(root)) + if (isa(archetype)) return false; // Only visit each archetype once. @@ -645,11 +648,10 @@ class Verifier : public ASTWalker { // We should know about archetypes corresponding to opened // existential archetypes. - if (auto opened = dyn_cast(root)) { - if (OpenedExistentialArchetypes.count(opened) == 0) { - Out << "Found opened existential archetype " - << root->getString() - << " outside enclosing OpenExistentialExpr\n"; + if (isa(archetype)) { + if (LocalGenerics.count(archetype->getGenericEnvironment()) == 0) { + Out << "Found local archetype " << archetype + << " outside its defining scope\n"; return true; } @@ -659,34 +661,19 @@ class Verifier : public ASTWalker { // Otherwise, the archetype needs to be from this scope. if (Generics.empty() || !Generics.back()) { Out << "AST verification error: archetype outside of generic " - "context: " << root->getString() << "\n"; + "context: " << archetype << "\n"; return true; } // Get the archetype's generic signature. - GenericEnvironment *archetypeEnv = root->getGenericEnvironment(); + GenericEnvironment *archetypeEnv = archetype->getGenericEnvironment(); auto archetypeSig = archetypeEnv->getGenericSignature(); auto genericCtx = Generics.back(); - GenericSignature genericSig; - if (auto *genericDC = genericCtx.dyn_cast()) { - genericSig = genericDC->getGenericSignatureOfContext(); - } else { - auto *genericEnv = genericCtx.get(); - genericSig = genericEnv->getGenericSignature(); - - // Check whether this archetype is a substitution from the - // outer generic context of an opened element environment. - if (genericEnv->getKind() == GenericEnvironment::Kind::OpenedElement) { - auto contextSubs = genericEnv->getPackElementContextSubstitutions(); - QuerySubstitutionMap isInContext{contextSubs}; - if (isInContext(root->getInterfaceType()->castTo())) - return false; - } - } + GenericSignature genericSig = genericCtx->getGenericSignatureOfContext(); if (genericSig.getPointer() != archetypeSig.getPointer()) { - Out << "Archetype " << root->getString() << " not allowed " + Out << "Archetype " << archetype->getString() << " not allowed " << "in this context\n"; Out << "Archetype generic signature: " << archetypeSig->getAsString() << "\n"; @@ -735,7 +722,7 @@ class Verifier : public ASTWalker { } void popScope(DeclContext *scope) { assert(Scopes.back().get() == scope); - assert(Generics.back().get() == scope); + assert(Generics.back() == scope); Scopes.pop_back(); Generics.pop_back(); } @@ -808,6 +795,9 @@ class Verifier : public ASTWalker { if (!shouldVerify(expansion)) { return false; } + + assert(ForEachPatternSequences.count(expansion) == 0); + ForEachPatternSequences.insert(expansion); } if (!S->getElementExpr()) @@ -821,6 +811,10 @@ class Verifier : public ASTWalker { void cleanup(ForEachStmt *S) { if (auto *expansion = dyn_cast(S->getParsedSequence())) { + assert(ForEachPatternSequences.count(expansion) != 0); + ForEachPatternSequences.erase(expansion); + + // Clean up for real. cleanup(expansion); } @@ -851,6 +845,16 @@ class Verifier : public ASTWalker { OpaqueValues.erase(expr->getInterpolationExpr()); } + void pushLocalGenerics(GenericEnvironment *env) { + assert(LocalGenerics.count(env)==0); + LocalGenerics.insert(env); + } + + void popLocalGenerics(GenericEnvironment *env) { + assert(LocalGenerics.count(env)==1); + LocalGenerics.erase(env); + } + bool shouldVerify(OpenExistentialExpr *expr) { if (!shouldVerify(cast(expr))) return false; @@ -862,8 +866,8 @@ class Verifier : public ASTWalker { assert(!OpaqueValues.count(expr->getOpaqueValue())); OpaqueValues[expr->getOpaqueValue()] = 0; - assert(OpenedExistentialArchetypes.count(expr->getOpenedArchetype())==0); - OpenedExistentialArchetypes.insert(expr->getOpenedArchetype()); + + pushLocalGenerics(expr->getOpenedArchetype()->getGenericEnvironment()); return true; } @@ -875,22 +879,28 @@ class Verifier : public ASTWalker { assert(OpaqueValues.count(expr->getOpaqueValue())); OpaqueValues.erase(expr->getOpaqueValue()); - assert(OpenedExistentialArchetypes.count(expr->getOpenedArchetype())==1); - OpenedExistentialArchetypes.erase(expr->getOpenedArchetype()); + + popLocalGenerics(expr->getOpenedArchetype()->getGenericEnvironment()); } bool shouldVerify(PackExpansionExpr *expr) { if (!shouldVerify(cast(expr))) return false; - Generics.push_back(expr->getGenericEnvironment()); + // Don't push local generics again when we visit the expr inside + // the ForEachStmt. + if (auto *genericEnv = expr->getGenericEnvironment()) + if (ForEachPatternSequences.count(expr) == 0) + pushLocalGenerics(genericEnv); return true; } - void cleanup(PackExpansionExpr *E) { - assert(Generics.back().get() == - E->getGenericEnvironment()); - Generics.pop_back(); + void cleanup(PackExpansionExpr *expr) { + // If this is a pack iteration pattern, don't pop local generics + // until we exit the ForEachStmt. + if (auto *genericEnv = expr->getGenericEnvironment()) + if (ForEachPatternSequences.count(expr) == 0) + popLocalGenerics(genericEnv); } bool shouldVerify(MakeTemporarilyEscapableExpr *expr) { diff --git a/lib/AST/CaptureInfo.cpp b/lib/AST/CaptureInfo.cpp index a107699ccb5a5..6784711193dfd 100644 --- a/lib/AST/CaptureInfo.cpp +++ b/lib/AST/CaptureInfo.cpp @@ -13,10 +13,21 @@ #include "swift/AST/CaptureInfo.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" +#include "swift/AST/GenericEnvironment.h" #include "llvm/Support/raw_ostream.h" using namespace swift; +ArrayRef +CaptureInfo::CaptureInfoStorage::getCaptures() const { + return llvm::ArrayRef(this->getTrailingObjects(), NumCapturedValues); +} + +ArrayRef +CaptureInfo::CaptureInfoStorage::getGenericEnvironments() const { + return llvm::ArrayRef(this->getTrailingObjects(), NumGenericEnvironments); +} + //===----------------------------------------------------------------------===// // MARK: CaptureInfo //===----------------------------------------------------------------------===// @@ -24,36 +35,50 @@ using namespace swift; CaptureInfo::CaptureInfo(ASTContext &ctx, ArrayRef captures, DynamicSelfType *dynamicSelf, OpaqueValueExpr *opaqueValue, - bool genericParamCaptures) { + bool genericParamCaptures, + ArrayRef genericEnv) { static_assert(IsTriviallyDestructible::value, "Capture info is alloc'd on the ASTContext and not destroyed"); static_assert(IsTriviallyDestructible::value, "Capture info is alloc'd on the ASTContext and not destroyed"); + // This is the only kind of local generic environment we can capture right now. +#ifndef NDEBUG + for (auto *env : genericEnv) { + assert(env->getKind() == GenericEnvironment::Kind::OpenedElement); + } +#endif + OptionSet flags; if (genericParamCaptures) flags |= Flags::HasGenericParamCaptures; - if (captures.empty() && !dynamicSelf && !opaqueValue) { + if (captures.empty() && genericEnv.empty() && !dynamicSelf && !opaqueValue) { *this = CaptureInfo::empty(); StorageAndFlags.setInt(flags); return; } size_t storageToAlloc = - CaptureInfoStorage::totalSizeToAlloc(captures.size()); + CaptureInfoStorage::totalSizeToAlloc(captures.size(), + genericEnv.size()); void *storageBuf = ctx.Allocate(storageToAlloc, alignof(CaptureInfoStorage)); - auto *storage = new (storageBuf) CaptureInfoStorage(captures.size(), - dynamicSelf, - opaqueValue); + auto *storage = new (storageBuf) CaptureInfoStorage(dynamicSelf, + opaqueValue, + captures.size(), + genericEnv.size()); StorageAndFlags.setPointerAndInt(storage, flags); std::uninitialized_copy(captures.begin(), captures.end(), storage->getTrailingObjects()); + std::uninitialized_copy(genericEnv.begin(), genericEnv.end(), + storage->getTrailingObjects()); } CaptureInfo CaptureInfo::empty() { - static const CaptureInfoStorage empty{0, /*dynamicSelf*/nullptr, - /*opaqueValue*/nullptr}; + static const CaptureInfoStorage empty{/*dynamicSelf*/nullptr, + /*opaqueValue*/nullptr, + 0, 0}; CaptureInfo result; result.StorageAndFlags.setPointer(&empty); return result; @@ -109,6 +134,13 @@ void CaptureInfo::print(raw_ostream &OS) const { OS << ""; }, [&] { OS << ", "; }); + + interleave(getGenericEnvironments(), + [&](GenericEnvironment *genericEnv) { + OS << " shape_class="; + OS << genericEnv->getOpenedElementShapeClass(); + }, + [&] { OS << ","; }); OS << ')'; } diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index 5d8d7a7fa6ccc..d37a88876e6c7 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -2833,10 +2833,9 @@ resolveTypeDeclsToNominal(Evaluator &evaluator, // Recognize Swift.AnyObject directly. if (typealias->getName().is("AnyObject")) { // Type version: an empty class-bound existential. - if (typealias->hasInterfaceType()) { - if (auto type = typealias->getUnderlyingType()) - if (type->isAnyObject()) - anyObject = true; + if (auto type = typealias->getUnderlyingType()) { + if (type->isAnyObject()) + anyObject = true; } // TypeRepr version: Builtin.AnyObject else if (auto *qualIdentTR = dyn_cast_or_null( diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 98af096cfed6b..fc57b841ac6fe 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -3021,15 +3021,12 @@ struct LocalArchetypeRequirementCollector { /// /// \param localArchetypes - the list of local archetypes to promote /// into the signature, if any -/// \param inheritGenericSig - whether to inherit the generic signature from the -/// parent function. /// \param genericEnv - the new generic environment /// \param contextSubs - map non-local archetypes from the original function /// to archetypes in the thunk /// \param interfaceSubs - map interface types to old archetypes static CanGenericSignature buildThunkSignature(SILFunction *fn, - bool inheritGenericSig, ArrayRef localArchetypes, GenericEnvironment *&genericEnv, SubstitutionMap &contextSubs, @@ -3037,6 +3034,7 @@ buildThunkSignature(SILFunction *fn, llvm::DenseMap &contextLocalArchetypes) { auto *mod = fn->getModule().getSwiftModule(); auto &ctx = mod->getASTContext(); + auto forwardingSubs = fn->getForwardingSubstitutionMap(); // If there are no local archetypes, we just inherit the generic // environment from the parent function. @@ -3044,7 +3042,7 @@ buildThunkSignature(SILFunction *fn, auto genericSig = fn->getLoweredFunctionType()->getInvocationGenericSignature(); genericEnv = fn->getGenericEnvironment(); - interfaceSubs = fn->getForwardingSubstitutionMap(); + interfaceSubs = forwardingSubs; contextSubs = interfaceSubs; return genericSig; } @@ -3052,12 +3050,10 @@ buildThunkSignature(SILFunction *fn, // Add the existing generic signature. unsigned depth = 0; GenericSignature baseGenericSig; - if (inheritGenericSig) { - if (auto genericSig = - fn->getLoweredFunctionType()->getInvocationGenericSignature()) { - baseGenericSig = genericSig; - depth = genericSig.getGenericParams().back()->getDepth() + 1; - } + if (auto genericSig = + fn->getLoweredFunctionType()->getInvocationGenericSignature()) { + baseGenericSig = genericSig; + depth = genericSig.getGenericParams().back()->getDepth() + 1; } // Add new generic parameters to replace the local archetypes. @@ -3088,13 +3084,11 @@ buildThunkSignature(SILFunction *fn, ->getInvocationGenericSignature()) { contextSubs = SubstitutionMap::get( calleeGenericSig, - [&](SubstitutableType *type) -> Type { - return genericEnv->mapTypeIntoContext(type); - }, - MakeAbstractConformanceForGenericType()); + genericEnv->getForwardingSubstitutionMap()); } // Calculate substitutions to map interface types to the caller's archetypes. + interfaceSubs = SubstitutionMap::get( genericSig, [&](SubstitutableType *type) -> Type { @@ -3103,7 +3097,7 @@ buildThunkSignature(SILFunction *fn, return collector.ParamSubs[param->getIndex()]; } } - return fn->mapTypeIntoContext(type); + return Type(type).subst(forwardingSubs); }, MakeAbstractConformanceForGenericType()); @@ -3142,18 +3136,14 @@ CanSILFunctionType swift::buildSILFunctionThunkType( if (withoutActuallyEscaping) extInfoBuilder = extInfoBuilder.withNoEscape(false); - // Does the thunk type involve archetypes other than local archetypes? - bool hasArchetypes = false; // Does the thunk type involve a local archetype type? SmallVector localArchetypes; auto archetypeVisitor = [&](CanType t) { if (auto archetypeTy = dyn_cast(t)) { - if (auto opened = dyn_cast(archetypeTy)) { - auto root = opened.getRoot(); + if (auto local = dyn_cast(archetypeTy)) { + auto root = local.getRoot(); if (llvm::find(localArchetypes, root) == localArchetypes.end()) localArchetypes.push_back(root); - } else { - hasArchetypes = true; } } }; @@ -3169,7 +3159,6 @@ CanSILFunctionType swift::buildSILFunctionThunkType( sourceType.visit(archetypeVisitor); genericSig = buildThunkSignature(fn, - hasArchetypes, localArchetypes, genericEnv, contextSubs, diff --git a/lib/SIL/IR/TypeLowering.cpp b/lib/SIL/IR/TypeLowering.cpp index 81b720e744a77..615d4dada59fb 100644 --- a/lib/SIL/IR/TypeLowering.cpp +++ b/lib/SIL/IR/TypeLowering.cpp @@ -4150,6 +4150,9 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) { // that IRGen can pass dynamic 'Self' metadata. std::optional selfCapture; + // Captured pack element environments. + llvm::SetVector genericEnv; + bool capturesGenericParams = false; DynamicSelfType *capturesDynamicSelf = nullptr; OpaqueValueExpr *capturesOpaqueValue = nullptr; @@ -4176,6 +4179,13 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) { if (captureInfo.hasOpaqueValueCapture()) capturesOpaqueValue = captureInfo.getOpaqueValue(); + // Any set of mutually-recursive local functions will capture the same + // element environments, because we can't "cross" a pack expansion + // expression. + for (auto *env : captureInfo.getGenericEnvironments()) { + genericEnv.insert(env); + } + for (auto capture : captureInfo.getCaptures()) { if (!capture.isLocalCapture()) continue; @@ -4399,8 +4409,9 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) { } // Cache the uniqued set of transitive captures. - CaptureInfo info{Context, resultingCaptures, capturesDynamicSelf, - capturesOpaqueValue, capturesGenericParams}; + CaptureInfo info(Context, resultingCaptures, + capturesDynamicSelf, capturesOpaqueValue, + capturesGenericParams, genericEnv.getArrayRef()); auto inserted = LoweredCaptures.insert({fn, info}); assert(inserted.second && "already in map?!"); (void)inserted; diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 812582385f135..f4f2892efa4fa 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -933,7 +933,7 @@ namespace { llvm::MapVector UnresolvedBaseTypes; /// A stack of pack expansions that can open pack elements. - llvm::SmallVector PackElementEnvironments; + llvm::SmallVector OuterExpansions; /// Returns false and emits the specified diagnostic if the member reference /// base is a nil literal. Returns true otherwise. @@ -1000,7 +1000,7 @@ namespace { } unsigned options = (TVO_CanBindToLValue | TVO_CanBindToNoEscape); - if (!PackElementEnvironments.empty()) + if (!OuterExpansions.empty()) options |= TVO_CanBindToPack; auto tv = CS.createTypeVariable( @@ -1185,6 +1185,12 @@ namespace { // result builders could generate constraints for its body // in the middle of the solving. CS.setPhase(ConstraintSystemPhase::ConstraintGeneration); + + // Pick up the saved stack of pack expansions so we can continue + // to handle pack element references inside the closure body. + if (auto *ACE = dyn_cast(CurDC)) { + OuterExpansions = CS.getCapturedExpansions(ACE); + } } virtual ~ConstraintGenerator() { @@ -1193,8 +1199,8 @@ namespace { ConstraintSystem &getConstraintSystem() const { return CS; } - void addPackElementEnvironment(PackExpansionExpr *expr) { - PackElementEnvironments.push_back(expr); + void pushPackExpansionExpr(PackExpansionExpr *expr) { + OuterExpansions.push_back(expr); SmallVector expandedPacks; collectExpandedPacks(expr, expandedPacks); @@ -1213,6 +1219,7 @@ namespace { CS.getConstraintLocator(expr, ConstraintLocator::PackShape); auto *shapeTypeVar = CS.createTypeVariable( shapeLoc, TVO_CanBindToPack | TVO_CanBindToHole); + auto expansionType = PackExpansionType::get(patternType, shapeTypeVar); CS.setType(expr, expansionType); } @@ -1585,7 +1592,7 @@ namespace { unsigned options = (TVO_CanBindToLValue | TVO_CanBindToNoEscape); - if (!PackElementEnvironments.empty()) + if (!OuterExpansions.empty()) options |= TVO_CanBindToPack; // Create an overload choice referencing this declaration and immediately @@ -1636,9 +1643,9 @@ namespace { // Add a PackElementOf constraint for 'each T' type reprs. PackExpansionExpr *elementEnv = nullptr; - if (!PackElementEnvironments.empty()) { + if (!OuterExpansions.empty()) { options |= TypeResolutionFlags::AllowPackReferences; - elementEnv = PackElementEnvironments.back(); + elementEnv = OuterExpansions.back(); } const auto packElementOpener = OpenPackElementType(CS, locator, elementEnv); @@ -1889,9 +1896,9 @@ namespace { TypeResolutionOptions(TypeResolverContext::InExpression); for (auto specializationArg : specializationArgs) { PackExpansionExpr *elementEnv = nullptr; - if (!PackElementEnvironments.empty()) { + if (!OuterExpansions.empty()) { options |= TypeResolutionFlags::AllowPackReferences; - elementEnv = PackElementEnvironments.back(); + elementEnv = OuterExpansions.back(); } const auto result = TypeResolution::resolveContextualType( specializationArg, CurDC, options, @@ -3055,6 +3062,9 @@ namespace { Constraint::create(CS, ConstraintKind::FallbackType, closureType, inferredType, locator, referencedVars)); + if (!OuterExpansions.empty()) + CS.setCapturedExpansions(closure, OuterExpansions); + CS.setClosureType(closure, inferredType); return closureType; } @@ -3160,8 +3170,8 @@ namespace { } Type visitPackExpansionExpr(PackExpansionExpr *expr) { - assert(PackElementEnvironments.back() == expr); - PackElementEnvironments.pop_back(); + assert(OuterExpansions.back() == expr); + OuterExpansions.pop_back(); auto expansionType = CS.getType(expr)->castTo(); auto elementResultType = CS.getType(expr->getPatternExpr()); @@ -3182,7 +3192,7 @@ namespace { for (auto pack : expandedPacks) { Type packType; /// Skipping over pack elements because the relationship to its - /// environment is now established during \c addPackElementEnvironment + /// environment is now established during \c pushPackExpansionExpr /// upon visiting its pack expansion and the Shape constraint added /// upon visiting the pack element. if (isExpr(pack)) { @@ -4301,7 +4311,7 @@ namespace { } if (auto *expansion = dyn_cast(expr)) { - CG.addPackElementEnvironment(expansion); + CG.pushPackExpansionExpr(expansion); } return Action::Continue(expr); diff --git a/lib/Sema/CSStep.cpp b/lib/Sema/CSStep.cpp index 687d2fb19b4a3..86ee912708d51 100644 --- a/lib/Sema/CSStep.cpp +++ b/lib/Sema/CSStep.cpp @@ -438,6 +438,20 @@ StepResult ComponentStep::take(bool prevFailed) { // If there are no disjunctions or type variables to bind // we can't solve this system unless we have free type variables // allowed in the solution. + if (CS.isDebugMode()) { + PrintOptions PO; + PO.PrintTypesForDebugging = true; + + auto &log = getDebugLogger(); + log << "(failed due to free variables:"; + for (auto *typeVar : CS.getTypeVariables()) { + if (!typeVar->getImpl().hasRepresentativeOrFixed()) { + log << " " << typeVar->getString(PO); + } + } + log << ")\n"; + } + return finalize(/*isSuccess=*/false); } diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index c12a10df4c41d..8663a63c935f8 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -1823,9 +1823,10 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, // If the closure's type was inferred to be noescape, then it doesn't // need qualification. - if (AnyFunctionRef(const_cast(CE)) - .isKnownNoEscape()) - return false; + if (auto funcTy = CE->getType()->getAs()) { + if (funcTy->isNoEscape()) + return false; + } if (auto autoclosure = dyn_cast(CE)) { if (autoclosure->getThunkKind() == AutoClosureExpr::Kind::AsyncLet) @@ -2094,9 +2095,11 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, AbstractClosureExpr *ACE = nullptr; if (DC->isLocalContext()) { while (DC->getParent()->isLocalContext() && !ACE) { + // FIXME: This is happening too early, because closure->getType() isn't set. if (auto *closure = dyn_cast(DC)) - if (DiagnoseWalker::isClosureRequiringSelfQualification(closure, ctx)) - ACE = const_cast(closure); + if (closure->getType()) + if (DiagnoseWalker::isClosureRequiringSelfQualification(closure, ctx)) + ACE = const_cast(closure); DC = DC->getParent(); } } diff --git a/lib/Sema/TypeCheckCaptures.cpp b/lib/Sema/TypeCheckCaptures.cpp index 566781daedc7d..1495be8674d19 100644 --- a/lib/Sema/TypeCheckCaptures.cpp +++ b/lib/Sema/TypeCheckCaptures.cpp @@ -38,6 +38,16 @@ class FindCapturedVars : public ASTWalker { ASTContext &Context; SmallVector Captures; llvm::SmallDenseMap captureEntryNumber; + + /// A stack of pack element environments we're currently walking into. + /// A reference to an element archetype defined by one of these is not + /// a capture. + llvm::SetVector VisitingEnvironments; + + /// A set of pack element environments we've encountered that were not + /// in the above stack; those are the captures. + llvm::SetVector CapturedEnvironments; + SourceLoc GenericParamCaptureLoc; SourceLoc DynamicSelfCaptureLoc; DynamicSelfType *DynamicSelf = nullptr; @@ -65,8 +75,9 @@ class FindCapturedVars : public ASTWalker { dynamicSelfToRecord = DynamicSelf; } - return CaptureInfo(Context, Captures, dynamicSelfToRecord, OpaqueValue, - HasGenericParamCaptures); + return CaptureInfo(Context, Captures, dynamicSelfToRecord, + OpaqueValue, HasGenericParamCaptures, + CapturedEnvironments.getArrayRef()); } bool hasGenericParamCaptures() const { @@ -148,9 +159,17 @@ class FindCapturedVars : public ASTWalker { // perform it accurately. if (type->hasArchetype() || type->hasTypeParameter()) { type.walk(TypeCaptureWalker(ObjC, [&](Type t) { - if ((t->is() || + // Record references to element archetypes that were bound + // outside the body of the current closure. + if (auto *element = t->getAs()) { + auto *env = element->getGenericEnvironment(); + if (VisitingEnvironments.count(env) == 0) + CapturedEnvironments.insert(env); + } + + if ((t->is() || + t->is() || t->is()) && - !t->isOpenedExistential() && !HasGenericParamCaptures) { GenericParamCaptureLoc = loc; HasGenericParamCaptures = true; @@ -619,6 +638,25 @@ class FindCapturedVars : public ASTWalker { } } + if (auto expansion = dyn_cast(E)) { + if (auto *env = expansion->getGenericEnvironment()) { + assert(VisitingEnvironments.count(env) == 0); + VisitingEnvironments.insert(env); + } + } + + return Action::Continue(E); + } + + PostWalkResult walkToExprPost(Expr *E) override { + if (auto expansion = dyn_cast(E)) { + if (auto *env = expansion->getGenericEnvironment()) { + assert(env == VisitingEnvironments.back()); + VisitingEnvironments.pop_back(); + (void) env; + } + } + return Action::Continue(E); } }; diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 11d4b97e8e348..03b2394ea6242 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -60,6 +60,9 @@ using namespace swift; #define DEBUG_TYPE "TypeCheckStmt" namespace { + /// After forming autoclosures, we must re-parent any closure expressions + /// nested inside the autoclosure, because the autoclosure introduces a new + /// DeclContext. class ContextualizeClosuresAndMacros : public ASTWalker { DeclContext *ParentDC; public: @@ -70,16 +73,10 @@ namespace { } PreWalkResult walkToExprPre(Expr *E) override { - // Autoclosures need to be numbered and potentially reparented. - // Reparenting is required with: - // - nested autoclosures, because the inner autoclosure will be - // parented to the outer context, not the outer autoclosure - // - non-local initializers if (auto CE = dyn_cast(E)) { CE->setParent(ParentDC); - // Recurse into the autoclosure body using the same sequence, - // but parenting to the autoclosure instead of the outer closure. + // Recurse into the autoclosure body with the new ParentDC. auto oldParentDC = ParentDC; ParentDC = CE; CE->getBody()->walk(*this); @@ -103,13 +100,12 @@ namespace { } } - // Explicit closures start their own sequence. if (auto CE = dyn_cast(E)) { CE->setParent(ParentDC); // If the closure was type checked within its enclosing context, - // we need to walk into it with a new sequence. - // Otherwise, it'll have been separately type-checked. + // we need to walk into it. Otherwise, it'll have been separately + // type-checked. if (!CE->isSeparatelyTypeChecked()) CE->getBody()->walk(ContextualizeClosuresAndMacros(CE)); diff --git a/test/Constraints/pack-expansion-expressions.swift b/test/Constraints/pack-expansion-expressions.swift index 723065d78ef66..e222b7756d23d 100644 --- a/test/Constraints/pack-expansion-expressions.swift +++ b/test/Constraints/pack-expansion-expressions.swift @@ -608,9 +608,8 @@ func test_that_expansions_are_bound_early() { do { func test(x: T) {} - // rdar://110711746 to make this valid func caller1(x: repeat each T) { - _ = (repeat { test(x: each x) }()) // expected-error {{pack reference 'each T' can only appear in pack expansion}} + _ = (repeat { test(x: each x) }()) } func caller2(x: repeat each T) { diff --git a/test/SILGen/partial_apply_protocol.swift b/test/SILGen/partial_apply_protocol.swift index 191ac73384ba8..dd207df4df688 100644 --- a/test/SILGen/partial_apply_protocol.swift +++ b/test/SILGen/partial_apply_protocol.swift @@ -54,8 +54,6 @@ func testClonable(c: Clonable) { //===----------------------------------------------------------------------===// // Partial apply of methods returning Self-derived types from generic context -// -// Make sure the thunk only has the context generic parameters if needed! //===----------------------------------------------------------------------===// // CHECK-LABEL: sil hidden [ossa] @$s22partial_apply_protocol28testClonableInGenericContext1c1tyAA0E0_p_xtlF : $@convention(thin) (@in_guaranteed any Clonable, @in_guaranteed T) -> () @@ -75,8 +73,8 @@ func testClonableInGenericContext(c: Clonable, t: T) { // CHECK: [[METHOD_FN:%.*]] = witness_method $@opened("{{.*}}", any Clonable) Self, #Clonable.getCloneFn : // CHECK: [[RESULT:%.*]] = apply [[METHOD_FN]]<@opened("{{.*}}", any Clonable) Self>({{.*}}) // CHECK: [[RESULT_CONV:%.*]] = convert_function [[RESULT]] - // CHECK: [[THUNK_FN:%.*]] = function_ref @$sxIegr_22partial_apply_protocol8Clonable_pIegr_AaBRzlTR : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@guaranteed @callee_guaranteed () -> @out τ_0_0) -> @out any Clonable - // CHECK: [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]<@opened("{{.*}}", any Clonable) Self>([[RESULT_CONV]]) : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@guaranteed @callee_guaranteed () -> @out τ_0_0) -> @out any Clonable + // CHECK: [[THUNK_FN:%.*]] = function_ref @$sqd__Iegr_22partial_apply_protocol8Clonable_pIegr_AaBRd__r__lTR : $@convention(thin) <τ_0_0><τ_1_0 where τ_1_0 : Clonable> (@guaranteed @callee_guaranteed () -> @out τ_1_0) -> @out any Clonable + // CHECK: [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]([[RESULT_CONV]]) : $@convention(thin) <τ_0_0><τ_1_0 where τ_1_0 : Clonable> (@guaranteed @callee_guaranteed () -> @out τ_1_0) -> @out any Clonable let _: () -> Clonable = c.getCloneFn() // CHECK: [[THUNK_FN:%.*]] = function_ref @$s22partial_apply_protocol28testClonableInGenericContext1c1tyAA0E0_p_xtlFAaE_pycycAaE_pcfu5_ : $@convention(thin) (@in_guaranteed any Clonable) -> @owned @callee_guaranteed () -> @owned @callee_guaranteed () -> @out any Clonable diff --git a/test/SILGen/variadic-generic-reabstract-tuple-result.swift b/test/SILGen/variadic-generic-reabstract-tuple-result.swift index 77dc2274d1106..0006ed5d529f1 100644 --- a/test/SILGen/variadic-generic-reabstract-tuple-result.swift +++ b/test/SILGen/variadic-generic-reabstract-tuple-result.swift @@ -312,7 +312,7 @@ func test11() -> Use { // CHECK-NEXT: [[DEST_ELT_ADDR:%.*]] = pack_element_get [[EXPANSION_INDEX]] of %0 : $*Pack{repeat @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> Bool for } as $*@callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> Bool for <@pack_element([[UUID]]) each T> // CHECK-NEXT: [[ESCAPING_ELT:%.*]] = convert_function [[ELT]] // CHECK-NEXT: // function_ref -// CHECK-NEXT: [[THUNK:%.*]] = function_ref @$sxSbIegnr_xSbIegnd_lTR : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0, @guaranteed @callee_guaranteed (@in_guaranteed τ_0_0) -> @out Bool) -> Bool +// CHECK-NEXT: [[THUNK:%.*]] = function_ref @$sqd__SbIegnr_qd__SbIegnd_Rvzr__lTR : $@convention(thin) <τ_1_0> (@in_guaranteed τ_1_0, @guaranteed @callee_guaranteed (@in_guaranteed τ_1_0) -> @out Bool) -> Bool // CHECK-NEXT: [[CONVERTED_ELT:%.*]] = partial_apply // CHECK-NEXT: [[CONVERTED_ELT_2:%.*]] = convert_function [[CONVERTED_ELT]] // CHECK-NEXT: store [[CONVERTED_ELT_2]] to [init] [[DEST_ELT_ADDR]] : diff --git a/test/SILGen/variadic-generic-reabstraction.swift b/test/SILGen/variadic-generic-reabstraction.swift index 4c9532cc4f2e1..57155ee3ee2fb 100644 --- a/test/SILGen/variadic-generic-reabstraction.swift +++ b/test/SILGen/variadic-generic-reabstraction.swift @@ -27,8 +27,8 @@ func forwardAndReabstractFunctionPack(functions: repeat (each T) -> Bool // CHECK-NEXT: [[COPY_CONVERT:%.*]] = convert_function [[COPY]] : $@noescape @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> Bool for <@pack_element([[UUID]]) each T> to $@noescape @callee_guaranteed (@in_guaranteed @pack_element([[UUID]]) each T) -> Bool // Wrap in the conversion thunk. // CHECK-NEXT: // function_ref -// CHECK-NEXT: [[THUNK:%.*]] = function_ref @$sxSbIgnd_xSbIegnr_lTR : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0, @guaranteed @noescape @callee_guaranteed (@in_guaranteed τ_0_0) -> Bool) -> @out Bool -// CHECK-NEXT: [[THUNKED:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]<@pack_element([[UUID]]) each T>([[COPY_CONVERT]]) +// CHECK-NEXT: [[THUNK:%.*]] = function_ref @$sqd__SbIgnd_qd__SbIegnr_Rvzr__lTR : $@convention(thin) <τ_1_0> (@in_guaranteed τ_1_0, @guaranteed @noescape @callee_guaranteed (@in_guaranteed τ_1_0) -> Bool) -> @out Bool +// CHECK-NEXT: [[THUNKED:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]([[COPY_CONVERT]]) // Convert to a substituted type. // CHECK-NEXT: [[THUNKED_CONVERT:%.*]] = convert_function [[THUNKED]] : $@callee_guaranteed (@in_guaranteed @pack_element([[UUID]]) each T) -> @out Bool to $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <@pack_element([[UUID]]) each T, Bool> // Convert to noescape.