Skip to content

Commit 719002b

Browse files
authored
Merge pull request swiftlang#30365 from jckarter/substitution-map-mismatches
Create an inherited conformance in SubstitutionMap::lookupConformance when needed.
2 parents ecd2e39 + d06b839 commit 719002b

File tree

8 files changed

+98
-9
lines changed

8 files changed

+98
-9
lines changed

include/swift/Basic/LangOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,9 @@ namespace swift {
322322
/// `@differentiable` declaration attribute, etc.
323323
bool EnableExperimentalDifferentiableProgramming = false;
324324

325+
/// Enable verification when every SubstitutionMap is constructed.
326+
bool VerifyAllSubstitutionMaps = false;
327+
325328
/// Sets the target we are building for and updates platform conditions
326329
/// to match.
327330
///
@@ -512,6 +515,7 @@ namespace swift {
512515
/// Enable constraint solver support for experimental
513516
/// operator protocol designator feature.
514517
bool SolverEnableOperatorDesignatedTypes = false;
518+
515519
};
516520
} // end namespace swift
517521

include/swift/Option/FrontendOptions.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,9 @@ def sil_merge_partial_modules : Flag<["-"], "sil-merge-partial-modules">,
548548

549549
def sil_verify_all : Flag<["-"], "sil-verify-all">,
550550
HelpText<"Verify SIL after each transform">;
551+
552+
def verify_all_substitution_maps : Flag<["-"], "verify-all-substitution-maps">,
553+
HelpText<"Verify all SubstitutionMaps on construction">;
551554

552555
def sil_debug_serialization : Flag<["-"], "sil-debug-serialization">,
553556
HelpText<"Do not eliminate functions in Mandatory Inlining/SILCombine dead "

lib/AST/ASTDumper.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3679,8 +3679,26 @@ namespace {
36793679

36803680
void visitSILFunctionType(SILFunctionType *T, StringRef label) {
36813681
printCommon(label, "sil_function_type");
3682-
// FIXME: Print the structure of the type.
36833682
printField("type", T->getString());
3683+
3684+
for (auto param : T->getParameters()) {
3685+
printRec("input", param.getInterfaceType());
3686+
}
3687+
for (auto yield : T->getYields()) {
3688+
printRec("yield", yield.getInterfaceType());
3689+
}
3690+
for (auto result : T->getResults()) {
3691+
printRec("result", result.getInterfaceType());
3692+
}
3693+
if (auto error = T->getOptionalErrorResult()) {
3694+
printRec("error", error->getInterfaceType());
3695+
}
3696+
OS << '\n';
3697+
T->getPatternSubstitutions().dump(OS, SubstitutionMap::DumpStyle::Full,
3698+
Indent+2);
3699+
OS << '\n';
3700+
T->getInvocationSubstitutions().dump(OS, SubstitutionMap::DumpStyle::Full,
3701+
Indent+2);
36843702
PrintWithColorRAII(OS, ParenthesisColor) << ')';
36853703
}
36863704

lib/AST/SubstitutionMap.cpp

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,12 @@ SubstitutionMap::SubstitutionMap(
5656
GenericSignature genericSig,
5757
ArrayRef<Type> replacementTypes,
5858
ArrayRef<ProtocolConformanceRef> conformances)
59-
: storage(Storage::get(genericSig, replacementTypes, conformances)) { }
59+
: storage(Storage::get(genericSig, replacementTypes, conformances)) {
60+
#ifndef NDEBUG
61+
if (genericSig->getASTContext().LangOpts.VerifyAllSubstitutionMaps)
62+
verify();
63+
#endif
64+
}
6065

6166
ArrayRef<Type> SubstitutionMap::getReplacementTypesBuffer() const {
6267
return storage ? storage->getReplacementTypes() : ArrayRef<Type>();
@@ -355,8 +360,10 @@ SubstitutionMap::lookupConformance(CanType type, ProtocolDecl *proto) const {
355360
// Check whether the superclass conforms.
356361
if (auto superclass = genericSig->getSuperclassBound(type)) {
357362
LookUpConformanceInSignature lookup(getGenericSignature().getPointer());
358-
if (auto conformance = lookup(type->getCanonicalType(), superclass, proto))
363+
auto substType = type.subst(*this);
364+
if (auto conformance = lookup(type->getCanonicalType(), substType, proto)){
359365
return conformance;
366+
}
360367
}
361368

362369
// If the type doesn't conform to this protocol, the result isn't formed
@@ -474,7 +481,7 @@ SubstitutionMap SubstitutionMap::subst(TypeSubstitutionFn subs,
474481
newConformances.push_back(
475482
conformance.subst(substType, subs, conformances, options));
476483
}
477-
484+
478485
oldConformances = oldConformances.slice(1);
479486
}
480487

@@ -657,6 +664,7 @@ void SubstitutionMap::verify() const {
657664
if (req.getKind() != RequirementKind::Conformance)
658665
continue;
659666

667+
SWIFT_DEFER { ++conformanceIndex; };
660668
auto substType = req.getFirstType().subst(*this);
661669
if (substType->isTypeParameter() ||
662670
substType->is<ArchetypeType>() ||
@@ -677,15 +685,44 @@ void SubstitutionMap::verify() const {
677685
llvm::dbgs() << "SubstitutionMap:\n";
678686
dump(llvm::dbgs());
679687
llvm::dbgs() << "\n";
688+
llvm::dbgs() << "Requirement:\n";
689+
req.dump(llvm::dbgs());
690+
llvm::dbgs() << "\n";
680691
}
681692
assert(conformance.isConcrete() && "Conformance should be concrete");
693+
694+
if (substType->is<UnboundGenericType>())
695+
continue;
696+
697+
auto conformanceTy = conformance.getConcrete()->getType();
698+
if (conformanceTy->hasTypeParameter()
699+
&& !substType->hasTypeParameter()) {
700+
conformanceTy = conformance.getConcrete()->getDeclContext()
701+
->mapTypeIntoContext(conformanceTy);
702+
}
703+
704+
if (!substType->isEqual(conformanceTy)) {
705+
llvm::dbgs() << "Conformance must match concrete replacement type:\n";
706+
substType->dump(llvm::dbgs());
707+
llvm::dbgs() << "Conformance type:\n";
708+
conformance.getConcrete()->getType()->dump(llvm::dbgs());
709+
llvm::dbgs() << "Conformance:\n";
710+
conformance.dump(llvm::dbgs());
711+
llvm::dbgs() << "\n";
712+
llvm::dbgs() << "SubstitutionMap:\n";
713+
dump(llvm::dbgs());
714+
llvm::dbgs() << "\n";
715+
llvm::dbgs() << "Requirement:\n";
716+
req.dump(llvm::dbgs());
717+
llvm::dbgs() << "\n";
718+
}
719+
assert(substType->isEqual(conformanceTy)
720+
&& "conformance should match corresponding type");
682721

683722
if (substType->isExistentialType()) {
684723
assert(isa<SelfProtocolConformance>(conformance.getConcrete()) &&
685724
"Existential type cannot have normal conformance");
686725
}
687-
688-
++conformanceIndex;
689726
}
690727
#endif
691728
}

lib/AST/Type.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2400,7 +2400,7 @@ getForeignRepresentable(Type type, ForeignLanguage language,
24002400

24012401
if (wasOptional && !result.isRepresentableAsOptional())
24022402
return failure();
2403-
2403+
24042404
// If our nominal type has type arguments, make sure they are
24052405
// representable as well. Because type arguments are not actually
24062406
// translated separately, whether they are trivially representable
@@ -2447,6 +2447,16 @@ getForeignRepresentable(Type type, ForeignLanguage language,
24472447
break;
24482448
}
24492449
}
2450+
2451+
// Specialize the conformance we were given for the type we're testing.
2452+
if (result.getKind() == ForeignRepresentableKind::Bridged
2453+
&& !result.getConformance()->getType()->isEqual(type)) {
2454+
auto specialized = type->getASTContext()
2455+
.getSpecializedConformance(type, result.getConformance(),
2456+
boundGenericType->getContextSubstitutionMap(dc->getParentModule(),
2457+
boundGenericType->getDecl()));
2458+
result = ForeignRepresentationInfo::forBridged(specialized);
2459+
}
24502460
}
24512461

24522462
return { result.getKind(), result.getConformance() };

lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
565565
Target.isOSDarwin());
566566
Opts.EnableSILOpaqueValues |= Args.hasArg(OPT_enable_sil_opaque_values);
567567

