@@ -1662,6 +1662,9 @@ SILGenModule::getWitnessTable(ProtocolConformance *conformance) {
1662
1662
static bool maybeOpenCodeProtocolWitness (SILGenFunction &gen,
1663
1663
ProtocolConformance *conformance,
1664
1664
SILLinkage linkage,
1665
+ Type selfInterfaceType,
1666
+ Type selfType,
1667
+ GenericEnvironment *genericEnv,
1665
1668
SILDeclRef requirement,
1666
1669
SILDeclRef witness,
1667
1670
ArrayRef<Substitution> witnessSubs) {
@@ -1670,7 +1673,8 @@ static bool maybeOpenCodeProtocolWitness(SILGenFunction &gen,
1670
1673
auto reqFn = cast<FuncDecl>(requirement.getDecl ());
1671
1674
assert (reqFn->getAccessorKind () == AccessorKind::IsMaterializeForSet);
1672
1675
return gen.maybeEmitMaterializeForSetThunk (conformance, linkage,
1673
- reqFn, witnessFn,
1676
+ selfInterfaceType, selfType,
1677
+ genericEnv, reqFn, witnessFn,
1674
1678
witnessSubs);
1675
1679
}
1676
1680
}
@@ -1689,13 +1693,11 @@ static bool isSelfDerived(Type selfTy, Type t) {
1689
1693
// / requirement's type to get the type of the witness.
1690
1694
static CanAnyFunctionType
1691
1695
substSelfTypeIntoProtocolRequirementType (SILModule &M,
1696
+ GenericEnvironment *reqtEnv,
1692
1697
CanGenericFunctionType reqtTy,
1693
- ProtocolConformance *conformance) {
1694
- if (conformance == nullptr ) {
1695
- // Default witness thunks just get the requirement type without
1696
- // substituting Self.
1697
- return reqtTy;
1698
- }
1698
+ ProtocolConformance *conformance,
1699
+ GenericEnvironment *&genericEnv,
1700
+ SubstitutionMap &thunkSubs) {
1699
1701
1700
1702
auto &C = M.getASTContext ();
1701
1703
@@ -1732,26 +1734,27 @@ substSelfTypeIntoProtocolRequirementType(SILModule &M,
1732
1734
1733
1735
// Now we look at the generic signature of the requirement.
1734
1736
// We are going to drop `Self`, and requirements rooted in `Self`.
1735
- for (auto *param : reqtTy ->getGenericParams ().slice (1 )) {
1737
+ for (auto *param : reqtEnv ->getGenericParams ().slice (1 )) {
1736
1738
allParams.push_back (param);
1737
1739
builder.addGenericParameter (param);
1738
1740
}
1739
1741
1740
1742
RequirementSource source (RequirementSource::Explicit, SourceLoc ());
1741
1743
1742
1744
for (auto &reqt : reqtTy->getRequirements ()) {
1743
- if (isSelfDerived (selfTy, reqt.getFirstType ()))
1744
- continue ;
1745
-
1746
1745
switch (reqt.getKind ()) {
1747
1746
case RequirementKind::Conformance:
1748
1747
case RequirementKind::Superclass:
1749
1748
case RequirementKind::WitnessMarker:
1749
+ if (isSelfDerived (selfTy, reqt.getFirstType ()))
1750
+ continue ;
1751
+
1750
1752
builder.addRequirement (reqt, source);
1751
1753
break ;
1752
1754
1753
1755
case RequirementKind::SameType: {
1754
- if (isSelfDerived (selfTy, reqt.getSecondType ()))
1756
+ if (isSelfDerived (selfTy, reqt.getFirstType ()) &&
1757
+ isSelfDerived (selfTy, reqt.getSecondType ()))
1755
1758
continue ;
1756
1759
1757
1760
// Substitute the constrained types.
@@ -1774,67 +1777,60 @@ substSelfTypeIntoProtocolRequirementType(SILModule &M,
1774
1777
auto input = reqtTy->getInput ().subst (subs)->getCanonicalType ();
1775
1778
auto result = reqtTy->getResult ().subst (subs)->getCanonicalType ();
1776
1779
1780
+ CanAnyFunctionType reqtSubstTy;
1781
+
1782
+ auto addArchetypeSubstitution = [&](ArchetypeType *archetypeTy, Type substTy) {
1783
+ auto contextTy = ArchetypeBuilder::mapTypeIntoContext (
1784
+ M.getSwiftModule (), genericEnv, substTy);
1785
+
1786
+ thunkSubs.addSubstitution (CanType (archetypeTy), contextTy);
1787
+
1788
+ SmallVector<ProtocolConformanceRef, 2 > conformances;
1789
+ for (auto proto : archetypeTy->getConformsTo ())
1790
+ conformances.push_back (ProtocolConformanceRef (proto));
1791
+ thunkSubs.addConformances (CanType (archetypeTy),
1792
+ C.AllocateCopy (conformances));
1793
+ };
1794
+
1777
1795
// The result might be fully concrete, if the witness had no generic
1778
1796
// signature, and the requirement had no additional generic parameters
1779
1797
// beyond `Self`.
1780
1798
if (!allParams.empty ()) {
1781
1799
builder.finalize (SourceLoc ());
1782
1800
1783
1801
auto *sig = builder.getGenericSignature ();
1802
+ genericEnv = builder.getGenericEnvironment ();
1803
+
1804
+ // Outer generic parameters come from the generic context of
1805
+ // the conformance (which might not be the same as the generic
1806
+ // context of the witness, if the witness is defined in a
1807
+ // superclass, concrete extension or protocol extension).
1808
+ if (auto *outerEnv = conformance->getGenericEnvironment ()) {
1809
+ for (auto pair : outerEnv->getArchetypeToInterfaceMap ()) {
1810
+ auto archetypeTy = pair.first ->castTo <ArchetypeType>();
1811
+ auto substTy = pair.second ;
1812
+ addArchetypeSubstitution (archetypeTy, substTy);
1813
+ }
1814
+ }
1784
1815
1785
- return cast<GenericFunctionType>(
1816
+ reqtSubstTy = cast<GenericFunctionType>(
1786
1817
GenericFunctionType::get (sig, input, result, reqtTy->getExtInfo ())
1787
1818
->getCanonicalType ());
1788
- }
1789
-
1790
- return CanFunctionType::get (input, result, reqtTy->getExtInfo ());
1791
- }
1792
-
1793
- static GenericEnvironment *
1794
- getSubstitutedGenericEnvironment (SILModule &M,
1795
- GenericEnvironment *reqtEnv,
1796
- CanGenericSignature witnessSig,
1797
- ProtocolConformance *conformance) {
1798
- if (conformance == nullptr ) {
1799
- // Default witness thunks just use the context archetypes of the requirement.
1800
- return reqtEnv;
1801
- }
1802
-
1803
- SmallVector<GenericTypeParamType *, 4 > genericParamTypes;
1804
- TypeSubstitutionMap witnessContextParams;
1805
-
1806
- auto selfTy = conformance->getProtocol ()->getSelfInterfaceType ()
1807
- ->getCanonicalType ();
1819
+ } else {
1820
+ genericEnv = nullptr ;
1808
1821
1809
- // Outer generic parameters come from the generic context of
1810
- // the conformance (which might not be the same as the generic
1811
- // context of the witness, if the witness is defined in a
1812
- // superclass, concrete extension or protocol extension).
1813
- if (auto *outerEnv = conformance->getGenericEnvironment ()) {
1814
- witnessContextParams = outerEnv->getInterfaceToArchetypeMap ();
1815
- for (auto *paramTy : outerEnv->getGenericParams ())
1816
- genericParamTypes.push_back (paramTy);
1822
+ reqtSubstTy = CanFunctionType::get (input, result, reqtTy->getExtInfo ());
1817
1823
}
1818
1824
1819
- for (auto *paramTy : reqtEnv->getGenericParams ().slice (1 ))
1820
- genericParamTypes.push_back (paramTy);
1821
-
1822
1825
// Inner generic parameters come from the requirement and
1823
1826
// also map to the archetypes of the requirement.
1824
- for (auto pair : reqtEnv->getInterfaceToArchetypeMap ()) {
1825
- // Skip the 'Self' parameter and friends.
1826
- if (isSelfDerived (selfTy, pair.first ))
1827
- continue ;
1828
-
1829
- auto result = witnessContextParams.insert (pair);
1830
- assert (result.second );
1827
+ for (auto pair : reqtEnv->getArchetypeToInterfaceMap ()) {
1828
+ auto archetypeTy = pair.first ->castTo <ArchetypeType>();
1829
+ auto substTy = pair.second .subst (subs);
1830
+ addArchetypeSubstitution (archetypeTy, substTy);
1831
1831
}
1832
1832
1833
- if (!witnessContextParams.empty ())
1834
- return GenericEnvironment::get (M.getASTContext (), genericParamTypes,
1835
- witnessContextParams);
1836
-
1837
- return nullptr ;
1833
+ return reqtSubstTy;
1838
1834
}
1839
1835
1840
1836
SILFunction *
@@ -1845,7 +1841,6 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance,
1845
1841
IsFreeFunctionWitness_t isFree,
1846
1842
ArrayRef<Substitution> witnessSubs) {
1847
1843
auto requirementInfo = Types.getConstantInfo (requirement);
1848
- auto witnessInfo = Types.getConstantInfo (witness);
1849
1844
unsigned witnessUncurryLevel = witness.uncurryLevel ;
1850
1845
1851
1846
// If the witness is a free function, consider the self argument
@@ -1859,11 +1854,37 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance,
1859
1854
assert (requirement.uncurryLevel == witnessUncurryLevel &&
1860
1855
" uncurry level of requirement and witness do not match" );
1861
1856
1857
+ GenericEnvironment *genericEnv = nullptr ;
1858
+
1862
1859
// Work out the lowered function type of the SIL witness thunk.
1863
1860
auto reqtOrigTy
1864
1861
= cast<GenericFunctionType>(requirementInfo.LoweredInterfaceType );
1865
- auto reqtSubstTy
1866
- = substSelfTypeIntoProtocolRequirementType (M, reqtOrigTy, conformance);
1862
+ CanAnyFunctionType reqtSubstTy;
1863
+ if (conformance == nullptr ) {
1864
+ reqtSubstTy = reqtOrigTy;
1865
+ genericEnv = requirementInfo.GenericEnv ;
1866
+ } else {
1867
+ SubstitutionMap thunkSubs;
1868
+ reqtSubstTy
1869
+ = substSelfTypeIntoProtocolRequirementType (M, requirementInfo.GenericEnv ,
1870
+ reqtOrigTy, conformance,
1871
+ genericEnv, thunkSubs);
1872
+
1873
+ // Remap witness substitutions to use the correct archetypes.
1874
+ // Sema produces witness substitutions using a mix of archetypes
1875
+ // from the requirement and the witness. To solve downstream
1876
+ // issues in the SIL optimizer, we build all-new archetypes
1877
+ // using the correct generic signature here.
1878
+ //
1879
+ // FIXME: Once Sema records witness substitutions in terms of
1880
+ // interface types, this code as well as the code that builds
1881
+ // thunkSubs in substSelfTypeIntoProtocolRequirementType() can
1882
+ // be removed.
1883
+ auto newWitnessSubs = getASTContext ().AllocateCopy (witnessSubs);
1884
+ for (unsigned i = 0 , e = witnessSubs.size (); i < e; i++)
1885
+ newWitnessSubs[i] = witnessSubs[i].subst (M.getSwiftModule (), thunkSubs);
1886
+ witnessSubs = newWitnessSubs;
1887
+ }
1867
1888
1868
1889
// Lower the witness thunk type with the requirement's abstraction level.
1869
1890
auto witnessSILFnType = getNativeSILFunctionType (M,
@@ -1899,16 +1920,6 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance,
1899
1920
nameBuffer = mangler.finalize ();
1900
1921
}
1901
1922
1902
- CanGenericSignature witnessSig;
1903
- if (auto gft = dyn_cast<GenericFunctionType>(
1904
- witnessInfo.LoweredInterfaceType ))
1905
- witnessSig = gft.getGenericSignature ();
1906
-
1907
- // Collect the generic environment for the witness.
1908
- GenericEnvironment *requirementEnv = requirementInfo.GenericEnv ;
1909
- GenericEnvironment *witnessEnv = getSubstitutedGenericEnvironment (
1910
- M, requirementEnv, witnessSig, conformance);
1911
-
1912
1923
// If the thunked-to function is set to be always inlined, do the
1913
1924
// same with the witness, on the theory that the user wants all
1914
1925
// calls removed if possible, e.g. when we're able to devirtualize
@@ -1927,7 +1938,7 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance,
1927
1938
1928
1939
auto *f = M.createFunction (
1929
1940
linkage, nameBuffer, witnessSILFnType,
1930
- witnessEnv , SILLocation (witness.getDecl ()),
1941
+ genericEnv , SILLocation (witness.getDecl ()),
1931
1942
IsNotBare, IsTransparent, isFragile, IsThunk,
1932
1943
SILFunction::NotRelevant, InlineStrategy);
1933
1944
@@ -1937,27 +1948,28 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance,
1937
1948
PrettyStackTraceSILFunction trace (" generating protocol witness thunk" , f);
1938
1949
1939
1950
// Create the witness.
1951
+ Type selfInterfaceType;
1940
1952
Type selfType;
1941
1953
1942
1954
// If the witness is a free function, there is no Self type.
1943
1955
if (!isFree) {
1944
- // If we are emitting a witness thunk for a concrete conformance, Self is
1945
- // just the conforming type.
1946
1956
if (conformance) {
1947
- selfType = conformance->getType ();
1948
-
1949
- // For default implementations, Self is the protocol archetype.
1957
+ selfInterfaceType = conformance->getInterfaceType ();
1950
1958
} else {
1951
1959
auto *proto = cast<ProtocolDecl>(requirement.getDecl ()->getDeclContext ());
1952
- selfType = proto->getSelfTypeInContext ();
1960
+ selfInterfaceType = proto->getSelfInterfaceType ();
1953
1961
}
1962
+
1963
+ selfType = ArchetypeBuilder::mapTypeIntoContext (
1964
+ M.getSwiftModule (), genericEnv, selfInterfaceType);
1954
1965
}
1955
1966
1956
1967
SILGenFunction gen (*this , *f);
1957
1968
1958
1969
// Open-code certain protocol witness "thunks".
1959
- if (maybeOpenCodeProtocolWitness (gen, conformance, linkage, requirement,
1960
- witness, witnessSubs)) {
1970
+ if (maybeOpenCodeProtocolWitness (gen, conformance, linkage,
1971
+ selfInterfaceType, selfType, genericEnv,
1972
+ requirement, witness, witnessSubs)) {
1961
1973
assert (!isFree);
1962
1974
return f;
1963
1975
}
0 commit comments