Skip to content

Commit 73c564a

Browse files
committed
[Name lookup] Implement name shadowing rule for Data.withUnsafeBytes.
Address an annoying source compatibility issue with the introduction of Data.withUnsafeBytes, which is ambiguous with Swift NIO's implementatio of the same function. Do so with a narrow hackish name shadowing rule (the Swift NIO version shadows the Foundation version) that we will eventually generalize to something sensible. Fixes rdar://problem/46850346. (cherry picked from commit 18f4bcb)
1 parent bdf70d1 commit 73c564a

File tree

3 files changed

+56
-0
lines changed

3 files changed

+56
-0
lines changed

lib/AST/NameLookup.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,42 @@ static void recordShadowedDeclsAfterSignatureMatch(
267267
}
268268
}
269269

270+
// The Foundation overlay introduced Data.withUnsafeBytes, which is
271+
// treated as being ambiguous with SwiftNIO's Data.withUnsafeBytes
272+
// extension. Apply a special-case name shadowing rule to use the
273+
// latter rather than the former, which be the consequence of a more
274+
// significant change to name shadowing in the future.
275+
if (auto owningStruct1
276+
= firstDecl->getDeclContext()->getSelfStructDecl()) {
277+
if (auto owningStruct2
278+
= secondDecl->getDeclContext()->getSelfStructDecl()) {
279+
if (owningStruct1 == owningStruct2 &&
280+
owningStruct1->getName().is("Data") &&
281+
isa<FuncDecl>(firstDecl) && isa<FuncDecl>(secondDecl) &&
282+
firstDecl->getFullName() == secondDecl->getFullName() &&
283+
firstDecl->getBaseName().userFacingName() == "withUnsafeBytes") {
284+
// If the second module is the Foundation module and the first
285+
// is the NIOFoundationCompat module, the second is shadowed by the
286+
// first.
287+
if (firstDecl->getModuleContext()->getName()
288+
.is("NIOFoundationCompat") &&
289+
secondDecl->getModuleContext()->getName().is("Foundation")) {
290+
shadowed.insert(secondDecl);
291+
continue;
292+
}
293+
294+
// If it's the other way around, the first declaration is shadowed
295+
// by the second.
296+
if (secondDecl->getModuleContext()->getName()
297+
.is("NIOFoundationCompat") &&
298+
firstDecl->getModuleContext()->getName().is("Foundation")) {
299+
shadowed.insert(firstDecl);
300+
break;
301+
}
302+
}
303+
}
304+
}
305+
270306
// Prefer declarations in an overlay to similar declarations in
271307
// the Clang module it customizes.
272308
if (firstDecl->hasClangNode() != secondDecl->hasClangNode()) {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import Foundation
2+
3+
extension Data {
4+
@_inlineable
5+
public func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R {
6+
let r: R? = nil
7+
return r!
8+
}
9+
}

test/NameBinding/nio_shadowing.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -o %t %S/Inputs/NIOFoundationCompat.swift
3+
// RUN: %target-swift-frontend -typecheck %s -I %t -verify
4+
5+
// REQUIRES: objc_interop
6+
import Foundation
7+
import NIOFoundationCompat
8+
9+
func test(data: Data) {
10+
data.withUnsafeBytes { x in print(x) }
11+
}

0 commit comments

Comments
 (0)