diff --git a/include/swift/Remote/MemoryReader.h b/include/swift/Remote/MemoryReader.h index 5c5669feec64c..f9bbdf1fffacf 100644 --- a/include/swift/Remote/MemoryReader.h +++ b/include/swift/Remote/MemoryReader.h @@ -149,19 +149,32 @@ class MemoryReader { return RemoteAbsolutePointer("", readValue); } - /// Atempt to resolve the pointer to a symbol for the given remote address. virtual llvm::Optional resolvePointerAsSymbol(RemoteAddress address) { return llvm::None; } + /// Lookup a symbol for the given remote address. + virtual RemoteAbsolutePointer getSymbol(RemoteAddress address) { + if (auto symbol = resolvePointerAsSymbol(address)) + return *symbol; + return RemoteAbsolutePointer("", address.getAddressData()); + } + + /// Lookup a dynamic symbol name (ie dynamic loader binding) for the given + /// remote address. Note: An address can be referenced by both dynamic and + /// regular symbols, this function must return a dynamic symbol only. + virtual RemoteAbsolutePointer getDynamicSymbol(RemoteAddress address) { + return nullptr; + } + /// Attempt to read and resolve a pointer value at the given remote address. llvm::Optional readPointer(RemoteAddress address, unsigned pointerSize) { - // Try to resolve the pointer as a symbol first, as reading memory - // may potentially be expensive. - if (auto symbolPointer = resolvePointerAsSymbol(address)) - return symbolPointer; + // First, try to lookup the pointer as a dynamic symbol (binding), as + // reading memory may potentially be expensive. + if (auto dynamicSymbol = getDynamicSymbol(address)) + return dynamicSymbol; auto result = readBytes(address, pointerSize); if (!result) diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h index bf1b979b80fe8..265cf2d67b9ec 100644 --- a/include/swift/Remote/MetadataReader.h +++ b/include/swift/Remote/MetadataReader.h @@ -420,11 +420,7 @@ class MetadataReader { return nullptr; } } else { - resolved = Reader->resolvePointer(RemoteAddress(remoteAddress), 0); - if (resolved.getSymbol().empty()) { - // No symbol found, use the already calculated address. - resolved = RemoteAbsolutePointer("", remoteAddress); - } + resolved = Reader->getSymbol(RemoteAddress(remoteAddress)); } switch (kind) { diff --git a/include/swift/SIL/TypeLowering.h b/include/swift/SIL/TypeLowering.h index 5d0788f8b7b72..7686bc4e36b38 100644 --- a/include/swift/SIL/TypeLowering.h +++ b/include/swift/SIL/TypeLowering.h @@ -1204,6 +1204,39 @@ CanSILFunctionType getNativeSILFunctionType( Optional reqtSubs = None, ProtocolConformanceRef witnessMethodConformance = ProtocolConformanceRef()); +/// The thunk kinds used in the differentiation transform. +enum class DifferentiationThunkKind { + /// A reabstraction thunk. + /// + /// Reabstraction thunks transform a function-typed value to another one with + /// different parameter/result abstraction patterns. This is identical to the + /// thunks generated by SILGen. + Reabstraction, + + /// An index subset thunk. + /// + /// An index subset thunk is used transform JVP/VJPs into a version that is + /// "wrt" fewer differentiation parameters. + /// - Differentials of thunked JVPs use zero for non-requested differentiation + /// parameters. + /// - Pullbacks of thunked VJPs discard results for non-requested + /// differentiation parameters. + IndexSubset +}; + +/// Build the type of a function transformation thunk. +CanSILFunctionType buildSILFunctionThunkType( + SILFunction *fn, + CanSILFunctionType &sourceType, + CanSILFunctionType &expectedType, + CanType &inputSubstType, + CanType &outputSubstType, + GenericEnvironment *&genericEnv, + SubstitutionMap &interfaceSubs, + CanType &dynamicSelfType, + bool withoutActuallyEscaping, + Optional differentiationThunkKind = None); + } // namespace swift namespace llvm { diff --git a/include/swift/SILOptimizer/Differentiation/Thunk.h b/include/swift/SILOptimizer/Differentiation/Thunk.h index 203848211ec53..02aa54f56c714 100644 --- a/include/swift/SILOptimizer/Differentiation/Thunk.h +++ b/include/swift/SILOptimizer/Differentiation/Thunk.h @@ -47,41 +47,6 @@ class ADContext; // moved to a shared location. //===----------------------------------------------------------------------===// -/// The thunk kinds used in the differentiation transform. -enum class DifferentiationThunkKind { - /// A reabstraction thunk. - /// - /// Reabstraction thunks transform a function-typed value to another one with - /// different parameter/result abstraction patterns. This is identical to the - /// thunks generated by SILGen. - Reabstraction, - - /// An index subset thunk. - /// - /// An index subset thunk is used transform JVP/VJPs into a version that is - /// "wrt" fewer differentiation parameters. - /// - Differentials of thunked JVPs use zero for non-requested differentiation - /// parameters. - /// - Pullbacks of thunked VJPs discard results for non-requested - /// differentiation parameters. - IndexSubset -}; - -CanGenericSignature buildThunkSignature(SILFunction *fn, bool inheritGenericSig, - OpenedArchetypeType *openedExistential, - GenericEnvironment *&genericEnv, - SubstitutionMap &contextSubs, - SubstitutionMap &interfaceSubs, - ArchetypeType *&newArchetype); - -/// Build the type of a function transformation thunk. -CanSILFunctionType buildThunkType(SILFunction *fn, - CanSILFunctionType &sourceType, - CanSILFunctionType &expectedType, - GenericEnvironment *&genericEnv, - SubstitutionMap &interfaceSubs, - bool withoutActuallyEscaping, - DifferentiationThunkKind thunkKind); /// Get or create a reabstraction thunk from `fromType` to `toType`, to be /// called in `caller`. diff --git a/include/swift/StaticMirror/ObjectFileContext.h b/include/swift/StaticMirror/ObjectFileContext.h index 517b3690164ce..dbf0941c15c41 100644 --- a/include/swift/StaticMirror/ObjectFileContext.h +++ b/include/swift/StaticMirror/ObjectFileContext.h @@ -70,6 +70,8 @@ class Image { remote::RemoteAbsolutePointer resolvePointer(uint64_t Addr, uint64_t pointerValue) const; + + remote::RemoteAbsolutePointer getDynamicSymbol(uint64_t Addr) const; }; /// MemoryReader that reads from the on-disk representation of an executable @@ -118,6 +120,9 @@ class ObjectMemoryReader : public reflection::MemoryReader { remote::RemoteAbsolutePointer resolvePointer(reflection::RemoteAddress Addr, uint64_t pointerValue) override; + + remote::RemoteAbsolutePointer + getDynamicSymbol(reflection::RemoteAddress Addr) override; }; using ReflectionContextOwner = std::unique_ptr; diff --git a/lib/AST/RequirementMachine/GenericSignatureQueries.cpp b/lib/AST/RequirementMachine/GenericSignatureQueries.cpp index 4740ff6539259..7813c3fc53fbb 100644 --- a/lib/AST/RequirementMachine/GenericSignatureQueries.cpp +++ b/lib/AST/RequirementMachine/GenericSignatureQueries.cpp @@ -239,7 +239,8 @@ RequirementMachine::getLongestValidPrefix(const MutableTerm &term) const { case Symbol::Kind::Superclass: case Symbol::Kind::ConcreteType: case Symbol::Kind::ConcreteConformance: - llvm_unreachable("Property symbol cannot appear in a type term"); + llvm::errs() <<"Invalid symbol in a type term: " << term << "\n"; + abort(); } // This symbol is valid, add it to the longest prefix. @@ -265,6 +266,9 @@ bool RequirementMachine::isCanonicalTypeInContext(Type type) const { explicit Walker(const RequirementMachine &self) : Self(self) {} Action walkToTypePre(Type component) override { + if (!component->hasTypeParameter()) + return Action::SkipChildren; + if (!component->isTypeParameter()) return Action::Continue; @@ -305,6 +309,9 @@ Type RequirementMachine::getCanonicalTypeInContext( TypeArrayView genericParams) const { return type.transformRec([&](Type t) -> Optional { + if (!t->hasTypeParameter()) + return t; + if (!t->isTypeParameter()) return None; diff --git a/lib/AST/RequirementMachine/HomotopyReduction.cpp b/lib/AST/RequirementMachine/HomotopyReduction.cpp index 907ca6dddb7a4..cf5ec036bbdfc 100644 --- a/lib/AST/RequirementMachine/HomotopyReduction.cpp +++ b/lib/AST/RequirementMachine/HomotopyReduction.cpp @@ -65,23 +65,30 @@ using namespace swift; using namespace rewriting; -/// Recompute Useful, RulesInEmptyContext, ProjectionCount and DecomposeCount -/// if needed. +/// Recompute various cached values if needed. void RewriteLoop::recompute(const RewriteSystem &system) { if (!Dirty) return; Dirty = 0; + Useful = 0; ProjectionCount = 0; DecomposeCount = 0; - Useful = false; + HasConcreteTypeAliasRule = 0; RewritePathEvaluator evaluator(Basepoint); for (auto step : Path) { switch (step.Kind) { - case RewriteStep::Rule: + case RewriteStep::Rule: { Useful |= (!step.isInContext() && !evaluator.isInContext()); + + const auto &rule = system.getRule(step.getRuleID()); + if (rule.isProtocolTypeAliasRule() && + rule.getLHS().size() == 3) + HasConcreteTypeAliasRule = 1; + break; + } case RewriteStep::LeftConcreteProjection: ++ProjectionCount; @@ -130,6 +137,14 @@ unsigned RewriteLoop::getDecomposeCount( return DecomposeCount; } +/// Returns true if the loop contains at least one concrete protocol typealias rule, +/// which have the form ([P].A.[concrete: C] => [P].A). +bool RewriteLoop::hasConcreteTypeAliasRule( + const RewriteSystem &system) const { + const_cast(this)->recompute(system); + return HasConcreteTypeAliasRule; +} + /// The number of Decompose steps, used by the elimination order to prioritize /// loops that are not concrete simplifications. bool RewriteLoop::isUseful( @@ -488,7 +503,7 @@ RewritePath::getRulesInEmptyContext(const MutableTerm &term, /// \p redundantConformances equal to the set of conformance rules that are /// not minimal conformances. Optional> RewriteSystem:: -findRuleToDelete(llvm::function_ref isRedundantRuleFn) { +findRuleToDelete(EliminationPredicate isRedundantRuleFn) { SmallVector, 2> redundancyCandidates; for (unsigned loopID : indices(Loops)) { auto &loop = Loops[loopID]; @@ -520,7 +535,10 @@ findRuleToDelete(llvm::function_ref isRedundantRuleFn) { } for (const auto &pair : redundancyCandidates) { + unsigned loopID = pair.first; unsigned ruleID = pair.second; + + const auto &loop = Loops[loopID]; const auto &rule = getRule(ruleID); // We should not find a rule that has already been marked redundant @@ -538,10 +556,10 @@ findRuleToDelete(llvm::function_ref isRedundantRuleFn) { // Homotopy reduction runs multiple passes with different filters to // prioritize the deletion of certain rules ahead of others. Apply // the filter now. - if (!isRedundantRuleFn(ruleID)) { + if (!isRedundantRuleFn(loopID, ruleID)) { if (Debug.contains(DebugFlags::HomotopyReductionDetail)) { llvm::dbgs() << "** Skipping rule " << rule << " from loop #" - << pair.first << "\n"; + << loopID << "\n"; } continue; @@ -549,7 +567,7 @@ findRuleToDelete(llvm::function_ref isRedundantRuleFn) { if (Debug.contains(DebugFlags::HomotopyReductionDetail)) { llvm::dbgs() << "** Candidate rule " << rule << " from loop #" - << pair.first << "\n"; + << loopID << "\n"; } if (!found) { @@ -561,7 +579,6 @@ findRuleToDelete(llvm::function_ref isRedundantRuleFn) { // we've found so far. const auto &otherRule = getRule(found->second); - const auto &loop = Loops[pair.first]; const auto &otherLoop = Loops[found->first]; { @@ -712,7 +729,7 @@ void RewriteSystem::deleteRule(unsigned ruleID, } void RewriteSystem::performHomotopyReduction( - llvm::function_ref isRedundantRuleFn) { + EliminationPredicate isRedundantRuleFn) { while (true) { auto optPair = findRuleToDelete(isRedundantRuleFn); @@ -803,14 +820,21 @@ void RewriteSystem::minimizeRewriteSystem() { // First pass: // - Eliminate all LHS-simplified non-conformance rules. // - Eliminate all RHS-simplified and substitution-simplified rules. - // - Eliminate all rules with unresolved symbols. + // + // An example of a conformance rule that is LHS-simplified but not + // RHS-simplified is (T.[P] => T) where T is irreducible, but there + // is a rule (V.[P] => V) for some V with T == U.V. + // + // Such conformance rules can still be minimal, as part of a hack to + // maintain compatibility with the GenericSignatureBuilder's minimization + // algorithm. if (Debug.contains(DebugFlags::HomotopyReduction)) { - llvm::dbgs() << "---------------------------------------------\n"; - llvm::dbgs() << "First pass: simplified and unresolved rules -\n"; - llvm::dbgs() << "---------------------------------------------\n"; + llvm::dbgs() << "------------------------------\n"; + llvm::dbgs() << "First pass: simplified rules -\n"; + llvm::dbgs() << "------------------------------\n"; } - performHomotopyReduction([&](unsigned ruleID) -> bool { + performHomotopyReduction([&](unsigned loopID, unsigned ruleID) -> bool { const auto &rule = getRule(ruleID); if (rule.isLHSSimplified() && @@ -821,8 +845,31 @@ void RewriteSystem::minimizeRewriteSystem() { rule.isSubstitutionSimplified()) return true; - if (rule.containsUnresolvedSymbols() && - !rule.isProtocolTypeAliasRule()) + return false; + }); + + // Second pass: + // - Eliminate all rules with unresolved symbols which were *not* + // simplified. + // + // Two examples of such rules: + // + // - (T.X => T.[P:X]) obtained from resolving the overlap between + // (T.[P] => T) and ([P].X => [P:X]). + // + // - (T.X.[concrete: C] => T.X) obtained from resolving the overlap + // between (T.[P] => T) and a protocol typealias rule + // ([P].X.[concrete: C] => [P].X). + if (Debug.contains(DebugFlags::HomotopyReduction)) { + llvm::dbgs() << "-------------------------------\n"; + llvm::dbgs() << "Second pass: unresolved rules -\n"; + llvm::dbgs() << "-------------------------------\n"; + } + + performHomotopyReduction([&](unsigned loopID, unsigned ruleID) -> bool { + const auto &rule = getRule(ruleID); + + if (rule.containsUnresolvedSymbols()) return true; return false; @@ -838,14 +885,14 @@ void RewriteSystem::minimizeRewriteSystem() { llvm::DenseSet redundantConformances; computeMinimalConformances(redundantConformances); - // Second pass: Eliminate all non-minimal conformance rules. + // Third pass: Eliminate all non-minimal conformance rules. if (Debug.contains(DebugFlags::HomotopyReduction)) { - llvm::dbgs() << "--------------------------------------------\n"; - llvm::dbgs() << "Second pass: non-minimal conformance rules -\n"; - llvm::dbgs() << "--------------------------------------------\n"; + llvm::dbgs() << "-------------------------------------------\n"; + llvm::dbgs() << "Third pass: non-minimal conformance rules -\n"; + llvm::dbgs() << "-------------------------------------------\n"; } - performHomotopyReduction([&](unsigned ruleID) -> bool { + performHomotopyReduction([&](unsigned loopID, unsigned ruleID) -> bool { const auto &rule = getRule(ruleID); if (rule.isAnyConformanceRule() && @@ -855,17 +902,22 @@ void RewriteSystem::minimizeRewriteSystem() { return false; }); - // Third pass: Eliminate all other redundant non-conformance rules. + // Fourth pass: Eliminate all remaining redundant non-conformance rules. if (Debug.contains(DebugFlags::HomotopyReduction)) { - llvm::dbgs() << "---------------------------------------\n"; - llvm::dbgs() << "Third pass: all other redundant rules -\n"; - llvm::dbgs() << "---------------------------------------\n"; + llvm::dbgs() << "----------------------------------------\n"; + llvm::dbgs() << "Fourth pass: all other redundant rules -\n"; + llvm::dbgs() << "----------------------------------------\n"; } - performHomotopyReduction([&](unsigned ruleID) -> bool { + performHomotopyReduction([&](unsigned loopID, unsigned ruleID) -> bool { + const auto &loop = Loops[loopID]; const auto &rule = getRule(ruleID); - if (!rule.isAnyConformanceRule()) + if (rule.isProtocolTypeAliasRule()) + return true; + + if (!loop.hasConcreteTypeAliasRule(*this) && + !rule.isAnyConformanceRule()) return true; return false; diff --git a/lib/AST/RequirementMachine/InterfaceType.cpp b/lib/AST/RequirementMachine/InterfaceType.cpp index 8f6438782305f..bb8376573aac5 100644 --- a/lib/AST/RequirementMachine/InterfaceType.cpp +++ b/lib/AST/RequirementMachine/InterfaceType.cpp @@ -311,7 +311,8 @@ getTypeForSymbolRange(const Symbol *begin, const Symbol *end, Type root, case Symbol::Kind::Superclass: case Symbol::Kind::ConcreteType: case Symbol::Kind::ConcreteConformance: - llvm_unreachable("Term has invalid root symbol"); + llvm::errs() << "Invalid root symbol: " << MutableTerm(begin, end) << "\n"; + abort(); } } diff --git a/lib/AST/RequirementMachine/MinimalConformances.cpp b/lib/AST/RequirementMachine/MinimalConformances.cpp index 566de47b3cd86..bc5121af4d0d8 100644 --- a/lib/AST/RequirementMachine/MinimalConformances.cpp +++ b/lib/AST/RequirementMachine/MinimalConformances.cpp @@ -365,7 +365,8 @@ static const ProtocolDecl *getParentConformanceForTerm(Term lhs) { break; } - llvm_unreachable("Bad symbol kind"); + llvm::errs() << "Bad symbol in " << lhs << "\n"; + abort(); } /// Collect conformance rules and parent paths, and record an initial diff --git a/lib/AST/RequirementMachine/RewriteContext.h b/lib/AST/RequirementMachine/RewriteContext.h index b9558b6d2fccc..67843f758f291 100644 --- a/lib/AST/RequirementMachine/RewriteContext.h +++ b/lib/AST/RequirementMachine/RewriteContext.h @@ -55,9 +55,6 @@ class RewriteContext final { /// Cache for associated type declarations. llvm::DenseMap AssocTypes; - /// Cache for merged associated type symbols. - llvm::DenseMap, Symbol> MergedAssocTypes; - /// Requirement machines built from generic signatures. llvm::DenseMap Machines; diff --git a/lib/AST/RequirementMachine/RewriteLoop.h b/lib/AST/RequirementMachine/RewriteLoop.h index 1acf62d0cc627..0f02aecb6f4e1 100644 --- a/lib/AST/RequirementMachine/RewriteLoop.h +++ b/lib/AST/RequirementMachine/RewriteLoop.h @@ -457,6 +457,9 @@ class RewriteLoop { /// Cached value for getDecomposeCount(). unsigned DecomposeCount : 15; + /// Cached value for hasConcreteTypeAliasRule(). + unsigned HasConcreteTypeAliasRule : 1; + /// A useful loop contains at least one rule in empty context, even if that /// rule appears multiple times or also in non-empty context. The only loops /// that are elimination candidates contain a rule in empty context *exactly @@ -478,6 +481,7 @@ class RewriteLoop { : Basepoint(basepoint), Path(path) { ProjectionCount = 0; DecomposeCount = 0; + HasConcreteTypeAliasRule = 0; Useful = 0; Deleted = 0; @@ -509,6 +513,8 @@ class RewriteLoop { unsigned getDecomposeCount(const RewriteSystem &system) const; + bool hasConcreteTypeAliasRule(const RewriteSystem &system) const; + void findProtocolConformanceRules( llvm::SmallDenseMap &result, diff --git a/lib/AST/RequirementMachine/RewriteSystem.cpp b/lib/AST/RequirementMachine/RewriteSystem.cpp index 460374bba245a..aea7be104c992 100644 --- a/lib/AST/RequirementMachine/RewriteSystem.cpp +++ b/lib/AST/RequirementMachine/RewriteSystem.cpp @@ -174,8 +174,13 @@ Optional Rule::isProtocolTypeAliasRule() const { // // We shouldn't have unresolved symbols on the right hand side; // they should have been simplified away. - if (RHS.containsUnresolvedSymbols()) - return None; + if (RHS.containsUnresolvedSymbols()) { + if (RHS.size() != 2 || + RHS[0] != LHS[0] || + RHS[1].getKind() != Symbol::Kind::Name) { + return None; + } + } } else { // This is the case where the underlying type is concrete. assert(LHS.size() == 3); @@ -660,6 +665,28 @@ void RewriteSystem::verifyRewriteRules(ValidityPolicy policy) const { for (unsigned index : indices(lhs)) { auto symbol = lhs[index]; + // The left hand side can contain a single name symbol if it has the form + // T.N or T.N.[p], where T is some prefix that does not contain name + // symbols, N is a name symbol, and [p] is an optional property symbol. + // + // In the latter case, we have a protocol typealias, or a rule derived + // via resolving a critical pair involving a protocol typealias. + // + // Any other valid occurrence of a name symbol should have been reduced by + // an associated type introduction rule [P].N, marking the rule as + // LHS-simplified. + if (!rule.isLHSSimplified() && + (rule.isPropertyRule() + ? index != lhs.size() - 2 + : index != lhs.size() - 1)) { + // This is only true if the input requirements were valid. + if (policy == DisallowInvalidRequirements) { + ASSERT_RULE(symbol.getKind() != Symbol::Kind::Name); + } else { + // FIXME: Assert that we diagnosed an error + } + } + if (index != lhs.size() - 1) { ASSERT_RULE(symbol.getKind() != Symbol::Kind::Layout); ASSERT_RULE(!symbol.hasSubstitutions()); @@ -677,14 +704,18 @@ void RewriteSystem::verifyRewriteRules(ValidityPolicy policy) const { for (unsigned index : indices(rhs)) { auto symbol = rhs[index]; - // RHS-simplified rules might have unresolved name symbols on the - // right hand side. Also, completion can introduce rules of the - // form T.X.[concrete: C] => T.X, where T is some resolved term, - // and X is a name symbol for a protocol typealias. - if (!rule.isLHSSimplified() && - !rule.isRHSSimplified() && - !(rule.isPropertyRule() && - index == rhs.size() - 1)) { + // The right hand side can contain a single name symbol if it has the form + // T.N, where T is some prefix that does not contain name symbols, and + // N is a name symbol. + // + // In this case, we have a protocol typealias, or a rule derived via + // resolving a critical pair involving a protocol typealias. + // + // Any other valid occurrence of a name symbol should have been reduced by + // an associated type introduction rule [P].N, marking the rule as + // RHS-simplified. + if (!rule.isRHSSimplified() && + index != rhs.size() - 1) { // This is only true if the input requirements were valid. if (policy == DisallowInvalidRequirements) { ASSERT_RULE(symbol.getKind() != Symbol::Kind::Name); diff --git a/lib/AST/RequirementMachine/RewriteSystem.h b/lib/AST/RequirementMachine/RewriteSystem.h index 7f8aaee7ff59a..9bb34d39cd8c0 100644 --- a/lib/AST/RequirementMachine/RewriteSystem.h +++ b/lib/AST/RequirementMachine/RewriteSystem.h @@ -506,13 +506,15 @@ class RewriteSystem final { void processConflicts(); + using EliminationPredicate = llvm::function_ref; + Optional> - findRuleToDelete(llvm::function_ref isRedundantRuleFn); + findRuleToDelete(EliminationPredicate isRedundantRuleFn); void deleteRule(unsigned ruleID, const RewritePath &replacementPath); - void performHomotopyReduction( - llvm::function_ref isRedundantRuleFn); + void performHomotopyReduction(EliminationPredicate isRedundantRuleFn); void computeMinimalConformances( llvm::DenseSet &redundantConformances); diff --git a/lib/AST/RequirementMachine/Symbol.cpp b/lib/AST/RequirementMachine/Symbol.cpp index a4b673d224336..aaed85436786a 100644 --- a/lib/AST/RequirementMachine/Symbol.cpp +++ b/lib/AST/RequirementMachine/Symbol.cpp @@ -596,7 +596,8 @@ Symbol Symbol::withConcreteSubstitutions( break; } - llvm_unreachable("Bad symbol kind"); + llvm::errs() << "Bad symbol kind: " << *this << "\n"; + abort(); } /// For a superclass or concrete type symbol diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index 5814afc8da214..29d0886122df6 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -999,15 +999,20 @@ bool NameImporter::hasNamingConflict(const clang::NamedDecl *decl, lookupResult.setAllowHidden(true); lookupResult.suppressDiagnostics(); - if (clangSema.LookupName(lookupResult, /*scope=*/nullptr)) { + if (clangSema.LookupName(lookupResult, /*scope=*/clangSema.TUScope)) { if (std::any_of(lookupResult.begin(), lookupResult.end(), conflicts)) return true; } - lookupResult.clear(clang::Sema::LookupTagName); - if (clangSema.LookupName(lookupResult, /*scope=*/nullptr)) { - if (std::any_of(lookupResult.begin(), lookupResult.end(), conflicts)) - return true; + // No need to lookup tags if we are using C++ mode. + if (!clang::LangStandard::getLangStandardForKind( + clangSema.getLangOpts().LangStd) + .isCPlusPlus()) { + lookupResult.clear(clang::Sema::LookupTagName); + if (clangSema.LookupName(lookupResult, /*scope=*/nullptr)) { + if (std::any_of(lookupResult.begin(), lookupResult.end(), conflicts)) + return true; + } } return false; diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index effb56794365d..4700f442372dd 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -2407,6 +2407,296 @@ CanSILFunctionType swift::getNativeSILFunctionType( substConstant, reqtSubs, witnessMethodConformance, None); } +/// Build a generic signature and environment for a re-abstraction thunk. +/// +/// Most thunks share the generic environment with their original function. +/// The one exception is if the thunk type involves an open existential, +/// in which case we "promote" the opened existential to a new generic parameter. +/// +/// \param SGF - the parent function +/// \param openedExistential - the opened existential to promote to a generic +// parameter, if any +/// \param inheritGenericSig - whether to inherit the generic signature from the +/// parent function. +/// \param genericEnv - the new generic environment +/// \param contextSubs - map old archetypes to new archetypes +/// \param interfaceSubs - map interface types to old archetypes +static CanGenericSignature +buildThunkSignature(SILFunction *fn, + bool inheritGenericSig, + OpenedArchetypeType *openedExistential, + GenericEnvironment *&genericEnv, + SubstitutionMap &contextSubs, + SubstitutionMap &interfaceSubs, + ArchetypeType *&newArchetype) { + auto *mod = fn->getModule().getSwiftModule(); + auto &ctx = mod->getASTContext(); + + // If there's no opened existential, we just inherit the generic environment + // from the parent function. + if (openedExistential == nullptr) { + auto genericSig = + fn->getLoweredFunctionType()->getInvocationGenericSignature(); + genericEnv = fn->getGenericEnvironment(); + interfaceSubs = fn->getForwardingSubstitutionMap(); + contextSubs = interfaceSubs; + return genericSig; + } + + // Add the existing generic signature. + int depth = 0; + GenericSignature baseGenericSig; + if (inheritGenericSig) { + if (auto genericSig = + fn->getLoweredFunctionType()->getInvocationGenericSignature()) { + baseGenericSig = genericSig; + depth = genericSig.getGenericParams().back()->getDepth() + 1; + } + } + + // Add a new generic parameter to replace the opened existential. + auto *newGenericParam = + GenericTypeParamType::get(/*type sequence*/ false, depth, 0, ctx); + + assert(openedExistential->isRoot()); + auto constraint = openedExistential->getExistentialType(); + if (auto existential = constraint->getAs()) + constraint = existential->getConstraintType(); + + Requirement newRequirement(RequirementKind::Conformance, newGenericParam, + constraint); + + auto genericSig = buildGenericSignature(ctx, baseGenericSig, + { newGenericParam }, + { newRequirement }); + genericEnv = genericSig.getGenericEnvironment(); + + newArchetype = genericEnv->mapTypeIntoContext(newGenericParam) + ->castTo(); + + // Calculate substitutions to map the caller's archetypes to the thunk's + // archetypes. + if (auto calleeGenericSig = fn->getLoweredFunctionType() + ->getInvocationGenericSignature()) { + contextSubs = SubstitutionMap::get( + calleeGenericSig, + [&](SubstitutableType *type) -> Type { + return genericEnv->mapTypeIntoContext(type); + }, + MakeAbstractConformanceForGenericType()); + } + + // Calculate substitutions to map interface types to the caller's archetypes. + interfaceSubs = SubstitutionMap::get( + genericSig, + [&](SubstitutableType *type) -> Type { + if (type->isEqual(newGenericParam)) + return openedExistential; + return fn->mapTypeIntoContext(type); + }, + MakeAbstractConformanceForGenericType()); + + return genericSig.getCanonicalSignature(); +} + +/// Build the type of a function transformation thunk. +CanSILFunctionType swift::buildSILFunctionThunkType( + SILFunction *fn, + CanSILFunctionType &sourceType, + CanSILFunctionType &expectedType, + CanType &inputSubstType, + CanType &outputSubstType, + GenericEnvironment *&genericEnv, + SubstitutionMap &interfaceSubs, + CanType &dynamicSelfType, + bool withoutActuallyEscaping, + Optional differentiationThunkKind) { + // We shouldn't be thunking generic types here, and substituted function types + // ought to have their substitutions applied before we get here. + assert(!expectedType->isPolymorphic() && + !expectedType->getCombinedSubstitutions()); + assert(!sourceType->isPolymorphic() && + !sourceType->getCombinedSubstitutions()); + + // This may inherit @noescape from the expectedType. The @noescape attribute + // is only stripped when using this type to materialize a new decl. + auto extInfoBuilder = expectedType->getExtInfo().intoBuilder(); + if (!differentiationThunkKind || + *differentiationThunkKind == DifferentiationThunkKind::Reabstraction || + extInfoBuilder.hasContext()) { + // Can't build a reabstraction thunk without context, so we require + // ownership semantics on the result type. + assert(expectedType->getExtInfo().hasContext()); + + extInfoBuilder = extInfoBuilder.withRepresentation( + SILFunctionType::Representation::Thin); + } + + if (withoutActuallyEscaping) + extInfoBuilder = extInfoBuilder.withNoEscape(false); + + // Does the thunk type involve archetypes other than opened existentials? + bool hasArchetypes = false; + // Does the thunk type involve an open existential type? + CanOpenedArchetypeType openedExistential; + auto archetypeVisitor = [&](CanType t) { + if (auto archetypeTy = dyn_cast(t)) { + if (auto opened = dyn_cast(archetypeTy)) { + const auto root = cast(CanType(opened->getRoot())); + assert((openedExistential == CanArchetypeType() || + openedExistential == root) && + "one too many open existentials"); + openedExistential = root; + } else { + hasArchetypes = true; + } + } + }; + + // Use the generic signature from the context if the thunk involves + // generic parameters. + CanGenericSignature genericSig; + SubstitutionMap contextSubs; + ArchetypeType *newArchetype = nullptr; + + if (expectedType->hasArchetype() || sourceType->hasArchetype()) { + expectedType.visit(archetypeVisitor); + sourceType.visit(archetypeVisitor); + + genericSig = buildThunkSignature(fn, + hasArchetypes, + openedExistential, + genericEnv, + contextSubs, + interfaceSubs, + newArchetype); + } + + auto substTypeHelper = [&](SubstitutableType *type) -> Type { + if (CanType(type) == openedExistential) + return newArchetype; + + // If a nested archetype is rooted on our opened existential, fail: + // Type::subst attempts to substitute the parent of a nested archetype + // only if it fails to find a replacement for the nested one. + if (auto *opened = dyn_cast(type)) { + if (openedExistential->isEqual(opened->getRoot())) { + return nullptr; + } + } + + return Type(type).subst(contextSubs); + }; + auto substConformanceHelper = + LookUpConformanceInSubstitutionMap(contextSubs); + + // Utility function to apply contextSubs, and also replace the + // opened existential with the new archetype. + auto substFormalTypeIntoThunkContext = + [&](CanType t) -> CanType { + return t.subst(substTypeHelper, substConformanceHelper) + ->getCanonicalType(); + }; + auto substLoweredTypeIntoThunkContext = + [&](CanSILFunctionType t) -> CanSILFunctionType { + return SILType::getPrimitiveObjectType(t) + .subst(fn->getModule(), substTypeHelper, substConformanceHelper) + .castTo(); + }; + + sourceType = substLoweredTypeIntoThunkContext(sourceType); + expectedType = substLoweredTypeIntoThunkContext(expectedType); + + bool hasDynamicSelf = false; + + if (inputSubstType) { + inputSubstType = substFormalTypeIntoThunkContext(inputSubstType); + hasDynamicSelf |= inputSubstType->hasDynamicSelfType(); + } + + if (outputSubstType) { + outputSubstType = substFormalTypeIntoThunkContext(outputSubstType); + hasDynamicSelf |= outputSubstType->hasDynamicSelfType(); + } + + hasDynamicSelf |= sourceType->hasDynamicSelfType(); + hasDynamicSelf |= expectedType->hasDynamicSelfType(); + + // If our parent function was pseudogeneric, this thunk must also be + // pseudogeneric, since we have no way to pass generic parameters. + if (genericSig) + if (fn->getLoweredFunctionType()->isPseudogeneric()) + extInfoBuilder = extInfoBuilder.withIsPseudogeneric(); + + // Add the function type as the parameter. + auto contextConvention = + fn->getTypeLowering(sourceType).isTrivial() + ? ParameterConvention::Direct_Unowned + : ParameterConvention::Direct_Guaranteed; + SmallVector params; + params.append(expectedType->getParameters().begin(), + expectedType->getParameters().end()); + + if (!differentiationThunkKind || + *differentiationThunkKind == DifferentiationThunkKind::Reabstraction) { + params.push_back({sourceType, + sourceType->getExtInfo().hasContext() + ? contextConvention + : ParameterConvention::Direct_Unowned}); + } + + // If this thunk involves DynamicSelfType in any way, add a capture for it + // in case we need to recover metadata. + if (hasDynamicSelf) { + dynamicSelfType = fn->getDynamicSelfMetadata()->getType().getASTType(); + if (!isa(dynamicSelfType)) { + dynamicSelfType = CanMetatypeType::get(dynamicSelfType, + MetatypeRepresentation::Thick); + } + params.push_back({dynamicSelfType, ParameterConvention::Direct_Unowned}); + } + + auto mapTypeOutOfContext = [&](CanType type) -> CanType { + return type->mapTypeOutOfContext()->getCanonicalType(genericSig); + }; + + // Map the parameter and expected types out of context to get the interface + // type of the thunk. + SmallVector interfaceParams; + interfaceParams.reserve(params.size()); + for (auto ¶m : params) { + auto interfaceParam = param.map(mapTypeOutOfContext); + interfaceParams.push_back(interfaceParam); + } + + SmallVector interfaceYields; + for (auto &yield : expectedType->getYields()) { + auto interfaceYield = yield.map(mapTypeOutOfContext); + interfaceYields.push_back(interfaceYield); + } + + SmallVector interfaceResults; + for (auto &result : expectedType->getResults()) { + auto interfaceResult = result.map(mapTypeOutOfContext); + interfaceResults.push_back(interfaceResult); + } + + Optional interfaceErrorResult; + if (expectedType->hasErrorResult()) { + auto errorResult = expectedType->getErrorResult(); + interfaceErrorResult = errorResult.map(mapTypeOutOfContext);; + } + + // The type of the thunk function. + return SILFunctionType::get( + genericSig, extInfoBuilder.build(), expectedType->getCoroutineKind(), + ParameterConvention::Direct_Unowned, interfaceParams, interfaceYields, + interfaceResults, interfaceErrorResult, + expectedType->getPatternSubstitutions(), SubstitutionMap(), + fn->getASTContext()); + +} + //===----------------------------------------------------------------------===// // Foreign SILFunctionTypes //===----------------------------------------------------------------------===// diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp index fa1772e7f5ccb..220d6755dd9d1 100644 --- a/lib/SILGen/SILGenPoly.cpp +++ b/lib/SILGen/SILGenPoly.cpp @@ -3001,98 +3001,6 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc, SGF.B.createReturn(loc, outerResult); } -/// Build a generic signature and environment for a re-abstraction thunk. -/// -/// Most thunks share the generic environment with their original function. -/// The one exception is if the thunk type involves an open existential, -/// in which case we "promote" the opened existential to a new generic parameter. -/// -/// \param SGF - the parent function -/// \param openedExistential - the opened existential to promote to a generic -// parameter, if any -/// \param inheritGenericSig - whether to inherit the generic signature from the -/// parent function. -/// \param genericEnv - the new generic environment -/// \param contextSubs - map old archetypes to new archetypes -/// \param interfaceSubs - map interface types to old archetypes -static CanGenericSignature -buildThunkSignature(SILGenFunction &SGF, - bool inheritGenericSig, - OpenedArchetypeType *openedExistential, - GenericEnvironment *&genericEnv, - SubstitutionMap &contextSubs, - SubstitutionMap &interfaceSubs, - ArchetypeType *&newArchetype) { - auto *mod = SGF.F.getModule().getSwiftModule(); - auto &ctx = mod->getASTContext(); - - // If there's no opened existential, we just inherit the generic environment - // from the parent function. - if (openedExistential == nullptr) { - auto genericSig = - SGF.F.getLoweredFunctionType()->getInvocationGenericSignature(); - genericEnv = SGF.F.getGenericEnvironment(); - interfaceSubs = SGF.F.getForwardingSubstitutionMap(); - contextSubs = interfaceSubs; - return genericSig; - } - - // Add the existing generic signature. - int depth = 0; - GenericSignature baseGenericSig; - if (inheritGenericSig) { - if (auto genericSig = - SGF.F.getLoweredFunctionType()->getInvocationGenericSignature()) { - baseGenericSig = genericSig; - depth = genericSig.getGenericParams().back()->getDepth() + 1; - } - } - - // Add a new generic parameter to replace the opened existential. - auto *newGenericParam = - GenericTypeParamType::get(/*type sequence*/ false, depth, 0, ctx); - - assert(openedExistential->isRoot()); - auto constraint = openedExistential->getExistentialType(); - if (auto existential = constraint->getAs()) - constraint = existential->getConstraintType(); - - Requirement newRequirement(RequirementKind::Conformance, newGenericParam, - constraint); - - auto genericSig = buildGenericSignature(ctx, baseGenericSig, - { newGenericParam }, - { newRequirement }); - genericEnv = genericSig.getGenericEnvironment(); - - newArchetype = genericEnv->mapTypeIntoContext(newGenericParam) - ->castTo(); - - // Calculate substitutions to map the caller's archetypes to the thunk's - // archetypes. - if (auto calleeGenericSig = SGF.F.getLoweredFunctionType() - ->getInvocationGenericSignature()) { - contextSubs = SubstitutionMap::get( - calleeGenericSig, - [&](SubstitutableType *type) -> Type { - return genericEnv->mapTypeIntoContext(type); - }, - MakeAbstractConformanceForGenericType()); - } - - // Calculate substitutions to map interface types to the caller's archetypes. - interfaceSubs = SubstitutionMap::get( - genericSig, - [&](SubstitutableType *type) -> Type { - if (type->isEqual(newGenericParam)) - return openedExistential; - return SGF.F.mapTypeIntoContext(type); - }, - MakeAbstractConformanceForGenericType()); - - return genericSig.getCanonicalSignature(); -} - /// Build the type of a function transformation thunk. CanSILFunctionType SILGenFunction::buildThunkType( CanSILFunctionType &sourceType, @@ -3103,181 +3011,7 @@ CanSILFunctionType SILGenFunction::buildThunkType( SubstitutionMap &interfaceSubs, CanType &dynamicSelfType, bool withoutActuallyEscaping) { - // We shouldn't be thunking generic types here, and substituted function types - // ought to have their substitutions applied before we get here. - assert(!expectedType->isPolymorphic() && - !expectedType->getCombinedSubstitutions()); - assert(!sourceType->isPolymorphic() && - !sourceType->getCombinedSubstitutions()); - - // Can't build a thunk without context, so we require ownership semantics - // on the result type. - assert(expectedType->getExtInfo().hasContext()); - - // This may inherit @noescape from the expectedType. The @noescape attribute - // is only stripped when using this type to materialize a new decl. - auto extInfoBuilder = - expectedType->getExtInfo().intoBuilder().withRepresentation( - SILFunctionType::Representation::Thin); - - if (withoutActuallyEscaping) - extInfoBuilder = extInfoBuilder.withNoEscape(false); - - // Does the thunk type involve archetypes other than opened existentials? - bool hasArchetypes = false; - // Does the thunk type involve an open existential type? - CanOpenedArchetypeType openedExistential; - auto archetypeVisitor = [&](CanType t) { - if (auto archetypeTy = dyn_cast(t)) { - if (auto opened = dyn_cast(archetypeTy)) { - const auto root = cast(CanType(opened->getRoot())); - assert((openedExistential == CanArchetypeType() || - openedExistential == root) && - "one too many open existentials"); - openedExistential = root; - } else { - hasArchetypes = true; - } - } - }; - - // Use the generic signature from the context if the thunk involves - // generic parameters. - CanGenericSignature genericSig; - SubstitutionMap contextSubs; - ArchetypeType *newArchetype = nullptr; - - if (expectedType->hasArchetype() || sourceType->hasArchetype()) { - expectedType.visit(archetypeVisitor); - sourceType.visit(archetypeVisitor); - - genericSig = buildThunkSignature(*this, - hasArchetypes, - openedExistential, - genericEnv, - contextSubs, - interfaceSubs, - newArchetype); - } - - auto substTypeHelper = [&](SubstitutableType *type) -> Type { - if (CanType(type) == openedExistential) - return newArchetype; - - // If a nested archetype is rooted on our opened existential, fail: - // Type::subst attempts to substitute the parent of a nested archetype - // only if it fails to find a replacement for the nested one. - if (auto *opened = dyn_cast(type)) { - if (openedExistential->isEqual(opened->getRoot())) { - return nullptr; - } - } - - return Type(type).subst(contextSubs); - }; - auto substConformanceHelper = - LookUpConformanceInSubstitutionMap(contextSubs); - - // Utility function to apply contextSubs, and also replace the - // opened existential with the new archetype. - auto substFormalTypeIntoThunkContext = - [&](CanType t) -> CanType { - return t.subst(substTypeHelper, substConformanceHelper) - ->getCanonicalType(); - }; - auto substLoweredTypeIntoThunkContext = - [&](CanSILFunctionType t) -> CanSILFunctionType { - return SILType::getPrimitiveObjectType(t) - .subst(SGM.M, substTypeHelper, substConformanceHelper) - .castTo(); - }; - - sourceType = substLoweredTypeIntoThunkContext(sourceType); - expectedType = substLoweredTypeIntoThunkContext(expectedType); - - bool hasDynamicSelf = false; - - if (inputSubstType) { - inputSubstType = substFormalTypeIntoThunkContext(inputSubstType); - hasDynamicSelf |= inputSubstType->hasDynamicSelfType(); - } - - if (outputSubstType) { - outputSubstType = substFormalTypeIntoThunkContext(outputSubstType); - hasDynamicSelf |= outputSubstType->hasDynamicSelfType(); - } - - hasDynamicSelf |= sourceType->hasDynamicSelfType(); - hasDynamicSelf |= expectedType->hasDynamicSelfType(); - - // If our parent function was pseudogeneric, this thunk must also be - // pseudogeneric, since we have no way to pass generic parameters. - if (genericSig) - if (F.getLoweredFunctionType()->isPseudogeneric()) - extInfoBuilder = extInfoBuilder.withIsPseudogeneric(); - - // Add the function type as the parameter. - auto contextConvention = - getTypeLowering(sourceType).isTrivial() - ? ParameterConvention::Direct_Unowned - : ParameterConvention::Direct_Guaranteed; - SmallVector params; - params.append(expectedType->getParameters().begin(), - expectedType->getParameters().end()); - params.push_back({sourceType, - sourceType->getExtInfo().hasContext() - ? contextConvention - : ParameterConvention::Direct_Unowned}); - - // If this thunk involves DynamicSelfType in any way, add a capture for it - // in case we need to recover metadata. - if (hasDynamicSelf) { - dynamicSelfType = F.getDynamicSelfMetadata()->getType().getASTType(); - if (!isa(dynamicSelfType)) { - dynamicSelfType = CanMetatypeType::get(dynamicSelfType, - MetatypeRepresentation::Thick); - } - params.push_back({dynamicSelfType, ParameterConvention::Direct_Unowned}); - } - - auto mapTypeOutOfContext = [&](CanType type) -> CanType { - return type->mapTypeOutOfContext()->getCanonicalType(genericSig); - }; - - // Map the parameter and expected types out of context to get the interface - // type of the thunk. - SmallVector interfaceParams; - interfaceParams.reserve(params.size()); - for (auto ¶m : params) { - auto interfaceParam = param.map(mapTypeOutOfContext); - interfaceParams.push_back(interfaceParam); - } - - SmallVector interfaceYields; - for (auto &yield : expectedType->getYields()) { - auto interfaceYield = yield.map(mapTypeOutOfContext); - interfaceYields.push_back(interfaceYield); - } - - SmallVector interfaceResults; - for (auto &result : expectedType->getResults()) { - auto interfaceResult = result.map(mapTypeOutOfContext); - interfaceResults.push_back(interfaceResult); - } - - Optional interfaceErrorResult; - if (expectedType->hasErrorResult()) { - auto errorResult = expectedType->getErrorResult(); - interfaceErrorResult = errorResult.map(mapTypeOutOfContext);; - } - - // The type of the thunk function. - return SILFunctionType::get( - genericSig, extInfoBuilder.build(), expectedType->getCoroutineKind(), - ParameterConvention::Direct_Unowned, interfaceParams, interfaceYields, - interfaceResults, interfaceErrorResult, - expectedType->getPatternSubstitutions(), SubstitutionMap(), - getASTContext()); + return buildSILFunctionThunkType(&F, sourceType, expectedType, inputSubstType, outputSubstType, genericEnv, interfaceSubs, dynamicSelfType, withoutActuallyEscaping); } static ManagedValue createPartialApplyOfThunk(SILGenFunction &SGF, diff --git a/lib/SILOptimizer/Differentiation/Thunk.cpp b/lib/SILOptimizer/Differentiation/Thunk.cpp index 72e96d42dbadf..e40bf96d91c04 100644 --- a/lib/SILOptimizer/Differentiation/Thunk.cpp +++ b/lib/SILOptimizer/Differentiation/Thunk.cpp @@ -36,78 +36,6 @@ namespace autodiff { // moved to a shared location. //===----------------------------------------------------------------------===// -CanGenericSignature buildThunkSignature(SILFunction *fn, bool inheritGenericSig, - OpenedArchetypeType *openedExistential, - GenericEnvironment *&genericEnv, - SubstitutionMap &contextSubs, - SubstitutionMap &interfaceSubs, - ArchetypeType *&newArchetype) { - // If there's no opened existential, we just inherit the generic environment - // from the parent function. - if (openedExistential == nullptr) { - auto genericSig = fn->getLoweredFunctionType()->getSubstGenericSignature(); - genericEnv = fn->getGenericEnvironment(); - interfaceSubs = fn->getForwardingSubstitutionMap(); - contextSubs = interfaceSubs; - return genericSig; - } - - auto &ctx = fn->getASTContext(); - - // Add the existing generic signature. - GenericSignature baseGenericSig; - int depth = 0; - if (inheritGenericSig) { - baseGenericSig = fn->getLoweredFunctionType()->getSubstGenericSignature(); - if (baseGenericSig) - depth = baseGenericSig.getGenericParams().back()->getDepth() + 1; - } - - // Add a new generic parameter to replace the opened existential. - auto *newGenericParam = - GenericTypeParamType::get(/*type sequence*/ false, depth, 0, ctx); - - assert(openedExistential->isRoot()); - auto constraint = openedExistential->getExistentialType(); - if (auto existential = constraint->getAs()) - constraint = existential->getConstraintType(); - - Requirement newRequirement(RequirementKind::Conformance, newGenericParam, - constraint); - - auto genericSig = buildGenericSignature(ctx, baseGenericSig, - { newGenericParam }, - { newRequirement }); - genericEnv = genericSig.getGenericEnvironment(); - - newArchetype = - genericEnv->mapTypeIntoContext(newGenericParam)->castTo(); - - // Calculate substitutions to map the caller's archetypes to the thunk's - // archetypes. - if (auto calleeGenericSig = - fn->getLoweredFunctionType()->getSubstGenericSignature()) { - contextSubs = SubstitutionMap::get( - calleeGenericSig, - [&](SubstitutableType *type) -> Type { - return genericEnv->mapTypeIntoContext(type); - }, - MakeAbstractConformanceForGenericType()); - } - - // Calculate substitutions to map interface types to the caller's archetypes. - interfaceSubs = SubstitutionMap::get( - genericSig, - [&](SubstitutableType *type) -> Type { - if (type->isEqual(newGenericParam)) - return openedExistential; - return fn->mapTypeIntoContext(type); - }, - MakeAbstractConformanceForGenericType()); - - return genericSig.getCanonicalSignature(); -} - CanSILFunctionType buildThunkType(SILFunction *fn, CanSILFunctionType &sourceType, CanSILFunctionType &expectedType, @@ -115,141 +43,12 @@ CanSILFunctionType buildThunkType(SILFunction *fn, SubstitutionMap &interfaceSubs, bool withoutActuallyEscaping, DifferentiationThunkKind thunkKind) { - assert(!expectedType->isPolymorphic() && - !expectedType->getCombinedSubstitutions()); - assert(!sourceType->isPolymorphic() && - !sourceType->getCombinedSubstitutions()); - - // Cannot build a reabstraction thunk without context. Ownership semantics - // on the result type are required. - if (thunkKind == DifferentiationThunkKind::Reabstraction) - assert(expectedType->getExtInfo().hasContext()); - - // This may inherit @noescape from the expected type. The `@noescape` - // attribute is only stripped when using this type to materialize a new decl. - // Use `@convention(thin)` if: - // - Building a reabstraction thunk type. - // - Building an index subset thunk type, where the expected type has context - // (i.e. is `@convention(thick)`). - auto extInfoBuilder = expectedType->getExtInfo().intoBuilder(); - if (thunkKind == DifferentiationThunkKind::Reabstraction || - extInfoBuilder.hasContext()) { - extInfoBuilder = extInfoBuilder.withRepresentation( - SILFunctionType::Representation::Thin); - } - if (withoutActuallyEscaping) - extInfoBuilder = extInfoBuilder.withNoEscape(false); - - // Does the thunk type involve archetypes other than opened existentials? - bool hasArchetypes = false; - // Does the thunk type involve an open existential type? - CanOpenedArchetypeType openedExistential; - auto archetypeVisitor = [&](CanType t) { - if (auto archetypeTy = dyn_cast(t)) { - if (auto opened = dyn_cast(archetypeTy)) { - const auto root = cast(CanType(opened->getRoot())); - assert((openedExistential == CanArchetypeType() || - openedExistential == root) && - "one too many open existentials"); - openedExistential = root; - } else { - hasArchetypes = true; - } - } - }; - - // Use the generic signature from the context if the thunk involves - // generic parameters. - CanGenericSignature genericSig; - SubstitutionMap contextSubs; - ArchetypeType *newArchetype = nullptr; - - if (expectedType->hasArchetype() || sourceType->hasArchetype()) { - expectedType.visit(archetypeVisitor); - sourceType.visit(archetypeVisitor); - genericSig = - buildThunkSignature(fn, hasArchetypes, openedExistential, genericEnv, - contextSubs, interfaceSubs, newArchetype); - } - - auto substTypeHelper = [&](SubstitutableType *type) -> Type { - if (CanType(type) == openedExistential) - return newArchetype; - return Type(type).subst(contextSubs); - }; - auto substConformanceHelper = LookUpConformanceInSubstitutionMap(contextSubs); - - // Utility function to apply contextSubs, and also replace the - // opened existential with the new archetype. - auto substLoweredTypeIntoThunkContext = - [&](CanSILFunctionType t) -> CanSILFunctionType { - return SILType::getPrimitiveObjectType(t) - .subst(fn->getModule(), substTypeHelper, substConformanceHelper) - .castTo(); - }; - - sourceType = substLoweredTypeIntoThunkContext(sourceType); - expectedType = substLoweredTypeIntoThunkContext(expectedType); - - // If our parent function was pseudogeneric, this thunk must also be - // pseudogeneric, since we have no way to pass generic parameters. - if (genericSig) - if (fn->getLoweredFunctionType()->isPseudogeneric()) - extInfoBuilder = extInfoBuilder.withIsPseudogeneric(); - - // Add the function type as the parameter. - auto contextConvention = - SILType::getPrimitiveObjectType(sourceType).isTrivial(*fn) - ? ParameterConvention::Direct_Unowned - : ParameterConvention::Direct_Guaranteed; - SmallVector params; - params.append(expectedType->getParameters().begin(), - expectedType->getParameters().end()); - // Add reabstraction function parameter only if building a reabstraction thunk - // type. - if (thunkKind == DifferentiationThunkKind::Reabstraction) - params.push_back({sourceType, sourceType->getExtInfo().hasContext() - ? contextConvention - : ParameterConvention::Direct_Unowned}); - - auto mapTypeOutOfContext = [&](CanType type) -> CanType { - return type->mapTypeOutOfContext()->getCanonicalType(genericSig); - }; - - // Map the parameter and expected types out of context to get the interface - // type of the thunk. - SmallVector interfaceParams; - interfaceParams.reserve(params.size()); - for (auto ¶m : params) { - auto interfaceParam = param.map(mapTypeOutOfContext); - interfaceParams.push_back(interfaceParam); - } - - SmallVector interfaceYields; - for (auto &yield : expectedType->getYields()) { - auto interfaceYield = yield.map(mapTypeOutOfContext); - interfaceYields.push_back(interfaceYield); - } - - SmallVector interfaceResults; - for (auto &result : expectedType->getResults()) { - auto interfaceResult = result.map(mapTypeOutOfContext); - interfaceResults.push_back(interfaceResult); - } - - Optional interfaceErrorResult; - if (expectedType->hasErrorResult()) { - auto errorResult = expectedType->getErrorResult(); - interfaceErrorResult = errorResult.map(mapTypeOutOfContext); - } - - // The type of the thunk function. - return SILFunctionType::get( - genericSig, extInfoBuilder.build(), expectedType->getCoroutineKind(), - ParameterConvention::Direct_Unowned, interfaceParams, interfaceYields, - interfaceResults, interfaceErrorResult, - expectedType->getPatternSubstitutions(), SubstitutionMap(), - fn->getASTContext()); + CanType inputSubstType; + CanType outputSubstType; + CanType dynamicSelfType; + return buildSILFunctionThunkType( + fn, sourceType, expectedType, inputSubstType, outputSubstType, genericEnv, + interfaceSubs, dynamicSelfType, withoutActuallyEscaping, thunkKind); } /// Forward function arguments, handling ownership convention mismatches. diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index edf4425605b7d..28261583c01c7 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -1146,7 +1146,9 @@ bool NotCompileTimeConst::diagnose(const Solution &solution, bool asNote) const // Referencing an enum element directly is considered a compile-time literal. if (auto *d = solution.resolveLocatorToDecl(locator).getDecl()) { if (isa(d)) { - return true; + if (!d->hasParameterList()) { + return true; + } } } NotCompileTimeConstFailure failure(solution, locator); diff --git a/lib/StaticMirror/ObjectFileContext.cpp b/lib/StaticMirror/ObjectFileContext.cpp index 1923e0a2948fb..768d7a167c0af 100644 --- a/lib/StaticMirror/ObjectFileContext.cpp +++ b/lib/StaticMirror/ObjectFileContext.cpp @@ -279,22 +279,23 @@ StringRef Image::getContentsAtAddress(uint64_t Addr, uint64_t Size) const { remote::RemoteAbsolutePointer Image::resolvePointer(uint64_t Addr, uint64_t pointerValue) const { + // In Mach-O images with ptrauth, the pointer value has an offset from the + // base address in the low 32 bits, and ptrauth discriminator info in the top + // 32 bits. + if (isMachOWithPtrAuth()) { + return remote::RemoteAbsolutePointer( + "", HeaderAddress + (pointerValue & 0xffffffffull)); + } else { + return remote::RemoteAbsolutePointer("", pointerValue); + } +} + +remote::RemoteAbsolutePointer Image::getDynamicSymbol(uint64_t Addr) const { auto found = DynamicRelocations.find(Addr); - remote::RemoteAbsolutePointer result; if (found == DynamicRelocations.end()) - // In Mach-O images with ptrauth, the pointer value has an offset from - // the base address in the low 32 bits, and ptrauth discriminator info - // in the top 32 bits. - if (isMachOWithPtrAuth()) { - result = remote::RemoteAbsolutePointer( - "", HeaderAddress + (pointerValue & 0xffffffffull)); - } else { - result = remote::RemoteAbsolutePointer("", pointerValue); - } - else - result = remote::RemoteAbsolutePointer(found->second.Symbol, - found->second.Offset); - return result; + return nullptr; + return remote::RemoteAbsolutePointer(found->second.Symbol, + found->second.Offset); } std::pair @@ -482,16 +483,24 @@ ObjectMemoryReader::resolvePointer(reflection::RemoteAddress Addr, return remote::RemoteAbsolutePointer(); auto resolved = image->resolvePointer(imageAddr, pointerValue); + // Mix in the image index again to produce a remote address pointing into the + // same image. + return remote::RemoteAbsolutePointer( + "", encodeImageIndexAndAddress( + image, resolved.getResolvedAddress().getAddressData())); +} - if (resolved && resolved.isResolved()) { - // Mix in the image index again to produce a remote address pointing into - // the same image. - return remote::RemoteAbsolutePointer( - "", encodeImageIndexAndAddress( - image, resolved.getResolvedAddress().getAddressData())); - } - // If the pointer is relative to an unresolved relocation, leave it as is. - return resolved; +remote::RemoteAbsolutePointer +ObjectMemoryReader::getDynamicSymbol(reflection::RemoteAddress Addr) { + auto addrValue = Addr.getAddressData(); + const Image *image; + uint64_t imageAddr; + std::tie(image, imageAddr) = decodeImageIndexAndAddress(addrValue); + + if (!image) + return nullptr; + + return image->getDynamicSymbol(imageAddr); } template diff --git a/stdlib/public/Reflection/TypeLowering.cpp b/stdlib/public/Reflection/TypeLowering.cpp index b311bacb94dd6..ba6093a0f0b87 100644 --- a/stdlib/public/Reflection/TypeLowering.cpp +++ b/stdlib/public/Reflection/TypeLowering.cpp @@ -2427,6 +2427,11 @@ class LowerType const TypeInfo * TypeConverter::getTypeInfo(const TypeRef *TR, remote::TypeInfoProvider *ExternalTypeInfo) { + if (!TR) { + DEBUG_LOG(fprintf(stderr, "null TypeRef")); + return nullptr; + } + // See if we already computed the result auto found = Cache.find({TR, ExternalTypeInfo}); if (found != Cache.end()) diff --git a/test/DebugInfo/debug_value_addr.swift b/test/DebugInfo/debug_value_addr.swift index 2a25dc98b9f2c..3a8e94364f2c9 100644 --- a/test/DebugInfo/debug_value_addr.swift +++ b/test/DebugInfo/debug_value_addr.swift @@ -1,8 +1,8 @@ // RUN: %target-swift-frontend -primary-file %s -emit-ir -g -o - | %FileCheck %s // RUN: %target-swift-frontend %s -emit-sil -g -o - | %FileCheck -check-prefix=CHECK-SIL %s -// rdar://89237318 -// REQUIRES: rdar89237318 +// Temporarily disable on arm64 (rdar://89237318) +// UNSUPPORTED: CPU=arm64 // Verify that -Onone shadow copies are emitted for debug_value_addr // instructions. @@ -30,7 +30,8 @@ func use(_ t : T) {} // CHECK-SIL: sil hidden @$s16debug_value_addr11GenericSelfV1xACyxGx_tcfC : $@convention(method) (@in T, @thin GenericSelf.Type) -> GenericSelf { // CHECK-SIL: bb0(%0 : $*T, %1 : $@thin GenericSelf.Type): -// CHECK-SIL-NEXT: alloc_stack [lexical] $GenericSelf, var, name "self", implicit, loc {{.*}} +// +// CHECK-SIL-NEXT: alloc_stack [lexical] $GenericSelf, {{var|let}}, name "self", implicit, loc {{.*}} // CHECK-SIL-NEXT: debug_value %0 : $*T, let, name "x", argno 1, expr op_deref, loc {{.*}} struct GenericSelf { init(x: T) { diff --git a/test/DebugInfo/move_function_dbginfo.swift b/test/DebugInfo/move_function_dbginfo.swift index 41f4b02c9e2cc..7a38abe60f4e1 100644 --- a/test/DebugInfo/move_function_dbginfo.swift +++ b/test/DebugInfo/move_function_dbginfo.swift @@ -3,9 +3,6 @@ // RUN: %target-swift-frontend -parse-as-library -Xllvm -sil-disable-pass=alloc-stack-hoisting -g -c %s -o %t/out.o // RUN: %llvm-dwarfdump --show-children %t/out.o | %FileCheck -check-prefix=DWARF %s -// rdar://90028779 -// REQUIRES: rdar90028779 - // This test checks that: // // 1. At the IR level, we insert the appropriate llvm.dbg.addr, llvm.dbg.value. @@ -90,11 +87,11 @@ public func copyableValueTest() { // CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo15copyableVarTestyyF"() // CHECK: call void @llvm.dbg.declare(metadata %T21move_function_dbginfo5KlassC** %m.debug, -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC** %k, metadata ![[K_COPYABLE_VAR_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] +// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC** [[VAR:%.*]], metadata ![[K_COPYABLE_VAR_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] // CHECK-NEXT: br // CHECK: call void @llvm.dbg.value(metadata %T21move_function_dbginfo5KlassC** undef, metadata ![[K_COPYABLE_VAR_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] // TODO: Should this be a deref like the original? -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC** %k, metadata ![[K_COPYABLE_VAR_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC** [[VAR]], metadata ![[K_COPYABLE_VAR_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] // CHECK-NEXT: br // CHECK: ret void // CHECK-NEXT: } @@ -263,7 +260,7 @@ public func copyableValueCCFlowTest() { // CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo037copyableVarTestCCFlowReinitOutOfBlockF0yyF"( // CHECK: call void @llvm.dbg.declare(metadata %T21move_function_dbginfo5KlassC** %m.debug, -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC** %k, metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] +// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC** [[VAR:%.*]], metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] // CHECK-NEXT: br label %[[BB_NEXT:[a-z0-9\.]+]], // // CHECK: [[BB_NEXT]]: @@ -278,7 +275,7 @@ public func copyableValueCCFlowTest() { // // CHECK: [[CONT_BB]]: // TODO: Should this be a deref like the original? -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC** %k, metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC** [[VAR]], metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] // CHECK-NEXT: br // CHECK: ret void // CHECK-NEXT: } @@ -296,7 +293,7 @@ public func copyableVarTestCCFlowReinitOutOfBlockTest() { // CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo034copyableVarTestCCFlowReinitInBlockF0yyF"( // CHECK: entry: // CHECK: call void @llvm.dbg.declare(metadata %T21move_function_dbginfo5KlassC** %m.debug, -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC** %k, metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] +// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC** [[VAR:%.*]], metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] // CHECK-NEXT: br label %[[BB_NEXT:[a-z0-9\.]+]], // // CHECK: [[BB_NEXT]]: @@ -305,7 +302,7 @@ public func copyableVarTestCCFlowReinitOutOfBlockTest() { // CHECK: [[LHS]]: // CHECK: call void @llvm.dbg.value(metadata %T21move_function_dbginfo5KlassC** undef, metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] // TODO: Should this be a deref like the original? -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC** %k, metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC** [[VAR]], metadata ![[K_COPYABLE_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] // CHECK-NEXT: br label %[[BB_NEXT_2:[a-z\.0-9]+]], // // CHECK: [[BB_NEXT_2]]: @@ -330,7 +327,7 @@ public func copyableVarTestCCFlowReinitInBlockTest() { // CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo040addressOnlyVarTestCCFlowReinitOutOfBlockG0yyxmAA1PRzlF"( // CHECK: entry: -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo1PP* %k, metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] +// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo1PP* [[VAR:%.*]], metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] // CHECK-NEXT: br label %[[BB_NEXT:[a-z0-9\.]+]], // // CHECK: [[BB_NEXT]]: @@ -345,7 +342,7 @@ public func copyableVarTestCCFlowReinitInBlockTest() { // // CHECK: [[CONT_BB]]: // TODO: Should this be a deref like the original? -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo1PP* %k, metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo1PP* [[VAR]], metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] // CHECK-NEXT: br // CHECK: ret void // CHECK-NEXT: } @@ -362,7 +359,7 @@ public func addressOnlyVarTestCCFlowReinitOutOfBlockTest(_ x: T.Type) { // CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo037addressOnlyVarTestCCFlowReinitInBlockG0yyxmAA1PRzlF"( // CHECK: entry: -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo1PP* %k, metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] +// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo1PP* [[VAR:%.*]], metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]*]] // CHECK-NEXT: br label %[[BB_NEXT:[a-z0-9\.]+]], // // CHECK: [[BB_NEXT]]: @@ -371,7 +368,7 @@ public func addressOnlyVarTestCCFlowReinitOutOfBlockTest(_ x: T.Type) { // CHECK: [[LHS]]: // CHECK: call void @llvm.dbg.value(metadata %T21move_function_dbginfo1PP* undef, metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] // TODO: Should this be a deref like the original? -// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo1PP* %k, metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo1PP* [[VAR]], metadata ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] // CHECK-NEXT: br label %[[BB_NEXT_2:[a-z\.0-9]+]], // // CHECK: [[BB_NEXT_2]]: diff --git a/test/Generics/concrete_protocol_typealias_minimization.swift b/test/Generics/concrete_protocol_typealias_minimization.swift new file mode 100644 index 0000000000000..0c036beb5cec7 --- /dev/null +++ b/test/Generics/concrete_protocol_typealias_minimization.swift @@ -0,0 +1,92 @@ +// RUN: %target-swift-frontend -typecheck %s -debug-generic-signatures -requirement-machine-inferred-signatures=verify -requirement-machine-protocol-signatures=verify 2>&1 | %FileCheck %s + +protocol P1a { + typealias X = Int +} + +// CHECK-LABEL: .P1b@ +// CHECK-NEXT: Requirement signature: +protocol P1b : P1a { + associatedtype X +} + +protocol P2a { + associatedtype A + typealias B = Int +} + +// CHECK-LABEL: .P2b@ +// CHECK-NEXT: +protocol P2b : P2a where Self.A == Self.B {} + +struct G {} + +protocol P3a { + typealias T = G + associatedtype X +} + +protocol P3b { + typealias T = G + associatedtype Y +} + +// CHECK-LABEL: .P3c@ +// CHECK-NEXT: +protocol P3c : P3a, P3b {} + +protocol P4a { + typealias T = G + associatedtype X +} + +// CHECK-LABEL: .P4b@ +// CHECK-NEXT: , Self.[P4b]B == Self.[P4a]X> +protocol P4b : P4a where A == T, A == G { + associatedtype A + associatedtype B +} + +// CHECK-LABEL: .P5@ +// CHECK-NEXT: +protocol P5 { + typealias A = Int + associatedtype B where B == A +} + +protocol P6a { + typealias A = Int + typealias B = A +} + +// CHECK-LABEL: .P6b@ +// CHECK-NEXT: +protocol P6b : P6a where C == B { + associatedtype C +} + +protocol P7a { + typealias A = Int +} + +protocol P7b : P7a { + typealias B = A +} + +// CHECK-LABEL: .P7c@ +// CHECK-NEXT: +protocol P7c : P7b { + associatedtype C where C == B +} + +protocol P8a { + associatedtype C +} + +// CHECK-LABEL: .f1@ +// CHECK-NEXT: +func f1(_: T, _: U) where T.C == U.B {} + +// CHECK-LABEL: .f2@ +// CHECK-NEXT: +func f2(_: T, _: U) where T.B == U.C {} diff --git a/test/Generics/protocol_type_aliases.swift b/test/Generics/protocol_type_aliases.swift index fdcb8ae42458f..f9bc514250ae7 100644 --- a/test/Generics/protocol_type_aliases.swift +++ b/test/Generics/protocol_type_aliases.swift @@ -1,9 +1,5 @@ -// FIXME: Once the Requirement Machine can emit diagnostics, run this test with -// it enabled unconditionally. - -// RUN: %target-typecheck-verify-swift -requirement-machine-protocol-signatures=off -// RUN: %target-swift-frontend -typecheck %s -debug-generic-signatures -requirement-machine-protocol-signatures=on > %t.dump 2>&1 -// RUN: %FileCheck %s < %t.dump +// RUN: %target-typecheck-verify-swift -requirement-machine-protocol-signatures=verify +// RUN: not %target-swift-frontend -typecheck %s -debug-generic-signatures -requirement-machine-protocol-signatures=verify > %t.dump 2>&1 func sameType(_: T.Type, _: T.Type) {} @@ -107,9 +103,9 @@ protocol P7 { } // CHECK-LABEL: .P7a@ -// CHECK: Requirement signature: +// CHECK: Requirement signature: protocol P7a : P7 { associatedtype A // expected-warning{{associated type 'A' is redundant with type 'A' declared in inherited protocol 'P7'}} } -func testP7A(_: T, a: T.A) -> Int { return a } \ No newline at end of file +func testP7A(_: T, a: T.A) -> Int { return a } diff --git a/test/Generics/protocol_typealias_same_type_requirement.swift b/test/Generics/protocol_typealias_same_type_requirement.swift index 502c0906b6371..5d913144d50a0 100644 --- a/test/Generics/protocol_typealias_same_type_requirement.swift +++ b/test/Generics/protocol_typealias_same_type_requirement.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -typecheck %s -debug-generic-signatures -requirement-machine-protocol-signatures=on 2>&1 | %FileCheck %s +// RUN: %target-swift-frontend -typecheck %s -debug-generic-signatures -requirement-machine-protocol-signatures=verify 2>&1 | %FileCheck %s protocol P1 { associatedtype A @@ -41,7 +41,7 @@ protocol P7 { } // CHECK-LABEL: protocol_typealias_same_type_requirement.(file).P8@ -// CHECK-LABEL: Requirement signature: +// CHECK-LABEL: Requirement signature: protocol P8 : P6, P7 {} -func testP8(_: T, x: T.X) -> Int { return x } \ No newline at end of file +func testP8(_: T, x: T.X) -> Int { return x } diff --git a/test/Interop/Cxx/class/Inputs/class-protocol-name-clash.h b/test/Interop/Cxx/class/Inputs/class-protocol-name-clash.h new file mode 100644 index 0000000000000..e59b8f5a108fa --- /dev/null +++ b/test/Interop/Cxx/class/Inputs/class-protocol-name-clash.h @@ -0,0 +1,5 @@ +@protocol TheClashingName +@end + +@interface TheClashingName +@end diff --git a/test/Interop/Cxx/class/Inputs/module.modulemap b/test/Interop/Cxx/class/Inputs/module.modulemap index 48745018d3046..60d0b459679c2 100644 --- a/test/Interop/Cxx/class/Inputs/module.modulemap +++ b/test/Interop/Cxx/class/Inputs/module.modulemap @@ -87,3 +87,8 @@ module InvalidNestedStruct { header "invalid-nested-struct.h" requires cplusplus } + +module ClassProtocolNameClash { + header "class-protocol-name-clash.h" + requires cplusplus +} diff --git a/test/Interop/Cxx/class/class-protocol-name-clash.swift b/test/Interop/Cxx/class/class-protocol-name-clash.swift new file mode 100644 index 0000000000000..b4085cccb5198 --- /dev/null +++ b/test/Interop/Cxx/class/class-protocol-name-clash.swift @@ -0,0 +1,7 @@ +// RUN: %target-swift-frontend %s -c -enable-cxx-interop -I %S/Inputs +// +// REQUIRES: objc_interop + +import ClassProtocolNameClash + +class Subclass : TheClashingName {} diff --git a/test/Interop/SwiftToCxx/functions/cdecl.swift b/test/Interop/SwiftToCxx/functions/cdecl.swift index 556c1fafdce26..67b8ce223e43b 100644 --- a/test/Interop/SwiftToCxx/functions/cdecl.swift +++ b/test/Interop/SwiftToCxx/functions/cdecl.swift @@ -1,9 +1,8 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend %s -typecheck -module-name CdeclFunctions -emit-cxx-header-path %t/empty.h -// RUN: %FileCheck %s < %t/empty.h +// RUN: %target-swift-frontend %s -typecheck -module-name CdeclFunctions -emit-cxx-header-path %t/cdecl.h +// RUN: %FileCheck %s < %t/cdecl.h -// RUN: %check-cxx-header-in-clang -std=c++14 %t/empty.h -// RUN: %check-cxx-header-in-clang -std=c++17 %t/empty.h +// RUN: %check-interop-cxx-header-in-clang(%t/cdecl.h) // CHECK-LABEL: namespace CdeclFunctions { diff --git a/test/Interop/SwiftToCxx/functions/function-availability.swift b/test/Interop/SwiftToCxx/functions/function-availability.swift index 9275ada518bbe..6242e5130d905 100644 --- a/test/Interop/SwiftToCxx/functions/function-availability.swift +++ b/test/Interop/SwiftToCxx/functions/function-availability.swift @@ -2,8 +2,7 @@ // RUN: %target-swift-frontend %s -typecheck -module-name Functions -emit-cxx-header-path %t/functions.h // RUN: %FileCheck %s < %t/functions.h -// RUN: %check-cxx-header-in-clang -std=c++14 %t/functions.h -// RUN: %check-cxx-header-in-clang -std=c++17 %t/functions.h +// RUN: %check-interop-cxx-header-in-clang(%t/functions.h) // CHECK-LABEL: namespace Functions { diff --git a/test/Interop/SwiftToCxx/functions/swift-functions.swift b/test/Interop/SwiftToCxx/functions/swift-functions.swift index 98d94406e3fea..e7516448cbb9e 100644 --- a/test/Interop/SwiftToCxx/functions/swift-functions.swift +++ b/test/Interop/SwiftToCxx/functions/swift-functions.swift @@ -2,8 +2,7 @@ // RUN: %target-swift-frontend %s -typecheck -module-name Functions -emit-cxx-header-path %t/functions.h // RUN: %FileCheck %s < %t/functions.h -// RUN: %check-cxx-header-in-clang -std=c++14 %t/functions.h -// RUN: %check-cxx-header-in-clang -std=c++17 %t/functions.h +// RUN: %check-interop-cxx-header-in-clang(%t/functions.h) // CHECK-LABEL: namespace Functions { diff --git a/test/Interop/SwiftToCxx/module/module-to-namespace.swift b/test/Interop/SwiftToCxx/module/module-to-namespace.swift index e9006a78f2ffa..eeba2992d63b5 100644 --- a/test/Interop/SwiftToCxx/module/module-to-namespace.swift +++ b/test/Interop/SwiftToCxx/module/module-to-namespace.swift @@ -2,8 +2,7 @@ // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) %s -typecheck -module-name Test -emit-cxx-header-path %t/empty.h // RUN: %FileCheck %s < %t/empty.h -// RUN: %check-cxx-header-in-clang -std=c++14 %t/empty.h -// RUN: %check-cxx-header-in-clang -std=c++17 %t/empty.h +// RUN: %check-interop-cxx-header-in-clang(%t/empty.h) // CHECK-LABEL: namespace Test { // CHECK: } // namespace Test diff --git a/test/Interop/lit.local.cfg b/test/Interop/lit.local.cfg index 2ea42927e8113..1c1d0c7c9a2a6 100644 --- a/test/Interop/lit.local.cfg +++ b/test/Interop/lit.local.cfg @@ -6,16 +6,25 @@ def get_target_os(): (run_cpu, run_vendor, run_os, run_version) = re.match('([^-]+)-([^-]+)-([^0-9]+)(.*)', config.variant_triple).groups() return run_os -libc_opt = '' clang_opt = '' if get_target_os() in ['windows-msvc']: config.substitutions.insert(0, ('%target-abi', 'WIN')) - #libc_opt = '-libc MT ' + # Clang should build object files with link settings equivalent to -libc MD + # when building for the MSVC target. clang_opt = '-D_MT -D_DLL -Xclang --dependent-lib=msvcrt -Xclang --dependent-lib=oldnames ' else: # FIXME(compnerd) do all the targets we currently support use SysV ABI? config.substitutions.insert(0, ('%target-abi', 'SYSV')) -config.substitutions.insert(0, ('%target-interop-build-swift', '%target-build-swift -Xfrontend -enable-cxx-interop ' + libc_opt)) +# Enable C++ interop when compiling Swift sources. +config.substitutions.insert(0, ('%target-interop-build-swift', + '%target-build-swift -Xfrontend -enable-cxx-interop ')) +# Build C++ files with matching link settings, if required by the target. config.substitutions.insert(0, ('%target-interop-build-clangxx', '%target-clangxx ' + clang_opt)) + +# Test parsing of the generated C++ header in different C++ language modes. +config.substitutions.insert(0, ('%check-interop-cxx-header-in-clang\(([^)]+)\)', + SubstituteCaptures(r'%check-cxx-header-in-clang -std=c++14 \1 && ' + r'%check-cxx-header-in-clang -std=c++17 \1 && ' + r'%check-cxx-header-in-clang -std=c++20 \1'))) diff --git a/test/Sema/const_enum_elements.swift b/test/Sema/const_enum_elements.swift index cbc408894cb9c..c9bac2c671fd8 100644 --- a/test/Sema/const_enum_elements.swift +++ b/test/Sema/const_enum_elements.swift @@ -1,6 +1,7 @@ // RUN: %target-typecheck-verify-swift enum CarKind { + static let wagon = "Wagon" case coupe case sedan case other(String) @@ -21,7 +22,8 @@ func main() { drive(.sedan, k2: .coupe) drive(CarKind.coupe, k2: CarKind.sedan) drive(CarKind.sedan, k2: CarKind.coupe) - drive(.other(""), k2: .sedan) + drive(.other(""), k2: .sedan) // expected-error {{expect a compile-time constant literal}} + drive(.other(CarKind.wagon), k2: .sedan) // expected-error {{expect a compile-time constant literal}} drive(.myCoupe, k2: .sedan) // expected-error {{expect a compile-time constant literal}} drive(.coupe, k2: .myCoupe) // expected-error {{expect a compile-time constant literal}} diff --git a/test/decl/protocol/req/associated_type_ambiguity.swift b/test/decl/protocol/req/associated_type_ambiguity.swift index d8e475b678051..32bd53d6df370 100644 --- a/test/decl/protocol/req/associated_type_ambiguity.swift +++ b/test/decl/protocol/req/associated_type_ambiguity.swift @@ -9,20 +9,24 @@ protocol P2 { associatedtype T } +// Note: the warnings should probably be emitted. + // CHECK: ExtensionDecl line={{.*}} base=P1 -// CHECK-NEXT: Generic signature: +// CHECK-NEXT: Generic signature: extension P1 where Self : P2, T == Int { // expected-warning {{redundant same-type constraint 'Self.T' == 'Int'}} func takeT11(_: T) {} func takeT12(_: Self.T) {} } // CHECK: ExtensionDecl line={{.*}} base=P1 -// CHECK-NEXT: Generic signature: +// CHECK-NEXT: Generic signature: extension P1 where Self : P2, Self.T == Int { // expected-warning {{redundant same-type constraint 'Self.T' == 'Int'}} func takeT21(_: T) {} func takeT22(_: Self.T) {} } +// CHECK: ExtensionDecl line={{.*}} base=P1 +// CHECK-NEXT: Generic signature: extension P1 where Self : P2 { func takeT31(_: T) {} func takeT32(_: Self.T) {} diff --git a/test/decl/typealias/protocol.swift b/test/decl/typealias/protocol.swift index 7cb08899aa901..6d3164e7763ef 100644 --- a/test/decl/typealias/protocol.swift +++ b/test/decl/typealias/protocol.swift @@ -1,4 +1,4 @@ -// RUN: %target-typecheck-verify-swift +// RUN: %target-typecheck-verify-swift -requirement-machine-inferred-signatures=verify // Tests for typealias inside protocols @@ -262,9 +262,9 @@ protocol P10 { @available(*, deprecated, message: "just use Int, silly") typealias V = Int -} -extension P10 { + // FIXME: This used to be in a protocol extension, but the Requirement Machine does + // not permit `where` clauses to reference typealiases in protocol extensions. typealias U = Float }