Skip to content

Commit 91be25f

Browse files
authored
Dependency analysis: treat member operators as top-level "provides". (#3986)
We still do a global lookup for operators even though they are syntactically declared within types now, so for dependency-tracking purposes continue to treat that as declared at the top level. This isn't where we actually want to be---ideally we can use the types of the arguments to limit the dependencies to a member lookup (or pair of member lookups)---but since the operator overloads /themselves/ participate in type-checking an expression, I'm not sure that's 100% correct. For now, it's better to be conservative. (This means dependency analysis for operators remains as lousy as it was in Swift 2, but it's not a regression.) rdar://problem/27659972
1 parent 490aefa commit 91be25f

File tree

3 files changed

+87
-6
lines changed

3 files changed

+87
-6
lines changed

lib/FrontendTool/FrontendTool.cpp

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -125,14 +125,31 @@ static bool emitMakeDependencies(DiagnosticEngine &diags,
125125
return false;
126126
}
127127

128-
static void findNominals(llvm::MapVector<const NominalTypeDecl *, bool> &found,
129-
DeclRange members) {
128+
static void findNominalsAndOperators(
129+
llvm::MapVector<const NominalTypeDecl *, bool> &foundNominals,
130+
llvm::SmallVectorImpl<const FuncDecl *> &foundOperators,
131+
DeclRange members) {
130132
for (const Decl *D : members) {
133+
auto *VD = dyn_cast<ValueDecl>(D);
134+
if (!VD)
135+
continue;
136+
137+
if (VD->hasAccessibility() &&
138+
VD->getFormalAccess() <= Accessibility::FilePrivate) {
139+
continue;
140+
}
141+
142+
if (VD->getFullName().isOperator()) {
143+
foundOperators.push_back(cast<FuncDecl>(VD));
144+
continue;
145+
}
146+
131147
auto nominal = dyn_cast<NominalTypeDecl>(D);
132148
if (!nominal)
133149
continue;
134-
found[nominal] |= true;
135-
findNominals(found, nominal->getMembers());
150+
foundNominals[nominal] |= true;
151+
findNominalsAndOperators(foundNominals, foundOperators,
152+
nominal->getMembers());
136153
}
137154
}
138155

@@ -209,6 +226,7 @@ static bool emitReferenceDependencies(DiagnosticEngine &diags,
209226
out << "### Swift dependencies file v0 ###\n";
210227

211228
llvm::MapVector<const NominalTypeDecl *, bool> extendedNominals;
229+
llvm::SmallVector<const FuncDecl *, 8> memberOperatorDecls;
212230
llvm::SmallVector<const ExtensionDecl *, 8> extensionsWithJustMembers;
213231

214232
out << "provides-top-level:\n";
@@ -243,7 +261,8 @@ static bool emitReferenceDependencies(DiagnosticEngine &diags,
243261
}
244262
}
245263
extendedNominals[NTD] |= !justMembers;
246-
findNominals(extendedNominals, ED->getMembers());
264+
findNominalsAndOperators(extendedNominals, memberOperatorDecls,
265+
ED->getMembers());
247266
break;
248267
}
249268

@@ -270,7 +289,8 @@ static bool emitReferenceDependencies(DiagnosticEngine &diags,
270289
}
271290
out << "- \"" << escape(NTD->getName()) << "\"\n";
272291
extendedNominals[NTD] |= true;
273-
findNominals(extendedNominals, NTD->getMembers());
292+
findNominalsAndOperators(extendedNominals, memberOperatorDecls,
293+
NTD->getMembers());
274294
break;
275295
}
276296

@@ -306,6 +326,10 @@ static bool emitReferenceDependencies(DiagnosticEngine &diags,
306326
}
307327
}
308328

