Skip to content

Commit 18f4bcb

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.
1 parent 1deee1e commit 18f4bcb

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
@@ -271,6 +271,42 @@ static void recordShadowedDeclsAfterSignatureMatch(
271271
}
272272
}
273273

274+
// The Foundation overlay introduced Data.withUnsafeBytes, which is
275+
// treated as being ambiguous with SwiftNIO's Data.withUnsafeBytes
276+
// extension. Apply a special-case name shadowing rule to use the
277+
// latter rather than the former, which be the consequence of a more
278+
// significant change to name shadowing in the future.
279+
if (auto owningStruct1
280+
= firstDecl->getDeclContext()->getSelfStructDecl()) {
281+
if (auto owningStruct2
282+
= secondDecl->getDeclContext()->getSelfStructDecl()) {
283+
if (owningStruct1 == owningStruct2 &&
284+
owningStruct1->getName().is("Data") &&
285+
isa<FuncDecl>(firstDecl) && isa<FuncDecl>(secondDecl) &&
286+
firstDecl->getFullName() == secondDecl->getFullName() &&
287+
firstDecl->getBaseName().userFacingName() == "withUnsafeBytes") {
288+
// If the second module is the Foundation module and the first
289+
// is the NIOFoundationCompat module, the second is shadowed by the
290+
// first.
291+
if (firstDecl->getModuleContext()->getName()
292+
.is("NIOFoundationCompat") &&
293+
secondDecl->getModuleContext()->getName().is("Foundation")) {
294+
shadowed.insert(secondDecl);
295+
continue;
296+
}
297+
298+
// If it's the other way around, the first declaration is shadowed
299+
// by the second.
300+
if (secondDecl->getModuleContext()->getName()
301+
.is("NIOFoundationCompat") &&
302+
firstDecl->getModuleContext()->getName().is("Foundation")) {
303+
shadowed.insert(firstDecl);
304+
break;
305+
}
306+
}
307+
}
308+
}
309+
274310
// Prefer declarations in an overlay to similar declarations in
275311
// the Clang module it customizes.
276312
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)