Merge pull request #9896 from devincoughlin/swap-fixit-weaken-assert-4.0

[Exclusivity] Weaken assert when suggesting swap() Fix-It
diff --git a/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp b/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp
index 5285299..8362971 100644
--- a/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp
+++ b/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp
@@ -313,6 +313,26 @@
   return SM.extractText(CSR);
 }
 
+/// Returns true when the call expression is a call to swap() in the Standard
+/// Library.
+/// This is a helper function that is only used in an assertion, which is why
+/// it is in a namespace rather than 'static'.
+namespace {
+bool isCallToStandardLibrarySwap(CallExpr *CE, ASTContext &Ctx) {
+  if (CE->getCalledValue() == Ctx.getSwap(nullptr))
+    return true;
+
+  // Is the call module qualified, i.e. Swift.swap(&a[i], &[j)?
+  if (auto *DSBIE = dyn_cast<DotSyntaxBaseIgnoredExpr>(CE->getFn())) {
+    if (auto *DRE = dyn_cast<DeclRefExpr>(DSBIE->getRHS())) {
+      return DRE->getDecl() == Ctx.getSwap(nullptr);
+    }
+  }
+
+  return false;
+}
+} // end anonymous namespace
+
 /// Do a sytactic pattern match to try to safely suggest a Fix-It to rewrite
 /// calls like swap(&collection[index1], &collection[index2]) to
 ///
@@ -356,7 +376,7 @@
     if (!CE)
       continue;
 
-    assert(CE->getCalledValue() == Ctx.getSwap(nullptr));
+    assert(isCallToStandardLibrarySwap(CE, Ctx));
     // swap() takes two arguments.
     auto *ArgTuple = cast<TupleExpr>(CE->getArg());
     const Expr *Arg1 = ArgTuple->getElement(0);
diff --git a/test/SILOptimizer/exclusivity_static_diagnostics.swift b/test/SILOptimizer/exclusivity_static_diagnostics.swift
index 6ba4819..2b0c3b5 100644
--- a/test/SILOptimizer/exclusivity_static_diagnostics.swift
+++ b/test/SILOptimizer/exclusivity_static_diagnostics.swift
@@ -133,6 +133,10 @@
     // expected-error@+2{{simultaneous accesses}}{{5-75=localOfGenericType.swapAt(paramIndex, paramIndex)}}
     // expected-note@+1{{conflicting access is here}}
     swap(&localOfGenericType[paramIndex], &localOfGenericType[paramIndex])
+
+    // expected-error@+2{{simultaneous accesses}}{{5-39=array1.swapAt(i, j)}}
+    // expected-note@+1{{conflicting access is here}}
+    Swift.swap(&array1[i], &array1[j]) // no-crash
   }
 
   mutating