568+
Opts.VerifyAllSubstitutionMaps |= Args.hasArg(OPT_verify_all_substitution_maps);
569+
568570
Opts.UseDarwinPreStableABIBit =
569571
(Target.isMacOSX() && Target.isMacOSXVersionLT(10, 14, 4)) ||
570572
(Target.isiOS() && Target.isOSVersionLT(12, 2)) ||
@@ -795,7 +797,7 @@ static bool ParseSearchPathArgs(SearchPathOptions &Opts,
795797
// Assumes exactly one of setMainExecutablePath() or setRuntimeIncludePath()
796798
// is called before setTargetTriple() and parseArgs().
797799
// TODO: improve the handling of RuntimeIncludePath.
798-
800+
799801
return false;
800802
}
801803

lib/SILGen/SILGenType.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -749,7 +749,7 @@ static SILFunction *emitSelfConformanceWitness(SILGenModule &SGM,
749749
auto protocolType = protocol->getDeclaredInterfaceType();
750750
auto reqtSubs = SubstitutionMap::getProtocolSubstitutions(protocol,
751751
protocolType,
752-
ProtocolConformanceRef(protocol));
752+
ProtocolConformanceRef(conformance));
753753

754754
// Open the protocol type.
755755
auto openedType = OpenedArchetypeType::get(protocolType);
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %target-swift-emit-silgen %s | %FileCheck %s
2+
protocol P {}
3+
4+
class C: P {}
5+
class D: C {}
6+
7+
struct Butt<T: P> {}
8+
9+
func foo<T: P>(_: (Butt<T>) -> ()) {}
10+
11+
// CHECK-LABEL: sil{{.*}}3bar
12+
func bar(_ f: (Butt<D>) -> ()) {
13+
// CHECK: convert_function {{.*}} $@noescape @callee_guaranteed (Butt<D>) -> () to $@noescape @callee_guaranteed @substituted <τ_0_0 where τ_0_0 : P> (Butt<τ_0_0>) -> () for <D>
14+
foo(f)
15+
}

0 commit comments

Comments
 (0)