From 09bf4cb6d16b64c51930eb7c4ad1699742a922ff Mon Sep 17 00:00:00 2001 From: LucianoAlmeida Date: Sun, 20 Feb 2022 18:18:35 -0300 Subject: [PATCH 01/17] [NFC] Fixing some stdlib unused warnings --- stdlib/public/core/CocoaArray.swift | 2 +- stdlib/public/core/ContiguousArrayBuffer.swift | 4 ++-- stdlib/public/core/Int128.swift.gyb | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/stdlib/public/core/CocoaArray.swift b/stdlib/public/core/CocoaArray.swift index ff61076d079a6..12a6707106b4a 100644 --- a/stdlib/public/core/CocoaArray.swift +++ b/stdlib/public/core/CocoaArray.swift @@ -154,7 +154,7 @@ internal struct _CocoaArrayWrapper: RandomAccessCollection { guard buffer.count > 0 else { return (makeIterator(), 0) } let start = buffer.baseAddress! let c = Swift.min(self.count, buffer.count) - let end = _copyContents(subRange: 0 ..< c, initializing: start) + _ = _copyContents(subRange: 0 ..< c, initializing: start) return (IndexingIterator(_elements: self, _position: c), c) } } diff --git a/stdlib/public/core/ContiguousArrayBuffer.swift b/stdlib/public/core/ContiguousArrayBuffer.swift index 43a721955c80e..8b81b0e4f2410 100644 --- a/stdlib/public/core/ContiguousArrayBuffer.swift +++ b/stdlib/public/core/ContiguousArrayBuffer.swift @@ -822,8 +822,8 @@ internal struct _ContiguousArrayBuffer: _ArrayBufferProtocol { // class type to use _ContiguousArrayStorage when we bridge // to objective-c we need to set the correct Element type so that when // we bridge back we can use O(1) bridging i.e we can adopt the storage. - _swift_setClassMetadata(_ContiguousArrayStorage.self, - onObject: _storage) + _ = _swift_setClassMetadata(_ContiguousArrayStorage.self, + onObject: _storage) } return _storage } diff --git a/stdlib/public/core/Int128.swift.gyb b/stdlib/public/core/Int128.swift.gyb index f403deba50859..18814faead290 100644 --- a/stdlib/public/core/Int128.swift.gyb +++ b/stdlib/public/core/Int128.swift.gyb @@ -590,7 +590,7 @@ private func _wideMaskedShiftLeft( var high = lhs.high &<< F(rhs) let rollover = F.Magnitude(F.bitWidth) &- rhs high |= F(truncatingIfNeeded: lhs.low &>> rollover) - var low = lhs.low &<< rhs + let low = lhs.low &<< rhs return (high, low) } From bf820c5dab57bc7a373f5d96ff620156cc8d32c5 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 21 Feb 2022 16:28:31 -0800 Subject: [PATCH 02/17] [CSDiagnostics] Look through l-value conversions when mismatch is in subscript setter `repairFailures` needs a special case when l-value conversion is associated with a result type of subscript setter because otherwise it falls through and treats result type as if it's an argument type, which leads to crashes. Resolves: rdar://84580119 --- lib/Sema/CSSimplify.cpp | 8 +++++++ .../Sema/SwiftUI/rdar84580119.swift | 24 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 validation-test/Sema/SwiftUI/rdar84580119.swift diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 9c81526feba09..c6d14e67ebf35 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -4563,6 +4563,14 @@ bool ConstraintSystem::repairFailures( break; } + // If this is a problem with result type of a subscript setter, + // let's re-attempt to repair without l-value conversion in the + // locator to fix underlying type mismatch. + if (path.back().is()) { + return repairFailures(lhs, rhs, matchKind, conversionsOrFixes, + getConstraintLocator(anchor, path)); + } + // If this is a function type param type mismatch in any position, // the mismatch we want to report is for the whole structural type. auto last = std::find_if( diff --git a/validation-test/Sema/SwiftUI/rdar84580119.swift b/validation-test/Sema/SwiftUI/rdar84580119.swift new file mode 100644 index 0000000000000..9e18c59a67f46 --- /dev/null +++ b/validation-test/Sema/SwiftUI/rdar84580119.swift @@ -0,0 +1,24 @@ +// RUN: %target-typecheck-verify-swift -target %target-cpu-apple-macosx10.15 -swift-version 5 +// REQUIRES: objc_interop +// REQUIRES: OS=macosx + +import SwiftUI + +extension HorizontalAlignment { + private enum MyHorizontalAlignment: AlignmentID { + static func defaultValue(in d: ViewDimensions) -> CGFloat { d.width } + } +} + +extension EnvironmentValues { + var myHorizontalAlignment: AlignmentID? { + get { fatalError() } + set { self[\.MyHorizontalAlignmentEnvironmentKey.self] = newValue } + // expected-error@-1 {{generic parameter 'K' could not be inferred}} + // expected-error@-2 {{cannot infer key path type from context; consider explicitly specifying a root type}} + } +} + +struct MyHorizontalAlignmentEnvironmentKey: EnvironmentKey { + static var defaultValue: AlignmentID? +} From 034c4bd77edd853e5e43881614aa96c8f8f6de76 Mon Sep 17 00:00:00 2001 From: LucianoAlmeida Date: Mon, 21 Feb 2022 22:27:17 -0300 Subject: [PATCH 03/17] [Sema] Attempt diagnose generic arg ambiguity if all solutions produce generic arg mismatch --- lib/Sema/ConstraintSystem.cpp | 48 ++++++++++++++++++----------- test/Constraints/casts_swift6.swift | 11 +++---- 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 990cdb9f02d55..784e19b4dd86f 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -3697,7 +3697,8 @@ static bool diagnoseConflictingGenericArguments(ConstraintSystem &cs, solution.Fixes, [](const ConstraintFix *fix) -> bool { return fix->getKind() == FixKind::AllowArgumentTypeMismatch || fix->getKind() == FixKind::AllowFunctionTypeMismatch || - fix->getKind() == FixKind::AllowTupleTypeMismatch; + fix->getKind() == FixKind::AllowTupleTypeMismatch || + fix->getKind() == FixKind::GenericArgumentsMismatch; }); }); @@ -3711,24 +3712,27 @@ static bool diagnoseConflictingGenericArguments(ConstraintSystem &cs, genericParams; // Consider only representative type variables shared across // all of the solutions. - for (auto *typeVar : cs.getTypeVariables()) { - if (auto *GP = typeVar->getImpl().getGenericParameter()) { - auto *locator = typeVar->getImpl().getLocator(); - auto *repr = cs.getRepresentative(typeVar); - // If representative is another generic parameter let's - // use its generic parameter type instead of originator's, - // but it's possible that generic parameter is equated to - // some other type e.g. - // - // func foo(_: T) -> T {} - // - // In this case when reference to function `foo` is "opened" - // type variable representing `T` would be equated to - // type variable representing a result type of the reference. - if (auto *reprGP = repr->getImpl().getGenericParameter()) - GP = reprGP; + for (auto &solution : solutions) { + for (auto &typeBinding : solution.typeBindings) { + auto *typeVar = typeBinding.first; + if (auto *GP = typeVar->getImpl().getGenericParameter()) { + auto *locator = typeVar->getImpl().getLocator(); + auto *repr = cs.getRepresentative(typeVar); + // If representative is another generic parameter let's + // use its generic parameter type instead of originator's, + // but it's possible that generic parameter is equated to + // some other type e.g. + // + // func foo(_: T) -> T {} + // + // In this case when reference to function `foo` is "opened" + // type variable representing `T` would be equated to + // type variable representing a result type of the reference. + if (auto *reprGP = repr->getImpl().getGenericParameter()) + GP = reprGP; - genericParams[repr] = {GP, getLoc(locator->getAnchor())}; + genericParams[repr] = {GP, getLoc(locator->getAnchor())}; + } } } @@ -3743,6 +3747,14 @@ static bool diagnoseConflictingGenericArguments(ConstraintSystem &cs, llvm::SmallSetVector arguments; for (const auto &solution : solutions) { auto type = solution.typeBindings.lookup(typeVar); + // Type variables gathered from a solution's type binding context may not + // exist in another given solution because each solution could have a + // different set of overload choices picked, which implies that some of + // the generic parameters, and type variables that represent them, would + // be unique to that solution. + if (!type) + continue; + // Contextual opaque result type is uniquely identified by // declaration it's associated with, so we have to compare // declarations instead of using pointer equality on such types. diff --git a/test/Constraints/casts_swift6.swift b/test/Constraints/casts_swift6.swift index a977842091225..496eeb90b7059 100644 --- a/test/Constraints/casts_swift6.swift +++ b/test/Constraints/casts_swift6.swift @@ -27,12 +27,11 @@ func test_compatibility_coercions(_ arr: [Int], _ optArr: [Int]?, _ dict: [Strin // expected-note@-1 {{arguments to generic parameter 'Element' ('Int' and 'String') are expected to be equal}} // Make sure we error on the following in Swift 6 mode. - - // FIXME: Bad diagnostics (SR-15843) - _ = id(arr) as [String] // expected-error {{type of expression is ambiguous without more context}} - _ = (arr ?? []) as [String] // expected-error {{type of expression is ambiguous without more context}} - _ = (arr ?? [] ?? []) as [String] // expected-error {{type of expression is ambiguous without more context}} - _ = (optArr ?? []) as [String] // expected-error {{type of expression is ambiguous without more context}} + _ = id(arr) as [String] // expected-error {{conflicting arguments to generic parameter 'T' ('[Int]' vs. '[String]')}} + _ = (arr ?? []) as [String] // expected-error {{conflicting arguments to generic parameter 'T' ('[String]' vs. '[Int]')}} + _ = (arr ?? [] ?? []) as [String] // expected-error {{conflicting arguments to generic parameter 'T' ('[String]' vs. '[Int]')}} + // expected-error@-1{{conflicting arguments to generic parameter 'T' ('[String]' vs. '[Int]')}} + _ = (optArr ?? []) as [String] // expected-error {{conflicting arguments to generic parameter 'T' ('[Int]' vs. '[String]'}} _ = (arr ?? []) as [String]? // expected-error {{'[Int]' is not convertible to '[String]?'}} // expected-note@-1 {{did you mean to use 'as!' to force downcast?}} From 0f67926298e6ba8c78acec750120e532c120d932 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Tue, 22 Feb 2022 20:03:07 -0800 Subject: [PATCH 04/17] [move-function-value] Make sure that we propagate the debug scope from our original debug value into new undef debug values. Otherwise if the move is in a different scope, the backend will think that we have two different variables and emit the corresponding dwarf. After I have this commit in and my alloc stack hoising commit (via a different PR), I am going to be able to commit a full end <-> end test in lldb that values are printed out appropriately as their lifetimes begin/end. --- .../MoveKillsCopyableValuesChecker.cpp | 18 ++++++++++-------- test/DebugInfo/move_function_dbginfo.swift | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/lib/SILOptimizer/Mandatory/MoveKillsCopyableValuesChecker.cpp b/lib/SILOptimizer/Mandatory/MoveKillsCopyableValuesChecker.cpp index 8a987c119f4ac..310b354953613 100644 --- a/lib/SILOptimizer/Mandatory/MoveKillsCopyableValuesChecker.cpp +++ b/lib/SILOptimizer/Mandatory/MoveKillsCopyableValuesChecker.cpp @@ -400,8 +400,8 @@ bool MoveKillsCopyableValuesChecker::check() { // Then look at all of our found consuming uses. See if any of these are // _move that are within the boundary. bool foundMove = false; - auto dbgVarInfo = DebugVarCarryingInst::getFromValue(lexicalValue); - StringRef varName = DebugVarCarryingInst::getName(dbgVarInfo); + auto dbgVarInst = DebugVarCarryingInst::getFromValue(lexicalValue); + StringRef varName = DebugVarCarryingInst::getName(dbgVarInst); for (auto *use : livenessInfo.consumingUse) { if (auto *mvi = dyn_cast(use->getUser())) { // Only emit diagnostics if our move value allows us to. @@ -420,14 +420,16 @@ bool MoveKillsCopyableValuesChecker::check() { emittedDiagnostic = true; } else { LLVM_DEBUG(llvm::dbgs() << " WithinBoundary: No!\n"); - if (auto varInfo = dbgVarInfo.getVarInfo()) { - successMovesDbgInfoCarryingInsts.push_back(*dbgVarInfo); + if (auto varInfo = dbgVarInst.getVarInfo()) { + successMovesDbgInfoCarryingInsts.push_back(*dbgVarInst); auto *next = mvi->getNextInstruction(); SILBuilderWithScope builder(next); - // Use an autogenerated location to ensure that if we are next to a - // terminator, we don't assert. + // We need to make sure any undefs we put in are the same loc/debug + // scope as our original so that the backend treats them as + // referring to the same "debug entity". + builder.setCurrentDebugScope(dbgVarInst->getDebugScope()); builder.createDebugValue( - dbgVarInfo.inst->getLoc(), + dbgVarInst->getLoc(), SILUndef::get(mvi->getOperand()->getType(), mod), *varInfo, false /*poison*/, true /*moved*/); } @@ -439,7 +441,7 @@ bool MoveKillsCopyableValuesChecker::check() { // If we found a move, mark our debug var inst as having a moved value. This // ensures we emit llvm.dbg.addr instead of llvm.dbg.declare in IRGen. if (foundMove) { - dbgVarInfo.markAsMoved(); + dbgVarInst.markAsMoved(); } } diff --git a/test/DebugInfo/move_function_dbginfo.swift b/test/DebugInfo/move_function_dbginfo.swift index 51ac00fb2dd81..d24d64e682668 100644 --- a/test/DebugInfo/move_function_dbginfo.swift +++ b/test/DebugInfo/move_function_dbginfo.swift @@ -240,6 +240,24 @@ public func addressOnlyVarTest(_ x: T) { // Conditional Tests // /////////////////////// +// CHECK-LABEL: define swiftcc void @"$s21move_function_dbginfo23copyableValueCCFlowTestyyF"( +// CHECK: call void @llvm.dbg.addr(metadata %T21move_function_dbginfo5KlassC** %k.debug, metadata ![[K_COPYABLE_LET_CCFLOW_METADATA:[0-9]+]], metadata !DIExpression()), !dbg ![[ADDR_LOC:[0-9]+]] +// CHECK-NEXT: br label %[[NEXT_BB:[0-9]+]], +// +// CHECK: [[NEXT_BB]]: +// CHECK: br i1 {{%[0-9]+}}, label %[[LHS:[0-9]+]], label %[[RHS:[0-9]+]], +// +// CHECK: [[LHS]]: +// CHECK: call void @llvm.dbg.value(metadata %T21move_function_dbginfo5KlassC* undef, metadata ![[K_COPYABLE_LET_CCFLOW_METADATA]], metadata !DIExpression()), !dbg ![[ADDR_LOC]] +public func copyableValueCCFlowTest() { + let k = Klass() + k.doSomething() + if trueValue { + let m = _move(k) + m.doSomething() + } +} + // 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]*]] @@ -385,3 +403,4 @@ public func addressOnlyVarTestCCFlowReinitInBlockTest(_ x: T.Type) { // CHECK-DAG: ![[K_COPYABLE_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]] = !DILocalVariable(name: "k", // CHECK-DAG: ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_OUT_BLOCK_METADATA]] = !DILocalVariable(name: "k", // CHECK-DAG: ![[K_ADDRESSONLY_VAR_CCFLOW_REINIT_IN_BLOCK_METADATA]] = !DILocalVariable(name: "k", +// CHECK-DAG: ![[K_COPYABLE_LET_CCFLOW_METADATA]] = !DILocalVariable(name: "k", From e766b44d527b430291c62279c2104746717d4766 Mon Sep 17 00:00:00 2001 From: nate-chandler <46721658+nate-chandler@users.noreply.github.com> Date: Tue, 22 Feb 2022 20:26:50 -0800 Subject: [PATCH 05/17] Revert "Revert "[SSADestroyHoisting] Split destroy from copy."" --- .../Transforms/SSADestroyHoisting.cpp | 65 +++++++++++++++---- 1 file changed, 54 insertions(+), 11 deletions(-) diff --git a/lib/SILOptimizer/Transforms/SSADestroyHoisting.cpp b/lib/SILOptimizer/Transforms/SSADestroyHoisting.cpp index 14bc5ff75a942..501583782a23b 100644 --- a/lib/SILOptimizer/Transforms/SSADestroyHoisting.cpp +++ b/lib/SILOptimizer/Transforms/SSADestroyHoisting.cpp @@ -754,6 +754,7 @@ void SSADestroyHoisting::run() { llvm::SmallVector asis; llvm::SmallVector bais; llvm::SmallVector sis; + llvm::SmallVector cais; // Collect the instructions that we'll be transforming. for (auto &block : *getFunction()) { @@ -768,6 +769,10 @@ void SSADestroyHoisting::run() { if (si->getOwnershipQualifier() == StoreOwnershipQualifier::Assign) { sis.push_back(si); } + } else if (auto *cai = dyn_cast(&inst)) { + if (cai->isInitializationOfDest() == IsNotInitialization) { + cais.push_back(cai); + } } } } @@ -804,6 +809,32 @@ void SSADestroyHoisting::run() { remainingDestroyAddrs.insert(dai); ++splitDestroys; } + // Similarly, also expand each + // + // copy_addr to + // + // instruction into + // + // destroy_addr + // copy_addr to [initialization] + // + // sequences to create still more destroy_addrs to hoist. + // + // As above, record the newly created destroy_addrs and copy_addrs off of + // which they were split. After hoisting, we'll merge them back together when + // possible. + llvm::SmallVector, 8> + splitDestroysAndCopies; + for (auto *cai : cais) { + auto builder = SILBuilderWithScope(cai); + auto *dai = builder.createDestroyAddr( + RegularLocation::getAutoGeneratedLocation(cai->getLoc()), + cai->getOperand(1)); + cai->setIsInitializationOfDest(IsInitialization); + splitDestroysAndCopies.push_back({dai, cai}); + remainingDestroyAddrs.insert(dai); + ++splitDestroys; + } // We assume that the function is in reverse post order so visiting the // blocks and pushing begin_access as we see them and then popping them off @@ -840,17 +871,29 @@ void SSADestroyHoisting::run() { if (!remainingDestroyAddrs.contains(dai)) continue; auto *si = pair.second; - if (dai->getNextInstruction() == si) { - // No stores should have been rewritten during hoisting. Their ownership - // qualifiers were set to [init] when splitting off the destroy_addrs. - assert(si->getOwnershipQualifier() == StoreOwnershipQualifier::Init); - // If a newly created destroy_addr has not been hoisted from its previous - // location, combine it back together with the store [init] which it was - // split off from. - deleter.forceDelete(dai); - si->setOwnershipQualifier(StoreOwnershipQualifier::Assign); - --splitDestroys; - } + if (dai->getNextInstruction() != si) + continue; + // No stores should have been rewritten during hoisting. Their ownership + // qualifiers were set to [init] when splitting off the destroy_addrs. + assert(si->getOwnershipQualifier() == StoreOwnershipQualifier::Init); + // If a newly created destroy_addr has not been hoisted from its previous + // location, combine it back together with the store [init] which it was + // split off from. + deleter.forceDelete(dai); + si->setOwnershipQualifier(StoreOwnershipQualifier::Assign); + --splitDestroys; + } + for (auto pair : splitDestroysAndCopies) { + auto *dai = pair.first; + if (!remainingDestroyAddrs.contains(dai)) + continue; + auto *cai = pair.second; + if (dai->getNextInstruction() != cai) + continue; + assert(cai->isInitializationOfDest() == IsInitialization); + deleter.forceDelete(dai); + cai->setIsInitializationOfDest(IsNotInitialization); + --splitDestroys; } // If there were any destroy_addrs split off of stores and not recombined // with them, then the function has changed. From ac7e28a57e44918590e81338f46ef54005bf89c0 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Thu, 17 Feb 2022 21:46:47 -0800 Subject: [PATCH 06/17] [alloc-stack-hoisting] Handle alloc_stack [move] correctly. This is just a quick fix to stop us from dropping live values such as m in the following example: ``` public func addressOnlyVarTest(_ x: T) { var k = x k.doSomething() let m = _move(k) m.doSomething() k = x k.doSomething() } ``` Before this change, we would just drop m and one wouldn't even see it in the debugger. I am only doing this currently for cases where when we merge at least one alloc_stack was moved. The reason why is that to implement this correctly, I need to use llvm.dbg.addr and changing the debug info from using llvm.dbg.declare -> llvm.dbg.addr requires statistics and needs to be done a little later in the swift development process. If one of these alloc_stack had the [moved] marker attached to it, we know the user /did/ use move so they have in a sense opted into having a move function effect its program so we are only changing how new code appears in the debugger. --- include/swift/SIL/SILInstruction.h | 30 ++ lib/IRGen/AllocStackHoisting.cpp | 168 +++++++++--- lib/SIL/Verifier/SILVerifier.cpp | 3 + .../allocstack_hoisting_debuginfo.sil | 257 ++++++++++++++++++ 4 files changed, 420 insertions(+), 38 deletions(-) create mode 100644 test/SILOptimizer/allocstack_hoisting_debuginfo.sil diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index c668c75398715..d56effcb76dac 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -1963,6 +1963,22 @@ class AllocStackInst final /// any point of the program. bool wasMoved = false; + /// Set to true if this AllocStack has var info that a pass purposely + /// invalidated. + /// + /// NOTE: + /// + /// 1. We don't print this state. It is just a way to invalidate the debug + /// info. When we parse back in whatever we printed, we will parse it without + /// debug var info since none will be printed. + /// + /// 2. Since we do not serialize debug info today, we do not need to serialize + /// this state. + /// + /// TODO: If we begin serializing debug info, we will need to begin + /// serializing this! + bool hasInvalidatedVarInfo = false; + AllocStackInst(SILDebugLocation Loc, SILType elementType, ArrayRef TypeDependentOperands, SILFunction &F, Optional Var, bool hasDynamicLifetime, @@ -2019,6 +2035,12 @@ class AllocStackInst final /// Return the debug variable information attached to this instruction. Optional getVarInfo() const { + // If we used to have debug info attached but our debug info is now + // invalidated, just bail. + if (hasInvalidatedVarInfo) { + return None; + } + Optional AuxVarType; Optional VarDeclLoc; const SILDebugScope *VarDeclScope = nullptr; @@ -2039,6 +2061,14 @@ class AllocStackInst final VarDeclScope, DIExprElements); } + bool isVarInfoInvalidated() const { return hasInvalidatedVarInfo; } + + /// Invalidate the debug info in an alloc_stack. This is useful in cases where + /// we one is merging alloc_stack and wants to split the debug info on an + /// alloc_stack into a separate debug_value instruction from the merged + /// alloc_stack. + void invalidateVarInfo() { hasInvalidatedVarInfo = true; } + bool isLet() const { if (auto varInfo = getVarInfo()) return varInfo->isLet(); diff --git a/lib/IRGen/AllocStackHoisting.cpp b/lib/IRGen/AllocStackHoisting.cpp index 9180f6ef66f72..3da635a172c17 100644 --- a/lib/IRGen/AllocStackHoisting.cpp +++ b/lib/IRGen/AllocStackHoisting.cpp @@ -12,16 +12,21 @@ #define DEBUG_TYPE "alloc-stack-hoisting" -#include "swift/IRGen/IRGenSILPasses.h" #include "swift/AST/Availability.h" -#include "swift/SILOptimizer/Analysis/Analysis.h" -#include "swift/SILOptimizer/PassManager/Passes.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/AST/IRGenOptions.h" +#include "swift/AST/SemanticAttrs.h" +#include "swift/IRGen/IRGenSILPasses.h" #include "swift/SIL/DebugUtils.h" +#include "swift/SIL/Dominance.h" +#include "swift/SIL/LoopInfo.h" +#include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILInstruction.h" -#include "swift/SIL/SILArgument.h" -#include "swift/AST/SemanticAttrs.h" +#include "swift/SILOptimizer/Analysis/Analysis.h" +#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "IRGenModule.h" #include "NonFixedTypeInfo.h" @@ -95,7 +100,22 @@ class Partition { /// /// This assumes that the live ranges of the alloc_stack instructions are /// non-overlapping. - void assignStackLocation(SmallVectorImpl &FunctionExits); + void assignStackLocation( + SmallVectorImpl &FunctionExits, + SmallVectorImpl &DebugValueToBreakBlocksAt); + + /// Returns true if any of the alloc_stack that we are merging were + /// moved. Causes us to insert extra debug addr. + /// + /// TODO: In the future we want to do this for /all/ alloc_stack but that + /// would require us moving /most of/ swift's IRGen emission to use + /// llvm.dbg.addr instead of llvm.dbg.declare and that would require us to do + /// statistics to make sure that we haven't hurt debuggability by making the + /// change. + bool hasMovedElt() const { + return llvm::any_of(Elts, + [](AllocStackInst *asi) { return asi->getWasMoved(); }); + } }; } // end anonymous namespace @@ -125,21 +145,40 @@ insertDeallocStackAtEndOf(SmallVectorImpl &FunctionExits, /// Hack to workaround a clang LTO bug. LLVM_ATTRIBUTE_NOINLINE -void moveAllocStackToBeginningOfBlock(AllocStackInst* AS, SILBasicBlock *BB) { +void moveAllocStackToBeginningOfBlock( + AllocStackInst *AS, SILBasicBlock *BB, bool haveMovedElt, + SmallVectorImpl &DebugValueToBreakBlocksAt) { + // If we have var info, create the debug_value at the alloc_stack position and + // invalidate the alloc_stack's var info. This transfers the debug info state + // of the debug_value to the original position. + if (haveMovedElt) { + if (auto varInfo = AS->getVarInfo()) { + SILBuilderWithScope Builder(AS); + auto *DVI = Builder.createDebugValue(AS->getLoc(), AS, *varInfo); + DVI->markAsMoved(); + DebugValueToBreakBlocksAt.push_back(DVI); + AS->invalidateVarInfo(); + AS->markAsMoved(); + } + } AS->moveFront(BB); } /// Assign a single alloc_stack instruction to all the alloc_stacks in the /// partition. void Partition::assignStackLocation( - SmallVectorImpl &FunctionExits) { + SmallVectorImpl &FunctionExits, + SmallVectorImpl &DebugValueToBreakBlocksAt) { assert(!Elts.empty() && "Must have a least one location"); + bool hasAtLeastOneMovedElt = hasMovedElt(); + // The assigned location is the first alloc_stack in our partition. auto *AssignedLoc = Elts[0]; // Move this assigned location to the beginning of the entry block. auto *EntryBB = AssignedLoc->getFunction()->getEntryBlock(); - moveAllocStackToBeginningOfBlock(AssignedLoc, EntryBB); + moveAllocStackToBeginningOfBlock(AssignedLoc, EntryBB, hasAtLeastOneMovedElt, + DebugValueToBreakBlocksAt); // Erase the dealloc_stacks. eraseDeallocStacks(AssignedLoc); @@ -153,6 +192,15 @@ void Partition::assignStackLocation( if (AssignedLoc == AllocStack) continue; eraseDeallocStacks(AllocStack); AllocStack->replaceAllUsesWith(AssignedLoc); + if (hasAtLeastOneMovedElt) { + if (auto VarInfo = AllocStack->getVarInfo()) { + SILBuilderWithScope Builder(AllocStack); + auto *DVI = Builder.createDebugValue(AllocStack->getLoc(), AssignedLoc, + *VarInfo); + DVI->markAsMoved(); + DebugValueToBreakBlocksAt.push_back(DVI); + } + } AllocStack->eraseFromParent(); } } @@ -234,6 +282,13 @@ class MergeStackSlots { SmallVector PartitionByType; /// The function exits. SmallVectorImpl &FunctionExits; + /// If we are merging any alloc_stack that were moved, to work around a bug in + /// SelectionDAG that sinks to llvm.dbg.addr, we need to break blocks right + /// after each llvm.dbg.addr. + /// + /// TODO: Once we have /any/ FastISel/better SelectionDAG support, this can be + /// removed. + SmallVector DebugValueToBreakBlocksAt; public: MergeStackSlots(SmallVectorImpl &AllocStacks, @@ -241,7 +296,7 @@ class MergeStackSlots { /// Merge alloc_stack instructions if possible and hoist them to the entry /// block. - void mergeSlots(); + SILAnalysis::InvalidationKind mergeSlots(DominanceInfo *domToUpdate); }; } // end anonymous namespace @@ -264,7 +319,10 @@ MergeStackSlots::MergeStackSlots(SmallVectorImpl &AllocStacks, /// Merge alloc_stack instructions if possible and hoist them to the entry /// block. -void MergeStackSlots::mergeSlots() { +SILAnalysis::InvalidationKind +MergeStackSlots::mergeSlots(DominanceInfo *DomToUpdate) { + auto Result = SILAnalysis::InvalidationKind::Instructions; + for (auto &PartitionOfOneType : PartitionByType) { Liveness Live(PartitionOfOneType); @@ -312,11 +370,26 @@ void MergeStackSlots::mergeSlots() { // Assign stack locations to disjoint partition hoisting alloc_stacks to the // entry block at the same time. for (auto &Par : DisjointPartitions) { - Par.assignStackLocation(FunctionExits); + Par.assignStackLocation(FunctionExits, DebugValueToBreakBlocksAt); } } -} + // Now that we have finished merging slots/hoisting, break any blocks that we + // need to. + if (!DebugValueToBreakBlocksAt.empty()) { + auto &Mod = DebugValueToBreakBlocksAt.front()->getModule(); + SILBuilderContext Context(Mod); + do { + auto *Next = DebugValueToBreakBlocksAt.pop_back_val(); + splitBasicBlockAndBranch(Context, Next->getNextInstruction(), DomToUpdate, + nullptr); + } while (!DebugValueToBreakBlocksAt.empty()); + + Result = SILAnalysis::InvalidationKind::BranchesAndInstructions; + } + + return Result; +} namespace { /// Hoist alloc_stack instructions to the entry block and merge them. @@ -329,13 +402,20 @@ class HoistAllocStack { SmallVector AllocStackToHoist; SmallVector FunctionExits; + Optional InvalidationKind = None; + + DominanceInfo *DomInfoToUpdate = nullptr; + public: HoistAllocStack(SILFunction *F, irgen::IRGenModule &Mod) : F(F), IRGenMod(Mod) {} - /// Try to hoist generic alloc_stack instructions to the entry block. - /// Returns true if the function was changed. - bool run(); + /// Try to hoist generic alloc_stack instructions to the entry block. Returns + /// none if the function was not changed. Otherwise, returns the analysis + /// invalidation kind to use if the function was changed. + Optional run(); + + void setDominanceToUpdate(DominanceInfo *DI) { DomInfoToUpdate = DI; } private: /// Collect generic alloc_stack instructions that can be moved to the entry @@ -395,37 +475,38 @@ void HoistAllocStack::collectHoistableInstructions() { /// Hoist the alloc_stack instructions to the entry block and sink the /// dealloc_stack instructions to the function exists. void HoistAllocStack::hoist() { - if (SILUseStackSlotMerging) { MergeStackSlots Merger(AllocStackToHoist, FunctionExits); - Merger.mergeSlots(); - } else { - // Hoist alloc_stacks to the entry block and delete dealloc_stacks. - auto *EntryBB = F->getEntryBlock(); - for (auto *AllocStack : AllocStackToHoist) { - // Insert at the beginning of the entry block. - AllocStack->moveFront(EntryBB); - // Delete dealloc_stacks. - eraseDeallocStacks(AllocStack); - } - // Insert dealloc_stack in the exit blocks. - for (auto *AllocStack : AllocStackToHoist) { - insertDeallocStackAtEndOf(FunctionExits, AllocStack); - } + InvalidationKind = Merger.mergeSlots(DomInfoToUpdate); + return; + } + + // Hoist alloc_stacks to the entry block and delete dealloc_stacks. + auto *EntryBB = F->getEntryBlock(); + for (auto *AllocStack : AllocStackToHoist) { + // Insert at the beginning of the entry block. + AllocStack->moveFront(EntryBB); + // Delete dealloc_stacks. + eraseDeallocStacks(AllocStack); + InvalidationKind = SILAnalysis::InvalidationKind::Instructions; + } + // Insert dealloc_stack in the exit blocks. + for (auto *AllocStack : AllocStackToHoist) { + insertDeallocStackAtEndOf(FunctionExits, AllocStack); } } /// Try to hoist generic alloc_stack instructions to the entry block. /// Returns true if the function was changed. -bool HoistAllocStack::run() { +Optional HoistAllocStack::run() { collectHoistableInstructions(); // Nothing to hoist? if (AllocStackToHoist.empty()) - return false; + return {}; hoist(); - return true; + return InvalidationKind; } namespace { @@ -434,9 +515,20 @@ class AllocStackHoisting : public SILFunctionTransform { auto *F = getFunction(); auto *Mod = getIRGenModule(); assert(Mod && "This pass must be run as part of an IRGen pipeline"); - bool Changed = HoistAllocStack(F, *Mod).run(); - if (Changed) { - PM->invalidateAnalysis(F, SILAnalysis::InvalidationKind::Instructions); + + HoistAllocStack Hoist(F, *Mod); + + // Update DomInfo when breaking. We don't use loop info right now this late, + // so we don't need to do that. + auto *DA = getAnalysis(); + if (DA->hasFunctionInfo(F)) + Hoist.setDominanceToUpdate(DA->get(F)); + + auto InvalidationKind = Hoist.run(); + + if (InvalidationKind) { + AnalysisPreserver preserveDominance(DA); + PM->invalidateAnalysis(F, *InvalidationKind); } } }; diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index 11635e4fcd677..e9a7c4b5ec5ee 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -1484,6 +1484,9 @@ class SILVerifier : public SILVerifierBase { verifyOpenedArchetype(AI, AI->getElementType().getASTType()); + require(!AI->isVarInfoInvalidated() || !bool(AI->getVarInfo()), + "AllocStack Var Info should be None if invalidated"); + // There used to be a check if all uses of ASI are inside the alloc-dealloc // range. But apparently it can be the case that ASI has uses after the // dealloc_stack. This can come up if the source contains a diff --git a/test/SILOptimizer/allocstack_hoisting_debuginfo.sil b/test/SILOptimizer/allocstack_hoisting_debuginfo.sil new file mode 100644 index 0000000000000..ccd274849e347 --- /dev/null +++ b/test/SILOptimizer/allocstack_hoisting_debuginfo.sil @@ -0,0 +1,257 @@ +// RUN: %target-sil-opt -enable-sil-verify-all %s -alloc-stack-hoisting -opt-mode=none | %FileCheck %s + +sil_stage canonical + +import Builtin + +// Make sure that we hoist the debug info and split its debug info into a +// separate debug_value. +// +// CHECK-LABEL: sil @hoist_generic_1 : +// CHECK: bb0({{.*}}): +// Make sure the debug info isn't on the alloc_stack any more. +// CHECK: [[STACK:%.*]] = alloc_stack [moved] $T{{[ ]*}} // users: +// CHECK: bb1: +// CHECK: debug_value [moved] [[STACK]] : $*T, let, name "x" +// CHECK-NOT: alloc_stack +// CHECK-NOT: dealloc_stack +// CHECK: bb2: +// CHECK-NOT: alloc_stack +// CHECK-NOT: dealloc_stack +// CHECK: bb3: +// CHECK: dealloc_stack +// CHECK: return +sil @hoist_generic_1 : $@convention(thin) (@in T, Builtin.Int1) -> () { +bb0(%0 : $*T, %1: $Builtin.Int1): + cond_br %1, bb1, bb2 + +bb1: + %2 = alloc_stack [moved] $T, let, name "x" + copy_addr [take] %0 to [initialization] %2 : $*T + destroy_addr %2 : $*T + dealloc_stack %2 : $*T + br bb3 +bb2: + destroy_addr %0 : $*T + br bb3 +bb3: + %3 = tuple () + return %3 : $() +} + +// CHECK-LABEL: sil @hoist_generic_2 : +// CHECK: bb0([[ARG:%.*]] : $*T, +// CHECK-NEXT: [[STACK:%.*]] = alloc_stack [moved] $T{{[ ]*}} // users: +// CHECK-NEXT: cond_br {{%.*}}, bb1, bb4 +// +// CHECK: bb1: +// CHECK-NEXT: debug_value [moved] [[STACK]] : $*T, let, name "x" +// CHECK-NEXT: br bb2 +// +// CHECK: bb2: +// CHECK: debug_value [moved] [[STACK]] : $*T, let, name "y" +// CHECK-NEXT: br bb3 +// +// CHECK: bb3: +// CHECK-NEXT: copy_addr [[ARG]] to [initialization] [[STACK]] +// CHECK-NEXT: destroy_addr [[STACK]] +// CHECK-NEXT: destroy_addr [[ARG]] +// CHECK-NEXT: br bb5 +// +// CHECK: bb4: +// CHECK-NEXT: destroy_addr [[ARG]] +// CHECK-NEXT: br bb5 +// +// CHECK: bb5: +// CHECK-NEXT: br bb6 +// +// CHECK: bb6: +// CHECK-NEXT: tuple +// CHECK-NEXT: dealloc_stack [[STACK]] +// CHECK-NEXT: return +// CHECK: } // end sil function 'hoist_generic_2' +sil @hoist_generic_2 : $@convention(thin) (@in T, Builtin.Int1) -> () { +bb0(%0 : $*T, %1: $Builtin.Int1): + cond_br %1, bb1, bb2 + +bb1: + %2 = alloc_stack [moved] $T, let, name "x" + copy_addr %0 to [initialization] %2 : $*T + destroy_addr %2 : $*T + dealloc_stack %2 : $*T + %3 = alloc_stack [moved] $T, let, name "y" + copy_addr %0 to [initialization] %3 : $*T + destroy_addr %3 : $*T + dealloc_stack %3 : $*T + destroy_addr %0 : $*T + br bb3 + +bb2: + destroy_addr %0 : $*T + br bb3 + +bb3: + br bb4 + +bb4: + %9999 = tuple () + return %9999 : $() +} + +// This case we are not moving anything so we are leaving in the default +// behavior which is not breaking blocks and not inserting debug_info. +// +// CHECK-LABEL: sil @hoist_generic_3 : +// CHECK: bb0([[ARG:%.*]] : $*T, +// CHECK-NEXT: [[STACK:%.*]] = alloc_stack $T{{[ ]*}}, let, name "x" +// CHECK-NOT: debug_value +// CHECK: } // end sil function 'hoist_generic_3' +sil @hoist_generic_3 : $@convention(thin) (@in T, Builtin.Int1) -> () { +bb0(%0 : $*T, %1: $Builtin.Int1): + cond_br %1, bb1, bb2 + +bb1: + %2 = alloc_stack $T, let, name "x" + copy_addr %0 to [initialization] %2 : $*T + destroy_addr %2 : $*T + dealloc_stack %2 : $*T + %3 = alloc_stack $T, let, name "y" + copy_addr %0 to [initialization] %3 : $*T + destroy_addr %3 : $*T + dealloc_stack %3 : $*T + destroy_addr %0 : $*T + br bb3 + +bb2: + destroy_addr %0 : $*T + br bb3 + +bb3: + br bb4 + +bb4: + %9999 = tuple () + return %9999 : $() +} + +//////////////////////////////////////////////// +// Mix and Match Moved and Non Moved -> Moved // +//////////////////////////////////////////////// + +// CHECK-LABEL: sil @mix_and_match_1 : +// CHECK: bb0([[ARG:%.*]] : $*T, +// CHECK-NEXT: [[STACK:%.*]] = alloc_stack [moved] $T{{[ ]*}} // users: +// CHECK-NEXT: cond_br {{%.*}}, bb1, bb4 +// +// CHECK: bb1: +// CHECK-NEXT: debug_value [moved] [[STACK]] : $*T, let, name "x" +// CHECK-NEXT: br bb2 +// +// CHECK: bb2: +// CHECK: debug_value [moved] [[STACK]] : $*T, let, name "y" +// CHECK-NEXT: br bb3 +// +// CHECK: bb3: +// CHECK-NEXT: copy_addr [[ARG]] to [initialization] [[STACK]] +// CHECK-NEXT: destroy_addr [[STACK]] +// CHECK-NEXT: destroy_addr [[ARG]] +// CHECK-NEXT: br bb5 +// +// CHECK: bb4: +// CHECK-NEXT: destroy_addr [[ARG]] +// CHECK-NEXT: br bb5 +// +// CHECK: bb5: +// CHECK-NEXT: br bb6 +// +// CHECK: bb6: +// CHECK-NEXT: tuple +// CHECK-NEXT: dealloc_stack [[STACK]] +// CHECK-NEXT: return +// CHECK: } // end sil function 'mix_and_match_1' +sil @mix_and_match_1 : $@convention(thin) (@in T, Builtin.Int1) -> () { +bb0(%0 : $*T, %1: $Builtin.Int1): + cond_br %1, bb1, bb2 + +bb1: + %2 = alloc_stack $T, let, name "x" + copy_addr %0 to [initialization] %2 : $*T + destroy_addr %2 : $*T + dealloc_stack %2 : $*T + %3 = alloc_stack [moved] $T, let, name "y" + copy_addr %0 to [initialization] %3 : $*T + destroy_addr %3 : $*T + dealloc_stack %3 : $*T + destroy_addr %0 : $*T + br bb3 + +bb2: + destroy_addr %0 : $*T + br bb3 + +bb3: + br bb4 + +bb4: + %9999 = tuple () + return %9999 : $() +} + +// CHECK-LABEL: sil @mix_and_match_2 : +// CHECK: bb0([[ARG:%.*]] : $*T, +// CHECK-NEXT: [[STACK:%.*]] = alloc_stack [moved] $T{{[ ]*}} // users: +// CHECK-NEXT: cond_br {{%.*}}, bb1, bb4 +// +// CHECK: bb1: +// CHECK-NEXT: debug_value [moved] [[STACK]] : $*T, let, name "x" +// CHECK-NEXT: br bb2 +// +// CHECK: bb2: +// CHECK: debug_value [moved] [[STACK]] : $*T, let, name "y" +// CHECK-NEXT: br bb3 +// +// CHECK: bb3: +// CHECK-NEXT: copy_addr [[ARG]] to [initialization] [[STACK]] +// CHECK-NEXT: destroy_addr [[STACK]] +// CHECK-NEXT: destroy_addr [[ARG]] +// CHECK-NEXT: br bb5 +// +// CHECK: bb4: +// CHECK-NEXT: destroy_addr [[ARG]] +// CHECK-NEXT: br bb5 +// +// CHECK: bb5: +// CHECK-NEXT: br bb6 +// +// CHECK: bb6: +// CHECK-NEXT: tuple +// CHECK-NEXT: dealloc_stack [[STACK]] +// CHECK-NEXT: return +// CHECK: } // end sil function 'mix_and_match_2' +sil @mix_and_match_2 : $@convention(thin) (@in T, Builtin.Int1) -> () { +bb0(%0 : $*T, %1: $Builtin.Int1): + cond_br %1, bb1, bb2 + +bb1: + %2 = alloc_stack [moved] $T, let, name "x" + copy_addr %0 to [initialization] %2 : $*T + destroy_addr %2 : $*T + dealloc_stack %2 : $*T + %3 = alloc_stack $T, let, name "y" + copy_addr %0 to [initialization] %3 : $*T + destroy_addr %3 : $*T + dealloc_stack %3 : $*T + destroy_addr %0 : $*T + br bb3 + +bb2: + destroy_addr %0 : $*T + br bb3 + +bb3: + br bb4 + +bb4: + %9999 = tuple () + return %9999 : $() +} From 90893b9511d69c5d06151320d4d4af97d6defeda Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 18 Feb 2022 23:50:44 -0500 Subject: [PATCH 07/17] AST: Types are immutable so there's no reason for TypeBase::findUnresolvedDependentMemberType() to return a 'const' --- include/swift/AST/Types.h | 2 +- lib/AST/Type.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 7b27ef3c266b0..2e4dcca54a420 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -696,7 +696,7 @@ class alignas(1 << TypeAlignInBits) TypeBase /// /// "Unresolved" dependent member types have no known associated type, /// and are only used transiently in the type checker. - const DependentMemberType *findUnresolvedDependentMemberType(); + DependentMemberType *findUnresolvedDependentMemberType(); /// Return the root generic parameter of this type parameter type. GenericTypeParamType *getRootGenericParam(); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 2fb972b602f90..e3eff17ef2b80 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -4540,10 +4540,10 @@ Type Type::subst(TypeSubstitutionFn substitutions, return substType(*this, substitutions, conformances, options); } -const DependentMemberType *TypeBase::findUnresolvedDependentMemberType() { +DependentMemberType *TypeBase::findUnresolvedDependentMemberType() { if (!hasTypeParameter()) return nullptr; - const DependentMemberType *unresolvedDepMemTy = nullptr; + DependentMemberType *unresolvedDepMemTy = nullptr; Type(this).findIf([&](Type type) -> bool { if (auto depMemTy = type->getAs()) { if (depMemTy->getAssocType() == nullptr) { From a3ab5f4cd4b60bf007abf2348d4a4a88f3eb69b8 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 18 Feb 2022 23:51:04 -0500 Subject: [PATCH 08/17] RequirementMachine: Remove no-longer used DebugFlags::Merge --- lib/AST/RequirementMachine/Debug.h | 27 +++++++++---------- lib/AST/RequirementMachine/RewriteContext.cpp | 1 - 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/lib/AST/RequirementMachine/Debug.h b/lib/AST/RequirementMachine/Debug.h index a0b33b5288287..2f7cad9f9b605 100644 --- a/lib/AST/RequirementMachine/Debug.h +++ b/lib/AST/RequirementMachine/Debug.h @@ -26,45 +26,42 @@ enum class DebugFlags : unsigned { /// Print debug output when adding rules. Add = (1<<1), - /// Print debug output when merging associated types. - Merge = (1<<2), - /// Print debug output from the Knuth-Bendix algorithm. - Completion = (1<<3), + Completion = (1<<2), /// Print debug output from property map construction. - PropertyMap = (1<<4), + PropertyMap = (1<<3), /// Print debug output when unifying concrete types in the property map. - ConcreteUnification = (1<<5), + ConcreteUnification = (1<<4), /// Print debug output when concretizing nested types in the property map. - ConcretizeNestedTypes = (1<<6), + ConcretizeNestedTypes = (1<<5), /// Print debug output when inferring conditional requirements in the /// property map. - ConditionalRequirements = (1<<7), + ConditionalRequirements = (1<<6), /// Print debug output from the homotopy reduction algorithm. - HomotopyReduction = (1<<8), + HomotopyReduction = (1<<7), /// Print more detailed debug output from the homotopy reduction algorithm. - HomotopyReductionDetail = (1<<9), + HomotopyReductionDetail = (1<<8), /// Print debug output from the minimal conformances algorithm. - MinimalConformances = (1<<10), + MinimalConformances = (1<<9), /// Print debug output from the protocol dependency graph. - ProtocolDependencies = (1<<11), + ProtocolDependencies = (1<<10), /// Print debug output from generic signature minimization. - Minimization = (1<<12), + Minimization = (1<<11), /// Print redundant rules and their replacement paths. - RedundantRules = (1<<13), + RedundantRules = (1<<12), /// Print more detail about redundant rules. - RedundantRulesDetail = (1<<14) + RedundantRulesDetail = (1<<13) }; using DebugOptions = OptionSet; diff --git a/lib/AST/RequirementMachine/RewriteContext.cpp b/lib/AST/RequirementMachine/RewriteContext.cpp index d1abbecf5eef4..cf3eeee9c1a81 100644 --- a/lib/AST/RequirementMachine/RewriteContext.cpp +++ b/lib/AST/RequirementMachine/RewriteContext.cpp @@ -29,7 +29,6 @@ static DebugOptions parseDebugFlags(StringRef debugFlags) { auto flag = llvm::StringSwitch>(flagStr) .Case("simplify", DebugFlags::Simplify) .Case("add", DebugFlags::Add) - .Case("merge", DebugFlags::Merge) .Case("completion", DebugFlags::Completion) .Case("property-map", DebugFlags::PropertyMap) .Case("concrete-unification", DebugFlags::ConcreteUnification) From e326c01f9b1f6195c64b43b0b4ba3a5ad7f5646a Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 17 Feb 2022 21:54:29 -0500 Subject: [PATCH 09/17] RequirementMachine: Write some comments --- .../SimplifySubstitutions.cpp | 53 ++++++++++++++++++- lib/AST/RequirementMachine/TypeDifference.cpp | 10 ++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/lib/AST/RequirementMachine/SimplifySubstitutions.cpp b/lib/AST/RequirementMachine/SimplifySubstitutions.cpp index 08655eba182d5..e4e9ccfca9f84 100644 --- a/lib/AST/RequirementMachine/SimplifySubstitutions.cpp +++ b/lib/AST/RequirementMachine/SimplifySubstitutions.cpp @@ -1,4 +1,4 @@ -//===--- PropertyUnification.cpp - Rules added w/ building property map ---===// +//===--- SimplifySubstitutions.cpp - Simplify concrete type rules ---------===// // // This source file is part of the Swift.org open source project // @@ -9,6 +9,57 @@ // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// +// +// Implements a pass for simplifying substitutions in concrete type symbols. +// Substitutions can be simplifed in one of two ways; either a substitution +// term can be replaced by a more canonical term, or it can be replaced by a +// concrete type. +// +// For example, given pair of rewrite rules: +// +// T.[concrete: G] => T +// Y => X +// +// We can apply (Y => X) to the term appearing in the concrete type symbol +// [concrete: G] to obtain the rule: +// +// T.[concrete: G] => T +// +// Similarly, if we have a pair of rewrite rules: +// +// T.[concrete: G] => T +// Y.[concrete: Int] => Y +// +// We can obtain the new rule: +// +// T.[concrete: G] => T +// +// Substitution simplification occurs during the Knuth-Bendix completion +// procedure, and after property map construction. +// +// In the first case, no property map is available yet, so substitution terms +// are simplified to other terms, but concrete type replacement is not +// performed. In the second case, the property map is consulted to perform +// concrete type replacement where appropriate. +// +// Either the new rule or the old rule can become redundant; they are related +// by rewrite loops. Additionally, rewrite loops are introduced for each +// transformation applied to the substitutions to relate them to the concrete +// type rules via "projections". +// +// These rewrite loops are in a sense dual to the property map's concrete type +// unification, and share a lot of the code; whereas the property map will +// relate two rules (T.[concrete: G] => T) with (T.[concrete: G] => T) +// and add the induced rule (Y => X), substitution simplification will use +// (Y => X) to transform (T.[concrete: G] => T) into +// (T.[concrete: G] => T). +// +// This logic (and concrete type unification) heavily relies on the "type +// difference" abstraction implemented in TypeDifference.cpp. Technical details +// about the various rewrite loops introduced here can be found in comments at +// the top of various functions below. +// +//===----------------------------------------------------------------------===// #include "PropertyMap.h" #include "RewriteSystem.h" diff --git a/lib/AST/RequirementMachine/TypeDifference.cpp b/lib/AST/RequirementMachine/TypeDifference.cpp index 09e8d7f0df773..f2f6fc0a656ee 100644 --- a/lib/AST/RequirementMachine/TypeDifference.cpp +++ b/lib/AST/RequirementMachine/TypeDifference.cpp @@ -9,6 +9,16 @@ // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// +// +// A mechanism for working with types that are related via the transformation +// of replacing a type parameter term with another type parameter term or +// concrete type. +// +// Used by concrete type unification (in PropertyUnification.cpp) and for +// substitution simplification (SimplifySubstitutions.cpp) to define rewrite +// loops relating various rules for rewrite system minimization. +// +//===----------------------------------------------------------------------===// #include "TypeDifference.h" #include "swift/AST/Types.h" From ae1ef6d50dbaa44acd6041a67c453425dfbabef0 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 18 Feb 2022 23:03:09 -0500 Subject: [PATCH 10/17] RequirementMachine: Eliminate RequirementMachine::initWithAbstractRequirements() --- .../RequirementMachine/RequirementMachine.cpp | 75 ++++++------------- .../RequirementMachine/RequirementMachine.h | 10 ++- .../RequirementMachineRequests.cpp | 21 ++++-- lib/AST/RequirementMachine/RewriteContext.cpp | 4 +- 4 files changed, 47 insertions(+), 63 deletions(-) diff --git a/lib/AST/RequirementMachine/RequirementMachine.cpp b/lib/AST/RequirementMachine/RequirementMachine.cpp index e8d6db609706b..e9c2a0f62e954 100644 --- a/lib/AST/RequirementMachine/RequirementMachine.cpp +++ b/lib/AST/RequirementMachine/RequirementMachine.cpp @@ -36,38 +36,46 @@ RequirementMachine::RequirementMachine(RewriteContext &ctx) RequirementMachine::~RequirementMachine() {} -static void checkCompletionResult(const RequirementMachine &machine, - CompletionResult result) { +/// Checks the result of a completion in a context where we can't diagnose +/// failure, either when building a rewrite system from an existing +/// minimal signature (which should have been checked when it was +/// minimized) or from AbstractGenericSignatureRequest (where failure +/// is fatal). +void RequirementMachine::checkCompletionResult(CompletionResult result) const { switch (result) { case CompletionResult::Success: break; case CompletionResult::MaxRuleCount: llvm::errs() << "Rewrite system exceeded maximum rule count\n"; - machine.dump(llvm::errs()); + dump(llvm::errs()); abort(); case CompletionResult::MaxRuleLength: llvm::errs() << "Rewrite system exceeded rule length limit\n"; - machine.dump(llvm::errs()); + dump(llvm::errs()); abort(); case CompletionResult::MaxConcreteNesting: llvm::errs() << "Rewrite system exceeded concrete type nesting depth limit\n"; - machine.dump(llvm::errs()); + dump(llvm::errs()); abort(); } } /// Build a requirement machine for the requirements of a generic signature. /// +/// In this mode, minimization is not going to be performed, so rewrite loops +/// are not recorded. +/// /// This must only be called exactly once, before any other operations are /// performed on this requirement machine. /// /// Used by ASTContext::getOrCreateRequirementMachine(). /// -/// Asserts if completion fails within the configured number of steps. -void RequirementMachine::initWithGenericSignature(CanGenericSignature sig) { +/// Returns failure if completion fails within the configured number of steps. +std::pair +RequirementMachine::initWithGenericSignature(CanGenericSignature sig) { Sig = sig; Params.append(sig.getGenericParams().begin(), sig.getGenericParams().end()); @@ -92,17 +100,21 @@ void RequirementMachine::initWithGenericSignature(CanGenericSignature sig) { std::move(builder.RequirementRules)); auto result = computeCompletion(RewriteSystem::DisallowInvalidRequirements); - checkCompletionResult(*this, result.first); if (Dump) { llvm::dbgs() << "}\n"; } + + return result; } /// Build a requirement machine for the structural requirements of a set /// of protocols, which are understood to form a strongly-connected component /// (SCC) of the protocol dependency graph. /// +/// In this mode, minimization will be performed, so rewrite loops are recorded +/// during completion. +/// /// This must only be called exactly once, before any other operations are /// performed on this requirement machine. /// @@ -138,55 +150,16 @@ RequirementMachine::initWithProtocols(ArrayRef protos) { return result; } -/// Build a requirement machine from a set of generic parameters and -/// (possibly non-canonical or non-minimal) abstract requirements. -/// -/// This must only be called exactly once, before any other operations are -/// performed on this requirement machine. -/// -/// Used by AbstractGenericSignatureRequest. -/// -/// Asserts if completion fails within the configured number of steps. -void RequirementMachine::initWithAbstractRequirements( - ArrayRef genericParams, - ArrayRef requirements) { - Params.append(genericParams.begin(), genericParams.end()); - - FrontendStatsTracer tracer(Stats, "build-rewrite-system"); - - if (Dump) { - llvm::dbgs() << "Adding generic parameters:"; - for (auto *paramTy : genericParams) - llvm::dbgs() << " " << Type(paramTy); - llvm::dbgs() << "\n"; - } - - // Collect the top-level requirements, and all transtively-referenced - // protocol requirement signatures. - RuleBuilder builder(Context, System.getProtocolMap()); - builder.addRequirements(requirements); - - // Add the initial set of rewrite rules to the rewrite system. - System.initialize(/*recordLoops=*/true, - /*protos=*/ArrayRef(), - std::move(builder.PermanentRules), - std::move(builder.RequirementRules)); - - auto result = computeCompletion(RewriteSystem::AllowInvalidRequirements); - checkCompletionResult(*this, result.first); - - if (Dump) { - llvm::dbgs() << "}\n"; - } -} - /// Build a requirement machine from a set of generic parameters and /// structural requirements. /// +/// In this mode, minimization will be performed, so rewrite loops are recorded +/// during completion. +/// /// This must only be called exactly once, before any other operations are /// performed on this requirement machine. /// -/// Used by InferredGenericSignatureRequest. +/// Used by AbstractGenericSignatureRequest and InferredGenericSignatureRequest. /// /// Returns failure if completion fails within the configured number of steps. std::pair diff --git a/lib/AST/RequirementMachine/RequirementMachine.h b/lib/AST/RequirementMachine/RequirementMachine.h index 124230b5cc680..1dd61075fc371 100644 --- a/lib/AST/RequirementMachine/RequirementMachine.h +++ b/lib/AST/RequirementMachine/RequirementMachine.h @@ -88,12 +88,14 @@ class RequirementMachine final { RequirementMachine &operator=(const RequirementMachine &) = delete; RequirementMachine &operator=(RequirementMachine &&) = delete; - void initWithGenericSignature(CanGenericSignature sig); + void checkCompletionResult(CompletionResult result) const; + + std::pair + initWithGenericSignature(CanGenericSignature sig); + std::pair initWithProtocols(ArrayRef protos); - void initWithAbstractRequirements( - ArrayRef genericParams, - ArrayRef requirements); + std::pair initWithWrittenRequirements( ArrayRef genericParams, diff --git a/lib/AST/RequirementMachine/RequirementMachineRequests.cpp b/lib/AST/RequirementMachine/RequirementMachineRequests.cpp index 29aef8604a11f..3c2c1a216be18 100644 --- a/lib/AST/RequirementMachine/RequirementMachineRequests.cpp +++ b/lib/AST/RequirementMachine/RequirementMachineRequests.cpp @@ -473,9 +473,9 @@ AbstractGenericSignatureRequestRQM::evaluate( return GenericSignatureWithError(result, /*hadError=*/false); } - SmallVector requirements( - baseSignature.getRequirements().begin(), - baseSignature.getRequirements().end()); + SmallVector requirements; + for (auto req : baseSignature.getRequirements()) + requirements.push_back({req, SourceLoc(), /*wasInferred=*/false}); // We need to create this errors vector to pass to // desugarRequirement, but this request should never @@ -492,14 +492,20 @@ AbstractGenericSignatureRequestRQM::evaluate( // Desugaring converts these kinds of requirements into "proper" // requirements where the subject type is always a type parameter, // which is what the RuleBuilder expects. - for (auto req : addedRequirements) - desugarRequirement(req, requirements, errors); + for (auto req : addedRequirements) { + SmallVector reqs; + desugarRequirement(req, reqs, errors); + for (auto req : reqs) + requirements.push_back({req, SourceLoc(), /*wasInferred=*/false}); + } // Heap-allocate the requirement machine to save stack space. std::unique_ptr machine(new RequirementMachine( ctx.getRewriteContext())); - machine->initWithAbstractRequirements(genericParams, requirements); + auto status = + machine->initWithWrittenRequirements(genericParams, requirements); + machine->checkCompletionResult(status.first); auto minimalRequirements = machine->computeMinimalGenericSignatureRequirements(); @@ -611,7 +617,8 @@ InferredGenericSignatureRequestRQM::evaluate( std::unique_ptr machine(new RequirementMachine( ctx.getRewriteContext())); - auto status = machine->initWithWrittenRequirements(genericParams, requirements); + auto status = + machine->initWithWrittenRequirements(genericParams, requirements); if (status.first != CompletionResult::Success) { ctx.Diags.diagnose(loc, diag::requirement_machine_completion_failed, diff --git a/lib/AST/RequirementMachine/RewriteContext.cpp b/lib/AST/RequirementMachine/RewriteContext.cpp index cf3eeee9c1a81..55ab8c791031e 100644 --- a/lib/AST/RequirementMachine/RewriteContext.cpp +++ b/lib/AST/RequirementMachine/RewriteContext.cpp @@ -133,7 +133,9 @@ RequirementMachine *RewriteContext::getRequirementMachine( // This might re-entrantly invalidate 'machine', which is a reference // into Protos. - newMachine->initWithGenericSignature(sig); + auto status = newMachine->initWithGenericSignature(sig); + newMachine->checkCompletionResult(status.first); + return newMachine; } From d36aecca491fc6aec5f2c009472a14126aa6b2f2 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Wed, 16 Feb 2022 17:58:13 +0300 Subject: [PATCH 11/17] Diag: Make 'could_not_use_member_on_existential' less assertive --- include/swift/AST/DiagnosticsSema.def | 4 +- test/Constraints/opened_existentials.swift | 2 +- test/Constraints/protocols.swift | 4 +- test/Generics/function_defs.swift | 2 +- ...ntial_member_accesses_self_assoctype.swift | 304 +++++++++--------- 5 files changed, 158 insertions(+), 158 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 68305a6a91b53..daef26db29e79 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -140,8 +140,8 @@ ERROR(could_not_use_instance_member_on_type,none, "%select{| instance of nested}3 type %0", (Type, DeclNameRef, Type, bool)) ERROR(could_not_use_member_on_existential,none, - "member %1 cannot be used on value of protocol type %0; use a generic" - " constraint instead", + "member %1 cannot be used on value of protocol type %0; consider using a" + " generic constraint instead", (Type, DeclNameRef)) FIXIT(replace_with_type,"%0",(Type)) FIXIT(insert_type_qualification,"%0.",(Type)) diff --git a/test/Constraints/opened_existentials.swift b/test/Constraints/opened_existentials.swift index 064ce9750c763..12ff263c22229 100644 --- a/test/Constraints/opened_existentials.swift +++ b/test/Constraints/opened_existentials.swift @@ -164,7 +164,7 @@ func testReturningOpaqueTypes(p: any P) { let q = p.getQ() let _: Int = q // expected-error{{cannot convert value of type 'Q' to specified type 'Int'}} - p.getCollectionOf() // expected-error{{member 'getCollectionOf' cannot be used on value of protocol type 'P'; use a generic constraint instead}} + p.getCollectionOf() // expected-error{{member 'getCollectionOf' cannot be used on value of protocol type 'P'; consider using a generic constraint instead}} let q2 = getPQ(p) let _: Int = q2 // expected-error{{cannot convert value of type 'Q' to specified type 'Int'}} diff --git a/test/Constraints/protocols.swift b/test/Constraints/protocols.swift index f82e45f3ee30b..6bc8c35dc8c83 100644 --- a/test/Constraints/protocols.swift +++ b/test/Constraints/protocols.swift @@ -370,8 +370,8 @@ func testClonableExistential(_ v: Clonable, _ vv: Clonable.Type) { let _: (Bool) -> Clonable? = id(vv.returnSelfIUOStatic as (Bool) -> Clonable?) let _: Clonable! = id(vv.returnSelfIUOStatic(true)) - let _ = v.badClonerFn() // expected-error {{member 'badClonerFn' cannot be used on value of protocol type 'Clonable'; use a generic constraint instead}} - let _ = v.veryBadClonerFn() // expected-error {{member 'veryBadClonerFn' cannot be used on value of protocol type 'Clonable'; use a generic constraint instead}} + let _ = v.badClonerFn() // expected-error {{member 'badClonerFn' cannot be used on value of protocol type 'Clonable'; consider using a generic constraint instead}} + let _ = v.veryBadClonerFn() // expected-error {{member 'veryBadClonerFn' cannot be used on value of protocol type 'Clonable'; consider using a generic constraint instead}} } diff --git a/test/Generics/function_defs.swift b/test/Generics/function_defs.swift index f716e8011e729..c41e567e00f23 100644 --- a/test/Generics/function_defs.swift +++ b/test/Generics/function_defs.swift @@ -38,7 +38,7 @@ func existential(_ t1: T, t2: T, u: U) eqComp = u if t1.isEqual(eqComp) {} // expected-error{{cannot convert value of type 'EqualComparable' to expected argument type 'T'}} if eqComp.isEqual(t2) {} - // expected-error@-1 {{member 'isEqual' cannot be used on value of protocol type 'EqualComparable'; use a generic constraint instead}} + // expected-error@-1 {{member 'isEqual' cannot be used on value of protocol type 'EqualComparable'; consider using a generic constraint instead}} } protocol OtherEqualComparable { diff --git a/test/decl/protocol/existential_member_accesses_self_assoctype.swift b/test/decl/protocol/existential_member_accesses_self_assoctype.swift index 8bb8645dadc57..f55ea92dc22a1 100644 --- a/test/decl/protocol/existential_member_accesses_self_assoctype.swift +++ b/test/decl/protocol/existential_member_accesses_self_assoctype.swift @@ -318,143 +318,143 @@ do { { (_: () -> Any?) in } ] - arg.contravariantSelf1(0) // expected-error {{member 'contravariantSelf1' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantSelf2(0) // expected-error {{member 'contravariantSelf2' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantSelf3(0) // expected-error {{member 'contravariantSelf3' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantSelf4(0) // expected-error {{member 'contravariantSelf4' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantSelf5(0) // expected-error {{member 'contravariantSelf5' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantSelf6(0) // expected-error {{member 'contravariantSelf6' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantSelf7() // expected-error {{member 'contravariantSelf7' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantSelf8() // expected-error {{member 'contravariantSelf8' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantSelf9(0) // expected-error {{member 'contravariantSelf9' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantSelf10() // expected-error {{member 'contravariantSelf10' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantSelf11(0) // expected-error {{member 'contravariantSelf11' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantAssoc1(0) // expected-error {{member 'contravariantAssoc1' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantAssoc2(0) // expected-error {{member 'contravariantAssoc2' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantAssoc3(0) // expected-error {{member 'contravariantAssoc3' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantAssoc4(0) // expected-error {{member 'contravariantAssoc4' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantAssoc5(0) // expected-error {{member 'contravariantAssoc5' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantAssoc6(0) // expected-error {{member 'contravariantAssoc6' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantAssoc7() // expected-error {{member 'contravariantAssoc7' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantAssoc8() // expected-error {{member 'contravariantAssoc8' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantAssoc9(0) // expected-error {{member 'contravariantAssoc9' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantAssoc10() // expected-error {{member 'contravariantAssoc10' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantAssoc11(0) // expected-error {{member 'contravariantAssoc11' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - - arg.invariantSelf1(0) // expected-error {{member 'invariantSelf1' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} + arg.contravariantSelf1(0) // expected-error {{member 'contravariantSelf1' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantSelf2(0) // expected-error {{member 'contravariantSelf2' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantSelf3(0) // expected-error {{member 'contravariantSelf3' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantSelf4(0) // expected-error {{member 'contravariantSelf4' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantSelf5(0) // expected-error {{member 'contravariantSelf5' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantSelf6(0) // expected-error {{member 'contravariantSelf6' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantSelf7() // expected-error {{member 'contravariantSelf7' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantSelf8() // expected-error {{member 'contravariantSelf8' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantSelf9(0) // expected-error {{member 'contravariantSelf9' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantSelf10() // expected-error {{member 'contravariantSelf10' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantSelf11(0) // expected-error {{member 'contravariantSelf11' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantAssoc1(0) // expected-error {{member 'contravariantAssoc1' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantAssoc2(0) // expected-error {{member 'contravariantAssoc2' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantAssoc3(0) // expected-error {{member 'contravariantAssoc3' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantAssoc4(0) // expected-error {{member 'contravariantAssoc4' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantAssoc5(0) // expected-error {{member 'contravariantAssoc5' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantAssoc6(0) // expected-error {{member 'contravariantAssoc6' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantAssoc7() // expected-error {{member 'contravariantAssoc7' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantAssoc8() // expected-error {{member 'contravariantAssoc8' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantAssoc9(0) // expected-error {{member 'contravariantAssoc9' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantAssoc10() // expected-error {{member 'contravariantAssoc10' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantAssoc11(0) // expected-error {{member 'contravariantAssoc11' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + + arg.invariantSelf1(0) // expected-error {{member 'invariantSelf1' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} if #available(macOS 10.15, *) { _ = arg.invariantSelf1_1() } - arg.invariantSelf2(0) // expected-error {{member 'invariantSelf2' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantSelf3(0) // expected-error {{member 'invariantSelf3' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantSelf4(0) // expected-error {{member 'invariantSelf4' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantSelf5() // expected-error {{member 'invariantSelf5' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantSelf6() // expected-error {{member 'invariantSelf6' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantSelf7(0) // expected-error {{member 'invariantSelf7' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantSelf8(0) // expected-error {{member 'invariantSelf8' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantSelf9(0) // expected-error {{member 'invariantSelf9' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantSelf10(0) // expected-error {{member 'invariantSelf10' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantSelf11() // expected-error {{member 'invariantSelf11' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantAssoc1(0) // expected-error {{member 'invariantAssoc1' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantAssoc2(0) // expected-error {{member 'invariantAssoc2' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantAssoc3(0) // expected-error {{member 'invariantAssoc3' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantAssoc4(0) // expected-error {{member 'invariantAssoc4' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantAssoc5() // expected-error {{member 'invariantAssoc5' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantAssoc6() // expected-error {{member 'invariantAssoc6' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantAssoc7(0) // expected-error {{member 'invariantAssoc7' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantAssoc8(0) // expected-error {{member 'invariantAssoc8' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantAssoc9(0) // expected-error {{member 'invariantAssoc9' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantAssoc10(0) // expected-error {{member 'invariantAssoc10' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantAssoc11() // expected-error {{member 'invariantAssoc11' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - - arg.contravariantSelfProp1 // expected-error {{member 'contravariantSelfProp1' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantSelfProp2 // expected-error {{member 'contravariantSelfProp2' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantSelfProp3 // expected-error {{member 'contravariantSelfProp3' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantSelfProp4 // expected-error {{member 'contravariantSelfProp4' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantSelfProp5 // expected-error {{member 'contravariantSelfProp5' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantSelfProp6 // expected-error {{member 'contravariantSelfProp6' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantSelfProp7 // expected-error {{member 'contravariantSelfProp7' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantSelfProp8 // expected-error {{member 'contravariantSelfProp8' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantSelfProp9 // expected-error {{member 'contravariantSelfProp9' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantSelfProp10 // expected-error {{member 'contravariantSelfProp10' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantSelfProp11 // expected-error {{member 'contravariantSelfProp11' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantAssocProp1 // expected-error {{member 'contravariantAssocProp1' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantAssocProp2 // expected-error {{member 'contravariantAssocProp2' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantAssocProp3 // expected-error {{member 'contravariantAssocProp3' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantAssocProp4 // expected-error {{member 'contravariantAssocProp4' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantAssocProp5 // expected-error {{member 'contravariantAssocProp5' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantAssocProp6 // expected-error {{member 'contravariantAssocProp6' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantAssocProp7 // expected-error {{member 'contravariantAssocProp7' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantAssocProp8 // expected-error {{member 'contravariantAssocProp8' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantAssocProp9 // expected-error {{member 'contravariantAssocProp9' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantAssocProp10 // expected-error {{member 'contravariantAssocProp10' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.contravariantAssocProp11 // expected-error {{member 'contravariantAssocProp11' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - - arg.invariantSelfProp1 // expected-error {{member 'invariantSelfProp1' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} + arg.invariantSelf2(0) // expected-error {{member 'invariantSelf2' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantSelf3(0) // expected-error {{member 'invariantSelf3' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantSelf4(0) // expected-error {{member 'invariantSelf4' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantSelf5() // expected-error {{member 'invariantSelf5' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantSelf6() // expected-error {{member 'invariantSelf6' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantSelf7(0) // expected-error {{member 'invariantSelf7' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantSelf8(0) // expected-error {{member 'invariantSelf8' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantSelf9(0) // expected-error {{member 'invariantSelf9' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantSelf10(0) // expected-error {{member 'invariantSelf10' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantSelf11() // expected-error {{member 'invariantSelf11' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantAssoc1(0) // expected-error {{member 'invariantAssoc1' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantAssoc2(0) // expected-error {{member 'invariantAssoc2' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantAssoc3(0) // expected-error {{member 'invariantAssoc3' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantAssoc4(0) // expected-error {{member 'invariantAssoc4' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantAssoc5() // expected-error {{member 'invariantAssoc5' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantAssoc6() // expected-error {{member 'invariantAssoc6' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantAssoc7(0) // expected-error {{member 'invariantAssoc7' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantAssoc8(0) // expected-error {{member 'invariantAssoc8' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantAssoc9(0) // expected-error {{member 'invariantAssoc9' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantAssoc10(0) // expected-error {{member 'invariantAssoc10' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantAssoc11() // expected-error {{member 'invariantAssoc11' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + + arg.contravariantSelfProp1 // expected-error {{member 'contravariantSelfProp1' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantSelfProp2 // expected-error {{member 'contravariantSelfProp2' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantSelfProp3 // expected-error {{member 'contravariantSelfProp3' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantSelfProp4 // expected-error {{member 'contravariantSelfProp4' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantSelfProp5 // expected-error {{member 'contravariantSelfProp5' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantSelfProp6 // expected-error {{member 'contravariantSelfProp6' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantSelfProp7 // expected-error {{member 'contravariantSelfProp7' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantSelfProp8 // expected-error {{member 'contravariantSelfProp8' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantSelfProp9 // expected-error {{member 'contravariantSelfProp9' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantSelfProp10 // expected-error {{member 'contravariantSelfProp10' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantSelfProp11 // expected-error {{member 'contravariantSelfProp11' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantAssocProp1 // expected-error {{member 'contravariantAssocProp1' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantAssocProp2 // expected-error {{member 'contravariantAssocProp2' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantAssocProp3 // expected-error {{member 'contravariantAssocProp3' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantAssocProp4 // expected-error {{member 'contravariantAssocProp4' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantAssocProp5 // expected-error {{member 'contravariantAssocProp5' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantAssocProp6 // expected-error {{member 'contravariantAssocProp6' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantAssocProp7 // expected-error {{member 'contravariantAssocProp7' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantAssocProp8 // expected-error {{member 'contravariantAssocProp8' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantAssocProp9 // expected-error {{member 'contravariantAssocProp9' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantAssocProp10 // expected-error {{member 'contravariantAssocProp10' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.contravariantAssocProp11 // expected-error {{member 'contravariantAssocProp11' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + + arg.invariantSelfProp1 // expected-error {{member 'invariantSelfProp1' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} if #available(macOS 10.15, *) { _ = arg.invariantSelfProp1_1 } - arg.invariantSelfProp2 // expected-error {{member 'invariantSelfProp2' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantSelfProp3 // expected-error {{member 'invariantSelfProp3' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantSelfProp4 // expected-error {{member 'invariantSelfProp4' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantSelfProp5 // expected-error {{member 'invariantSelfProp5' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantSelfProp6 // expected-error {{member 'invariantSelfProp6' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantSelfProp7 // expected-error {{member 'invariantSelfProp7' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantSelfProp8 // expected-error {{member 'invariantSelfProp8' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantSelfProp9 // expected-error {{member 'invariantSelfProp9' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantSelfProp10 // expected-error {{member 'invariantSelfProp10' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantSelfProp11 // expected-error {{member 'invariantSelfProp11' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantAssocProp1 // expected-error {{member 'invariantAssocProp1' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantAssocProp2 // expected-error {{member 'invariantAssocProp2' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantAssocProp3 // expected-error {{member 'invariantAssocProp3' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantAssocProp4 // expected-error {{member 'invariantAssocProp4' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantAssocProp5 // expected-error {{member 'invariantAssocProp5' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantAssocProp6 // expected-error {{member 'invariantAssocProp6' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantAssocProp7 // expected-error {{member 'invariantAssocProp7' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantAssocProp8 // expected-error {{member 'invariantAssocProp8' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantAssocProp9 // expected-error {{member 'invariantAssocProp9' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantAssocProp10 // expected-error {{member 'invariantAssocProp10' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg.invariantAssocProp11 // expected-error {{member 'invariantAssocProp11' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - - arg[contravariantSelfSubscript1: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[contravariantSelfSubscript2: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[contravariantSelfSubscript3: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[contravariantSelfSubscript4: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[contravariantSelfSubscript5: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[contravariantSelfSubscript6: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[contravariantSelfSubscript7: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[contravariantSelfSubscript8: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[contravariantSelfSubscript9: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[contravariantSelfSubscript10: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[contravariantSelfSubscript11: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[contravariantAssocSubscript1: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[contravariantAssocSubscript2: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[contravariantAssocSubscript3: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[contravariantAssocSubscript4: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[contravariantAssocSubscript5: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[contravariantAssocSubscript6: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[contravariantAssocSubscript7: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[contravariantAssocSubscript8: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[contravariantAssocSubscript9: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[contravariantAssocSubscript10: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[contravariantAssocSubscript11: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - - arg[invariantSelfSubscript1: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[invariantSelfSubscript2: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[invariantSelfSubscript3: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[invariantSelfSubscript4: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[invariantSelfSubscript5: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[invariantSelfSubscript6: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[invariantSelfSubscript7: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[invariantSelfSubscript8: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[invariantAssocSubscript1: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[invariantAssocSubscript2: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[invariantAssocSubscript3: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[invariantAssocSubscript4: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[invariantAssocSubscript5: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[invariantAssocSubscript6: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[invariantAssocSubscript7: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} - arg[invariantAssocSubscript8: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; use a generic constraint instead}} + arg.invariantSelfProp2 // expected-error {{member 'invariantSelfProp2' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantSelfProp3 // expected-error {{member 'invariantSelfProp3' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantSelfProp4 // expected-error {{member 'invariantSelfProp4' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantSelfProp5 // expected-error {{member 'invariantSelfProp5' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantSelfProp6 // expected-error {{member 'invariantSelfProp6' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantSelfProp7 // expected-error {{member 'invariantSelfProp7' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantSelfProp8 // expected-error {{member 'invariantSelfProp8' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantSelfProp9 // expected-error {{member 'invariantSelfProp9' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantSelfProp10 // expected-error {{member 'invariantSelfProp10' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantSelfProp11 // expected-error {{member 'invariantSelfProp11' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantAssocProp1 // expected-error {{member 'invariantAssocProp1' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantAssocProp2 // expected-error {{member 'invariantAssocProp2' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantAssocProp3 // expected-error {{member 'invariantAssocProp3' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantAssocProp4 // expected-error {{member 'invariantAssocProp4' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantAssocProp5 // expected-error {{member 'invariantAssocProp5' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantAssocProp6 // expected-error {{member 'invariantAssocProp6' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantAssocProp7 // expected-error {{member 'invariantAssocProp7' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantAssocProp8 // expected-error {{member 'invariantAssocProp8' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantAssocProp9 // expected-error {{member 'invariantAssocProp9' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantAssocProp10 // expected-error {{member 'invariantAssocProp10' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg.invariantAssocProp11 // expected-error {{member 'invariantAssocProp11' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + + arg[contravariantSelfSubscript1: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[contravariantSelfSubscript2: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[contravariantSelfSubscript3: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[contravariantSelfSubscript4: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[contravariantSelfSubscript5: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[contravariantSelfSubscript6: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[contravariantSelfSubscript7: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[contravariantSelfSubscript8: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[contravariantSelfSubscript9: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[contravariantSelfSubscript10: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[contravariantSelfSubscript11: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[contravariantAssocSubscript1: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[contravariantAssocSubscript2: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[contravariantAssocSubscript3: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[contravariantAssocSubscript4: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[contravariantAssocSubscript5: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[contravariantAssocSubscript6: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[contravariantAssocSubscript7: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[contravariantAssocSubscript8: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[contravariantAssocSubscript9: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[contravariantAssocSubscript10: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[contravariantAssocSubscript11: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + + arg[invariantSelfSubscript1: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[invariantSelfSubscript2: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[invariantSelfSubscript3: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[invariantSelfSubscript4: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[invariantSelfSubscript5: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[invariantSelfSubscript6: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[invariantSelfSubscript7: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[invariantSelfSubscript8: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[invariantAssocSubscript1: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[invariantAssocSubscript2: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[invariantAssocSubscript3: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[invariantAssocSubscript4: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[invariantAssocSubscript5: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[invariantAssocSubscript6: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[invariantAssocSubscript7: 0] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} + arg[invariantAssocSubscript8: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} } } @@ -484,7 +484,7 @@ do { protoMeta.static_invariantSelfProp // expected-error {{static member 'static_invariantSelfProp' cannot be used on protocol metatype '(P1_TypeMemberOnInstanceAndViceVersa).Protocol'}} protoMeta[static_invariantSelfSubscript: ()] // expected-error {{static member 'subscript' cannot be used on protocol metatype '(P1_TypeMemberOnInstanceAndViceVersa).Protocol'}} _ = protoMeta.covariantSelfMethod // ok - protoMeta.invariantSelfMethod // expected-error {{member 'invariantSelfMethod' cannot be used on value of protocol type '(P1_TypeMemberOnInstanceAndViceVersa).Protocol'; use a generic constraint instead}} + protoMeta.invariantSelfMethod // expected-error {{member 'invariantSelfMethod' cannot be used on value of protocol type '(P1_TypeMemberOnInstanceAndViceVersa).Protocol'; consider using a generic constraint instead}} protoMeta.invariantSelfProp // expected-error {{instance member 'invariantSelfProp' cannot be used on type 'P1_TypeMemberOnInstanceAndViceVersa'}} protoMeta[invariantSelfSubscript: ()] // expected-error {{instance member 'subscript' cannot be used on type 'P1_TypeMemberOnInstanceAndViceVersa'}} @@ -492,9 +492,9 @@ do { _ = existMeta.static_covariantSelfMethod // ok _ = existMeta.static_covariantSelfProp // ok _ = existMeta[static_covariantSelfSubscript: ()] // ok - existMeta.static_invariantSelfMethod // expected-error {{member 'static_invariantSelfMethod' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa.Type'; use a generic constraint instead}} - existMeta.static_invariantSelfProp // expected-error {{member 'static_invariantSelfProp' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa.Type'; use a generic constraint instead}} - existMeta[static_invariantSelfSubscript: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa.Type'; use a generic constraint instead}} + existMeta.static_invariantSelfMethod // expected-error {{member 'static_invariantSelfMethod' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa.Type'; consider using a generic constraint instead}} + existMeta.static_invariantSelfProp // expected-error {{member 'static_invariantSelfProp' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa.Type'; consider using a generic constraint instead}} + existMeta[static_invariantSelfSubscript: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa.Type'; consider using a generic constraint instead}} existMeta.invariantSelfMethod // expected-error {{instance member 'invariantSelfMethod' cannot be used on type 'P1_TypeMemberOnInstanceAndViceVersa'}} existMeta.invariantSelfProp // expected-error {{instance member 'invariantSelfProp' cannot be used on type 'P1_TypeMemberOnInstanceAndViceVersa'}} existMeta[invariantSelfSubscript: ()] // expected-error {{instance member 'subscript' cannot be used on type 'P1_TypeMemberOnInstanceAndViceVersa'}} @@ -548,14 +548,14 @@ do { _ = exist.method3(false) // ok exist.method4(false) // expected-error@-1 {{instance method 'method4' requires that 'Bool' inherit from 'Class'}} - // expected-error@-2 {{member 'method4' cannot be used on value of protocol type 'UnfulfillableGenericRequirements'; use a generic constraint instead}} + // expected-error@-2 {{member 'method4' cannot be used on value of protocol type 'UnfulfillableGenericRequirements'; consider using a generic constraint instead}} exist.method5(false) // expected-error@-1 {{instance method 'method5' requires that 'Bool' conform to 'Sequence'}} - // expected-error@-2 {{member 'method5' cannot be used on value of protocol type 'UnfulfillableGenericRequirements'; use a generic constraint instead}} + // expected-error@-2 {{member 'method5' cannot be used on value of protocol type 'UnfulfillableGenericRequirements'; consider using a generic constraint instead}} exist.method7(false) // expected-error@-1 {{instance method 'method7' requires that 'U' conform to 'UnfulfillableGenericRequirements'}} - // expected-error@-2 {{member 'method7' cannot be used on value of protocol type 'UnfulfillableGenericRequirements'; use a generic constraint instead}} + // expected-error@-2 {{member 'method7' cannot be used on value of protocol type 'UnfulfillableGenericRequirements'; consider using a generic constraint instead}} } protocol UnfulfillableGenericRequirementsDerived1: UnfulfillableGenericRequirements where A == Bool {} protocol UnfulfillableGenericRequirementsDerived2: UnfulfillableGenericRequirements where A == Class {} @@ -567,7 +567,7 @@ do { exist1.method4(false) // expected-error@-1 {{instance method 'method4' requires that 'Bool' inherit from 'Class}} exist2.method4(false) - // expected-error@-1 {{member 'method4' cannot be used on value of protocol type 'UnfulfillableGenericRequirementsDerived2'; use a generic constraint instead}} + // expected-error@-1 {{member 'method4' cannot be used on value of protocol type 'UnfulfillableGenericRequirementsDerived2'; consider using a generic constraint instead}} // expected-error@-2 {{instance method 'method4' requires that 'Bool' inherit from 'Class'}} } protocol UnfulfillableGenericRequirementsDerived3: UnfulfillableGenericRequirements where A: Sequence, A.Element: Sequence {} @@ -582,7 +582,7 @@ do { // expected-error@-2 {{instance method 'method6' requires that 'Self.A' conform to 'Sequence'}} // expected-error@-3 {{instance method 'method6' requires that 'Bool' conform to 'UnfulfillableGenericRequirements'}} exist2.method6(false) - // expected-error@-1 {{member 'method6' cannot be used on value of protocol type 'UnfulfillableGenericRequirementsDerived3'; use a generic constraint instead}} + // expected-error@-1 {{member 'method6' cannot be used on value of protocol type 'UnfulfillableGenericRequirementsDerived3'; consider using a generic constraint instead}} // expected-error@-2 {{instance method 'method6' requires that 'Bool' conform to 'UnfulfillableGenericRequirements'}} } @@ -603,7 +603,7 @@ do { exist.method1() // expected-error {{instance method 'method1()' requires that 'Self.A' conform to 'InvalidTypeParameters'}} exist.method2(false) // expected-error {{instance method 'method2' requires that 'Self.A' conform to 'InvalidTypeParameters'}} exist.method3(false, false) // expected-error {{instance method 'method3' requires that 'Self.A' conform to 'InvalidTypeParameters'}} - // expected-error@-1 {{member 'method3' cannot be used on value of protocol type 'InvalidTypeParameters'; use a generic constraint instead}} + // expected-error@-1 {{member 'method3' cannot be used on value of protocol type 'InvalidTypeParameters'; consider using a generic constraint instead}} } protocol GenericRequirementFailures { @@ -623,7 +623,7 @@ do { exist.method1() // expected-error {{referencing instance method 'method1()' on 'GenericRequirementFailures' requires the types 'Self.A' and 'Never' be equivalent}} exist.method2() // expected-error {{referencing instance method 'method2()' on 'GenericRequirementFailures' requires the types 'Self.A' and 'Never' be equivalent}} exist.method3(false) // expected-error {{referencing instance method 'method3' on 'GenericRequirementFailures' requires the types 'Self.A' and 'Never' be equivalent}} - // expected-error@-1 {{member 'method3' cannot be used on value of protocol type 'GenericRequirementFailures'; use a generic constraint instead}} + // expected-error@-1 {{member 'method3' cannot be used on value of protocol type 'GenericRequirementFailures'; consider using a generic constraint instead}} exist.method4() // expected-error {{referencing instance method 'method4()' on 'GenericRequirementFailures' requires that 'Self.A' conform to 'GenericRequirementFailures'}} } protocol GenericRequirementFailuresDerived: GenericRequirementFailures where A: GenericRequirementFailures {} @@ -642,9 +642,9 @@ protocol P2 { } func takesP2(p2: any P2) { _ = p2[] - // expected-error@-1{{member 'subscript' cannot be used on value of protocol type 'P2'; use a generic constraint instead}} + // expected-error@-1{{member 'subscript' cannot be used on value of protocol type 'P2'; consider using a generic constraint instead}} _ = p2.prop - // expected-error@-1{{member 'prop' cannot be used on value of protocol type 'P2'; use a generic constraint instead}} + // expected-error@-1{{member 'prop' cannot be used on value of protocol type 'P2'; consider using a generic constraint instead}} } protocol MiscTestsProto { @@ -745,16 +745,16 @@ protocol ConcreteAssocTypes { } do { func test(arg: any ConcreteAssocTypes) { - _ = arg.method1 // expected-error {{member 'method1' cannot be used on value of protocol type 'ConcreteAssocTypes'; use a generic constraint instead}} - _ = arg.method2 // expected-error {{member 'method2' cannot be used on value of protocol type 'ConcreteAssocTypes'; use a generic constraint instead}} - _ = arg.method3 // expected-error {{member 'method3' cannot be used on value of protocol type 'ConcreteAssocTypes'; use a generic constraint instead}} - _ = arg.property1 // expected-error {{member 'property1' cannot be used on value of protocol type 'ConcreteAssocTypes'; use a generic constraint instead}} + _ = arg.method1 // expected-error {{member 'method1' cannot be used on value of protocol type 'ConcreteAssocTypes'; consider using a generic constraint instead}} + _ = arg.method2 // expected-error {{member 'method2' cannot be used on value of protocol type 'ConcreteAssocTypes'; consider using a generic constraint instead}} + _ = arg.method3 // expected-error {{member 'method3' cannot be used on value of protocol type 'ConcreteAssocTypes'; consider using a generic constraint instead}} + _ = arg.property1 // expected-error {{member 'property1' cannot be used on value of protocol type 'ConcreteAssocTypes'; consider using a generic constraint instead}} // Covariant 'Self' erasure works in conjunction with concrete associated types. let _: (Bool, any ConcreteAssocTypes) = arg.property2 // ok - _ = arg.property3 // expected-error {{member 'property3' cannot be used on value of protocol type 'ConcreteAssocTypes'; use a generic constraint instead}} - _ = arg[subscript1: false] // expected-error {{member 'subscript' cannot be used on value of protocol type 'ConcreteAssocTypes'; use a generic constraint instead}} - _ = arg[subscript2: false] // expected-error {{member 'subscript' cannot be used on value of protocol type 'ConcreteAssocTypes'; use a generic constraint instead}} - _ = arg[subscript3: false] // expected-error {{member 'subscript' cannot be used on value of protocol type 'ConcreteAssocTypes'; use a generic constraint instead}} + _ = arg.property3 // expected-error {{member 'property3' cannot be used on value of protocol type 'ConcreteAssocTypes'; consider using a generic constraint instead}} + _ = arg[subscript1: false] // expected-error {{member 'subscript' cannot be used on value of protocol type 'ConcreteAssocTypes'; consider using a generic constraint instead}} + _ = arg[subscript2: false] // expected-error {{member 'subscript' cannot be used on value of protocol type 'ConcreteAssocTypes'; consider using a generic constraint instead}} + _ = arg[subscript3: false] // expected-error {{member 'subscript' cannot be used on value of protocol type 'ConcreteAssocTypes'; consider using a generic constraint instead}} let _: ( Struct, (any ConcreteAssocTypes).Type, () -> Bool From f239dbcf54a18b22ad5a7b525661ab82be6ec303 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Fri, 4 Feb 2022 03:05:11 +0300 Subject: [PATCH 12/17] [SE-309] CSDiag: Add a fix-it that replaces an existential parameter type with its generic equivalent --- lib/Sema/CSDiagnostics.cpp | 146 ++++++++++++- ...member_accesses_self_assoctype_fixit.swift | 206 ++++++++++++++++++ 2 files changed, 342 insertions(+), 10 deletions(-) create mode 100644 test/decl/protocol/existential_member_accesses_self_assoctype_fixit.swift diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index d09fedd1d531d..f64b6e06c5a4d 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -3933,19 +3933,145 @@ bool UnintendedExtraGenericParamMemberFailure::diagnoseAsError() { } bool InvalidMemberRefOnExistential::diagnoseAsError() { - auto anchor = getRawAnchor(); + const auto Anchor = getRawAnchor(); - DeclNameLoc nameLoc; - if (auto *UDE = getAsExpr(anchor)) { - nameLoc = UDE->getNameLoc(); - } else if (auto *UME = getAsExpr(anchor)) { - nameLoc = UME->getNameLoc(); + DeclNameLoc NameLoc; + ParamDecl *PD = nullptr; + if (auto *UDE = getAsExpr(Anchor)) { + NameLoc = UDE->getNameLoc(); + if (auto *DRE = dyn_cast(UDE->getBase())) { + PD = dyn_cast(DRE->getDecl()); + } + } else if (auto *UME = getAsExpr(Anchor)) { + NameLoc = UME->getNameLoc(); + } else if (auto *SE = getAsExpr(Anchor)) { + if (auto *DRE = dyn_cast(SE->getBase())) { + PD = dyn_cast(DRE->getDecl()); + } } - emitDiagnostic(diag::could_not_use_member_on_existential, getBaseType(), - getName()) - .highlight(nameLoc.getSourceRange()) - .highlight(getSourceRange()); + auto Diag = emitDiagnostic(diag::could_not_use_member_on_existential, + getBaseType(), getName()); + Diag.highlight(NameLoc.getSourceRange()); + Diag.highlight(getSourceRange()); + + // If the base expression is a reference to a function or subscript + // parameter, offer a fixit that replaces the existential parameter type with + // its generic equivalent, e.g. func foo(p: any P) → func foo(p: T). + // FIXME: Add an option to use 'some' vs. an explicit generic parameter. + + if (!PD || !PD->getDeclContext()->getAsDecl()) + return true; + + // Code inside a subscript is bound against a duplicate set of implicit + // accessor parameters, which don't have a TypeRepr; dig out the corresponding + // explicit subscript parameter. + if (auto *const AD = + dyn_cast(PD->getDeclContext()->getAsDecl())) { + auto *const SD = dyn_cast(AD->getStorage()); + if (!SD) + return true; + + const auto AccessorParams = AD->getParameters()->getArray(); + const unsigned idx = + llvm::find(AccessorParams, PD) - AccessorParams.begin(); + + switch (AD->getAccessorKind()) { + case AccessorKind::Set: + case AccessorKind::WillSet: + case AccessorKind::DidSet: + // Ignore references to the 'newValue' or 'oldValue' parameters. + if (AccessorParams.front() == PD) { + return true; + } + + PD = SD->getIndices()->get(idx - 1); + break; + + case AccessorKind::Get: + case AccessorKind::Read: + case AccessorKind::Modify: + case AccessorKind::Address: + case AccessorKind::MutableAddress: + PD = SD->getIndices()->get(idx); + break; + } + } + + // Bail out in the absence of a TypeRepr. + if (!PD->getTypeRepr()) + return true; + + // Give up on 'inout' parameters. The intent is far more vague in this case, + // and applying the fix-it would invalidate mutations. + if (PD->isInOut()) + return true; + + constexpr StringRef GPNamePlaceholder = "<#generic parameter name#>"; + SourceRange TyReplacementRange; + SourceRange RemoveAnyRange; + SourceLoc GPDeclLoc; + std::string GPDeclStr; + { + llvm::raw_string_ostream OS(GPDeclStr); + auto *const GC = PD->getDeclContext()->getAsDecl()->getAsGenericContext(); + if (GC->getParsedGenericParams()) { + GPDeclLoc = GC->getParsedGenericParams()->getRAngleLoc(); + OS << ", "; + } else { + GPDeclLoc = + isa(GC) + ? cast(GC)->getParameters()->getLParenLoc() + : cast(GC)->getIndices()->getLParenLoc(); + OS << "<"; + } + OS << GPNamePlaceholder << ": "; + + auto *TR = PD->getTypeRepr()->getWithoutParens(); + if (auto *STR = dyn_cast(TR)) { + TR = STR->getBase()->getWithoutParens(); + } + if (auto *ETR = dyn_cast(TR)) { + TR = ETR->getConstraint(); + RemoveAnyRange = SourceRange(ETR->getAnyLoc(), TR->getStartLoc()); + TR = TR->getWithoutParens(); + } + if (auto *MTR = dyn_cast(TR)) { + TR = MTR->getBase(); + + // (P & Q).Type -> T.Type + // (P).Type -> (T).Type + // ((P & Q)).Type -> ((T)).Type + if (auto *TTR = dyn_cast(TR)) { + assert(TTR->isParenType()); + if (!isa(TTR->getElementType(0))) { + TR = TR->getWithoutParens(); + } + } + } + TyReplacementRange = TR->getSourceRange(); + + // Strip any remaining parentheses and print the conformance constraint. + TR->getWithoutParens()->print(OS); + + if (!GC->getParsedGenericParams()) { + OS << ">"; + } + } + + // First, replace the constraint type with the generic parameter type + // placeholder. + Diag.fixItReplace(TyReplacementRange, GPNamePlaceholder); + + // Remove 'any' if needed, using a character-based removal to pick up + // whitespaces between it and its constraint repr. + if (RemoveAnyRange.isValid()) { + Diag.fixItRemoveChars(RemoveAnyRange.Start, RemoveAnyRange.End); + } + + // Finally, insert the generic parameter declaration. + Diag.fixItInsert(GPDeclLoc, GPDeclStr); + return true; } diff --git a/test/decl/protocol/existential_member_accesses_self_assoctype_fixit.swift b/test/decl/protocol/existential_member_accesses_self_assoctype_fixit.swift new file mode 100644 index 0000000000000..2b6b80699617e --- /dev/null +++ b/test/decl/protocol/existential_member_accesses_self_assoctype_fixit.swift @@ -0,0 +1,206 @@ +// RUN: %target-typecheck-verify-swift + +protocol P { + associatedtype A + + func method(_: A) + subscript(_: A) -> A { get } + init(_: A) + + static func staticMethod(_: A) +} +protocol Q {} + +do { + func test(p: P) { // expected-warning {{protocol 'P' as a type must be explicitly marked as 'any'}} + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type 'P'; consider using a generic constraint instead}} {{-1:16--1:17=<#generic parameter name#>}} {{-1:12--1:12=<<#generic parameter name#>: P>}} {{none}} + } +} +do { + func test(p: ((P))) { // expected-warning {{protocol 'P' as a type must be explicitly marked as 'any'}} + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type 'P'; consider using a generic constraint instead}} {{-1:18--1:19=<#generic parameter name#>}} {{-1:12--1:12=<<#generic parameter name#>: P>}} {{none}} + } +} +do { + func test(p: any P) { + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type 'P'; consider using a generic constraint instead}} {{-1:20--1:21=<#generic parameter name#>}} {{-1:16--1:20=}} {{-1:12--1:12=<<#generic parameter name#>: P>}} {{none}} + } +} +do { + func test(p: (inout any P)) { + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type 'P'; consider using a generic constraint instead}} {{none}} + } +} +do { + func test(p: __shared (any P)) { + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type 'P'; consider using a generic constraint instead}} {{-1:30--1:31=<#generic parameter name#>}} {{-1:26--1:30=}} {{-1:12--1:12=<<#generic parameter name#>: P>}} {{none}} + } +} +do { + func test(p: ((any P))) { + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type 'P'; consider using a generic constraint instead}} {{-1:22--1:23=<#generic parameter name#>}} {{-1:18--1:22=}} {{-1:12--1:12=<<#generic parameter name#>: P>}} {{none}} + } +} +do { + func test(p: any (P)) { + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type '(P)'; consider using a generic constraint instead}} {{-1:21--1:22=<#generic parameter name#>}} {{-1:16--1:20=}} {{-1:12--1:12=<<#generic parameter name#>: P>}} {{none}} + } +} +do { + func test(p: any P) { + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type 'P'; consider using a generic constraint instead}} {{-1:22--1:23=<#generic parameter name#>}} {{-1:16--1:22=}} {{-1:12--1:12=<<#generic parameter name#>: P>}} {{none}} + } +} +do { + func test(p: (any (P))) { + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type '(P)'; consider using a generic constraint instead}} {{-1:23--1:24=<#generic parameter name#>}} {{-1:17--1:22=}} {{-1:12--1:12=<<#generic parameter name#>: P>}} {{none}} + } +} +do { + func test(p: P.Type) { // expected-warning {{protocol 'P' as a type must be explicitly marked as 'any'}} + p.staticMethod(false) // expected-error {{member 'staticMethod' cannot be used on value of protocol type 'P.Type'; consider using a generic constraint instead}} {{-1:16--1:17=<#generic parameter name#>}} {{-1:12--1:12=<<#generic parameter name#>: P>}} {{none}} + } +} +do { + func test(p: (P).Type) { // expected-warning {{protocol 'P' as a type must be explicitly marked as 'any'}} + p.staticMethod(false) // expected-error {{member 'staticMethod' cannot be used on value of protocol type '(P).Type'; consider using a generic constraint instead}} {{-1:17--1:18=<#generic parameter name#>}} {{-1:12--1:12=<<#generic parameter name#>: P>}} {{none}} + } +} +do { + func test(p: any P.Type) { + p.staticMethod(false) // expected-error {{member 'staticMethod' cannot be used on value of protocol type 'P.Type'; consider using a generic constraint instead}} {{-1:20--1:21=<#generic parameter name#>}} {{-1:16--1:20=}} {{-1:12--1:12=<<#generic parameter name#>: P>}} {{none}} + } +} +do { + func test(p: any ((P).Type)) { + p.staticMethod(false) // expected-error {{member 'staticMethod' cannot be used on value of protocol type '(P).Type'; consider using a generic constraint instead}} {{-1:22--1:23=<#generic parameter name#>}} {{-1:16--1:20=}} {{-1:12--1:12=<<#generic parameter name#>: P>}} {{none}} + } +} + +do { + func test(p: P & Q) { // expected-warning {{protocol 'P' as a type must be explicitly marked as 'any'}} + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type 'P & Q'; consider using a generic constraint instead}} {{-1:16--1:21=<#generic parameter name#>}} {{-1:12--1:12=<<#generic parameter name#>: P & Q>}} {{none}} + } +} +do { + func test(p: ((P & Q))) { // expected-warning {{protocol 'P' as a type must be explicitly marked as 'any'}} + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type 'P & Q'; consider using a generic constraint instead}} {{-1:18--1:23=<#generic parameter name#>}} {{-1:12--1:12=<<#generic parameter name#>: P & Q>}} {{none}} + } +} +do { + func test(p: any P & Q) { + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type 'P & Q'; consider using a generic constraint instead}} {{-1:20--1:25=<#generic parameter name#>}} {{-1:16--1:20=}} {{-1:12--1:12=<<#generic parameter name#>: P & Q>}} {{none}} + } +} +do { + func test(p: inout any P & Q) { + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type 'P & Q'; consider using a generic constraint instead}} {{none}} + } +} +do { + func test(p: __shared (any P & Q)) { + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type 'P & Q'; consider using a generic constraint instead}} {{-1:30--1:35=<#generic parameter name#>}} {{-1:26--1:30=}} {{-1:12--1:12=<<#generic parameter name#>: P & Q>}} {{none}} + } +} +do { + func test(p: ((any P & Q))) { + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type 'P & Q'; consider using a generic constraint instead}} {{-1:22--1:27=<#generic parameter name#>}} {{-1:18--1:22=}} {{-1:12--1:12=<<#generic parameter name#>: P & Q>}} {{none}} + } +} +do { + func test(p: any (P & Q)) { + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type '(P & Q)'; consider using a generic constraint instead}} {{-1:21--1:26=<#generic parameter name#>}} {{-1:16--1:20=}} {{-1:12--1:12=<<#generic parameter name#>: P & Q>}} {{none}} + } +} +do { + func test(p: any P & Q) { + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type 'P & Q'; consider using a generic constraint instead}} {{-1:22--1:27=<#generic parameter name#>}} {{-1:16--1:22=}} {{-1:12--1:12=<<#generic parameter name#>: P & Q>}} {{none}} + } +} +do { + func test(p: (any (P & Q))) { + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type '(P & Q)'; consider using a generic constraint instead}} {{-1:23--1:28=<#generic parameter name#>}} {{-1:17--1:22=}} {{-1:12--1:12=<<#generic parameter name#>: P & Q>}} {{none}} + } +} +do { + func test(p: (P & Q).Type) { // expected-warning {{protocol 'P' as a type must be explicitly marked as 'any'}} + p.staticMethod(false) // expected-error {{member 'staticMethod' cannot be used on value of protocol type '(P & Q).Type'; consider using a generic constraint instead}} {{-1:16--1:23=<#generic parameter name#>}} {{-1:12--1:12=<<#generic parameter name#>: P & Q>}} {{none}} + } +} +do { + func test(p: ((P & Q)).Type) { // expected-warning {{protocol 'P' as a type must be explicitly marked as 'any'}} + p.staticMethod(false) // expected-error {{member 'staticMethod' cannot be used on value of protocol type '((P & Q)).Type'; consider using a generic constraint instead}} {{-1:18--1:23=<#generic parameter name#>}} {{-1:12--1:12=<<#generic parameter name#>: P & Q>}} {{none}} + } +} +do { + func test(p: any (P & Q).Type) { + p.staticMethod(false) // expected-error {{member 'staticMethod' cannot be used on value of protocol type '(P & Q).Type'; consider using a generic constraint instead}} {{-1:20--1:27=<#generic parameter name#>}} {{-1:16--1:20=}} {{-1:12--1:12=<<#generic parameter name#>: P & Q>}} {{none}} + } +} +do { + func test(p: any (((P & Q)).Type)) { + p.staticMethod(false) // expected-error {{member 'staticMethod' cannot be used on value of protocol type '((P & Q)).Type'; consider using a generic constraint instead}} {{-1:23--1:28=<#generic parameter name#>}} {{-1:16--1:20=}} {{-1:12--1:12=<<#generic parameter name#>: P & Q>}} {{none}} + } +} + +do { + // With an existing generic parameter list. + func test(t: T, p: any P) { + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type 'P'; consider using a generic constraint instead}} {{-1:39--1:40=<#generic parameter name#>}} {{-1:35--1:39=}} {{-1:24--1:24=, <#generic parameter name#>: P}} {{none}} + } +} +do { + // With an subscript expression. + func test(p: any P) { + p[false] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P'; consider using a generic constraint instead}} {{-1:20--1:21=<#generic parameter name#>}} {{-1:16--1:20=}} {{-1:12--1:12=<<#generic parameter name#>: P>}} {{none}} + } +} +do { + // With an initializer. + func test(p: any P.Type) { + p.init(false) // expected-error {{member 'init' cannot be used on value of protocol type 'P.Type'; consider using a generic constraint instead}} {{-1:20--1:21=<#generic parameter name#>}} {{-1:16--1:20=}} {{-1:12--1:12=<<#generic parameter name#>: P>}} {{none}} + } +} + +// Inside initializers, accessors and subscripts. +struct Test { + init(p: any P) { + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type 'P'; consider using a generic constraint instead}} {{-1:15--1:16=<#generic parameter name#>}} {{-1:11--1:15=}} {{-1:7--1:7=<<#generic parameter name#>: P>}} {{none}} + } + + init(p: any P, t: T) { + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type 'P'; consider using a generic constraint instead}} {{-1:21--1:22=<#generic parameter name#>}} {{-1:17--1:21=}} {{-1:12--1:12=, <#generic parameter name#>: P}} {{none}} + } + + subscript(p: any P) -> any P { + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type 'P'; consider using a generic constraint instead}} {{-1:20--1:21=<#generic parameter name#>}} {{-1:16--1:20=}} {{-1:12--1:12=<<#generic parameter name#>: P>}} {{none}} + return p + } + + subscript(p: any P, t: T) -> any P { + get { + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type 'P'; consider using a generic constraint instead}} {{-2:26--2:27=<#generic parameter name#>}} {{-2:22--2:26=}} {{-2:17--2:17=, <#generic parameter name#>: P}} {{none}} + return p + } + set(value) { + p.method(false) // expected-error {{member 'method' cannot be used on value of protocol type 'P'; consider using a generic constraint instead}} {{-6:26--6:27=<#generic parameter name#>}} {{-6:22--6:26=}} {{-6:17--6:17=, <#generic parameter name#>: P}} {{none}} + value.method(false) // expected-error {{member 'method' cannot be used on value of protocol type 'P'; consider using a generic constraint instead}} {{none}} + } + } + + subscript(p: any P & Q) -> any P { + _read { p.method(false) } // expected-error {{member 'method' cannot be used on value of protocol type 'P & Q'; consider using a generic constraint instead}} {{-1:20--1:25=<#generic parameter name#>}} {{-1:16--1:20=}} {{-1:12--1:12=<<#generic parameter name#>: P & Q>}} {{none}} + _modify { p.method(false) } // expected-error {{member 'method' cannot be used on value of protocol type 'P & Q'; consider using a generic constraint instead}} {{-2:20--2:25=<#generic parameter name#>}} {{-2:16--2:20=}} {{-2:12--2:12=<<#generic parameter name#>: P & Q>}} {{none}} + willSet { p.method(false) } // expected-error {{member 'method' cannot be used on value of protocol type 'P'; consider using a generic constraint instead}} {{-3:20--3:25=<#generic parameter name#>}} {{-3:16--3:20=}} {{-3:12--3:12=<<#generic parameter name#>: P & Q>}} {{none}} + didSet { p.method(false) } // expected-error {{member 'method' cannot be used on value of protocol type 'P'; consider using a generic constraint instead}} {{-4:20--4:25=<#generic parameter name#>}} {{-4:16--4:20=}} {{-4:12--4:12=<<#generic parameter name#>: P & Q>}} {{none}} + // expected-error@-2 {{'willSet' is not allowed in subscripts}} + // expected-error@-2 {{'didSet' is not allowed in subscripts}} + } + + var property: any P { + get {} + set { + newValue.method(false) // expected-error {{member 'method' cannot be used on value of protocol type 'P'; consider using a generic constraint instead}} {{none}} + } + } +} From 88dc3ad3fa5b7f12b3277bf613d9b8ea0248b538 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Sat, 19 Feb 2022 04:22:22 +0300 Subject: [PATCH 13/17] Sema: Fix interface type computation for observer parameters --- lib/Sema/TypeCheckDecl.cpp | 6 ++---- ...existential_member_accesses_self_assoctype_fixit.swift | 6 +++--- test/decl/subscript/subscripting.swift | 8 ++++++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 5fee99387390c..d1408e63f658f 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -1611,7 +1611,7 @@ bool TypeChecker::isAvailabilitySafeForConformance( return requirementInfo.isContainedIn(witnessInfo); } -// Returns 'nullptr' if this is the setter's 'newValue' parameter; +// Returns 'nullptr' if this is the 'newValue' or 'oldValue' parameter; // otherwise, returns the corresponding parameter of the subscript // declaration. static ParamDecl *getOriginalParamFromAccessor(AbstractStorageDecl *storage, @@ -1623,11 +1623,9 @@ static ParamDecl *getOriginalParamFromAccessor(AbstractStorageDecl *storage, switch (accessor->getAccessorKind()) { case AccessorKind::DidSet: case AccessorKind::WillSet: - return nullptr; - case AccessorKind::Set: if (param == accessorParams->get(0)) { - // This is the 'newValue' parameter. + // This is the 'newValue' or 'oldValue' parameter. return nullptr; } diff --git a/test/decl/protocol/existential_member_accesses_self_assoctype_fixit.swift b/test/decl/protocol/existential_member_accesses_self_assoctype_fixit.swift index 2b6b80699617e..dd77daf002492 100644 --- a/test/decl/protocol/existential_member_accesses_self_assoctype_fixit.swift +++ b/test/decl/protocol/existential_member_accesses_self_assoctype_fixit.swift @@ -189,10 +189,10 @@ struct Test { } subscript(p: any P & Q) -> any P { - _read { p.method(false) } // expected-error {{member 'method' cannot be used on value of protocol type 'P & Q'; consider using a generic constraint instead}} {{-1:20--1:25=<#generic parameter name#>}} {{-1:16--1:20=}} {{-1:12--1:12=<<#generic parameter name#>: P & Q>}} {{none}} + _read { p.method(false) } // expected-error {{member 'method' cannot be used on value of protocol type 'P & Q'; consider using a generic constraint instead}} {{-1:20--1:25=<#generic parameter name#>}} {{-1:16--1:20=}} {{-1:12--1:12=<<#generic parameter name#>: P & Q>}} {{none}} _modify { p.method(false) } // expected-error {{member 'method' cannot be used on value of protocol type 'P & Q'; consider using a generic constraint instead}} {{-2:20--2:25=<#generic parameter name#>}} {{-2:16--2:20=}} {{-2:12--2:12=<<#generic parameter name#>: P & Q>}} {{none}} - willSet { p.method(false) } // expected-error {{member 'method' cannot be used on value of protocol type 'P'; consider using a generic constraint instead}} {{-3:20--3:25=<#generic parameter name#>}} {{-3:16--3:20=}} {{-3:12--3:12=<<#generic parameter name#>: P & Q>}} {{none}} - didSet { p.method(false) } // expected-error {{member 'method' cannot be used on value of protocol type 'P'; consider using a generic constraint instead}} {{-4:20--4:25=<#generic parameter name#>}} {{-4:16--4:20=}} {{-4:12--4:12=<<#generic parameter name#>: P & Q>}} {{none}} + willSet { p.method(false) } // expected-error {{member 'method' cannot be used on value of protocol type 'P & Q'; consider using a generic constraint instead}} {{-3:20--3:25=<#generic parameter name#>}} {{-3:16--3:20=}} {{-3:12--3:12=<<#generic parameter name#>: P & Q>}} {{none}} + didSet { p.method(false) } // expected-error {{member 'method' cannot be used on value of protocol type 'P & Q'; consider using a generic constraint instead}} {{-4:20--4:25=<#generic parameter name#>}} {{-4:16--4:20=}} {{-4:12--4:12=<<#generic parameter name#>: P & Q>}} {{none}} // expected-error@-2 {{'willSet' is not allowed in subscripts}} // expected-error@-2 {{'didSet' is not allowed in subscripts}} } diff --git a/test/decl/subscript/subscripting.swift b/test/decl/subscript/subscripting.swift index eaca1b180fb8f..842a1106cc6f4 100644 --- a/test/decl/subscript/subscripting.swift +++ b/test/decl/subscript/subscripting.swift @@ -165,18 +165,22 @@ protocol ProtocolWillSetDidSet4 { } class DidSetInSubscript { - subscript(_: Int) -> Int { + subscript(x: Int) -> Bool { didSet { // expected-error {{'didSet' is not allowed in subscripts}} print("eek") + // Make sure implicit observer parameters pick up the right type. + let _: Int = x } get {} } } class WillSetInSubscript { - subscript(_: Int) -> Int { + subscript(x: Int) -> Bool { willSet { // expected-error {{'willSet' is not allowed in subscripts}} print("eek") + // Make sure implicit observer parameters pick up the right type. + let _: Int = x } get {} } From 2342712ca089805e9a6fd17e295ea9e878294215 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Wed, 23 Feb 2022 02:59:48 +0300 Subject: [PATCH 14/17] [NFC] Reorganize a few SE-309 test cases with opaque result types --- ...tential_member_accesses_self_assoctype.swift | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/test/decl/protocol/existential_member_accesses_self_assoctype.swift b/test/decl/protocol/existential_member_accesses_self_assoctype.swift index f55ea92dc22a1..5a550abb0c0b4 100644 --- a/test/decl/protocol/existential_member_accesses_self_assoctype.swift +++ b/test/decl/protocol/existential_member_accesses_self_assoctype.swift @@ -225,11 +225,10 @@ protocol P1 { subscript(invariantAssocSubscript7 _: any P1 & Class) -> Void { get } subscript(invariantAssocSubscript8 _: Void) -> Struct.InnerGeneric { get } } -@available(macOS 10.15, *) extension P1 { - func invariantSelf1_1() -> some P1 { self } - var invariantSelfProp1_1: some P1 { self } - subscript(invariantSelfSubscript1_1: Void) -> some P1 { self } + func opaqueResultTypeMethod() -> some P1 { self } + var opaqueResultTypeProp: some P1 { self } + subscript(opaqueResultTypeSubscript _: Bool) -> some P1 { self } } do { @@ -318,6 +317,10 @@ do { { (_: () -> Any?) in } ] + let _: any P1 = arg.opaqueResultTypeMethod() + let _: any P1 = arg.opaqueResultTypeProp + let _: any P1 = arg[opaqueResultTypeSubscript: true] + arg.contravariantSelf1(0) // expected-error {{member 'contravariantSelf1' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} arg.contravariantSelf2(0) // expected-error {{member 'contravariantSelf2' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} arg.contravariantSelf3(0) // expected-error {{member 'contravariantSelf3' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} @@ -342,9 +345,6 @@ do { arg.contravariantAssoc11(0) // expected-error {{member 'contravariantAssoc11' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} arg.invariantSelf1(0) // expected-error {{member 'invariantSelf1' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} - if #available(macOS 10.15, *) { - _ = arg.invariantSelf1_1() - } arg.invariantSelf2(0) // expected-error {{member 'invariantSelf2' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} arg.invariantSelf3(0) // expected-error {{member 'invariantSelf3' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} arg.invariantSelf4(0) // expected-error {{member 'invariantSelf4' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} @@ -391,9 +391,6 @@ do { arg.contravariantAssocProp11 // expected-error {{member 'contravariantAssocProp11' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} arg.invariantSelfProp1 // expected-error {{member 'invariantSelfProp1' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} - if #available(macOS 10.15, *) { - _ = arg.invariantSelfProp1_1 - } arg.invariantSelfProp2 // expected-error {{member 'invariantSelfProp2' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} arg.invariantSelfProp3 // expected-error {{member 'invariantSelfProp3' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} arg.invariantSelfProp4 // expected-error {{member 'invariantSelfProp4' cannot be used on value of protocol type 'P1'; consider using a generic constraint instead}} From 02207288a33be26ad1c93e0ef30f121796b63af2 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Wed, 23 Feb 2022 08:21:56 -0800 Subject: [PATCH 15/17] [Gardening] Tweaked verifier wording. Added trailing "be" to match "is" in "memory is [not] initialized, but should[n't]". The errors are now "meemory is [not] initialized, but should[n't] be". --- lib/SIL/Verifier/MemoryLifetimeVerifier.cpp | 4 +- test/SIL/memory_lifetime_failures.sil | 48 ++++++++++----------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/lib/SIL/Verifier/MemoryLifetimeVerifier.cpp b/lib/SIL/Verifier/MemoryLifetimeVerifier.cpp index b160b9d26d3e9..fe9fde4bd8399 100644 --- a/lib/SIL/Verifier/MemoryLifetimeVerifier.cpp +++ b/lib/SIL/Verifier/MemoryLifetimeVerifier.cpp @@ -264,7 +264,7 @@ void MemoryLifetimeVerifier::require(const Bits &wrongBits, void MemoryLifetimeVerifier::requireBitsClear(const Bits &bits, SILValue addr, SILInstruction *where) { if (auto *loc = locations.getLocation(addr)) { - require(bits & loc->subLocations, "memory is initialized, but shouldn't", + require(bits & loc->subLocations, "memory is initialized, but shouldn't be", where, /*excludeTrivialEnums*/ true); } } @@ -273,7 +273,7 @@ void MemoryLifetimeVerifier::requireBitsSet(const Bits &bits, SILValue addr, SILInstruction *where) { if (auto *loc = locations.getLocation(addr)) { require(~bits & loc->subLocations, - "memory is not initialized, but should", where); + "memory is not initialized, but should be", where); } } diff --git a/test/SIL/memory_lifetime_failures.sil b/test/SIL/memory_lifetime_failures.sil index e9cf95e5b3e48..5e13ae5c3488b 100644 --- a/test/SIL/memory_lifetime_failures.sil +++ b/test/SIL/memory_lifetime_failures.sil @@ -89,7 +89,7 @@ bb0(%0 : $*Outer): sil @throwing_func : $@convention(thin) () -> (@out T, @error Error) -// CHECK: SIL memory lifetime failure in @test_try_apply_return: memory is initialized, but shouldn't +// CHECK: SIL memory lifetime failure in @test_try_apply_return: memory is initialized, but shouldn't be sil [ossa] @test_try_apply_return : $@convention(thin) () -> ((), @error Error) { bb0: %0 = alloc_stack $T @@ -107,7 +107,7 @@ bb2(%4 : @owned $Error): } -// CHECK: SIL memory lifetime failure in @test_try_apply_throw: memory is not initialized, but should +// CHECK: SIL memory lifetime failure in @test_try_apply_throw: memory is not initialized, but should be sil [ossa] @test_try_apply_throw : $@convention(thin) () -> ((), @error Error) { bb0: %0 = alloc_stack $T @@ -127,7 +127,7 @@ bb2(%4 : @owned $Error): } -// CHECK: SIL memory lifetime failure in @test_single_block: memory is initialized, but shouldn't +// CHECK: SIL memory lifetime failure in @test_single_block: memory is initialized, but shouldn't be sil [ossa] @test_single_block : $@convention(thin) (@owned T) -> () { bb0(%0 : @owned $T): %2 = alloc_stack $T @@ -137,7 +137,7 @@ bb0(%0 : @owned $T): return %r : $() } -// CHECK: SIL memory lifetime failure in @test_mixed: memory is not initialized, but should +// CHECK: SIL memory lifetime failure in @test_mixed: memory is not initialized, but should be sil [ossa] @test_mixed : $@convention(thin) (@in Mixed, Int) -> Int { bb0(%0 : $*Mixed, %1 : $Int): %2 = struct_element_addr %0 : $*Mixed, #Mixed.i @@ -147,7 +147,7 @@ bb0(%0 : $*Mixed, %1 : $Int): return %3 : $Int } -// CHECK: SIL memory lifetime failure in @test_missing_store_to_trivial: memory is not initialized, but should +// CHECK: SIL memory lifetime failure in @test_missing_store_to_trivial: memory is not initialized, but should be sil [ossa] @test_missing_store_to_trivial : $@convention(thin) () -> Int { bb0: %1 = alloc_stack $Mixed @@ -157,7 +157,7 @@ bb0: return %3 : $Int } -// CHECK: SIL memory lifetime failure in @test_load_after_dealloc: memory is not initialized, but should +// CHECK: SIL memory lifetime failure in @test_load_after_dealloc: memory is not initialized, but should be sil [ossa] @test_load_after_dealloc : $@convention(thin) (Int) -> Int { bb0(%0 : $Int): %1 = alloc_stack $Mixed @@ -224,7 +224,7 @@ bb3: return %r : $() } -// CHECK: SIL memory lifetime failure in @test_store_to_enum: memory is initialized, but shouldn't +// CHECK: SIL memory lifetime failure in @test_store_to_enum: memory is initialized, but shouldn't be sil [ossa] @test_store_to_enum : $@convention(thin) (@owned T) -> () { bb0(%0 : @owned $T): %1 = alloc_stack $Optional @@ -238,7 +238,7 @@ bb0(%0 : @owned $T): return %r : $() } -// CHECK: SIL memory lifetime failure in @test_select_enum_addr: memory is not initialized, but should +// CHECK: SIL memory lifetime failure in @test_select_enum_addr: memory is not initialized, but should be sil [ossa] @test_select_enum_addr : $@convention(thin) () -> Builtin.Int1 { bb0: %0 = alloc_stack $Optional @@ -271,7 +271,7 @@ bb0(%0 : $*T): return %res : $() } -// CHECK: SIL memory lifetime failure in @test_store_borrow_destroy: memory is not initialized, but should +// CHECK: SIL memory lifetime failure in @test_store_borrow_destroy: memory is not initialized, but should be sil [ossa] @test_store_borrow_destroy : $@convention(thin) (@guaranteed T) -> () { bb0(%0 : @guaranteed $T): %s = alloc_stack $T @@ -361,7 +361,7 @@ bb0(%0 : @guaranteed $Optional): return %res : $() } -// CHECK: SIL memory lifetime failure in @test_cast_br_take_always: memory is not initialized, but should +// CHECK: SIL memory lifetime failure in @test_cast_br_take_always: memory is not initialized, but should be sil [ossa] @test_cast_br_take_always : $@convention(thin) (@in U) -> () { bb0(%0 : $*U): %s = alloc_stack $V @@ -411,7 +411,7 @@ bb3: return %res : $() } -// CHECK: SIL memory lifetime failure in @test_unconditional_checked_cast_1: memory is initialized, but shouldn't +// CHECK: SIL memory lifetime failure in @test_unconditional_checked_cast_1: memory is initialized, but shouldn't be sil [ossa] @test_unconditional_checked_cast_1 : $@convention(thin) (@in U) -> () { bb0(%0 : $*U): %s = alloc_stack $V @@ -421,7 +421,7 @@ bb0(%0 : $*U): return %5 : $() } -// CHECK: SIL memory lifetime failure in @test_unconditional_checked_cast_2: memory is not initialized, but should +// CHECK: SIL memory lifetime failure in @test_unconditional_checked_cast_2: memory is not initialized, but should be sil [ossa] @test_unconditional_checked_cast_2 : $@convention(thin) (@in_guaranteed U) -> () { bb0(%0 : $*U): %u = alloc_stack $U @@ -434,7 +434,7 @@ bb0(%0 : $*U): return %5 : $() } -// CHECK: SIL memory lifetime failure in @test_unchecked_ref_cast_1: memory is initialized, but shouldn't +// CHECK: SIL memory lifetime failure in @test_unchecked_ref_cast_1: memory is initialized, but shouldn't be sil [ossa] @test_unchecked_ref_cast_1 : $@convention(thin) (@in U) -> () { bb0(%0 : $*U): %s = alloc_stack $V @@ -444,7 +444,7 @@ bb0(%0 : $*U): return %5 : $() } -// CHECK: SIL memory lifetime failure in @test_unchecked_ref_cast_2: memory is not initialized, but should +// CHECK: SIL memory lifetime failure in @test_unchecked_ref_cast_2: memory is not initialized, but should be sil [ossa] @test_unchecked_ref_cast_2 : $@convention(thin) (@in_guaranteed U) -> () { bb0(%0 : $*U): %u = alloc_stack $U @@ -459,7 +459,7 @@ bb0(%0 : $*U): protocol P {} -// CHECK: SIL memory lifetime failure in @test_init_existential: memory is not initialized, but should +// CHECK: SIL memory lifetime failure in @test_init_existential: memory is not initialized, but should be sil [ossa] @test_init_existential : $@convention(thin) (@in_guaranteed U) -> () { bb0(%0 : $*U): %s = alloc_stack $P @@ -470,7 +470,7 @@ bb0(%0 : $*U): return %5 : $() } -// CHECK: SIL memory lifetime failure in @test_open_existential: memory is not initialized, but should +// CHECK: SIL memory lifetime failure in @test_open_existential: memory is not initialized, but should be sil [ossa] @test_open_existential : $@convention(thin) (@in_guaranteed U) -> () { bb0(%0 : $*U): %s = alloc_stack $P @@ -485,7 +485,7 @@ bb0(%0 : $*U): return %5 : $() } -// CHECK: SIL memory lifetime failure in @test_existential_metatype: memory is not initialized, but should +// CHECK: SIL memory lifetime failure in @test_existential_metatype: memory is not initialized, but should be sil [ossa] @test_existential_metatype : $@convention(thin) () -> () { bb0: %0 = alloc_stack $P @@ -495,7 +495,7 @@ bb0: return %5 : $() } -// CHECK: SIL memory lifetime failure in @test_value_metatype: memory is not initialized, but should +// CHECK: SIL memory lifetime failure in @test_value_metatype: memory is not initialized, but should be sil [ossa] @test_value_metatype : $@convention(thin) (@in_guaranteed U) -> () { bb0(%0 : $*U): %1 = alloc_stack $U @@ -505,7 +505,7 @@ bb0(%0 : $*U): return %5 : $() } -// CHECK: SIL memory lifetime failure in @test_is_unique: memory is not initialized, but should +// CHECK: SIL memory lifetime failure in @test_is_unique: memory is not initialized, but should be sil [ossa] @test_is_unique : $@convention(thin) () -> () { bb0: %0 = alloc_stack $T @@ -515,7 +515,7 @@ bb0: return %5 : $() } -// CHECK: SIL memory lifetime failure in @test_fix_lifetime: memory is not initialized, but should +// CHECK: SIL memory lifetime failure in @test_fix_lifetime: memory is not initialized, but should be sil [ossa] @test_fix_lifetime : $@convention(thin) () -> () { bb0: %0 = alloc_stack $T @@ -527,7 +527,7 @@ bb0: sil @modify_bool : $@convention(thin) (@inout_aliasable Bool) -> () -// CHECK: SIL memory lifetime failure in @test_trivial_alloc_stack: memory is not initialized, but should +// CHECK: SIL memory lifetime failure in @test_trivial_alloc_stack: memory is not initialized, but should be sil [ossa] @test_trivial_alloc_stack : $@convention(thin) (Bool) -> () { bb0(%0 : $Bool): %1 = alloc_stack $Bool @@ -555,7 +555,7 @@ bb2: return %r : $() } -// CHECK: SIL memory lifetime failure in @test_load_borrow2: memory is not initialized, but should +// CHECK: SIL memory lifetime failure in @test_load_borrow2: memory is not initialized, but should be sil [ossa] @test_load_borrow2 : $@convention(thin) (@in Optional) -> () { bb0(%0 : $*Optional): destroy_addr %0 : $*Optional @@ -575,7 +575,7 @@ enum Result{ sil @try_get_error : $@convention(thin) () -> @error Error -// CHECK: SIL memory lifetime failure in @test_init_enum_trivial_case: memory is not initialized, but should +// CHECK: SIL memory lifetime failure in @test_init_enum_trivial_case: memory is not initialized, but should be sil [ossa] @test_init_enum_trivial_case : $@convention(thin) () -> @error Error { bb0: %0 = alloc_stack $Result @@ -601,7 +601,7 @@ bb3: return %15 : $() } -// CHECK: SIL memory lifetime failure in @test_double_enum_destroy: memory is not initialized, but should +// CHECK: SIL memory lifetime failure in @test_double_enum_destroy: memory is not initialized, but should be sil [ossa] @test_double_enum_destroy : $@convention(thin) (@in Optional) -> () { bb0(%0 : $*Optional): %l = load_borrow %0 : $*Optional From 039eb10daba4299f58a710f64ba7777948decc16 Mon Sep 17 00:00:00 2001 From: Mike Ash Date: Wed, 23 Feb 2022 12:16:35 -0500 Subject: [PATCH 16/17] Mark stdlib/Assert-debugPrecondition-off.swift as REQUIRES: executable_test. --- validation-test/stdlib/Assert-debugPrecondition-off.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/validation-test/stdlib/Assert-debugPrecondition-off.swift b/validation-test/stdlib/Assert-debugPrecondition-off.swift index 5d80f7eeed10e..cbb219731419a 100644 --- a/validation-test/stdlib/Assert-debugPrecondition-off.swift +++ b/validation-test/stdlib/Assert-debugPrecondition-off.swift @@ -10,6 +10,7 @@ // RUN: %target-run %t/Assert_Unchecked | %FileCheck --check-prefixes=UNCHECKED %s // UNSUPPORTED: swift_stdlib_debug_preconditions_in_release +// REQUIRES: executable_test // DEBUG: _isStdlibDebugChecksEnabled: true // RELEASE: _isStdlibDebugChecksEnabled: false From f6b2e2e40c17ead39b01cf7fc63e15f55483db38 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Wed, 23 Feb 2022 09:46:07 -0800 Subject: [PATCH 17/17] Fix invalid warning for enum cases named self (#41520) https://github.com/apple/swift/pull/37992/ introduced a warning when you were likely to confuse `self` with `TypeName.self`, this also applied to enum cases that were named `self`, these cases should not be easily confused at call sites since their use requires prefixing them with a `.`. There was also no way to avoid this warning since other syntax such as `TypeName.self`, which produces the enum type instead, or `` TypeName.`self` `` which produced the same warning again. Fixes https://bugs.swift.org/browse/SR-15691 --- lib/Sema/MiscDiagnostics.cpp | 17 +++++++++-------- test/Parse/self_rebinding.swift | 10 ++++++++++ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index edaf24fc00403..03f3af7a5f3a0 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -4748,19 +4748,20 @@ static void diagUnqualifiedAccessToMethodNamedSelf(const Expr *E, if (auto typeContext = DC->getInnermostTypeContext()) { // self() is not easily confusable if (!isa(Parent.getAsExpr())) { - auto baseType = typeContext->getDeclaredInterfaceType(); - auto baseTypeString = baseType.getString(); + if (!baseType->getEnumOrBoundGenericEnum()) { + auto baseTypeString = baseType.getString(); - Ctx.Diags.diagnose(E->getLoc(), diag::self_refers_to_method, - baseTypeString); + Ctx.Diags.diagnose(E->getLoc(), diag::self_refers_to_method, + baseTypeString); - Ctx.Diags + Ctx.Diags .diagnose(E->getLoc(), - diag::fix_unqualified_access_member_named_self, - baseTypeString) + diag::fix_unqualified_access_member_named_self, + baseTypeString) .fixItInsert(E->getLoc(), diag::insert_type_qualification, - baseType); + baseType); + } } } } diff --git a/test/Parse/self_rebinding.swift b/test/Parse/self_rebinding.swift index 0892023ca63a8..17cef308f34bb 100644 --- a/test/Parse/self_rebinding.swift +++ b/test/Parse/self_rebinding.swift @@ -116,3 +116,13 @@ struct TypeWithSelfProperty { let `self`: () = () } + +enum EnumCaseNamedSelf { + case `self` + + init() { + self = .self // OK + self = .`self` // OK + self = EnumCaseNamedSelf.`self` // OK + } +}