@@ -1798,44 +1798,160 @@ class IsBindableVisitor
1798
1798
}
1799
1799
1800
1800
CanType visitDynamicSelfType (DynamicSelfType *orig, CanType subst,
1801
- ArchetypeType *, ArrayRef<ProtocolConformanceRef>) {
1801
+ ArchetypeType *upperBound,
1802
+ ArrayRef<ProtocolConformanceRef> substConformances) {
1802
1803
// A "dynamic self" type can be bound to another dynamic self type, or the
1803
1804
// non-dynamic base class type.
1804
1805
if (auto dynSubst = dyn_cast<DynamicSelfType>(subst)) {
1805
1806
if (auto newBase = visit (orig->getSelfType (), dynSubst.getSelfType (),
1806
- nullptr , {} )) {
1807
+ upperBound, substConformances )) {
1807
1808
return CanDynamicSelfType::get (newBase, orig->getASTContext ())
1808
1809
->getCanonicalType ();
1809
1810
}
1810
1811
return CanType ();
1811
1812
}
1812
1813
1813
1814
if (auto newNonDynBase = visit (orig->getSelfType (), subst,
1814
- nullptr , {} )) {
1815
+ upperBound, substConformances )) {
1815
1816
return newNonDynBase;
1816
1817
}
1817
1818
return CanType ();
1818
1819
}
1819
1820
1821
+ // / Handle a nominal type with generic parameters anywhere in its context.
1822
+ // / \c origType and \c substType must already have been established to be
1823
+ // / instantiations of the same \c NominalTypeDecl.
1824
+ CanType handleGenericNominalType (NominalTypeDecl *decl,
1825
+ CanType origType,
1826
+ CanType substType,
1827
+ ArchetypeType *upperBound,
1828
+ ArrayRef<ProtocolConformanceRef> substConformances) {
1829
+ assert (origType->getAnyNominal () == decl
1830
+ && substType->getAnyNominal () == decl);
1831
+
1832
+ auto *moduleDecl = decl->getParentModule ();
1833
+ auto origSubMap = origType->getContextSubstitutionMap (
1834
+ moduleDecl, decl, decl->getGenericEnvironment ());
1835
+ auto substSubMap = substType->getContextSubstitutionMap (
1836
+ moduleDecl, decl, decl->getGenericEnvironment ());
1837
+
1838
+ auto genericSig = decl->getGenericSignature ();
1839
+
1840
+ SmallVector<Type, 4 > newParams;
1841
+ llvm::DenseMap<Type, Type> newParamsMap;
1842
+ bool didChange = false ;
1843
+
1844
+ for (auto gpTy : genericSig.getGenericParams ()) {
1845
+ auto gp = gpTy->getCanonicalType ();
1846
+
1847
+ auto orig = gp.subst (origSubMap)->getCanonicalType ();
1848
+ auto subst = gp.subst (substSubMap)->getCanonicalType ();
1849
+
1850
+ // The new type is upper-bounded by the constraints the nominal type
1851
+ // requires. The substitution operation may be interested in transforming
1852
+ // the substituted type's conformances to these protocols.
1853
+ //
1854
+ // FIXME: The upperBound on the nominal type itself may impose additional
1855
+ // requirements on the type parameters due to conditional conformances.
1856
+ // These are currently not considered, leading to invalid generic signatures
1857
+ // built during SILGen.
1858
+ auto paramUpperBound = decl->mapTypeIntoContext (gp)
1859
+ ->getAs <ArchetypeType>();
1860
+ SmallVector<ProtocolConformanceRef, 4 > paramSubstConformances;
1861
+ if (paramUpperBound) {
1862
+ for (auto proto : paramUpperBound->getConformsTo ()) {
1863
+ auto conformance = substSubMap.lookupConformance (gp->getCanonicalType (),
1864
+ proto);
1865
+ if (!conformance)
1866
+ return CanType ();
1867
+ paramSubstConformances.push_back (conformance);
1868
+ }
1869
+ }
1870
+
1871
+ auto newParam = visit (orig, subst, paramUpperBound,
1872
+ paramSubstConformances);
1873
+ if (!newParam)
1874
+ return CanType ();
1875
+
1876
+ newParams.push_back (newParam);
1877
+ newParamsMap.insert ({gpTy, newParam});
1878
+ didChange |= (newParam != subst);
1879
+ }
1880
+
1881
+ SmallVector<ProtocolConformanceRef, 4 > newConformances;
1882
+
1883
+ // Collect conformances for the new substitutions, and verify that they don't
1884
+ // invalidate the binding to the original type.
1885
+ for (const auto &req : genericSig.getRequirements ()) {
1886
+ if (req.getKind () != RequirementKind::Conformance) continue ;
1887
+
1888
+ auto canTy = req.getFirstType ()->getCanonicalType ();
1889
+
1890
+ // Verify the generic requirements, if the subst type is bound to
1891
+ // concrete type.
1892
+ auto *proto = req.getProtocolDecl ();
1893
+ if (!canTy.subst (substSubMap)->isTypeParameter ()) {
1894
+ auto origConf = origSubMap.lookupConformance (canTy, proto);
1895
+ auto substConf = substSubMap.lookupConformance (canTy, proto);
1896
+
1897
+ if (origConf.isConcrete ()) {
1898
+ // A generic argument may inherit a concrete conformance from a class
1899
+ // constraint, which could still be bound to a type parameter we don't
1900
+ // know more about.
1901
+ if (origConf.getConcrete ()->getType ()->is <ArchetypeType>())
1902
+ continue ;
1903
+
1904
+ if (!substConf.isConcrete ())
1905
+ return CanType ();
1906
+ if (origConf.getConcrete ()->getRootConformance ()
1907
+ != substConf.getConcrete ()->getRootConformance ())
1908
+ return CanType ();
1909
+ }
1910
+ }
1911
+
1912
+ // Gather the conformances for the new binding type, if the type changed.
1913
+ if (didChange) {
1914
+ auto newSubstTy = newParamsMap.find (req.getFirstType ());
1915
+ assert (newSubstTy != newParamsMap.end ());
1916
+
1917
+ if (newSubstTy->second ->isTypeParameter ()) {
1918
+ newConformances.push_back (ProtocolConformanceRef (proto));
1919
+ } else {
1920
+ auto newConformance
1921
+ = moduleDecl->lookupConformance (newSubstTy->second , proto);
1922
+ if (!newConformance)
1923
+ return CanType ();
1924
+ newConformances.push_back (newConformance);
1925
+ }
1926
+ }
1927
+ }
1928
+
1929
+ if (!didChange)
1930
+ return substType;
1931
+
1932
+ // Build the new substituted generic type.
1933
+ auto newSubMap = SubstitutionMap::get (genericSig,
1934
+ newParams,
1935
+ newConformances);
1936
+ return decl->getDeclaredInterfaceType ().subst (newSubMap)
1937
+ ->getCanonicalType ();
1938
+ }
1939
+
1820
1940
CanType visitNominalType (NominalType *nom, CanType subst,
1821
- ArchetypeType*, ArrayRef<ProtocolConformanceRef>) {
1941
+ ArchetypeType* upperBound,
1942
+ ArrayRef<ProtocolConformanceRef> substConformances) {
1822
1943
if (auto substNom = dyn_cast<NominalType>(subst)) {
1944
+ auto nomDecl = nom->getDecl ();
1823
1945
if (nom->getDecl () != substNom->getDecl ())
1824
1946
return CanType ();
1825
1947
1826
- // Same decl should always either have or not have a parent.
1827
- assert ((bool )nom->getParent () == (bool )substNom->getParent ());
1828
-
1829
- if (nom->getParent ()) {
1830
- auto substParent = visit (nom->getParent ()->getCanonicalType (),
1831
- substNom->getParent ()->getCanonicalType (),
1832
- nullptr , {});
1833
- if (substParent == substNom.getParent ())
1834
- return subst;
1835
- return NominalType::get (nom->getDecl (), substParent,
1836
- nom->getASTContext ())
1837
- ->getCanonicalType ();
1948
+ // If the type is generic (because it's a nested type in a generic context),
1949
+ // process the generic type bindings.
1950
+ if (!isa<ProtocolDecl>(nomDecl) && nomDecl->isGenericContext ()) {
1951
+ return handleGenericNominalType (nomDecl, CanType (nom), subst,
1952
+ upperBound, substConformances);
1838
1953
}
1954
+ // Otherwise, the nongeneric nominal types trivially match.
1839
1955
return subst;
1840
1956
}
1841
1957
return CanType ();
@@ -2055,7 +2171,8 @@ class IsBindableVisitor
2055
2171
}
2056
2172
2057
2173
CanType visitBoundGenericType (BoundGenericType *bgt, CanType subst,
2058
- ArchetypeType *, ArrayRef<ProtocolConformanceRef>) {
2174
+ ArchetypeType *upperBound,
2175
+ ArrayRef<ProtocolConformanceRef> substConformances) {
2059
2176
auto substBGT = dyn_cast<BoundGenericType>(subst);
2060
2177
if (!substBGT)
2061
2178
return CanType ();
@@ -2065,95 +2182,8 @@ class IsBindableVisitor
2065
2182
2066
2183
auto *decl = bgt->getDecl ();
2067
2184
2068
- auto *moduleDecl = decl->getParentModule ();
2069
- auto origSubMap = bgt->getContextSubstitutionMap (
2070
- moduleDecl, decl, decl->getGenericEnvironment ());
2071
- auto substSubMap = substBGT->getContextSubstitutionMap (
2072
- moduleDecl, decl, decl->getGenericEnvironment ());
2073
-
2074
- auto genericSig = decl->getGenericSignature ();
2075
-
2076
- // Same decl should always either have or not have a parent.
2077
- assert ((bool )bgt->getParent () == (bool )substBGT->getParent ());
2078
- CanType newParent;
2079
- if (bgt->getParent ()) {
2080
- newParent = visit (bgt->getParent ()->getCanonicalType (),
2081
- substBGT.getParent (),
2082
- nullptr , {});
2083
- if (!newParent)
2084
- return CanType ();
2085
- }
2086
-
2087
- SmallVector<Type, 4 > newParams;
2088
- bool didChange = newParent != substBGT.getParent ();
2089
-
2090
- auto depthStart =
2091
- genericSig.getGenericParams ().size () - bgt->getGenericArgs ().size ();
2092
- for (auto i : indices (bgt->getGenericArgs ())) {
2093
- auto orig = bgt->getGenericArgs ()[i]->getCanonicalType ();
2094
- auto subst = substBGT.getGenericArgs ()[i];
2095
- auto gp = genericSig.getGenericParams ()[depthStart + i];
2096
-
2097
- // The new type is upper-bounded by the constraints the nominal type
2098
- // requires. The substitution operation may be interested in transforming
2099
- // the substituted type's conformances to these protocols.
2100
- auto upperBoundArchetype = decl->mapTypeIntoContext (gp)
2101
- ->getAs <ArchetypeType>();
2102
- SmallVector<ProtocolConformanceRef, 4 > substConformances;
2103
- if (upperBoundArchetype) {
2104
- for (auto proto : upperBoundArchetype->getConformsTo ()) {
2105
- auto conformance = substSubMap.lookupConformance (gp->getCanonicalType (),
2106
- proto);
2107
- if (!conformance)
2108
- return CanType ();
2109
- substConformances.push_back (conformance);
2110
- }
2111
- }
2112
-
2113
- auto newParam = visit (orig, subst, upperBoundArchetype,
2114
- substConformances);
2115
- if (!newParam)
2116
- return CanType ();
2117
-
2118
- newParams.push_back (newParam);
2119
- didChange |= (newParam != subst);
2120
- }
2121
-
2122
- for (const auto &req : genericSig.getRequirements ()) {
2123
- if (req.getKind () != RequirementKind::Conformance) continue ;
2124
-
2125
- auto canTy = req.getFirstType ()->getCanonicalType ();
2126
-
2127
- // If the substituted type is an interface type, we can't verify the
2128
- // generic requirements.
2129
- if (canTy.subst (substSubMap)->isTypeParameter ())
2130
- continue ;
2131
-
2132
- auto *proto = req.getProtocolDecl ();
2133
- auto origConf = origSubMap.lookupConformance (canTy, proto);
2134
- auto substConf = substSubMap.lookupConformance (canTy, proto);
2135
-
2136
- if (origConf.isConcrete ()) {
2137
- // A generic argument may inherit a concrete conformance from a class
2138
- // constraint, which could still be bound to a type parameter we don't
2139
- // know more about.
2140
- if (origConf.getConcrete ()->getType ()->is <ArchetypeType>())
2141
- continue ;
2142
-
2143
- if (!substConf.isConcrete ())
2144
- return CanType ();
2145
- if (origConf.getConcrete ()->getRootConformance ()
2146
- != substConf.getConcrete ()->getRootConformance ())
2147
- return CanType ();
2148
- }
2149
- }
2150
-
2151
- if (!didChange)
2152
- return subst;
2153
-
2154
- return BoundGenericType::get (substBGT->getDecl (),
2155
- newParent, newParams)
2156
- ->getCanonicalType ();
2185
+ return handleGenericNominalType (decl, CanType (bgt), subst,
2186
+ upperBound, substConformances);
2157
2187
}
2158
2188
};
2159
2189
}
0 commit comments