Skip to content

Commit ab167ac

Browse files
authored
Merge pull request #9053 from swiftix/partial-specialization-fixes
[sil-combine] Fix a subtle bug in getConformanceAndConcreteType related to handling of inherited conformances
2 parents 2680087 + 48b1f16 commit ab167ac

File tree

3 files changed

+51
-27
lines changed

3 files changed

+51
-27
lines changed

lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#define DEBUG_TYPE "sil-combine"
1414
#include "SILCombiner.h"
15+
#include "swift/AST/SubstitutionMap.h"
1516
#include "swift/SIL/DynamicCasts.h"
1617
#include "swift/SIL/PatternMatch.h"
1718
#include "swift/SIL/SILBuilder.h"
@@ -686,27 +687,30 @@ SILCombiner::createApplyWithConcreteType(FullApplySite AI,
686687
}
687688
Args.push_back(NewSelf);
688689

689-
// Form a new set of substitutions where Self is
690-
// replaced by a concrete type.
691-
SmallVector<Substitution, 8> Substitutions;
692-
for (auto Subst : AI.getSubstitutions()) {
693-
auto *A = Subst.getReplacement()->getAs<ArchetypeType>();
694-
if (A && A == OpenedArchetype) {
695-
auto Conformances = AI.getModule().getASTContext()
696-
.AllocateUninitialized<ProtocolConformanceRef>(1);
697-
Conformances[0] = Conformance;
698-
Substitution NewSubst(ConcreteType, Conformances);
699-
Substitutions.push_back(NewSubst);
700-
} else
701-
Substitutions.push_back(Subst);
702-
}
703-
690+
auto FnTy = AI.getCallee()->getType().castTo<SILFunctionType>();
704691
SILType SubstCalleeType = AI.getSubstCalleeSILType();
705-
706692
SILType NewSubstCalleeType;
707693

708-
auto FnTy = AI.getCallee()->getType().castTo<SILFunctionType>();
694+
// Form a new set of substitutions where Self is
695+
// replaced by a concrete type.
696+
SmallVector<Substitution, 8> Substitutions;
709697
if (FnTy->isPolymorphic()) {
698+
auto FnSubsMap =
699+
FnTy->getGenericSignature()->getSubstitutionMap(AI.getSubstitutions());
700+
auto FinalSubsMap = FnSubsMap.subst(
701+
[&](SubstitutableType *type) -> Type {
702+
if (type == OpenedArchetype)
703+
return ConcreteType;
704+
return type;
705+
},
706+
[&](CanType origTy, Type substTy,
707+
ProtocolType *proto) -> Optional<ProtocolConformanceRef> {
708+
if (substTy->isEqual(ConcreteType)) {
709+
return Conformance.getInherited(proto->getDecl());
710+
}
711+
return ProtocolConformanceRef(proto->getDecl());
712+
});
713+
FnTy->getGenericSignature()->getSubstitutions(FinalSubsMap, Substitutions);
710714
// Handle polymorphic functions by properly substituting
711715
// their parameter types.
712716
CanSILFunctionType SFT = FnTy->substGenericArgs(
@@ -794,10 +798,8 @@ getConformanceAndConcreteType(FullApplySite AI,
794798
if (Requirement->inheritsFrom(Protocol)) {
795799
// If Requirement != Protocol, then the abstract conformance cannot be used
796800
// as is and we need to create a proper conformance.
797-
return std::make_tuple(Conformance.isAbstract()
798-
? ProtocolConformanceRef(Protocol)
799-
: Conformance,
800-
ConcreteType, ConcreteTypeDef);
801+
return std::make_tuple(Conformance.getInherited(Protocol), ConcreteType,
802+
ConcreteTypeDef);
801803
}
802804
}
803805

test/Interpreter/FunctionConversion.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
//===----------------------------------------------------------------------===//
1212
// RUN: %target-run-simple-swift
1313
// REQUIRES: executable_test
14-
// REQUIRES: substitution_map_not_broken
1514
//
1615

1716
import StdlibUnittest

test/SILOptimizer/devirt_protocol_method_invocations.swift

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,30 @@
11
// RUN: %target-swift-frontend -O -emit-sil %s | %FileCheck %s
22

3+
protocol PPP {
4+
func f()
5+
}
6+
7+
protocol QQQ : PPP {
8+
}
9+
10+
struct S : QQQ {}
11+
12+
extension QQQ {
13+
@_semantics("optimize.sil.never")
14+
func f() {}
15+
}
16+
17+
// Test that all witness_method instructions are devirtualized.
18+
// This test used to crash the compiler because it uses inherited conformances.
19+
// CHECK-LABEL: sil @_T034devirt_protocol_method_invocations24testInheritedConformanceyyF : $@convention(thin) () -> ()
20+
// CHECK-NOT: witness_method
21+
// CHECK-NOT: class_method
22+
// CHECK: apply
23+
// CHECK: // end sil function '_T034devirt_protocol_method_invocations24testInheritedConformanceyyF'
24+
public func testInheritedConformance() {
25+
(S() as QQQ).f()
26+
}
27+
328
public protocol Foo {
429
func foo(_ x:Int) -> Int
530
}
@@ -49,12 +74,10 @@ public func test_devirt_protocol_extension_method_invocation_with_self_return_ty
4974
return callGetSelf(c)
5075
}
5176

52-
// It's not obvious why this isn't completely devirtualized.
5377
// CHECK: sil @_T034devirt_protocol_method_invocations12test24114020SiyF
54-
// CHECK: [[T0:%.*]] = alloc_stack $SimpleBase
55-
// CHECK: [[T1:%.*]] = witness_method $SimpleBase, #Base.x!getter.1
56-
// CHECK: [[T2:%.*]] = apply [[T1]]<SimpleBase>([[T0]])
57-
// CHECK: return [[T2]]
78+
// CHECK: [[T0:%.*]] = integer_literal $Builtin.Int64, 1
79+
// CHECK: [[T1:%.*]] = struct $Int ([[T0]] : $Builtin.Int64)
80+
// CHECK: return [[T1]]
5881

5982
// CHECK: sil @_T034devirt_protocol_method_invocations14testExMetatypeSiyF
6083
// CHECK: [[T0:%.*]] = builtin "sizeof"<Int>

0 commit comments

Comments
 (0)