329+
// This is also part of "provides-top-level".
330+
for (auto *operatorFunction : memberOperatorDecls)
331+
out << "- \"" << escape(operatorFunction->getName()) << "\"\n";
332+
309333
out << "provides-nominal:\n";
310334
for (auto entry : extendedNominals) {
311335
if (!entry.second)

test/NameBinding/Inputs/reference-dependencies-helper.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,22 @@ func getOtherFileIntArray() -> OtherFileIntArray { return OtherFileIntArray() }
3131
typealias OtherFileAliasForSecret = OtherFileSecretTypeWrapper.SecretType
3232

3333
prefix operator *** {}
34+
prefix operator ~~~~~ {}
35+
36+
prefix operator ****
37+
infix operator *****
38+
infix operator ******
39+
protocol Starry {
40+
static prefix func ****(arg: Self)
41+
static func *****(lhs: Self, rhs: Int)
42+
static func ******(lhs: Int, rhs: Self)
43+
}
44+
// Deliberately does not conform to Starry.
45+
struct Flyswatter {
46+
static prefix func ****(arg: Flyswatter) {}
47+
static func *****(lhs: Flyswatter, rhs: Int) {}
48+
static func ******(lhs: Int, rhs: Flyswatter) {}
49+
}
3450

3551
typealias ExpressibleByOtherFileAliasForFloatLiteral = ExpressibleByFloatLiteral
3652

test/NameBinding/reference-dependencies.swift

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,22 @@
1818
// CHECK-NEXT: "ThreeTilde"
1919
// CHECK-NEXT: "overloadedOnProto"
2020
// CHECK-NEXT: "overloadedOnProto"
21+
// CHECK-NEXT: "~~~~"
22+
// CHECK-NEXT: "FourTilde"
23+
// CHECK-NEXT: "FourTildeImpl"
24+
// CHECK-NEXT: "FiveTildeImpl"
2125
// CHECK-NEXT: "topLevelComputedProperty"
2226
// CHECK-NEXT: "lookUpManyTopLevelNames"
27+
// CHECK-NEXT: "testOperators"
2328
// CHECK-NEXT: "TopLevelForMemberLookup"
2429
// CHECK-NEXT: "lookUpMembers"
2530
// CHECK-NEXT: "publicUseOfMember"
2631
// CHECK-NEXT: "Outer"
2732
// CHECK: "eof"
33+
// CHECK-NEXT: "~~~"
34+
// CHECK-NEXT: "~~~~"
35+
// CHECK-NEXT: "~~~~"
36+
// CHECK-NEXT: "~~~~~"
2837

2938
// CHECK-LABEL: {{^provides-nominal:$}}
3039
// CHECK-NEXT: "V4main10IntWrapper"
@@ -46,6 +55,8 @@
4655
// CHECK: - ["Ps25ExpressibleByArrayLiteral", "useless"]
4756
// CHECK-NEXT: - ["Ps25ExpressibleByArrayLiteral", "useless2"]
4857
// CHECK-NEXT: - ["Sb", "InnerToBool"]
58+
// CHECK-NEXT: - ["{{.*[0-9]}}FourTildeImpl", "~~~~"]
59+
// CHECK-NEXT: - ["{{.*[0-9]}}FiveTildeImpl", "~~~~~"]
4960

5061
// CHECK-LABEL: {{^depends-top-level:$}}
5162

@@ -129,6 +140,23 @@ func overloadedOnProto<T: ThreeTilde>(_: T) {}
129140
// CHECK-DAG: - "~~~"
130141
private prefix func ~~~(_: ThreeTildeTypeImpl) {}
131142

143+
// CHECK-DAG: - "~~~~"
144+
prefix operator ~~~~ {}
145+
protocol FourTilde {
146+
prefix static func ~~~~(arg: Self)
147+
}
148+
struct FourTildeImpl : FourTilde {}
149+
extension FourTildeImpl {
150+
prefix static func ~~~~(arg: FourTildeImpl) {}
151+
}
152+
153+
// CHECK-DAG: - "~~~~~"
154+
// ~~~~~ is declared in the other file.
155+
struct FiveTildeImpl {}
156+
extension FiveTildeImpl {
157+
prefix static func ~~~~~(arg: FiveTildeImpl) {}
158+
}
159+
132160
var topLevelComputedProperty: Bool {
133161
return true
134162
}
@@ -213,6 +241,19 @@ func lookUpManyTopLevelNames() {
213241
overloadedOnProto(otherFileGetNonImpl())
214242
}
215243

244+
func testOperators<T: Starry>(generic: T, specific: Flyswatter) {
245+
// CHECK-DAG: !private "****"
246+
// CHECK-DAG: !private "*****"
247+
// CHECK-DAG: !private "******"
248+
****generic
249+
generic*****0
250+
0******generic
251+
252+
****specific
253+
specific*****0
254+
0******specific
255+
}
256+
216257
struct TopLevelForMemberLookup {
217258
static func m1() {}
218259
static func m2() {}

0 commit comments

Comments
 (0)