Skip to content

Commit 72083bf

Browse files
committed
Diagnostics: Specify the module name on ambiguities across modules
When a file defining an API is included in two modules, clients calling that API may get an error about the ambiguity on the duplicated API. That error is not very helpful when it takes into account the swiftsourceinfo data and points to the source file instead of the module. In such a case the notes point twice to the same file and line of code. Improve this diagnostic by appending the module name to the notes when a candidate is found outside of the module. rdar://116255141
1 parent d976ea6 commit 72083bf

File tree

4 files changed

+72
-6
lines changed

4 files changed

+72
-6
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4239,6 +4239,9 @@ WARNING(warn_use_async_alternative,none,
42394239

42404240
NOTE(found_candidate,none,
42414241
"found this candidate", ())
4242+
NOTE(found_candidate_in_module,none,
4243+
"found this candidate %select{|in module %1}0",
4244+
(bool, const ModuleDecl *))
42424245
NOTE(found_candidate_type,none,
42434246
"found candidate with type %0", (Type))
42444247

lib/Sema/ConstraintSystem.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5598,12 +5598,17 @@ bool ConstraintSystem::diagnoseAmbiguity(ArrayRef<Solution> solutions) {
55985598
case OverloadChoiceKind::Decl:
55995599
case OverloadChoiceKind::DeclViaDynamic:
56005600
case OverloadChoiceKind::DeclViaBridge:
5601-
case OverloadChoiceKind::DeclViaUnwrappedOptional:
5601+
case OverloadChoiceKind::DeclViaUnwrappedOptional: {
56025602
// FIXME: show deduced types, etc, etc.
5603-
if (EmittedDecls.insert(choice.getDecl()).second)
5604-
DE.diagnose(choice.getDecl(), diag::found_candidate);
5603+
auto decl = choice.getDecl();
5604+
if (EmittedDecls.insert(decl).second) {
5605+
auto declModule = decl->getDeclContext()->getParentModule();
5606+
bool printModuleName = declModule != DC->getParentModule();
5607+
DE.diagnose(decl, diag::found_candidate_in_module,
5608+
printModuleName, declModule);
5609+
}
56055610
break;
5606-
5611+
}
56075612
case OverloadChoiceKind::KeyPathApplication:
56085613
case OverloadChoiceKind::DynamicMemberLookup:
56095614
case OverloadChoiceKind::KeyPathDynamicMemberLookup:
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
/// Compile the exact same source file into 2 different modules.
5+
// RUN: %target-swift-frontend -emit-module -o %t/A.swiftmodule %t/Lib.swift \
6+
// RUN: -emit-module-source-info -module-name A -package-name pkg \
7+
// RUN: -enable-testing
8+
// RUN: %target-swift-frontend -emit-module -o %t/B.swiftmodule %t/Lib.swift \
9+
// RUN: -emit-module-source-info -module-name B -package-name pkg \
10+
// RUN: -enable-testing
11+
12+
// Build a client importing both modules and hitting the ambiguities.
13+
// RUN: not %target-swift-frontend -typecheck -I %t %t/Client.swift -package-name pkg 2> %t/out
14+
// RUN: cat %t/out | %FileCheck %s
15+
16+
//--- Lib.swift
17+
public func publicAmbiguity() {}
18+
package func packageAmbiguity() {}
19+
internal func internalAmbiguity() {}
20+
21+
//--- Client.swift
22+
@testable import A
23+
@testable import B
24+
25+
func foo() {
26+
publicAmbiguity()
27+
// CHECK: error: ambiguous use of 'publicAmbiguity()'
28+
// CHECK-NEXT: publicAmbiguity()
29+
// CHECK-NEXT: ^
30+
// CHECK-NEXT: Lib.swift:1:13: note: found this candidate in module 'A'
31+
// CHECK-NEXT: public func publicAmbiguity() {}
32+
// CHECK-NEXT: ^
33+
// CHECK-NEXT: Lib.swift:1:13: note: found this candidate in module 'B'
34+
// CHECK-NEXT: public func publicAmbiguity() {}
35+
// CHECK-NEXT: ^
36+
37+
packageAmbiguity()
38+
// CHECK: error: ambiguous use of 'packageAmbiguity()'
39+
// CHECK-NEXT: packageAmbiguity()
40+
// CHECK-NEXT: ^
41+
// CHECK-NEXT: Lib.swift:2:14: note: found this candidate in module 'A'
42+
// CHECK-NEXT: package func packageAmbiguity() {}
43+
// CHECK-NEXT: ^
44+
// CHECK-NEXT: Lib.swift:2:14: note: found this candidate in module 'B'
45+
// CHECK-NEXT: package func packageAmbiguity() {}
46+
// CHECK-NEXT: ^
47+
48+
internalAmbiguity()
49+
// CHECK: error: ambiguous use of 'internalAmbiguity()'
50+
// CHECK-NEXT: internalAmbiguity()
51+
// CHECK-NEXT: ^
52+
// CHECK-NEXT: Lib.swift:3:15: note: found this candidate in module 'A'
53+
// CHECK-NEXT: internal func internalAmbiguity() {}
54+
// CHECK-NEXT: ^
55+
// CHECK-NEXT: Lib.swift:3:15: note: found this candidate in module 'B'
56+
// CHECK-NEXT: internal func internalAmbiguity() {}
57+
// CHECK-NEXT: ^
58+
}

test/diagnostics/testable-printast-locations.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@
99
ambiguous()
1010

1111
// CHECK: testable-printast-locations.swift:[[@LINE-2]]:1: error: ambiguous use of 'ambiguous()'
12-
// CHECK: ModuleA.ambiguous (internal):1:15: note: found this candidate
13-
// CHECK: ModuleB.ambiguous (internal):1:15: note: found this candidate
12+
// CHECK: ModuleA.ambiguous (internal):1:15: note: found this candidate in module 'ModuleA'
13+
// CHECK: ModuleB.ambiguous (internal):1:15: note: found this candidate in module 'ModuleB'

0 commit comments

Comments
 (0)