Skip to content

Commit 3ed6325

Browse files
authored
Merge pull request #72457 from xymus/diag-type-mismatch-6.0
[6.0] Serialization: report type mismatch when it causes a deserialization failure
2 parents 06874f0 + ef74a8f commit 3ed6325

File tree

4 files changed

+78
-5
lines changed

4 files changed

+78
-5
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,10 @@ NOTE(modularization_issue_stale_module,none,
954954
"the module %0 has enabled library-evolution; "
955955
"the following file may need to be deleted if the SDK was modified: '%1'",
956956
(const ModuleDecl *, StringRef))
957+
NOTE(modularization_issue_type_mismatch,none,
958+
"a candidate was filtered out because of a type mismatch; "
959+
"expected: %0, found: %1",
960+
(const Type, const Type))
957961
NOTE(modularization_issue_swift_version,none,
958962
"the module %0 was built with a Swift language version set to %1 "
959963
"while the current invocation uses %2; "

lib/Serialization/Deserialization.cpp

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,12 @@ ModularizationError::diagnose(const ModuleFile *MF,
270270
declIsType, foundModule,
271271
foundModule->getModuleSourceFilename());
272272

273+
if (mismatchingTypes.has_value()) {
274+
ctx.Diags.diagnose(loc,
275+
diag::modularization_issue_type_mismatch,
276+
mismatchingTypes->first, mismatchingTypes->second);
277+
}
278+
273279
// A Swift language version mismatch could lead to a different set of rules
274280
// from APINotes files being applied when building the module vs when reading
275281
// from it.
@@ -2147,6 +2153,7 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
21472153

21482154
auto errorKind = ModularizationError::Kind::DeclNotFound;
21492155
ModuleDecl *foundIn = nullptr;
2156+
std::optional<std::pair<Type, Type>> mismatchingTypes;
21502157
bool isType = false;
21512158

21522159
if (recordID == XREF_TYPE_PATH_PIECE ||
@@ -2190,7 +2197,10 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
21902197
values);
21912198
}
21922199

2193-
bool hadAMatchBeforeFiltering = !values.empty();
2200+
std::optional<ValueDecl*> matchBeforeFiltering = std::nullopt;
2201+
if (!values.empty()) {
2202+
matchBeforeFiltering = values[0];
2203+
}
21942204
filterValues(filterTy, nullptr, nullptr, isType, inProtocolExt,
21952205
importedFromClang, isStatic, std::nullopt, values);
21962206

@@ -2202,13 +2212,21 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
22022212
errorKind = ModularizationError::Kind::DeclMoved;
22032213
foundIn = otherModule;
22042214
break;
2205-
} else if (hadAMatchBeforeFiltering) {
2215+
} else if (matchBeforeFiltering.has_value()) {
22062216
// Found a match that was filtered out. This may be from the same
22072217
// expected module if there's a type difference. This can be caused
22082218
// by the use of different Swift language versions between a library
22092219
// with serialized SIL and a client.
22102220
errorKind = ModularizationError::Kind::DeclKindChanged;
22112221
foundIn = otherModule;
2222+
2223+
if (filterTy) {
2224+
auto expectedTy = filterTy->getCanonicalType();
2225+
auto foundTy = (*matchBeforeFiltering)->getInterfaceType();
2226+
if (expectedTy && foundTy && !expectedTy->isEqual(foundTy))
2227+
mismatchingTypes = std::make_pair(expectedTy, foundTy);
2228+
}
2229+
22122230
break;
22132231
}
22142232
}
@@ -2221,7 +2239,8 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
22212239
baseModule,
22222240
this,
22232241
foundIn,
2224-
pathTrace);
2242+
pathTrace,
2243+
mismatchingTypes);
22252244

22262245
// If we want to workaround broken modularization, we can keep going if
22272246
// we found a matching top-level decl in a different module. This is

lib/Serialization/DeserializationErrors.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,16 +367,21 @@ class ModularizationError : public llvm::ErrorInfo<ModularizationError> {
367367

368368
XRefTracePath path;
369369

370+
/// Expected vs found type if the mismatch caused a decl to be rejected.
371+
std::optional<std::pair<Type, Type>> mismatchingTypes;
372+
370373
public:
371374
explicit ModularizationError(DeclName name, bool declIsType, Kind errorKind,
372375
const ModuleDecl *expectedModule,
373376
const ModuleFile *referenceModule,
374377
const ModuleDecl *foundModule,
375-
XRefTracePath path):
378+
XRefTracePath path,
379+
std::optional<std::pair<Type, Type>> mismatchingTypes):
376380
name(name), declIsType(declIsType), errorKind(errorKind),
377381
expectedModule(expectedModule),
378382
referenceModule(referenceModule),
379-
foundModule(foundModule), path(path) {}
383+
foundModule(foundModule), path(path),
384+
mismatchingTypes(mismatchingTypes) {}
380385

381386
void diagnose(const ModuleFile *MF,
382387
DiagnosticBehavior limit = DiagnosticBehavior::Fatal) const;
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
/// Compile two libraries A and LibWithXRef.
5+
// RUN: %target-swift-frontend -emit-module %t/LibWithXRef.swift -I %t \
6+
// RUN: -module-name LibWithXRef -o %t/LibWithXRef.swiftmodule \
7+
// RUN: -swift-version 5
8+
// RUN: %target-swift-frontend -c -O %t/Client.swift -I %t \
9+
// RUN: -validate-tbd-against-ir=none -swift-version 5
10+
11+
// Replace headers, changing the type of `foo`.
12+
// RUN: mv %t/A_DifferentAPI.h %t/A.h
13+
// RUN: not --crash %target-swift-frontend -c -O %t/Client.swift -I %t \
14+
// RUN: -validate-tbd-against-ir=none -swift-version 5 2>&1 \
15+
// RUN: | %FileCheck %s
16+
// CHECK: error: reference to top-level declaration 'foo' broken by a context change; the declaration kind of 'foo' from 'A' changed since building 'LibWithXRef'
17+
// CHECK: note: the declaration was expected to be found in module 'A' at '{{.*}}module.modulemap'
18+
// CHECK: note: the declaration was actually found in module 'A' at '{{.*}}module.modulemap'
19+
// CHECK: note: a candidate was filtered out because of a type mismatch; expected: '() -> ()', found: '() -> Float'
20+
21+
//--- module.modulemap
22+
module A {
23+
header "A.h"
24+
}
25+
26+
//--- A.h
27+
void foo() {}
28+
29+
//--- A_DifferentAPI.h
30+
float foo() {
31+
return 1.2;
32+
}
33+
34+
//--- LibWithXRef.swift
35+
import A
36+
37+
@inlinable
38+
public func bar() {
39+
foo()
40+
}
41+
42+
//--- Client.swift
43+
import LibWithXRef
44+
45+
bar()

0 commit comments

Comments
 (0)